def install_hook(self, mod_name, new_address, name=None, ordinal=None): if not (bool(name) ^ bool(ordinal)): raise ValueError('must select either name or ordinal, not both') image_import_descriptors = self.get_proc_attribute('image_import_descriptor') image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') is_ordinal = lambda x: bool(x & 0x80000000) for iid in image_import_descriptors: cur_mod_name = self._get_name_for_image_import_descriptor(iid) if cur_mod_name.lower() != mod_name.lower(): continue ilt = self._get_ilt_for_image_import_descriptor(iid) iat = self._get_iat_for_image_import_descriptor(iid) for idx in range(len(ilt)): if ilt[idx] is None: continue hook_it = False if not is_ordinal(ilt[idx]) and name: cur_func_name = self._get_name_for_ilt_entry(ilt[idx]) if cur_func_name == name: hook_it = True elif is_ordinal(ilt[idx]) and ordinal: cur_func_ordinal = self._get_ordinal_for_ilt_entry(ilt[idx]) if cur_func_ordinal == ordinal: hook_it = True if hook_it: old_address = iat[idx] iat_ent_addr = image_dos_header_addr iat_ent_addr += iid.FirstThunk iat_ent_addr += (ctypes.sizeof(ctypes.c_void_p) * idx) new_addr = ctypes.c_void_p() new_addr.value = new_address written = wintypes.DWORD() if self.k32.WriteProcessMemory(self.handle, iat_ent_addr, ctypes.byref(new_addr), ctypes.sizeof(new_addr), ctypes.byref(written)) == 0: errno = self.k32.GetLastError() if errno == 998: errno = 0 old_permissions = wintypes.DWORD() if (self.k32.VirtualProtectEx(self.handle, iat_ent_addr, 0x400, flags('PAGE_READWRITE'), ctypes.byref(old_permissions)) == 0): raise WindowsProcessError('Error: VirtualProtectEx', get_last_error=self.k32.GetLastError()) if self.k32.WriteProcessMemory(self.handle, iat_ent_addr, ctypes.byref(new_addr), ctypes.sizeof(new_addr), ctypes.byref(written)) == 0: errno = self.k32.GetLastError() self.protect(iat_ent_addr, permissions=old_permissions) if errno: raise WindowsProcessError('Error: WriteProcessMemory', get_last_error=errno) hook = Hook('iat', iat_ent_addr, old_address, new_address) self._installed_hooks.append(hook) return hook raise ProcessError('failed to find location to install hook')
def load_library(self, libpath): libpath = os.path.abspath(libpath) libpath_len = align_up(len(libpath) + 1, 0x200) LoadLibraryA = self.k32.GetProcAddress( self.k32.GetModuleHandleA("kernel32.dll"), "LoadLibraryA") RemotePage = self.k32.VirtualAllocEx(self.handle, None, len(libpath) + 1, flags("MEM_COMMIT"), flags("PAGE_EXECUTE_READWRITE")) if not RemotePage: raise WindowsProcessError( 'Error: failed to allocate space for library name in the target process' ) self.k32.WriteProcessMemory(self.handle, RemotePage, libpath, len(libpath), None) RemoteThread = self.k32.CreateRemoteThread(self.handle, None, 0, LoadLibraryA, RemotePage, 0, None) self.k32.WaitForSingleObject(RemoteThread, -1) exitcode = wintypes.DWORD(0) self.k32.GetExitCodeThread(RemoteThread, ctypes.byref(exitcode)) self.k32.VirtualFreeEx(self.handle, RemotePage, len(libpath), flags("MEM_RELEASE")) if exitcode.value == 0: raise WindowsProcessError('Error: failed to load: ' + repr(libpath)) self._update_maps() return exitcode.value
def read(self): ctarray = (ctypes.c_byte * self.buffer_size)() bytes_read = wintypes.DWORD(0) if not kernel32.ReadFile(self.handle, ctarray, self.buffer_size, ctypes.byref(bytes_read), 0): return None return utilities.ctarray_to_bytes(ctarray)[:bytes_read.value]
def load_library(self, libpath): libpath = os.path.abspath(libpath) libpath = libpath.encode('utf-8') + b'\x00' LoadLibraryA = self.k32.GetProcAddress( self.k32.GetModuleHandleA(b'kernel32.dll'), b'LoadLibraryA') remote_page = self.k32.VirtualAllocEx(self.handle, None, len(libpath), flags("MEM_COMMIT"), flags("PAGE_EXECUTE_READWRITE")) if not remote_page: raise WindowsProcessError( 'Error: failed to allocate space for library name in the target process' ) if not self.k32.WriteProcessMemory(self.handle, remote_page, libpath, len(libpath), None): raise WindowsProcessError( 'Error: failed to copy the library name to the target process') remote_thread = self.k32.CreateRemoteThread(self.handle, None, 0, LoadLibraryA, remote_page, 0, None) self.k32.WaitForSingleObject(remote_thread, -1) exitcode = wintypes.DWORD(0) self.k32.GetExitCodeThread(remote_thread, ctypes.byref(exitcode)) self.k32.VirtualFreeEx(self.handle, remote_page, len(libpath), flags("MEM_RELEASE")) if exitcode.value == 0: raise WindowsProcessError( "Error: failed to load: {0}, thread exited with status: 0x{1:x}" .format(libpath, exitcode.value)) self._update_maps() return exitcode.value
def load_library(self, path): path = os.path.abspath(path) libpath = path.encode('mbcs') + b'\x00' remote_page = m_k32.VirtualAllocEx(self.handle, None, len(libpath), flags("MEM_COMMIT"), flags("PAGE_EXECUTE_READWRITE")) if not remote_page: raise WindowsProcessError( 'Error: failed to allocate space for library name in the target process' ) if not m_k32.WriteProcessMemory(self.handle, remote_page, libpath, len(libpath), None): raise WindowsProcessError( 'Error: failed to copy the library name to the target process') remote_thread = m_k32.CreateRemoteThread(self.handle, None, 0, m_k32.LoadLibraryA.address, remote_page, 0, None) m_k32.WaitForSingleObject(remote_thread, -1) exitcode = wintypes.DWORD(0) m_k32.GetExitCodeThread(remote_thread, ctypes.byref(exitcode)) m_k32.VirtualFreeEx(self.handle, remote_page, len(libpath), flags("MEM_RELEASE")) if exitcode.value == 0: raise WindowsProcessError( "Error: failed to load \"{0}\", thread exited with status: 0x{1:x}" .format(path, exitcode.value)) return exitcode.value
def protect(self, address, permissions=None, size=0x400): permissions = flags(permissions or 'PAGE_EXECUTE_READWRITE') old_permissions = wintypes.DWORD() if (self.k32.VirtualProtectEx(self.handle, address, size, permissions, ctypes.byref(old_permissions)) == 0): raise WindowsProcessError('Error: VirtualProtectEx', get_last_error=self.k32.GetLastError()) return
def _get_attr_peb_addr(self): process_basic_information = wintypes.PROCESS_BASIC_INFORMATION() return_length = wintypes.DWORD() self.ntdll.NtQueryInformationProcess( self.handle, 0, ctypes.byref(process_basic_information), ctypes.sizeof(process_basic_information), ctypes.byref(return_length)) return process_basic_information.PebBaseAddress
def read(self): ctarray = (ctypes.c_byte * self.buffer_size)() bytes_read = wintypes.DWORD(0) overlapped = wintypes.OVERLAPPED() overlapped.hEvent = m_k32.CreateEventW(None, True, False, None) if m_k32.ReadFile(self.handle, ctypes.byref(ctarray), self.buffer_size, ctypes.byref(bytes_read), ctypes.byref(overlapped)): return utilities.ctarray_to_bytes(ctarray)[:bytes_read.value] error = m_k32.GetLastError() if error == ERROR_IO_PENDING and _wait_overlapped_io(overlapped): return utilities.ctarray_to_bytes(ctarray)[:overlapped.InternalHigh] if error == ERROR_BROKEN_PIPE: return None raise ctypes.WinError()