IDA [call $+5 / pop reg] 清洁

逆向工程 艾达 idapro插件 蟒蛇
2021-06-17 20:52:50

谁能告诉我如何清理包含以下块的代码:

call $+5
pop reg
add reg, 08BE96h
[...]

换句话说,我需要将所有这些块更改为:

mov reg, offset

编辑 #1

列出所有区块 EA:

ea = ScreenEA()
for funcea in Functions(SegStart(ea), SegEnd(ea)):
    E = list(FuncItems(funcea))
    for e in E:
        if idc.GetMnem(e) == "call" and idc.GetOpnd(e, 0) == "$+5" and idc.GetMnem(e + 5) == "pop":
            print "%x" % e
2个回答

这是一个粗略的实现,它扫描此模式的当前聚焦功能:

call $+5
pop <reg>
op <reg>, imm32

并将其更改为

mov <reg>, <computed imm32>
nop
nop

调整它以扫描不同范围并支持更多指令作为练习留给读者。

def simplify(tgtEA):
  ins1 = tgtEA
  if not idc.isHead(idc.GetFlags(ins1)):
    ins1 = idaapi.prev_head(ins1, limits.startEA)

  ins2 = idaapi.next_head(ins1, limits.endEA)
  if ins2 == 0xFFFFFFFF:
    return False

  ins3 = idaapi.next_head(ins2, limits.endEA)
  if ins3 == 0xFFFFFFFF:
    return False

  print "Scanning instructions at %d, %d, %d" % (ins1, ins2, ins3)

  result = ins2
  matched = False
  reg = 0

  if idc.GetMnem(ins1) == "call":
    if idc.GetOpnd(ins1, 0) == "$+5":
      if idc.GetMnem(ins2) == "pop":
        if idc.GetOpType(ins3, 0) == 1:
          reg = GetOperandValue(ins2, 0)
          if idc.GetOperandValue(ins3, 0) == reg:
            op = idc.GetMnem(ins3)
            optype = idc.GetOpType(ins3, 1)

            if op == "inc":
              matched = True
              result = result + 1
            elif op == "dec":
              matched = True
              result = result - 1
            elif op == "add":
              if optype == 5:
                # optype 5 = immediate
                matched = True
                offset = idc.GetOperandValue(ins3, 1)
                result = result + offset

  if matched:
    # patch the bytes by hand - there's no nice API to assemble("foo bar")?
    # MOV r32, imm32 = 0xB8 /rd 
    # reg is the register number acquired from IDA operand value
    # IDA uses the same register numbering as Intel
    regbyte = 0xB8 + reg;
    idaapi.patch_byte(ins1, regbyte)
    idaapi.patch_long(ins1 + 1, result)
    idaapi.patch_word(ins1 + 5, 0x9090) # NOP NOP 
    return True

  return False

# ----

curEA = ScreenEA()
tgtEA = idaapi.askaddr(curEA, "Enter target address")
#tgtEA = curEA
if tgtEA is None:
  exit

f = idaapi.get_func(tgtEA)
if not f:
  print "No function at 0x%x" % (tgtEA)
  exit

limits = idaapi.area_t()
if not idaapi.get_func_limits(f, limits):
  print "No limits in this function?!"
  exit

print "Scanning function from %x to %x" % (limits.startEA, limits.endEA)

itEA = limits.startEA
while itEA < limits.endEA:
  if simplify(itEA):
    itEA = idaapi.next_head(itEA + 7, limits.endEA)
  else:
    itEA = idaapi.next_head(itEA, limits.endEA)

call $+5 is 5 byte(e8 00000000) pop reg is 1 byte add reg will be3 and more bytes

如果你需要 call $+5成为mov reg , const

你首先需要计算返回地址+常量的值

在你的情况下的地址 pop reg + 0xbe96

然后使用一个 5 byte mov REG, computed value

那叶子4 + bytes,你需要NOP出来,这样的执行路径是一样的,如果你没有NOP字节则离开了垃圾字节可以改变的执行路径