def write_memory(self, addr, data): """Write `data` at `addr`""" if windows.current_process.bitness == 32 and self.bitness == 64: if not winproxy.is_implemented(winproxy.NtWow64WriteVirtualMemory64): 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): if windows.current_process.bitness == 32 and self.bitness == 64: # OptionalExport can be None (see winproxy.py) if not winproxy.is_implemented(winproxy.NtWow64ReadVirtualMemory64): raise ValueError("NtWow64ReadVirtualMemory64 non available in ntdll: cannot read into 64bits processus") return winproxy.NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size) #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)
class WinThread(THREADENTRY32, AutoHandle): """Represent a thread """ @utils.fixedpropety def tid(self): """Thread ID :type: :class:`int`""" return self.th32ThreadID @utils.fixedpropety def owner(self): """The Process owning the thread :type: :class:`WinProcess` """ if hasattr(self, "_owner"): return self._owner try: self._owner = [process for process in windows.system.processes if process.pid == self.th32OwnerProcessID][0] except IndexError: return None return self._owner @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 = 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 = 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 = exception.ECONTEXT32() else: x = exception.ECONTEXT64.new_aligned() x.ContextFlags = CONTEXT_ALL winproxy.GetThreadContext(self.handle, x) return x @property def context_syswow(self): """The 64 bits context of a syswow thread. :type: :class:`windows.exception.ECONTEXT64` """ if not self.owner.is_wow_64: raise ValueError("Not a syswow process") x = exception.ECONTEXT64.new_aligned() x.ContextFlags = CONTEXT_ALL if windows.current_process.bitness == 64: winproxy.GetThreadContext(self.handle, x) else: windows.syswow64.NtGetContextThread_32_to_64(self.handle, x) return x def set_context(self, context): """Set the thread's 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: return winproxy.Wow64SetThreadContext(self.handle, context) return windows.syswow64.NtSetContextThread_32_to_64(self.handle, ctypes.byref(context)) def set_syswow_context(self, context): """Set a syswow thread's 64 context to ``context``""" if not self.owner.is_wow_64: raise ValueError("Not a syswow process") if windows.current_process.bitness == 64: return winproxy.SetThreadContext(self.handle, context) return windows.syswow64.NtSetContextThread_32_to_64(self.handle, ctypes.byref(context)) @property def start_address(self): """The start address of the thread :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)) return res.value res_size = max(self.owner.bitness, windows.current_process.bitness) if res_size == 32: res = ULONG() else: res = ULONGLONG() winproxy.NtQueryInformationThread(self.handle, ThreadQuerySetWin32StartAddress, byref(res), ctypes.sizeof(res)) return res.value @property def teb_base(self): """The address of the thread's TEB :type: :class:`int` """ if windows.current_process.bitness == 32 and self.owner.bitness == 64: restype = rctypes.transform_type_to_remote64bits(THREAD_BASIC_INFORMATION) ressize = (ctypes.sizeof(restype)) # Manual aligned allocation :DDDD nb_qword = (ressize + 8) / ctypes.sizeof(ULONGLONG) buffer = (nb_qword * ULONGLONG)() struct_address = ctypes.addressof(buffer) if (struct_address & 0xf) not in [0, 8]: raise ValueError("ULONGLONG array not aligned on 8") windows.syswow64.NtQueryInformationThread_32_to_64(self.handle, ThreadBasicInformation, struct_address, ressize) return restype(struct_address, windows.current_process).TebBaseAddress res = THREAD_BASIC_INFORMATION() windows.winproxy.NtQueryInformationThread(self.handle, ThreadBasicInformation, byref(res), ctypes.sizeof(res)) return res.TebBaseAddress def exit(self, code=0): """Exit the thread""" return winproxy.TerminateThread(self.handle, code) def resume(self): """Resume the thread""" return winproxy.ResumeThread(self.handle) def suspend(self): """Suspend the thread""" return winproxy.SuspendThread(self.handle) def _get_handle(self): return winproxy.OpenThread(dwThreadId=self.tid) @property def is_exit(self): """``True`` if the thread is terminated :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` """ res = DWORD() winproxy.GetExitCodeThread(self.handle, byref(res)) return res.value def __repr__(self): owner = self.owner if owner is None: owner_name = "<Dead process with pid {0}>".format(hex(self.th32OwnerProcessID)) else: owner_name = owner.name return '<{0} {1} owner "{2}" at {3}>'.format(self.__class__.__name__, self.tid, owner_name, hex(id(self))) @staticmethod def _from_handle(handle): tid = WinThread._get_thread_id(handle) try: # Really useful ? thread = [t for t in windows.winobject.system.System().threads if t.tid == tid][0] # set AutoHandle _handle thread._handle = handle dbgprint("Thread {0} from handle {1}".format(thread, hex(handle)), "HANDLE") return thread except IndexError: dbgprint("DeadThread from handle {0}".format(hex(handle)), "HANDLE") return DeadThread(handle, tid) @staticmethod def _get_thread_id_by_api(handle): return winproxy.GetThreadId(handle) @staticmethod def _get_thread_id_manual(handle): if windows.current_process.bitness == 32 and self.owner.bitness == 64: raise NotImplementedError("[_get_thread_id_manual] 32 -> 64 (XP64 bits + Syswow process ?)") res = THREAD_BASIC_INFORMATION() windows.winproxy.NtQueryInformationThread(hand, ThreadBasicInformation, byref(res), ctypes.sizeof(res)) id2 = res.ClientId.UniqueThread return id2 if winproxy.is_implemented(winproxy.GetThreadId): _get_thread_id = _get_thread_id_by_api else: _get_thread_id = _get_thread_id_manual