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.
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