From 481b8861f02947c80bde591bb5e6bbda9c775b89 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Wed, 1 Apr 2015 18:22:42 +0200 Subject: [PATCH] Add TCP connections + Syswow64 injection --- generated_def/windef.py | 33 +++++- generated_def/winfuncs.py | 14 ++- generated_def/winstructs.py | 148 ++++++++++++++++++++++-- injection.py | 32 +++--- k32testing.py | 182 ++++++++++++++++------------- native_exec/native_function.py | 2 +- native_exec/simple_x64.py | 5 +- network.py | 151 ++++++++++++++++++++++++ pe_parse.py | 79 ++++++------- syswow64.py | 202 +++++++++++++++++++++++++++++++++ winobject.py | 178 ++++++++++++++++------------- 11 files changed, 795 insertions(+), 231 deletions(-) create mode 100644 network.py create mode 100644 syswow64.py diff --git a/generated_def/windef.py b/generated_def/windef.py index 11553e1..f9f8cf2 100644 --- a/generated_def/windef.py +++ b/generated_def/windef.py @@ -13,6 +13,7 @@ class Flag(long): NULL = Flag("NULL", 0) MAX_PATH = Flag("MAX_PATH", 260) ANYSIZE_ARRAY = Flag("ANYSIZE_ARRAY", 1) +ANY_SIZE = Flag("ANY_SIZE", 1) IMAGE_SIZEOF_SHORT_NAME = Flag("IMAGE_SIZEOF_SHORT_NAME", 8) IMAGE_NUMBEROF_DIRECTORY_ENTRIES = Flag("IMAGE_NUMBEROF_DIRECTORY_ENTRIES", 16) STD_INPUT_HANDLE = Flag("STD_INPUT_HANDLE", -10) @@ -242,4 +243,34 @@ TOKEN_ALL_ACCESS = Flag("TOKEN_ALL_ACCESS", ( TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_ SE_PRIVILEGE_ENABLED_BY_DEFAULT = Flag("SE_PRIVILEGE_ENABLED_BY_DEFAULT", ( 0x00000001L )) SE_PRIVILEGE_ENABLED = Flag("SE_PRIVILEGE_ENABLED", ( 0x00000002L )) SE_PRIVILEGE_REMOVED = Flag("SE_PRIVILEGE_REMOVED", ( 0X00000004L )) -SE_PRIVILEGE_USED_FOR_ACCESS = Flag("SE_PRIVILEGE_USED_FOR_ACCESS", ( 0x80000000L )) \ No newline at end of file +SE_PRIVILEGE_USED_FOR_ACCESS = Flag("SE_PRIVILEGE_USED_FOR_ACCESS", ( 0x80000000L )) +AF_UNSPEC = Flag("AF_UNSPEC", 0) +AF_UNIX = Flag("AF_UNIX", 1) +AF_INET = Flag("AF_INET", 2) +AF_IMPLINK = Flag("AF_IMPLINK", 3) +AF_PUP = Flag("AF_PUP", 4) +AF_CHAOS = Flag("AF_CHAOS", 5) +AF_NS = Flag("AF_NS", 6) +AF_IPX = Flag("AF_IPX", AF_NS) +AF_ISO = Flag("AF_ISO", 7) +AF_OSI = Flag("AF_OSI", AF_ISO) +AF_ECMA = Flag("AF_ECMA", 8) +AF_DATAKIT = Flag("AF_DATAKIT", 9) +AF_CCITT = Flag("AF_CCITT", 10) +AF_SNA = Flag("AF_SNA", 11) +AF_DECnet = Flag("AF_DECnet", 12) +AF_DLI = Flag("AF_DLI", 13) +AF_LAT = Flag("AF_LAT", 14) +AF_HYLINK = Flag("AF_HYLINK", 15) +AF_APPLETALK = Flag("AF_APPLETALK", 16) +AF_NETBIOS = Flag("AF_NETBIOS", 17) +AF_VOICEVIEW = Flag("AF_VOICEVIEW", 18) +AF_FIREFOX = Flag("AF_FIREFOX", 19) +AF_UNKNOWN1 = Flag("AF_UNKNOWN1", 20) +AF_BAN = Flag("AF_BAN", 21) +AF_ATM = Flag("AF_ATM", 22) +AF_INET6 = Flag("AF_INET6", 23) +AF_CLUSTER = Flag("AF_CLUSTER", 24) +AF_12844 = Flag("AF_12844", 25) +AF_IRDA = Flag("AF_IRDA", 26) +AF_NETDES = Flag("AF_NETDES", 28) \ No newline at end of file diff --git a/generated_def/winfuncs.py b/generated_def/winfuncs.py index 6ee9e27..425948d 100644 --- a/generated_def/winfuncs.py +++ b/generated_def/winfuncs.py @@ -3,7 +3,7 @@ from ctypes import * from ctypes.wintypes import * from winstructs import * -functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentProcessorNumber', 'AllocConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile'] +functions = ['ExitProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtQuerySystemInformation', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualProtect', 'VirtualQuery', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'SetThreadContext', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentProcessorNumber', 'AllocConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile', 'GetExtendedTcpTable', 'GetExtendedUdpTable', 'SetTcpEntry'] # ExitProcess(uExitCode): ExitProcessPrototype = WINFUNCTYPE(VOID, UINT) @@ -213,3 +213,15 @@ SetThreadAffinityMaskParams = ((1, 'hThread'), (1, 'dwThreadAffinityMask')) WriteFilePrototype = WINFUNCTYPE(BOOL, HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED) WriteFileParams = ((1, 'hFile'), (1, 'lpBuffer'), (1, 'nNumberOfBytesToWrite'), (1, 'lpNumberOfBytesWritten'), (1, 'lpOverlapped')) +# GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved): +GetExtendedTcpTablePrototype = WINFUNCTYPE(DWORD, PVOID, PDWORD, BOOL, ULONG, TCP_TABLE_CLASS, ULONG) +GetExtendedTcpTableParams = ((1, 'pTcpTable'), (1, 'pdwSize'), (1, 'bOrder'), (1, 'ulAf'), (1, 'TableClass'), (1, 'Reserved')) + +# GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, ulAf, TableClass, Reserved): +GetExtendedUdpTablePrototype = WINFUNCTYPE(DWORD, PVOID, PDWORD, BOOL, ULONG, UDP_TABLE_CLASS, ULONG) +GetExtendedUdpTableParams = ((1, 'pUdpTable'), (1, 'pdwSize'), (1, 'bOrder'), (1, 'ulAf'), (1, 'TableClass'), (1, 'Reserved')) + +# SetTcpEntry(pTcpRow): +SetTcpEntryPrototype = WINFUNCTYPE(DWORD, PMIB_TCPROW) +SetTcpEntryParams = ((1, 'pTcpRow'),) + diff --git a/generated_def/winstructs.py b/generated_def/winstructs.py index 1a093fe..07cdd53 100644 --- a/generated_def/winstructs.py +++ b/generated_def/winstructs.py @@ -15,6 +15,7 @@ LPTHREAD_START_ROUTINE = PVOID LPBYTE = POINTER(BYTE) ULONG_PTR = PULONG CHAR = c_char +UCHAR = c_char FARPROC = PVOID HGLOBAL = PVOID ULONGLONG = c_ulonglong @@ -23,9 +24,9 @@ PULONG64 = POINTER(ULONG64) PHANDLE = POINTER(HANDLE) VOID = DWORD -structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_PEB_LDR_DATA', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED'] +structs = ['_LIST_ENTRY', '_PEB_LDR_DATA', '_LSA_UNICODE_STRING', '_RTL_USER_PROCESS_PARAMETERS', '_PEB', '_SECURITY_ATTRIBUTES', '_SYSTEM_VERIFIER_INFORMATION', '_LDR_DATA_TABLE_ENTRY', '_IMAGE_FILE_HEADER', '_IMAGE_DATA_DIRECTORY', '_IMAGE_SECTION_HEADER', '_IMAGE_OPTIONAL_HEADER64', '_IMAGE_OPTIONAL_HEADER', '_IMAGE_NT_HEADERS64', '_IMAGE_NT_HEADERS', '_IMAGE_IMPORT_DESCRIPTOR', '_IMAGE_IMPORT_BY_NAME', '_MEMORY_BASIC_INFORMATION', '_STARTUPINFOA', '_STARTUPINFOW', '_PROCESS_INFORMATION', '_FLOATING_SAVE_AREA', '_CONTEXT', 'tagPROCESSENTRY32W', 'tagPROCESSENTRY32', 'tagTHREADENTRY32', '_LUID', '_LUID_AND_ATTRIBUTES', '_TOKEN_PRIVILEGES', '_OSVERSIONINFOA', '_OSVERSIONINFOW', '_OSVERSIONINFOEXA', '_OSVERSIONINFOEXW', '_OVERLAPPED', '_MIB_TCPROW_OWNER_PID', '_MIB_TCPTABLE_OWNER_PID', '_MIB_UDPROW_OWNER_PID', '_MIB_UDPTABLE_OWNER_PID', '_MIB_UDP6ROW_OWNER_PID', '_MIB_UDP6TABLE_OWNER_PID', '_MIB_TCP6ROW_OWNER_PID', '_MIB_TCP6TABLE_OWNER_PID', '_MIB_TCPROW'] -enums = ['_SYSTEM_INFORMATION_CLASS'] +enums = ['_SYSTEM_INFORMATION_CLASS', '_TCP_TABLE_CLASS', '_UDP_TABLE_CLASS', '_MIB_TCP_STATE'] # Enum _SYSTEM_INFORMATION_CLASS definitions _SYSTEM_INFORMATION_CLASS = DWORD @@ -114,6 +115,42 @@ SystemSuperfetchInformation = 0x4f SystemMemoryListInformation = 0x50 SystemFileCacheInformationEx = 0x51 MaxSystemInfoClass = 0x52 +# Enum _TCP_TABLE_CLASS definitions +_TCP_TABLE_CLASS = DWORD +TCP_TABLE_CLASS = _TCP_TABLE_CLASS + +TCP_TABLE_BASIC_LISTENER = 0x0 +TCP_TABLE_BASIC_CONNECTIONS = 0x1 +TCP_TABLE_BASIC_ALL = 0x2 +TCP_TABLE_OWNER_PID_LISTENER = 0x3 +TCP_TABLE_OWNER_PID_CONNECTIONS = 0x4 +TCP_TABLE_OWNER_PID_ALL = 0x5 +TCP_TABLE_OWNER_MODULE_LISTENER = 0x6 +TCP_TABLE_OWNER_MODULE_CONNECTIONS = 0x7 +TCP_TABLE_OWNER_MODULE_ALL = 0x8 +# Enum _UDP_TABLE_CLASS definitions +_UDP_TABLE_CLASS = DWORD +UDP_TABLE_CLASS = _UDP_TABLE_CLASS + +UDP_TABLE_BASIC = 0x0 +UDP_TABLE_OWNER_PID = 0x1 +UDP_TABLE_OWNER_MODULE = 0x2 +# Enum _MIB_TCP_STATE definitions +_MIB_TCP_STATE = DWORD +MIB_TCP_STATE = _MIB_TCP_STATE + +MIB_TCP_STATE_CLOSED = 0x1 +MIB_TCP_STATE_LISTEN = 0x2 +MIB_TCP_STATE_SYN_SENT = 0x3 +MIB_TCP_STATE_SYN_RCVD = 0x4 +MIB_TCP_STATE_ESTAB = 0x5 +MIB_TCP_STATE_FIN_WAIT1 = 0x6 +MIB_TCP_STATE_FIN_WAIT2 = 0x7 +MIB_TCP_STATE_CLOSE_WAIT = 0x8 +MIB_TCP_STATE_CLOSING = 0x9 +MIB_TCP_STATE_LAST_ACK = 0xa +MIB_TCP_STATE_TIME_WAIT = 0xb +MIB_TCP_STATE_DELETE_TCB = 0xc # Struct _LIST_ENTRY definitions # Self referencing struct tricks class _LIST_ENTRY(Structure): pass @@ -238,16 +275,6 @@ class _LDR_DATA_TABLE_ENTRY(Structure): PLDR_DATA_TABLE_ENTRY = POINTER(_LDR_DATA_TABLE_ENTRY) LDR_DATA_TABLE_ENTRY = _LDR_DATA_TABLE_ENTRY -# Struct _PEB_LDR_DATA definitions -class _PEB_LDR_DATA(Structure): - _fields_ = [ - ("Reserved1", BYTE * 8), - ("Reserved2", PVOID * 3), - ("InMemoryOrderModuleList", LIST_ENTRY), - ] -PPEB_LDR_DATA = POINTER(_PEB_LDR_DATA) -PEB_LDR_DATA = _PEB_LDR_DATA - # Struct _IMAGE_FILE_HEADER definitions class _IMAGE_FILE_HEADER(Structure): _fields_ = [ @@ -687,3 +714,100 @@ class _OVERLAPPED(Structure): LPOVERLAPPED = POINTER(_OVERLAPPED) OVERLAPPED = _OVERLAPPED +# Struct _MIB_TCPROW_OWNER_PID definitions +class _MIB_TCPROW_OWNER_PID(Structure): + _fields_ = [ + ("dwState", DWORD), + ("dwLocalAddr", DWORD), + ("dwLocalPort", DWORD), + ("dwRemoteAddr", DWORD), + ("dwRemotePort", DWORD), + ("dwOwningPid", DWORD), + ] +MIB_TCPROW_OWNER_PID = _MIB_TCPROW_OWNER_PID +PMIB_TCPROW_OWNER_PID = POINTER(_MIB_TCPROW_OWNER_PID) + +# Struct _MIB_TCPTABLE_OWNER_PID definitions +class _MIB_TCPTABLE_OWNER_PID(Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", MIB_TCPROW_OWNER_PID * ANY_SIZE), + ] +MIB_TCPTABLE_OWNER_PID = _MIB_TCPTABLE_OWNER_PID +PMIB_TCPTABLE_OWNER_PID = POINTER(_MIB_TCPTABLE_OWNER_PID) + +# Struct _MIB_UDPROW_OWNER_PID definitions +class _MIB_UDPROW_OWNER_PID(Structure): + _fields_ = [ + ("dwLocalAddr", DWORD), + ("dwLocalPort", DWORD), + ("dwOwningPid", DWORD), + ] +MIB_UDPROW_OWNER_PID = _MIB_UDPROW_OWNER_PID +PMIB_UDPROW_OWNER_PID = POINTER(_MIB_UDPROW_OWNER_PID) + +# Struct _MIB_UDPTABLE_OWNER_PID definitions +class _MIB_UDPTABLE_OWNER_PID(Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", MIB_UDPROW_OWNER_PID * ANY_SIZE), + ] +MIB_UDPTABLE_OWNER_PID = _MIB_UDPTABLE_OWNER_PID +PMIB_UDPTABLE_OWNER_PID = POINTER(_MIB_UDPTABLE_OWNER_PID) + +# Struct _MIB_UDP6ROW_OWNER_PID definitions +class _MIB_UDP6ROW_OWNER_PID(Structure): + _fields_ = [ + ("ucLocalAddr", UCHAR * 16), + ("dwLocalScopeId", DWORD), + ("dwLocalPort", DWORD), + ("dwOwningPid", DWORD), + ] +MIB_UDP6ROW_OWNER_PID = _MIB_UDP6ROW_OWNER_PID +PMIB_UDP6ROW_OWNER_PID = POINTER(_MIB_UDP6ROW_OWNER_PID) + +# Struct _MIB_UDP6TABLE_OWNER_PID definitions +class _MIB_UDP6TABLE_OWNER_PID(Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", MIB_UDP6ROW_OWNER_PID * ANY_SIZE), + ] +PMIB_UDP6TABLE_OWNER_PID = POINTER(_MIB_UDP6TABLE_OWNER_PID) +MIB_UDP6TABLE_OWNER_PID = _MIB_UDP6TABLE_OWNER_PID + +# Struct _MIB_TCP6ROW_OWNER_PID definitions +class _MIB_TCP6ROW_OWNER_PID(Structure): + _fields_ = [ + ("ucLocalAddr", UCHAR * 16), + ("dwLocalScopeId", DWORD), + ("dwLocalPort", DWORD), + ("ucRemoteAddr", UCHAR * 16), + ("dwRemoteScopeId", DWORD), + ("dwRemotePort", DWORD), + ("dwState", DWORD), + ("dwOwningPid", DWORD), + ] +MIB_TCP6ROW_OWNER_PID = _MIB_TCP6ROW_OWNER_PID +PMIB_TCP6ROW_OWNER_PID = POINTER(_MIB_TCP6ROW_OWNER_PID) + +# Struct _MIB_TCP6TABLE_OWNER_PID definitions +class _MIB_TCP6TABLE_OWNER_PID(Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", MIB_TCP6ROW_OWNER_PID * ANY_SIZE), + ] +MIB_TCP6TABLE_OWNER_PID = _MIB_TCP6TABLE_OWNER_PID +PMIB_TCP6TABLE_OWNER_PID = POINTER(_MIB_TCP6TABLE_OWNER_PID) + +# Struct _MIB_TCPROW definitions +class _MIB_TCPROW(Structure): + _fields_ = [ + ("dwState", DWORD), + ("dwLocalAddr", DWORD), + ("dwLocalPort", DWORD), + ("dwRemoteAddr", DWORD), + ("dwRemotePort", DWORD), + ] +MIB_TCPROW = _MIB_TCPROW +PMIB_TCPROW = POINTER(_MIB_TCPROW) + diff --git a/injection.py b/injection.py index 1ff2185..d55c03e 100644 --- a/injection.py +++ b/injection.py @@ -27,22 +27,22 @@ def generate_python_exec_shellcode_32(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): code += Push_X(PyRun) code += Push_EDI() code += Call_EBX() - # Call PyInit with python code to exec + # Call PyRun with python code to exec code += Push_X(PYCODE_ADDR) code += Call_EAX() code += Pop_EDI() code += Ret() return code.get_code() -# 64 to 64 injection +# 64 to 64 injection def generate_python_exec_shellcode_64(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): from native_exec.simple_x64 import * LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA') GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress') - + Reserve_space_for_call = MultipleInstr([Push_RDI()] * 4) Clean_space_for_call = MultipleInstr([Pop_RDI()] * 4) - + code = MultipleInstr() # Do stack alignement code += Push_RAX() @@ -81,34 +81,33 @@ def generate_python_exec_shellcode_64(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): # Remove stack alignement code += Pop_RAX() code += Ret() - return code.get_code() - - + return code.get_code() + + def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"): PyInitT = "Py_Initialize\x00" Pyrun = "PyRun_SimpleString\x00" PYCODE = code_injected + "\x00" remote_addr_base = process.virtual_alloc(len(code_injected) + 0x100) remote_addr = remote_addr_base - + PYDLL_addr = remote_addr process.write_memory(remote_addr, PYDLL) remote_addr += len(PYDLL) - - + + PyInitT_ADDR = remote_addr process.write_memory(remote_addr, PyInitT) remote_addr += len(PyInitT) Pyrun_ADDR = remote_addr process.write_memory(remote_addr, Pyrun) - remote_addr += len(Pyrun) - + remote_addr += len(Pyrun) + PYCODE_ADDR = remote_addr process.write_memory(remote_addr, PYCODE) remote_addr += len(PYCODE) - - + SHELLCODE_ADDR = remote_addr if process.bitness == 32: shellcode = generate_python_exec_shellcode_32(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR) @@ -117,8 +116,8 @@ def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"): process.write_memory(SHELLCODE_ADDR, shellcode) return SHELLCODE_ADDR - - + + def execute_python_code(process, code): print("me = {0}".format(windows.current_process.bitness)) print("him = {0}".format(process.bitness)) @@ -126,4 +125,3 @@ def execute_python_code(process, code): raise NotImplementedError("Cannot perform 32 <-> 64 injection") shellcode_remote_addr = inject_python_command(process, code) return process.create_thread(shellcode_remote_addr, 0) - \ No newline at end of file diff --git a/k32testing.py b/k32testing.py index 3dd42a8..23e3d02 100644 --- a/k32testing.py +++ b/k32testing.py @@ -9,11 +9,9 @@ import windows.generated_def.winfuncs as winfuncs kernel32 = ctypes.windll.kernel32 advapi32 = ctypes.windll.Advapi32 - - +iphlpapi = ctypes.windll.iphlpapi class Kernel32Error(WindowsError): - def __new__(cls, func_name): win_error = ctypes.WinError() api_error = super(Kernel32Error, cls).__new__(cls) @@ -22,21 +20,45 @@ class Kernel32Error(WindowsError): api_error.strerror = win_error.strerror api_error.args = (func_name, win_error.winerror, win_error.strerror) return api_error - - def __init__(self, func_name): - pass - + def __repr__(self): return "{0}: {1}".format(self.api_name, super(Kernel32Error, self).__repr__()) - + def __str__(self): return "{0}: {1}".format(self.api_name, super(Kernel32Error, self).__str__()) - -def no_error_check(result, func, args): + +class IphlpapiError(Kernel32Error): + + def __new__(cls, func_name, code): + win_error = ctypes.WinError(code) + api_error = super(Kernel32Error, cls).__new__(cls) + api_error.api_name = func_name + api_error.winerror = win_error.winerror + api_error.strerror = win_error.strerror + api_error.args = (func_name, win_error.winerror, win_error.strerror) + return api_error + + def __init__(self, func_name, code): + pass + +# Error check method +def no_error_check(func_name, result, func, args): """Nothing special""" - return args - -# Design 1 + return args + +def kernel32_error_check(func_name, result, func, args): + """raise Kernel32Error if result is 0""" + if not result: + raise Kernel32Error(func_name) + return args + +def iphlpapi_error_check(func_name, result, func, args): + """raise IphlpapiError if result is NOT 0""" + if result: + raise IphlpapiError(func_name, result) + return args + +# Design 1 class ApiProxy(object): APIDLL = None """Create a python wrapper around a kernel32 function""" @@ -44,14 +66,8 @@ class ApiProxy(object): self.func_name = func_name if error_check is None: error_check = self.default_error_check - self.error_check = error_check - - def default_error_check(self, result, func, args): - """raise Kernel32Error if result is 0""" - if not result: - raise Kernel32Error(self.func_name) - return args - + self.error_check = functools.wraps(error_check)(functools.partial(error_check, func_name)) + def __call__(self, python_proxy, ): prototype = getattr(winfuncs, self.func_name + "Prototype") params = getattr(winfuncs, self.func_name + "Params") @@ -74,44 +90,44 @@ class ApiProxy(object): return c_prototyped(*args) setattr(python_proxy, "ctypes_function", perform_call) return python_proxy - + class Kernel32Proxy(ApiProxy): APIDLL = kernel32 + default_error_check = staticmethod(kernel32_error_check) class Advapi32Proxy(ApiProxy): APIDLL = advapi32 - -def TransparentApiProxy(APIDLL, func_name, error_check=None): + default_error_check = staticmethod(kernel32_error_check) + +class IphlpapiProxy(ApiProxy): + APIDLL = iphlpapi + default_error_check = staticmethod(iphlpapi_error_check) + +def TransparentApiProxy(APIDLL, func_name, error_check): """Create a ctypes function for 'func_name' with no python arg pre-check""" - def default_error_check(result, func, args): - if not result: - raise Kernel32Error(func_name) - return args - if error_check is None: - error_check = default_error_check + prototype = getattr(winfuncs, func_name + "Prototype") args = getattr(winfuncs, func_name + "Params") c_prototyped = prototype((func_name, APIDLL), args) - c_prototyped.errcheck = error_check - return c_prototyped + c_prototyped.errcheck = functools.wraps(error_check)(functools.partial(error_check, func_name)) + return c_prototyped + + +TransparentKernel32Proxy = lambda func_name, error_check=kernel32_error_check : TransparentApiProxy(kernel32, func_name, error_check) +TransparentAdvapi32Proxy = lambda func_name, error_check=kernel32_error_check : TransparentApiProxy(advapi32, func_name, error_check) +TransparentIphlpapiProxy = lambda func_name, error_check=iphlpapi_error_check : TransparentApiProxy(iphlpapi, func_name, error_check) - -TransparentKernel32Proxy = lambda *args: TransparentApiProxy(kernel32, *args) -TransparentAdvapi32Proxy = lambda *args: TransparentApiProxy(advapi32, *args) - class NeededParameterType(object): _inst = None def __new__(cls): if cls._inst is None: cls._inst = super(NeededParameterType, cls).__new__(cls) return cls._inst - + def __repr__(self): return "NeededParameter" - -NeededParameter = NeededParameterType() - +NeededParameter = NeededParameterType() ExitProcess = TransparentKernel32Proxy("ExitProcess") CloseHandle = TransparentKernel32Proxy("CloseHandle") @@ -130,23 +146,23 @@ SetStdHandle = TransparentKernel32Proxy("SetStdHandle") @Kernel32Proxy("VirtualAlloc") def VirtualAlloc(lpAddress=0, dwSize=NeededParameter, flAllocationType=MEM_COMMIT, flProtect=PAGE_EXECUTE_READWRITE): return VirtualAlloc.ctypes_function(lpAddress, dwSize, flAllocationType, flProtect) - + @Kernel32Proxy("VirtualAllocEx") def VirtualAllocEx(hProcess, lpAddress=0, dwSize=NeededParameter, flAllocationType=MEM_COMMIT, flProtect=PAGE_EXECUTE_READWRITE): return VirtualAllocEx.ctypes_function(hProcess, lpAddress, dwSize, flAllocationType, flProtect) - -@Kernel32Proxy("CreateRemoteThread") + +@Kernel32Proxy("CreateRemoteThread") def CreateRemoteThread(hProcess=NeededParameter, lpThreadAttributes=None, dwStackSize=0, lpStartAddress=NeededParameter, lpParameter=NeededParameter, dwCreationFlags=0, lpThreadId=None): return CreateRemoteThread.ctypes_function(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId) - -@Kernel32Proxy("VirtualProtect") + +@Kernel32Proxy("VirtualProtect") def VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect=0): return VirtualProtect.ctypes_function(lpAddress, dwSize, flNewProtect, lpflOldProtect) - + @Kernel32Proxy("CreateProcessA") def CreateProcessA(lpApplicationName, lpCommandLine=None, lpProcessAttributes=None, lpThreadAttributes=None, bInheritHandles=False, - dwCreationFlags=0, lpEnvironment=None, lpCurrentDirectory=None, lpStartupInfo=None, lpProcessInformation=None): + dwCreationFlags=0, lpEnvironment=None, lpCurrentDirectory=None, lpStartupInfo=None, lpProcessInformation=None): if lpStartupInfo is None: StartupInfo = STARTUPINFOA() StartupInfo.cb = ctypes.sizeof(StartupInfo) @@ -154,22 +170,22 @@ def CreateProcessA(lpApplicationName, lpCommandLine=None, lpProcessAttributes=No StartupInfo.wShowWindow = SW_HIDE lpStartupInfo = ctypes.byref(StartupInfo) if lpProcessInformation is None: - lpProcessInformation = ctypes.byref(PROCESS_INFORMATION()) + lpProcessInformation = ctypes.byref(PROCESS_INFORMATION()) return CreateProcessA.ctypes_function(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation) @Kernel32Proxy("CreateProcessW") def CreateProcessW(lpApplicationName, lpCommandLine=None, lpProcessAttributes=None, lpThreadAttributes=None, bInheritHandles=False, - dwCreationFlags=0, lpEnvironment=None, lpCurrentDirectory=None, lpStartupInfo=None, lpProcessInformation=None): + dwCreationFlags=0, lpEnvironment=None, lpCurrentDirectory=None, lpStartupInfo=None, lpProcessInformation=None): if lpStartupInfo is None: StartupInfo = STARTUPINFOW() StartupInfo.cb = ctypes.sizeof(StartupInfo) StartupInfo.dwFlags = STARTF_USESHOWWINDOW StartupInfo.wShowWindow = SW_HIDE - lpStartupInfo = ctypes.byref(StartupInfo) + lpStartupInfo = ctypes.byref(StartupInfo) if lpProcessInformation is None: - lpProcessInformation = ctypes.byref(PROCESS_INFORMATION()) + lpProcessInformation = ctypes.byref(PROCESS_INFORMATION()) return CreateProcessW.ctypes_function(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation) - + @Kernel32Proxy("GetThreadContext") def GetThreadContext(hThread, lpContext=None): if lpContext is None: @@ -177,14 +193,14 @@ def GetThreadContext(hThread, lpContext=None): context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS lpContext = ctypes.byref(Context) return GetThreadContext.ctypes_function(hThread, lpContext) - + @Kernel32Proxy("SetThreadContext") def SetThreadContext(hThread, lpContext): """ Allows to directly pass a CONTEXT and will call with byref(CONTEXT) by itself""" if type(lpContext) == CONTEXT: lpContext = ctypes.byref(lpContext) return SetThreadContext.ctypes_function(hThread, lpContext) - + @Kernel32Proxy("OpenThread") def OpenThread(dwDesiredAccess=THREAD_ALL_ACCESS, bInheritHandle=0, dwThreadId=NeededParameter): return OpenThread.ctypes_function(dwDesiredAccess, bInheritHandle, dwThreadId) @@ -192,64 +208,60 @@ def OpenThread(dwDesiredAccess=THREAD_ALL_ACCESS, bInheritHandle=0, dwThreadId=N @Kernel32Proxy("OpenProcess") def OpenProcess(dwDesiredAccess=PROCESS_ALL_ACCESS, bInheritHandle=0, dwProcessId=NeededParameter): return OpenProcess.ctypes_function(dwDesiredAccess, bInheritHandle, dwProcessId) - + @Kernel32Proxy("ReadProcessMemory") -def ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer=None, nSize=NeededParameter, lpNumberOfBytesRead=None): - """Create a string buffer if lpBuffer is not given""" - if lpBuffer is None and nSize is not NeededParameter: - lpBuffer = ctypes.create_string_buffer(nSize) +def ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead=None): return ReadProcessMemory.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead) - + @Kernel32Proxy("WriteProcessMemory") def WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize=None, lpNumberOfBytesWritten=None): """Computer nSize with len(lpBuffer) if not given""" if nSize is None: nSize = len(lpBuffer) return WriteProcessMemory.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten) - + @Kernel32Proxy('SetThreadAffinityMask') def SetThreadAffinityMask(hThread=None, dwThreadAffinityMask=NeededParameter): """If hThread is not given, it will be the current thread""" if hThread is None: hThread = GetCurrentThread() return SetThreadAffinityMask.ctypes_function(hThread, dwThreadAffinityMask) - - -@Kernel32Proxy("CreateToolhelp32Snapshot") + +@Kernel32Proxy("CreateToolhelp32Snapshot") def CreateToolhelp32Snapshot(dwFlags, th32ProcessID=0): return CreateToolhelp32Snapshot.ctypes_function(dwFlags, th32ProcessID) - -@Kernel32Proxy("Thread32First", no_error_check) + +@Kernel32Proxy("Thread32First", no_error_check) def Thread32First(hSnapshot, lpte): """Set byref(lpte) if needed""" if type(lpte) == THREADENTRY32: lpte = ctypes.byref(lpte) return Thread32First.ctypes_function(hSnapshot, lpte) -@Kernel32Proxy("Thread32Next", no_error_check) +@Kernel32Proxy("Thread32Next", no_error_check) def Thread32Next(hSnapshot, lpte): """Set byref(lpte) if needed""" if type(lpte) == THREADENTRY32: lpte = ctypes.byref(lpte) return Thread32Next.ctypes_function(hSnapshot, lpte) -@Kernel32Proxy("Process32First", no_error_check) +@Kernel32Proxy("Process32First", no_error_check) def Process32First(hSnapshot, lpte): """Set byref(lpte) if needed""" if type(lpte) == THREADENTRY32: lpte = ctypes.byref(lpte) return Process32First.ctypes_function(hSnapshot, lpte) -@Kernel32Proxy("Process32Next", no_error_check) +@Kernel32Proxy("Process32Next", no_error_check) def Process32Next(hSnapshot, lpte): """Set byref(lpte) if needed""" if type(lpte) == THREADENTRY32: lpte = ctypes.byref(lpte) return Process32Next.ctypes_function(hSnapshot, lpte) - + # File stuff -@Kernel32Proxy("WriteFile") +@Kernel32Proxy("WriteFile") def WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite=None, lpNumberOfBytesWritten=None, lpOverlapped=None): if nNumberOfBytesToWrite is None: nNumberOfBytesToWrite = len(lpBuffer) @@ -257,7 +269,6 @@ def WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite=None, lpNumberOfBytesWritte lpNumberOfBytesWritten = ctypes.byref(DWORD()) return WriteFile.ctypes_function(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped) - ###### ADVAPI32 ######## @Advapi32Proxy('OpenProcessToken') @@ -270,23 +281,30 @@ def OpenProcessToken(ProcessHandle=None, DesiredAccess=NeededParameter, TokenHan @Advapi32Proxy('LookupPrivilegeValueA') def LookupPrivilegeValueA(lpSystemName=None, lpName=NeededParameter, lpLuid=NeededParameter): return LookupPrivilegeValueA.ctypes_function(lpSystemName, lpName, lpLuid) - + @Advapi32Proxy('LookupPrivilegeValueW') def LookupPrivilegeValueW(lpSystemName=None, lpName=NeededParameter, lpLuid=NeededParameter): - return LookupPrivilegeValueW.ctypes_function(lpSystemName, lpName, lpLuid) - + return LookupPrivilegeValueW.ctypes_function(lpSystemName, lpName, lpLuid) + @Advapi32Proxy('AdjustTokenPrivileges') def AdjustTokenPrivileges(TokenHandle, DisableAllPrivileges=False, NewState=NeededParameter, BufferLength=None, PreviousState=None, ReturnLength=None): if BufferLength is None: BufferLength = ctypes.sizeof(NewState) return AdjustTokenPrivileges.ctypes_function(TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength) -# if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { -# fprintf(stderr, "[-] The token does not have the specified privilege\n"); -# return FALSE; - - - + + +###### Iphlpapi (network list and stuff) ####### + +SetTcpEntry = TransparentIphlpapiProxy('SetTcpEntry') + +@IphlpapiProxy('GetExtendedTcpTable') +def GetExtendedTcpTable(pTcpTable, pdwSize=None, bOrder=True, ulAf=NeededParameter, TableClass=TCP_TABLE_OWNER_PID_ALL, Reserved=0): + if pdwSize is None: + ctypes.sizeof(pTcpTable) + return GetExtendedTcpTable.ctypes_function(pTcpTable, pdwSize, bOrder, ulAf, TableClass, Reserved) + + + # Design 2 # Design 2 should use the automatics args - \ No newline at end of file diff --git a/native_exec/native_function.py b/native_exec/native_function.py index b93eed9..796eca5 100644 --- a/native_exec/native_function.py +++ b/native_exec/native_function.py @@ -121,7 +121,7 @@ def analyse_callback(callback): def generate_stub_32(callback): from simple_x86 import * obj_id = analyse_callback(callback) - + c_callback = ctypes.c_ulong.from_address(id(callback._objects['0']) + 3 * ctypes.sizeof(ctypes.c_void_p)).value gstate_save_addr = allocator.reserve_int() return_addr_save_addr = allocator.reserve_int() diff --git a/native_exec/simple_x64.py b/native_exec/simple_x64.py index d483a94..6149d9c 100644 --- a/native_exec/simple_x64.py +++ b/native_exec/simple_x64.py @@ -58,6 +58,10 @@ class Int3(X64Instruction): mnemo = "int3" code = "CC" +class Retf(X64Instruction): + mnemo = "retf" + code = "CB" + class SimpleRegInstructionGenerator(object): name = "" @@ -65,7 +69,6 @@ class SimpleRegInstructionGenerator(object): class OneBindX64Instruction(X64Instruction): biding = 1 - class Mov_RAX_DX(OneBindX64Instruction): name = 'Mov_RAX_DX' diff --git a/network.py b/network.py new file mode 100644 index 0000000..478b4c6 --- /dev/null +++ b/network.py @@ -0,0 +1,151 @@ +import windows +import windows.k32testing +import ctypes +import socket +import struct + +from windows.generated_def.winstructs import * +from windows.generated_def.windef import * + + +class TCP4Connection(MIB_TCPROW_OWNER_PID): + + @property + def established(self): + return self.dwState == MIB_TCP_STATE_ESTAB + + @property + def remote_port(self): + return socket.ntohs(self.dwRemotePort) + + @property + def local_port(self): + return socket.ntohs(self.dwLocalPort) + + @property + def local_addr(self): + return socket.inet_ntoa(struct.pack("".format(self.local_addr, self.local_port) + return " {2}:{3}>".format(self.local_addr, self.local_port, self.remote_addr, self.remote_port) + + +class TCP6Connection(MIB_TCP6ROW_OWNER_PID): + @staticmethod + def _str_ipv6_addr(addr): + return ":".join(c.encode('hex') for c in addr) + + @property + def established(self): + return self.dwState == MIB_TCP_STATE_ESTAB + + @property + def remote_port(self): + return socket.ntohs(self.dwRemotePort) + + @property + def local_port(self): + return socket.ntohs(self.dwLocalPort) + + @property + def local_addr(self): + return self._str_ipv6_addr(self.ucLocalAddr) + + @property + def remote_addr(self): + return self._str_ipv6_addr(self.ucRemoteAddr) + + @property + def remote_proto(self): + return self.remote_port + + @property + def remote_host(self): + return self.remote_addr + + def close(self): + raise NotImplementedError("Closing IPV6 connection non implemented") + + def __repr__(self): + if not self.established: + return "".format(self.local_addr, self.local_port) + return " {2}:{3}>".format(self.local_addr, self.local_port, self.remote_addr, self.remote_port) + + +def get_MIB_TCPTABLE_OWNER_PID_from_buffer(buffer): + x = windows.generated_def.winstructs.MIB_TCPTABLE_OWNER_PID.from_buffer(buffer) + nb_entry = x.dwNumEntries + + class _GENERATED_MIB_TCPTABLE_OWNER_PID(ctypes.Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", TCP4Connection * nb_entry), + ] + return _GENERATED_MIB_TCPTABLE_OWNER_PID.from_buffer(buffer) + +def get_MIB_TCP6TABLE_OWNER_PID_from_buffer(buffer): + x = windows.generated_def.winstructs.MIB_TCP6TABLE_OWNER_PID.from_buffer(buffer) + nb_entry = x.dwNumEntries + + # Struct _MIB_TCP6TABLE_OWNER_PID definitions + class _GENERATED_MIB_TCP6TABLE_OWNER_PID(Structure): + _fields_ = [ + ("dwNumEntries", DWORD), + ("table", TCP6Connection * nb_entry), + ] + return _GENERATED_MIB_TCP6TABLE_OWNER_PID.from_buffer(buffer) + + + +def get_tcp_ipv4_sockets(): + size = ctypes.c_uint(0) + try: + windows.k32testing.GetExtendedTcpTable(None, ctypes.byref(size), ulAf=windows.generated_def.windef.AF_INET) + except windows.k32testing.IphlpapiError as e: + pass # Allow us to set size to the needed value + buffer = (ctypes.c_char * size.value)() + windows.k32testing.GetExtendedTcpTable(buffer, ctypes.byref(size), ulAf=windows.generated_def.windef.AF_INET) + t = get_MIB_TCPTABLE_OWNER_PID_from_buffer(buffer) + return list(t.table) + +def get_tcp_ipv6_sockets(): + size = ctypes.c_uint(0) + try: + windows.k32testing.GetExtendedTcpTable(None, ctypes.byref(size), ulAf=windows.generated_def.windef.AF_INET6) + except windows.k32testing.IphlpapiError as e: + pass # Allow us to set size to the needed value + buffer = (ctypes.c_char * size.value)() + windows.k32testing.GetExtendedTcpTable(buffer, ctypes.byref(size), ulAf=windows.generated_def.windef.AF_INET6) + t = get_MIB_TCP6TABLE_OWNER_PID_from_buffer(buffer) + return list(t.table) + + diff --git a/pe_parse.py b/pe_parse.py index a4ac064..a5d3103 100644 --- a/pe_parse.py +++ b/pe_parse.py @@ -16,95 +16,96 @@ def RedefineCtypesStruct(struct, replacement): _fields_ = transform_ctypes_fields(struct, replacement_) NewStruct.__name__ = struct.__name__ return NewStruct - + +# type replacement based on name def transform_ctypes_fields(struct, replacement): - return [(name, replacement.get(name, type)) for name, type in struct._fields_] + return [(name, replacement.get(name, type)) for name, type in struct._fields_] def PEFile(baseaddr): if windows.current_process.bitness == 32: IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32 else: IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64 - + class RVA(DWORD): @property def addr(self): return baseaddr + self.value - + def __repr__(self): return "".format(self.value, hex(self.addr)) - + class StringRVa(RVA): @property def str(self): return ctypes.c_char_p(self.addr).value - + def __repr__(self): return "".format(self.value, self.str) - + def __int__(self): return self.value - - + + class IMPORT_BY_NAME(ctypes.Structure): _fields_ = [ ("Hint", WORD), ("Name", BYTE) - ] - + ] + class THUNK_DATA(ctypes.Union): _fields_ = [ ("Ordinal", PVOID), ("AddressOfData", PVOID) ] - + class IATEntry(ctypes.Structure): _fields_ = [ ("value", PVOID)] - - @classmethod + + @classmethod def create(cls, addr, ord, name): self = cls.from_address(addr) self.addr = addr self.ord = ord - self.name = name + self.name = name self.hook = None self.nonhookvalue = self.value return self - + def __repr__(self): return '<{0} "{1}" ordinal {2}>'.format(self.__class__.__name__, self.name, self.ord) - + def set_hook(self, callback, types=None): import hooks # TODO: set import at the beginning hook = hooks.IATHook(self, callback, types) self.hook = hook hook.enable() return hook - + def remove_hook(self): if self.hook is None: return None self.hook.disable() self.hook = None return True - + class PEFile(object): def __init__(self): self.baseaddr = baseaddr - + def get_DOS_HEADER(self): return IMAGE_DOS_HEADER.from_address(baseaddr) - + def get_NT_HEADER(self): return self.get_DOS_HEADER().get_NT_HEADER() - + def get_OptionalHeader(self): return self.get_NT_HEADER().OptionalHeader - + def get_DataDirectory(self): return self.get_OptionalHeader().DataDirectory - + def get_IMPORT_DESCRIPTORS(self): import_datadir = self.get_DataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT] if import_datadir.VirtualAddress == 0: @@ -117,15 +118,15 @@ def PEFile(baseaddr): import_descriptor_addr += ctypes.sizeof(self.IMAGE_IMPORT_DESCRIPTOR) current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) return res - + #def get_EXPORT_DIRECTORY(self): # return self.get_OptionalHeader().get_EXPORT_DIRECTORY() - + #@property #def exports(self): # return self.get_EXPORT_DIRECTORY().get_exports() - + # TODO: get imports by parsing other modules exports if no INT @property def imports(self): @@ -139,11 +140,11 @@ def PEFile(baseaddr): iat_entry.ord = ord res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT) return res - + # Will be usable as `self.IMPORT_DESCRIPTOR` class IMAGE_IMPORT_DESCRIPTOR(ctypes.Structure): _fields_ = transform_ctypes_fields(IMAGE_IMPORT_DESCRIPTOR, {"Name" : StringRVa, "OriginalFirstThunk" : RVA, "FirstThunk" : RVA}) - + def get_INT(self): if not self.OriginalFirstThunk.value: return None @@ -160,7 +161,7 @@ def PEFile(baseaddr): int_addr += ctypes.sizeof(THUNK_DATA) int_entry = THUNK_DATA.from_address(int_addr) return res - + def get_IAT(self): iat_addr = self.FirstThunk.addr iat_entry = THUNK_DATA.from_address(iat_addr) @@ -169,10 +170,10 @@ def PEFile(baseaddr): res.append(IATEntry.create(iat_addr, -1, "??")) iat_addr += ctypes.sizeof(THUNK_DATA) iat_entry = THUNK_DATA.from_address(iat_addr) - return res - + return res + current_pe = PEFile() - + class IMAGE_DOS_HEADER(ctypes.Structure): _fields_ = [ ("e_magic", CHAR * 2), @@ -195,22 +196,22 @@ def PEFile(baseaddr): ("e_res2", WORD * 10), ("e_lfanew", DWORD), ] - + def get_NT_HEADER(self): if windows.current_process.bitness == 32: return IMAGE_NT_HEADERS32.from_address(baseaddr + self.e_lfanew) return IMAGE_NT_HEADERS64.from_address(baseaddr + self.e_lfanew) - - # + + # # def get_EXPORT_DIRECTORY(self): # export_directory_rva = self.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress # if export_directory_rva == 0: # return None # export_directory_addr = baseaddr + export_directory_rva # return IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr) - # + # + - #class IMAGE_EXPORT_DIRECTORY(ctypes.Structure): # _fields_ = [ # ("Characteristics", DWORD), @@ -225,7 +226,7 @@ def PEFile(baseaddr): # ("AddressOfNames", RVA), # ("AddressOfNameOrdinals", RVA), # ] - # + # # def get_exports(self): # NameOrdinals = (WORD * self.NumberOfNames).from_address(self.AddressOfNameOrdinals.addr) # NameOrdinals = list(NameOrdinals) diff --git a/syswow64.py b/syswow64.py new file mode 100644 index 0000000..1dc8613 --- /dev/null +++ b/syswow64.py @@ -0,0 +1,202 @@ +import struct +import ctypes +import windows +import windows.native_exec.simple_x64 as x64 +from generated_def.winstructs import * + +# Special code for syswow64 process + +CS_32bits = 0x23 +CS_64bits = 0x33 + +# See assembly into doc/NtCreateThreadStub_64b.asm +Pretty_NtCreateThreadStub = """ +50 50 53 51 52 56 57 41 50 41 51 41 52 41 53 41 +54 41 55 48 C7 C0 00 00 00 00 50 48 B8 54 68 72 +65 61 64 45 78 50 48 B8 4E 74 43 72 65 61 74 65 +50 4C 8B DC 48 C7 C3 61 72 79 41 53 48 BB 4C 6F +61 64 4C 69 62 72 53 4C 8B E4 65 48 8B 04 25 60 +00 00 00 48 8B 40 18 48 8B 40 20 48 8B D0 48 8B +C2 48 8B 58 20 48 23 DB 74 14 48 8B 48 50 48 8B +09 81 F9 6E 00 74 00 74 0B 48 8B 10 EB E0 68 42 +42 42 42 C3 8B 43 3C 48 03 C3 48 83 C0 18 8B 48 +70 48 03 CB 48 8B C1 50 8B 48 18 4C 8B E9 8B 50 +20 48 03 D3 48 33 C9 8B 34 8A 48 03 F3 51 49 8B +FB 48 C7 C1 11 00 00 00 F3 A6 8B C1 59 48 FF C1 +85 C0 75 E3 48 FF C9 58 8B 50 24 48 03 D3 66 8B +0C 4A 48 81 E1 FF FF 00 00 8B 50 1C 48 03 D3 8B +14 8A 48 03 D3 4C 8B EA 6A 00 48 8B CC 48 C7 C2 +FF FF 1F 00 49 C7 C0 00 00 00 00 49 B9 40 40 40 +40 40 40 40 40 48 C7 C0 00 00 00 00 50 50 50 50 +50 48 B8 42 42 42 42 42 42 42 42 50 48 B8 41 41 +41 41 41 41 41 41 50 41 51 41 50 52 51 41 FF D5 +48 89 84 24 E8 00 00 00 48 83 C4 40 48 83 C4 28 +48 83 C4 20 41 5D 41 5C 41 5B 41 5A 41 59 41 58 +5F 5E 5A 59 5B 58 58 +""" +NtCreateThreadStub = Pretty_NtCreateThreadStub.replace(" ", "").replace("\n", "").decode('hex') + +def genere_return_32bits_stub(ret_addr): + ret_32b = x64.MultipleInstr() + ret_32b += x64.Mov_RCX_X((CS_32bits << 32) + ret_addr) + ret_32b += x64.Push_RCX() + ret_32b += x64.Retf() + return ret_32b.get_code() + +# The format of a jump to 64bits mode +dummy_jump = "\xea" + struct.pack("'.format(self.__class__.__name__, self.tid, self.owner.name, hex(id(self))) - - + + class CurrentProcess(object): get_peb = None get_peb_32_code = '64a130000000c3'.decode('hex') - + # mov rax,QWORD PTR gs:0x60 # ret get_peb_64_code = "65488B042560000000C3".decode('hex') - + def get_peb_builtin(self): if self.get_peb is not None: return self.get_peb @@ -84,48 +83,64 @@ class CurrentProcess(object): get_peb = native_exec.create_function(self.get_peb_64_code, [PVOID]) self.get_peb = get_peb return get_peb - - @property + + @property def peb(self): return PEB.from_address(self.get_peb_builtin()()) - + @property def bitness(self): """Return 32 or 64""" import platform bits = platform.architecture()[0] return int(bits[:2]) - + @property def is_wow_64(self): - return utils.is_wow_64(kernel32proxy.GetCurrentProcess()) + return utils.is_wow_64(kernel32proxy.GetCurrentProcess()) + + def virtual_alloc(self, size): + return kernel32proxy.VirtualAlloc(dwSize=size) + + def write_memory(self, addr, data): + buffertype = (c_char * len(data)).from_address(addr) + buffertype[:len(data)] = data + return True + + def read_memory(self, addr, size): + buffer = (c_char * size).from_address(addr) + return buffer[:] class WinProcess(PROCESSENTRY32, AutoHandle): is_pythondll_injected = 0 is_remote_slave_running = False - + @property def name(self): return self.szExeFile[:] - - @property + + @property def pid(self): return self.th32ProcessID - + + @property + def ppid(self): + return self.th32ParentProcessID + @property def threads(self): return [thread for thread in utils.enumerate_threads() if thread.th32OwnerProcessID == self.pid] - + def _get_handle(self): return kernel32proxy.OpenProcess(dwProcessId=self.pid) - + def __repr__(self): return '<{0} "{1}" pid {2} at {3}>'.format(self.__class__.__name__, self.name, self.pid, hex(id(self))) - + @property def is_wow_64(self): - return utils.is_wow_64(self.handle) - + return utils.is_wow_64(self.handle) + @property def bitness(self): if windows.system.bitness == 32: @@ -133,106 +148,115 @@ class WinProcess(PROCESSENTRY32, AutoHandle): if self.is_wow_64: return 32 return 64 - + def virtual_alloc(self, size): return kernel32proxy.VirtualAllocEx(self.handle, dwSize=size) - + def write_memory(self, addr, data): return kernel32proxy.WriteProcessMemory(self.handle, addr, lpBuffer=data) - + + def low_read_memory(self, addr, buffer_addr, size): + if windows.current_process.bitness == 32 and self.bitness == 64: + NtWow64ReadVirtualMemory64Addr = windows.utils.get_func_addr("ntdll.dll", "NtWow64ReadVirtualMemory64") + NtWow64ReadVirtualMemory64 = WINFUNCTYPE(HRESULT, HANDLE, ULONG64, PVOID, ULONG64, PULONG64)(NtWow64ReadVirtualMemory64Addr) + return NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size, None) + return kernel32proxy.ReadProcessMemory(self.handle, addr, lpBuffer=buffer_addr, nSize=size) + def read_memory(self, addr, size): - return kernel32proxy.ReadProcessMemory(self.handle, addr, nSize=size) - -## CreateRemoteThread(hProcess, lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId): -#CreateRemoteThreadPrototype = WINFUNCTYPE(HANDLE, HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD) - - def NtCreateThreadEx(self, addr, param): - print("CALLING SPECIAL NtCreateThreadEx") - NtCreateThreadExAddr = utils.get_func_addr("ntdll.dll", "NtCreateThreadEx") - NtCreateThreadEx = WINFUNCTYPE(HRESULT, PHANDLE, LPSECURITY_ATTRIBUTES, PVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID, BOOL, DWORD, DWORD, DWORD, PVOID)(NtCreateThreadExAddr) - thread_handle = HANDLE() - res = NtCreateThreadEx(byref(thread_handle), None, None, self.handle, addr, param, False, 0, 0, 0, None) - print("RES = {0}".format(hex(res & 0xffffffff))) - if res: - raise WinError() - - def RtlCreateUserThread(self, addr, param): - print("CALLING SPECIAL RtlCreateUserThread") - RtlCreateUserThreadAddr = utils.get_func_addr("ntdll.dll", "RtlCreateUserThread") - RtlCreateUserThread = WINFUNCTYPE(HRESULT, HANDLE, LPSECURITY_ATTRIBUTES, BOOL, ULONG, PULONG, PULONG, PVOID, PVOID, PHANDLE, PVOID)(RtlCreateUserThreadAddr) - thread_handle = HANDLE() - tmp1 = DWORD() - tmp2 = DWORD() - res = RtlCreateUserThread(self.handle, None, False, 0, None, None, addr, param, None, None) - print("RES = {0}".format(hex(res & 0xffffffff))) - if res: - raise WinError() - - + buffer = ctypes.create_string_buffer(size) + self.low_read_memory(addr, ctypes.byref(buffer), size) + return buffer[:] + + def read_memory_into(self, addr, struct): + self.low_read_memory(addr, ctypes.byref(struct), ctypes.sizeof(struct)) + return struct + def create_thread(self, addr, param): if windows.current_process.bitness == 32 and self.bitness == 64: - raise NotImplementedError("Injection 32 to 64") - return kernel32proxy.CreateRemoteThread(hProcess=self.handle, lpStartAddress=addr, lpParameter=param) - + return windows.syswow64.NtCreateThreadEx_32_to_64(self, addr, param) + return kernel32proxy.CreateRemoteThread(hProcess=self.handle, lpStartAddress=addr, lpParameter=param) + def load_library(self, dll_path): x = self.virtual_alloc(0x1000) self.write_memory(x, dll_path) LoadLibrary = utils.get_func_addr('kernel32', 'LoadLibraryA') return self.create_thread(LoadLibrary, x) - + def execute(self, code): x = self.virtual_alloc(len(code)) self.write_memory(x, code) return self.create_thread(x, 0) - + def execute_python(self, pycode): return injection.execute_python_code(self, pycode) - - + + #def NtCreateThreadEx(self, addr, param): + # print("CALLING SPECIAL NtCreateThreadEx") + # NtCreateThreadExAddr = utils.get_func_addr("ntdll.dll", "NtCreateThreadEx") + # NtCreateThreadEx = WINFUNCTYPE(HRESULT, PHANDLE, DWORD, PVOID, HANDLE, LPTHREAD_START_ROUTINE, LPVOID, BOOL, DWORD, DWORD, DWORD, PVOID)(NtCreateThreadExAddr) + # thread_handle = HANDLE() + # res = NtCreateThreadEx(byref(thread_handle), 0x1fffff, None, self.handle, addr, param, False, 0, 0, 0, None) + # print("RES = {0}".format(hex(res & 0xffffffff))) + # if res: + # raise WinError() + # + #def RtlCreateUserThread(self, addr, param): + # print("CALLING SPECIAL RtlCreateUserThread") + # RtlCreateUserThreadAddr = utils.get_func_addr("ntdll.dll", "RtlCreateUserThread") + # RtlCreateUserThread = WINFUNCTYPE(HRESULT, HANDLE, LPSECURITY_ATTRIBUTES, BOOL, ULONG, PULONG, PULONG, PVOID, PVOID, PHANDLE, PVOID)(RtlCreateUserThreadAddr) + # thread_handle = HANDLE() + # tmp1 = DWORD() + # tmp2 = DWORD() + # res = RtlCreateUserThread(self.handle, None, False, 0, None, None, addr, param, None, None) + # print("RES = {0}".format(hex(res & 0xffffffff))) + # if res: + # raise WinError() + + class LoadedModule(LDR_DATA_TABLE_ENTRY): @property def baseaddr(self): return self.DllBase - + @property def name(self): return self.BaseDllName.Buffer - + @property def fullname(self): return self.FullDllName.Buffer def __repr__(self): return '<{0} "{1}" at {2}>'.format(self.__class__.__name__, self.name, hex(id(self))) - + @property def pe(self): return pe_parse.PEFile(self.baseaddr) - + class WinUnicodeString(LSA_UNICODE_STRING): def __repr__(self): return """<{0} "{1}" at {2}>""".format(type(self).__name__, self.Buffer, hex(id(self))) - + class LIST_ENTRY_PTR(PVOID): def TO_LDR_ENTRY(self): return LDR_DATA_TABLE_ENTRY.from_address(self.value - sizeof(PVOID) * 2) -# May want to have all known fields.. +# May want to have all known fields.. class PEB(PEB): - + @property def imagepath(self): raw_imagepath = self.ProcessParameters.contents.ImagePathName return WinUnicodeString.from_address(ctypes.addressof(raw_imagepath)) - + @property def commandline(self): # This or changing the __repr__ of LSA_UNICODE_STRING raw_cmd = self.ProcessParameters.contents.CommandLine return WinUnicodeString.from_address(ctypes.addressof(raw_cmd)) - + @property def modules(self): res = []