PE File Format and Packer - Inc0gnito 2016
-
Upload
hajin-jang -
Category
Technology
-
view
226 -
download
14
Transcript of PE File Format and Packer - Inc0gnito 2016
2016 년 8 월 16 일
PE File Format & PackerKUICS 장하진
KUICS 2
Who am I?
고려대학교 정보보호동아리 KUICS 12 대 회장 (2015.12 ~ 현재 ) 차세대 보안리더 양성프로그램 BoB 4 기 수료생
https://joveler.kr https://ied206.github.io https://github.com/ied206 http://www.slideshare.net/ied206
PE File Formatexe 파일의 정체는 ?
KUICS 4
PE File 이란 ?
Windows 에서 사용하는 실행 파일 포맷 Portable Executable 의 약자
대표적인 PE File Format- exe ( 실행 파일 )- dll ( 동적 링크 라이브러리 )- sys ( 드라이버 )
KUICS 5
PE File 구조
다음과 같은 구조로 이루어져 있다 .
DOS Header DOS Stub COFF File Header Optional Header Section Header Sections
- .text, .data 등
KUICS 6
PE File 구조 – 1) DOS Header & Stub
PE File 은 DOS 의 MZ 실행 파일 규격에 대한 하위 호환성을 지닌다 . MS-DOS 에서 Windows 의 exe 파일을 실행할 경우 다음과 같은
문구를 볼 수 있다 .
동일 exe 파일은 Windows 에서 다음과 같이 실행된다 .
즉 , 하나의 파일이 운영체제에 따라 다르게 실행된다 .
KUICS 7
PE File 구조 – 1) DOS Header & Stub
이러한 구조가 가능한 이유 ? PE File 은 DOS MZ 규격을 확장한 형태이다 .
DOS Header
DOS Stub
DOS 에서 PE File 을 실행하면 DOS Stub 을 실행하고 종료한다 . Windows 에서 PE File 을 실행할 때 , 이 DOS 관련 부분을 곧바로
건너뛴다 .
KUICS 8
PE File 구조 – 2) COFF File Header
PE File 은 MZ 포맷의 확장이기도 하지만 COFF 포맷의 확장이기도 하다 .
대표적으로 다음과 같은 값을 지닌다 .
Machine SizeOfOptionalHeader Characteristics
KUICS 9
PE File 구조 – 3) Optional File Header
PE File 이 메모리에 로드되기 위해 필요한 정보들이 이곳에 담겨 있다 .
AddressOfEntryPoint ImageBase SectionAlignment FileAlignment SizeOfImage SizeOfHeader Subsystem NumberOfRavAndSizes DataDirectory
KUICS 10
PE File 구조 – 3) Optional File Header
AddressOfEntryPoint- 처음 실행될 때 어디부터 시작할지 결정
ImageBase- 가상 메모리 주소에서 PE File 이 로드되는 기준 위치
FileAlignment & SectionAlignment- Section 의 크기는 반드시 특정 값의 배수여야 한다 .- 파일 상태 : FileAlignment 의 배수- 메모리 : SectionAlignment 의 배수
SizeOfImage- PE 파일이 메모리에 로드되었을 때 차지하는 크기
Subsystem- PE 파일이 실행될 때 사용하는 Windows 의 Subsystem
KUICS 11
PE File 구조 – 4) Section
실행 파일은 크게 기계어와 기계어가 사용하는 데이터로 이루어져 있다 . PE File 은 이들을 별도의 영역에 분리해 보관한다 .
.text- 기계어 코드
.data- 데이터 ( 전역변수 , 상수 등 )
.rsrc- 아이콘 등의 리소스
KUICS 12
PE File 구조 – 4) Section
각각의 Section 은 별도의 권한을 가진다 . Ex) Read, Write, Execute
.text- Read, Execute
.data- Read, Write
.rsrc- Read, Write
KUICS 13
PE File 구조 – 4) Section
Section Header- 각 섹션에 대한 정보가 담겨 있다 .
VirtualSize VirtualAddress (VirtualOffset)
- 섹션이 메모리에 로딩되었을 상태의 크기와 시작 위치- VirtualAddress 는 SectionAlignment 의 배수
SizeOfRawData (RawSize) PointerToRawData (RawOffset)
- 파일 상태일때의 섹션의 크기와 시작 위치- PointerToRawData 는 FileAlignment 의 배수
Characteristics- 섹션의 속성 (Ex 권한 )
KUICS 14
PE File 구조 – 4) Section
PE(File).text
.data
.rsrc
PE(Memory)
.text
.data
.rsrc
KUICS 15
VA & RVA
하나의 exe 파일이 실행될 때는 다음과 같이 메모리 구역을 용도에 맞게 나눠 사용한다 .
다양한 dll 도 함께 로드된다 .
KUICS 16
VA & RVA
Virtual Memory (VA)- 가상 메모리의 절대주소
Relative Virtual Memory (RVA)- Base Address 부터의 상대주소
PE File 내부의 메모리 주소는 RVA 로 표현되어 있다 . PE File 이 메모리에 올라갈 때 RVA 주소값은 절대주소인 VA 로
변환된다 . RVA 로 메모리 주소를 표현한 이유는 Base Address 는 로드시마다
다르게 바뀔 수 있기 때문이다 .
PE 파일을 조작하고 분석하기 위해선 RVA 와 RAW 의 관계를 잘 알아야 한다 .
KUICS 17
VA & RVA
다음 이유들로 인해 메모리와 파일 형태에 차이가 생긴다 . - FileAlignment 와 SectionAlignment 의 차이- RVA 의 사용
메모리 형태에서 본 주소를 PE 파일과 매핑하려면 , VA 와 RVA 사이의 관계를 알아야 한다 .
VA = BaseAddress + RVA RAW – PointerToRawData = RVA – VirtualAddress
PointerToRawData : 파일에서 RVA 가 속해 있는 섹션의 시작 위치
VirtualAddress : 메모리에서 RVA 가 속해 있는 섹션의 시작 위치
KUICS 18
PE File 구조 – 4) Section
PE(File).text
.data
.rsrc
PE(Memory)
.text
.data
.rsrc
KUICS 19
IAT
Import Address Table- dll 에서 불러 사용하는 함수의 주소값을 보관할 영역
dll 에서 불러 사용하는 함수의 주소는 PE 파일의 상태에 따라 다르다 .- 파일 형태에서는 RVA 로 표현되어 있다 .- 메모리에 로드되면 이 RVA 가 VA 값으로 바뀐다 .
KUICS 20
IAT
CloseHandle 의 주소가 0x400000 + 0x122B8 로 표기되어 있다 . 0x4122B8 를 통해 0x73BB9660 에 있는 Kernel32.dll 의 CloseHan-
dle 로 간다 .
dll 에 있는 함수를 호출하는 경우 , 이와 같이 IAT 를 활용한 간접 호출을 한다 .
KUICS 21
IAT
실행파일 내부에서 API 를 호출할 때 다음과 같은 과정을 거친다 .- 코드 -> API (X)- 코드 -> IAT -> API (O)
후자는 속도가 더 느려지지 않을까 ?
DLL 이 메모리에 로드될 때 ImageBase 값이 변경될 수 있다 . VA 는 ImageBase 값에 따라 변동된다 . 이러한 특징 때문에 API 의 주소를 VA 로 하드코딩할 수 없다 . 따라서 , API 의 주소는 dll 에 대한 RVA 로 적혀 있으며 dll 이
로딩되는 시점에 VA 로 변환된다 .
PE Packer 분석UPX 와 UPack 의 세계로 !
KUICS
KUICS 23
PE Packer
Packer 의 종류
Compressor- 실행 프로그램의 용량을 줄인다 .
Ex) UPX
Protector- 실행 프로그램의 역공학을 방해한다 .- 상용프로그램의 경우 , 핵심 알고리즘의 역공학을 막기 위해 사용
Ex) Themida- 악성코드는 백신 탐지를 어렵게 할 목적으로 사용
Ex) UPack
KUICS 24
Compressor : UPX
실행 압축계의 No1 패커- http://upx.sourceforge.net/
다양한 운영체제와 아키텍쳐를 지원한다 .- OS : Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, MS-DOS 등- Arch : amd64, i386, arm, mips, powerpc 등
압축해제 속도가 매우 빠른 UCL 라이브러리를 사용- 실행 압축 특성상 압축해제가 빨라야 한다 .
작동 방법- 1) SFX 형태로 임시 폴더에 압축을 해제하여 실행 (extract to temp file)- 2) 실행되는 시점에 메모리에 압축 해제를 하고 실행 (in-place)- 대부분 2 번 in-place 방법을 사용
KUICS 25
Compressor : UPX
구조를 알아보기 위해 한 실행 프로그램을 패킹하고 , 분석해보자 .
패킹 전
- 다양한 섹션이 존재하는 것을 확인할 수 있다 .- 섹션의 용도에 맞는 권한들을 가지고 있다 .
KUICS 26
Compressor : UPX
패킹 중
212KB 가 175KB 로 줄어들었다
KUICS 27
Compressor : UPX
패킹 후
- rsrc 섹션을 제외한 나머지 섹션들이 사라졌다 .- UPX0, UPX1 모두 Read/Write/Execute 권한을 가지고 있다 .- UPX0 의 RawSize 는 0 이다 ( 파일 상태에서는 존재하지 않는다 ).- UPX0 의 VirtualSize 는 원본 파일의 섹션의 크기를 다 더한 것보다 크다 .- UPX1 은 RawSize 를 가지고 있으며 VirtualSize 의 크기와 같다 .- UPX1 에 EntryPoint 가 존재한다 .
이것들이 의미하는 바는 ?
KUICS 28
Compressor : UPX
패킹 후
가정- UPX1 섹션에 EP 가 존재하므로 , 압축해제 코드가 존재하리라 알 수 있다 .- UPX0 섹션의 RawSize 가 0 이지만 VirtualSize 는 값이 크다는 점에서 ,
이 프로그램이 실행되는 시점에 원래의 데이터가 UPX0 에 압축해제됨을 추측할 수 있다 .
- rsrc 섹션의 크기는 거의 똑같으므로 , 압축된 데이터는 UPX1 섹션에 존재할 것이다 .
- UPX0 섹션은 Read/Write/Execute 권한을 모두 가지고 있으므로 , code 섹션 (Read/Execute) 과 data 섹션 (Read/Write) 의 역할을 모두 할 것이다 .
KUICS 29
Compressor : UPX
패킹 후
섹션 Offset (ImageAddress + VirtualOffset)- UPX0 = 0x400000 + 0x01000 = 0x401000 (~0x436FFFF)- UPX1 = 0x400000 + 0x37000 = 0x437000 (~0x43CFFFF)
EntryPoint- EP = 0x400000 + 0x3CC50 = 0x43CC50- EP 는 UPX1 섹션에 존재한다 .
KUICS 30
Compressor : UPX
UPX 의 압축 해제 코드를 분석해보자 .
IDA 로 패킹된 프로그램을 열 경우 IAT 가 깨져있다는 경고가 나타난다 . -> UPX 는 압축시 IAT 를 건드린다는 점을 알 수 있다 .
KUICS 31
Compressor : UPX
패킹 전의 IAT
KUICS 32
Compressor : UPX
패킹 후의 IAT
압축 해제에 필수적인 API 만 제대로 표시되고 있다 .
KUICS 33
Compressor : UPX
패킹된 파일은 단 두개의 함수만을 가지고 있다 .
start 함수가 압축해제 코드일 가능성이 높다 .
KUICS 34
Compressor : UPX
start 함수는 PUSHA 로 시작하여 POPA ~ JMP 문으로 끝난다 .
35
Compressor : UPX
첫 부분에서 ESI 와 EDI 를 세팅하고 있다 .
어셈블리어에서 ESI 와 EDI 가 쓰일 경우 관용적으로 다음을 가리킨다 .- ESI : Source, 데이터를 읽어올 주소- EDI : Destination, 데이터를 쓸 주소
즉 , 다음 가능성이 높다 .- ESI : 압축된 데이터의 주소- EDI : 원본 데이터가 들어가야 할 위치
KUICS
36
Compressor : UPX
첫 부분에서 ESI 와 EDI 를 세팅하고 있다 .
세팅되는 값을 살펴보자 .- ESI = 0x437015- EDI = 0x401000
즉 , ESI 는 UPX1 섹션 , EDI 는 UPX0 섹션을 가리키고 있다 .- UPX0 = 0x401000 ~ 0x436FFFF- UPX1 = 0x437000 ~ 0x43CFFFF
KUICS
37
Compressor : UPX
[EDI] 에 쓰기를 하는 코드가 있는 곳이 패킹된 파일을 원래 상태로 복구하는 핵심 부분이다 .
KUICS
38
Compressor : UPX
CALL 을 만났다 . 뭐하는 녀석이지 ?
KUICS
39
Compressor : UPX
더 진행하면 CALL 로 함수를 호출하는 부분이 존재한다 .
KUICS
40
Compressor : UPX
동적 분석 결과 , LoadLibrary 와 GetProcAddress 를 호출하고 있음을 알 수 있다 .
KUICS
41
Compressor : UPX
UPX 로 패킹된 프로그램은 IAT Table 에 함수의 RVA 가 없어 불완전하다 .
LoadLibrary 로 dll 을 로드하고 그 주소를 EBP 에 저장한다 . dll 명단은 IAT 에서 직접 가져온다 .
KUICS
42
UPX 로 패킹된 프로그램은 IAT Table 에 함수의 RVA 가 없어 불완전하다 .
GetProcAddress 을 dll 주소 (EBP), 함수 이름 (EDI) 을 인자로 주고 호출한다 .
API 의 주소 (VA) 를 얻어 (EAX) EBX 가 가리키는 곳에 복사한다 .
Compressor : UPX
KUICS
KUICS 43
Compressor : UPX
마무리로 , 메모리 특정 구역의 권한을 설정한다 .
KUICS 44
Compressor : UPX
동적 분석 결과 , 다음과 같은 작업을 한다 .
VirtualProtect(0x400000, 0x1000, PAGE_READWRITE, &지역변수 );
VirtualProtect(0x400000, 0x1000, PAGE_READONLY, &지역변수 );
TlsCallback(…);
KUICS 45
Compressor : UPX
마지막 단계
POPA 명령으로 레지스터를 복구한다 . 그 뒤 원래의 EP 로 JMP 한다 .
KUICS 46
Compressor : UPX
패킹 전 원본 파일의 EP
KUICS 47
Compressor : UPX
패킹된 프로그램의 압축해제 전 ( 원본의 EP)
NULL Padding 만 존재한다 .
KUICS 48
Compressor : UPX
패킹된 프로그램의 압축해제 후 ( 원본의 EP)
원본과 같은 코드가 나타난 것을 볼 수 있다 .
KUICS 49
Compressor : UPX
UPX 압축해제가 정상적으로 끝난 상태에서 F9 를 눌러주면 ?
원본이 실행되듯이 정상적으로 잘 실행된다 .
KUICS 50
Compressor : UPX
결론
UPX 의 압축 해제는 다음과 같은 순서로 진행된다 . UCL 알고리즘으로 압축된 PE 섹션의 압축 해제 -> IAT 복구
KUICS 51
Compressor : UPX
사족 : 디버거의 빼애애액 패커가 적용되었을 때 디버거에서 BP 를 걸면 다음과 같은 경고 메시지가 뜬다 .
디버거는 EP 를 보고 어떤 섹션이 code 섹션인지 구분한다 . 패커가 EP 를 다른 섹션으로 바꿔버렸기 때문에 디버거에 혼동이 온 것 .
KUICS 52
Protector : UPack
PE 파일을 난독화시키는 패커이다 . 헤더를 꼬아 파일의 구조를 완벽하게 바꿔 버리기에 리버싱에 큰 지장이 온다 .
Windows 의 PE 로더가 PE 표준 규격보다 너그럽게 구현된 것을 악용한다 .
KUICS 53
Protector : UPack
원본 PE 파일 헤더 구조- 헤더들이 순서대로 붙어 있다 .
DOS MZ Header
COFFHeader
DOSStub
Optional Header
KUICS 54
Protector : UPack
UPack 으로 패킹한 후의 PE 헤더- 헤더들이 이리저리 꼬여 있다 .
DOS MZ Header
COFFHeader
Optional Header
KUICS 55
Protector : UPack
헤더 겹치기 Windows 는 DOS Stub 을 전혀 참고하지 않으며 , MZ Header 의 맨 마지막 값 , e_lfnew 값을 보고 PE 헤더의 시작점을 찾는다 .
PE 규격에 COFF Header 의 시작 오프셋은 정해져 있지 않다 . MZ Header 의 e_lfnew 값을 MZ Header 의 바깥이 아닌 ,
안을 향하게 만들어서 헤더를 겹치게 만든다 .
DOS MZ Header
COFFHeader
Optional Header
KUICS 56
Protector : UPack
Section 겹치기 + Alignment 꼬기
섹션의 메모리상 Offset (ImageAddress + VirtualOffset)- Sec01 = 0x400000 + 0x01000 = 0x401000 (~0x43BFFFF)- Sec02 = 0x400000 + 0x3C000 = 0x43C000 (~0x46DFFFF)- Sec03 = 0x400000 + 0x6E000 = 0x46E000 (~0x46EFFFF)
섹션의 파일상 Offset (PointerToRawData)- Sec01 = 0x000010 ~ 0x0001FF- Sec02 = 0x000200 ~ 0x02AAB7- Sec03 = 0x000010 ~ 0x0001FF
파일상 Offset 이 이상하다 ?
KUICS 57
Protector : UPack
Section 겹치기 + Alignment 꼬기
섹션의 파일상 Offset (PointerToRawData)- Sec01 = 0x000010 ~ 0x0001FF- Sec02 = 0x000200 ~ 0x02AAB7- Sec03 = 0x000010 ~ 0x0001FF
파일상 Offset 이 이상하다 ?- 파일상의 Offset 은 반드시 FileAlignment 의 배수여야 한다 .- 일반적으로 FlieAlignment 는 0x200 (512) 의 값을 가진다 .- 그런데 0x10 은 0x200 의 배수가 아니다 .
Windows 의 PE Loader 는 이 경우 강제로 배수에 맞춘다 .
KUICS 58
Protector : UPack
Section 겹치기 + Alignment 꼬기
즉 여기서 0x10 의 RawOffset 은 0x0 또는 0x200 으로 교정된다 .- 테스트 결과 0x00 으로 계산됨
실제 파일상 Offset (PointerToRawData)- Sec01 = 0x000000 ~ 0x0001EF- Sec02 = 0x000200 ~ 0x02AAB7- Sec03 = 0x000000 ~ 0x0001EF
RAW to RVA 를 계산할 때도 이 점에 유의해야 한다 .
KUICS 59
Protector : UPack
Section 겹치기 + Alignment 꼬기
EntryPoint (RAW) 를 계산해보자 . 헤더에 따르면 , EntryPoint (RVA) 는 0x00001018 이다 . 이 RAW 주소는 Sec01 및 Sec03 에 속한다 . RAW = RVA–VirtualOffset + RawOffset EP (RAW) = 0x1018 – 0x1000 + 0x10 = 0x28 (X)
그러나 RawOffset 이 0x10 으로 , 0x200 의 배수가 아니므로 0x0 으로 교정한다 .
EP (RAW) = 0x1018 – 0x1000 + 0x0 = 0x18(O)
KUICS 60
Protector : UPack
x64dbg 의 경우 , Sec01 에 진입을 시도할 시 크래시가 발생한다 .
KUICS 61
Protector : UPack
ImmunityDebugger
패킹된 프로그램의EP 로 접근하지못한다 .
KUICS 62
Protector : UPack
UPack 이 RAW to RVA 변환법을 꼬아놓기에 Immunity De-bugger 가 EP 를 제대로 계산하지 못해 발생하는 문제이다 .
EP 를 강제로 지정해야 디버깅이 가능하다 .
EP = ImageBase + EntryPoint (RVA)
EP = 0x400000 + 0x001018 = 0x401018
KUICS 63
Protector : UPack
EP 를 강제로 지정해야 디버깅이 가능하다 . Ctrl + G -> 00401018 (EP) 입력 New origin here 로 EP 강제 지정 .
KUICS 64
Protector : UPack
정상적인 PE 파일이 아니기에 Ctrl + G 를 통해 00401018 로 직접 이동하지 않으면 어셈블리 코드가 비정상적으로 표기된다 .
정상
디버거의 표시
KUICS 65
Protector : UPack
IDA Pro 는 ?
경고 5 관왕 달성 !
KUICS 66
Protector : UPack
4) Section 겹치기 + Alignment 꼬기
섹션의 파일상 Offset (PointerToRawData)- Sec01 = 0x000010 ~ 0x0001FF- Sec02 = 0x000200 ~ 0x02AAB7- Sec03 = 0x000010 ~ 0x0001FF
파일상 Offset 이 이상하다 ?- 파일상의 Offset 은 반드시 FileAlignment 의 배수여야 한다 .- 일반적으로 FlieAlignment 는 0x200 (512) 의 값을 가진다 .- 그런데 0x10 은 0x200 의 배수가 아니다 .
Windows 의 PE Loader 는 이 경우 강제로 배수에 맞춘다 .
KUICS 67
Protector : UPack
가정
Sec01 은 파일 상태의 크기는 작으나 , 메모리 상태의 크기는 크다 . Sec02 는 파일 상태의 크기와 메모리 상태의 크기가 모두 크다 . Sec03 은 파일 상태의 크기와 메모리 상태의 크기가 모두 작다 .
용량으로 보아 Sec02 에 압축된 원본 데이터가 존재하리라 추측할 수 있다 .
Sec01 이 Sec02 보다 메모리 상태의 크기가 더 크다 . 이를 통해 Sec01 에 원본 데이터가 압축해제 된다는 점을 추측할 수
있다 .
KUICS 68
Protector : UPack
EP 에서 몇가지 연산을 수행한 이후 0x004667A3 으로 JMP 한다 .
KUICS 69
Protector : UPack
0x4667A3 이후부터는 CALL DWORD PTR [ESI] 구문이 자주 등장한다 .
KUICS 70
Protector : UPack
CALL DWORD PTR DS:[ESI] 실행시 0x46675B 함수를 호출한다 .
인자를 EAX 와 EDX 로 받는다 . 자주 호출되는 것을 보아 압축 해제를 담당하는 코드일 가능성이 높다 .
KUICS 71
Protector : UPack
[ESI] 뿐만 아니라 [ESI+54], [ESI+50] 도 호출하고 있다 .
KUICS 72
Protector : UPack
BP 를 걸고 F9 를 계속 눌러보자 .
KUICS 73
Protector : UPack
원본 프로그램의.text 섹션
패킹된 프로그램디버깅 중 살펴본동일 영역
압축 해제가 이루어지고 있다 .
KUICS 74
Protector : UPack
이 시점에서 다시 IAT 를 살펴보자 .
IAT 를 복구할 때 필요한 두 API 만 여기에 존재한다 . 원래의 IAT 명단을 복구해야 하므로 , IAT 를 복구하는 코드가 존재할
것이다 .
KUICS 75
Protector : UPack
그런데 이 주소를 직접 부르고 있지 않아 정적 분석으로는 추적이 불가능하다 !
동적 분석 중 0x4011E8 나 0x4011EC 를 CALL 하는 부분을 찾자 . 모든 CALL 에 BP 를 걸고 진행하며 찾다보면 나오지 않을까 ?
KUICS 76
Protector : UPack
0x466923 LoadLibraryA("GDI32.DLL");
KUICS 77
Protector : UPack
0x46693A GetProcAddress([HANDLE of GDI32.DLL], "BitBlt");
KUICS 78
Protector : UPack
EAX 에 BitBlt 값이 반환되고 , STOS 를 통해 EAX 의 값을 [EDI]에 복사한다 .
KUICS 79
Protector : UPack
F9 를 반복해서 눌러 상황을 보자 .
IAT 가 복구되고 있다 .
KUICS 80
Protector : UPack
IAT 를 복구한 뒤 원래의 EP 로 JMP 한다 .
패킹 전 원본 파일
패킹 복구 후
KUICS 81
Protector : UPack
결론
UPack 도 UPX 와 마찬가지로 실행시 압축 해제 -> IAT 복구 순서를 거친다 .
용량을 줄이기 위해 압축만 하는 UPX 와는 달리 , UPack 은 PE 헤더의 값을 꼬아 분석의 난이도를 높인다 .
결과적으로 리버싱과 같은 바이너리 분석을 크게 방해한다 .
Q&A
KUICS
05/03/2023 동아리이름