目录

易语言模块函数特征码识别

通用的函数特征对于易语言程序来说肯定是不行的, 因此必须定制一套独立的特征码识别引擎。

调研易语言用户函数

1、易语言用户函数必定是以下几条指令开头

push ebp
mov ebp,esp

如果函数内含有局部变量,那么编译器便会通过下列指令申请变量空间,指令会紧跟着易语言函数头。

sub esp,0x4

局部变量初始化指令会紧跟着申请局部变量空间指令,默认数据类型都是初始化为0

mov dword ptr ss:[ebp-0x4],0x0
mov dword ptr ss:[ebp-0x8],0x0
mov dword ptr ss:[ebp-0xC],0x0

2、易语言用户函数必定是以下几条指令结尾

mov esp,ebp
pop ebp
ret xxx

3、关于易语言函数特征的生成顺序

在函数体内没有call的情况下,跳转指令也当成普通指令,从函数头到尾依次往下生成特征。

为了防止出现递归分析的状况,因此制定这样一条规则:

如果函数是第一次分析,那么该函数使用计算后的MD5作为特征,否则使用函数索引作为特征。

函数索引就是函数出现的顺序,每遇到函数自增加一。

对指令进行种类划分

为什么不站在易语言编译器的角度,而只站在汇编的角度对指令进行划分?

因为表面上看易语言编译器已经十多年没更新过,但仍无法排除未来有一天会更新的可能,站在汇编的角度才是真正的永恒。

1、灵活的单操作数指令

push、inc、dec

特点是它们都支持以下几种形式的用法

inc eax
inc [eax]
inc [0x401000]
inc [eax+ebx*4+0x401000]

其中push指令额外多一种用法push 0x401000,但是不影响划分。

2、灵活的双操作数指令

add、sub、mov

特点是它们都支持以下几种形式的用法

sub eax,0x1
sub eax,ebx
sub dword ptr[eax],0x1
sub dword ptr[0x401000],1
sub dword ptr[eax+ebx*4+0x401000],0x1

指定特征生成规则

1、特征生成的一个难点是区分数据和代码。

例如,push 0x401000这条指令,根本无法区分0x401000是一个常数,还是一个数据地址。

2、先制定一套指令模板规则,在模板规则基础上增加强化规则。

例如,可能有多个函数满足模板规则,在模板规则上不同的强化规则可满足识别任意函数。

3、我比较懒,个人力量比较弱,所以规则肯定是建立在txt或者sqlite上,这样比较好修改呢。我个人还是倾向于txt吧。

格式应该是这样吧:

特征函数1:c4ca4238a0b923820dcc509a6f75849b,<1,push,55664477889911223374456456465>
特征函数2:28c8edde3d61a0411511d3b1866f0636,<start+60,none,2333333>

首先是函数名字,然后是函数模板,最后是特征规则。

特征函数1规则:第一条指令是push指令,且push的常量数据是后面的二进制

特征函数2规则:函数头偏移60的位置数据233333。

有这两种规则,应该能表示大多数函数了吧。

4、call这条指令太烦人了。。。到底如何才能解决掉这种东西???去它大爷的,用call来对付call。

call func0
{
	1.1,push ebp
	1.2,mov esp,ebp
	1.3,call func1
	{
		2.1,push const
		2.2,call func0
		2.3,ret
	}
	1.4,call func2
	{
		2.4,mov eax,[const + ecx * 4]
		2.5,ret
	}
	1.5 jnz +0x60
	1.6,mov eax,const
	1.7,mov ebp,esp
	1.8,ret 0x4
}

文本型局部变量赋值

易语言的文本型变量,可以理解为const char*,因此常量赋值无需拷贝,直接传递eax即可。

mov eax,0x47B2FB

如果是变量赋值给一个另外一个变量,那么易语言会通过以下指令进行拷贝。

mov eax,dword ptr ss:[ebp-0x4]
test eax,eax
je short $+18
push eax
mov ebx,eax
call Strlen             //获取字符串长度
inc eax
push eax
call AllocMemory        //申请新内存
pop ecx
pop esi
mov edi,eax
rep movs byte ptr es:[edi],byte ptr ds:[esi]     //字符串拷贝

字节集局部变量赋值

易语言的字节集类型变量,本质上是一块存储了大小的Buffer,常量可通过直接传递eax来进行赋值。

mov eax,0x47B2B3

如果是变量赋值给一个另外一个变量,那么易语言会通过以下指令进行拷贝。

test eax,eax

易语言的类

push 0x4
call malloc
add esp,0x4
mov var,eax
mov ebx,eax
mov dword ptr ds:[ebx],0x0
mov dword ptr ds:[ebx],classVt

1.类的构造函数不在虚表中,而会直接以call的形式进行调用。类的析构函数是虚表中的第一个函数。

2.如果类含有继承类,那么这两个类函数合并使用一张虚表,构造函数 = 父类构造函数 + 子类构造函数。

类的析构函数同样是虚表中的第一个函数,析构函数 = 子类的析构函数 + 父类的析构函数。