Win32 Shellcoding

5 minute read

Enviornment Setup

WinExec() function from kernel32.dll

  • WinExec function - Microsoft Documentation
  • the kernel32.dll Dynamically Linking Library is loaded into all windows xp programs
  • The WinExec() function within kernel32.dll can be used to launch any program that the user running the process can access
  • Use WinExec() from kernel32.dll to launch any program on a windows computer.
    • Similar to Execve() in linux
UINT WinExec(LPCSTR lpCmdLine, UINT uCmdShow);
//  lpCmdLine = path to application to be executed
//  uCmdShow  = Display options

lpCmdLine Parameter

  • If the lpCmdLine variable does not include the full path to the application, then the path is determined in this order:
  1. The directory from which the application loaded.
  2. The current directory.
  3. The Windows system directory.
    • The GetSystemDirectory function retrieves the path of this directory.
  4. The Windows directory.
    • The GetWindowsDirectory function retrieves the path of this directory.
  5. The directories listed in the PATH environment variable.

uCmdShow Parameter

SW-SHOWNORMAL = 0x00000001 
  • An application should specify this flag when displaying the window for the first time.

Find WinExec & ExitProcess Address’s within kernel32.dll

arwin - win32 address resolution program - by steve hanna - v.01
Usage: arwin.exe <Library Name> <Function Name>
C:\arwin.exe kernel32.dll WinExec
WinExec is located at 0x738623ad in kernel32.dll
C:\arwin.exe kernel32.dll ExitProcess
ExitProcess is located at 0x7c81cafa in kernel32.dll
  • The ExitProcess function within kernel32.dll is used to gracefully close the host process after the calc.exe process is launched using the WinExec function.

  • Arwin is case sensitive for the <Function Name> parameter.

Creating the Shellcode Assembly

Push to Stack Little Endian source code
import sys
input = sys.argv[1]
print 'String length : ' +str(len(input))
stringList = [input[i:i+4] for i in range(0, len(input), 4)]
for item in stringList[::-1] :
        print item[::-1] + ' : ' + str(item[::-1].encode('hex'))
  • Python program from Vivek’s SLAE32 course at Penteser Academy.
    • Best course for Linux 32-bit Shellcoding.

calc.exe to Little Endian

root@kali# python "calc.exe"
String length : 8
exe. : 6578652e
clac : 636c6163
  • Intel 32 bit processor’s store data on the Stack in Little Endian
  • To put something in Little Endian format, just put the hex of the bytes in as reverse
; UINT WinExec( LPCSTR lpCmdLine, UINT uCmdShow );
;  WinExec() = 0x7c8623ad    # kernel32.dll on WinXP SP3
;  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 ebx
    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 ebx, 0x7c8623ad   ; call WinExec() function addr in kernel32.dll
    call ebx              ; win32 does not support call to address
; ExitProcess is located at 0x7c81cafa in kernel32.dll
    xor eax, eax          ; clear the eax register
    push eax              ; push a null
    mov eax, 0x7c81cafa   ; ExitProcess Address
    jmp eax               ; Execute the ExitProcess function
Compile Assembly to Object File
root@kali# nasm -v 
NASM version 2.14.02 
root@kali# nasm -f elf32 execCalc.asm -o execCalc.o
  • Shellcode was created and compiled on x64 Kali Host
  • Compiling as a linux 32 ELF file oddly yielded the best results for Windows 32-bit shellcode.
    • Should not matter since we are only using nasm to translate the opcodes for us so we do not have to do it by hand.
Extract the Shellcode Hex from the Object File
root@kali# for i in $(objdump -D execCalc.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
Testing the Shellcode on Windows XP 32-bit
char code[] = \
int main(int argc, char **argv)
  int (*func)();
  func = (int(*)()) code;

  • Compile with lcc-win32.
Test Shellcode Execution

  • The host program gracefully closes using the ExitProcess function at the end of our Shellcode.
  • The calculator process runs even after the host process dies because it is it’s own process.
  • Without the ExitProcess function, the calculator successfully launches, but the host process returns a windows exception / error.