#!/usr/bin/env python # -*- coding: utf-8 -*- # # mayhem/proc/windows.py # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of the project nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # from __future__ import unicode_literals import collections import ctypes import os import platform from mayhem.proc import ProcessBase, ProcessError, Hook, MemoryRegion from mayhem.datatypes import windows as wintypes from mayhem.utilities import ctarray_to_bytes, eval_number CONSTANTS = { 'GENERIC_READ': 0x80000000, 'GENERIC_WRITE': 0x40000000, 'OPEN_EXISTING': 0x03, 'CREATE_ALWAYS': 0x02, # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366890%28v=vs.85%29.aspx 'MEM_COMMIT': 0x00001000, 'MEM_RESERVE': 0x00002000, 'MEM_RESET': 0x00080000, 'MEM_RESET_UNDO': 0x01000000, 'MEM_LARGE_PAGES': 0x20000000, 'MEM_PHYSICAL': 0x00400000, 'MEM_TOP_DOWN': 0x00100000, # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366775%28v=vs.85%29.aspx 'MEM_IMAGE': 0x01000000, 'MEM_MAPPED': 0x00040000, 'MEM_PRIVATE': 0x00020000, # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366894%28v=vs.85%29.aspx 'MEM_DECOMMIT': 0x4000, 'MEM_RELEASE': 0x8000, # http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786%28v=vs.85%29.aspx 'PAGE_EXECUTE': 0x10, 'PAGE_EXECUTE_READ': 0x20, 'PAGE_EXECUTE_READWRITE': 0x40, 'PAGE_EXECUTE_WRITECOPY': 0x80, 'PAGE_NOACCESS': 0x01, 'PAGE_READONLY': 0x02, 'PAGE_READWRITE': 0x04, 'PAGE_WRITECOPY': 0x08, # http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880%28v=vs.85%29.aspx 'PROCESS_CREATE_PROCESS': 0x0080, 'PROCESS_CREATE_THREAD': 0x0002, 'PROCESS_DUP_HANDLE': 0x0040, 'PROCESS_QUERY_INFORMATION': 0x0400, 'PROCESS_QUERY_LIMITED_INFORMATION': 0x1000, 'PROCESS_SET_INFORMATION': 0x0200, 'PROCESS_SET_QUOTA': 0x0100, 'PROCESS_SUSPEND_RESUME': 0x0800, 'PROCESS_TERMINATE': 0x0001, 'PROCESS_VM_OPERATION': 0x0008, 'PROCESS_VM_READ': 0x0010, 'PROCESS_VM_WRITE': 0x0020, 'SYNCHRONIZE': 0x00100000, # http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v:vs.85%29.aspx 'FILE_SHARE_READ': 0x00000001, 'FILE_SHARE_WRITE': 0x00000002, 'FILE_SHARE_DELETE': 0x00000004, 'FILE_FLAG_OVERLAPPED': 0x40000000 } IMAGE_DIRECTORY_ENTRY_EXPORT = 0 IMAGE_DIRECTORY_ENTRY_IMPORT = 1 IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 IMAGE_DIRECTORY_ENTRY_DEBUG = 6 IMAGE_DIRECTORY_ENTRY_TLS = 9 class WindowsProcessError(ProcessError): def __init__(self, *args, **kwargs): self.get_last_error = None if 'get_last_error' in kwargs: self.get_last_error = kwargs['get_last_error'] del kwargs['get_last_error'] ProcessError.__init__(self, *args, **kwargs) def flags(flags): supported_operators = ['|', '+', '-', '^'] if isinstance(flags, int): return flags if flags[0] == '(' and flags[-1] == ')': flags = flags[1:-1] for sop in supported_operators: flags = flags.replace(sop, ' ' + sop + ' ') flags = flags.split() parsed_flags = 0 last_operator = None for part in flags: if part in CONSTANTS: part = CONSTANTS[part] elif part in supported_operators: last_operator = part continue else: part = eval_number(part) if last_operator is None: parsed_flags = part else: parsed_flags = eval(str(parsed_flags) + last_operator + str(part)) return parsed_flags def process_is_wow64(handle=None): """ Determine whether the process associated with the handle is running in WOW64 or not. :param int handle: A handle to the process to check. :return: Whether the process is running in WOW64 or not. :rtype: bool """ if not hasattr(ctypes.windll.kernel32, 'IsWow64Process'): return False if platform.architecture()[0] == '64bit': ctypes.windll.kernel32.IsWow64Process.argtypes = [ctypes.c_uint64, ctypes.POINTER(ctypes.c_bool)] handle = (handle or -1) is_wow64 = ctypes.c_bool() if not ctypes.windll.kernel32.IsWow64Process(handle, ctypes.byref(is_wow64)): raise WindowsProcessError('Error: IsWow64Process', get_last_error=ctypes.windll.kernel32.GetLastError()) return is_wow64.value class WindowsProcess(ProcessBase): """This class represents a process in a Windows environment.""" def __init__(self, pid=None, exe=None, handle=None, arch='x86', access=None): if platform.system() != 'Windows': raise RuntimeError('incompatible platform') self.__arch__ = arch self.k32 = ctypes.windll.kernel32 self.ntdll = ctypes.windll.ntdll self.psapi = ctypes.windll.psapi self._setup_winapi() self.handle = None if pid == -1: handle = -1 pid = None if access is None: access = "(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_TERMINATE)" if pid: self.handle = self.k32.OpenProcess(flags(access), False, pid) if not self.handle: raise ProcessError('could not open PID') elif exe: startupinfo = wintypes.STARTUPINFO() process_info = wintypes.PROCESS_INFORMATION() startupinfo.dwFlags = 0x01 startupinfo.wShowWindow = 0x00 startupinfo.cb = ctypes.sizeof(startupinfo) self.k32.CreateProcessA(exe, None, None, None, True, 0, None, None, ctypes.byref(startupinfo), ctypes.byref(process_info)) self.handle = process_info.hProcess if not self.handle: raise ProcessError('could not the create process') elif handle: self.handle = handle else: raise ProcessError('either a pid, exe or a handle must be specified') if process_is_wow64() != process_is_wow64(self.handle): raise ProcessError('the python process must be the same architecture as the target process') self.pid = self.k32.GetProcessId(self.handle) _name = (ctypes.c_char * 0x400) name = _name() if hasattr(self.psapi, 'GetModuleFileNameExA'): self.psapi.GetModuleFileNameExA(self.handle, 0, name, ctypes.sizeof(name)) else: self.k32.GetModuleFileNameExA(self.handle, 0, name, ctypes.sizeof(name)) self.exe_file = b''.join(name).rstrip(b'\x00').decode('utf-8') self._installed_hooks = [] def __del__(self): if self.handle: self.close() def get_proc_attribute(self, attribute): requested_attribute = attribute if attribute.startswith('&'): attribute = attribute[1:] + '_addr' if hasattr(self, '_get_attr_' + attribute): return getattr(self, '_get_attr_' + attribute)() raise ProcessError('Unknown Attribute: ' + requested_attribute) 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 _get_attr_peb(self): peb_addr = self.get_proc_attribute('peb_addr') peb = wintypes.PEB() self.k32.ReadProcessMemory(self.handle, peb_addr, ctypes.byref(peb), ctypes.sizeof(peb), 0) return peb def _get_attr_peb_ldr_data_addr(self): peb = self.get_proc_attribute('peb') return peb.Ldr def _get_attr_peb_ldr_data(self): peb_ldr_data_addr = self.get_proc_attribute('peb_ldr_data_addr') peb_ldr_data = wintypes.PEB_LDR_DATA() self.k32.ReadProcessMemory(self.handle, peb_ldr_data_addr, ctypes.byref(peb_ldr_data), ctypes.sizeof(peb_ldr_data), 0) return peb_ldr_data def _get_attr_image_dos_header_addr(self): return self.get_proc_attribute('peb').ImageBaseAddress def _get_attr_image_dos_header(self): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') image_dos_header = wintypes.IMAGE_DOS_HEADER() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr, ctypes.byref(image_dos_header), ctypes.sizeof(image_dos_header), 0) return image_dos_header def _get_attr_image_nt_headers_addr(self): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') image_dos_header = self.get_proc_attribute('image_dos_header') return image_dos_header_addr + image_dos_header.e_lfanew def _get_attr_image_nt_headers(self): if self.__arch__ == 'x86': image_nt_headers = wintypes.IMAGE_NT_HEADERS32() else: raise Exception('the selected architecture is not supported') self.k32.ReadProcessMemory(self.handle, self.get_proc_attribute('image_nt_headers_addr'), ctypes.byref(image_nt_headers), ctypes.sizeof(image_nt_headers), 0) return image_nt_headers def _get_attr_image_import_descriptor_addr(self): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') optional_header = self.get_proc_attribute('image_nt_headers').OptionalHeader return image_dos_header_addr + optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress def _get_attr_image_import_descriptor(self): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') optional_header = self.get_proc_attribute('image_nt_headers').OptionalHeader import_directory = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] _import_descriptors = wintypes.IMAGE_IMPORT_DESCRIPTOR * ( (import_directory.Size / ctypes.sizeof(wintypes.IMAGE_IMPORT_DESCRIPTOR)) - 1) import_descriptors = _import_descriptors() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr + import_directory.VirtualAddress, ctypes.byref(import_descriptors), ctypes.sizeof(import_descriptors), 0) return import_descriptors def _get_attr_system_info(self): system_info = wintypes.SYSTEM_INFO() self.k32.GetSystemInfo(ctypes.byref(system_info)) return system_info def _get_name_for_ilt_entry(self, ilt_ent): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') _name = (ctypes.c_char * 0x200) name = _name() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr + ilt_ent + ctypes.sizeof(wintypes.WORD), ctypes.byref(name), ctypes.sizeof(name), 0) name = ''.join(name) name = name.split('\x00')[0] return name def _get_ordinal_for_ilt_entry(self, ilt_ent): return (ilt_ent & 0x7FFFFFFF) def _get_name_for_image_import_descriptor(self, iid): image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') _name = (ctypes.c_char * 0x400) name = _name() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr + iid.Name, ctypes.byref(name), ctypes.sizeof(name), 0) name = ''.join(name) name = name.split('\x00')[0] return name def _get_ilt_for_image_import_descriptor(self, iid): # import lookup table image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') _ilt = (ctypes.c_void_p * 0x200) ilt = _ilt() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr + iid.OriginalFirstThunk, ctypes.byref(ilt), ctypes.sizeof(ilt), 0) return ilt def _get_iat_for_image_import_descriptor(self, iid): # import address table image_dos_header_addr = self.get_proc_attribute('image_dos_header_addr') _iat = (ctypes.c_void_p * 0x200) iat = _iat() self.k32.ReadProcessMemory(self.handle, image_dos_header_addr + iid.FirstThunk, ctypes.byref(iat), ctypes.sizeof(iat), 0) return iat def _get_image_base_by_name(self, name): peb_ldr_data = self.get_proc_attribute('peb_ldr_data') firstFLink = 0 fLink = peb_ldr_data.InLoadOrderModuleList.Flink while fLink != firstFLink: firstFLink = peb_ldr_data.InLoadOrderModuleList.Flink module = wintypes.LDR_MODULE() self.k32.ReadProcessMemory(self.handle, fLink, ctypes.byref(module), ctypes.sizeof(module), 0) _base_dll_name = (ctypes.c_wchar * module.BaseDllName.MaximumLength) base_dll_name = _base_dll_name() self.k32.ReadProcessMemory(self.handle, module.BaseDllName.Buffer, base_dll_name, module.BaseDllName.Length + 2, 0) base_dll_name = base_dll_name[:(module.BaseDllName.Length / 2)] if name == base_dll_name: return module fLink = module.InLoadOrderModuleList.Flink return None def _setup_winapi(self): self.k32.CreateRemoteThread.argtypes = [wintypes.HANDLE, ctypes.POINTER(wintypes.SECURITY_ATTRIBUTES), wintypes.SIZE_T, ctypes.c_void_p, wintypes.LPVOID, wintypes.DWORD, wintypes.PDWORD] self.k32.CreateRemoteThread.restype = wintypes.HANDLE self.k32.GetExitCodeThread.argtypes = [wintypes.HANDLE, wintypes.PDWORD] self.k32.GetModuleHandleA.argtypes = [wintypes.LPSTR] self.k32.GetModuleHandleA.restype = wintypes.HANDLE self.k32.GetProcAddress.argtypes = [wintypes.HMODULE, wintypes.LPSTR] self.k32.GetProcAddress.restype = ctypes.c_void_p self.k32.GetProcessId.argtypes = [wintypes.HANDLE] self.k32.GetProcessId.restype = wintypes.DWORD self.k32.ReadProcessMemory.argtypes = [wintypes.HANDLE, wintypes.LPCVOID, wintypes.LPVOID, wintypes.SIZE_T, wintypes.SIZE_T] self.k32.VirtualAllocEx.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.SIZE_T, wintypes.DWORD, wintypes.DWORD] self.k32.VirtualAllocEx.restype = wintypes.SIZE_T self.k32.VirtualFreeEx.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.SIZE_T, wintypes.DWORD] self.k32.VirtualProtectEx.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.SIZE_T, wintypes.DWORD, ctypes.POINTER(wintypes.DWORD)] self.k32.VirtualQueryEx.argtypes = [wintypes.HANDLE, wintypes.LPCVOID, wintypes.PMEMORY_BASIC_INFORMATION, wintypes.SIZE_T] self.k32.VirtualQueryEx.restype = wintypes.SIZE_T self.k32.WaitForSingleObject.argtypes = [wintypes.HANDLE, wintypes.DWORD] self.k32.WaitForSingleObject.restype = wintypes.DWORD self.k32.WriteProcessMemory.argtypes = [wintypes.HANDLE, wintypes.LPVOID, wintypes.LPCVOID, wintypes.SIZE_T, ctypes.POINTER(wintypes.SIZE_T)] if hasattr(self.psapi, 'GetModuleFileNameExA'): self.psapi.GetModuleFileNameExA.argtypes = [wintypes.HANDLE, wintypes.HMODULE, wintypes.LPSTR, wintypes.DWORD] self.psapi.GetModuleFileNameExA.restype = wintypes.DWORD else: self.k32.GetModuleFileNameExA.argtypes = [wintypes.HANDLE, wintypes.HMODULE, wintypes.LPSTR, wintypes.DWORD] self.k32.GetModuleFileNameExA.restype = wintypes.DWORD @property def maps(self): sys_info = self.get_proc_attribute('system_info') _maps = collections.deque() address_cursor = 0 VirtualQueryEx = self.k32.VirtualQueryEx meminfo = wintypes.MEMORY_BASIC_INFORMATION() MEM_COMMIT = flags('MEM_COMMIT') MEM_PRIVATE = flags('MEM_PRIVATE') PROTECT_FLAGS = {0x01: '---', 0x02: 'r--', 0x04: 'rw-', 0x08: 'r--', 0x10: '--x', 0x20: 'r-x', 0x40: 'rwx', 0x80: 'r-x'} while address_cursor < sys_info.lpMaximumApplicationAddress: if VirtualQueryEx(self.handle, address_cursor, ctypes.byref(meminfo), ctypes.sizeof(meminfo)) == 0: break address_cursor = meminfo.BaseAddress + meminfo.RegionSize if not meminfo.State & MEM_COMMIT: continue addr_low = meminfo.BaseAddress addr_high = address_cursor perms = PROTECT_FLAGS[meminfo.Protect & 0xff] perms += 'p' if meminfo.Type & MEM_PRIVATE else 's' _maps.append(MemoryRegion(addr_low, addr_high, perms)) return collections.OrderedDict((mr.addr_low, mr) for mr in sorted(_maps, key=lambda mr: mr.addr_low)) 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 close(self): self.k32.CloseHandle(self.handle) self.handle = None def kill(self): self.k32.TerminateProcess(self.handle, 0) self.close() 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)) return exitcode.value def read_memory(self, address, size=0x400): _data = (ctypes.c_byte * size) data = _data() if (self.k32.ReadProcessMemory(self.handle, address, ctypes.byref(data), ctypes.sizeof(data), 0) == 0): raise WindowsProcessError('Error: ReadProcessMemory', get_last_error=self.k32.GetLastError()) return ctarray_to_bytes(data) def write_memory(self, address, data): if isinstance(data, str): data = data.encode('utf-8') _wr_data = (ctypes.c_char * len(data)) wr_data = _wr_data() wr_data.value = data written = wintypes.SIZE_T() if not self.k32.WriteProcessMemory(self.handle, address, ctypes.byref(wr_data), ctypes.sizeof(wr_data), ctypes.byref(written)): raise WindowsProcessError('Error: WriteProcessMemory', get_last_error=self.k32.GetLastError()) return def allocate(self, size=0x400, address=None, permissions=None): alloc_type = flags('MEM_COMMIT') permissions = flags(permissions or 'PAGE_EXECUTE_READWRITE') result = self.k32.VirtualAllocEx(self.handle, address, size, alloc_type, permissions) return result def free(self, address): free_type = flags('MEM_RELEASE') if (self.k32.VirtualFreeEx(self.handle, address, 0, free_type) == 0): raise WindowsProcessError('Error: VirtualFreeEx', get_last_error=self.k32.GetLastError()) return 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 start_thread(self, address, targ=None): handle = self.k32.CreateRemoteThread(self.handle, None, 0, address, targ, 0, None) if handle == 0: raise WindowsProcessError('Error: CreateRemoteThread', get_last_error=self.k32.GetLastError()) return handle def join_thread(self, thread_id, timeout=-1): self.k32.WaitForSingleObject(thread_id, timeout) return def run_payload(self, shellcode): VIRTUAL_MEM = (0x1000 | 0x2000) PAGE_EXECUTE_READWRITE = 0x00000040 shellcode_address = self.k32.VirtualAllocEx(self.handle, 0, len(shellcode), VIRTUAL_MEM, PAGE_EXECUTE_READWRITE) # shellcode_address = self.allocate(size=utilities.align_up(len(shellcode)), permissions='PAGE_READWRITE') w = ctypes.c_int(0) self.k32.WriteProcessMemory(self.handle, shellcode_address, shellcode, len(shellcode), ctypes.byref(w)) t_id = ctypes.c_ulong(0) if not self.k32.CreateRemoteThread(self.handle, None, 0, shellcode_address, None, 0, ctypes.byref(t_id)): # Cannot start thread return False