这是一个粗略的实现,它扫描此模式的当前聚焦功能:
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)