此文用来整理和分析做题过程中所遇到的那些花指令,必然持续更新。
关于花指令的介绍见:花指令 · 逆向工程入门指南,这里只总结例子啦~
call $+5模式
[2021 ISCC] 擂台题-ZCM

| 1 | ...:00815023 038 E8 00 00 00 00 call $+5 | 
这一段可以完全等同于等同长度字节的nop,但是却能干扰IDA的反编译器。
首先我们知道:
| 1 | call addr ;将返回地址(即call的下一条指令首地址)压入栈中,等同于:push 下一条指令的首地址; mov ip,addr | 
那么执行完前三条指令(到0x0081502B时)栈区分布大概是:

在本例中,ret_addr=0x00815028,而add dword ptr [ebp+4], 0Ah根据栈区分布可以很明显地知道[ebp+4]就是ret_addr,所以是ret_addr+=0x0A即ret_addr=0x00815032。
而0x00815032这个返回地址正是ret指令的下一条指令,也就是说这一整段0x00815023-0x00815031代码是完全无意义的,甚至没有破坏寄存器值,所以可以完全用相同长度的nop指令代替。
[划重点] 去花方法:等同于相同长度的nop指令。
[2021 CISCN总决赛] junk

| 1 | .text:0000000000401641 018 E8 00 00 00 00 call $+5 | 
由局部变量定义区可知var_18=-0x18,那么0x401646处的指令可以等同于add [rsp], 6,同理可知call时栈顶处仅新增了ret_addr=0x401646,而这条指令就是将栈顶处的值+6,即将ret_addr+6=0x40164c,正好是retn指令后的下一条指令,所以0x401641-0x40164B这段也可以全部nop掉。
[划重点] 去花方法:等同于相同长度的nop指令。
[2021 CISCN总决赛] junk

| 1 | .text:000000000040166F 018 49 C7 C0 0D 00 00 00 mov r8, 0Dh | 
pop r9; add r9, r8; push r9这一段就是把栈顶值(即ret_addr=0x40167B)取出来以后自加0x0D,结果为ret_addr=0x401688,所以在下一步执行retn时返回地址设置成了0x401688,就会直接跳过下面三条指令跳到0x401688处。
这里有破坏寄存器r8和r9的值,所以patch的时候不能直接nop掉,要注意更改寄存器的值(当然如果这两个寄存器后面都没用到的话当我没说x 不过保险起见,建议还是补上最好)。
[划重点] 去花方法:patch成以下指令,多于字节用nop填充。
