def __init__(self, *args, **kwargs): self.errno = None """The libc error number at the time the exception was raised.""" if 'errno' in kwargs: self.errno = kwargs['errno'] del kwargs['errno'] ProcessError.__init__(self, *args, **kwargs)
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 = ''.join(name).rstrip('\x00') self._installed_hooks = [] self._update_maps()
def install_hook(self, mod_name, new_address, name=None, ordinal=None): if architecture_is_32bit(self.__arch__): lm_struct = elf.Elf32_Link_Map dyn_struct = elf.Elf32_Dyn sym_struct = elf.Elf32_Sym elif architecture_is_64bit(self.__arch__): lm_struct = elf.Elf64_Link_Map dyn_struct = elf.Elf64_Dyn sym_struct = elf.Elf64_Sym else: raise LinuxProcessError('unsupported architecture: ' + repr(self.__arch__)) if ordinal: raise NotImplementedError('an ordinal is not supported for this implementation') if not name: raise RuntimeError('a name is required for this implementation') lm = self._read_structure_from_memory(self.get_proc_attribute('link_map_addr'), lm_struct) if os.path.isabs(mod_name): validate_name = lambda lm: bool(self.read_memory_string(lm.l_name) == mod_name) else: validate_name = lambda lm: bool(os.path.split(self.read_memory_string(lm.l_name))[-1].startswith(mod_name)) while not validate_name(lm): if lm.l_next == 0: raise ProcessError('unable to locate shared library') lm = self._read_structure_from_memory(lm.l_next, lm_struct) idx = 0 dyn = self._read_structure_from_memory(lm.l_ld, dyn_struct) nchains = 0 strtab = 0 symtab = 0 while dyn.d_tag: idx += 1 if dyn.d_tag == elf.constants.DT_HASH: #nchains = struct.unpack('I', self.read_memory(dyn.d_un.d_ptr + lm.l_addr + ctypes.sizeof(ctypes.c_int), ctypes.sizeof(ctypes.c_int)))[0] nchains = struct.unpack('I', self.read_memory(dyn.d_un.d_ptr + ctypes.sizeof(ctypes.c_int), ctypes.sizeof(ctypes.c_int)))[0] elif dyn.d_tag == elf.constants.DT_STRTAB: strtab = dyn.d_un.d_ptr elif dyn.d_tag == elf.constants.DT_SYMTAB: symtab = dyn.d_un.d_ptr dyn = self._read_structure_from_memory(lm.l_ld + (ctypes.sizeof(dyn_struct) * idx), dyn_struct) for idx in xrange(0, nchains): sym = self._read_structure_from_memory(symtab + (ctypes.sizeof(sym_struct) * idx), sym_struct) if (sym.st_info & 0xf) != elf.constants.STT_FUNC: continue if self.read_memory_string(strtab + sym.st_name) == name: sym_addr = (symtab + (ctypes.sizeof(sym_struct) * idx)) old_address = lm.l_addr + sym.st_value sym.st_value = (lm.l_addr - new_address) self.write_memory(sym_addr, struct_pack(sym)) hook = Hook('eat', (sym_addr + sym_struct.st_value.offset), old_address, new_address) self._installed_hooks.append(hook) return hook raise ProcessError('unable to locate function')
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_proc_attribute(self, attribute): requested_attribute = attribute if attribute.startswith('&'): attribute = attribute[1:] + '_addr' if attribute.startswith('elf_'): if architecture_is_32bit(self.__arch__): attribute = 'elf32_' + attribute[4:] elif architecture_is_64bit(self.__arch__): attribute = 'elf64_' + attribute[4:] if hasattr(self, '_get_attr_' + attribute): return getattr(self, '_get_attr_' + attribute)() elif not attribute.endswith('_addr') and attribute.startswith( 'elf32_'): if hasattr(self, '_get_attr_' + attribute + '_addr'): address = getattr(self, '_get_attr_' + attribute + '_addr')() attribute = 'Elf32_' + attribute[6:].title() if hasattr(elf, attribute): return self._read_structure_from_memory( address, getattr(elf, attribute)) elif not attribute.endswith('_addr') and attribute.startswith( 'elf64_'): if hasattr(self, '_get_attr_' + attribute + '_addr'): address = getattr(self, '_get_attr_' + attribute + '_addr')() attribute = 'Elf64_' + attribute[6:].title() if hasattr(elf, attribute): return self._read_structure_from_memory( address, getattr(elf, attribute)) raise ProcessError('Unknown Attribute: ' + requested_attribute)
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 _allocate_malloc(self, size): malloc_addr = None malloc_locations = ['libc-', 'ld-linux.so'] for lib in malloc_locations: try: malloc_addr = self._get_function_address(lib, 'malloc') break except ProcessError: pass if malloc_addr is None: raise ProcessError('unable to locate function') return self._call_function(malloc_addr, size)
def _free_free(self, address): free_addr = None free_locations = ['libc-', 'ld-linux.so'] for lib in free_locations: try: free_addr = self._get_function_address(lib, 'free') break except ProcessError: pass if free_addr is None: raise ProcessError('unable to locate function') self._call_function(free_addr, address) return
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 _get_function_address(self, mod_name, func_name): if architecture_is_32bit(self.__arch__): ehdr_struct = elf.Elf32_Ehdr shdr_struct = elf.Elf32_Shdr sym_struct = elf.Elf32_Sym elif architecture_is_64bit(self.__arch__): ehdr_struct = elf.Elf64_Ehdr shdr_struct = elf.Elf64_Shdr sym_struct = elf.Elf64_Sym else: raise LinuxProcessError('unsupported architecture: ' + repr(self.__arch__)) ehdr_addr = None if os.path.isabs(mod_name): exe_maps = filter(lambda x: x.pathname == mod_name, self.maps.values()) filename = mod_name else: exe_maps = filter( lambda x: x.pathname != None and os.path.basename(x.pathname). startswith(mod_name), self.maps.values()) filename = exe_maps[0].pathname handle = open(filename, 'rb') ehdr = struct_unpack(ehdr_struct, handle.read(ctypes.sizeof(ehdr_struct))) # get the shdrs handle.seek(ehdr.e_shoff, os.SEEK_SET) data = handle.read(ehdr.e_shnum * ehdr.e_shentsize) _shdrs = (shdr_struct * ehdr.e_shnum) shdrs = _shdrs() ctypes.memmove(ctypes.byref(shdrs), data, len(data)) strtab = 0 symtab = 0 for idx in range(len(shdrs)): shdr = shdrs[idx] if shdr.sh_type == elf.constants.SHT_SYMTAB or shdr.sh_type == elf.constants.SHT_DYNSYM: if not (shdr.sh_entsize and shdr.sh_size): continue symtab = idx elif shdr.sh_type == elf.constants.SHT_STRTAB: if idx != ehdr.e_shstrndx: strtab = idx if symtab == 0 or strtab == 0: continue symh = shdrs[symtab] strh = shdrs[strtab] handle.seek(strh.sh_offset, os.SEEK_SET) strsymtbl = handle.read(strh.sh_size) sym_num = symh.sh_size / symh.sh_entsize _syms = (sym_struct * sym_num) syms = _syms() handle.seek(symh.sh_offset, os.SEEK_SET) ctypes.memmove(ctypes.byref(syms), handle.read(ctypes.sizeof(syms)), ctypes.sizeof(syms)) for idx in range(1, len(syms)): sym = syms[idx] name = "" if sym.st_name == 0: continue name_end = strsymtbl.find('\x00', sym.st_name) if strsymtbl[sym.st_name:name_end] != func_name: continue address = sym.st_value if filter( lambda mr: (address > mr.addr_low and address < mr.addr_high), exe_maps): return address else: return address + sorted( exe_maps, key=lambda mr: mr.addr_low)[0].addr_low strtab = 0 symtab = 0 raise ProcessError('unable to locate function')
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)