1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
| from capstone import * from capstone.x86 import * from capstone.x86_const import *
buf = open('runofthemill', 'rb').read() code = buf[0x1054:0x117F7]
cs = Cs(CS_ARCH_X86, CS_MODE_64) cs.imm_unsigned = True cs.detail = True
def all_insns(): it = cs.disasm(code, 0x401054) return it
def is_buffer_addr(addr): return 0x412000 <= addr < 0x412040
def buffer_off(op): return op.mem.disp - 0x412000
def is_buffer_op(op0): return (op0.type == X86_OP_MEM \ and is_buffer_addr(op0.mem.disp) \ and op0.mem.scale == 1 \ and op0.mem.base == X86_REG_INVALID \ and op0.mem.index == X86_REG_INVALID \ )
def is_temp_op(op0): return (op0.type == X86_OP_MEM \ and op0.mem.disp == 0x412090 \ and op0.mem.scale == 1 \ and op0.mem.base == X86_REG_INVALID \ and op0.mem.index == X86_REG_INVALID \ )
SIMPLE_ENC = { X86_INS_ADD: X86_INS_SUB, X86_INS_SUB: X86_INS_ADD, X86_INS_XOR: X86_INS_XOR, X86_INS_ROR: X86_INS_ROL, X86_INS_ROL: X86_INS_ROR, }
class Operator: def __init__(self, op, off, size, param): self.op = op self.off = off self.size = size self.param = param
@classmethod def is_simple(cls, insn:CsInsn): if insn.id not in SIMPLE_ENC: return False
if len(insn.operands) != 2: return False op0 = insn.operands[0] op1 = insn.operands[1] if not is_buffer_op(op0): return False if not (op1.type == X86_OP_IMM): return False
return True
@classmethod def simple_op(cls, insn:CsInsn): op0 = insn.operands[0] op1 = insn.operands[1]
return cls(insn.id, buffer_off(op0), op0.size, op1.imm)
ins_types = {} for insn in all_insns(): key = insn.mnemonic if key not in ins_types: ins_types[key] = 1 else: ins_types[key] += 1
ops = [] regs = {} for insn in all_insns():
if Operator.is_simple(insn): op = Operator.simple_op(insn) assert op is not None, hex(insn.address) +' ' + insn.mnemonic + ' ' + insn.op_str ops.append(op)
elif insn.id in (X86_INS_MOVABS, X86_INS_MOV, X86_INS_MOVQ): op0 = insn.operands[0] op1 = insn.operands[1] opty = (op0.type, op1.type) assert opty in {(X86_OP_REG, X86_OP_IMM), (X86_OP_REG, X86_OP_MEM), (X86_OP_MEM, X86_OP_REG)} if opty == (X86_OP_REG, X86_OP_IMM): regs[op0.reg] = op1 elif opty == (X86_OP_REG, X86_OP_MEM): assert is_buffer_op(op1) or is_temp_op(op1) regs[op0.reg] = op1 elif opty == (X86_OP_MEM, X86_OP_REG): assert is_buffer_op(op0) or is_temp_op(op0) if is_temp_op(op0): regs[X86_REG_ENDING] = regs[op1.reg] else: assert op1.reg == X86_REG_MM0 o = regs[op1.reg] assert isinstance(o, Operator) assert buffer_off(op0) == o.off ops.append(o) else: raise AssertionError
elif insn.id == X86_INS_PXOR: op0 = insn.operands[0] op1 = insn.operands[1] assert op0.type == X86_OP_REG and op1.type == X86_OP_MEM assert op0.reg == X86_REG_MM0 and is_buffer_op(op1) op00 = regs[op0.reg] assert op00.type == X86_OP_IMM or is_temp_op(op00) if is_temp_op(op00): op00 = regs[X86_REG_ENDING] assert op00.type == X86_OP_IMM regs[op0.reg] = Operator(X86_INS_XOR, buffer_off(op1), op1.size, op00.imm)
elif insn.id in SIMPLE_ENC: pass
else: raise AssertionError(hex(insn.address) +' ' + insn.mnemonic + ' ' + insn.op_str)
for i in reversed(ops): mnem = cs.insn_name(SIMPLE_ENC[i.op]) sz = {8:'qword', 4:'dword', 2:'word', 1:'byte'}[i.size] param = i.param if param < 0: param += 1 << (i.size * 8) if i.size != 8: print(f'{mnem} {sz} [buffer + 0x{i.off:x}], 0x{param:x}') else: print(f'mov rax, 0x{param:x}') print(f'{mnem} {sz} [buffer + 0x{i.off:x}], rax')
|