| 64 | |
| 65 | |
| 66 | def parse_instr(code_str, base_str, arch): |
| 67 | code = bytes.fromhex(code_str) |
| 68 | base = int(base_str, 16) |
| 69 | base &= ~1 |
| 70 | |
| 71 | if arch == 'arm64': |
| 72 | md = Cs(CS_ARCH_ARM64, CS_MODE_ARM) |
| 73 | ptr_size = 8 |
| 74 | addr_width = 16 |
| 75 | hex_col = 16 |
| 76 | data_dir = ".quad" |
| 77 | elif arch == 'arm': |
| 78 | md = Cs(CS_ARCH_ARM, CS_MODE_ARM) |
| 79 | ptr_size = 4 |
| 80 | addr_width = 8 |
| 81 | hex_col = 8 |
| 82 | data_dir = ".word" |
| 83 | elif arch == 'thumb': |
| 84 | md = Cs(CS_ARCH_ARM, CS_MODE_THUMB) |
| 85 | ptr_size = 4 |
| 86 | addr_width = 8 |
| 87 | hex_col = 8 |
| 88 | data_dir = ".word" |
| 89 | else: |
| 90 | raise ValueError(f"Unsupported architecture: {arch}") |
| 91 | |
| 92 | md.detail = True |
| 93 | md.skipdata = True |
| 94 | |
| 95 | literal_addrs = set() |
| 96 | for insn in md.disasm(code, base): |
| 97 | if arch == 'arm64': |
| 98 | # ARM64 LDR literal: second operand is an immediate (absolute addr) |
| 99 | if insn.id == ARM64_INS_LDR: |
| 100 | ops = insn.operands |
| 101 | if len(ops) == 2 and ops[1].type == ARM64_OP_IMM: |
| 102 | target = ops[1].imm |
| 103 | literal_addrs.add(target) |
| 104 | else: # arm / thumb |
| 105 | # ARM/Thumb LDR literal: second operand is [PC, #disp] |
| 106 | if insn.id == ARM_INS_LDR: |
| 107 | ops = insn.operands |
| 108 | if len(ops) == 2 and ops[1].type == ARM_OP_MEM: |
| 109 | mem = ops[1].mem |
| 110 | if mem.base == ARM_REG_PC and mem.index == ARM_REG_INVALID: |
| 111 | if arch == 'thumb': |
| 112 | # Thumb: PC = Align(insn_addr + 4, 4) |
| 113 | pc_val = (insn.address + 4) & ~3 |
| 114 | else: |
| 115 | # ARM: PC = insn_addr + 8 |
| 116 | pc_val = insn.address + 8 |
| 117 | disp = mem.disp |
| 118 | # capstone may expose an unsigned disp + subtracted flag |
| 119 | if getattr(ops[1], 'subtracted', False): |
| 120 | disp = -disp |
| 121 | literal_addrs.add(pc_val + disp) |
| 122 | |
| 123 | offset = 0 |