Save 37% off PRO during our Black Friday Sale! »

Implementing Software Packer@VXCON

229b1596ce57cd0935a2bacd410d87a0?s=47 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

229b1596ce57cd0935a2bacd410d87a0?s=128

adr

April 20, 2018
Tweet

Transcript

  1. Implementing Software Packer aaaddress1@chroot.org

  2. •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
  3. Today... We're talking about How to Build A Software Packer

  4. Today... We're talking about How to Build A Software Packer

    Nope, Is Application Loader
  5. 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
  6. A Easy Beginning! #include <Windows.h> int main() { MessageBoxA( 0,

    "hi there.", "info", 0 ); return 0; }
  7. Compile Source to Exe File via Visual Studio C++ 2017

    Community
  8. General Compiler Source.cpp Object Files Main.exe Compiler Assembly Codes Assembler

    Linker
  9. Source Code #include <Windows.h> int main() { MessageBoxA( 0, "hi

    there.", "info", 0 ); return 0; }
  10. 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
  11. 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
  12. 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
  13. 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)
  14. 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)
  15. 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
  16. 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
  17. 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 :)
  18. PE File 101 DOS Program NT Header ⋯⋯ File Header

    Optional Header DOS Header
  19. 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
  20. 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; }
  21. 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
  22. 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
  23. 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 ); }
  24. Example: Process Hollowing (aka RunPE)

  25. ntdll!LdrVerifyImageMatchesChecksum

  26. ntdll!LdrVerifyImageMatchesChecksumEx

  27. None
  28. None
  29. Ntdll.dll ... Process Kernel32.dll User32.dll ... ... Process Chrome Memory

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

    at ImageBase + 0x00 Copy SizeOfHeaders bytes from (malware.exe + 0x00) Image Header Malware.exe
  31. 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
  32. 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
  33. .text ... Process Chrome Section 2 Section 3 ... Ntdll.dll

    Process User32.dll SetThreadContext() & ResumeThread() eax = AddressOfEntryPoint ... Malware.exe Image Header Kernel32.dll
  34. 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; }
  35. 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 ...
  36. pImageBase = VirtualAllocEx( PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase), NtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    WriteProcessMemory( PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
  37. 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 ); }
  38. 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);
  39. Code & Demo github.com/aaaddress1/RunPE-In-Memory/blob/master/runPE/runPE/runPE.cpp

  40. But... We Want to Build a Software Packer. We need

    to fix IAT by myself :/
  41. 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
  42. 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; }
  43. 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;
  44. 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
  45. Exe File (PE) DOS Program OptionalHeader NtHeader ... DataDirectory index

    Import Address Table ... 12 ... .VirtualAddress .Size IMAGE_IMPORT_DESCRIPTOR
  46. 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)
  47. 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); }
  48. 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;
  49. 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;
  50. 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); }
  51. 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
  52. 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
  53. 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
  54. 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); }
  55. 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; }
  56. And What's Relocation?

  57. Process Main.exe .text Address 0x400000 0x401000 ... .idata 0x40D000 .rdata

    0x40D110
  58. Process Main.exe .text Address 0x400000 0x401000 ... .idata 0x40D000 .rdata

    0x40D110
  59. 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
  60. Process Main.exe .text Address 0x400000 0x401000 ... .idata 0x40D000 .rdata

    0x40D110
  61. Process Main.exe .text Address 0x500000 0x501000 ... .idata 0x50D000 .rdata

    0x50D110
  62. Process Main.exe .text Address 0x600000 0x601000 ... .idata 0x60D000 .rdata

    0x60D110
  63. Process Main.exe .text Address 0x600000 0x601000 ... .idata 0x60D000 .rdata

    0x60D110 Access violation
  64. 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
  65. 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
  66. 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
  67. 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; }
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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) );
  77. 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) ); }
  78. Code & Demo github.com/aaaddress1/RunPE-In-Memory

  79. Thanks for listening :) aaaddress1@chroot.org Slides Github Project