分类: WINDOWS
2009-11-06 13:16:39
For shellcode, a common method to resolve the addresses of library functions needed, is to get the base address of the kernel32.dll image in memory and retrieve the addresses of GetProcAddress and LoadLibraryA by parsing the kernel32 images Export Address Table (EAT). These two functions can then be used to resolve the remaining functions needed by the shellcode. To retrieve the kernel32.dll base address most shellcodes use the Process Environment Block (PEB) structure to retrieve a list of modules currently loaded in the processes address space. The InInitializationOrder module list pointed to by the PEB's Ldr structure holds a linked list of modules. Typically the second entry in this list has always been that of kernel32.dll. The code used to retrieve the kernel32 base address based on this method is shown below:
xor ebx, ebx // clear ebx
mov ebx, fs:[ 0x30 ] // get a pointer to the PEB
mov ebx, [ ebx + 0x0C ] // get PEB->Ldr
mov ebx, [ ebx + 0x1C ] // get PEB->Ldr.InInitializationOrderModuleList.Flink (1st entry)
mov ebx, [ ebx ] // get the next entry (2nd entry)
mov ebx, [ ebx + 0x08 ] // get the 2nd entries base address (kernel32.dll)
This method has worked for all versions of Windows from Windows 2000 up to and including Windows Vista. The introduction of Windows 7 (rc1) has broken this method of retrieving the kernel32 base address due to the new MinWin kernel structure employed by Windows 7. A new module kernelbase.dll is loaded before kernel32.dll and as such appears in the second entry of the InInitializationOrder module list.
To retrieve the kernel32.dll base address in a generic manner on all versions of Windows from Windows 2000 up to and including Windows 7 (rc1) a slightly modified approach can be used. Instead of parsing the PEB's InInitializationOrder module list, the InMemoryOrder module list can be parsed instead. The third entry in this list will always be that of kernel32.dll (The first being that of the main module and the second being that of ntdll.dll). The code used to retrieve the kernel32 base address based on this method is shown below:
xor ebx, ebx // clear ebx
mov ebx, fs:[ 0x30 ] // get a pointer to the PEB
mov ebx, [ ebx + 0x0C ] // get PEB->Ldr
mov ebx, [ ebx + 0x14 ] // get PEB->Ldr.InMemoryOrderModuleList.Flink (1st entry)
mov ebx, [ ebx ] // get the next entry (2nd entry)
mov ebx, [ ebx ] // get the next entry (3rd entry)
mov ebx, [ ebx + 0x10 ] // get the 3rd entries base address (kernel32.dll)
Update:
Their appears to be some cases on Windows 2000 whereby the above method
will not yield the correct result. A more robust method, albeit a more
lengthy one, can be seen below. We search the InMemoryOrder module list
for the kernel32 module using a hash of the module name for comparison.
We also normalise the module name to uppercase as some systems store
module names in uppercase and some in lowercase.
cld // clear the direction flag for the loop
xor edx, edx // zero edx
mov edx, [fs:edx+0x30] // get a pointer to the PEB
mov edx, [edx+0x0C] // get PEB->Ldr
mov edx, [edx+0x14] // get the first module from the InMemoryOrder module list
next_mod:
mov esi, [edx+0x28] // get pointer to modules name (unicode string)
push byte 24 // push down the length we want to check
pop ecx // set ecx to this length for the loop
xor edi, edi // clear edi which will store the hash of the module name
loop_modname:
xor eax, eax // clear eax
lodsb // read in the next byte of the name
cmp al, 'a' // some versions of Windows use lower case module names
jl not_lowercase
sub al, 0x20 // if so normalise to uppercase
not_lowercase:
ror edi, 13 // rotate right our hash value
add edi, eax // add the next byte of the name to the hash
loop loop_modname // loop until we have read enough
cmp edi, 0x6A4ABC5B // compare the hash with that of KERNEL32.DLL
mov ebx, [edx+0x10] // get this modules base address
mov edx, [edx] // get the next module
jne next_mod // if it doesn't match, process the next module
// when we get here EBX is the kernel32 base (or change to suit).
To verify these methods on your own system you can use the following tool: GetKernel32Base.zip
This code has been verified on the following systems:
The following WinDbg session shows how we can manually verify the above methods on a Windows 7 RC1 system:
Labels: Exploitation, Reverse Engineering