前言:
花指令的出现主要是防止软件被反编译,加大逆向分析的难度,在一些代码中插入一些脏字节
为啥我要写呢,因为面试的时候也碰到了,虽然我都答出来了,但是特意过来记个笔记2333
一.花指令的分类
1. 可执行的花指令
之前在西电的ctf上,就碰到一题,只是为了混淆视听而已,实际上根本不会执行,
加大你静态分析的难度,那题是在源码级上搞,还有那种在汇编级上push一下
,再pop一下,这种看似没什么用的操作同理
2. 不可执行的花指令
这里要总结几种汇编层面上的花指令模式,很大程度是因为ida无法联系上下文233
1.jx+jnx
这个就不用多说了吧,很常见的一种花指令了,这里jnz实际上是fake的,因为jz这个指令,让ida
认为jz下面的是另外一个分支,所以这里去除,就是将jnz下面包括jnz 全c了,然后把loc_402669+1
的字节码全给nop了,f5就管用了
2. call pop / add esp
这里call指令,其实本质就是jmp&push 下一条指令的地址,但是这里其实就是一个jmp指令
所以 push这条指令是多余的,需要add esp,4 调整堆栈,但是ida会默认把call 后面的那个地址
当成一个函数。
3. stx/jx
clc是清除EFlags寄存器的carry位的标志,而jnb是根据cf==0时跳转的,然而jnb这个分支指令,ida
又将后面的部分认作成了另外的分支,interesting。
4.jmp xxx红色
这也是一种非常常见的花指令的,其实这里很明显就有问题,因为虚拟地址怎么可能有那么大对吧,
我们来看一下花指令源代码,
实际是e9在搞鬼,ida会默认将e9后面的4个字节当成地址,只要nop掉就好了
5. 多重跳转的
这里也是,仔细分析下逻辑发现其实这一大段根本没用,就离谱,单纯恶心反编译器的,我们可以使用idapython
来进行去花,而且当花指令很多的时候,idapython的自动化会很有用
二.利用idapython去除第5点花指令
def nop(addr,endaddr): while(addr<endaddr): PatchByte(addr,0x90) addr+=1 def undefine(addr,endaddr): while addr<endaddr: MakeUnkn(addr,0) addr+=1 def dejunkcode(addr,endaddr): while addr<endaddr: MakeCode(addr) # 匹配模版 if GetMnem(addr)=='jmp' and GetOperandValue(addr,0)==addr+5 and Byte(addr+2)==0x12: next=addr+10 nop(addr,next) addr=next continue addr+=ItemSize(addr)
里面使用到的ida函数解析
MakeCode(ea) #分析代码区,相当于ida快捷键C ItemSize(ea) #获取指令或数据长度 GetMnem(ea) #得到addr地址的操作码 GetOperandValue(ea,n) #返回指令的操作数的被解析过的值 PatchByte(ea, value) #修改程序字节 Byte(ea) #将地址解释为Byte MakeUnkn(ea,0) #MakeCode的反过程,相当于ida快捷键U MakeFunction(ea,end) #将有begin到end的指令转换成一个函数。如果end被指定为BADADDR(-1),IDA会尝试通过定位函数的返回指令,来自动确定该函数的结束地址
idapython的参考api链接:
https://www.bbsmax.com/A/x9J27Lgg56/