def main(): parser = argparse.ArgumentParser( description='syringe: library & shellcode injection utility', conflict_handler='resolve', epilog='The PID argument can be specified as -1 to inject into the context of the syringe process.' ) parser.add_argument('-l', '--load', dest='library', action='store', help='load the library in the target process') shellcode_group = parser.add_mutually_exclusive_group() shellcode_group.add_argument('-i', '--inject', dest='shellcode', action='store', help='inject code into the process') shellcode_group.add_argument('-f', '--inject-file', dest='shellcode_file', type=argparse.FileType('rb'), help='inject code from a file into the process') parser.add_argument('-d', '--decode', dest='decode', action='store', choices=('b64', 'hex', 'raw'), default='b64', help='decode the shellcode prior to execution') parser.add_argument('pid', action='store', type=int, help='process to control') arguments = parser.parse_args() try: process_h = NativeProcess(pid=arguments.pid) except ProcessError as error: print("[-] {0}".format(error.msg)) return print("[+] Opened a handle to pid: {0}".format(arguments.pid)) if arguments.library: try: lib_h = process_h.load_library(arguments.library) except ProcessError as error: print("[-] {0}".format(error.msg)) else: print("[+] Loaded {0} with handle 0x{1:08x}".format(arguments.library, lib_h)) if arguments.shellcode or arguments.shellcode_file: if arguments.shellcode: shellcode = arguments.shellcode else: shellcode = arguments.shellcode_file.read() arguments.shellcode_file.close() if arguments.decode == 'b64': shellcode = shellcode.decode('base64') elif arguments.decode == 'hex': shellcode = shellcode.decode('hex') stub = "" # no stub by default if architecture_is_32bit(process_h.arch): stub = "\x8b\x44\x24\x04" # mov eax,[esp+4] elif architecture_is_64bit(process_h.arch): stub = "\x48\x8b\x44\x24\x08" # mov rax,[rsp+8] shellcode_sz = align_up(len(stub + shellcode), 1024) address = process_h.allocate(size=shellcode_sz, address=0) print("[+] Allocated {0} bytes at 0x{1:08x}".format(shellcode_sz, address)) process_h.protect(address, size=shellcode_sz) process_h.write_memory(address, stub + shellcode) thread_id = process_h.start_thread(address, (address + len(stub))) print("[+] Started thread at 0x{0:08x}".format(address)) print("[*] Waiting for thread to complete...") try: process_h.join_thread(thread_id) print("[+] Thread completed") except ProcessError as err: print("[-] {0} {1}".format(err.__class__.__name__, err.msg)) process_h.close()
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 jump_stub(address): arch = platform.machine() if utilities.architecture_is_32bit(arch): stub = b'\xb8' + struct.pack('I', address) # mov eax, address stub += b'\xff\xe0' # jmp eax elif utilities.architecture_is_64bit(arch): stub = b'\x48\xb8' + struct.pack('Q', address) # mov rax, address stub += b'\xff\xe0' # jmp rax return stub
def jump_stub(address): arch = platform.machine() if utilities.architecture_is_32bit(arch): #ff is jump near with absolute addr, and also requires addr to be loaded into register before jumping stub = b'\xb8' + struct.pack('I', address) # mov eax, address stub += b'\xff\xe0' # jmp eax elif utilities.architecture_is_64bit(arch): stub = b'\x48\xb8' + struct.pack('Q', address) # mov rax, address stub += b'\xff\xe0' # jmp rax return stub
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 __init__(self, pid=None, exe=None): if platform.system() != 'Linux': raise RuntimeError('incompatible platform') # Ensure that we are running in a version of python that matches the native architecture of the system. if platform.architecture()[0] == '32bit': if not architecture_is_32bit(platform.machine()): raise LinuxProcessError( 'Running a 32-bit version of Python on a non x86 system is not supported' ) elif platform.architecture()[0] == '64bit': if not architecture_is_64bit(platform.machine()): raise LinuxProcessError( 'Running a 64-bit version of Python on a non x86-64 system is not supported' ) else: raise LinuxProcessError('Could not determine the Python version') self._proc_h = None signal.signal(signal.SIGCHLD, self._signal_sigchld) if exe: self._proc_h = subprocess.Popen([exe], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) pid = self._proc_h.pid if pid == -1: pid = os.fork() if pid == 0: select.select([], [], [], None) select.select([], [], [], 0.50) self.handle = pid self.pid = pid self.exe_file = os.readlink('/proc/' + str(self.pid) + '/exe') ei_ident = open(self.exe_file, 'rb').read(elf.constants.EI_NIDENT) ei_ident = map(ord, ei_ident) if ei_ident[elf.constants.EI_CLASS] == elf.constants.ELFCLASS32: self.__arch__ = 'x86' elif ei_ident[elf.constants.EI_CLASS] == elf.constants.ELFCLASS64: if architecture_is_32bit(platform.machine()): raise LinuxProcessError( 'Controlling a 64-bit process from a 32-bit process is not supported' ) self.__arch__ = 'x86_64' else: raise LinuxProcessError('Unsupported EI_CLASS ' + str(ei_ident[elf.constants.EI_CLASS])) if self._ptrace(PTRACE_ATTACH) != 0: Exception('could not open PID') os.waitpid(pid, 0) self._installed_hooks = [] self._update_maps()
def _get_attr_got_addr(self): if architecture_is_32bit(self.__arch__): dyn_struct = elf.Elf32_Dyn elif architecture_is_64bit(self.__arch__): dyn_struct = elf.Elf64_Dyn else: raise LinuxProcessError('unsupported architecture: ' + repr(self.__arch__)) dyn_addr = self.get_proc_attribute('elf_dyn_addr') dyn = self._read_structure_from_memory(dyn_addr, dyn_struct) idx = 0 while dyn.d_tag != elf.constants.DT_PLTGOT: idx += 1 next_dyn_addr = dyn_addr + (ctypes.sizeof(dyn_struct) * idx) dyn = self._read_structure_from_memory(next_dyn_addr, dyn_struct) return dyn.d_un.d_ptr
def _call_function(self, function_address, *args): if len(args) > 6: raise Exception('can not pass more than 6 arguments') registers_backup = self._get_registers() if architecture_is_32bit(self.__arch__): registers = {'eip': function_address, 'eax': function_address} self._set_registers(registers) backup_sp = self.read_memory(registers_backup['esp'], 4) self.write_memory(registers_backup['esp'], '\x00\x00\x00\x00') for i in range(len(args)): stack_cursor = registers_backup['esp'] + ((i + 1) * 4) backup_sp += self.read_memory(stack_cursor, 4) if args[i] < 0: self.write_memory(stack_cursor, struct.pack('i', args[i])) else: self.write_memory(stack_cursor, struct.pack('I', args[i])) self._ptrace(PTRACE_CONT) wait_result = os.waitpid(self.pid, 0) self.write_memory(registers_backup['esp'], backup_sp) ending_ip = self._get_registers()['eip'] result = self._get_registers()['eax'] elif architecture_is_64bit(self.__arch__): registers = {'rip': function_address, 'rax': function_address} arg_registers = ['rdi', 'rsi', 'rdx', 'rcx', 'r8', 'r9'] for i in range(len(args)): registers[arg_registers[i]] = args[i] self._set_registers(registers) backup_sp = self.read_memory(registers_backup['rsp'], 8) self.write_memory(registers_backup['rsp'], '\x00\x00\x00\x00\x00\x00\x00\x00') self._ptrace(PTRACE_CONT) wait_result = os.waitpid(self.pid, 0) self.write_memory(registers_backup['rsp'], backup_sp) ending_ip = self._get_registers()['rip'] result = self._get_registers()['rax'] self._set_registers(registers_backup) if (os.WSTOPSIG(wait_result[1]) == signal.SIGSEGV) and (ending_ip != 0): raise LinuxProcessError('segmentation fault') return result
def __init__(self, pid=None, exe=None): if platform.system() != 'Linux': raise RuntimeError('incompatible platform') # Ensure that we are running in a version of python that matches the native architecture of the system. if platform.architecture()[0] == '32bit': if not architecture_is_32bit(platform.machine()): raise LinuxProcessError('Running a 32-bit version of Python on a non x86 system is not supported') elif platform.architecture()[0] == '64bit': if not architecture_is_64bit(platform.machine()): raise LinuxProcessError('Running a 64-bit version of Python on a non x86-64 system is not supported') else: raise LinuxProcessError('Could not determine the Python version') self._proc_h = None signal.signal(signal.SIGCHLD, self._signal_sigchld) if exe: self._proc_h = subprocess.Popen([exe], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) pid = self._proc_h.pid if pid == -1: pid = os.fork() if pid == 0: select.select([], [], [], None) select.select([], [], [], 0.50) self.handle = pid self.pid = pid self.exe_file = os.readlink('/proc/' + str(self.pid) + '/exe') ei_ident = open(self.exe_file, 'rb').read(elf.constants.EI_NIDENT) ei_ident = map(ord, ei_ident) if ei_ident[elf.constants.EI_CLASS] == elf.constants.ELFCLASS32: self.__arch__ = 'x86' elif ei_ident[elf.constants.EI_CLASS] == elf.constants.ELFCLASS64: if architecture_is_32bit(platform.machine()): raise LinuxProcessError('Controlling a 64-bit process from a 32-bit process is not supported') self.__arch__ = 'x86_64' else: raise LinuxProcessError('Unsupported EI_CLASS ' + str(ei_ident[elf.constants.EI_CLASS])) if self._ptrace(PTRACE_ATTACH) != 0: Exception('could not open PID') os.waitpid(pid, 0) self._installed_hooks = [] self._update_maps()
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 main(): parser = argparse.ArgumentParser( description='syringe: library & shellcode injection utility', conflict_handler='resolve', epilog= 'The PID argument can be specified as -1 to inject into the context of the syringe process.' ) parser.add_argument('-l', '--load', dest='library', action='store', help='load the library in the target process') shellcode_group = parser.add_mutually_exclusive_group() shellcode_group.add_argument('-i', '--inject', dest='shellcode', action='store', help='inject code into the process') shellcode_group.add_argument( '-f', '--inject-file', dest='shellcode_file', type=argparse.FileType('rb'), help='inject code from a file into the process') parser.add_argument('-d', '--decode', dest='decode', action='store', choices=('b64', 'hex', 'raw'), default='b64', help='decode the shellcode prior to execution') parser.add_argument('pid', action='store', type=int, help='process to control') arguments = parser.parse_args() try: process_h = NativeProcess(pid=arguments.pid) except ProcessError as error: print("[-] {0}".format(error.msg)) return print("[+] Opened a handle to pid: {0}".format(arguments.pid)) if arguments.library: try: lib_h = process_h.load_library(arguments.library) except ProcessError as error: print("[-] {0}".format(error.msg)) else: print("[+] Loaded {0} with handle 0x{1:08x}".format( arguments.library, lib_h)) if arguments.shellcode or arguments.shellcode_file: if arguments.shellcode: shellcode = arguments.shellcode else: shellcode = arguments.shellcode_file.read() arguments.shellcode_file.close() if arguments.decode == 'b64': shellcode = shellcode.decode('base64') elif arguments.decode == 'hex': shellcode = shellcode.decode('hex') stub = '' # no stub by default if architecture_is_32bit(process_h.arch): stub = b'\x8b\x44\x24\x04' # mov eax,[esp+4] elif architecture_is_64bit(process_h.arch): stub = b'\x48\x8b\x44\x24\x08' # mov rax,[rsp+8] shellcode_sz = align_up(len(stub + shellcode), 1024) address = process_h.allocate(size=shellcode_sz, address=0) print("[+] Allocated {0} bytes at 0x{1:08x}".format( shellcode_sz, address)) process_h.protect(address, size=shellcode_sz) process_h.write_memory(address, stub + shellcode) thread_id = process_h.start_thread(address, (address + len(stub))) print("[+] Started thread at 0x{0:08x}".format(address)) print("[*] Waiting for thread to complete...") try: process_h.join_thread(thread_id) print("[+] Thread completed") except ProcessError as err: print("[-] {0} {1}".format(err.__class__.__name__, err.msg)) process_h.close()
def architecture_is_supported(arch): return architecture_is_32bit(arch) or architecture_is_64bit(arch)
def _set_registers(self, registers={}): if not architecture_is_supported(self.__arch__): raise LinuxProcessError('unsupported architecture: ' + repr(self.__arch__)) old_registers = self._get_registers() old_registers.update(registers) _raw_registers = (ctypes.c_ulong * 32) raw_registers = _raw_registers() # constants from sys/reg.h if architecture_is_32bit(platform.machine()): raw_registers[0] = old_registers['ebx'] raw_registers[1] = old_registers['ecx'] raw_registers[2] = old_registers['edx'] raw_registers[3] = old_registers['esi'] raw_registers[4] = old_registers['edi'] raw_registers[5] = old_registers['ebp'] raw_registers[6] = old_registers['eax'] raw_registers[7] = old_registers['ds'] raw_registers[8] = old_registers['es'] raw_registers[9] = old_registers['fs'] raw_registers[10] = old_registers['gs'] raw_registers[11] = old_registers['orig_eax'] raw_registers[12] = old_registers['eip'] raw_registers[13] = old_registers['cs'] raw_registers[14] = old_registers['eflags'] raw_registers[15] = old_registers['esp'] raw_registers[16] = old_registers['ss'] elif architecture_is_64bit(platform.machine()): if architecture_is_32bit(self.__arch__): _raw_registers = (ctypes.c_ulong * 32) raw_registers = _raw_registers() if self._ptrace(PTRACE_GETREGS, 0, ctypes.byref(raw_registers)) != 0: raise LinuxProcessError('Error: PTRACE_GETREGS', errno=get_errno()) raw_registers[4] = old_registers['ebp'] raw_registers[5] = old_registers['ebx'] raw_registers[10] = old_registers['eax'] raw_registers[11] = old_registers['ecx'] raw_registers[12] = old_registers['edx'] raw_registers[13] = old_registers['esi'] raw_registers[14] = old_registers['edi'] raw_registers[15] = old_registers['orig_eax'] raw_registers[16] = old_registers['eip'] raw_registers[17] = old_registers['cs'] raw_registers[18] = old_registers['eflags'] raw_registers[19] = old_registers['esp'] raw_registers[20] = old_registers['ss'] raw_registers[23] = old_registers['ds'] raw_registers[24] = old_registers['es'] raw_registers[25] = old_registers['fs'] raw_registers[26] = old_registers['gs'] else: raw_registers[0] = old_registers['r15'] raw_registers[1] = old_registers['r14'] raw_registers[2] = old_registers['r13'] raw_registers[3] = old_registers['r12'] raw_registers[4] = old_registers['rbp'] raw_registers[5] = old_registers['rbx'] raw_registers[6] = old_registers['r11'] raw_registers[7] = old_registers['r10'] raw_registers[8] = old_registers['r9'] raw_registers[9] = old_registers['r8'] raw_registers[10] = old_registers['rax'] raw_registers[11] = old_registers['rcx'] raw_registers[12] = old_registers['rdx'] raw_registers[13] = old_registers['rsi'] raw_registers[14] = old_registers['rdi'] raw_registers[15] = old_registers['orig_rax'] raw_registers[16] = old_registers['rip'] raw_registers[17] = old_registers['cs'] raw_registers[18] = old_registers['eflags'] raw_registers[19] = old_registers['rsp'] raw_registers[20] = old_registers['ss'] raw_registers[21] = old_registers['fs_base'] raw_registers[22] = old_registers['gs_base'] raw_registers[23] = old_registers['ds'] raw_registers[24] = old_registers['es'] raw_registers[25] = old_registers['fs'] raw_registers[26] = old_registers['gs'] if self._ptrace(PTRACE_SETREGS, 0, ctypes.byref(raw_registers)) != 0: raise LinuxProcessError('Error: PTRACE_SETREGS', errno=get_errno()) return
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 _get_attr_link_map_addr(self): got_addr = self.get_proc_attribute('got_addr') if architecture_is_32bit(self.__arch__): return struct.unpack('II', self.read_memory(got_addr, 8))[1] elif architecture_is_64bit(self.__arch__): return struct.unpack('QQ', self.read_memory(got_addr, 16))[1]
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')