再谈逆向工程中的函数识别
逆向工程中一般使用bindiff等工具进行二进制比较,常用来进行windows补丁分析,也可以用来函数识别。
分析一个被strip过的,不包含调试信息和符号信息的ELF,最难地莫过于怎样确定库函数了。常用的函数识别技术主要牵涉2类:一是IDA自身的FLIRT技术,二是rizzo技术。
1、FLIRT技术
FLIRT是”Fast Library Identification and Recognition Technology”的缩写。这是IDA自带的一种函数识别技术。它为静态库中每个函数确定其特征字节流、特定调用关系、特定检查项等等,以此识别出对应函数。将各函数名及其识别特征按特定格式组织并存放在签名文件中,形成扩展名为.sig的签名文件。IDA在分析ELF时,可以加载.sig,自动识别ELF中静态链接进来的库函数。
定制签名文件的一般流程是:
ELF->PAT->SIG
windows下为myLib.lib制作sig文件的一个示例:
pcf.exe myLib.lib myLib.pat
sigmake.exe myLib.pat myLib.sig
Linux下为静态库libc.a制作sig的示例如下
pelf libc.a libc.pat
sigmake libc.pat libc.sig
上述pcf.exe, sigmake.exe、pelf等为FLAIR工具集里的工具。FLAIR可在IDA SDK中获取。
2、rizzo
rizzio是另一套启发式函数识别标准,它检查函数对特征字符串的引用、对特征常量的引用、CFG等。这些检查项受编译器、编译选项、源代码版本影响较小。
rizzo的工作流程是:
IDB A -> RIZ -> IDB B
rizzo.py是IDA插件,将之复制到plugins目录,重启IDA即可。
https://github.com/fireundubh/IDA7-Rizzo
上述版本的rizzo可应用到IDA 7.0。
导出.riz:
File -> Produce file -> Rizzo signature file
加载.riz:
File -> Load file -> Rizzo signature file
下面仍然以看雪·安恒2020KCTF春季赛第2题 子鼠开天(https://ctf.pediy.com/game-season_fight-136.htm)来说明函数识别的步骤
(1)查看程序的编译器信息

程序采用VC6.0编译。
另外,如果程序为linux下的elf文件,则可以用readelf查看.comment段

譬如,上述format程序采用GCC 5.4.0编译,运行在Ubuntu 5.4.0-6或Ubuntu 16.04.11系统下。
(2)查找字符串,确定开源库的源代码版本

从网上下载OpenSSL 0.9.8zh版本的源码
https://github.com/openssl/openssl/archive/OpenSSL_0_9_8zh.zip
结合第(1)步的结论,用VC6.0将其编译为dll文件,最终生成libeay32.dll、ssleay32.dll。
IDA打开这些dll文件,发现libeay32.dll才是加密函数的主体部分,ssleay32.dll不过是SSL相关的函数,因此之后我们只会用libeay32.dll。
(3)为libeay32.dll导出sigature文件,假设文件名为openssl.riz
File -> Produce file -> Rizzo signature file
(4)IDA 7.0打开keygenme_1,应用openssl.riz
File -> Load file -> Rizzo signature file
最后output窗口会显示如下信息

正式识别了80个函数,晦涩难懂的sub_ 401210的识别效果如下

是不是跟阅读自己写的代码一样,兴奋吧?
虽然rizzo号称受编译器、编译选项、源代码版本影响较小,实际上影响还是挺大的。为了验证,我将上述openssl 0.9.8zh源码用VS 2008编译一次,根据VS 2008生成的dll文件生成rizzo签名文件,应用时output窗口显示的信息如下

这次正式识别了12个函数,sub_ 401210的识别效果如下

核心函数都没有识别出来。因此确定编译器版本、源代码版本对于函数识别影响很大。
现在再说说用FLIRT识别这个程序的情况:
将openssl 0.9.8zh用VC6编译为libeay32.lib、ssleay32.lib,分别用pcf.exe、sigmake.exe生成模式文件和签名文件,应用签名时,结果却是

白忙一场,没有任何效果
总结: rizzo的函数识别效果比FLIRT的效果要好,如果用FLIRT的签名文件没有识别出函数千万别放弃,兴许rizzo能让你柳暗花明又一村。