花指令实质就是一串垃圾指令,它与程序本身的功能无关,并不影响程序本身的逻辑。在软件保护中,花指令被作为一种手段来增加静态分析的难度,花指令也可以被用在病毒或木马上,通过加入花指令改变程序的特征码,躲避杀软的扫描,从而达到免杀的目的,本文将介绍一些常见的花指令的形式,花指令一般被分为两类,被执行的和不会被执行的。
花指令虽然被插入到了正常代码的中间,但是并不意味着它一定会得到执行,这类花指令通常形式为在代码中出现了类似数据的代码,或者IDA反汇编后为jmupout(xxxxx).
这类花指令一般不属于CPU可以识别的操作码,那么就需要在上面用跳转跳过这些花指令才能保证程序的正常运行。
反汇编引擎主要有两种算法,一种是线性扫描算法,一种是递归行进算法。
线性扫描算法将遇到的每一条指令都解析成汇编指令,没有对反汇编的内容进行判断,因而无法正确区分代码和数据,一些数据也会被当成代码来解码,从而导致反汇编出现错误,这种错误将会影响对下一条指令的正确识别。
递归行进算法按照代码可能的执行顺序来反汇编程序,对每条可能的路径进行扫描,当解码出分支指令后,反汇编工具就将这么地址记录下来,并分别反汇编各个分支中的指令,这种算法比较灵活,可以避免将代码中的数据作为指令来解码。
形式一:如果我们插入的花指令是一个操作码,那么后面程序原本的机器码就会被误认为是这个操作码的操作数,从而导致反汇编引擎的解析错误。
示例代码:
int main() {_asm {xor eax, eax;jz s;_emit 0x11;_emit 0x22;_emit 0x33;//0x33是xor指令的操作码,会导致后面正常的Push指令被错误解析s:} printf("Hello World!n"); } 123456789101112
_emit 指令为插入字节码
由于经过xor eax,eax后,ZF标志位被置为1,那么jz这条跳转指令必定会被执行,后面插入的0x11,0x22,0x33就会被跳过,程序正常输出Hello World!
我们把程序放到IDA中查看下花指令的干扰效果。
此时IDA已经无法正常解析这个函数了,由于我们实验代码是写在main函数中的还能找到这段代码,在实际做题的过程中,如果出题人把关键代码写在其他函数并添加类似花指令,那么我们就无法顺利找到关键函数,尝试下用搜索Hello World字符串通过交叉引用的方式定位代码,发现也是定位不到的。
在加了这类花指令的情况下,我们想要定位关键函数只能借助动态调试的方法,首先在OD的内存窗口中搜索到Hello World字符串(p.s:可能会出现多个相同的字符串,在C语言中常量字符串会被存放在rdata段,所以可以在这个范围内进行字符串的查找)
然后在该地址设置内存访问断点,运行程序后使用快捷键ctrl+F9进行堆栈回溯,即可定位到关键位置
针对一些字符串加密的情况,可以尝试在控制台的输入输出函数下断点,然后再进行堆栈回溯,本题可在ucrtbase.__stdio_common_vfprintf
函数设置断点
观察汇编代码可以发现从401043-40103F都属于花指令,我们可以用NOP指令对其进行填充后保存文件,然后再放到IDA中进行静态分析。
插入的花指令也可以是改变堆栈平衡的汇编代码,跟形式一相同在这些花指令上面写上跳转指令,虽然花指令不会被执行,但是IDA进行解析时会认为该函数堆栈不平衡,从而使F5功能失效
示例代码;
int main() {_asm {xor eax, eax;jz s;add esp, 0x11;s:}printf("Hello World!n"); } 12345678910
效果:
对抗方法同上,将造成堆栈不平衡的软件NOP掉即可。
这类花指令本身是正常的汇编指令,它们运行完后不会改变原来程序的堆栈,寄存器,但能起到干扰静态分析的作用,一般分为两种,一种是改变堆栈操作,另一种是利用call指令或Jmp指令增加执行流程复杂度。
形式一:示例代码:
int main() {_asm {push eax;add esp, 4;}printf("Hello World!n"); } 123456789
在32位下,push eax分为两个步骤,1.esp=esp-4 2.将eax值放入esp地址中,正常情况下,push操作需要对应一个pop操作来保持堆栈的平衡。
这里后面跟着的add esp,4起到了pop 指令的部分功能,也就是恢复了堆栈的平衡,使得程序能够正常运行。
但是在IDA中却无法正常识别这种操作。
利用call指令来增加程序执行流程的复杂度,我们知道,执行call执行时会向堆栈中压入返回地址,我们可以修改这个返回地址,配合ret指令跳转到任意一个我们想去的地方,这里具体例子位2018网鼎杯的一道题,本文仅分析花指令部分
程序入口有该花指令,在402006位置有个call指令,call到了call指令所在的下一行,然后add [esp],0x17
也就是将返回地址加了0x17然后ret 原先的返回地址应该为40200B 加上0x17后为402022,我们跳转过去看下
后面代码也很乱是因为后面有相同做法的花指令。像这种花指令在程序中多次出现,但是他们都有相似的特征,靠手动清除需要耗费大量的时间,所以可以通过编写脚本来清楚这些花指令。
编写IDC脚本清除花指令IDC脚本是IDA的一项功能,他的语法与C语言类似所以叫IDC,另外还有一种IDAPYTHON使用的是pyhton的语法,具体可以参考IDA权威指南,这里介绍下编写IDC脚本清除花指令需要用到的一些函数。
首先是一个编写IDC脚本的框架
#include <idc.idc> static main() { } 1234567
在IDC脚本中,变量的声明使用的是auto关键字,例如:auto i=0;
for,if语句等语法与C语言相同,值得注意的是在IDC脚本中不支持+=;++等写法,需要老老实实的写全。
PatchByte(地址,内容)
Byte(地址)
IDC中提供了以上两个函数,第一个是修改字节,Byte是指定修改大小,同理还有PatchWord等等
Byte()是向地址中读取一个字节,Word就是读取双字节…
了解了这些后就可以写一个简单的脚本来清除花指令了,具体的代码就不贴了,等大家遇到花指令时动手编写下吧。
花指令相对来说还是比较容易处理的,需要对堆栈变化,函数调用等知识有一定的了解,才能分辨出哪些是花指令,然后做出相应的处理,如果不太确定的话就可以配合动态调试来进行分析,一般来说一个程序中的花指令都是属于同一种,提取他的特征后就可以通过编写脚本来清除花指令,还原出程序本身的面目了。
相关知识
逆向分析基础
[原创]CTF竞赛中常见花指令解决方法
主动式逆向物流与RLOM模型
CTF常见花指令去除IDA插件
逆向分析“海莲花” APT木马的花指令反混淆工具
我校学子荣获第八届全国绿色供应链与逆向物流设计大赛一等奖
某花夕拾日记APP的一次逆向教程
菊花及其近缘种属植物质膜Na~+/H~+逆向转运蛋白SOS1s基因克隆与功能鉴定
文管系(学院)在第八届“云丰杯” 全国绿色供应链与逆向物流设计大赛中斩获佳绩
Halomonas sp. Y2中NhaD型Na~+/H~+逆向转运蛋白及其突变体功能研究
网址: CTF逆向基础 https://m.huajiangbk.com/newsview702612.html
上一篇: 花:英文怎么写 |
下一篇: 花的作文怎么写? |