Reverse Engineering/Build Process & Portable Executable

[Reverse Engineering] PE (Portable Executable) Body Structure Analysis

DF_m@ster 2025. 8. 7. 14:16

PE (Portable Executable)

PE (Portable Executable) 정의 : Windows OS에서 실행 가능한 Executable File Format이다. x86 아키텍처의 경우 PE32, x86-64 아키텍처의 경우 PE32+이라고 칭한다.

본 문단은, PE Header 를 제외한 PE Body 를 분석한 글로, PE Header의 구조 분석 글은 아래 링크를 참조 바란다.

 

 

 

PE (Portable Executable) Structure

PE 파일은 아래와 같은 구조로 구성되어 있으며, 각 섹션은 고유의 역할을 수행한다.

PE (Portable Executable) Structure

 

 

 

PE Body

Section Header

Section Header 정의

PE 파일의 각 Section(.text, .data, .rdata 등)의 속성과 메모리 배치 정보를 저장하는 구조체로, ’IMAGE_NT_HEADERS.IMAGE_FILE_HEADER.NumberOfSections’ 값만큼 _IMAGE_SECTION_HEADER 구조체를 읽어 각 Section 정보를 저장한다.

 

Section Header 주요 Field

 - Name : Section의 이름을 나타내며 최대 8 Byte까지 저장 가능하지만, 실제 Section을 구분하는 기준은 Characteristics Flag 값을 기반으로 한다.

 - Virtual Size : PE 파일이 Memory에 Load된 이후, 해당 Section에 할당되는 Memory 영역의 Logical Size이다. 해당 Size는 Padding Size를 포함하지 않은 순수한 Memory 사용량을 의미한다.

 - Virtual Address : PE 파일이 Memory에 Load된 이후, 해당 Section에 할당된 Memory의 시작 주소이다. 해당 값은 Section Alignment의 배수 값을 갖는다.

 - Size of Raw Data : PE 파일이 Disk에서 File 형태로 존재할 때, 해당 Section에 할당된 File 내부의 Pysical Size이다. 해당 값은 File Alignment의 배수 값을 갖는다.

 - Pointer to Raw Data : PE 파일이 Disk에서 File 형태로 존재할 때, 해당 Section에 할당된 File의 시작 주소이다. 해당 값은 File Alignment의 배수 값을 갖는다.

 - Pointer to Relocations : PE 파일이 Disk에서 File 형태로 존재할 때, 현재 Section의 Relocation 정보가 저장된 File의 시작 주소이다. 실행 파일(EXE)은 Relocation 과정이 필요하지 않기 때문에 항상 ‘0x00’ 값을 갖는다.

 - Pointer to Linenumbers : COFF 형식의 디버깅을 위한 Line Number 정보의 파일 내 오프셋으로, 현대 PE 파일에서는 항상 ‘0x00’ 값을 갖는다.

 - Number of Relocations : Section의 재배치 항목 개수이다. 실행 파일(EXE)은 Relocation 과정이 필요하지 않기 때문에 항상 ‘0x00’ 값을 갖는다.

 - Number of Linenumbers : Section의 Line Number 항목 개수로, 현대 PE 파일에서는 항상 ‘0x00’ 값을 갖는다.

 - Characteristics : PE 파일의 각 Section이 가지는 속성(Read/Write/실행 가능 여부/Code 및 Data 포함 여부 등)을 정의하는 4 Byte의 Flag 값이다. 섹션의 구분 기준은 Name이 아니라 Characteristics 값이며, 예를 들어 ‘.data Section’과 ‘.rdata Section’은 ‘IMAGE_SCN_MEM_WRITE’Flag의 존재 여부로 구분된다.

#define IMAGE_SCN_TYPE_NO_PAD                0x00000008  // No padding  
#define IMAGE_SCN_CNT_CODE                   0x00000020  // Section contains executable 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_LNK_OTHER                  0x00000100  // Reserved  
#define IMAGE_SCN_LNK_INFO                   0x00000200  // Section contains comments or other info (valid for object files only)  
#define IMAGE_SCN_LNK_REMOVE                 0x00000800  // Section will not be part of the image (valid for object files only)  
#define IMAGE_SCN_LNK_COMDAT                 0x00001000  // Section contains COMDAT data (valid for object files only)  
#define IMAGE_SCN_GPREL                      0x00008000  // Section contains global pointer referenced data  
#define IMAGE_SCN_MEM_PURGEABLE              0x00020000  // Reserved  
#define IMAGE_SCN_MEM_16BIT                  0x00020000  // Reserved  
#define IMAGE_SCN_MEM_LOCKED                 0x00040000  // Reserved  
#define IMAGE_SCN_MEM_PRELOAD                0x00080000  // Reserved  

// Section alignment (valid for object files only)  
#define IMAGE_SCN_ALIGN_1BYTES               0x00100000  // Align data to 1-byte boundary  
#define IMAGE_SCN_ALIGN_2BYTES               0x00200000  // Align data to 2-byte boundary  
#define IMAGE_SCN_ALIGN_4BYTES               0x00300000  // Align data to 4-byte boundary  
#define IMAGE_SCN_ALIGN_8BYTES               0x00400000  // Align data to 8-byte boundary  
#define IMAGE_SCN_ALIGN_16BYTES              0x00500000  // Align data to 16-byte boundary  
#define IMAGE_SCN_ALIGN_32BYTES              0x00600000  // Align data to 32-byte boundary  
#define IMAGE_SCN_ALIGN_64BYTES              0x00700000  // Align data to 64-byte boundary  
#define IMAGE_SCN_ALIGN_128BYTES             0x00800000  // Align data to 128-byte boundary  
#define IMAGE_SCN_ALIGN_256BYTES             0x00900000  // Align data to 256-byte boundary  
#define IMAGE_SCN_ALIGN_512BYTES             0x00A00000  // Align data to 512-byte boundary  
#define IMAGE_SCN_ALIGN_1024BYTES            0x00B00000  // Align data to 1024-byte boundary  
#define IMAGE_SCN_ALIGN_2048BYTES            0x00C00000  // Align data to 2048-byte boundary  
#define IMAGE_SCN_ALIGN_4096BYTES            0x00D00000  // Align data to 4096-byte boundary  
#define IMAGE_SCN_ALIGN_8192BYTES            0x00E00000  // Align data to 8192-byte boundary  

#define IMAGE_SCN_LNK_NRELOC_OVFL            0x01000000  // Section contains extended relocations  
#define IMAGE_SCN_MEM_DISCARDABLE            0x02000000  // Section can be discarded as needed  
#define IMAGE_SCN_MEM_NOT_CACHED             0x04000000  // Section cannot be cached  
#define IMAGE_SCN_MEM_NOT_PAGED              0x08000000  // Section cannot be paged  
#define IMAGE_SCN_MEM_SHARED                 0x10000000  // Section can be shared in memory  
#define IMAGE_SCN_MEM_EXECUTE                0x20000000  // Section can be executed as code  
#define IMAGE_SCN_MEM_READ                   0x40000000  // Section can be read  
#define IMAGE_SCN_MEM_WRITE                  0x80000000  // Section can be written

 

Section Header Structure (_IMAGE_SECTION_HEADER)

typedef struct _IMAGE_SECTION_HEADER {
    BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; /* 00: Section name (null-terminated or full 8 bytes) */
    union {
        DWORD PhysicalAddress;           /* 08: Physical address (deprecated) */
        DWORD VirtualSize;               /* 08: Virtual size of section */
    } Misc;
    DWORD VirtualAddress;                /* 0C: RVA (Relative Virtual Address) of section */
    DWORD SizeOfRawData;                 /* 10: Size of section data on disk */
    DWORD PointerToRawData;              /* 14: File pointer to section data */
    DWORD PointerToRelocations;          /* 18: File pointer to relocation entries */
    DWORD PointerToLinenumbers;          /* 1C: File pointer to line numbers (deprecated) */
    WORD  NumberOfRelocations;           /* 20: Number of relocations */
    WORD  NumberOfLinenumbers;           /* 22: Number of line numbers (deprecated) */
    DWORD Characteristics;               /* 24: Section characteristics flags */
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

_IMAGE_SECTION_HEADER

 

 

 

Section

Section 정의

각각의 Section의 실제 Data가 저장된 영역이다. 각 Section의 정보는 ‘IMAGE_SECTION_HEADER’에 정의되어 있다.

 

Import Descripter

Import Descripter 정의

PE 파일에서 Import Table을 정의하는 구조체로, 실행 파일이 참조하는 DLL 목록과 각 DLL에서 Import(가져오는) 함수 정보를 포함한다.

 

     - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[12]의 RVA와 Virtual Size를 기반으로, File Offset을 계산하여 접근할 수 있다.

         - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[12]

              - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[12].VirtualAddress = 0x01D000

              - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[12].Size = 0x024C

IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[12]

 

         - IMAGE_SECTION_HEADER

              - IMAGE_SECTION_HEADER.VirtualAddress = 0x01D000

              - IMAGE_SECTION_HEADER.PointeTtoRawData = 0xA600

IMAGE_SECTION_HEADER

 

              - 이때, 계산 방법은 아래와 같다. 여기서 ‘IMAGE_SECTION_HEADER’는 현재 DataDirectory[12]가 갖는 RVA의 Range를 갖는 Section을 의미한다. 일반적으로, Import 정보를 포함하는 ‘.idata’ Section일 확률이 크다.

FileOffset = DataDirectory[12].RVA - IMAGE_SECTION_HEADER.VirtualAddress + IMAGE_SECTION_HEADER.PointerToRawData + DataDirectory[12].VirtualSize

              - 0xA84C = 0x01D000 - 0x01D000 + 0xA600 + 0x024C

FileOffset

 

     - ‘IMAGE_IMPORT_DESCRIPTOR’ 구조체 내부의 RVA는 전부 아래의 과정으로 해석하여 추가적으로 접근한다.

 

 - Import Descripter 주요 속성

     - Original First Thunk : 해당 Import되는 Library의 INT(Import Name Table)의 주소(RVA) 정보를 저장한다.

 

         - INT (Import Name Table) 정의 : PE 파일에서 Import된 함수의 이름(또는 Ordinal 값)을 저장하는 테이블로, 실행 시 PE Loader가 이를 참조하여 IAT(Import Address Table)를 채운다.

 

         - INT (Import Name Table) Structure : Long Type의 4 Byte 자료형으로, 크기가 따로 명시되어 있지 않아 NULL Byte가 나타나면 종료된다.

typedef struct _IMAGE_IMPORT_BY_NAME {
	WORD	Hint;
	BYTE	Name[1];
} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;

Import Name Table

 

     - Name : 해당 Import되는 Library의 String 주소(RVA) 정보를 저장한다.

 

     - First Thunk : 해당 Import되는 Library의 IAT(Import Address Table)의 주소(RVA) 정보를 저장한다.

 

          - IAT (Import Address Table) 정의 : PE 파일이 실행될 때 PE Loader가 실제 DLL 함수의 주소를 채워 넣는 테이블로, 실행 파일이 Import된 함수를 호출할 때 직접 참조하여 호출하게 된다. 파일에 존재할 때, INT와 IAT는 동일한 함수 이름을 가리키지만, PE Loader가 로드하면 INT는 변하지 않고 함수 이름을 유지하며, IAT는 INT를 기반으로 DLL에서 가져온 실제 함수 주소로 덮어써진다.

 

          - IAT (Import Address Table) Structure : Long Type의 4 Byte 자료형으로, 크기가 따로 명시되어 있지 않아 NULL Byte가 나타나면 종료된다.

Import Address Table

 

 

 

Export Descripter

Export Descripter 정의

PE 파일에서 Export Table을 정의하는 구조체로, DLL이 외부에 제공하는 함수 목록과 각 함수의 주소를 포함한다. 이를 통해 다른 PE 파일(EXE, SYS)이 해당 DLL의 기능을 호출할 수 있게된다. 추가적으로, IMAGE_EXPORT_DIRECTORY 구조체는 PE 파일에서 하나만을 갖는다는 특징이 있다.

 

     - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[0]의 RVA와 Virtual Size를 기반으로, File Offset을 계산하여 접근할 수 있다.

         - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[0]

             - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[0].VirtualAddress = 0x01B910

IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[0]

 

         - IMAGE_SECTION_HEADER

              - IMAGE_SECTION_HEADER.VirtualAddress = 0x019000

              - IMAGE_SECTION_HEADER.PointeTtoRawData = 0x8200

IMAGE_SECTION_HEADER

 

              - 이때, 계산 방법은 아래와 같다. 여기서 ‘IMAGE_SECTION_HEADER’는 현재 DataDirectory[0]가 갖는 RVA의 Range를 갖는 Section을 의미한다.

FileOffset = DataDirectory[0].RVA - IMAGE_SECTION_HEADER.VirtualAddress + IMAGE_SECTION_HEADER.PointerToRawData

              - 0xAB10 = 0x01B910 - 0x019000 + 0x8200

FileOffset

 

Export Descripter 주요 속성

     - Name : Export되는 Library의 String 주소(RVA) 정보를 저장한다. Export의 Name String의 경우 현재 File의 Name String을 갖는다.

Export Descripter Name

 

     - Number of Functions : Export되는 Function의 갯수 정보를 저장한다.

     - Number of Names : Export되는 Function 중 Name String을 갖는 Function의 갯수 정보를 저장한다.

     - Address of Functions : 해당 Import되는 Library의 EAT(Export Address Table)의 주소(RVA) 정보를 저장한다. Table의 Entry 갯수는 ‘Number of Functions’ 값을 갖는다.

          - EAT (Export Address Table) 정의 : DLL이 외부에 제공하는 함수들의 실제 메모리 주소를 저장하는 테이블로, 호출 시 해당 주소를 통해 실행된다. EAT는 특정 Function을 Indirect Call(간접 호출)하기 때문에, 호출하려는 함수의 Jump Table을 Pointing한다.

           - EAT (Export Address Table) Structure : Long Type의 4 Byte 자료형이다.

Export Address Table

 

               - Jump Table  (Indirect Call)

                   - 0x06CB = 0x0112CB - 0x011000 + 0x0400

                   - .text Section의 Virtual Address = 0x11000

                   - .text Section의 Pointer to Raw Data = 0x0400

Jump Table

 

               -  0x0B00 = 0x06D0(+0x05) + 0x0430

                   - Jump Table의 Jump Address = 0x0430

                   - 0x89 54 24 10 = mov dword ptr[rsp + 0x10] + edx

                   - 해당 함수의 Disassemble Code와 일치함

mov     [rsp-8 + arg_8], edx
mov     [rsp-8 + arg_0], ecx
push    rbp
push    rdi
sub     rsp, 0E8h
lea     rbp, [rsp + 20h]
lea     rcx, unk_180021001
call    sub_1800112DA
nop
mov     eax, [rbp + 0D0h + arg_0]
imul    eax, [rbp + 0D0h + arg_8]
lea     rsp, [rbp + 0C8h]
pop     rdi
pop     rbp
retn

 

 

 

     -  Address of Names : 해당 Import되는 Library의 ENT(Export Name Table)의 주소(RVA) 정보를 저장한다.

          - ENT (Export Name Table) 정의 : DLL이 외부에 제공하는 함수들의 이름을 저장하는 테이블로, 함수 호출 시 이름을 기반으로 EAT의 주소를 조회하는 역할을 한다.

          -  ENT (Export Name Table) Structure : Long Type의 4 Byte 자료형이다. 

Export Name Table

 

     -   Address of Name Ordinals : 해당 Export되는 Library의 EOT(Export Ordinal Table)의 주소(RVA) 정보를 저장한다. Table의 Entry 갯수는 ‘Number of Names’ 값을 갖는다.

          -  EOT (Export Ordinal Table) 정의 : DLL이 외부에 제공하는 함수들의 Ordinal(숫자 기반 식별자)을 저장하는 테이블로, Ordinal을 이용한 빠른 함수 조회를 가능하게 한다. Function의 Name이 정의되어 있지 않은 경우 Ordinal 값을 활용해 함수를 접근가능하게 한다.

          -  EOT (Export Ordinal Table) Structure : Long Type의 2 Byte 자료형이다.

Export Ordinal Table

 

Export Descripter Load 과정

  1. ‘IMAGE_EXPORT_DIRECTORY’ 구조체의 AddressOfNames 멤버를 기반으로, ENT(Export Name Tabel)에 접근한다.
  2. ENT(Export Name Table)에서 호출하고자하는 Function의 Name String을 Strcpy로 검색한다.
  3. ‘IMAGE_EXPORT_DIRECTORY’ 구조체의 AddressOfNameOrdinals 멤버를 기반으로, EOT(Export Ordinal Table)에 접근한다.
  4. EOT(Export Ordinal Table)에서 이전에 Name String을 검색한 번째의 Entry에 접근하여 Ordinal 값을 획득한다.
  5. ‘IMAGE_EXPORT_DIRECTORY’ 구조체의 AddressOfFunctions 멤버를 기반으로, EAT(Export Address Tabel)에 접근하여 이전에 획득한 Ordinal 값을 기반으로, Function의 Address 값을 획득하여 호출한다.

 

Export Descripter Structure (_IMAGE_EXPORT_DIRECTORY)

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD Characteristics;        /* 00: Reserved, must be 0 */
    DWORD TimeDateStamp;          /* 04: Time and date stamp of the export data */
    WORD  MajorVersion;           /* 08: Major version number (set by user) */
    WORD  MinorVersion;           /* 0A: Minor version number (set by user) */
    DWORD Name;                   /* 0C: RVA to ASCII string containing DLL name */
    DWORD Base;                   /* 10: Starting ordinal number for exports */
    DWORD NumberOfFunctions;      /* 14: Number of functions in the export table */
    DWORD NumberOfNames;          /* 18: Number of named functions */
    DWORD AddressOfFunctions;     /* 1C: RVA to array of function addresses */
    DWORD AddressOfNames;         /* 20: RVA to array of function name RVAs */
    DWORD AddressOfNameOrdinals;  /* 24: RVA to array of function ordinals */
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

 

_IMAGE_EXPORT_DIRECTORY

 

 

 

Jump Table

Jump Table 정의

PE 파일에서 특정 Function의 Address로 이동할 때 사용되는 Indirect Reference Table(간접 참조 테이블)로, VTable(가상 함수 호출) 또는 DLL Import 함수 호출(IAT) 등에 활용된다. 위치는 '.text Section'의 처음 영역에 존재한다.

 

 - Direct Reference (직접 참조) : 메모리 주소를 직접 사용하지 않고, 포인터 또는 테이블을 통해 접근하는 방식으로, Jump Table, VTable, IAT(Import Address Table) 등이 해당된다. 이는, Reference 해야하는 영역의 Memory Address가 동적으로 변환하는 경우에도 오류 없이 처리할 수 있게한다.

 

 - Indirect Reference (간접 참조) : 메모리 주소를 기반으로 직접 접근하는 방식으로, 일반적인 함수 호출(Call <Address>)이나 전역 변수 접근 등이 해당된다.

Jump Table

 

Jump Table 주요 속성

 - IAT와 EAT는 Run Time에서 Reference 해야하는 Memory Address가 변경될 수 있기 때문에, Jump Table을 사용하여 Indirect Reference 방식으로 함수에 접근한다. 이를 통해, 실행 파일이 특정 메모리 주소에 고정적으로 종속되지 않고, 동적 로딩 및 재배치 후 함수 호출을 가능하게 한다.

 

 

 

Base Relocation Table

Base Relocation Table 정의

PE(Portable Executable) 파일에서 VA로 저장된 Symbol의 Address를 저장한 Table이다.

 

구체적으로는 PE 파일이 기존의 예상과 다른 Base Address로 메모리에 로드 될 경우, 하드 코딩된 기존의 VA 값을 새로운 Base Address주소로 재수정해야 할 메모리 주소 목록을 저장하는 Windows의 PE 파일 전용 Relocation Table이다.

 

CALL 명령어나 PTR 변수는 메모리의 절대 주소(Absolute VA)로 저장하여 사용한다. 때문에 PE 파일이 로드될 때 Base Address가 변경되면, CALL 및 PTR 과 같은 절대 주소들도 새로운 Base Address를 반영하도록 재수정해야 한다. 이를 위해 VA로 저장된 즉 수정해야하는 Address를 모은 Table이 Base Relocation Table이며, PE 파일이 로드 되면 OS에서 제공해주는 Base Address를 참고하여 변경된 주소 값으로 업데이트한다.

 

 - Relocation Table 정의 : 실행 파일에서 VA로 저장된 Symbol의 Address를 저장한 Table이다. 해당 개념은 주로 광범위한 개념으로, 다양한 환경에서의 재배치 Table을 통틀어 의미한다.

 

     - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[5]의 RVA와 Virtual Size를 기반으로, File Offset을 계산하여 접근할 수 있다.

 

     - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[5]

          - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[5].VirtualAddress = 0x026000

          - IMAGE_NT_HEADERS.IMAGE_OPTIONAL_HEADER.DataDirectory[5].Size = 0x68

 

     - IMAGE_SECTION_HEADER

          - IMAGE_SECTION_HEADER.VirtualAddress = 0x026000

          - IMAGE_SECTION_HEADER.PointeTtoRawData = 0x010E00

 

     - 이때, 계산 방법은 아래와 같다. 여기서 ‘IMAGE_SECTION_HEADER’는 현재 DataDirectory[5]가 갖는 RVA의 Range를 갖는 Section을 의미한다. 일반적으로, Import 정보를 포함하는 ‘.reloc’ Section일 확률이 크다.

FileOffset = DataDirectory[5].RVA - IMAGE_SECTION_HEADER.VirtualAddress + IMAGE_SECTION_HEADER.PointerToRawData

     - 0x10E68 = 0x026000 - 0x026000 + 0x010E00 ~ 0x68

Relocation Table

 

Base Relocation Table 주요 속성

 - Virtual Address : Relocation이 필요한 VA가 존재하는 영역의 시작 RVA이다. 해당 값은 Section Alignment 값을 기준으로, 구분된다.

 - Size of Block : IMAGE_BASE_RELOCATION 구조체의 전체 Size 정보를 나타낸다.

 - Type Offset : 상위 4 Bit는 Type 정보를 저장하고, 하위 12 Bit는 Offset 정보를 저장한다.

      - (TypeOffset[i] >> 12) & 0xF : Pointing하는 VA의 Type 정보를 저장한다. 일반적으로 x86의 경우 IMAGE_REL_BASED_HIGHLOW (0x03) 값을 갖고, x86-64의 경우 IMAGE_REL_BASED_DIR64 (0x10) 값을 갖는다.

      - TypeOffset[i] & 0xFFF : Pointing하는 VA의 Offset 정보를 저장한다. 이때, 동일한 IMAGE_BASE_RELOCATION 구조체의 VirtualAddress 값과 더하여 접근한다.

Base Relocation Table

 

Base Relocation Table의 Entry 접근

 - 첫 번째 IMAGE_BASE_RELOCATION 구조체의 경우, RVA와 Offset은 각각 0x01A000과 0x0110 값을 갖는다. 때문에, Base Address가 변경될 경우 업데이트 해야하는 VA의 RVA는 0x01A110이 된다. File Offset의 경우, .rdata Section의 VirtualAddress와 PointerToRawData 값은 각각 0x1A000과 0x09400 값을 갖는다. 때문에, File Offset은 0x09510 값을 갖는다.

 - 해당 주소로 접근하면, VA 값이 존재한다.

 

 - xdbg로 해당 exe를 실행하고 접근해보면, 새롭게 할당된 Base Address를 기반으로 업데이트 됨을 확인할 수 있다.

 

Base Relocation Table Structure (_IMAGE_BASE_RELOCATION)

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD VirtualAddress;  /* 00: RVA of the page that needs relocation */
    DWORD SizeOfBlock;     /* 04: Size of the entire relocation block, including entries */
    // WORD  TypeOffset[1]; 08: Array of type/offset entries (variable size) */
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;
// (IMAGE_BASE_RELOCATION.TypeOffset[i] >> 12) & 0xF
#define IMAGE_REL_BASED_ABSOLUTE        0  /* No relocation required */
#define IMAGE_REL_BASED_HIGH            1  /* High 16 bits of a 32-bit address */
#define IMAGE_REL_BASED_LOW             2  /* Low 16 bits of a 32-bit address */
#define IMAGE_REL_BASED_HIGHLOW         3  /* 32-bit address relocation */
#define IMAGE_REL_BASED_HIGHADJ         4  /* Adjusted high 16 bits */
#define IMAGE_REL_BASED_MIPS_JMPADDR    5  /* MIPS jump address */
#define IMAGE_REL_BASED_ARM_MOV32A      5  /* ARM MOVW/MOVT relocation */
#define IMAGE_REL_BASED_ARM_MOV32       5  /* ARM MOVW/MOVT relocation */
#define IMAGE_REL_BASED_SECTION         6  /* Section-relative relocation */
#define IMAGE_REL_BASED_REL             7  /* Offset relative to section start */
#define IMAGE_REL_BASED_ARM_MOV32T      7  /* ARM MOVW/MOVT relocation (same as 7) */
#define IMAGE_REL_BASED_THUMB_MOV32     7  /* Thumb MOVW/MOVT relocation (same as 7) */
#define IMAGE_REL_BASED_MIPS_JMPADDR16  9  /* MIPS16 jump address */
#define IMAGE_REL_BASED_IA64_IMM64      9  /* IA-64 64-bit immediate relocation (same as 9) */
#define IMAGE_REL_BASED_DIR64           10 /* 64-bit address relocation */
#define IMAGE_REL_BASED_HIGH3ADJ        11 /* Adjusted high 16 bits for 64-bit architecture */

 

_IMAGE_BASE_RELOCATION