Finding Kernel32 Base Address Shellcode

Yet another one…
This time, smaller, more correct, and still null-free.
I looked a bit at some shellcodes at exploit-db and googled too, to see whether anyone got a smaller way to no avail.

I based my code on:
AFAIK, who based his post on:

And this is my version:

00000000 (02) 6a30                     PUSH 0x30
00000002 (01) 5e                       POP ESI
; Use DB 0x64; LODSD
00000003 (02) 64ad                     LODS EAX, [FS:ESI]
00000005 (03) 8b700c                   MOV ESI, [EAX+0xc]
00000008 (03) 8b761c                   MOV ESI, [ESI+0x1c]
0000000b (03) 8b5608                   MOV EDX, [ESI+0x8]
0000000e (04) 807e1c18                 CMP BYTE [ESI+0x1c], 0x18
00000012 (02) 8b36                     MOV ESI, [ESI]
00000014 (02) 75f5                     JNZ 0xb

The tricky part was how to read from FS:0x30, and the way I use is the smallest one, at least from what I checked.
Another issue that was fixed is the check for kernel32.dll, usually the variation of this shellcode checks for a null byte, but it turned out to be bogous on W2k machines, so it was changed to check for a null word. Getting the shellcode by a byte or two longer.

This way, it’s only 22 bytes, it doesn’t assume that kernel32.dll is the second/third entry in the list, it actually loops till it finds the correct module length (len of ‘kernel32.dll’ * 2 bytes). Also since kernelbase.dll can come first and that renders lots of implementations of this technique unusable.
And obviously the resulting base address of kernel32.dll is in EDX.


[Update July 9th:]
Here’s a link to an explanation about PEB/LDR lists.
See first comment for a better version which is only 17 bytes.

9 Responses to “Finding Kernel32 Base Address Shellcode”

  1. Peter Ferrie says:

    but it does assume that kernel32.dll is the first one whose name is that long. Old style, Win7-compatible, 17 bytes:

    push 30h
    pop esi
    mov eax, [eax+0ch]
    mov esi, [eax+0ch]
    xchg esi, eax
    mov edx, [eax+18h]

  2. arkon says:

    What a RAPE Peter. InLoadedOrder list proved to be better.
    By the way, the xchg/lods could be mov eax, [eax], still 2 bytes, more readable…

  3. Peter Ferrie says:

    Yes, but it looks more like the old way using lodsd. :-)

  4. FASM says:

    How do you get the fs:lodsd thing to assemble in FASM ?

  5. arkon says:

    As the original snippet suggested,
    DB 0×64; LODSD

  6. Agustin says:

    Hi Arkon, a 15 byte version

    PUSHL $0x30
    POPL %esi
    LODSL %fs:(%esi), %eax
    MOVL 0x0C(%eax), %eax
    MOVL 0x1C(%eax), %esi

    ; Here 0x08(%eax) will contain the address of kernel
    PUSHL 0x08(%eax)
    …. Use -0x4(%ebp) for access to the module

  7. Warren Buffet says:

    nasm does not like LODS EAX, [FS:ESI] so one should keep only the LODS.

  8. arkon says:

    Agustin, your code will fail if kernel32 is in the place you expect it, and that happen ITW.

Leave a Reply