从技术上讲,
PUSH A
RET
相当于
JMP A
和
PUSH A
PUSH B
RET
相当于
CALL B
JMP A
您可以编写一个 x64dbg 脚本来搜索上述模式并将其替换为简化的程序集。
例子
PUSH + RET
有字节模式
0: 68 44 33 22 11 push 0x11223344
5: c3 ret
以下脚本将其替换为 ,JMP
其余部分(如果有)替换为NOP
。
$base = 0x91e000
$search_size = 0x100
findall $base, "68 ?? ?? ?? ?? c3", $search_size
$count = $result
next:
dec $count
$addr = ref.addr($count)
$jmp_addr = dis.imm($addr)
asm $addr, "jmp 0x{$jmp_addr}"
$asm_size = $result
$remainder = 6 - $asm_size
fill_nop:
dec $remainder
asm $addr+$asm_size+$remainder, "nop"
test $remainder, $remainder
jnz fill_nop
test $count, $count
jnz next
msg "Done"
同样对于PUSH + PUSH + RET
,
0: 68 44 33 22 11 push 0x11223344
5: 68 dd cc bb aa push 0xaabbccdd
a: c3 ret
以下脚本将其替换为CALL + JMP
.
$base = 0x91e000
$search_size = 0x100
findall $base, "68 ?? ?? ?? ?? 68 ?? ?? ?? ?? c3", $search_size
$count = $result
next:
dec $count
$addr = ref.addr($count)
$ret_addr = dis.imm($addr)
$call_addr = dis.imm($addr+5)
asm $addr, "call 0x{$call_addr}"
$asm_size = $result
asm $addr+$asm_size, "jmp 0x{$ret_addr}"
add $asm_size, $result
$remainder = 0xb - $asm_size
fill_nop:
dec $remainder
asm $addr+$asm_size+$remainder, "nop"
test $remainder, $remainder
jnz fill_nop
test $count, $count
jnz next
msg "Done"
但是,上述方法有一些注意事项:
PUSH + PUSH + RET
CALL + JMP
仅当被调用者使用RET
指令返回调用者时才能转换为(这在 cdecl 中是正常的)。如果它使用JMP
指令混淆返回,它将不起作用。那不是RET
有
ADD ESP, 4
JMP DWORD PTR [ESP-4]
模式搜索在大多数情况下都有效。但是,如果部分代码被加密,则可能会返回误报,并且您可能会无意中覆盖错误的数据。