[docs]classGymratLifter(Lifter):""" This is a base class for lifters that use Gymrat. For most architectures, all you need to do is subclass this, and set the property "instructions" to be a list of classes that define each instruction. By default, a lifter will decode instructions by attempting to instantiate every class until one works. This will use an IRSBCustomizer, which will, if it succeeds, add the appropriate VEX instructions to a pyvex IRSB. pyvex, when lifting a block of code for this architecture, will call the method "lift", which will produce the IRSB of the lifted code. """__slots__=("bitstrm","errors","thedata","disassembly",)REQUIRE_DATA_PY=Trueinstrs:list[type["Instruction"]]
def_decode_next_instruction(self,addr):# Try every instruction until one worksforpossible_instrinself.instrs:try:log.debug("Trying %s",possible_instr.name)returnpossible_instr(self.bitstrm,self.irsb.arch,addr)# a ParserError signals that this instruction did not match# we need to try other instructions, so we ignore this errorexceptParseError:pass# l.exception(repr(possible_instr))# if we are out of input, ignore.# there may be other, shorter instructions that still match,# so we continue with the loopexcept(bitstring.ReadError,bitstring.InterpretError):pass# If no instruction matches, log an errorerrorstr="Unknown instruction at bit position %d"%self.bitstrm.bitposlog.debug(errorstr)log.debug("Address: %#08x"%addr)
[docs]defdecode(self):try:self.create_bitstrm()count=0disas=[]addr=self.irsb.addrlog.debug("Starting block at address: "+hex(addr))bytepos=self.bitstrm.byteposwhilenotis_empty(self.bitstrm):instr=self._decode_next_instruction(addr)ifnotinstr:breakdisas.append(instr)log.debug("Matched "+instr.name)addr+=self.bitstrm.bytepos-byteposbytepos=self.bitstrm.byteposcount+=1returndisasexceptExceptionase:self.errors=str(e)log.exception(f"Error decoding block at offset {bytepos:#x} (address {addr:#x}):")raise
def_lift(self):self.thedata=(self.data[:self.max_bytes]ifisinstance(self.data,(bytes,bytearray,memoryview))elseself.data[:self.max_bytes].encode())log.debug(repr(self.thedata))instructions=self.decode()ifself.disasm:self.disassembly=[instr.disassemble()forinstrininstructions]self.irsb.jumpkind=JumpKind.Invalidirsb_c=IRSBCustomizer(self.irsb)log.debug("Decoding complete.")fori,instrinenumerate(instructions[:self.max_inst]):log.debug("Lifting instruction %s",instr.name)instr(irsb_c,instructions[:i],instructions[i+1:])ifirsb_c.irsb.jumpkind!=JumpKind.Invalid:breakif(i+1)==self.max_inst:# if we are on our last iterationinstr.jump(None,irsb_c.irsb.addr+irsb_c.irsb.size)breakelse:iflen(irsb_c.irsb.statements)==0:raiseLiftingException("Could not decode any instructions")irsb_c.irsb.jumpkind=JumpKind.NoDecodedst=irsb_c.irsb.addr+irsb_c.irsb.sizedst_ty=vex_int_class(irsb_c.irsb.arch.bits).typeirsb_c.irsb.next=irsb_c.mkconst(dst,dst_ty)log.debug(str(self.irsb))ifself.dump_irsb:self.irsb.pp()returnself.irsb