Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

•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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Today... We're talking about How to Build A Software Packer Nope, Is Application Loader

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

A Easy Beginning! #include int main() { MessageBoxA( 0, "hi there.", "info", 0 ); return 0; }

Slide 7

Slide 7 text

Compile Source to Exe File via Visual Studio C++ 2017 Community

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Source Code #include int main() { MessageBoxA( 0, "hi there.", "info", 0 ); return 0; }

Slide 10

Slide 10 text

Source Code → Assembly Codes #include 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

Slide 11

Slide 11 text

based on x86 Calling Convention #include 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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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)

Slide 14

Slide 14 text

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)

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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 :)

Slide 18

Slide 18 text

PE File 101 DOS Program NT Header ⋯⋯ File Header Optional Header DOS Header

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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; }

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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 ); }

Slide 24

Slide 24 text

Example: Process Hollowing (aka RunPE)

Slide 25

Slide 25 text

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 ...

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

ntdll!LdrInitializeThunk [email protected] 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?

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Ntdll.dll ... Process Kernel32.dll User32.dll ... ... Process Chrome WriteProcessMemory() at ImageBase + 0x00 Copy SizeOfHeaders bytes from (malware.exe + 0x00) Image Header Malware.exe

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

.text ... Process Chrome Section 2 Section 3 ... Ntdll.dll Process User32.dll SetThreadContext() & ResumeThread() eax = AddressOfEntryPoint ... Malware.exe Image Header Kernel32.dll

Slide 33

Slide 33 text

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; }

Slide 34

Slide 34 text

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 ...

Slide 35

Slide 35 text

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);

Slide 36

Slide 36 text

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 ); }

Slide 37

Slide 37 text

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);

Slide 38

Slide 38 text

Code & Demo github.com/aaaddress1/RunPE-In-Memory/blob/master/runPE/runPE/runPE.cpp

Slide 39

Slide 39 text

But... We Want to Build a Software Packer. We need to fix IAT by myself :/

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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; }

Slide 42

Slide 42 text

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;

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Exe File (PE) DOS Program OptionalHeader NtHeader ... DataDirectory index Import Address Table ... 12 ... .VirtualAddress .Size IMAGE_IMPORT_DESCRIPTOR

Slide 45

Slide 45 text

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)

Slide 46

Slide 46 text

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); }

Slide 47

Slide 47 text

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;

Slide 48

Slide 48 text

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;

Slide 49

Slide 49 text

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); }

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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); }

Slide 54

Slide 54 text

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; }

Slide 55

Slide 55 text

And What's Relocation?

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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; }

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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) );

Slide 76

Slide 76 text

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) ); }

Slide 77

Slide 77 text

Code & Demo github.com/aaaddress1/RunPE-In-Memory

Slide 78

Slide 78 text

Thanks for listening :) [email protected] Slide Github Project Twitter Facebook