DOS Hader
- 중요 멤버 : e_magic, e_lfanew
- 크기 : 32bit - 40byte, 64bit - 64byte
#include <WinTH.h>
typedef struct _IMAGE_DOS_HEADER // DOS .EXE header
{
WORD e_magic; // Magic number / DOS signature : 4D5A("MZ")
WORD e_cblp; // Byte on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Inital SP value
WORD e_csum; // Checksum
WORD e_ip; // Initital IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header / offset to NT header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
NT_HEADER
- 크기 : 264byte
#include <WinTH.h>
typedef struct _IMAGE_NT_HEADERS
{
DWORD Signature; // 4byte, PE Signature : 50450000("PE"00)
IMAGE_FILE_HEADER FileHeader; // 20 byte
IMAGE_OPTIONAL_HEADER32 OptionalHeader; // 32bit - 224byte, 64bit - 240byte
} IMAGE_NT_HEADER32, *PIMAGE_NT_HEADER32;
NT HEADER - File Header
- 파일의 개략적인 속성을 나타내는 IMAGE_FILE_HEADER 구조체이다.
- 크기 : 20byte
- 중요 멤버 : Machine, NumberOfSections, SizeOfOptionalHeader, Characteristics
(이 값이 정확히 세팅되어 있지 않으면 파일은 정상적으로 실행되지 않는다.)
typedef struct _IMAGE_FILE_HEADER
{
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAE_FILE_HEADER;
Machine
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I386 0x014c// Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162// MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166// MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168// MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169// MIPS little-endian WCE v2#define IMAGE_FILE_MACHINE_ALPHA 0x0184// Alpha_AXP#define IMAGE_FILE_MACHINE_SH3 0x01a2// SH3 little-endian#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4// SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6// SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8// SH5#define IMAGE_FILE_MACHINE_ARM 0x01c0// ARM Little-Endian#define IMAGE_FILE_MACHINE_THUMB 0x01c2// ARM Thumb/Thumb-2 Little-Endian#define IMAGE_FILE_MACHINE_ARMNT 0x01c4// ARM Thumb-2 Little-Endian#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0// IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200// Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266// MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284// ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366// MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466// MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520// Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC// EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664// AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041// M32R little-endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
Characteristics
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Agressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
NT Header - Optional Header
- PE 헤더 구조체 중에서 가장 크기가 큰 IMAGE_OPTIONAL_HEADER32이다.
- 중요 멤버 : Magic, AddressOfEntryPoint, ImageBase, SectionAlignment, FileAlignment, SizeOfimage, SizeOfHeader, Subsystem, NumberOfRvaAndSizes, DataDirectory
- 크기 : 32bit - 224byte, 64bit - 240byte
typedef struct _IMAGE_DATA_DIRECTORY
{
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER
{
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER64
{
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
ULONGLONG ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
Subsystem
값 | 의미 | 비고 |
1 | Driver File | 시스템 드라이버(ex. ntfs.sys) |
2 | GUI 파일 | 창 기반 애플리케이션(ex. notepad.exe) |
3 | CUI 파일 | 콘솔 기반 애플리케이션(ex. cmd.exe) |
DataDirectory
- IMAGE_DATA_DIRECTORY 구조체의 배열로 배열의 각 항목마다 정의된 값을 가진다.
DataDirectory[0] = EXPORT Directory
DataDirectory[1] = IMPORT Directory
DataDirectory[2] = RESOURCE Directory
DataDirectory[3] = EXCEPTION Directory
DataDirectory[4] = SECURITY Directory
DataDirectory[5] = BASERELOC Directory
DataDirectory[6] = DEBUG Directory
DataDirectory[7] = COPYRIGHT Directory
DataDirectory[8] = GLOBALPTR Directory
DataDirectory[9] = TLS Directory
DataDirectory[A] = LOAD_CONFIG Directory
DataDirectory[B] = BOUND_IMPORT Directory
DataDirectory[C] = IAT Directory
DataDirectory[D] = DELAY_IMPORT Directory
DataDirectory[E] = COM_DESCRIPTOR Directory
DataDirectory[F] = Reserved Directory
IMAGE_SECTION_HEADER
- 각 섹션별 IMAGE_SECTION_HEADER 구조체 배열로 되어 있다.
- 중요 멤버 : VirtualSize, VirtualAddress, SizeofRawData, PointerToRawData, Characteristics
참고)
VirtualAddress와 PointerToRawData는 아무 값이나 가질 수 없고, 각각 IMAGE_OPTIONAL_HEADER에 정의된 SectionAlignment와 FileAlignment에 맞게 결정된다.
VirtualSize와 SizeOfRawData는 일반적으로 서로 다른 값을 가지는데, 즉 파일에서의 섹션 크기와 메모리에 로딩된 섹션의 크기를 다르다
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER
{
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union
{
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
Characteristics
#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
IMAGE_IMPORT_DESCRIPTOR
- PE 파일은 자신이 어떤 라이브러리를 Import 하고 있는지 IMAGE_IMPORT_DESCRIPTOR 구조체에 명시하고 있다.
- 라이브러리의 개수만큼 구조체의 배열 형식으로 존재한다.
- 구조체 배열의 마지막은 NULL 구조체로 끝나게 된다.
- 중요 멤버 : OriginalFirstThunk, Name, FirstThunk
- 크기 : 20byte
typedef struct _IMAGE_IMPORT_DESCRIPTOR
{
union
{
DWORD Characteristics;
DWORD OriginalFirstThunk;// INT(Import Name Table) address (RVA)
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;// library name string address (RVA)
DWORD FirstThunk;// IAT(Import Address Table) address (RVA)
} IMAGE_IMPORT_DESCRIPTOR;
/*
위의 IMAGE_IMPORT_DESCRIPTOR 구조체의 멤버 중
OriginalFirstThunk와 FirstThunk 멤버의 값이 가리키는 곳으로
해당 위치의 값들은 아래의 구조체 형태로 되어있다.
*/
typedef struct _IMAGE_THUNK_DATA32
{
union
{
DWORD ForwarderString;// PBYTE
DWORD Function;// PDWORD
DWORD Ordinal;
DWORD AddressOfData;// PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef struct _IMAGE_THUNK_DATA64
{
union
{
ULONGLONG ForwarderString;// PBYTE
ULONGLONG Function;// PDWORD
ULONGLONG Ordinal;
ULONGLONG AddressOfData;// PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA64;
typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;
/*
ForwarderString : 실제 Import 한 함수가 Forwarding된 함수일 경우. Forwarding에 대해서는 Export에서 설명
Function : FirstThunk의 경우 메모리에 로딩이 되면 실제 함수 주소를 가리키는 IMAGE_THUNK_DATA의 RVA값을 표시한다고 했는데, 이때 실제 Function의 주소가 포함된 부분
Ordinal : Import를 함수 명이 아니라 서수(Ordinal)로 한 경우. 0x80000000 값으로 마스크하면 최 상위 비트를 구할 수 있는데 이것이 1로 셋팅된 경우 서수로 판단
AddressOfData : 실제 Import 된 함수의 이름이 포함된 IMAGE_IMPORT_BY_NAME 구조체에 대한 RVA 주소 포함
*/
/*
위의 IMAGE_THUNK_DATA 구조체 멤버의 값이 가리키는 곳에 있는 값들은
아래의 구조체 형태로 되어 있다.
*/
typedef struct _IMAGE_IMPORT_BY_NAME
{
WORD Hint;// ordinal
BYTE Name[1];// function name string
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
IMAGE_EXPORT_DIRECTORY
- 중요 멤버 : NumberOfFunctions, NumberOfNames, AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals
- 크기 : 40 byte
typedef struct _IMAGE_EXPORT_DIRECTORY
{
DWORD Characteristics; // creation time date stamp
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; // address of library file name
DWORD Base; // ordinal base
DWORD NumberOfFunctions; // number of functions
DWORD NumberOfNames; // number of names
DWORD AddressOfFunction; // address of function start address array
DWORD AddressOfNames; // address of function name string array
DWORD AddressOfNameOrdinals; // address of ordinal array
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
GetProcAddress() 동작 과정
- AddressOfNames 멤버를 이용해 “함수 이름 배열”로 간다.
- “함수 이름 배열”은 문자열 주소가 저장되어 있다. 문자열 비교(strcmp)를 통해 원하는 함수 이름을 찾는다. (이때 배열의 인덱스를 name_index라고 임시로 정한다)
- AddressOfNameOrdinals 멤버를 이용해 “ordinal 배열”로 간다.
- “Ordinal 배열”에서 name_index로 해당 ordinal 값을 찾는다.
- AddressOfFunctions 멤버를 이용해 “함수 주소 배열(EAT)”로 간다.
- “함수 주소 배열(EAT)”에서 이전에 구한 ordinal을 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻는다.
리원핵 서적에서 나온 EAT 참고 사진
참고)
함수 이름 없이 Ordinal로만 Export된 함수의 주소를 찾을 수도 있다.
그 Ordinal 값에 IMAGE_EXPORT_DIRECTORY.Base 멤버를 뺀 값을 ‘함수 주소 배열’의 인덱스로 하여 해당 함수 주소를 찾을 수 있다.
Dos header
Dos Stub
NT header
file header
FC : machine - 8664
FE : NumberOfSections - 0007
10C : SizeofOptionalHeader - 00F0
10E : Characteristics - 2022
optional header
110 : magic - 020B
120 : address of EntryPoint - 015580
128 : ImageBase - 0000000180000000
130 : SectionAlignment - 1000
134 : FileAlignment - 1000
150 : CheckSum - 000C961F
154 : SubSystem - 0003(CUI)
17C : NumberOfRvaAndSizes - 00000010
180 : dataDirectory[0].VirtualAddress - 000980A0
184 : DataDirectory[0].size - 0000E488
188 : DataDirectory[1].VirtualAddress - A6528
18C : DataDirectory[1].size - 7E4
section header
.text
208 : virtualsize - 0007CDC7
20c : VirtualAddress - 1000
210 : SizeOfRawData - 7D000
214 : PointerToRawData - 1000
.rdata
230 : virtualsize - 000334AC
234 : VirtualAddress - 0007E000
238 : SizeOfRawData - 34000
23C : PointerToRawData - 0007E000
.data
258 : virtualsize - 00001234
25C : VirtualAddress - 000B2000
260 : SizeOfRawData - 1000
264 : PointerToRawData - 000B2000
.pdata
280 : virtualsize - 00005490
284 : VirtualAddress - 000B4000
288 : SizeOfRawData - 6000
28C : PointerToRawData - 000B3000
.didat
2A8 : virtualsize - 000000A8
2AC: VirtualAddress - 000BA0
2B0 : SizeOfRawData - 1000
2B4 : PointerToRawData - 000B9000
.rsrc
2D0 : virtualsize - 00000520
2D4 : VirtualAddress - 000BB000
2D8 : SizeOfRawData - 1000
2DC : PointerToRawData - 000BA000
.reloc
2F8 : virtualsize - 00000334
2FC : VirtualAddress - 000BC000
300 : SizeOfRawData - 1000
304 : PointerToRawData - 000BB000
IMAGE_EXPORT_DIRECTORY
- 중요 멤버 : NumberOfFunctions, NumberOfNames, AddressOfFunctions, AddressOfNames, AddressOfNameOrdinals
- 크기 : 40 byte
typedef struct _IMAGE_EXPORT_DIRECTORY
{
DWORD Characteristics; // creation time date stamp
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name; // address of library file name
DWORD Base; // ordinal base
DWORD NumberOfFunctions; // number of functions
DWORD NumberOfNames; // number of names
DWORD AddressOfFunction; // address of function start address array
DWORD AddressOfNames; // address of function name string array
DWORD AddressOfNameOrdinals; // address of ordinal array
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
GetProcAddress() 동작 원리
- AddressOfNames 멤버를 이용해 “함수 이름 배열”로 간다.
- “함수 이름 배열”은 문자열 주소가 저장되어 있다. 문자열 비교(strcmp)를 통해 원하는 함수 이름을 찾는다. (이때 배열의 인덱스를 name_index라고 임시로 정한다)
- AddressOfNameOrdinals 멤버를 이용해 “ordinal 배열”로 간다.
- “Ordinal 배열”에서 name_index로 해당 ordinal 값을 찾는다.
- AddressOfFunctions 멤버를 이용해 “함수 주소 배열(EAT)”로 간다.
- “함수 주소 배열(EAT)”에서 이전에 구한 ordinal을 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻는다.
참고)
함수 이름 없이 Ordinal로만 Export된 함수의 주소를 찾을 수도 있다.
그 Ordinal 값에 IMAGE_EXPORT_DIRECTORY.Base 멤버를 뺀 값을 ‘함수 주소 배열’의 인덱스로 하여 해당 함수 주소를 찾을 수 있다.
IMAGE_EXPORT_DIRECTORY 구조체 영역
NT_HEADER.IMAGE_OPTIONAL_HEADER.DataDirectory[0].VirtualAddress(EAT(IMAGE_EXPORT_DIRECTORY) 시작 주소) : 980A0
(980A0(RVA) - 7E000(VirtualAddress) + 7E000(PointerToRawData)
- kernel32.dll의 IMAGE_EXPORT_DIRECTORY 구조체
Member | Value(RVA) | RAW |
Characteristics | 00000000 | - |
TimeDateStamp | DDBFE4AA | - |
MajorVersion | 0000 | - |
MinorVersion | 0000 | - |
Name | 00091C82 | 9C182 |
Base | 00000001 | - |
NumberOfFunctions | 00000679 | - |
NumberOfNames | 00000679 | - |
AddressOfFunctions | 000980C8 | 980C8 |
AddressOfNames | 00099AAC | 99AAC |
AddressOfNameOrdinals | 0009B490 | 9B490 |
0. Name
Export 하는 파일의 이름 KERNEL32.dll이 들어있다.
이름 다음으로는 함수들의 이름이 적혀져 있다.
AddAtomW를 확인해보면 11번째에 있고, 9C24D이다.
Offet | Name |
9C18F | AcquireSRWLockExclusive |
9C1A7 | NTDLL |
9C1AD | RtlAcquireSRWLockExclusive |
9C1C8 | AcquireSRWLockShared |
9C1DD | NTDLL |
9C1E3 | RtlAcquireSRWLockShared |
9C1FB | ActivateActCtx |
9C20A | ActivateActCtxWorker |
9C21F | ActivatePackageVirtualizationContext |
9C244 | AddAtomA |
9C24D | AddAtomW |
1. AddressOfNames 함수 이름 배열
아래의 사진은 4byte의 RVA로 이루어진 배열이다.
배열 원소의 개수는 NumberOfNames(679)이다.
이 4byte RVA 값을 하나하나 따라가면 함수 이름 문자열이 나온다.
2. 원하는 함수 이름 찾기
AddAtomW 함수 이름 문자열을 찾아보자
위의 0번에서 KERNEL32.dll 다음에 함수 이름들이 적혀있었고, AddAtomW 함수의 주소는 9C24D였다.
그리고 AddressOfNames 영역에서 AddAtomW에 해당하는 주소를 찾으면 7번에 해당하고, 배열 인덱스로는 6이다.
(AddressOfNames 영역은 99AAC부터 시작하여 4byte의 RVA 값들을 가진다.)
9C24D(RVA) - 7E000(VirtualAddress) + 7E000(PointerToRawData) = 9C24D(RAW)
9C24D(RAW)로 이동하면 아래와 같이 AddAtomW 문자열이 있다.
3. Ordinal 배열
이제 AddAtomW 함수의 Ordinal 값을 알아내자
IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals 멤버의 RAW 값은 9B490이다.
위의 그림과 같이 2byte의 Ordinal로 이루어진 배열이 나타난다.
(ordinal 배열의 각 원소 크기는 2byte이다.)
4. ordinal
2번에서 구한 index 값(6)을 3번의 “Ordinal 배열”에 적용하면 Ordinal(6)을 구할 수 있다.
AddressOfNameOrdinals[index] = ordinal (index = 6, ordinal = 6)
5. 함수 주소 배열 - EAT
마지막으로 AddAtomW의 실제 함수 주소로 찾아갈 수 있는데,
IMAGE_EXPORT_DIRECTORY.AddressOfFunctions 멤버의 RAW 값은 980C8이다.
위의 사진은 AddressOfFuntions 부분이고, Drag되어 파란색으로 표시된 부분부터 시작이다.
AddressOfFunctions은 4byte 함수 주소 RVA 배열이 있고, 모두 Export 함수 주소들이다.
6. AddAtomW 함수 주소
AddressOfFunctions 영역에서 AddAtomW 함수의 주소를 얻기 위해 3번에서 구한 Ordinal을 AddressOfFunctions 영역에서 배열 index로 적용하면 RVA = 000080F0을 얻을 수 있다.
AddressOfFunctions[ordinal] = RVA(ordinal = 6, RVA = 000080F0)
kernel32.dll을 x64dbg에서 로드하여 ImageBase을 확인하면 7FFCB5590000이고
AddAtomW 함수의 실제 주소(VA)는 7FFCB55980F0이다.
(7FFCB5590000(ImageBase) + 80F0(RVA) = 7FFCB55980F0(VA))
x64dbg에서 7FFCB55980F0 주소(VA)를 확인하면 AddAtomW 함수와 관련된 부분이 나온다.
지금까지 살펴본 DLL 파일에서 Export 함수 주소를 찾아내는 방법이 GetProcAddress() API가 특정 함수 주소를 얻어내는 방법과 동일하다.
참고 URL
https://dhhd-goldmilk777.tistory.com/152
'Reversing > 실습' 카테고리의 다른 글
[Reversing 실습] 지뢰찾기.exe DLL Injection (0) | 2022.08.24 |
---|---|
Windows 7 64bit에서 32bit notepad.exe PE 재배치(Base Relocation Table) (0) | 2022.06.19 |
Windows 7 64bit에서 HxD로 32bit notepad.exe PE 파일 EP 영역 확인 (0) | 2022.06.19 |
UPX packer로 notepad.exe 실행 압축한 파일 분석 (0) | 2022.06.13 |
Windows 11 64bit 환경에서 PE 파일(notepad.exe) 분석 냠냠쓰 (3) | 2022.06.07 |