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

加密與保護:揭秘程式保護殼如何防止駭客破解你的產品

229b1596ce57cd0935a2bacd410d87a0?s=47 adr
July 12, 2018

 加密與保護:揭秘程式保護殼如何防止駭客破解你的產品

在 Windows 上許多知名的執行程式都會因為其商業技術不希望被竊取,而替發布的程式套上一層保護殼,免除遭受駭客分析執行程式而找到實現程式技術的細節、甚至挖掘漏洞。
知名的保護殼如: UPX 殼用於壓縮執行程式的大小、VMProtect 殼用於原始碼碼混淆與虛擬機保護、Themida 殼與 WinLicense 殼穩定且難以分析的複合式保護技術。
本議程將基於 Windows 作業系統,介紹 C/C++ 開發時編譯器層級如何產生出執行程式,執行程式(PE)結構體,與裝載器(PE Loader)在進程創建時,如何實現完整執行程式的加載過程;進而深入分析惡意程式如何以 Process Hollowing(aka RunPE)技巧移花接木、注入自身執行程式到系統服務中。
最後議程重點將著重於如何以 C/C++ 實作完整一個簡單的執行程式保護殼,此部分將完整實作使程式從資源中解壓到內存、針對程式區段節正確重新分配內存位址、修正引入函數表與重定向處理。

229b1596ce57cd0935a2bacd410d87a0?s=128

adr

July 12, 2018
Tweet

More Decks by adr

Other Decks in Technology

Transcript

  1. 加密與保護: 揭秘程式保護殼如何防⽌止駭客破解你的產品 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. •Speaker at BlackHat, DEFCON, 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. 3) create first thread of this process, point register eax

    to AddressOfEntry, point ebx+8 (TIB base + 8) to image base, and point eip to ntdll!LdrInitializeThunk Process Process? Kernel (ring0) Application (ring3) 1) create process via CreateProcess() 2) mapping file into memory iexplorer.exe .data section .text section AddressOfEntry ntdll.dll kernel32.dll ...
  26. Process? Process iexplorer.exe ntdll.dll kernel32.dll ... Call Stack -------------- _LdrpSnapModule

    _LdrpMapAndSnapDependency _LdrpMapDllWithSectionHandle _LdrpLoadKnownDll _LdrpFindOrPrepareLoadingModule _LdrpLoadDllInternal _LdrpLoadDll _LdrLoadDll _LdrpInitializeProcess __LdrpInitialize _LdrInitializeThunk fix import address table, fix export directory, apply relocation, etc .text section ntdll!LdrInitializeThunk
  27. ntdll!LdrInitializeThunk AddressOfEntry@.text Process iexplorer.exe .text section ntdll.dll kernel32.dll ... ntdll!RtlUserThreadStart

    RtlUserThreadStart is entry-point of every thread. We can hijack thread via write shellcode address into global variable ‘LdrDelegatedRtlUserThreadStart'. Process?
  28. Ntdll.dll ... Process Kernel32.dll User32.dll ... ... Process Chrome Memory

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

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

    Process User32.dll SetThreadContext() & ResumeThread() eax = AddressOfEntryPoint ... Malware.exe Image Header Kernel32.dll
  33. 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; }
  34. 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 ...
  35. 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);
  36. 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 ); }
  37. 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);
  38. Code & Demo github.com/aaaddress1/RunPE-In-Memory/blob/master/runPE/runPE/runPE.cpp

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

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

    Import Address Table ... 12 ... .VirtualAddress .Size IMAGE_IMPORT_DESCRIPTOR
  45. 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)
  46. 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; DWORD parsedSize = 0; while (parsedSize < maxSize) { IMAGE_IMPORT_DESCRIPTOR* lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)( impAddr + parsedSize + (ULONG_PTR)modulePtr ); ... parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR); }
  47. 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;
  48. 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;
  49. 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); }
  50. 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
  51. 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
  52. 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
  53. 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); }
  54. 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; }
  55. And What's Relocation?

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

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

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

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

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

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

    0x60D110 Access violation
  63. 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
  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 ... index ...

    ... .VirtualAddress .Size IMAGE_BASE_RELOCATION typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; } IMAGE_BASE_RELOCATION; Base Relocation Table 5 DataDirectory
  66. 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; }
  67. 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
  68. 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
  69. 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
  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 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
  71. 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
  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 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
  73. 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
  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 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
  75. 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) );
  76. 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) ); }
  77. Code & Demo github.com/aaaddress1/RunPE-In-Memory

  78. Thanks for listening :) aaaddress1@chroot.org Slide Github Project Twitter Facebook