From 0da86e20aac24755c6198d3385cbbafd1be81b00 Mon Sep 17 00:00:00 2001 From: Clement Rouault Date: Mon, 1 Feb 2016 17:31:56 +0100 Subject: [PATCH] SetThreadContext 32<->64 + test --- ctypes_generation/winfunc.txt | 10 +++++++ windows/generated_def/winfuncs.py | 10 ++++++- windows/syswow64.py | 4 ++- windows/test/mytest.py | 49 +++++++++++++++++++++++++++---- windows/vectored_exception.py | 2 +- windows/winobject.py | 6 +++- windows/winproxy.py | 11 +++++-- 7 files changed, 80 insertions(+), 12 deletions(-) diff --git a/ctypes_generation/winfunc.txt b/ctypes_generation/winfunc.txt index f549383..64289b1 100644 --- a/ctypes_generation/winfunc.txt +++ b/ctypes_generation/winfunc.txt @@ -222,6 +222,12 @@ BOOL WINAPI SetThreadContext( __in CONST LPCONTEXT lpContext ); +BOOL WINAPI NtSetContextThread( + __in HANDLE hThread, + __in CONST LPCONTEXT lpContext +); + + HANDLE WINAPI OpenThread( __in DWORD dwDesiredAccess, __in BOOL bInheritHandle, @@ -737,4 +743,8 @@ DWORD WINAPI GetProcessId( _In_ HANDLE Process ); +BOOL WINAPI Wow64SetThreadContext( + __in HANDLE hThread, + __in CONST WOW64_CONTEXT *lpContext +); diff --git a/windows/generated_def/winfuncs.py b/windows/generated_def/winfuncs.py index 6a7315e..cb9a702 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', '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'] +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'] # ExitProcess(uExitCode): ExitProcessPrototype = WINFUNCTYPE(VOID, UINT) @@ -129,6 +129,10 @@ NtGetContextThreadParams = ((1, 'hThread'), (1, 'lpContext')) SetThreadContextPrototype = WINFUNCTYPE(BOOL, HANDLE, LPCONTEXT) SetThreadContextParams = ((1, 'hThread'), (1, 'lpContext')) +# NtSetContextThread(hThread, lpContext): +NtSetContextThreadPrototype = WINFUNCTYPE(BOOL, HANDLE, LPCONTEXT) +NtSetContextThreadParams = ((1, 'hThread'), (1, 'lpContext')) + # OpenThread(dwDesiredAccess, bInheritHandle, dwThreadId): OpenThreadPrototype = WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD) OpenThreadParams = ((1, 'dwDesiredAccess'), (1, 'bInheritHandle'), (1, 'dwThreadId')) @@ -517,3 +521,7 @@ DebugBreakProcessParams = ((1, 'Process'),) GetProcessIdPrototype = WINFUNCTYPE(DWORD, HANDLE) GetProcessIdParams = ((1, 'Process'),) +# Wow64SetThreadContext(hThread, lpContext): +Wow64SetThreadContextPrototype = WINFUNCTYPE(BOOL, HANDLE, POINTER(WOW64_CONTEXT)) +Wow64SetThreadContextParams = ((1, 'hThread'), (1, 'lpContext')) + diff --git a/windows/syswow64.py b/windows/syswow64.py index 208f0f3..6736752 100644 --- a/windows/syswow64.py +++ b/windows/syswow64.py @@ -290,4 +290,6 @@ def NtGetContextThread_32_to_64(hThread, lpContext): def LdrLoadDll_32_to_64(PathToFile, Flags, ModuleFileName, ModuleHandle): return LdrLoadDll_32_to_64.ctypes_function(PathToFile, Flags, ModuleFileName, ModuleHandle) - +@Syswow64ApiProxy(windows.winproxy.NtSetContextThread) +def NtSetContextThread_32_to_64(hThread, lpContext): + return NtSetContextThread_32_to_64.ctypes_function(hThread, lpContext) diff --git a/windows/test/mytest.py b/windows/test/mytest.py index a06f08c..0c90559 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -298,6 +298,48 @@ class WindowsTestCase(unittest.TestCase): self.assertEqual(calc.exit_code, 42) self.assertEqual(calc.is_exit, True) + def test_set_thread_context_32(self): + code = x86.MultipleInstr() + code += x86.Label(":LOOP") + code += x86.Jmp(":LOOP") + data_len = len(code.get_code()) + code += x86.Ret() + + with Calc32() as calc: + t = calc.execute(code.get_code()) + time.sleep(0.1) + self.assertEqual(calc.is_exit, False) + t.suspend() + ctx = t.context + ctx.Eip += data_len + ctx.Eax = 0x11223344 + t.set_context(ctx) + t.resume() + time.sleep(0.1) + self.assertEqual(t.exit_code, 0x11223344) + + + @windows_64bit_only + def test_set_thread_context_64(self): + code = x64.MultipleInstr() + code += x64.Label(":LOOP") + code += x64.Jmp(":LOOP") + data_len = len(code.get_code()) + code += x64.Ret() + + with Calc64() as calc: + t = calc.execute(code.get_code()) + time.sleep(0.1) + self.assertEqual(calc.is_exit, False) + t.suspend() + ctx = t.context + ctx.Rip += data_len + ctx.Rax = 0x11223344 + t.set_context(ctx) + t.resume() + time.sleep(0.1) + self.assertEqual(t.exit_code, 0x11223344) + class WindowsAPITestCase(unittest.TestCase): def test_createfileA_fail(self): with self.assertRaises(WindowsError) as ar: @@ -323,8 +365,7 @@ class NativeUtilsTestCase(unittest.TestCase): k32 = [mod for mod in windows.current_process.peb.modules if mod.name == "kernel32.dll"][0] exports = [(x,y) for x,y in k32.pe.exports.items() if isinstance(x, basestring)] - for i in range(15): - name, addr = random.choice(exports) + for name, addr in exports: name = name.encode() compute_addr = getprocaddr64("KERNEL32.DLL", name) # Put name in test to know which function caused the assert fails @@ -348,9 +389,7 @@ class NativeUtilsTestCase(unittest.TestCase): k32 = [mod for mod in windows.current_process.peb.modules if mod.name == "kernel32.dll"][0] exports = [(x,y) for x,y in k32.pe.exports.items() if isinstance(x, basestring)] - - for i in range(1500): - name, addr = random.choice(exports) + for name, addr in exports: name = name.encode() compute_addr = getprocaddr32("KERNEL32.DLL", name) # Put name in test to know which function caused the assert fails diff --git a/windows/vectored_exception.py b/windows/vectored_exception.py index 44f9a3f..fe6a4ea 100644 --- a/windows/vectored_exception.py +++ b/windows/vectored_exception.py @@ -189,7 +189,7 @@ class EDr7(ctypes.Structure): ("LEN3", DWORD, 2), ] -class EnhancedCONTEXTBase(): +class EnhancedCONTEXTBase(object): default_dump = () pc_reg = '' special_reg_type = {} diff --git a/windows/winobject.py b/windows/winobject.py index 34b3457..b6a81f4 100644 --- a/windows/winobject.py +++ b/windows/winobject.py @@ -171,7 +171,11 @@ class WinThread(THREADENTRY32, AutoHandle): return x def set_context(self, context): - return winproxy.SetThreadContext(self.handle, 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: + return winproxy.Wow64SetThreadContext(self.handle, context) + return windows.syswow64.NtSetContextThread_32_to_64(self.handle, ctypes.byref(context)) @property def start_address(self): diff --git a/windows/winproxy.py b/windows/winproxy.py index d730ec0..d8be864 100644 --- a/windows/winproxy.py +++ b/windows/winproxy.py @@ -352,11 +352,12 @@ def GetThreadContext(hThread, lpContext=None): @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("Wow64SetThreadContext") +def Wow64SetThreadContext(hThread, lpContext): + return Wow64SetThreadContext.ctypes_function(hThread, lpContext) + @Kernel32Proxy("OpenThread") def OpenThread(dwDesiredAccess=THREAD_ALL_ACCESS, bInheritHandle=0, dwThreadId=NeededParameter): @@ -554,6 +555,10 @@ def NtCreateThreadEx(ThreadHandle=None, DesiredAccess=0x1fffff, ObjectAttributes return NtCreateThreadEx.ctypes_function(ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, lpStartAddress, lpParameter, CreateSuspended, dwStackSize, Unknown1, Unknown2, Unknown3) +@NtdllProxy("NtSetContextThread", error_ntstatus) +def NtSetContextThread(hThread, lpContext): + return NtSetContextThread.ctypes_function(hThread, lpContext) + # ##### ADVAPI32 ####### # @Advapi32Proxy('OpenProcessToken')