def swap(il, addr, distance): stack_offset = distance * ADDR_SIZE load = il.load( ADDR_SIZE, il.add(ADDR_SIZE, il.reg(ADDR_SIZE, 'sp'), il.const(ADDR_SIZE, stack_offset))) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(0), load)) il.append( il.set_reg(ADDR_SIZE, LLIL_TEMP(1), il.load(ADDR_SIZE, il.reg(ADDR_SIZE, 'sp')))) il.append( il.store( ADDR_SIZE, il.add(ADDR_SIZE, il.reg(ADDR_SIZE, 'sp'), il.const(ADDR_SIZE, stack_offset)), il.reg(ADDR_SIZE, LLIL_TEMP(1)))) il.append( il.store(ADDR_SIZE, il.reg(ADDR_SIZE, 'sp'), il.reg(ADDR_SIZE, LLIL_TEMP(0)))) return []
def do_il(self, data, addr, il): src = SourceOperandsIL[self.flag](il, self.src_value) return [ il.set_reg(2, LLIL_TEMP(0), src), il.set_reg(2, Registers[self.src_value], il.reg(2, Registers[self.dst_value])), il.set_reg(2, Registers[self.dst_value], il.reg(2, LLIL_TEMP(0))) ]
def mstore(il, addr, imm): il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(0), il.pop(ADDR_SIZE))) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(1), il.pop(ADDR_SIZE))) # il.append( # il.store( # ADDR_SIZE, # il.unimplemented(), # il.reg(ADDR_SIZE, LLIL_TEMP(1)) # ) # ) return []
def dup(il, addr, distance): il.append( il.set_reg( ADDR_SIZE, LLIL_TEMP(0), il.load( ADDR_SIZE, il.add(ADDR_SIZE, il.reg(ADDR_SIZE, 'sp'), il.const(ADDR_SIZE, (distance - 1) * ADDR_SIZE))))) il.append(il.push(ADDR_SIZE, il.reg(ADDR_SIZE, LLIL_TEMP(0)))) return []
def exp_inst(il, addr, imm): base = il.pop(ADDR_SIZE) exponent = il.pop(ADDR_SIZE) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(0), base)) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(1), exponent)) if ('value' in dir(base) and 'value' in dir(exponent) and base.value.is_constant and exponent.value.is_constant): result = base.value.value**exponent.value.value il.append(il.push(ADDR_SIZE, il.const(ADDR_SIZE, result))) else: il.append(il.push(ADDR_SIZE, il.unimplemented())) il.append(il.nop()) return []
def jalr(self, il, op, imm, inst_size=4): if len(op) < 2: ret_adr = 'ra' base = op[0] else: ret_adr = op[0] base = op[1] # ret_addr => register where the return address is written to # base => call target (+ imm value) # copy base register to temp (needed in case base == ret_adr) il.append( il.set_reg(self.addr_size, LLIL_TEMP(0), il.reg(self.addr_size, base))) base = il.reg(self.addr_size, LLIL_TEMP(0)) # the zero register acts as a sink-hole for data, any write to it is # ignored, so we can just omit lifting this to LLIL altogether. if ret_adr != 'zero': # compute return address and store to ret_addr register il.append( il.set_reg( self.addr_size, ret_adr, il.const(self.addr_size, il.current_address + inst_size))) # compute the jump target dest = base if imm: il.append( il.set_reg( self.addr_size, LLIL_TEMP(0), il.add(self.addr_size, base, il.const(self.addr_size, imm)))) dest = il.reg(self.addr_size, LLIL_TEMP(0)) if ret_adr == 'zero': if base == 'ra' and not imm: # jalr zero, ra, 0 => jump to return address, but link address # is discarded into zero register => basically a JR ra => "ret" il.append(il.ret(dest)) else: # if ret_adr == zero, but base != ra then we basically have a # normal jump instead of a function call il.append(il.jump(dest)) else: il.append(il.call(dest))
def get_instruction_low_level_il(self, data, addr, il): instruction = disassemble_one(data, addr) ill = insn_il.get(instruction.name, None) if ill is None: for i in range(instruction.pops): il.append( il.set_reg(ADDR_SIZE, LLIL_TEMP(i), il.pop(ADDR_SIZE)) ) for i in range(instruction.pushes): il.append(il.push(ADDR_SIZE, il.unimplemented())) il.append(il.nop()) return instruction.size ils = ill(il, addr, instruction.operand) if isinstance(ils, list): for i in ils: il.append(il) else: il.append(ils) return instruction.size
def jumpi(il, addr, imm): dest = il.pop(ADDR_SIZE) if len(il) > 0: push = il[len(il)-1] else: push = None if (push is not None and push.operation == LowLevelILOperation.LLIL_PUSH and push.src.operation == LowLevelILOperation.LLIL_CONST): dest = il.const(ADDR_SIZE, push.src.constant) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(1), il.pop(ADDR_SIZE))) else: il.append(dest) t = LowLevelILLabel() f = il.get_label_for_address(Architecture['EVM'], addr+1) must_mark = False if f is None: f = LowLevelILLabel() must_mark = True # We need to use a temporary register here. The il.if_expr() helper # function makes a tree and evaluates the condition's il.pop() # first, but dest needs to be first. #il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(addr), dest)) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(0), il.pop(ADDR_SIZE))) il.append(il.if_expr(il.reg(ADDR_SIZE, LLIL_TEMP(0)), t, f)) il.mark_label(t) il.append(il.jump(il.unimplemented())) # il.reg(ADDR_SIZE, LLIL_TEMP(1)))) if must_mark: il.mark_label(f) # false is the fall through case il.append(il.jump(il.const(ADDR_SIZE, addr + 1))) return []
def jump(il, addr, imm): dest = il.pop(ADDR_SIZE) if len(il) > 0: push = il[len(il) - 1] else: push = None if (push is not None and push.operation == LowLevelILOperation.LLIL_PUSH and push.src.operation == LowLevelILOperation.LLIL_CONST): dest = il.const(ADDR_SIZE, push.src.constant) il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(0), il.pop(ADDR_SIZE))) # We need to use a temporary register here. The il.if_expr() helper # function makes a tree and evaluates the condition's il.pop() # first, but dest needs to be first. il.append(il.set_reg(ADDR_SIZE, LLIL_TEMP(addr), dest)) il.append(il.jump(il.reg(ADDR_SIZE, LLIL_TEMP(addr)))) return []
def call(il, src_op, src, src_value): if src_op == INDIRECT_AUTOINCREMENT_MODE: # autoincrement mode is special in that prior to making the call, # the register needs to be incremented. This requires a temp register, # so that the original value of the register can be preserved while # the register is incremented prior to actually making the call. temp_expr = il.set_reg(2, LLIL_TEMP(0), il.reg(2, src)) call_expr = il.call(il.load(2, il.reg(2, LLIL_TEMP(0)))) inc_expr = il.set_reg(2, src, il.add(2, il.reg(2, src), il.const(2, 2))) il.append(temp_expr) il.append(inc_expr) elif src_op == IMMEDIATE_MODE: call_expr = il.call(il.const_pointer(2, src_value)) else: call_expr = il.call(SourceOperandsIL[src_op](il, 2, src, src_value)) il.append(call_expr)
def get_instruction_low_level_il(self, data, addr, il): big_reg = LLIL_TEMP(il.temp_reg_count) big_reg_expr = il.set_reg(8, big_reg, il.add(8, il.reg(4, GPR[self.t]), il.shift_left(8, il.reg(4, GPR[self.s]), il.const(4, 32)))) il.append(il.set_reg(4, GPR[self.r], il.logical_shift_right(4, big_reg_expr, il.reg(4, "sar")))) return self.length