From b621e6a09fb6ae9062fabf542196586c6effc66a Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Mon, 18 Apr 2016 11:24:41 +0200 Subject: [PATCH] fix queryworkingset / add test / add virtual protect context manager --- ctypes_generation/winfunc.txt | 26 ++++++++ windows/generated_def/winfuncs.py | 17 +++++- windows/syswow64.py | 9 +++ windows/test/mytest.py | 98 ++++++++++++++++++++++++++++++- windows/winobject/process.py | 41 +++++++++++-- windows/winproxy.py | 21 ++++++- 6 files changed, 202 insertions(+), 10 deletions(-) diff --git a/ctypes_generation/winfunc.txt b/ctypes_generation/winfunc.txt index 7e867a9..34edbe0 100644 --- a/ctypes_generation/winfunc.txt +++ b/ctypes_generation/winfunc.txt @@ -110,6 +110,15 @@ LPVOID WINAPI VirtualAllocEx( _In_ DWORD flProtect ); +NTSTATUS WINAPI NtProtectVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PULONG NumberOfBytesToProtect, + _In_ ULONG NewAccessProtection, + _Out_ PULONG OldAccessProtection +); + + BOOL WINAPI VirtualFree( _In_ LPVOID lpAddress, _In_ SIZE_T dwSize, @@ -130,6 +139,15 @@ BOOL WINAPI VirtualProtect( _Out_ PDWORD lpflOldProtect ); +BOOL WINAPI VirtualProtectEx( + _In_ HANDLE hProcess, + _In_ LPVOID lpAddress, + _In_ SIZE_T dwSize, + _In_ DWORD flNewProtect, + _Out_ PDWORD lpflOldProtect +); + + DWORD VirtualQuery( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, @@ -281,6 +299,14 @@ BOOL WINAPI WriteProcessMemory( _Out_ SIZE_T *lpNumberOfBytesWritten ); +BOOL WINAPI NtWow64WriteVirtualMemory64( + _In_ HANDLE hProcess, + _In_ ULONG64 lpBaseAddress, + _Out_ LPVOID lpBuffer, + _In_ ULONG64 nSize, + _Out_ PULONG64 *lpNumberOfBytesWritten +); + HANDLE WINAPI CreateToolhelp32Snapshot( _In_ DWORD dwFlags, _In_ DWORD th32ProcessID diff --git a/windows/generated_def/winfuncs.py b/windows/generated_def/winfuncs.py index 53db1e2..a9fc12b 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', 'QueryWorkingSet', 'QueryWorkingSetEx', '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', 'RtlInitString', 'RtlInitUnicodeString', 'RtlAnsiStringToUnicodeString', 'OpenEventA', 'OpenEventW', 'NtOpenEvent', 'NtAlpcCreatePort', 'NtAlpcConnectPort', 'NtAlpcAcceptConnectPort', 'AlpcInitializeMessageAttribute', 'AlpcGetMessageAttribute', 'NtAlpcSendWaitReceivePort', 'lstrcmpA', 'lstrcmpW', 'CreateFileMappingA', 'CreateFileMappingW', 'MapViewOfFile', 'OpenSCManagerA', 'OpenSCManagerW', 'EnumServicesStatusExA', 'EnumServicesStatusExW', 'EnumWindows', 'GetWindowTextA', 'GetWindowTextW', 'GetWindowModuleFileNameA', 'GetWindowModuleFileNameW', 'CryptCATAdminCalcHashFromFileHandle', 'CryptCATAdminEnumCatalogFromHash', 'CryptCATAdminAcquireContext', 'CryptCATCatalogInfoFromContext', 'CryptCATAdminReleaseCatalogContext', 'CryptCATAdminReleaseContext', 'GetLogicalDriveStringsA', 'GetLogicalDriveStringsW', 'GetVolumeInformationA', 'GetVolumeInformationW', 'GetVolumeNameForVolumeMountPointA', 'GetVolumeNameForVolumeMountPointW', 'GetDriveTypeA', 'GetDriveTypeW', 'QueryDosDeviceA', 'QueryDosDeviceW', 'NtQueryObject', 'DuplicateHandle', 'GetModuleBaseNameA', 'GetModuleBaseNameW', 'GetProcessImageFileNameA', 'GetProcessImageFileNameW', 'GetFileVersionInfoA', 'GetFileVersionInfoW', 'GetFileVersionInfoSizeA', 'GetFileVersionInfoSizeW', 'VerQueryValueA', 'VerQueryValueW', 'GetSystemMetrics', 'GetComputerNameA', 'GetComputerNameW', 'LookupAccountSidA', 'LookupAccountSidW', 'CoInitializeEx', 'CoInitializeSecurity', 'CoCreateInstance', 'GetInterfaceInfo', 'GetIfTable', 'GetIpAddrTable', 'NtOpenDirectoryObject', 'NtQueryDirectoryObject', 'NtQuerySymbolicLinkObject', 'NtOpenSymbolicLinkObject'] +functions = ['ExitProcess', 'TerminateProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'LdrLoadDll', 'NtQuerySystemInformation', 'NtQueryInformationProcess', 'NtQueryVirtualMemory', 'NtCreateThreadEx', 'NtQueryInformationThread', 'GetExitCodeThread', 'GetExitCodeProcess', 'VirtualAlloc', 'VirtualAllocEx', 'NtProtectVirtualMemory', 'VirtualFree', 'VirtualFreeEx', 'VirtualProtect', 'VirtualProtectEx', 'VirtualQuery', 'VirtualQueryEx', 'QueryWorkingSet', 'QueryWorkingSetEx', 'GetModuleFileNameA', 'GetModuleFileNameW', 'CreateThread', 'CreateRemoteThread', 'VirtualProtect', 'CreateProcessA', 'CreateProcessW', 'GetThreadContext', 'NtGetContextThread', 'SetThreadContext', 'NtSetContextThread', 'OpenThread', 'OpenProcess', 'CloseHandle', 'ReadProcessMemory', 'NtWow64ReadVirtualMemory64', 'WriteProcessMemory', 'NtWow64WriteVirtualMemory64', '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', 'RtlInitString', 'RtlInitUnicodeString', 'RtlAnsiStringToUnicodeString', 'OpenEventA', 'OpenEventW', 'NtOpenEvent', 'NtAlpcCreatePort', 'NtAlpcConnectPort', 'NtAlpcAcceptConnectPort', 'AlpcInitializeMessageAttribute', 'AlpcGetMessageAttribute', 'NtAlpcSendWaitReceivePort', 'lstrcmpA', 'lstrcmpW', 'CreateFileMappingA', 'CreateFileMappingW', 'MapViewOfFile', 'OpenSCManagerA', 'OpenSCManagerW', 'EnumServicesStatusExA', 'EnumServicesStatusExW', 'EnumWindows', 'GetWindowTextA', 'GetWindowTextW', 'GetWindowModuleFileNameA', 'GetWindowModuleFileNameW', 'CryptCATAdminCalcHashFromFileHandle', 'CryptCATAdminEnumCatalogFromHash', 'CryptCATAdminAcquireContext', 'CryptCATCatalogInfoFromContext', 'CryptCATAdminReleaseCatalogContext', 'CryptCATAdminReleaseContext', 'GetLogicalDriveStringsA', 'GetLogicalDriveStringsW', 'GetVolumeInformationA', 'GetVolumeInformationW', 'GetVolumeNameForVolumeMountPointA', 'GetVolumeNameForVolumeMountPointW', 'GetDriveTypeA', 'GetDriveTypeW', 'QueryDosDeviceA', 'QueryDosDeviceW', 'NtQueryObject', 'DuplicateHandle', 'GetModuleBaseNameA', 'GetModuleBaseNameW', 'GetProcessImageFileNameA', 'GetProcessImageFileNameW', 'GetFileVersionInfoA', 'GetFileVersionInfoW', 'GetFileVersionInfoSizeA', 'GetFileVersionInfoSizeW', 'VerQueryValueA', 'VerQueryValueW', 'GetSystemMetrics', 'GetComputerNameA', 'GetComputerNameW', 'LookupAccountSidA', 'LookupAccountSidW', 'CoInitializeEx', 'CoInitializeSecurity', 'CoCreateInstance', 'GetInterfaceInfo', 'GetIfTable', 'GetIpAddrTable', 'NtOpenDirectoryObject', 'NtQueryDirectoryObject', 'NtQuerySymbolicLinkObject', 'NtOpenSymbolicLinkObject'] #def ExitProcess(uExitCode): # return ExitProcess.ctypes_function(uExitCode) @@ -85,6 +85,11 @@ VirtualAllocParams = ((1, 'lpAddress'), (1, 'dwSize'), (1, 'flAllocationType'), VirtualAllocExPrototype = WINFUNCTYPE(LPVOID, HANDLE, LPVOID, SIZE_T, DWORD, DWORD) VirtualAllocExParams = ((1, 'hProcess'), (1, 'lpAddress'), (1, 'dwSize'), (1, 'flAllocationType'), (1, 'flProtect')) +#def NtProtectVirtualMemory(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection): +# return NtProtectVirtualMemory.ctypes_function(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection) +NtProtectVirtualMemoryPrototype = WINFUNCTYPE(NTSTATUS, HANDLE, POINTER(PVOID), PULONG, ULONG, PULONG) +NtProtectVirtualMemoryParams = ((1, 'ProcessHandle'), (1, 'BaseAddress'), (1, 'NumberOfBytesToProtect'), (1, 'NewAccessProtection'), (1, 'OldAccessProtection')) + #def VirtualFree(lpAddress, dwSize, dwFreeType): # return VirtualFree.ctypes_function(lpAddress, dwSize, dwFreeType) VirtualFreePrototype = WINFUNCTYPE(BOOL, LPVOID, SIZE_T, DWORD) @@ -100,6 +105,11 @@ VirtualFreeExParams = ((1, 'hProcess'), (1, 'lpAddress'), (1, 'dwSize'), (1, 'dw VirtualProtectPrototype = WINFUNCTYPE(BOOL, LPVOID, SIZE_T, DWORD, PDWORD) VirtualProtectParams = ((1, 'lpAddress'), (1, 'dwSize'), (1, 'flNewProtect'), (1, 'lpflOldProtect')) +#def VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect): +# return VirtualProtectEx.ctypes_function(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect) +VirtualProtectExPrototype = WINFUNCTYPE(BOOL, HANDLE, LPVOID, SIZE_T, DWORD, PDWORD) +VirtualProtectExParams = ((1, 'hProcess'), (1, 'lpAddress'), (1, 'dwSize'), (1, 'flNewProtect'), (1, 'lpflOldProtect')) + #def VirtualQuery(lpAddress, lpBuffer, dwLength): # return VirtualQuery.ctypes_function(lpAddress, lpBuffer, dwLength) VirtualQueryPrototype = WINFUNCTYPE(DWORD, LPCVOID, PMEMORY_BASIC_INFORMATION, DWORD) @@ -205,6 +215,11 @@ NtWow64ReadVirtualMemory64Params = ((1, 'hProcess'), (1, 'lpBaseAddress'), (1, ' WriteProcessMemoryPrototype = WINFUNCTYPE(BOOL, HANDLE, LPVOID, LPCVOID, SIZE_T, POINTER(SIZE_T)) WriteProcessMemoryParams = ((1, 'hProcess'), (1, 'lpBaseAddress'), (1, 'lpBuffer'), (1, 'nSize'), (1, 'lpNumberOfBytesWritten')) +#def NtWow64WriteVirtualMemory64(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten): +# return NtWow64WriteVirtualMemory64.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten) +NtWow64WriteVirtualMemory64Prototype = WINFUNCTYPE(BOOL, HANDLE, ULONG64, LPVOID, ULONG64, POINTER(PULONG64)) +NtWow64WriteVirtualMemory64Params = ((1, 'hProcess'), (1, 'lpBaseAddress'), (1, 'lpBuffer'), (1, 'nSize'), (1, 'lpNumberOfBytesWritten')) + #def CreateToolhelp32Snapshot(dwFlags, th32ProcessID): # return CreateToolhelp32Snapshot.ctypes_function(dwFlags, th32ProcessID) CreateToolhelp32SnapshotPrototype = WINFUNCTYPE(HANDLE, DWORD, DWORD) diff --git a/windows/syswow64.py b/windows/syswow64.py index 4e365cf..baced55 100644 --- a/windows/syswow64.py +++ b/windows/syswow64.py @@ -286,6 +286,15 @@ def NtQueryVirtualMemory_32_to_64(ProcessHandle, BaseAddress, MemoryInformationC return NtQueryVirtualMemory_32_to_64.ctypes_function(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength) +@Syswow64ApiProxy(winproxy.NtProtectVirtualMemory) +def NtProtectVirtualMemory_32_to_64(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection=None): + if OldAccessProtection is None: + XOldAccessProtection = DWORD() + OldAccessProtection = ctypes.addressof(XOldAccessProtection) + return NtProtectVirtualMemory_32_to_64.ctypes_function(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection) + + + @Syswow64ApiProxy(winproxy.NtGetContextThread) def NtGetContextThread_32_to_64(hThread, lpContext): if type(lpContext) == windows.winobject.exception.ECONTEXT64: diff --git a/windows/test/mytest.py b/windows/test/mytest.py index ec7aff4..3453c3f 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -144,6 +144,34 @@ class WindowsTestCase(unittest.TestCase): sections[0].start sections[0].size + # Read / write + + def test_read_memory_32(self): + with Calc32() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + self.assertEqual(calc.read_memory(k32.baseaddr, 2), "MZ") + + @windows_64bit_only + def test_read_memory_64(self): + with Calc64() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + self.assertEqual(calc.read_memory(k32.baseaddr, 2), "MZ") + + def test_write_memory_32(self): + with Calc32() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + with calc.virtual_protected(k32.baseaddr, 2, PAGE_EXECUTE_READWRITE): + calc.write_memory(k32.baseaddr, "XD") + self.assertEqual(calc.read_memory(k32.baseaddr, 2), "XD") + + @windows_64bit_only + def test_write_memory_64(self): + with Calc64() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + with calc.virtual_protected(k32.baseaddr, 2, PAGE_EXECUTE_READWRITE): + calc.write_memory(k32.baseaddr, "XD") + self.assertEqual(calc.read_memory(k32.baseaddr, 2), "XD") + # Native execution def test_execute_to_32(self): with Calc32() as calc: @@ -451,7 +479,7 @@ class WindowsTestCase(unittest.TestCase): @windows_64bit_only def test_get_working_set_64(self): - with Calc32() as calc: + with Calc64() as calc: k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] api_addr = k32.pe.exports["CreateFileA"] data = calc.read_memory(api_addr, 5) @@ -462,7 +490,8 @@ class WindowsTestCase(unittest.TestCase): break else: raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) - data = calc.write_memory(api_addr, data) + with calc.virtual_protected(api_addr, 5, PAGE_EXECUTE_READWRITE): + data = calc.write_memory(api_addr, data) for page_info in calc.query_working_set(): if page_info.virtualpage == page_target: self.assertEqual(page_info.shared, False) @@ -470,6 +499,71 @@ class WindowsTestCase(unittest.TestCase): else: raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) + def test_get_working_setex_32(self): + with Calc32() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + + text = [s for s in k32.pe.sections if s.name == ".text"][0] + pages = [text.start + off for off in range(0, text.size, 0x1000)] + + api_addr = k32.pe.exports["CreateFileA"] + data = calc.read_memory(api_addr, 5) + page_target = (api_addr >> 12) << 12 + + for page_info in calc.query_working_setex(pages): + self.assertIn(page_info.VirtualAddress, pages) + if page_info.VirtualAddress == page_target: + self.assertEqual(page_info.VirtualAttributes.shared, True) + break + else: + raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) + with calc.virtual_protected(api_addr, 5, PAGE_EXECUTE_READWRITE): + data = calc.write_memory(api_addr, data) + for page_info in calc.query_working_setex(pages): + self.assertIn(page_info.VirtualAddress, pages) + if page_info.VirtualAddress == page_target: + self.assertEqual(page_info.VirtualAttributes.shared, False) + break + else: + raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) + + @windows_64bit_only + def test_get_working_setex_64(self): + with Calc64() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + + text = [s for s in k32.pe.sections if s.name == ".text"][0] + pages = [text.start + off for off in range(0, text.size, 0x1000)] + + api_addr = k32.pe.exports["CreateFileA"] + + data = calc.read_memory(api_addr, 5) + page_target = (api_addr >> 12) << 12 + + for page_info in calc.query_working_setex(pages): + self.assertIn(page_info.VirtualAddress, pages) + if page_info.VirtualAddress == page_target: + self.assertEqual(page_info.VirtualAttributes.shared, True) + break + else: + raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) + + with calc.virtual_protected(api_addr, 5, PAGE_EXECUTE_READWRITE): + data = calc.write_memory(api_addr, data) + for page_info in calc.query_working_setex(pages): + self.assertIn(page_info.VirtualAddress, pages) + if page_info.VirtualAddress == page_target: + self.assertEqual(page_info.VirtualAttributes.shared, False) + break + else: + raise ValueError("query_working_set page info for <0x{0:x}> not found".format(page_target)) + + def test_mapped_filename(self): + with Calc32() as calc: + k32 = [m for m in calc.peb.modules if m.name == "kernel32.dll"][0] + mapped_filname = calc.get_mapped_filename(k32.baseaddr) + self.assertTrue(mapped_filname.endswith("kernel32.dll")) + class WindowsAPITestCase(unittest.TestCase): def test_createfileA_fail(self): with self.assertRaises(WindowsError) as ar: diff --git a/windows/winobject/process.py b/windows/winobject/process.py index edb9518..ff05a36 100644 --- a/windows/winobject/process.py +++ b/windows/winobject/process.py @@ -279,6 +279,32 @@ class Process(AutoHandle): finally: winproxy.VirtualFreeEx(self.handle, addr) + @contextmanager + def virtual_protected(self, addr, size, protect): + old_protect = DWORD() + self.low_virtual_protect(addr, size, protect, old_protect) + try: + yield addr + finally: + self.low_virtual_protect(addr, size, old_protect.value, old_protect) + + def low_virtual_protect(self, addr, size, protect, old_protect): + if windows.current_process.bitness == 32 and self.bitness == 64: + #addr = (addr >> 12) << 12 + #addr = ULONG64(addr) + size = ((size >> 12) + 1) << 12 + #ssize = ULONG(size) + #import pdb;pdb.set_trace() + old_protect = ctypes.addressof(old_protect) + xaddr = ULONG64(addr) + addr = ctypes.addressof(xaddr) + xsize = ULONG(size) + size = ctypes.addressof(xsize) + return windows.syswow64.NtProtectVirtualMemory_32_to_64(self.handle, addr, size, protect, old_protect) + else: + winproxy.VirtualProtectEx(self.handle, addr, size, protect, old_protect) + + def execute(self, code, parameter=0): """Execute some native code in the context of the process @@ -338,9 +364,9 @@ class Process(AutoHandle): if e.winerror != 24: raise + NumberOfEntriesType = [f for f in WSET_BLOCK._fields_ if f[0] == "Flags"][0][1] for i in range(10): # use the same type as WSET_BLOCK.Flags - NumberOfEntriesType = [f for f in WSET_BLOCK._fields_ if f[0] == "Flags"][0][1] class GENERATED_PSAPI_WORKING_SET_INFORMATION(ctypes.Structure): _fields_ = [ ("NumberOfEntries", NumberOfEntriesType), @@ -363,9 +389,10 @@ class Process(AutoHandle): dummy.NumberOfEntries = res.NumberOfEntries continue return res.WorkingSetInfo + # Raise ? return None - def query_working_set_ex(self, addresses): + def query_working_setex(self, addresses): if self.bitness == 64 or windows.current_process.bitness == 64: info_type = EPSAPI_WORKING_SET_EX_INFORMATION64 else: @@ -373,7 +400,10 @@ class Process(AutoHandle): info_array = (info_type * len(addresses))() for i, data in enumerate(info_array): info_array[i].VirtualAddress = addresses[i] - winproxy.QueryWorkingSetEx(self.handle, ctypes.byref(info_array), ctypes.sizeof(info_array)) + if windows.current_process.bitness == 32 and self.bitness == 64: + windows.syswow64.NtQueryVirtualMemory_32_to_64(self.handle, 0, 4, info_array) + else: + winproxy.QueryWorkingSetEx(self.handle, ctypes.byref(info_array), ctypes.sizeof(info_array)) return info_array @@ -703,6 +733,10 @@ class WinProcess(Process): def write_memory(self, addr, data): """Write `data` at `addr`""" + if windows.current_process.bitness == 32 and self.bitness == 64: + if winproxy.NtWow64WriteVirtualMemory64 is None: + raise ValueError("NtWow64WriteVirtualMemory64 non available in ntdll: cannot write into 64bits processus") + return winproxy.NtWow64WriteVirtualMemory64(self.handle, addr, data, len(data)) return winproxy.WriteProcessMemory(self.handle, addr, lpBuffer=data) def low_read_memory(self, addr, buffer_addr, size): @@ -711,7 +745,6 @@ class WinProcess(Process): if winproxy.NtWow64ReadVirtualMemory64 is None: raise ValueError("NtWow64ReadVirtualMemory64 non available in ntdll: cannot read into 64bits processus") return winproxy.NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size) - NtWow64ReadVirtualMemory64 #if self.is_wow_64 and addr > 0xffffffff: # return winproxy.NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size) return winproxy.ReadProcessMemory(self.handle, addr, lpBuffer=buffer_addr, nSize=size) diff --git a/windows/winproxy.py b/windows/winproxy.py index d5f4f94..3a62a7d 100644 --- a/windows/winproxy.py +++ b/windows/winproxy.py @@ -338,6 +338,12 @@ def VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect=None): return VirtualProtect.ctypes_function(lpAddress, dwSize, flNewProtect, lpflOldProtect) +@Kernel32Proxy("VirtualProtectEx") +def VirtualProtectEx(hProcess, lpAddress, dwSize, flNewProtect, lpflOldProtect=None): + if lpflOldProtect is None: + lpflOldProtect = ctypes.byref(DWORD()) + return VirtualProtectEx.ctypes_function(hProcess, 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): @@ -538,14 +544,14 @@ def QueryWorkingSetWrapper(hProcess, pv, cb): QueryWorkingSet = OptionalExport(Kernel32Proxy("QueryWorkingSet"))(QueryWorkingSetWrapper) def QueryWorkingSetExWrapper(hProcess, pv, cb): - return QueryWorkingSet.ctypes_function(hProcess, pv, cb) -QueryWorkingSetEx = OptionalExport(Kernel32Proxy("QueryWorkingSetEx"))(QueryWorkingSetWrapper) + return QueryWorkingSetEx.ctypes_function(hProcess, pv, cb) +QueryWorkingSetEx = OptionalExport(Kernel32Proxy("QueryWorkingSetEx"))(QueryWorkingSetExWrapper) if GetMappedFileNameA is None: GetMappedFileNameW = PsapiProxy("GetMappedFileNameW")(GetMappedFileNameWWrapper) GetMappedFileNameA = PsapiProxy("GetMappedFileNameA")(GetMappedFileNameAWrapper) QueryWorkingSet = PsapiProxy("QueryWorkingSet")(QueryWorkingSetWrapper) - QueryWorkingSetEx = PsapiProxy("QueryWorkingSetEx")(QueryWorkingSetWrapper) + QueryWorkingSetEx = PsapiProxy("QueryWorkingSetEx")(QueryWorkingSetExWrapper) def GetModuleBaseNameAWrapper(hProcess, hModule, lpBaseName, nSize=None): if nSize is None: @@ -631,6 +637,9 @@ def GetVolumeInformationW(lpRootPathName, lpVolumeNameBuffer=None, nVolumeNameSi def NtWow64ReadVirtualMemory64(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead=None): return NtWow64ReadVirtualMemory64.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead) +@OptionalExport(NtdllProxy('NtWow64WriteVirtualMemory64', error_ntstatus)) +def NtWow64WriteVirtualMemory64(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten=None): + return NtWow64WriteVirtualMemory64.ctypes_function(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten) def ntquerysysteminformation_error_check(func_name, result, func, args): if result == 0: @@ -676,6 +685,12 @@ def NtQueryInformationThread(ThreadHandle, ThreadInformationClass, ThreadInforma return NtQueryInformationThread.ctypes_function(ThreadHandle, ThreadInformationClass, ThreadInformation, ThreadInformationLength, ReturnLength) +@NtdllProxy('NtProtectVirtualMemory', error_ntstatus) +def NtProtectVirtualMemory(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection=None): + if OldAccessProtection is None: + OldAccessProtection = DWORD() + return NtProtectVirtualMemory.ctypes_function(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection) + @OptionalExport(NtdllProxy('NtQueryVirtualMemory', error_ntstatus)) def NtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation=NeededParameter, MemoryInformationLength=0, ReturnLength=None): if ReturnLength is None: