def __cs_translate_operand(self, cs_op, cs_insn): if cs_op.type == ARM_OP_REG: reg = self.__cs_reg_idx_to_arm_op_reg(cs_op.value.reg, cs_insn) if cs_op.shift.type > 0: oprnd = self.__cs_shift_to_arm_op(cs_op, cs_insn, reg) else: oprnd = reg elif cs_op.type == ARM_OP_IMM: oprnd = ArmImmediateOperand(cs_op.value.imm, self._arch_info.operand_size) elif cs_op.type == ARM_OP_MEM: reg_base = self.__cs_reg_idx_to_arm_op_reg(cs_op.mem.base, cs_insn) # TODO: memory index type index_type = ARM_MEMORY_INDEX_OFFSET if cs_op.mem.index > 0: if cs_op.mem.disp > 0: raise Exception( "ARM_OP_MEM: Both index and disp > 0, only one can be." ) displacement = self.__cs_reg_idx_to_arm_op_reg( cs_op.mem.index, cs_insn) # NOTE: In the case of a memory operand, in the second # position (slot [1]), the information regarding whether # or not the displacement of the operand has a shifted # register is encoded in the first operand (slot [0]), # that doesn't have a direct relation with the other. # TODO: Check if this has to be reported to CS. if cs_insn.operands[0].shift.type > 0: # There's a shift operation, the displacement extracted # earlier was just the base register of the shifted # register that is generating the displacement. displacement = self.__cs_shift_to_arm_op( cs_insn.operands[0], cs_insn, displacement) else: displacement = ArmImmediateOperand( cs_op.mem.disp, self._arch_info.operand_size) disp_minus = True if cs_op.mem.index == -1 else False oprnd = ArmMemoryOperand(reg_base, index_type, displacement, disp_minus, self._arch_info.operand_size) else: error_msg = "Instruction: " + cs_insn.mnemonic + " " + cs_insn.op_str + ". Unknown operand type: " + str( cs_op.type) logger.error(error_msg) raise CapstoneOperandNotSupported(error_msg) return oprnd
def process_shifted_register(tokens): base = process_register(tokens["base"]) sh_type = tokens["type"] amount = tokens.get("amount", None) if amount: if "imm" in amount: amount = ArmImmediateOperand("".join(amount["imm"]), arch_info.operand_size) elif "reg" in amount: amount = process_register(amount["reg"]) else: raise Exception("Unknown amount type.") return ArmShiftedRegisterOperand(base, sh_type, amount, base.size)
def __cs_shift_to_arm_op(self, cs_op, cs_insn, arm_base): if cs_op.shift.type == 0: raise Exception("Invalid shift type.") cs_shift_mapper = { ARM_SFT_ASR: "asr", ARM_SFT_LSL: "lsl", ARM_SFT_LSR: "lsr", ARM_SFT_ROR: "ror", ARM_SFT_RRX: "rrx", ARM_SFT_ASR_REG: "asr", ARM_SFT_LSL_REG: "lsl", ARM_SFT_LSR_REG: "lsr", ARM_SFT_ROR_REG: "ror", ARM_SFT_RRX_REG: "rrx", } # The base register (arm_base) is not included in the shift # struct in Capstone, so it's provided separately. sh_type = cs_shift_mapper[cs_op.shift.type] if cs_op.shift.type <= ARM_SFT_RRX: amount = ArmImmediateOperand(cs_op.shift.value, self._arch_info.operand_size) # TODO: check if this is a valid case. if cs_op.shift.value == 0: raise Exception("Shift value is zero.") elif cs_op.shift.type <= ARM_SFT_RRX_REG: amount = self.__cs_reg_idx_to_arm_op_reg(cs_op.shift.value, cs_insn) else: raise Exception("Unknown shift type.") return ArmShiftedRegisterOperand(arm_base, sh_type, amount, arm_base.size)
def parse_operand(string, location, tokens): """Parse an ARM instruction operand. """ if "immediate_operand" in tokens: size = arch_info.operand_size oprnd = ArmImmediateOperand("".join(tokens["immediate_operand"]), size) if "register_operand" in tokens: oprnd = process_register(tokens["register_operand"]) # TODO: Figure out where to really store this flag, instead of in the register class if "wb" in tokens["register_operand"]: oprnd.wb = True if "memory_operand" in tokens: mem_oprnd = tokens["memory_operand"] if "offset" in mem_oprnd: index_type = ARM_MEMORY_INDEX_OFFSET mem_oprnd = mem_oprnd["offset"] elif "pre" in mem_oprnd: index_type = ARM_MEMORY_INDEX_PRE mem_oprnd = mem_oprnd["pre"] elif "post" in mem_oprnd: index_type = ARM_MEMORY_INDEX_POST mem_oprnd = mem_oprnd["post"] else: raise Exception("Unknown index type.") reg_base = process_register(mem_oprnd["base"]) disp = mem_oprnd.get("disp", None) disp_minus = True if mem_oprnd.get("minus") else False if disp: if "shift" in disp: displ_imm = process_shifted_register(disp["shift"]) elif "reg" in disp: displ_imm = process_register(disp["reg"]) elif "imm" in disp: displ_imm = ArmImmediateOperand("".join(disp["imm"]), arch_info.operand_size) else: raise Exception("Unknown displacement type.") else: displ_imm = None size = arch_info.operand_size # TODO: Add sizes for LDR/STR variations (half word, byte, double word) oprnd = ArmMemoryOperand(reg_base, index_type, displ_imm, disp_minus, size) if "shifted_register" in tokens: oprnd = process_shifted_register(tokens["shifted_register"]) if "register_list_operand" in tokens: parsed_reg_list = tokens["register_list_operand"] reg_list = [] for reg_range in parsed_reg_list: start_reg = process_register(reg_range[0]) if len(reg_range) > 1: end_reg = process_register(reg_range[1]) reg_list.append([start_reg, end_reg]) else: reg_list.append([start_reg]) oprnd = ArmRegisterListOperand(reg_list, reg_list[0][0].size) return oprnd