410 likes | 925 Views
PE(Portable Executable) File 구조. 신민용 , 한경수. 2011 년 Keeper – 보안 기술문서 – Packing. 순 서. PE File 이란 ? PE 구조를 알아야 하는 이유 개략적인 PE 구조 Section 구분이 필요한 이유 상세 구조 로더 제작 및 시연. PE File 이란 ?. 정 의
E N D
PE(Portable Executable) File 구조 신민용, 한경수 • 2011년 Keeper – 보안 기술문서 – Packing
순 서 PE File이란? PE구조를 알아야 하는 이유 개략적인 PE구조 Section구분이 필요한 이유 상세 구조 로더 제작 및 시연
PE File이란? • 정 의 • MS WINDOWS 3.1부터 지원되는 실행 파일의 형식을 말한다. 유닉스 COFF(Common Object file format)를 기반으로 나왔으며, PE 포맷을 사용하는 파일의 확장자는cpl, exe, dll, ocx, vxd, sys, scr, drv가 있다. • 다양한 운영 체제에이식이 가능한 실행 형식(Portable Excutable)이라는 이름
PE File이란? • 프로그램 실행 원리 - 폰노이만 구조 • 데이터 메모리와 프로그램 메모리가 구분되어 있지 않고 하나의 버스를 가지고 있는 구조 • CPU, 메모리, 프로그램 구조를 갖는 프로그램 내장 방식 컴퓨터의 아이디어
PE File이란? • 디스크에서 본 실행파일(notepad.exe)
PE File이란? • 메모리에서 본 실행파일(notepad.exe)
PE File이란? • CPU에서 본 실행파일(notepad.exe)
PE File이란? • 4C01이란? • 우선 Big Endian과 Little Endian을 비교해 보자 인텔기반 4C01 014C
PE File이란? • 4C01이란?
PE File이란? • 의미 전달을 위해서 Notepad.exe Visual Studio2010 어디가 시작일까?
PE File이란? • 의미 전달을 위해서 • 의미단위 프레임이 필요 ⇒ Protocol • IP(Internet Protocol), TCP(Transmission Control Protocol) IP Header TCP Header UDP Header
PE File이란? Memory • 의미 전달을 위해서 • 실행 가능한 프로그램 ⇒ PE구조
PE구조를 알아야 하는 이유 • 실행프로그램의 수행 기능을 추가 / 변경 • 이번 프로젝트에서의 Packing의 경우 • 프로그램 자체 기능에 영향을 미치지 않아야 한다. • Reversing을 어렵게 만들어야 한다. • File자체를 분석하지는 못하도록 실행파일을 변환시킨다. • 실행 시에는 제대로 수행할 수 있도록 다시 변환시켜야 한다.
PE구조를 알아야 하는 이유 • 이번 프로젝트에서의 Packing의 경우 • .text, .data에 있는 값들을 변환시킨다. Section header(“.pack”) Section(“.pack”)
개략적인 PE구조 000 040 0E0 1D8
개략적인 PE구조 – DOS header 000 040 0E0 1D8 DOS 실행파일 설계자 Mark Zbikowski의 이니셜 새로운 EXE Header의 주소 : 0x000000E0
개략적인 PE구조 – DOS stub 000 040 0E0 1D8 DOS에서 실행 시 수행되는 부분 16비트 assembly어 0D : Carrige Return(CR) 0A : Line Feed(LF)
개략적인 PE구조 – NT headers PE구조의 서명은 ‘PE’ 000 040 0E0 1D8 Machine : 4C01 Section의 수 : 0x0003 TimeStamp : 0x41107CC3 SizeOfOptionalHeader : 0x00E0 Characteristics : 0x010F 101111
개략적인 PE구조 – NT headers 000 040 0E0 1D8 Magic : 0x010B(32bit) 0x020B(64bit) SizeOfCode : 0x00007800 AddressOfEntryPoint : 0x0000739D ImageBase : 0x01000000 SectionAlignment: 0x00100000 FileAlignment: 0x00200000 Subsystem : 0x0002(GUI) 0x0001(sys, driver file) 0x0003(CUI) SizeOfImage : 0x00014000 SizeOfHeaders : 0x00000400 NumberOfRvaAndSizes : 0x00000010
개략적인 PE구조 – Section headers 000 040 0E0 1D8 Name : “.text” VirtualSize: 0x00007748 VirtualAddress: 0x00001000 SizeOfRawData: 0x00007800 PointerToRawData: 0x00000400 Characteristics: 0x60000020 0x00007748 0x00001000 0x00007800 0x00000400 0x60000020
개략적인 PE구조 – Section headers 0x00007C00 0x00007B48 000 040 0E0 1D8 0x00007748 0x00001000 0x00007800 0x00007B48 0x00000400 0x60000020 0x00007BFF
RVAto FileOffset – 1 • 우리가 다룰 주소의 종류는 크게 네가지로 나눌 수 있다. • Physics Address • VA:Virtual Address • RVA:Relative Virtual Address • RawOffset≡FileOffset • 지금까지 다루어지던 주소들은 모두 RVA 로써 RVA를FileOffset으로 변환을 하려면 조금의 연산이 필요하다.
RVAto FileOffset – 2 • RVA– BaseVirtualAddress + PointerToRawData = FileOffset • Ex1 )RVA= 0x4880 의 FileOffset은? • FileOffset = 0x4880 – 0x1000 + 0x400 = 0x3C00 • Ex2 )RVA= 0x9550 의 FileOffset은? • FileOffset = 0x9550 – 0x9000 + 0x7C00 = 0x8150 0x9000 <= 0x9550 < 0x9000 + 0x1BA8 0x1000 <= 0x4880 < 0x1000 + 0x7748
Import Address Table - 0 Export Address Table Import Address Table
Import Address Table - 1 • IAT– 어떤 프로그램에서 어떤 라이브러리를 사용하는지 기술한 테이블.
Import Address Table - 2 파일이 실행되는 순간 PE Loader가 01001104 의 위치에 CreateFileW의 주소를 입력 Call 7C8107F0 과 똑같은 효과. 하지만 왜 call [1001104] 로 쓸까?
Import Address Table - 3 typedefstruct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics DWORD OriginalFirstThunk; //IMAGE_IMPORT_BY_NAME array } DUMMYUNIONNAME; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; // dll이름 DWORD FirstThunk; //dll안에 있는 함수주소들이 하드코딩되어있다. } IMAGE_IMPORT_DESCRIPTOR
Import Address Table – 4 cmddlg32.dll 의 OriginalFirst Thunk RVA to Offset 변환
Export Address Table – 0 Kernel32.dll 을 KPloader로 열어본 모습 Export Address Table
Export Address Table – 1 EAT(Export Address Table) 은 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 매커니즘. Kernel32.dll 의 RVA:0x262C 를 offset 으로 변환해보면 0x262C – 0x1000 + 0x400 = 0x1A2C 가 됩니다.
Export Address Table - 2 typedefstruct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion;DWORD Name; // dll이름을 가르키는 주소 DWORD Base; DWORD NumberOfFunctions; // 실제 함수의 개수(전체) DWORD NumberOfNames; // 이름을 가지는 함수의 개수 DWORD AddressOfFunctions; //함수의 주소배열을 가르키는 주소 DWORD AddressOfNames; // address of functino name string array DWORD AddressOfNameOrdinals; // address of ordinal array} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
Export Address Table - 3 1. AddressOfNames멤버의 값으로 이동 2. AddressOfNames의 값으로 가면 문자열 주소가 저장되어 있음. 문자열 비교를 통하여 원하는 함수 이름을 찾음. 이 때의 배열 인덱스를 "idx" 라고 하겠습니다. 3. AddressOfNameOrdinals멤버의 값을 통해 "ordinal 배열" 로 이동 4. "ordinal 배열" 에서 "idx" 로 해당 "ordinal_idx" 값을 찾습니다. 5. AddressOfFunctions로 이동하여 ordinal_idx멤버를 이용해 함수의 시작 주소를 얻습니다. 그렇다면 “AddAtomW” 함수를 kernel32.dll 에서 어느 위치에 있는지 어떻게 알아낼 수 있을까?
Export Address Table - 4 실제 kernel32.dll 파일의 EAT 에서AddAtomW함수 주소를 찾는 과정 앞에서 kernel32.dll 의 IMPORT_EXPORT_DIRECTORY 구조체 file offset 은 1A2Ch였음 Characteristics = 00000000hTimeDateStamp = 49C4D12EhMajorVersion = 0000hMinorVersion = 0000hName = 00004B98hBase = 00000001hNumberOfFunctions = 000003BAhNumberOfNames = 000003BAhAddressOfFunctions = 00002654hAddressOfNames = 0000353ChAddressOfNameOrdinals = 00004424h AddressOfNames멤버의 값은 RVA = 353Ch 이므로 file offset = 293Ch
Export Address Table - 5 file offset = 293Ch RVA = 4BBDh 은 file offset = 3FBDh [0x00003FBD] 를 따라가보면, … 찾았다. AddAtomW를 찾았음 AddressOfFunctions멤버의 값은 RVA = 2654h 이므로 file offset = 1A54h Characteristics = 00000000hTimeDateStamp = 49C4D12EhMajorVersion = 0000hMinorVersion = 0000hName = 00004B98hBase = 00000001hNumberOfFunctions = 000003BAhNumberOfNames = 000003BAhAddressOfFunctions = 00002654hAddressOfNames = 0000353ChAddressOfNameOrdinals = 00004424h AddressOfFunctions[ordinal(2)] = 326F1 kernel32.dll의ImageBase = 7C7D0000h입니다.따라서"AddAtomW" 함수의실제 주소(VA)는7C8026F1h