Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Implementing Software Packer@VXCON

adr
April 20, 2018

Implementing Software Packer@VXCON

Software developers wish to prevent their applications from cracking, analyzing by others, even looking for vulnerabilities. Generally, developers protect their applications by software packer, e.g. reducing the size of software by UPX Packer, using VMProtect Packer to obfuscate the execution logic, or using Themida Packer to deal with more complicated issues.

* What's PE structure?
* How compilers build a PE like executable file
* The logic of creating processes in PE Loader
* Case Study- RunPE — Malware Injection like a Loader
* Build your packer in C

adr

April 20, 2018
Tweet

More Decks by adr

Other Decks in Technology

Transcript

  1. •Core member of CHROOT Security Group and TDOHacker security community

    in Taiwan.
 •Ten years of experience in reverse engineering and machine language, also mastered the intel 8086. Expert in Windows vulnerability, reverse engineering. •Many papers presented in security conferences such as BSidesLV, ICNC, MC2015 and CISC.
 •Speaker at BlackHat Asia Arsenal, HITCON (Hackers In Taiwan Conference), SITCON (Students In Taiwan Conference), iThome#Chatbot. ./bio
  2. Exe File? The Portable Executable (PE) format is a file

    format for executables, object code, DLLs, FON Font files, and others used in 32-bit and 64-bit versions of Windows operating systems. The PE format is a data structure that encapsulates the information necessary for the Windows OS loader to manage the wrapped executable code. This includes dynamic library references for linking, API export and import tables, resource management data and thread-local storage (TLS) data. On NT operating systems, the PE format is used for EXE, DLL, SYS (device driver), and other file types. https://en.wikipedia.org/wiki/Portable_Executable
  3. Source Code → Assembly Codes #include <Windows.h> int main() {

    MessageBoxA( 0, "hi there.", "info", 0 ); return 0; } push 0 push "info" push "hi there." push 0 call MessageBoxA xor eax, eax ret
  4. based on x86 Calling Convention #include <Windows.h> int main() {

    MessageBoxA( 0, "hi there.", "info", 0 ); return 0; } push 0 push "info" push "hi there." push 0 call MessageBoxA xor eax, eax ret
  5. xor eax, eax ret push 0 push "info" push "hi

    there." push 0 call MessageBoxA 0xdead: "info" 0xbeef: "hi there." .rdata section 0xcafe: 0x7630EA99 .idata section (Import Address Table) How Compiler Works
  6. xor eax, eax ret push 0 push offset "info" push

    offset "hi there." push 0 call MessageBoxA 0xdead: "info" 0xbeef: "hi there." .rdata section 0xcafe: 0x7630EA99 How Linker Works .idata section (Import Address Table)
  7. xor eax, eax ret push 0 push 0xdead push 0xbeef

    push 0 call ds:0xcafe 0xdead: "info" 0xbeef: "hi there." .rdata section 0xcafe: 0x7630EA99 How Linker Works .idata section (Import Address Table)
  8. Assembler Works push 0 ; 6A 00 push 0xdead ;

    68 AD DE 00 00 push 0xbeef ; 68 EF BE 00 00 push 0 ; 6A 00 call ds:0xcafe ; FF 15 FE CA 00 00 xor eax, eax ; 33 C0 ret ; C3
  9. Main.exe .text Section 6A 00 68 AD DE 00 00

    68 EF BE 00 00 6A 00 FF 15 FE CA 00 00 33 C0 C3 0xdead: "info" 0xbeef: "hi there." 0xcafe: 0x7630EA99 .rdata Section .idata Section
  10. There's 3 issues We need to Deal with: • Where

    The Exe File Data Should be Placed • How to Place Each Section in Memory • Fix The Import Address Table (IAT) So... Let's Take a Look at PE Structure :)
  11. PE File 101 DOS Program NT Header ⋯⋯ File Header

    Optional Header DOS Header 1.DOSHeader starts with 'MZ'
 2.DOSHeader->e_lfanew point to NT Header
  12. BYTE* getNtHdrs(BYTE *pe_buffer) { if (pe_buffer == NULL) return NULL;

    IMAGE_DOS_HEADER *idh;= (IMAGE_DOS_HEADER *)pe_buffer; if (idh->e_magic != IMAGE_DOS_SIGNATURE) return NULL; IMAGE_NT_HEADERS32 *inh; inh = (IMAGE_NT_HEADERS32 *)( (BYTE*)pe_buffer + pe_offset ); if (inh->Signature != IMAGE_NT_SIGNATURE) return NULL; return (BYTE*)inh; }
  13. Exe File (PE) DOS Program OptionalHeader NtHeader ... .ImageBase (0x400000)

    .SizeOfHeaders File Header .NumberOfSections .AddressOfEntryPoint SizeOfHeaders Section Header 1 (.text) ... sizeof(Section Header) = IMAGE_SIZEOF_SECTION_HEADER = 40(fixed) .SizeOfImage Section Header 2 Section Header 3 Section Data 1 (.text) .DataDirectory
  14. Exe File (PE) DOS Program NtHeader ... Section Header 1

    (.text) ... Section Header 2 Section Header 3 Section Data 1 (.text) SectionHeader[i] = PIMAGE_SECTION_HEADER( NtHeader + sizeof(IMAGE_NT_HEADERS) + IMAGE_SIZEOF_SECTION_HEADER * index ); IMAGE SECTION HEADER .VirtualAddress .SizeOfRawData .PointerToRawData
  15. IMAGE_NT_HEADERS32 *ntHeader; ntHeader = (IMAGE_NT_HEADERS32 *)getNtHdrs(data); memcpy(pImageBase, data, ntHeader->OptionalHeader.SizeOfHeaders); int

    maxNum = ntHeader->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER * SectionHeader; for (DWORD count = 0; count < maxNum; count++) { SectionHeader = (IMAGE_SECTION_HEADER *)( DWORD(ntHeader) + sizeof(IMAGE_NT_HEADERS) + IMAGE_SIZEOF_SECTION_HEADER * count ); memcpy( LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), LPVOID(DWORD(data) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData ); }
  16. Ntdll.dll ... Process Kernel32.dll User32.dll ... ... Process Chrome Memory

    Allocated VirtualAllocEx() (Length = SizeOfImage) 0x400000 Malware.exe Allocate memory at ImageBase(0x400000)
  17. Ntdll.dll ... Process Kernel32.dll User32.dll ... ... Process Chrome WriteProcessMemory()

    at ImageBase + 0x00 Copy SizeOfHeaders bytes from (malware.exe + 0x00) Image Header Malware.exe
  18. DOS Program ... malware.exe ... Process Chrome NtHeader Section Header

    1 Section Data 1 ... .VirtualAddress = 0xbeef Space@beef .PointerToRawData .SizeOfRawData copy SizeOfRaowData bytes from PointerToRawData via WriteProcessMemory() Image Header
  19. Space@beef Section Header 1 ... malware.exe ... Process Chrome NtHeader

    Section Header2 Section Data 2 ... .VirtualAddress = 0xcafe Space@cafe .PointerToRawData .SizeOfRawData copy SizeOfRaowData bytes from PointerToRawData via WriteProcessMemory() Image Header DOS Program
  20. .text ... Process Chrome Section 2 Section 3 ... Ntdll.dll

    Process User32.dll SetThreadContext() & ResumeThread() eax = AddressOfEntryPoint ... Malware.exe Image Header Kernel32.dll
  21. BYTE* MapFileToMemory(LPCSTR filename, LONGLONG &filelen){ FILE *fileptr; BYTE *buffer; fileptr

    = fopen(filename, "rb"); fseek(fileptr, 0, SEEK_END); filelen = ftell(fileptr); rewind(fileptr); buffer = (BYTE *)malloc((filelen + 1) * sizeof(char)); fread(buffer, filelen, 1, fileptr); fclose(fileptr); return buffer; }
  22. DOSHeader = PIMAGE_DOS_HEADER(Image); NtHeader = PIMAGE_NT_HEADERS( DWORD(Image) + DOSHeader->e_lfanew );

    // process in suspended state, for the new image. if (CreateProcessA( path, 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &SI, &PI)) { if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) { //if context is in thread ...
  23. int maxNum = NtHeader->FileHeader.NumberOfSections; for (int count = 0; count

    < maxNum; count++) { SectionHeader = PIMAGE_SECTION_HEADER( DWORD(NtHeader) + sizeof(IMAGE_NT_HEADERS) + IMAGE_SIZEOF_SECTION_HEADER * count ); WriteProcessMemory( PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0 ); }
  24. WriteProcessMemory( PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&pImageBase), sizeof(DWORD), 0 ); CTX->Eax

    = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint; SetThreadContext(PI.hThread, LPCONTEXT(CTX)); //Start the process/call main() ResumeThread(PI.hThread);
  25. Exe File (PE) DOS Program OptionalHeader NtHeader ... .ImageBase (0x400000)

    .SizeOfHeaders File Header .NumberOfSections .AddressOfEntryPoint SizeOfHeaders Section Header 1 (.text) ... sizeof(Section Header) = IMAGE_SIZEOF_SECTION_HEADER = 40(fixed) .SizeOfImage Section Header 2 Section Header 3 Section Data 1 (.text) .DataDirectory
  26. IMAGE_DATA_DIRECTORY* getPeDir(PVOID pe_buffer, DWORD dir_id) { if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES)

    return NULL; IMAGE_NT_HEADERS32* nt_header; nt_header = (IMAGE_NT_HEADERS32*)getNtHdrs((BYTE *)pe_buffer); if (nt_header == NULL) return NULL; IMAGE_DATA_DIRECTORY* peDir = NULL; peDir = &(nt_header->OptionalHeader.DataDirectory[dir_id]); if (peDir->VirtualAddress == NULL) return NULL; return peDir; }
  27. Exe File (PE) DOS Program OptionalHeader NtHeader ... DataDirectory Export

    Directory index 0 Import Directory 1 Exception Directory 2 Security Directory Base Relocation Table Resource Directory Import Address Table 3 4 5 ... 12 ... IMAGE_DATA_DIRECTORY[16] typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
  28. Exe File (PE) DOS Program OptionalHeader NtHeader ... DataDirectory index

    Import Address Table ... 12 ... typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; .VirtualAddress .Size
  29. Exe File (PE) DOS Program OptionalHeader NtHeader ... DataDirectory index

    Import Address Table ... 12 ... .VirtualAddress .Size IMAGE_IMPORT_DESCRIPTOR
  30. IMAGE_IMPORT_DESCRIPTOR Array IMAGE_IMPORT_DESCRIPTOR 1 IMAGE_IMPORT_DESCRIPTOR 2 IMAGE_IMPORT_DESCRIPTOR 3 ... \x00\x00\x00\x00\x00\x00\x00

    Fixed Size Fixed Size Fixed Size Exe File (PE) OptionalHeader DataDirectory index Import Address Table 12 .VirtualAddress .Size sizeof(IMAGE_IMPORT_DESCRIPTOR) NT Header sizeof(Descriptor Array)
  31. bool fixIAT(PVOID modulePtr) { printf("[+] Fix Import Address Table\n"); IMAGE_DATA_DIRECTORY

    *importsDir = getPeDir( modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT ); if (importsDir == NULL) return false; DWORD maxSize = importsDir->Size; DWORD impAddr = importsDir->VirtualAddress; IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL; DWORD parsedSize = 0; while (parsedSize < maxSize) { lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)( impAddr + parsedSize + (ULONG_PTR)modulePtr ); ... parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR); }
  32. IMAGE_IMPORT_DESCRIPTOR typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics;// 0

    for terminating null import descriptor DWORD OriginalFirstThunk;// RVA to original unbound IAT (PIMAGE_THUNK_DATA) } DUMMYUNIONNAME; DWORD TimeDateStamp;// 0 if not bound, // -1 if bound, and real date\time stamp // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) // O.W. date/time stamp of DLL bound to (Old BIND) DWORD ForwarderChain; // -1 if no forwarders DWORD Name; DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) } IMAGE_IMPORT_DESCRIPTOR; typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
  33. IMAGE_IMPORT_DESCRIPTOR 1 Exe File (PE) OptionalHeader DataDirectory index Import Address

    Table 12 .VirtualAddress .Size NT Header .OriginalFirstThunk .FirstThunk .Name (User32.dll) IMAGE_IMPORT_BY_NAME: MessageBoxA typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; CHAR Name[1]; } IMAGE_IMPORT_BY_NAME;
  34. while (parsedSize < maxSize) { lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)( impAddr +

    parsedSize + (ULONG_PTR)modulePtr ); if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) break; LPSTR lib_name = (LPSTR)((DWORD)modulePtr + lib_desc->Name); printf(" [+] Import DLL: %s\n", lib_name); DWORD call_via = lib_desc->FirstThunk; DWORD thunk_addr = lib_desc->OriginalFirstThunk; if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk; ... parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR); }
  35. xor eax, eax ret push 0 push 0xdead push 0xbeef

    push 0 call ds:0xcafe IMAGE_IMPORT_DESCRIPTOR 1 Exe File (PE) OptionalHeader DataDirectory index Import Address Table 12 .VirtualAddress .Size NT Header .OriginalFirstThunk .FirstThunk = 0xcafe .Name (User32.dll) IMAGE_IMPORT_BY_NAME: MessageBoxA
  36. IMAGE_IMPORT_DESCRIPTOR 1 Exe File (PE) OptionalHeader DataDirectory index Import Address

    Table 12 .VirtualAddress .Size NT Header .FirstThunk = 0xcafe .FirstThunk .Name (User32.dll) IMAGE_IMPORT_BY_NAME: MessageBoxA HANDLE mod = LoadLibrary("User32.dll"); GetProcAddress(mod, "MessageBoxA") = 0x7547EA99 0x7547EA99
  37. Thunk Array IMAGE_IMPORT_DESCRIPTOR 1 Exe File (PE) OptionalHeader DataDirectory index

    Import Address Table 12 .VirtualAddress .Size NT Header MessageBoxA: *(uint32_t *)0xcafe = 0x7547EA99 .FirstThunk = 0xcafe .Thunk = 0xcaff .Thunk = 0xcb00 .Thunk = 0xcb02 .Name (User32.dll) LoadStringA: *(uint32_t *)0xcaff = 0x75130D4D KillTimer: *(uint32_t *)0xcb01 = 0x754364C7 Lastest Thunk: *(uint32_t *)0xcb02 = NULL
  38. DWORD offsetField = 0; DWORD offsetThunk = 0; while (true)

    { IMAGE_THUNK_DATA32* fieldThunk = (IMAGE_THUNK_DATA32*)( DWORD(modulePtr) + offsetField + call_via ); IMAGE_THUNK_DATA32* orginThunk = (IMAGE_THUNK_DATA32*)( DWORD(modulePtr) + offsetThunk + thunk_addr ); if (fieldThunk->u1.Function == NULL) break; ... offsetField += sizeof(IMAGE_THUNK_DATA32); offsetThunk += sizeof(IMAGE_THUNK_DATA32); }
  39. if (fieldThunk->u1.Function == orginThunk->u1.Function) { PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)( DWORD(modulePtr)

    + orginThunk->u1.AddressOfData ); LPSTR func_name = (LPSTR)by_name->Name; DWORD addr = (DWORD)GetProcAddress( LoadLibraryA(lib_name), func_name ); printf(" [V] API %s at %x\n", func_name, addr); fieldThunk->u1.Function = addr; }
  40. Address space layout randomization (ASLR) Address space layout randomization (ASLR)

    is a computer security technique involved in preventing exploitation of memory corruption vulnerabilities. In order to prevent an attacker from reliably jumping to, for example, a particular exploited function in memory, ASLR randomly arranges the address space positions of key data areas of a process, including the base of the executable and the positions of the stack, heap and libraries. https://en.wikipedia.org/wiki/Address_space_layout_randomization
  41. Exe File (PE) DOS Program OptionalHeader NtHeader ... Export Directory

    index 0 Import Directory 1 Exception Directory 2 Security Directory Base Relocation Table Resource Directory Import Address Table 3 4 5 ... 12 ... IMAGE_DATA_DIRECTORY[16] typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; DataDirectory
  42. Exe File (PE) DOS Program OptionalHeader NtHeader ... Export Directory

    index 0 Import Directory 1 Exception Directory 2 Security Directory Base Relocation Table Resource Directory Import Address Table 3 4 5 ... 12 ... IMAGE_DATA_DIRECTORY[16] typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; DataDirectory
  43. Exe File (PE) DOS Program OptionalHeader NtHeader ... index ...

    ... .VirtualAddress .Size IMAGE_BASE_RELOCATION typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BASE_RELOCATION; Base Relocation Table 5 DataDirectory
  44. IMAGE_DATA_DIRECTORY* relocDir = getPeDir( modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC ); /* Cannot relocate

    - application have no relocation table */ if (relocDir == NULL) return false; DWORD maxSize = relocDir->Size; DWORD relocAddr = relocDir->VirtualAddress; IMAGE_BASE_RELOCATION* reloc = NULL; DWORD parsedSize = 0; while (parsedSize < maxSize) { reloc = (IMAGE_BASE_RELOCATION*)( relocAddr + parsedSize + DWORD(modulePtr)); if (reloc->VirtualAddress == NULL || reloc->SizeOfBlock == 0) break; ... parsedSize += reloc->SizeOfBlock; }
  45. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header SizeOfBlock IMAGE_BASE_RELOCATION 2 VirtualAddress SizeOfBlock IMAGE_BASE_RELOCATION 3 ... Relocation Table DataDirectory
  46. typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type

    : 4; } BASE_RELOCATION_ENTRY; OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5 IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 1 _BASE_RELOCATION_ENTRY 2 _BASE_RELOCATION_ENTRY 3 ... SizeOfBlock We can get the count of RELOCATION_ENTRY by: (SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(RELOCATION_ENTRY) = (SizeOfBlock - 2 * sizeof(DWORD)) / 2; DataDirectory
  47. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 1 SizeOfBlock 0x1000 Offset: 0x003 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8194100 - push 004119E8 00601007 - 68 F0194100 - push 004119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D14000 - call dword ptr [0040D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  48. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 1 SizeOfBlock 0x1000 Offset: 0x003 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8196100 - push 006119E8 00601007 - 68 F0194100 - push 004119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D14000 - call dword ptr [0040D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  49. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 2 SizeOfBlock 0x1000 Offset: 0x008 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8196100 - push 006119E8 00601007 - 68 F0194100 - push 004119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D14000 - call dword ptr [0040D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  50. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 2 SizeOfBlock 0x1000 Offset: 0x008 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8196100 - push 006119E8 00601007 - 68 F0196100 - push 006119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D14000 - call dword ptr [0040D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  51. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 3 SizeOfBlock 0x1000 Offset: 0x010 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8196100 - push 006119E8 00601007 - 68 F0196100 - push 006119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D14000 - call dword ptr [0040D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  52. OptionalHeader index ... ... .VirtualAddress .Size Base Relocation Table 5

    IMAGE_BASE_RELOCATION 1 VirtualAddress Exe File (PE) NT Header _BASE_RELOCATION_ENTRY 3 SizeOfBlock 0x1000 Offset: 0x010 Type: 03 ... 00601000 - 6A 00 - push 00 00601002 - 68 E8196100 - push 006119E8 00601007 - 68 F0196100 - push 006119F0 0060100C - 6A 00 - push 00 0060100E - FF 15 08D16000 - call dword ptr [0060D108] ... typedef struct _BASE_RELOCATION_ENTRY { WORD Offset : 12; WORD Type : 4; } BASE_RELOCATION_ENTRY; #define RELOC_32BIT_FIELD 3 #define RELOC_64BIT_FIELD 0xA DataDirectory
  53. DWORD entriesNum = ( reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof(BASE_RELOCATION_ENTRY);

    DWORD page = reloc->VirtualAddress; BASE_RELOCATION_ENTRY* entry = (BASE_RELOCATION_ENTRY*)( DWORD(reloc) + sizeof(IMAGE_BASE_RELOCATION) );
  54. for (DWORD i = 0; i < entriesNum; i++) {

    DWORD offset = entry->Offset; DWORD type = entry->Type; DWORD reloc_field = page + offset; if (entry == NULL || type == 0) break; DWORD* relocateAddr = (DWORD*)(DWORD(modulePtr) + reloc_field); (*relocateAddr) = ((*relocateAddr) - oldBase + newBase); printf(" [V] Apply Reloc Field at %x\n", relocateAddr); entry = (BASE_RELOCATION_ENTRY*)( DWORD(entry) + sizeof(BASE_RELOCATION_ENTRY) ); }