每个程序、甚至是不同版本的同一个程序,都有“特征”这一说法。那么“特征”在外挂与反外挂领域,有什么用呢?
首先是“第三方”领域,特征可以用来定位基址,偏移,call等等。甚至可以用来定位“动态crc”,这里的动态crc指的是正常手段无法断到,或者无法被定位的代码段。这个时候可以将整个模块内存拷贝出来,进行一个特征搜索。
同样,在反外挂领域,“特征”也功不可没,在这里举两个例子:
例子一:
某游戏外挂,对游戏进行注入了dll,实现了某些功能,而作者非常狡猾,加了壳或者每次加载Dll都会打乱头部特征,抹除pe等等。这个时候,安全系统应该如何对其进行特征呢?这个时候就需要找到对游戏进行读写内存的第三方call,进行一个特征定位。
反外挂突破口推荐为最常见的人物坐标。不管是FPS,还是RPG,几乎绝大部分外挂,都要对其进行读取,通过一系列算法写出自动打怪,或者自动瞄准之类的功能。而安全人员,可以在人物坐标上下断点,查看是否有非游戏自身代码,对人物坐标进行访问,抓到访问代码后,顺藤摸瓜,可对三方程序的函数进行一个特征定位,让“误查”的可能性降到最低。
这里以QQ的代码为例子,随便找一个CALL,假设该CALL是第三方外挂功能,应该如何定位他? 如下图:
首先,该函数位于Mail.dll模块中,而非主模块。那么该函数的地址,肯定是每次加载都会进行一个变动的,跟外挂动态加载比较接近,刚好用来练手。
既然在非主模块,就需要先将Maill.dll进行一个内存拷贝,将内存复制出来后,再进行特征搜索。而OD观察,该模块的大小为 0x2b0000,我们需要拷贝的大小,即为模块大小。那么如何用代码实现,非常简单:
GetModuleHandle(Mail.dll)
BOOL ReadProcessMemory(
HANDLE -1,
LPCVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD 0x2b0000,
LPDWORD lpNumberOfBytesRead
);
如此,便将Mail.dll整个模块都拷贝出来存放在lpBuffer,大小为0x2b0000。
接下来对lpBuffer进行一个特征搜索,对其定位,如果在特征库中匹配到,就说明该dll被劫持了。既然是匹配,肯定要有一个特征,那么,该函数的特征是什么呢?
所谓的特征,即死码,不经常发生变化的,观察下该函数可以有哪些“死码”:
从1692B5C8 开始,可用作特征的机器码为(十六进制 ??代表可能发生变化的):
75 29 8B 45 ?? ?? ???? 8B ?? 50 ?? ?? ?? ?? ?? 57 ?? ?? ?? 8B CE E8 ?? ?? ?? ??.
得到这串特征码后,在lpBuffer中搜索匹配,如果匹配到,代表Dll可能被劫持,那么就出现第三方,木马加载等等。
那么如何搜索匹配上面的字符串呢?非常简单,以易语言和汇编代码为例子:
易语言代码:
翻译成汇编代码:
[ebp-n]
分别代表
被搜索的代码段(lpBuffer)
欲搜索的特征码
开始搜索的位置
' mov edi,[ebp-4]
' mov ecx,[ebp-8]
' mov esi,[ebp-12]
' mov edx ,[esi-04]
' xor eax,eax
' @for:;循环
' test ecx,ecx
' jz @over;搜索完成
' mov al,[esi+1]
' repne scasb
' jnz @over;搜索完成跳到失败;
' mov ebx,2;首个字符串匹配成功,开始匹配其他字符串
' @for2:;子循环
' mov al,[ebx+esi];取对应位置
' mov al,[eax+edi];将被搜索字节集对应位置的值取出来
' cmp al,[ebx+esi+1];与搜索的字节集对比
' jnz @for;子串对比失败,跳到开始位置
' add ebx,2;子串对比成功加2继续对比
' cmp ebx,edx;判断子串是否对比完成
' jnb @end;比较完成成功了
' jmp @for2;子循环继续
' @over:;失败
' mov eax,-1
' mov esp,ebp
' pop ebp
' retn 10
' @end:;成功
' sub edi,[ebp-4]
' mov [ebp-4],edi
例子二:
相信易语言很多人都不陌生,开发的本意是中文编程能让更多人学习和了解编程,而近年来大多数人听到易语言的第一反应,就是外挂。很多游戏公司,干脆将所有易语言程序都定位为外挂,只要你开了易语言所写的程序,就会产生“误封”。那么如何通过“特征”来判断一个程序是不是易语言所写的呢?非常简单。
易语言很多函数都是封装好的,拥有着特定的死码,列如易语言的窗口程序,入口函数可以为_启动窗口的函数名,该函数有着特定的死码,游戏公司只要定位这个特征码,几乎绝大多数易语言所写的窗口程序都会被判定为外挂,而想要改变这些易语言的特征码,也是可以的,只是相对来说,工程量较大。