Source code for revenge.cpu.assembly.instruction


import logging
logger = logging.getLogger(__name__)

import re
from termcolor import cprint, colored
from prettytable import PrettyTable

[docs]class AssemblyBlock(object): """Represents an assembly block.""" def __init__(self, process, address): self._process = process self.instructions = [] self.address = address self._parse_block() def _parse_block(self): address = self.address end_block = ['ret', 'call', 'branch_relative'] while True: self.instructions.append(AssemblyInstruction(self._process, address)) for ender in end_block: if ender in self.instructions[-1].groups: return address = self.instructions[-1].address_next def __getitem__(self, item): return self.instructions[item] def __str__(self): s = [] for i in self.instructions: s.append(str(i)) return '\n'.join(s) def __repr__(self): attrs = ['AssemblyBlock', str(len(self.instructions)), 'instructions'] return '<' + ' '.join(attrs) + '>'
[docs]class AssemblyInstruction(object): """Represents an assembly instruction.""" def __init__(self, process, address=None): """ Args: process: Process object address (int, optional): Address for this instruction. Will load from this address. """ self._process = process self.address = address
[docs] @classmethod def from_frida_dict(klass, process, d): """Builds this assembly instruction from a frida dictionary, ala Instruction.parse()""" instruction = klass(process) instruction._parse_instruction(d) return instruction
def _parse_instruction(self, inst): """Given an instruction dict as returned from Frida, parse it into this object.""" self.__address = types.Pointer(common.auto_int(inst['address'])) self.__address_next = types.Pointer(common.auto_int(inst['next'])) self.__size = inst['size'] self.__mnemonic = inst['mnemonic'] self.__args_str = inst['opStr'] self.__operands = inst['operands'] self.__registers_read = inst['regsRead'] self.__registers_written = inst['regsWritten'] self.__groups = inst['groups'] def _load_from_address(self): inst = self._process.engine.run_script_generic("""send(Instruction.parse({}));""".format(self.address.js), raw=True, unload=True)[0][0] self._parse_instruction(inst) def __str__(self): return "{address} {mnemonic: <20}{args}".format( address=colored(hex(self.address), attrs=['bold']) + ":", mnemonic=colored(self.mnemonic, "cyan"), args=colored(self.args_str_resolved, "cyan", attrs=['bold']), ) def __repr__(self): attrs = ['AssemblyInstruction', hex(self.address), self.mnemonic, self.args_str] return '<' + ' '.join(attrs) + '>' def __hash__(self): return hash((self.address, self.args_str)) @property def args_str_resolved(self): """str: Attempt to resolve addresses in the args str into symbols.""" s = self.args_str things = re.findall('0x[0-9a-f]+', s) for thing in things: sym = self._process.modules.lookup_symbol(int(thing,16)) if sym is not None: s = s.replace(thing, str(sym)) return s @property def groups(self): """list: List of descriptive groups that this instruction belongs to.""" return self.__groups @property def registers_written(self): """list: List of registers written by this instruction.""" return self.__registers_written @property def registers_read(self): """list: List of registers that are read by this instruction.""" return self.__registers_read @property def operands(self): """list: List of operands.""" return self.__operands @property def args_str(self): """str: Operation arguments as a string.""" return self.__args_str @property def mnemonic(self): """str: Operation mnemonic.""" return self.__mnemonic @property def size(self): """int: Size of this instruction in bytes.""" return self.__size @property def address_next(self): """Pointer: Address of instruction following this one.""" return self.__address_next @property def address(self): """Pointer: Address where this instruction is located.""" return self.__address @address.setter def address(self, address): if address is None: self.__address = None return self.__address = types.Pointer(common.auto_int(address)) self._load_from_address()
from ... import types, common