代码混淆 - 花指令分析

萌新只会搞定一些特别简单的花指令,而且还得灵光一闪才搞的定,今天来具体学习一下花指令相关内容

概念

花指令(或者叫脏字节)是企图隐藏掉不想被逆向工程的代码块(或其它功能)的一种方法,在真实代码中插入一些垃圾代码的同时还保证原有程序的正确执行,而程序无法很好地反编译, 难以理解程序内容,达到混淆视听的效果。

简单花指令及其原理

用ida举例吧。我们用ida打开一个程序

我们看到,里面有代码,有数据块这些东西

但实际上,这并不是程序本身的样子,我们可以选中一些代码,按快捷键u(Undefined,取消定义)

这些代码会变成一堆十六进制的单字节的数据,这才是程序本身的样子

ida本身并不能区分什么是代码什么是数据,它是通过某种算法来分析出一堆数据组合在一起是什么代码。

让这种分析算法出错的最简单的方法,就是花指令。

例如,下列汇编指令中,0xE8就是一个简单花指令

addr:
	push ebp
	jz addr2
	jnz addr2
	db 0xE8
addr3:
	sub esp, 0x100
	add eax, 0x1
	sub ebx, 0xAFBC11
addr2:
	mov ebp, esp
	jmp addr3 

这种花指令的作用可以通过前面第一张图片看到(第二张图片可以看到里面插入了几个E8,效果和这串代码是一样的):

  1. 出现了一坨红色的、IDA分析不出来的数据(或者说,已经被错误分析的数据)
  2. 红色的玩意后面,有一些数据没有被分析成代码,变成了一个数据块,IDA认为他只是普通的数据
    这就是花指令的作用

我们来分析上面那串代码

jz是结果为0就跳转,jnz是结果不为0就跳转,可以看成是if语句的2种分支
那一个条件只有真假两种状态,也就是说,不管条件如何,这里都会跳转到addr2,那么,db 0xE8 这段东西就没有卵用
但是,E8是call的机器码,那么IDA会认为:如果不会jz/jnz跳转的话,call(E8)就会使程序跳转到一个新地址。这个地址就是下面的机器码。

ida分析到jnz时会认为:如果他为0就不会跳转了,但是事实上为0的时候会在jz跳转,但是ida的算法处理不了这种情况
这串代码中,ida会认为sub esp的一部分值是call的跳转地址,此时就会出现如上方红色数据的异常(根本没有红色数据这个地址)

然而,如果出题人经过精心设计,让E8后的机器码变成一个存在的地址,那么ida是不会报错的。
这时我们就要这样分析:例如上面那个红色数据的地址是0x40101A,但是所有的call调用这个地址的时候都不是直接用0x40101A,而是诸如0x401019+1或者0x401018+2这种玩意,那么这里大概率有一个花指令。

这种花指令的应对方法就是按u

我们会看到一个XREF(非自然程序流程,可以用它对程序流进行跟踪和控制,估计以后有的学了),关注到这一行,忽略掉上一行,选中XREF及之后没有被分析的数据,然后按C转换成代码

这里优先用Analyze模式,如果Analyze分析错了的话再用Force

这样就恢复到了正常状态。

另:这种花指令直接看汇编动调其实可以直接绕过去。

sp/esp analysis failed

IDA分析时,需要确认“代码块”和“数据块”,并把代码块分析为函数
但是,这种分析过程需要对esp寄存器进行追踪,一旦追踪失败便会报错sp/esp analysis failed

一个简单的概念:ret和jmp操作可以修改程序的执行流。ret是通过esp的指向来进行修改的,jmp是直接通过其后面的数字进行修改的。那么可以通过一些操作来让ret当做jmp使用

比如这种main函数,你F5按坏了也不会反汇编成代码

这个是源码

#include <stdio.h>
#include <stdbool.h>
#pragma warning(disable:4996)
#include <stdlib.h>
void func1()
{
	__asm
	{
		lea eax, lab1;
		call eax;
		db 0xE8;
	lab1:
	}
	printf("func1\n");
}
void func2()
{
	__asm
	{
		cmp eax, ecx;
		jnz lab1;
		jz lab1;
		db 0xB8
	lab1: 
	}
	printf("func2\n");
}

这里我们用到了__asm代码块,简单的说,这种内联汇编的使用会让ida错误地认为这里出现了函数嵌套函数的情况,导致不能用F5转化为代码。

这种情况下,我们关注一下有没有红色字体的XREF, 如果有的话再看看这种红色字附近有没有jz&jnz

上图可以看到jnz short near ptr loc_40107E+1jz short near ptr loc_40107E+1

那我们找到地址40107E,然后按u

顺便,我们还会发现:loc_40107E+1的+1没了,变成了函数unk_40107F

然后从有XREF的这一行选中下面所有数据按C,首选Analyze,没用再选Force

然后发现还真没用,但是对这个奇怪的数据再按一下c

就没问题了

脚本去除花指令

刚好大爹说暂时没必要学,那充分必要地摸了(

posted @ 2022-01-14 15:20  iPlayForSG  阅读(1010)  评论(0编辑  收藏  举报