Tuesday, May 3, 2011

CreateRemoteThread Shellcode

Analyzing shellcode statically can be a pain at times. Thus far the best approach to analyze it is the dynamic ways. There are multiple online tools that can provide assistance during the analysis of shellcode, one such site is the sandsprite's shellcode2exe. It converts the given shellcode to an exe which can be latter debugged.

There are multiple other ways to analyze the shellcode. One such way is dynamically allocate memory in a dummy process and step through executing the shellcode using a debugger. It all first starts with allocating the virtual memory under a process. It then leads to writing the shellcode to the allocated memory and then creating a remote thread with the base address of the allocated memory as reference. For our convenience we can have the thread created in a suspended mode which can be later resumed with the help of the debugger.

The below python script will do the job. All it does is creates a process notepad.exe, allocates memory under the created process, writes the shellcode and creates a suspended thread of that shellcode.



#-------------------------------------------------------------------------------
# Name: Injector
# Purpose: Analyze ShellCode
#-------------------------------------------------------------------------------
#!/usr/bin/env python

from ctypes import *
from ctypes.wintypes import BOOL
import binascii

#Substitute your shellcode here
shellcode = "\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x48\x49\x49\x49\x49\x51\x5a\x6a\x46\x58\x30\x42\x30\x50\x42\x6b\x42\x41\x56\x42\x32\x42\x41\x41\x32\x41\x41\x30\x41\x41\x58\x38\x42\x42\x50\x75\x58\x69\x69\x6c\x4b\x58\x62\x64\x65\x50\x67\x70\x47\x70\x6c\x4b\x42\x65\x45\x6c\x6e\x6b\x73\x4c\x53\x35\x73\x48\x45\x51\x4a\x4f\x6c\x4b\x70\x4f\x52\x38\x4c\x4b\x33\x6f\x55\x70\x57\x71\x6a\x4b\x61\x59\x4c\x4b\x36\x54\x6e\x6b\x53\x31\x48\x6e\x55\x61\x39\x50\x4d\x49\x4c\x6c\x4d\x54\x6b\x70\x74\x34\x66\x67\x4b\x71\x78\x4a\x56\x6d\x67\x71\x39\x52\x48\x6b\x4c\x34\x35\x6b\x62\x74\x56\x44\x57\x74\x54\x35\x6b\x55\x4e\x6b\x31\x4f\x65\x74\x67\x71\x5a\x4b\x50\x66\x6c\x4b\x56\x6c\x42\x6b\x6e\x6b\x53\x6f\x47\x6c\x67\x71\x7a\x4b\x6c\x4b\x45\x4c\x6c\x4b\x47\x71\x48\x6b\x4f\x79\x33\x6c\x44\x64\x73\x34\x49\x53\x70\x31\x6b\x70\x71\x74\x4e\x6b\x73\x70\x56\x50\x4b\x35\x49\x50\x62\x58\x66\x6c\x4c\x4b\x43\x70\x56\x6c\x4c\x4b\x50\x70\x45\x4c\x4c\x6d\x6c\x4b\x35\x38\x77\x78\x78\x6b\x67\x79\x4e\x6b\x6b\x30\x6c\x70\x57\x70\x63\x30\x33\x30\x4c\x4b\x32\x48\x67\x4c\x73\x6f\x35\x61\x48\x76\x71\x70\x56\x36\x6c\x49\x4a\x58\x6e\x63\x69\x50\x41\x6b\x56\x30\x65\x38\x6c\x30\x6f\x7a\x75\x54\x73\x6f\x31\x78\x4e\x78\x79\x6e\x6f\x7a\x36\x6e\x66\x37\x6b\x4f\x5a\x47\x52\x43\x65\x31\x30\x6c\x70\x63\x45\x50\x46"

BYTE = c_ubyte
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
PVOID = c_void_p
LPVOID = c_void_p
UNIT_PTR = c_ulong
SIZE_T = c_ulong

class STARTUPINFO(Structure):
_fields_ = [("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute",DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),]

class PROCESS_INFORMATION(Structure):
_fields_ = [("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),]

class MEMORY_BASIC_INFORMATION(Structure):
_fields_ = [("BaseAddress", PVOID),
("AllocationBase", PVOID),
("AllocationProtect", DWORD),
("RegionSize", SIZE_T),
("State", DWORD),
("Protect", DWORD),
("Type", DWORD),]

class Main():
def __init__(self):
self.h_process = None
self.pid = None

def launch(self, path_to_exe):
CREATE_NEW_CONSOLE = 0x00000010
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000

startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()

startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x1
startupinfo.cb = sizeof(startupinfo)

if windll.kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
True,
CREATE_NEW_CONSOLE,
None,
None,
byref(startupinfo),
byref(process_information)):

self.pid = process_information.dwProcessId
print "[*] Success: CreateProcess - ", path_to_exe
else:
print "[*] Failed: Create Process - Error code: ", windll.kernel32.GetLastError()

def get_handle(self, pid):
PROCESS_ALL_ACCESS = 0x001F0FFF
self.h_process = windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
if self.h_process:
print "[*] Success: Got Handle - PID:", self.pid
else:
print "[*] Failed: Get Handle - Error code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)

def virtual_alloc(self):
MEM_COMMIT = 0x1000
PAGE_EXECUTE_READWRITE = 0x40
size = 200
result = windll.kernel32.VirtualAllocEx(self.h_process, None, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
if result:
return result
else:
print "[*] Failed: Virtual Alloc - Error Code: ", windll.kernel32.GetLastError()

def write_memory(self, address, data):
count = c_ulong(0)
length = len(data)
c_data = c_char_p(data[count.value:])
null = c_int(0)
if not windll.kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
print "[*] Failed: Write Memory - Error Code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)
else:
print "[*] Injecting ShellCode"
print "[*] Wrote %d bytes of data at 0x%x" %(length, address)

def createremote_thread(self, address):
lpThreadID = c_ulong(0)
CREATE_SUSPENDED = 0x00000004
result = windll.kernel32.CreateRemoteThread(self.h_process, None, None, address, None, CREATE_SUSPENDED, byref(lpThreadID))
if result:
print "[*] Remote Process started - ThreadID %x" %(lpThreadID.value)
else:
print "[*] Remote Process failed to start - Error Code: ", windll.kernel32.GetLastError()


main = Main()
print "[*] Launching Notepad"
main.launch("C:\\WINDOWS\\system32\\notepad.exe")
main.get_handle(main.pid)
address = main.virtual_alloc()
main.write_memory(address, shellcode)
main.createremote_thread(address)
print "[*] Attach debugger to notepad.exe and resume the suspended thread to continue analyzing the shellcode"


The debugger can now be attached and the suspended thread can be resumed. This approach can be useful when all other techniques for analyzing shellcode proves unsuccessful. The sample shellcode included will spawn a CALC process.

No comments:

Post a Comment