From 3184cbdeabda3da77815637df086507ff94e0cda Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Mon, 18 Jul 2016 16:23:11 +0200 Subject: [PATCH] MemBP has explicit event RWX, add GetProcessDEPPolicy, add Debugger API to disable/re-enable memory BP --- ctypes_generation/definitions/winfunc.txt | 7 ++ windows/debug/breakpoints.py | 8 +-- windows/debug/debugger.py | 87 +++++++++++++++++------ windows/generated_def/winfuncs.py | 7 +- windows/test/test_debugger.py | 22 +++--- windows/test/test_utils.py | 10 ++- windows/winproxy.py | 4 ++ 7 files changed, 109 insertions(+), 36 deletions(-) diff --git a/ctypes_generation/definitions/winfunc.txt b/ctypes_generation/definitions/winfunc.txt index ea5f06b..9c8f57a 100644 --- a/ctypes_generation/definitions/winfunc.txt +++ b/ctypes_generation/definitions/winfunc.txt @@ -1353,3 +1353,10 @@ DWORD WINAPI GetLongPathNameW( _Out_ LPWSTR lpszLongPath, _In_ DWORD cchBuffer ); + + +BOOL WINAPI GetProcessDEPPolicy( + _In_ HANDLE hProcess, + _Out_ LPDWORD lpFlags, + _Out_ PBOOL lpPermanent +); diff --git a/windows/debug/breakpoints.py b/windows/debug/breakpoints.py index 7e1e568..4099da5 100644 --- a/windows/debug/breakpoints.py +++ b/windows/debug/breakpoints.py @@ -43,14 +43,12 @@ class HXBreakpoint(Breakpoint): class MemoryBreakpoint(Breakpoint): type = MEMORY_BREAKPOINT - - DEFAULT_PROTECT = PAGE_READONLY + DEFAULT_EVENTS = "RWX" DEFAULT_SIZE = 0x1000 - def __init__(self, addr, size=None, prot=None): + def __init__(self, addr, size=None, events=None): super(MemoryBreakpoint, self).__init__(addr) self.size = size if size is not None else self.DEFAULT_SIZE - self.protect = prot if prot is not None else self.DEFAULT_PROTECT - + self.events = events if events is not None else self.DEFAULT_EVENTS def trigger(self, dbg, exception): """Called when breakpoint is hit""" diff --git a/windows/debug/debugger.py b/windows/debug/debugger.py index e1c3d61..79f102f 100644 --- a/windows/debug/debugger.py +++ b/windows/debug/debugger.py @@ -233,47 +233,71 @@ class Debugger(object): pass return True + ## MemBP helpers + def _compute_page_access_for_event(self, target, events): + if "R" in events: + return PAGE_NOACCESS + if set("WX").issubset(events): + return PAGE_READONLY + if events == set("W"): + return PAGE_EXECUTE_READ + if events == set("X"): + # Might have problem if DEP is not enabled + if windows.winproxy.is_implemented(windows.winproxy.GetProcessDEPPolicy): + has_DEP = DWORD() + permaned = LONG() + windows.winproxy.GetProcessDEPPolicy(target.handle, has_DEP, permaned) + has_DEP = has_DEP.value + else: + has_DEP = 0 + return PAGE_READWRITE if has_DEP else PAGE_NOACCESS + raise ValueError("Unexpected set of event for Membp: {0}".format(events)) + + def _setup_breakpoint_MEMBP(self, bp, target): addr = self._resolve(bp.addr, target) bp._addr = addr + self._events = set(bp.events) if addr is None: return False # Split in affected pages: + protection_for_bp = self._compute_page_access_for_event(target, self._events) affected_pages = range((addr >> 12) << 12, addr + bp.size, PAGE_SIZE) old_prot = DWORD() - vprot_begin = affected_pages[0] - vprot_size = PAGE_SIZE * len(affected_pages) - print("[VP] {0:#x} {1:#x} {2}".format(vprot_begin, vprot_size, bp.protect)) - target.virtual_protect(vprot_begin, vprot_size, bp.protect, old_prot) - bp._old_prot = old_prot.value - #self._virtual_protected_memory[vprot_begin] = (vprot_size, bp.protect, old_prot) cp_watch_page = self._watched_pages[self.current_process.pid] for page_addr in affected_pages: if page_addr not in cp_watch_page: - cp_watch_page[page_addr] = WatchedPage(old_prot, []) - cp_watch_page[page_addr].bps.append(bp) - # TODO: watch for overlap with other MEM breakpoints + target.virtual_protect(page_addr, PAGE_SIZE, protection_for_bp, old_prot) + # Page with no other MemBP + cp_watch_page[page_addr] = WatchedPage(old_prot.value, [bp]) + else: + # Reduce the right of the page to the common need + cp_watch_page[page_addr].bps.append(bp) + full_page_events = set.union(*[bp.events for bp in cp_watch_page[page_addr].bps]) + protection_for_page = self._compute_page_access_for_event(target, full_page_events) + target.virtual_protect(page_addr, PAGE_SIZE, protection_for_page, None) + # TODO: watch for overlap with other MEM breakpoints return True def _restore_breakpoint_MEMBP(self, bp, target): - return target.virtual_protect(bp._reput_page, PAGE_SIZE, bp.protect, None) + (page_addr, page_prot) = bp._reput_page + return target.virtual_protect(page_addr, PAGE_SIZE, page_prot, None) def _remove_breakpoint_MEMBP(self, bp, target): affected_pages = range((bp._addr >> 12) << 12, bp._addr + bp.size, PAGE_SIZE) - old_prot = DWORD() vprot_begin = affected_pages[0] vprot_size = PAGE_SIZE * len(affected_pages) - target.virtual_protect(vprot_begin, vprot_size, bp._old_prot, None) - cp_watch_page = self._watched_pages[self.current_process.pid] for page_addr in affected_pages: cp_watch_page[page_addr].bps.remove(bp) if not cp_watch_page[page_addr].bps: + target.virtual_protect(page_addr, PAGE_SIZE, cp_watch_page[page_addr].original_prot, None) del cp_watch_page[page_addr] else: - raise NotImplementedError("Removing MemBP on page with multiple MemBP > 12) << 12 cp_watch_page = self._watched_pages[self.current_process.pid] @@ -428,7 +455,7 @@ class Debugger(object): if mem_bp is False: # No BP on this page return self.on_exception(exception) original_prot = cp_watch_page[fault_page].original_prot - if mem_bp is None: # Page as MEMBP but None handle this address + if mem_bp is None or event not in mem_bp.events: # Page has MEMBP but None handle this address | event not asked by membp # This hack is bad, find a BP on the page to restore original access.. bp = cp_watch_page[fault_page].bps[-1] self._pass_memory_breakpoint(bp, original_prot, fault_page) @@ -671,6 +698,24 @@ class Debugger(object): return bp return None + def disable_all_memory_breakpoints(self, target=None): + if target is None: + target = self.current_process + res = {} + cp_watch_page = self._watched_pages[self.current_process.pid] + page_protection = DWORD() + for page_addr, watched_page in cp_watch_page.items(): + target.virtual_protect(page_addr, PAGE_SIZE, watched_page.original_prot, page_protection) + res[page_addr] = page_protection.value + return res + + def restore_all_memory_breakpoints(self, data, target=None): + if target is None: + target = self.current_process + for page_addr, protection in data.items(): + target.virtual_protect(page_addr, PAGE_SIZE, protection, None) + return + # Public callback def on_exception(self, exception): """Called on exception event other that known breakpoint or requested single step. ``exception`` is one of the following type: diff --git a/windows/generated_def/winfuncs.py b/windows/generated_def/winfuncs.py index c84142a..8ef5d02 100644 --- a/windows/generated_def/winfuncs.py +++ b/windows/generated_def/winfuncs.py @@ -6,7 +6,7 @@ from ctypes.wintypes import * from winstructs import * -functions = ['ExitProcess', 'TerminateProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtCreateFile', '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', 'ReadFile', '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', 'GetProcessTimes', 'GetShortPathNameA', 'GetShortPathNameW', 'GetLongPathNameA', 'GetLongPathNameW', 'CryptQueryObject', 'CryptMsgGetParam', 'CryptDecodeObject', 'CertFindCertificateInStore', 'CertGetNameStringA', 'CertGetNameStringW', 'CertGetCertificateChain'] +functions = ['ExitProcess', 'TerminateProcess', 'GetLastError', 'GetCurrentProcess', 'CreateFileA', 'CreateFileW', 'NtCreateFile', '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', 'ReadFile', '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', 'GetProcessTimes', 'GetShortPathNameA', 'GetShortPathNameW', 'GetLongPathNameA', 'GetLongPathNameW', 'GetProcessDEPPolicy', 'CryptQueryObject', 'CryptMsgGetParam', 'CryptDecodeObject', 'CertFindCertificateInStore', 'CertGetNameStringA', 'CertGetNameStringW', 'CertGetCertificateChain'] #def ExitProcess(uExitCode): @@ -1074,6 +1074,11 @@ GetLongPathNameAParams = ((1, 'lpszShortPath'), (1, 'lpszLongPath'), (1, 'cchBuf GetLongPathNameWPrototype = WINFUNCTYPE(DWORD, LPWSTR, LPWSTR, DWORD) GetLongPathNameWParams = ((1, 'lpszShortPath'), (1, 'lpszLongPath'), (1, 'cchBuffer')) +#def GetProcessDEPPolicy(hProcess, lpFlags, lpPermanent): +# return GetProcessDEPPolicy.ctypes_function(hProcess, lpFlags, lpPermanent) +GetProcessDEPPolicyPrototype = WINFUNCTYPE(BOOL, HANDLE, LPDWORD, PBOOL) +GetProcessDEPPolicyParams = ((1, 'hProcess'), (1, 'lpFlags'), (1, 'lpPermanent')) + #def CryptQueryObject(dwObjectType, pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext): # return CryptQueryObject.ctypes_function(dwObjectType, pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext) CryptQueryObjectPrototype = WINFUNCTYPE(BOOL, DWORD, PVOID, DWORD, DWORD, DWORD, POINTER(DWORD), POINTER(DWORD), POINTER(DWORD), POINTER(HCERTSTORE), POINTER(HCRYPTMSG), POINTER(PVOID)) diff --git a/windows/test/test_debugger.py b/windows/test/test_debugger.py index 6bf382b..0ba8386 100644 --- a/windows/test/test_debugger.py +++ b/windows/test/test_debugger.py @@ -377,7 +377,9 @@ class DebuggerTestCase(unittest.TestCase): TEST_CASE = self store_data = [0] class TSTBP(windows.debug.MemoryBreakpoint): - DEFAULT_PROTECT = PAGE_READONLY + #DEFAULT_PROTECT = PAGE_READONLY + #DEFAULT_PROTECT = PAGE_READONLY + DEFAULT_EVENTS = "W" """Check that BP/dbg can trigger single step and that instruction follows""" def trigger(self, dbg, exc): fault_addr = exc.ExceptionRecord.ExceptionInformation[1] @@ -421,7 +423,8 @@ class DebuggerTestCase(unittest.TestCase): class TSTBP(windows.debug.MemoryBreakpoint): """Check that BP/dbg can trigger single step and that instruction follows""" - DEFAULT_PROTECT = PAGE_NOACCESS + #DEFAULT_PROTECT = PAGE_NOACCESS + DEFAULT_EVENTS = "X" def trigger(self, dbg, exc): fault_addr = exc.ExceptionRecord.ExceptionInformation[1] data.append(fault_addr) @@ -565,7 +568,8 @@ class DebuggerTestCase(unittest.TestCase): calc.exit() class TSTBP(windows.debug.MemoryBreakpoint): - DEFAULT_PROTECT = PAGE_NOACCESS + #DEFAULT_PROTECT = PAGE_NOACCESS + DEFAULT_EVENTS = "RWX" def trigger(self, dbg, exc): addr = exc.ExceptionRecord.ExceptionAddress fault_addr = exc.ExceptionRecord.ExceptionInformation[1] @@ -597,7 +601,8 @@ class DebuggerTestCase(unittest.TestCase): calc.exit() class TSTBP(windows.debug.MemoryBreakpoint): - DEFAULT_PROTECT = PAGE_NOACCESS + #DEFAULT_PROTECT = PAGE_NOACCESS + DEFAULT_EVENTS = "RWX" def trigger(self, dbg, exc): addr = exc.ExceptionRecord.ExceptionAddress fault_addr = exc.ExceptionRecord.ExceptionInformation[1] @@ -639,18 +644,19 @@ class DebuggerTestCase(unittest.TestCase): calc.exit() class MemBP(windows.debug.MemoryBreakpoint): - DEFAULT_PROTECT = PAGE_NOACCESS + #DEFAULT_PROTECT = PAGE_NOACCESS + DEFAULT_EVENTS = "RWX" def trigger(self, dbg, exc): addr = exc.ExceptionRecord.ExceptionAddress fault_addr = exc.ExceptionRecord.ExceptionInformation[1] - print("Got <{0:#x}> <{1}>".format(fault_addr, exc.ExceptionRecord.ExceptionInformation[0])) + #print("Got <{0:#x}> <{1}>".format(fault_addr, exc.ExceptionRecord.ExceptionInformation[0])) data.append((self, fault_addr)) calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS) d = windows.debug.Debugger(calc) data_addr = calc.virtual_alloc(0x1000) - the_write_bp = MemBP(data_addr + 0x500, prot=PAGE_READONLY, size=0x500) - the_read_bp = MemBP(data_addr, prot=PAGE_NOACCESS, size=0x500) + the_write_bp = MemBP(data_addr + 0x500, size=0x500, events="W") + the_read_bp = MemBP(data_addr, size=0x500, events="RW") d.add_bp(the_write_bp) d.add_bp(the_read_bp) threading.Thread(target=do_check).start() diff --git a/windows/test/test_utils.py b/windows/test/test_utils.py index 6ea123a..da75deb 100644 --- a/windows/test/test_utils.py +++ b/windows/test/test_utils.py @@ -62,4 +62,12 @@ def Calc32(dwCreationFlags=0, exit_code=0): raise finally: if "calc" in locals(): - calc.exit(exit_code) \ No newline at end of file + calc.exit(exit_code) + + +def print_call(f): + def wrapper(*args, **kwargs): + res = f(*args, **kwargs) + print("Call to <{0}>({1}) returned <{2}>".format(f.func_name, (args, kwargs), res)) + return res + return wrapper \ No newline at end of file diff --git a/windows/winproxy.py b/windows/winproxy.py index 0438732..6b5543b 100644 --- a/windows/winproxy.py +++ b/windows/winproxy.py @@ -665,6 +665,10 @@ def GetVolumeInformationW(lpRootPathName, lpVolumeNameBuffer=None, nVolumeNameSi def SetConsoleCtrlHandler(HandlerRoutine, Add): return SetConsoleCtrlHandler.ctypes_function(HandlerRoutine, Add) +@Kernel32Proxy("GetProcessDEPPolicy") +def GetProcessDEPPolicy(hProcess, lpFlags, lpPermanent): + return GetProcessDEPPolicy.ctypes_function(hProcess, lpFlags, lpPermanent) + # ### NTDLL #### # @NtdllProxy('NtWow64ReadVirtualMemory64', error_ntstatus)