반응형

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() 동작 과정

 

  1. AddressOfNames 멤버를 이용해 “함수 이름 배열”로 간다.
  2. “함수 이름 배열”은 문자열 주소가 저장되어 있다. 문자열 비교(strcmp)를 통해 원하는 함수 이름을 찾는다. (이때 배열의 인덱스를 name_index라고 임시로 정한다)
  3. AddressOfNameOrdinals 멤버를 이용해 “ordinal 배열”로 간다.
  4. “Ordinal 배열”에서 name_index로 해당 ordinal 값을 찾는다.
  5. AddressOfFunctions 멤버를 이용해 “함수 주소 배열(EAT)”로 간다.
  6. “함수 주소 배열(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() 동작 원리

  1. AddressOfNames 멤버를 이용해 “함수 이름 배열”로 간다.
  2. “함수 이름 배열”은 문자열 주소가 저장되어 있다. 문자열 비교(strcmp)를 통해 원하는 함수 이름을 찾는다. (이때 배열의 인덱스를 name_index라고 임시로 정한다)
  3. AddressOfNameOrdinals 멤버를 이용해 “ordinal 배열”로 간다.
  4. “Ordinal 배열”에서 name_index로 해당 ordinal 값을 찾는다.
  5. AddressOfFunctions 멤버를 이용해 “함수 주소 배열(EAT)”로 간다.
  6. “함수 주소 배열(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

 

 

 

반응형

+ Recent posts