From c40cb0c8b062ce16cf44d45a7bb59affd5bd29a6 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Wed, 10 Feb 2016 16:29:46 +0100 Subject: [PATCH] Add get_mapped_filename to WinProcess --- ctypes_generation/winfunc.txt | 14 +++ windows/__init__.py | 3 +- windows/generated_def/winfuncs.py | 10 +- windows/winobject.py | 201 +++++++++++++++--------------- windows/winproxy.py | 52 ++++++-- 5 files changed, 168 insertions(+), 112 deletions(-) diff --git a/ctypes_generation/winfunc.txt b/ctypes_generation/winfunc.txt index 64289b1..271c897 100644 --- a/ctypes_generation/winfunc.txt +++ b/ctypes_generation/winfunc.txt @@ -45,6 +45,7 @@ NTSTATUS WINAPI NtQuerySystemInformation( _Out_opt_ PULONG ReturnLength ); + NTSTATUS WINAPI NtQueryInformationProcess( _In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, @@ -748,3 +749,16 @@ BOOL WINAPI Wow64SetThreadContext( __in CONST WOW64_CONTEXT *lpContext ); +DWORD WINAPI GetMappedFileNameW ( + __in HANDLE hProcess, + __in LPVOID lpv, + __out PVOID lpFilename, + __in DWORD nSize +); + +DWORD WINAPI GetMappedFileNameA ( + __in HANDLE hProcess, + __in LPVOID lpv, + __out PVOID lpFilename, + __in DWORD nSize +); \ No newline at end of file diff --git a/windows/__init__.py b/windows/__init__.py index 7b6906d..640f348 100644 --- a/windows/__init__.py +++ b/windows/__init__.py @@ -22,9 +22,10 @@ current_thread = CurrentThread() # Late import: other imports should go here # Do not move it: risk of circular import -import windows.vectored_exception +import windows.exception import windows.wmi import windows.utils +import windows.debug __all__ = ["system", "VirtualProtected", 'current_process', 'current_thread', 'winproxy'] diff --git a/windows/generated_def/winfuncs.py b/windows/generated_def/winfuncs.py index cb9a702..848125b 100644 --- a/windows/generated_def/winfuncs.py +++ b/windows/generated_def/winfuncs.py @@ -3,7 +3,7 @@ from ctypes import * from ctypes.wintypes import * from .winstructs import * -functions = ['ExitProcess', 'TerminateProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'LdrLoadDll', 'NtQuerySystemInformation', 'NtQueryInformationProcess', 'NtQueryVirtualMemory', 'NtCreateThreadEx', 'NtQueryInformationThread', 'GetExitCodeThread', 'GetExitCodeProcess', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualFree', 'VirtualFreeEx', 'VirtualProtect', 'VirtualQuery', 'VirtualQueryEx', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateThread', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'NtGetContextThread', 'SetThreadContext', 'NtSetContextThread', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'NtWow64ReadVirtualMemory64', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentThreadId', 'GetCurrentProcessorNumber', 'AllocConsole', 'FreeConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile', 'GetExtendedTcpTable', 'GetExtendedUdpTable', 'SetTcpEntry', 'AddVectoredContinueHandler', 'AddVectoredExceptionHandler', 'TerminateThread', 'ExitThread', 'RemoveVectoredExceptionHandler', 'ResumeThread', 'SuspendThread', 'WaitForSingleObject', 'GetThreadId', 'LoadLibraryExA', 'LoadLibraryExW', 'SymInitialize', 'SymFromName', 'SymLoadModuleEx', 'SymSetOptions', 'SymGetTypeInfo', 'DeviceIoControl', 'GetTokenInformation', 'RegOpenKeyExA', 'RegOpenKeyExW', 'RegGetValueA', 'RegGetValueW', 'RegCloseKey', 'Wow64DisableWow64FsRedirection', 'Wow64RevertWow64FsRedirection', 'Wow64EnableWow64FsRedirection', 'Wow64GetThreadContext', 'SetConsoleCtrlHandler', 'WinVerifyTrust', 'GlobalAlloc', 'GlobalFree', 'GlobalUnlock', 'GlobalLock', 'OpenClipboard', 'EmptyClipboard', 'CloseClipboard', 'SetClipboardData', 'GetClipboardData', 'EnumClipboardFormats', 'GetClipboardFormatNameA', 'GetClipboardFormatNameW', 'WinVerifyTrust', 'OpenProcessToken', 'OpenThreadToken', 'GetTokenInformation', 'SetTokenInformation', 'GetSidIdentifierAuthority', 'GetSidSubAuthority', 'GetSidSubAuthorityCount', 'DebugBreak', 'WaitForDebugEvent', 'ContinueDebugEvent', 'DebugActiveProcess', 'DebugActiveProcessStop', 'DebugSetProcessKillOnExit', 'DebugBreakProcess', 'GetProcessId', 'Wow64SetThreadContext'] +functions = ['ExitProcess', 'TerminateProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'LdrLoadDll', 'NtQuerySystemInformation', 'NtQueryInformationProcess', 'NtQueryVirtualMemory', 'NtCreateThreadEx', 'NtQueryInformationThread', 'GetExitCodeThread', 'GetExitCodeProcess', 'VirtualAlloc', 'VirtualAllocEx', 'VirtualFree', 'VirtualFreeEx', 'VirtualProtect', 'VirtualQuery', 'VirtualQueryEx', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateThread', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'NtGetContextThread', 'SetThreadContext', 'NtSetContextThread', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'NtWow64ReadVirtualMemory64', 'WriteProcessMemory', 'CreateToolhelp32Snapshot', 'Thread32First', 'Thread32Next', 'Process32First', 'Process32Next', 'Process32FirstW', 'Process32NextW', 'GetProcAddress', 'LoadLibraryA', 'LoadLibraryW', 'OpenProcessToken', 'LookupPrivilegeValueA', 'LookupPrivilegeValueW', 'AdjustTokenPrivileges', 'FindResourceA', 'FindResourceW', 'SizeofResource', 'LoadResource', 'LockResource', 'GetVersionExA', 'GetVersionExW', 'GetVersion', 'GetCurrentThread', 'GetCurrentThreadId', 'GetCurrentProcessorNumber', 'AllocConsole', 'FreeConsole', 'GetStdHandle', 'SetStdHandle', 'SetThreadAffinityMask', 'WriteFile', 'GetExtendedTcpTable', 'GetExtendedUdpTable', 'SetTcpEntry', 'AddVectoredContinueHandler', 'AddVectoredExceptionHandler', 'TerminateThread', 'ExitThread', 'RemoveVectoredExceptionHandler', 'ResumeThread', 'SuspendThread', 'WaitForSingleObject', 'GetThreadId', 'LoadLibraryExA', 'LoadLibraryExW', 'SymInitialize', 'SymFromName', 'SymLoadModuleEx', 'SymSetOptions', 'SymGetTypeInfo', 'DeviceIoControl', 'GetTokenInformation', 'RegOpenKeyExA', 'RegOpenKeyExW', 'RegGetValueA', 'RegGetValueW', 'RegCloseKey', 'Wow64DisableWow64FsRedirection', 'Wow64RevertWow64FsRedirection', 'Wow64EnableWow64FsRedirection', 'Wow64GetThreadContext', 'SetConsoleCtrlHandler', 'WinVerifyTrust', 'GlobalAlloc', 'GlobalFree', 'GlobalUnlock', 'GlobalLock', 'OpenClipboard', 'EmptyClipboard', 'CloseClipboard', 'SetClipboardData', 'GetClipboardData', 'EnumClipboardFormats', 'GetClipboardFormatNameA', 'GetClipboardFormatNameW', 'WinVerifyTrust', 'OpenProcessToken', 'OpenThreadToken', 'GetTokenInformation', 'SetTokenInformation', 'GetSidIdentifierAuthority', 'GetSidSubAuthority', 'GetSidSubAuthorityCount', 'DebugBreak', 'WaitForDebugEvent', 'ContinueDebugEvent', 'DebugActiveProcess', 'DebugActiveProcessStop', 'DebugSetProcessKillOnExit', 'DebugBreakProcess', 'GetProcessId', 'Wow64SetThreadContext', 'GetMappedFileNameW', 'GetMappedFileNameA'] # ExitProcess(uExitCode): ExitProcessPrototype = WINFUNCTYPE(VOID, UINT) @@ -525,3 +525,11 @@ GetProcessIdParams = ((1, 'Process'),) Wow64SetThreadContextPrototype = WINFUNCTYPE(BOOL, HANDLE, POINTER(WOW64_CONTEXT)) Wow64SetThreadContextParams = ((1, 'hThread'), (1, 'lpContext')) +# GetMappedFileNameW(hProcess, lpv, lpFilename, nSize): +GetMappedFileNameWPrototype = WINFUNCTYPE(DWORD, HANDLE, LPVOID, PVOID, DWORD) +GetMappedFileNameWParams = ((1, 'hProcess'), (1, 'lpv'), (1, 'lpFilename'), (1, 'nSize')) + +# GetMappedFileNameA(hProcess, lpv, lpFilename, nSize): +GetMappedFileNameAPrototype = WINFUNCTYPE(DWORD, HANDLE, LPVOID, PVOID, DWORD) +GetMappedFileNameAParams = ((1, 'hProcess'), (1, 'lpv'), (1, 'lpFilename'), (1, 'nSize')) + diff --git a/windows/winobject.py b/windows/winobject.py index 8874b2e..8acc36e 100644 --- a/windows/winobject.py +++ b/windows/winobject.py @@ -11,7 +11,7 @@ import windows import windows.network import windows.registry import windows.syswow64 -#import windows.vectored_exception +import windows.exception import windows.winproxy as winproxy import windows.injection as injection import windows.native_exec as native_exec @@ -71,27 +71,21 @@ class System(object): def processes(self): """The list of running processes - :type: [:class:`WinProcess`] -- A list of Process - - """ + :type: [:class:`WinProcess`] -- A list of Process""" return self.enumerate_processes() @property def threads(self): """The list of running threads - :type: [:class:`WinThread`] -- A list of Thread - - """ + :type: [:class:`WinThread`] -- A list of Thread""" return self.enumerate_threads() @utils.fixedpropety def bitness(self): """The bitness of the system - :type: :class:`int` -- 32 or 64 - - """ + :type: :class:`int` -- 32 or 64""" if os.environ["PROCESSOR_ARCHITECTURE"].lower() != "x86": return 64 if "PROCESSOR_ARCHITEW6432" in os.environ: @@ -136,9 +130,7 @@ class WinThread(THREADENTRY32, AutoHandle): def owner(self): """The Process owning the thread - :type: :class:`WinProcess` - - """ + :type: :class:`WinProcess`""" if hasattr(self, "_owner"): return self._owner try: @@ -149,28 +141,32 @@ class WinThread(THREADENTRY32, AutoHandle): @property def context(self): + """The context of the thread, type depend of the target process. + + :type: :class:`windows.exception.ECONTEXT32` or :class:`windows.exception.ECONTEXT64` or :class:`windows.exception.ECONTEXTWOW64` """ if self.owner.bitness == 32 and windows.current_process.bitness == 64: # Wow64 - x = windows.vectored_exception.EnhancedCONTEXTWOW64() + x = windows.exception.ECONTEXTWOW64() x.ContextFlags = CONTEXT_ALL winproxy.Wow64GetThreadContext(self.handle, x) return x if self.owner.bitness == 64 and windows.current_process.bitness == 32: - x = windows.vectored_exception.EnhancedCONTEXT64.new_aligned() + x = windows.exception.ECONTEXT64.new_aligned() x.ContextFlags = CONTEXT_ALL windows.syswow64.NtGetContextThread_32_to_64(self.handle, x) return x if self.owner.bitness == 32: - x = windows.vectored_exception.EnhancedCONTEXT32() + x = windows.exception.ECONTEXT32() else: - x = windows.vectored_exception.EnhancedCONTEXT64.new_aligned() + x = windows.exception.ECONTEXT64.new_aligned() x.ContextFlags = CONTEXT_ALL winproxy.GetThreadContext(self.handle, x) return x def set_context(self, context): + """Set the thread context to ``context``""" if self.owner.bitness == windows.current_process.bitness: return winproxy.SetThreadContext(self.handle, context) if windows.current_process.bitness == 64 and self.owner.bitness == 32: @@ -181,8 +177,7 @@ class WinThread(THREADENTRY32, AutoHandle): def start_address(self): """The start address of the thread - :type: :class:`int` - """ + :type: :class:`int`""" if windows.current_process.bitness == 32 and self.owner.bitness == 64: res = ULONGLONG() windows.syswow64.NtQueryInformationThread_32_to_64(self.handle, ThreadQuerySetWin32StartAddress, byref(res), ctypes.sizeof(res)) @@ -214,16 +209,14 @@ class WinThread(THREADENTRY32, AutoHandle): def is_exit(self): """Is ``True`` if the thread is terminated - :type: :class:`bool` - """ + :type: :class:`bool`""" return self.exit_code != STILL_ACTIVE @property def exit_code(self): """The exit code of the thread : ``STILL_ACTIVE`` means the process is not dead - :type: :class:`int` - """ + :type: :class:`int`""" res = DWORD() winproxy.GetExitCodeThread(self.handle, byref(res)) return res.value @@ -263,16 +256,14 @@ class DeadThread(AutoHandle): def is_exit(self): """Is ``True`` if the thread is terminated - :type: :class:`bool` - """ + :type: :class:`bool`""" return self.exit_code != STILL_ACTIVE @property def exit_code(self): """The exit code of the thread : ``STILL_ACTIVE`` means the process is not dead - :type: :class:`int` - """ + :type: :class:`int`""" res = DWORD() winproxy.GetExitCodeThread(self.handle, byref(res)) return res.value @@ -283,8 +274,7 @@ class Process(AutoHandle): def is_wow_64(self): """``True`` if the process is a SysWow64 process (32bit process on 64bits system). - :type: :class:`bool` - """ + :type: :class:`bool`""" return utils.is_wow_64(self.handle) @utils.fixedpropety @@ -302,8 +292,7 @@ class Process(AutoHandle): def threads(self): """The threads of the process - :type: [:class:`WinThread`] -- A list of Thread - """ + :type: [:class:`WinThread`] -- A list of Thread""" return [thread for thread in windows.system.threads if thread.th32OwnerProcessID == self.pid] def virtual_alloc(self, size): @@ -316,8 +305,7 @@ class Process(AutoHandle): def exit_code(self): """The exit code of the process : ``STILL_ACTIVE`` means the process is not dead - :type: :class:`int` - """ + :type: :class:`int`""" res = DWORD() winproxy.GetExitCodeProcess(self.handle, byref(res)) return res.value @@ -326,12 +314,14 @@ class Process(AutoHandle): def is_exit(self): """``True`` if the process is terminated - :type: :class:`bool` - """ + :type: :class:`bool`""" return self.exit_code != STILL_ACTIVE @contextmanager def allocated_memory(self, size): + """ContextManager to allocate memory and free it + + :type: :class:`int` -- the address of the allocated memory""" addr = self.virtual_alloc(size) try: yield addr @@ -350,8 +340,7 @@ class Process(AutoHandle): def query_memory(self, addr): """Query the memory informations about page at ``addr`` - :rtype: :class:`MEMORY_BASIC_INFORMATION` - """ + :rtype: :class:`MEMORY_BASIC_INFORMATION`""" if windows.current_process.bitness == 32 and self.bitness == 64: res = MEMORY_BASIC_INFORMATION64() try: @@ -371,8 +360,7 @@ class Process(AutoHandle): def memory_state(self): """Yield the memory information for the whole address space of the process - :yield: :class:`MEMORY_BASIC_INFORMATION` - """ + :yield: :class:`MEMORY_BASIC_INFORMATION`""" addr = 0 res = [] while True: @@ -383,24 +371,40 @@ class Process(AutoHandle): return addr += x.RegionSize - def read_char(self, addr): + def mapped_filename(self, addr): + """The filename mapped at address ``addr`` or None + + :rtype: :class:`str` or None""" + buffer = ctypes.c_buffer(0x1024) + try: + size = windows.winproxy.GetMappedFileNameA(self.handle, addr, buffer) + except windows.winproxy.Kernel32Error: + return None + return buffer[:size] + + def read_byte(self, addr): + """Read a ``CHAR`` at ``addr``""" sizeof_char = sizeof(CHAR) return struct.unpack(" 0xffffffff: + # return winproxy.NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size) return winproxy.ReadProcessMemory(self.handle, addr, lpBuffer=buffer_addr, nSize=size) def read_memory(self, addr, size): """Read ``size`` from ``addr`` :return: The data read - :rtype: :class:`str` - """ + :rtype: :class:`str`""" buffer = ctypes.create_string_buffer(size) self.low_read_memory(addr, ctypes.byref(buffer), size) return buffer[:] @@ -694,8 +700,7 @@ class WinProcess(PROCESSENTRY32, Process): def create_thread(self, addr, param): """Create a remote thread - :rtype: :class:`WinThread` or :class:`DeadThread` - """ + :rtype: :class:`WinThread` or :class:`DeadThread`""" if windows.current_process.bitness == 32 and self.bitness == 64: thread_handle = HANDLE() windows.syswow64.NtCreateThreadEx_32_to_64(ThreadHandle=byref(thread_handle) ,ProcessHandle=self.handle, lpStartAddress=addr, lpParameter=param) @@ -724,8 +729,7 @@ class WinProcess(PROCESSENTRY32, Process): def peb_addr(self): """The address of the PEB - :type: :class:`int` - """ + :type: :class:`int`""" if windows.current_process.bitness == 32 and self.bitness == 64: x = windows.remotectypes.transform_type_to_remote64bits(PROCESS_BASIC_INFORMATION) # Fuck-it <3 @@ -751,8 +755,7 @@ class WinProcess(PROCESSENTRY32, Process): def peb(self): """The PEB of the remote process (see :mod:`remotectypes`) - :type: :class:`PEB` - """ + :type: :class:`PEB`""" if windows.current_process.bitness == 32 and self.bitness == 64: return RemotePEB64(self.peb_addr, self) if windows.current_process.bitness == 64 and self.bitness == 32: @@ -761,6 +764,9 @@ class WinProcess(PROCESSENTRY32, Process): @utils.fixedpropety def peb_syswow(self): + """The 64bits PEB of a SysWow64 process + + :type: :class:`PEB`""" if not self.is_wow_64: raise ValueError("Not a syswow process") if windows.current_process.bitness == 64: @@ -785,11 +791,15 @@ class WinProcess(PROCESSENTRY32, Process): # Create ProcessToken and Thread Token objects ? class Token(AutoHandle): + """The token of a process""" def __init__(self, handle): self._handle = handle @property def integrity(self): + """Return the integrity level of a process + + :type: :class:`int`""" buffer_size = self.get_required_information_size(TokenIntegrityLevel) buffer = ctypes.c_buffer(buffer_size) self.get_informations(TokenIntegrityLevel, buffer) @@ -825,24 +835,21 @@ class LoadedModule(LDR_DATA_TABLE_ENTRY): def baseaddr(self): """Base address of the module - :type: :class:`int` - """ + :type: :class:`int`""" return self.DllBase @property def name(self): """Name of the module - :type: :class:`str` - """ + :type: :class:`str`""" return str(self.BaseDllName.Buffer).lower() @property def fullname(self): """Full name of the module (path) - :type: :class:`str` - """ + :type: :class:`str`""" return self.FullDllName.Buffer.decode() def __repr__(self): @@ -852,8 +859,7 @@ class LoadedModule(LDR_DATA_TABLE_ENTRY): def pe(self): """A PE representation of the module - :type: :class:`windows.pe_parse.PEFile` - """ + :type: :class:`windows.pe_parse.PEFile`""" return pe_parse.GetPEFile(self.baseaddr) @@ -892,16 +898,14 @@ class PEB(Structure): def imagepath(self): """The ImagePathName of the PEB - :type: :class:`WinUnicodeString` - """ + :type: :class:`WinUnicodeString`""" return self.ProcessParameters.contents.ImagePathName @property def commandline(self): """The CommandLine of the PEB - :type: :class:`WinUnicodeString` - """ + :type: :class:`WinUnicodeString`""" # This or changing the __repr__ of LSA_UNICODE_STRING return self.ProcessParameters.contents.CommandLine @@ -909,8 +913,7 @@ class PEB(Structure): def modules(self): """The loaded modules present in the PEB - :type: [:class:`LoadedModule`] -- List of loaded modules - """ + :type: [:class:`LoadedModule`] -- List of loaded modules""" res = [] list_entry_ptr = ctypes.cast(self.Ldr.contents.InMemoryOrderModuleList.Flink, LIST_ENTRY_PTR) current_dll = list_entry_ptr.TO_LDR_ENTRY() @@ -927,8 +930,7 @@ class RemoteLoadedModule(rctypes.RemoteStructure.from_structure(LoadedModule)): def pe(self): """A PE representation of the module - :type: :class:`windows.pe_parse.PEFile` - """ + :type: :class:`windows.pe_parse.PEFile`""" return pe_parse.GetPEFile(self.baseaddr, target=self._target) @@ -941,8 +943,7 @@ class RemotePEB(rctypes.RemoteStructure.from_structure(PEB)): def modules(self): """The loaded modules present in the PEB - :type: [:class:`LoadedModule`] -- List of loaded modules - """ + :type: [:class:`LoadedModule`] -- List of loaded modules""" res = [] if not self.Ldr.value: raise ValueError("PEB->Ldr is NULL: cannot walk the module list") @@ -961,8 +962,7 @@ if CurrentProcess().bitness == 32: def pe(self): """A PE representation of the module - :type: :class:`windows.pe_parse.PEFile` - """ + :type: :class:`windows.pe_parse.PEFile`""" return pe_parse.GetPEFile(self.baseaddr, target=self._target) class RemotePEB64(rctypes.transform_type_to_remote64bits(PEB)): @@ -974,8 +974,7 @@ if CurrentProcess().bitness == 32: def modules(self): """The loaded modules present in the PEB - :type: [:class:`LoadedModule`] -- List of loaded modules - """ + :type: [:class:`LoadedModule`] -- List of loaded modules""" res = [] if not self.Ldr.value: raise ValueError("PEB->Ldr is NULL: cannot walk the module list") @@ -994,8 +993,7 @@ if CurrentProcess().bitness == 64: def pe(self): """A PE representation of the module - :type: :class:`windows.pe_parse.PEFile` - """ + :type: :class:`windows.pe_parse.PEFile`""" return pe_parse.GetPEFile(self.baseaddr, target=self._target) class RemotePEB32(rctypes.transform_type_to_remote32bits(PEB)): @@ -1007,8 +1005,7 @@ if CurrentProcess().bitness == 64: def modules(self): """The loaded modules present in the PEB - :type: [:class:`LoadedModule`] -- List of loaded modules - """ + :type: [:class:`LoadedModule`] -- List of loaded modules""" res = [] if not self.Ldr.value: raise ValueError("PEB->Ldr is NULL: cannot walk the module list") diff --git a/windows/winproxy.py b/windows/winproxy.py index d8be864..6a56171 100644 --- a/windows/winproxy.py +++ b/windows/winproxy.py @@ -136,6 +136,7 @@ class ApiProxy(object): return self._cprototyped(*args) setattr(python_proxy, "ctypes_function", perform_call) + setattr(python_proxy, "force_resolution", generate_ctypes_function) return python_proxy @@ -166,7 +167,9 @@ class Ole32Proxy(ApiProxy): APIDLL = "ole32" default_error_check = staticmethod(no_error_check) - +class PsapiProxy(ApiProxy): + APIDLL = "psapi" + default_error_check = staticmethod(kernel32_error_check) class OptionalExport(object): """used 'around' a Proxy decorator @@ -183,7 +186,9 @@ class OptionalExport(object): def __call__(self, f): try: - return self.subdecorator(f) + x = self.subdecorator(f) + x.force_resolution() + return x except ExportNotFound as e: dbgprint("Export <{e.func_name}> not found in <{e.api_name}>".format(e=e), "EXPORTNOTFOUND") return None @@ -200,14 +205,17 @@ class TransparentApiProxy(object): def __call__(self, *args, **kwargs): if self._ctypes_function is None: - try: - c_prototyped = self.prototype((self.func_name, getattr(ctypes.windll, self.dll_name)), self.args) - except AttributeError: - raise ExportNotFound(func_name, APIDLL) - c_prototyped.errcheck = functools.wraps(self.error_check)(functools.partial(self.error_check, self.func_name)) - self._ctypes_function = c_prototyped + self.force_resolution() return self._ctypes_function(*args, **kwargs) + def force_resolution(self): + try: + c_prototyped = self.prototype((self.func_name, getattr(ctypes.windll, self.dll_name)), self.args) + except AttributeError: + raise ExportNotFound(func_name, APIDLL) + c_prototyped.errcheck = functools.wraps(self.error_check)(functools.partial(self.error_check, self.func_name)) + self._ctypes_function = 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) @@ -470,6 +478,34 @@ def DeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize=None, lp return DeviceIoControl.ctypes_function(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped) +# TODO: might be in another DLL depending of version +# Should handle this.. + +@OptionalExport(Kernel32Proxy("GetMappedFileNameW")) +def GetMappedFileNameW(hProcess, lpv, lpFilename, nSize=None): + if nSize is None: + nSize = ctypes.sizeof(lpFilename) + return GetMappedFileNameW.ctypes_function(hProcess, lpv, lpFilename, nSize) + +@OptionalExport(Kernel32Proxy("GetMappedFileNameA")) +def GetMappedFileNameA(hProcess, lpv, lpFilename, nSize=None): + if nSize is None: + nSize = ctypes.sizeof(lpFilename) + return GetMappedFileNameA.ctypes_function(hProcess, lpv, lpFilename, nSize) + +if GetMappedFileNameA is None: + @PsapiProxy("GetMappedFileNameW") + def GetMappedFileNameW(hProcess, lpv, lpFilename, nSize=None): + if nSize is None: + nSize = ctypes.sizeof(lpFilename) + return GetMappedFileNameW.ctypes_function(hProcess, lpv, lpFilename, nSize) + + @PsapiProxy("GetMappedFileNameA") + def GetMappedFileNameA(hProcess, lpv, lpFilename, nSize=None): + if nSize is None: + nSize = ctypes.sizeof(lpFilename) + return GetMappedFileNameA.ctypes_function(hProcess, lpv, lpFilename, nSize) + # Debug API DebugBreak = TransparentKernel32Proxy("DebugBreak")