findSymbolByHash
function that can be used to find exported symbols in loaded DLLs.findKernel32Base
and findSymbolByHash
functions, instead of relying on hard-coded API locations.Example 19-7. Position-independent Hello World
mov ebp, esp sub esp, 24h call sub_A0 ❶ ; call to real start of code db 'user32',0 ❷ db 'Hello World!!!!',0 sub_A0: pop ebx ; ebx gets pointer to data call findKernel32Base ❸ mov [ebp-4], eax ; store kernel32 base address push 0EC0E4E8Eh ; LoadLibraryA hash push dword ptr [ebp-4] call findSymbolByHash ❹ mov [ebp-14h], eax ; store LoadLibraryA location lea eax, [ebx] ❺ ; eax points to "user32" push eax call dword ptr [ebp-14h] ; LoadLibraryA mov [ebp-8], eax ; store user32 base address push 0BC4DA2A8h ❻ ; MessageBoxA hash push dword ptr [ebp-8] ; user32 dll location call findSymbolByHash mov [ebp-0Ch], eax ; store MessageBoxA location push 73E2D87Eh ; ExitProcess hash push dword ptr [ebp-4] ; kernel32 dll location call findSymbolByHash mov [ebp-10h], eax ; store ExitProcess location xor eax, eax lea edi, [ebx+7] ; edi:= "Hello World!!!!" pointer push eax ; uType: MB_OK push edi ; lpCaption push edi ; lpText push eax ; hWnd: NULL call dword ptr [ebp-0Ch] ; call MessageBoxA xor eax, eax push eax ; uExitCode call dword ptr [ebp-10h] ; call ExitProcess
The code begins by using a call
/pop
at ❶ to obtain a pointer to the data starting at ❷. It then calls findKernel32Base
at ❸ to find kernel32.dll and calls findSymbolByHash
at ❹ to find the export in kernel32.dll with the hash 0xEC0E4E8E. This is the ror-13-additive hash of the string LoadLibraryA
. When this function returns EAX, it will point to the actual memory location for LoadLibraryA
.
The code loads a pointer to the "user32"
string at ❺ and calls the LoadLibraryA
function. It then finds the exported function MessageBoxA
at ❻ and calls it to display the “Hello World!!!!” message. Finally, it calls ExitProcess
to cleanly exit.