前言:
花指令是,由设计者特别构思,希望使反汇编的时候出错,让破解者无法清楚正确地反汇编程序的内容,迷失方向。经典的是,目标位置是另一条指令的中间,这样在反汇编的时候便会出现混乱。花指令有可能利用各种指令:jmp, call, ret的一些堆栈技巧,位置运算,等等----摘自百度百科。
我最近遇到了几个花指令,现记录整理如下:
第一种花指令:
特征:先有一个push 操作,然后jmp到一个Call,Call后面跟一个POP
56 EB 27 2B A6 F1 CC 7E 25 31 96 23 39 7D B0 18 5A 1B D7 5E CB 5E FF E6 2B A6 F1 CC 7E 25 31 96 23 39 7D B0 18 5A 1B D7 5E CB E8 E6 FF FF FF 5E
01
原理:
push D(寄存器) 1.先push esi(使用一个参数,保留环境,这里也可以push eax-edi等寄存器)
jmp C(偏移) 2.通过EB xx的jmp偏移指令,跳转至精心构造的偏移xx处,也就是Call
call B() 3.特定E8的Call指令回退调用(Call => 1.push 下一条指令的地址A 2.jmp 函数地址B)
pop D,jmp D 4.此时pop esi 就把地址A从堆栈中push出来,然后jmp esi就跳转至地址A
pop D 5.再次pop esi 的目的在于还原环境
解决方案:单步跟踪时,只需要F8即可过掉。(想在IDA内看结构,就把它们全部NOP掉就好了)
变通点:B C D都可以变换,导致特征码不好定位,暂时没想到好的批处理方法
第二种花指令:
特征:
无效指令:如CLC,CLD,FNOP。
无效跳转:
mov 寄存器,A;
cmp 寄存器,A;
JNZ 迷惑跳转;
02
解决方案:这种比较简单,迷惑跳转不用管,直接nop填充即可,调试跟踪的时候也可以当当乐子
第三种花指令:
特征:
push ss
pop ss
待执行指令
有效OPCODE 16 17
03
push ss;向堆栈压入16字节内容
04
pop ss;
05
原理:在执行push ss,pop ss语句后,会自动执行下一条语句,当下一条为jmp或着Call是就会跑飞/关键功能丢失
解决方案:如果pop ss后面跟的是Call,在Call入口下断即可。如图:
07
第四种花指令(来源于GrandCrab5.3的一个样本):
08
1.mov ecx,0x1C3D2(给ecx赋值) 有效OPCODE:B9
09
2.Call XXxx(将下一条语句作为返回地址push入栈,然后跳转至偏移)有效OPCODE:E8 0B 00 00 00(Call XXxx)
0A
3.add [esp],0x12; 修改返回地址 有效OPCODE:83 04 24 12
4.loopd short 循环跳转 ,然后cmp ecx,XXXX(由于之前赋值的是较小数一定会跳转)最后retn返回至被修改过的函数返回地址,结束 有效OPCODE:E2 EF(loopd short) 81 F9 XXxx( cmp ecx,XX) 78 F0(JS short) C3(retn)
0C
解决方案:
利用010去花指令:花指令特征码为B9 D2 C3 01 00 E8 0B 00 00 00 81 F9 58 FF FE 01 78 F0 79 F8 E9 83 04 24 12 E2 EF E8 替换为EB 1A,后面随便填充即可,如:EB 1A 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
去花对比:
0D
去花后:
总结:
1.前三种花指令都是来自于最近看的一个VB样本的ShellCode内,没能太大阻碍分析过程。第四个来源于很早之前看的一个GrandCrab5.3勒索病毒,解决花指令能有效利用IDA对其快速分析,帮助还是挺大的(当OD分析花指令时候一定要灵活利用ctrl+↑和ctrl+↓手动矫正反编译结果)。
2.花指令就是一个消耗分析人员耐心的行为(主要考验分析人员的汇编功底),分析的多了自然就熟练了(一般加花的话,像上面的有效OPCODE就很难变动)写下此贴目的之一就是告诫自己要耐心耐性
3.我们也可以通过上面的有效指令,构造属于我们的花指令(具体怎么操作就靠大家发散了),然后添加到代码的任意位置,略微增大分析难度