type
status
date
slug
summary
tags
category
icon
password
我所用到的环境vs stuio code 2022,ida7.7(曾因为环境问题一直没有好好弄这个,希望对你有帮助)
花指令介绍
花指令是对抗反汇编的杀器之一,正常代码添加了花指令之后,可以破坏静态反汇编的过程,使反汇编出错,可以让破解者的分析工作大量增加,从而使不能理解程序的结构和算法,然后不能破解程序,达到保护病毒和软件的目的
作用
欺骗反汇编器,让反汇编器无法正确反汇编出汇编代码,具体来说是破坏了反编译的分析,使得栈指针在反编译引擎中出现异常,从而加大静态分析的难度,使得逆向分析人员难以识别代码的真正意图
花指令分类
可执行花指令
通常程序保护用到的一般就是可执行的花指令,即垃圾指令
可执行花指令指的是能够正常运行的但又不改变原始程序逻辑性的一组无用指令
其特点:
- 程序可以正常运行
- 不改变任何寄存器的值
- 反汇编器可以正常反汇编该指令
不可执行花指令
反编译器的工作原理
由于反编译器的工作原理一般是线性扫描算法或递归下降反汇编算法。
线性扫描反汇编算法从程序的入口点开始反汇编,然后对整个代码进行扫描,反汇编扫描其过程中所遇到的每条指令。那么线性扫描算法的缺点也就显而易见了,由于其不定常的指令格式,在反汇编扫描过程中无法区分数据与代码,从而导致将代码段中嵌入的数据误解释为指令的操作码,以致最后得到错误的反汇编结果。
递归下降算法,递归下降算法通过程序的控制流来确定反汇编的下一条指令,遇到非控制转移指令时顺序进行反汇编,而遇到控制转移指令时则从转移地址处开始进行反汇编。该算法的缺点在于难于准确确定间接转移的目的地址。
花指令原理
不同的字节码可以转换为不同的指令,有的一个字节码就可以转换成一条指令,比如0x55就反编译为push ebp
如果是0xe8,就为汇编中的call指令,后面就会跟着四个与地址有关的字节,反汇编器就会一下子读取5个字节。同理除了0xe8字节码外还有其他字节码会读取2,3,4个字节
如果中间的反编译出错,例如两条汇编中出现一个0xe8字节,那么反编译器会把跟着的四个字节处理为call地址相关的数据,反汇编成 call XXXXXXX的指令,但其实后面的四个字节码根本不是需要调用的地址字节码,而是其他的字节码或者指令
常见花指令
简单花指令
除了上面两种,还有一种只会增加垃圾指令的简单花指令(只能生成垃圾指令,不影响ida反编译)
我写的源码(镶嵌到main函数里面),垃圾指令就这个一个,没啥用,不影响,ida反编译后自动就进入了main函数的伪代码,ida可正常f5
多层嵌套
互补条件跳转
先看我写的源码(我写在main函数里的)
反汇编就成了这样
升级版
在如下代码中,先对eax进行xor之后,再进行test比较,zf标志位肯定为1,就肯定执行跳转jz code2;,也就是说中间0xC7永远不会执行
注意先压栈保存eax的值,最后再把eax的值pop出来
编译源码(嵌入在main函数里),实测ida f5已经废了,花指令如下
再来个加强版
编译源码,这个花指令已经不是看着很明显了(ida f5照样废了)
看到花指令的强大没有
其实还有
call&ret构造花指令
代码中的esp存储的就是函数返回地址,对[esp]+8,就是函数的返回地址+8,正好盖过代码中的函数指令和垃圾数据。
编译源码(我同样写在main函数里的)这个花指令,刚开始反编译完,我人傻了,要不是往后面翻有个83h,都看不出来是一个花
这里建议动态调试一下
动态花就没了,还能理解一下这个花指令
call 指令的直观理解:push 函数返回地址; jmp 立即数 ret 指令的直观理解:pop eip; add esp,4
利用函数返回确定值
有些函数返回值是确定的,比如我们自己写的函数,返回值可以是任意非零整数,就可以自己构造永恒跳转
还有些API函数也是如此,比如在Win下HMODULE LoadLibraryA(LPCSTR lpLibFileName);函数,如果我们故意传入一个不存在的模块名称,那么他就会返回一个确定的值NULL,此时就可以通过这个函数来构造永恒跳转。
如下例子:
这里注意一下,LoadLibrary函数需要调用windows.h这个库,这次写在外面的函数,花指令如下,f5可以实现
call和ret的组合
这里直接放出处的图片
思路有很多种,按照自己喜欢的方式组合,只要不影响其他正常代码的运行就可以,如下也是比较好的两种思路
call嵌套的思路1
call嵌套的思路2
花指令原理另类利用
当我们理解了花指令的原理后,我们可以在将花指令中的垃圾数据替换为一些特定的特征码,可以对应的$“定位功能”$,尤其在SMC自解码这个反调试技术中可以运用。
例如:
将这串特征码hElLowoRlD嵌入到代码中,那我们只需要在当前进程中搜索hElLowoRlD字符串,就可以定位到当前代码位置,然后对下面的代码进行SMC自解密。
破解之道
- 手动分析出花指令,然后nop掉,然后保存副本
- 动态调试,不用管花指令(不过好像并不是所有都能这样)上面有个call ret那个可以直接动调过了
- 简单分析几个花指令,写一个idc,idapython脚本
这里简单演示一个,手动去花指令
先上源码
编译完,反编译
这个花简单,就在这里,直接nop掉,快捷键ctrl n
然后反编译结果为:
好像大差不差,其实是我这个花没写好。。。。问题不大,下次一定,写在flag下面
参考