def __init__(self, address=None, size=None, instr=None, registers=None, process=None): """ address is an integer or a list of integer """ if address is not None: if isinstance(address, (list, tuple)): arguments = " or ".join( formatAddress(addr) for addr in address) else: arguments = formatAddress(address) message = self.PREFIX_ADDR % arguments else: message = self.PREFIX if size: message += " (size=%s bytes)" % size name = self.NAME if address is not None: name += "-" + formatAddress(address).lower() SignalInfo.__init__(self, name, message, address=address, size=size, instr=instr, process=process, registers=registers)
def _dumpCode(self, address, ip, manage_bp): if not HAS_DISASSEMBLER: code = self.readCode(address) text = " ".join( "%02x" % ord(byte) for byte in code ) error("CODE: %s" % text) return if manage_bp: for line in xrange(10): bp = False if address in self.breakpoints: bytes = self.breakpoints[address].old_bytes instr = disassembleOne(bytes, address) bp = True else: instr = self.disassembleOne(address) text = "ASM %s: %s (%s)" % (formatAddress(instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" if bp: text += " * BREAKPOINT *" error(text) address = address+instr.size else: for instr in self.disassemble(address): text = "ASM %s: %s (%s)" % (formatAddress(instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" error(text)
def _dumpCode(self, address, ip, manage_bp): if not HAS_DISASSEMBLER: code = self.readCode(address) text = " ".join("%02x" % ord(byte) for byte in code) error("CODE: %s" % text) return if manage_bp: for line in xrange(10): bp = False if address in self.breakpoints: bytes = self.breakpoints[address].old_bytes instr = disassembleOne(bytes, address) bp = True else: instr = self.disassembleOne(address) text = "ASM %s: %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" if bp: text += " * BREAKPOINT *" error(text) address = address + instr.size else: for instr in self.disassemble(address): text = "ASM %s: %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" error(text)
def xray(self): for process, procmap, address, term in self._xray(): pointers = " ".join(formatAddress(ptr_addr) for ptr_addr in getPointers(process, address)) print("term[%s] pid[%i] %s %s pointers: %s" % ( repr(term), process.pid, procmap, formatAddress(address), pointers))
def dumpStack(self): stack = self.findStack() if stack: error("STACK: %s..%s" % (formatAddress(stack[0]), formatAddress(stack[1]))) try: self._dumpStack() except PtraceError, err: error("Unable to read stack: %s" % err)
def dumpStack(self): stack = self.findStack() if stack: error("STACK: %s..%s" % ( formatAddress(stack[0]), formatAddress(stack[1]))) try: self._dumpStack() except PtraceError, err: error("Unable to read stack: %s" % err)
def display(self): if self.address is not None: if isinstance(self.address, (list, tuple)): address = " or ".join( formatAddress(addr) for addr in self.address ) else: address = formatAddress(self.address) message = self.prefix_addr % address else: message = self.prefix if self.text: message = "%s: %s" % (message, self.text) error(message)
def display(self): if self.address is not None: if isinstance(self.address, (list, tuple)): address = " or ".join( formatAddress(addr) for addr in self.address) else: address = formatAddress(self.address) message = self.prefix_addr % address else: message = self.prefix if self.text: message = "%s: %s" % (message, self.text) error(message)
def __init__(self, address, process=None): SignalInfo.__init__(self, "instr_error", "UNABLE TO EXECUTE CODE AT %s (SEGMENTATION FAULT)" % formatAddress( address), address=address, process=process, registers={'<instr pointer>': address})
def writeWord(self, address, word): """ Address have to be aligned! """ debug("Write word %s at %s" % ( formatWordHex(word), formatAddress(address))) ptrace_poketext(self.pid, address, word)
def readArray(self, address, basetype, count): debug("Read array %sx%s at %s" % ( basetype.__name__, count, formatAddress(address))) bytes = self.readBytes(address, sizeof(basetype)*count) if not CPU_64BITS: bytes = c_char_p(bytes) return cast(bytes, POINTER(basetype))
def readStruct(self, address, struct): debug("Read structure %s at %s" % ( struct.__name__, formatAddress(address))) bytes = self.readBytes(address, sizeof(struct)) if not CPU_64BITS: bytes = c_char_p(bytes) return cast(bytes, POINTER(struct))[0]
def _peek(command, pid, address): if address % CPU_WORD_SIZE: raise PtraceError( "ptrace can't read a word from an unaligned address (%s)!" % formatAddress(address), pid=pid) return ptrace(command, pid, address, check_errno=True)
def exit(self): if self.name in PREFORMAT_ARGUMENTS: preformat = set(PREFORMAT_ARGUMENTS[self.name]) else: preformat = set() # Data pointed by arguments may have changed during the syscall # eg. uname() syscall for index, argument in enumerate(self.arguments): if index in preformat: # Don't lose preformatted arguments continue if argument.type and not argument.type.endswith("*"): continue argument.text = None self.result = self.process.getreg(RETURN_VALUE_REGISTER) if self.restype.endswith("*"): text = formatAddress(self.result) else: uresult = self.result self.result = ulong2long(self.result) if self.result < 0: text = "%s %s (%s)" % ( self.result, errorcode[-self.result], strerror(-self.result)) elif not(0 <= self.result <= 9): text = "%s (%s)" % (self.result, formatWordHex(uresult)) else: text = str(self.result) self.result_text = text return text
def readStruct(self, address, struct): debug("Read structure %s at %s" % (struct.__name__, formatAddress(address))) bytes = self.readBytes(address, sizeof(struct)) if not CPU_64BITS: bytes = c_char_p(bytes) return cast(bytes, POINTER(struct))[0]
def _readBytes(self, address, size): debug("Read %s bytes at %s" % (size, formatAddress(address))) offset = address % CPU_WORD_SIZE if offset: # Read word address -= offset word = self.readWord(address) bytes = word2bytes(word) # Read some bytes from the word subsize = min(CPU_WORD_SIZE - offset, size) data = bytes[offset:offset+subsize] # <-- FIXME: Big endian! # Move cursor size -= subsize address += CPU_WORD_SIZE else: data = '' while size: # Read word word = self.readWord(address) bytes = word2bytes(word) # Read bytes from the word if size < CPU_WORD_SIZE: data += bytes[:size] # <-- FIXME: Big endian! break data += bytes # Move cursor size -= CPU_WORD_SIZE address += CPU_WORD_SIZE return data
def _poke(command, pid, address, word): if address % CPU_WORD_SIZE: raise PtraceError( "ptrace can't write a word to an unaligned address (%s)!" % formatAddress(address), pid=pid) ptrace(command, pid, address, word)
def step(self, enter_call, address=None): if address is None: self.displayInstr("Execute") if (not HAS_PTRACE_SINGLESTEP) or (not enter_call): if address is None: address = self.process.getInstrPointer() size = self.readInstrSize(address, default_size=None) if not size: return "Unable to read instruction size at %s" \ % formatAddress(address) address += size size = self.readInstrSize(address) # Set a breakpoint breakpoint = self.process.createBreakpoint(address, size) # Continue the process self.process.cont() else: # Use ptrace single step command self.process.singleStep() breakpoint = None # Execute processus until next TRAP try: self.process.waitSignals(SIGTRAP) if breakpoint: breakpoint.desinstall(set_ip=True) except: # noqa: E722 if breakpoint: breakpoint.desinstall() raise return None
def exit(self): if self.name in PREFORMAT_ARGUMENTS: preformat = set(PREFORMAT_ARGUMENTS[self.name]) else: preformat = set() # Data pointed by arguments may have changed during the syscall # e.g. uname() syscall for index, argument in enumerate(self.arguments): if index in preformat: # Don't lose preformatted arguments continue if argument.type and not argument.type.endswith("*"): continue argument.text = None self.result = self.process.getreg(RETURN_VALUE_REGISTER) if self.restype.endswith("*"): text = formatAddress(self.result) else: uresult = self.result self.result = ulong2long(self.result) if self.result < 0 and (-self.result) in errorcode: errcode = -self.result text = "%s %s (%s)" % ( self.result, errorcode[errcode], strerror(errcode)) elif not(0 <= self.result <= 9): text = "%s (%s)" % (self.result, formatWordHex(uresult)) else: text = str(self.result) self.result_text = text return text
def step(self, enter_call, address=None): if address is None: self.displayInstr("Execute") if (not HAS_PTRACE_SINGLESTEP) or (not enter_call): if address is None: address = self.process.getInstrPointer() size = self.readInstrSize(address, default_size=None) if not size: return "Unable to read instruction size at %s" \ % formatAddress(address) address += size size = self.readInstrSize(address) # Set a breakpoint breakpoint = self.process.createBreakpoint(address, size) # Continue the process self.process.cont() else: # Use ptrace single step command self.process.singleStep() breakpoint = None # Execute processus until next TRAP try: self.process.waitSignals(SIGTRAP) if breakpoint: breakpoint.desinstall(set_ip=True) except: if breakpoint: breakpoint.desinstall() raise return None
def readBytes(self, address, size): if not self.read_mem_file: filename = '/proc/%u/mem' % self.pid try: self.read_mem_file = open(filename, 'rb', 0) except IOError as err: message = "Unable to open %s: fallback to ptrace implementation" % filename if err.errno != EACCES: error(message) else: info(message) self.readBytes = self._readBytes return self.readBytes(address, size) try: mem = self.read_mem_file mem.seek(address) data = mem.read(size) except (IOError, ValueError) as err: raise ProcessError(self, "readBytes(%s, %s) error: %s" % ( formatAddress(address), size, err)) if len(data) == 0 and size: # Issue #10: If the process was not created by the debugger # (ex: fork), the kernel may deny reading private mappings of # /proc/pid/mem to the debugger, depending on the kernel # version and kernel config (ex: SELinux enabled or not). # # Fallback to PTRACE_PEEKTEXT. It is slower but a debugger # tracing the process is always allowed to use it. self.readBytes = self._readBytes return self.readBytes(address, size) return data
def readArray(self, address, basetype, count): debug("Read array %sx%s at %s" % (basetype.__name__, count, formatAddress(address))) bytes = self.readBytes(address, sizeof(basetype) * count) if not CPU_64BITS: bytes = c_char_p(bytes) return cast(bytes, POINTER(basetype))
def readBytes(self, address, size): if not self.read_mem_file: filename = '/proc/%u/mem' % self.pid try: self.read_mem_file = open(filename, 'rb', 0) except IOError as err: message = "Unable to open %s: fallback to ptrace implementation" % filename if err.errno != EACCES: warning(message) else: info(message) self.readBytes = self._readBytes return self.readBytes(address, size) try: mem = self.read_mem_file mem.seek(address) data = mem.read(size) except (IOError, ValueError) as err: raise ProcessError( self, "readBytes(%s, %s) error: %s" % (formatAddress(address), size, err)) if len(data) == 0 and size: # Issue #10: If the process was not created by the debugger # (ex: fork), the kernel may deny reading private mappings of # /proc/pid/mem to the debugger, depending on the kernel # version and kernel config (ex: SELinux enabled or not). # # Fallback to PTRACE_PEEKTEXT. It is slower but a debugger # tracing the process is always allowed to use it. self.readBytes = self._readBytes return self.readBytes(address, size) return data
def writeWord(self, address, word): """ Address have to be aligned! """ debug("Write word %s at %s" % (formatWordHex(word), formatAddress(address))) ptrace_poketext(self.pid, address, word)
def _readBytes(self, address, size): debug("Read %s bytes at %s" % (size, formatAddress(address))) offset = address % CPU_WORD_SIZE if offset: # Read word address -= offset word = self.readWord(address) bytes = word2bytes(word) # Read some bytes from the word subsize = min(CPU_WORD_SIZE - offset, size) data = bytes[offset:offset + subsize] # <-- FIXME: Big endian! # Move cursor size -= subsize address += CPU_WORD_SIZE else: data = '' while size: # Read word word = self.readWord(address) bytes = word2bytes(word) # Read bytes from the word if size < CPU_WORD_SIZE: data += bytes[:size] # <-- FIXME: Big endian! break data += bytes # Move cursor size -= CPU_WORD_SIZE address += CPU_WORD_SIZE return data
def createText(self): value = self.value argtype = self.type name = self.name if not argtype or not name: return formatWordHex(self.value) syscall = self.function.name # Special cases try: return SYSCALL_ARG_DICT[syscall][name][value] except KeyError: pass try: callback = ARGUMENT_CALLBACK[syscall][name] except KeyError: callback = None if callback: return callback(value) if syscall == "execve": if name in ("argv", "envp"): return self.readCStringArray(value) if syscall == "socketcall": if name == "call": try: return SOCKETCALL[value][0] except KeyError: return str(value) if name == "args": func_call = FunctionCall("socketcall", self.options) setupSocketCall(func_call, self.function.process, self.function[0], self.value) text = "<%s>" % func_call.format() return self.formatPointer(text, self.value) if syscall == "write" and name == "buf": fd = self.function[0].value if fd < 3: length = self.function[2].value return self.readString(value, length) if name == "signum": return signalName(value) if name in FILENAME_ARGUMENTS: return self.readCString(value) # Remove "const " prefix if argtype.startswith("const "): argtype = argtype[6:] # Format depending on the type if argtype.endswith("*"): try: text = self.formatValuePointer(argtype[:-1]) if text: return text except PTRACE_ERRORS, err: writeError(getLogger(), err, "Format argument value error") value = None return formatAddress(self.value)
def _dumpCode(self, start, stop, ip, manage_bp, log): if stop is not None: stop = max(start, stop) stop = min(stop, start + MAX_CODE_SIZE - 1) if not HAS_DISASSEMBLER: if stop is not None: size = stop - start + 1 else: size = MIN_CODE_SIZE code = self.readBytes(start, size) if RUNNING_PYTHON3: text = " ".join("%02x" % byte for byte in code) else: text = " ".join("%02x" % ord(byte) for byte in code) log("CODE: %s" % text) return log("CODE:") if manage_bp: address = start for line in range(10): bp = False if address in self.breakpoints: bytes = self.breakpoints[address].old_bytes instr = disassembleOne(bytes, address) bp = True else: instr = self.disassembleOne(address) text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" if bp: text += " * BREAKPOINT *" log(text) address = address + instr.size if stop is not None and stop <= address: break else: for instr in self.disassemble(start, stop): text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" log(text)
def _dumpCode(self, start, stop, ip, manage_bp, log): if stop is not None: stop = max(start, stop) stop = min(stop, start + MAX_CODE_SIZE - 1) if not HAS_DISASSEMBLER: if stop is not None: size = stop - start + 1 else: size = MIN_CODE_SIZE code = self.readBytes(start, size) if RUNNING_PYTHON3: text = " ".join("%02x" % byte for byte in code) else: text = " ".join("%02x" % ord(byte) for byte in code) log("CODE: %s" % text) return if manage_bp: address = start for line in range(10): bp = False if address in self.breakpoints: bytes = self.breakpoints[address].old_bytes instr = disassembleOne(bytes, address) bp = True else: instr = self.disassembleOne(address) text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" if bp: text += " * BREAKPOINT *" log(text) address = address + instr.size if stop is not None and stop <= address: break else: for instr in self.disassemble(start, stop): text = "%s| %s (%s)" % (formatAddress( instr.address), instr.text, instr.hexa) if instr.address == ip: text += " <==" log(text)
def readBytes(self, address, size): debug("Read %s bytes at %s" % (size, formatAddress(address))) buffer = create_string_buffer(size) io_desc = ptrace_io_desc(piod_op=PIOD_READ_D, piod_offs=address, piod_addr=addressof(buffer), piod_len=size) ptrace_io(self.pid, io_desc) return buffer.raw
def writeBytes(self, address, bytes): size = len(bytes) debug("Write %s bytes at %s" % (size, formatAddress(address))) bytes = create_string_buffer(bytes) io_desc = ptrace_io_desc(piod_op=PIOD_WRITE_D, piod_offs=address, piod_addr=addressof(bytes), piod_len=size) ptrace_io(self.pid, io_desc)
def displayInstr(self, prefix): try: if HAS_DISASSEMBLER: instr = self.process.disassembleOne() error("%s %s: %s" % ( prefix, formatAddress(instr.address), instr.text)) else: self.process.dumpCode() except PtraceError as err: error("Unable to read current instruction: %s" % err)
def readBytes(self, address, size): debug("Read %s bytes at %s" % (size, formatAddress(address))) buffer = create_string_buffer(size) io_desc = ptrace_io_desc( piod_op=PIOD_READ_D, piod_offs=address, piod_addr=addressof(buffer), piod_len=size) ptrace_io(self.pid, io_desc) return buffer.raw
def __init__(self, address=None, size=None, instr=None, registers=None, process=None): """ address is an integer or a list of integer """ if address is not None: if isinstance(address, (list, tuple)): arguments = " or ".join(formatAddress(addr) for addr in address) else: arguments = formatAddress(address) message = self.PREFIX_ADDR % arguments else: message = self.PREFIX if size: message += " (size=%s bytes)" % size name = self.NAME if address is not None: name += "-" + formatAddress(address).lower() SignalInfo.__init__( self, name, message, address=address, size=size, instr=instr, process=process, registers=registers )
def readInstrSize(self, address, default_size=None): if not HAS_DISASSEMBLER: return default_size try: # Get address and size of instruction at specified address instr = self.process.disassembleOne(address) return instr.size except PtraceError as err: warning("Warning: Unable to read instruction size at %s: %s" % ( formatAddress(address), err)) return default_size
def breakpoint(self, address): # Create breakpoint size = self.readInstrSize(address) try: bp = self.process.createBreakpoint(address, size) except PtraceError as err: return "Unable to set breakpoint at %s: %s" % ( formatAddress(address), err) #error("New breakpoint: %s" % bp) return None
def readInstrSize(self, address, default_size=None): if not HAS_DISASSEMBLER: return default_size try: # Get address and size of instruction at specified address instr = self.process.disassembleOne(address) return instr.size except PtraceError as err: warning("Warning: Unable to read instruction size at %s: %s" % (formatAddress(address), err)) return default_size
def writeBytes(self, address, bytes): size = len(bytes) debug("Write %s bytes at %s" % ( size, formatAddress(address))) bytes = create_string_buffer(bytes) io_desc = ptrace_io_desc( piod_op=PIOD_WRITE_D, piod_offs=address, piod_addr=addressof(bytes), piod_len=size) ptrace_io(self.pid, io_desc)
def delete(self, command): try: address = self.parseInteger(command) except ValueError as err: return str(err) breakpoint = self.process.findBreakpoint(address) if not breakpoint: return "No breakpoint at %s " % formatAddress(address) breakpoint.desinstall() error("%s deleted" % breakpoint) return None
def displaySyscall(self, syscall): text = syscall.format() if syscall.result is not None: text = "%-40s = %s" % (text, syscall.result_text) prefix = [] if self.options.show_pid: prefix.append("[%s]" % syscall.process.pid) if self.options.show_ip: prefix.append("[%s]" % formatAddress(syscall.instr_pointer)) if prefix: text = ''.join(prefix) + ' ' + text error(text)
def _dumpStack(self, log): sp = self.getStackPointer() displayed = 0 for index in range(-5, 5 + 1): delta = index * CPU_WORD_SIZE try: value = self.readWord(sp + delta) log("STACK%+ 3i: %s" % (delta, formatWordHex(value))) displayed += 1 except PtraceError: pass if not displayed: log("ERROR: unable to read the stack (SP=%s)" % formatAddress(sp))
def getText(self): if not self.text: try: text = self.createText() if text is not None: self.text = str(text) elif self.type and self.type.endswith("*"): self.text = formatAddress(self.value) else: self.text = repr(self.value) except PTRACE_ERRORS, err: writeError(getLogger(), err, "Format argument value error") self.text = repr(self.value)
def _dumpStack(self): sp = self.getStackPointer() displayed = 0 for index in xrange(-5, 5 + 1): delta = index * CPU_WORD_SIZE try: value = self.readWord(sp + delta) error("STACK%+ 3i: %s" % (delta, formatWordHex(value))) displayed += 1 except PtraceError: pass if not displayed: error("ERROR: unable to read stack (%s)" % formatAddress(sp))
def findMappings(addresses, process, size): mappings = [] if addresses is None or not process: return mappings if not isinstance(addresses, (list, tuple)): addresses = (addresses,) if not size: size = 0 process_mappings = process.readMappings() if not process_mappings: return mappings for address in addresses: address_str = formatAddress(address) if 1 < size: address_str += "..%s" % formatAddress(address + size - 1) found = False for map in process_mappings: if (map.start <= address < map.end) or (map.start <= (address + size - 1) < map.end): found = True mappings.append("%s is part of %s" % (address_str, map)) if not found: mappings.append("%s is not mapped in memory" % address_str) return mappings
def breakpoint(self, command): try: address = self.parseInteger(command) except ValueError as err: return str(err) # Create breakpoint size = self.readInstrSize(address) try: bp = self.process.createBreakpoint(address, size) except PtraceError as err: return "Unable to set breakpoint at %s: %s" % ( formatAddress(address), err) error("New breakpoint: %s" % bp) return None
def readBytes(self, address, size): debug("Read %s bytes at %s" % (size, formatAddress(address))) if not self.read_mem_file: filename = '/proc/%u/mem' % self.pid try: self.read_mem_file = open(filename, 'rb', 0) except IOError, err: message = "Unable to open %s: fallback to ptrace implementation" % filename if err.errno != EACCES: error(message) else: info(message) self.readBytes = self._readBytes return self.readBytes(address, size)
def findMappings(addresses, process, size): mappings = [] if addresses is None or not process: return mappings if not isinstance(addresses, (list, tuple)): addresses = (addresses, ) if not size: size = 0 process_mappings = process.readMappings() if not process_mappings: return mappings for address in addresses: address_str = formatAddress(address) if 1 < size: address_str += "..%s" % formatAddress(address + size - 1) found = False for map in process_mappings: if (map.start <= address < map.end) \ or (map.start <= (address + size - 1) < map.end): found = True mappings.append("%s is part of %s" % (address_str, map)) if not found: mappings.append("%s is not mapped in memory" % address_str) return mappings
def getText(self): if not self.text: try: text = self.createText() if text is not None: self.text = str(text) elif self.type and self.type.endswith("*"): self.text = formatAddress(self.value) else: self.text = repr(self.value) except PTRACE_ERRORS as err: writeError(getLogger(), err, "Format argument %s of function %s() value error" % (self.name, self.function.name)) self.text = repr(self.value) return self.text
def dumpCode(self, start=None, stop=None, manage_bp=False, log=None): if not log: log = error try: ip = self.getInstrPointer() except PtraceError as err: if start is None: log("Unable to read instruction pointer: %s" % err) return ip = None if start is None: start = ip try: self._dumpCode(start, stop, ip, manage_bp, log) except PtraceError as err: log("Unable to dump code at %s: %s" % (formatAddress(start), err))
def dumpCode(self, start=None, stop=None, manage_bp=False, log=None): if not log: log = error try: ip = self.getInstrPointer() except PtraceError as err: if start is None: log("Unable to read instruction pointer: %s" % err) return ip = None if start is None: start = ip try: self._dumpCode(start, stop, ip, manage_bp, log) except PtraceError as err: log("Unable to dump code at %s: %s" % ( formatAddress(start), err))
def exit(self): if self.name in PREFORMAT_ARGUMENTS: preformat = set(PREFORMAT_ARGUMENTS[self.name]) else: preformat = set() # Data pointed by arguments may have changed during the syscall # eg. uname() syscall for index, argument in enumerate(self.arguments): if index in preformat: # Don't lose preformatted arguments continue if argument.type and not argument.type.endswith("*"): continue argument.text = None if CPU_ARM: regname = "r0" elif CPU_I386: regname = "eax" elif CPU_X86_64: regname = "rax" elif CPU_POWERPC: regname = "result" else: raise NotImplementedError() self.result = self.process.getreg(regname) if self.restype.endswith("*"): text = formatAddress(self.result) else: uresult = self.result self.result = ulong2long(self.result) if self.result < 0: text = "%s (%s)" % ( self.result, strerror(-self.result)) elif not(0 <= self.result <= 9): text = "%s (%s)" % (self.result, formatWordHex(uresult)) else: text = str(self.result) self.result_text = text return text