基于交叉引用来解析易语言常量资源
目录
通过寻找易语言静态编译的程序规律,我们可以找到一处结构体,这个结构体大概是下面这个样子:
struct EHead
{
unsigned int dwMagic; //未知,值固定为3
unsigned int szNone2; //未知,值固定为0
unsigned int szNone3; //未知,好像是个随机数,修改不影响程序
unsigned int lpStartCode; //起始用户代码地址,不可修改
unsigned int lpEString; //常量资源,如果没有常量资源,则为0
unsigned int dwEStringSize; //常量资源大小,如果没有常量资源,则为0
unsigned int lpEWindow; //创建组件信息
unsigned int dwEWindowSize; //创建组件信息大小
unsigned int dwLibNum; //支持库数量
unsigned int lpLibEntry; //支持库信息入口
unsigned int dwApiCount; //Api数量
unsigned int lpModuleName; //指向模块名称
unsigned int lpApiName; //指向Api名称
};
可以看到这些结构体包含着易语言程序中的很多重要数据,今天我们要研究的就是常量资源部分。
lpEString
这个指针指向着易语言代码中所用到的全部常量,包括文本字符串、字节集、浮点数、类虚表、数组头、数组数据等,而dwEStringSize
则表示常量的总大小。
这些数据十分复杂,无论是在理论上还是实际上,我们仅凭数据本身,是很难分辨出这些数据的类别的,因此本文的主题就诞生了——基于交叉引用来解析易语言常量资源。
基于交叉引用来解析资源,原理就是通过对数据进行代码交叉引用,观察代码是怎么使用数据的,我们根据固定的数据使用模板就能识别出数据类别了。
但是在实际情况下,有大量的代码被保护,是无法得知使用代码的,如果代码100%全部被虚拟化保护,那么基于交叉引用来识别数据类型就彻底不可行了。幸运的是,大部分程序只会对少量关键代码进行虚拟化保护,如何最大化地利用交叉引用来识别这些被保护的程序的资源便是一个值得研究的问题了。
固定的数据使用模板
因为在易语言程序中,不同的常量数据类型有不同的使用模板,因此首先我们要记录下这些模板。
浮点数模板
使用到数据的指令是fadd
、fsub
、fmul
、fdiv
、fcomp
、fld
其中的一种。
空白字符串模板
一种是jnz$+0x5
,mov eax,addr
。
一种是push addr
字符串模板
一种是push addr
一种是mov eax,addr
空白字节集模板
一种是jnz$+0x5
,mov eax,addr
。
一种是push addr
一种是mov esi,addr
,0xABADABAD
字节集模板
一种是push addr
一种是mov eax,addr
数组头模板
一种是
mov esi,addr
lodsd
stosd
lodsd
stosd
数组模板
一种是mov eax,addr