花指令总结
花指令总结
做花指令的题,主要是看汇编代码,将那些可疑的代码patch掉,多patch,说不一定就patch出来了,有些题就比较恶心,出现一大堆花,人肉去花非常麻烦,只能使用脚本。
什么是花指令?
所谓花指令就是指程序中完全冗余,不影响程序功能却会对逆向工程产生干扰的指令。
花指令的作用:
主打一个静态混淆,让我们的反汇编工具不能正常识别出,像我们的IDA一些加花了的程序,我们就不能看到它的伪代码了.大多数起到一个提高逆向成本的作用,花时间去花.
在了解花指令之前,我们首先要了解我们的反编译是怎么运作,通过这样我们才能从源头明白,为啥会有花指令的出现.
反汇编器的运作方式:
我们常见的工具有,ida,od,WinDbg,objdump,这些工具运用的原理有不同两种
线性扫描反汇编
正如其名,像一条直线式的进行扫描然后反汇编.就是按照着机器码的顺序,一条条的翻译我们的机器码,逐条的反汇编我们的每一条指令,直到将代码段整个扫描完毕.
这个方法有一个明显的缺点,就是它太直了,它不会考虑到代码中可能混有数据,因此无法正确地将嵌入的数据与代码区分开。从而造成反汇编失败.
递归下降反汇编
这个算法主要是基于控制流来判断是否被另一条指令引用来决定是否进行反汇编.
主要为下面几个指令进行判断:
顺序流指令(一条一条进行执行的指令),条件分支指令(ja,je,jne…..),无条件分支指令(jmp),函数调用指令(call),返回指令(ret)
优点:具有区分代码与数据的能力.
缺点:就是我们可以构造反汇编器无法判断真假的恒真/恒假分支,再插入不可执行的花指令来达到欺骗效果。
对于花指令的去除,我们现在用于分析的主要是IDA,而我们的IDA运用的算法正是递归下降算法的反汇编.
因此我们的花指令主要的是针对于让我们的IDA混淆起来,让它不能正常的反编译我们的文件,从而增大逆向分析难度.
opcode。opcode operation code也叫指令机器码 Instruction Machine Code,就是汇编指令翻译后的二进制形式,我们也称之为硬编码,比如0XE8一般为call,0XE9为JMP,0X90为NOP.
一些常见的花指令套路
1、插入无效步骤
无效跳转
比如通过一些抵消的操作来达到混淆效果,比如在push后,然后就紧接着Jmp,跳到一个地方后,pop,然后在jmp回来,形成一个无效的代码,从而造成混淆。
2、绝对跳转(永真跳转)
一个是直接使用jmp进行跳转,还有的就是进行je,jne这种互补的指令,由于递归下降算法不能获取到程序运行中的上下文信息,遇到条件跳转语句时,它会递归地将跳转的分支与不跳转的分支都就行反汇编。
1 | _asm { |
对于这种我们直接nop就行。
二,
1 | __asm { |
3、call,与ret的使用(指令替换)
一、
例如,对于我们的call addr指令,是可以替换为下面的片段
1 | push addr |
因为call本质上将其拆解为两条指令进行理解:push 函数并返回地址
然后jmp 函数地址
对于我们的ret, 可以替换为
1 | push ecx |
对于ret本质上等于pop eip
加 jmp
通过此中代换,就会破坏我们的ecx寄存器,从而操作我们工具解析出的函数地址范围与调用关系出现错误。
一、
1 | __asm { |
在使用内联汇编时,ret
指令用于从子函数返回到调用函数。正常情况下,ret
指令会弹出栈顶的返回地址,并将程序控制流转移到该地址。
然而,在某些特殊情况下,我们可能需要在 ret
后面添加机器码。这是因为在编写内联汇编时,编译器会对代码进行优化,并且可能会对指令进行重新排序或优化。如果我们在 ret
指令后面没有添加机器码,编译器可能会将其与后面的指令进行合并或优化,导致程序行为不符合预期。
通过在 ret
指令后面添加机器码,我们可以确保编译器不会对 ret
指令进行优化或重新排序。这样可以保证 ret
指令的行为与我们的预期一致,从而实现特定的功能或行为。
ret
指令后面的机器码不会被执行,而是用于控制程序的流程。
出现堆栈不平衡,从而造成后面的代码不能成功反编译出
二、
1 | __asm { |
效果如图:
对于call与ret的花指令构造可以在函数中修改返回地址,达到跳过thunkcode到正常流程的目的。
4、相互抵消的操作(IDA能修复)
如下
1 | push ebp |
在汇编代码中添加一下互相抵消的指令,从而让分析器,发生干扰,不能正常反编译。