Reverse Engineering Techniques - Detect open source Libraries and its functions
About articles in old-blogpost: These pages are old and migrated in gitbook without translation. Probably I will translate them in the future.
在各种逆向工程项目以及CTF竞赛题目中,很多都会用到开源库,例如LuaJIT中集成的Lua解释器,和OpenSSL、zlib等常用的库。很多库都有十分复杂的逻辑,在逆向过程中如果详细的去分析便会加大很多工作量,而且很多的逻辑会应用到数学、密码方面的知识,如果缺乏这些理论知识基本没有办法去逆向这些程序。那么这时候对于各种库函数的识别便会变得十分重要,这篇文章主要介绍两种方式对开源库函数进行识别。
首先说一下大体的思路,我们既然找到了开源库,那么在程序中用到的很多函数 的代码逻辑基本上和库里是相同的。也就是说,我们拿到了程序的部分源代码,但是并不知道这些源代码分别对应程序中的哪一个部分。如果我们可以找到对应的函数,就可以通过查阅开源库的源代码、函数名(符号)、开发文档去了解函数的功能。本篇文章要介绍的两种方式均是以这种思路去展开。
BinDiff是一款用于比对IDA数据库中的函数代码相似度的自动化工具,识别出的代码相似度越高,实现相同逻辑的可能性就越大。换句话说,就是将函数名与程序中的函数体进行匹配的工具。
Java SE Development Kit
首先需要安装JDK,笔者这里用的是JDK 11,在Oracle的官网即可下载安装。
IDA Pro
BinDiff是通过IDA生成的数据库进行的匹配,IDA Pro产品需要购买才可使用,是一款十分强大的逆向工具,笔者这里使用的是IDA 7.6版本。
BinDiff
注意:安装过程中会让你选择IDA的路径,此时要选择你的IDA工具(ida.exe/ida64.exe)的所在目录
若要使用BinDiff工具,需要提供另一个idb数据库作为比对。
在此我们首先使用IDA打开被分析程序的数据库,然后File->BinDiff中选择要比对的idb数据库即可
等待一段时间后便可以在Matched Functions中得到匹配结果。

在左侧的sub_XXXX这些没有被命名的函数便可以通过这种方式找出对应的函数名。
在这里使用Defcon Final 2021 - Barb Metal举例。(题目地址:https://github.com/o-o-overflow/dc2021f-barb-metal-public )
这道题使用了mrubyc库实现了一个虚拟机,并对虚拟机的代码进行了加密,题目要求在虚拟机代码中寻找漏洞得到flag。
在此我们只进行相关库的匹配。
第一步是寻找库的特征,例如OpenSSL中的字符串,编译时添加的Assertion信息等,通过这些信息定位到具体使用了哪个开源库。
直接在IDA中进行字符串的查找,可以得到以下结果,有很多的代码路径信息。


直接进入Google搜索LibTomMath、mrubyc,以及代码的路径信息。
得到以下三个开源库,均托管在Github:
第二步,将开源库编译成相同架构的二进制库文件,这里是Linux下的x86架构程序

这里要注意的有两点,第一点是一定要在32位环境下编译(如果在64位环境下需要在CFLAG上加-m32参数),因为我们要逆向的文件是32位的。第二点是,如果要在比较方便的情况下使用BinDiff,就需要将静态链接库(ar)转化为动态链接库(so),因为静态链接库实质是一个压缩包,里面有很多编译后的库文件,那么每个库文件就需要一个idb去存储它的代码信息。而动态链接库只需要一个idb即可,因此我们尽量使用动态链接库的方式生成二进制文件。
修改Makefile文件,以mrubyc为例
这样make后的结果便 是libmrubyc.so这一个动态链接库文件
以此类推,继续编译LibTomCrypt和LibTomMath库,最终我们得到了三个so文件


分别导入IDA生成对应的idb,使用BinDiff选中进行分析
但是对于libTomCrypt和libTomMath,BinDiff便有些鸡肋了。


通过BinDiff,我们的分析便会变得十分简单,例如如下函数

同时mrubyc的opcode也一清二楚
对于BinDiff就介绍这么多,这款自动化工具十分好用,对于各种开源库的识别十分有帮助,当然,选择开源库的版本也十分重要,最好是要让所有库的版本都和待逆向程序的版本相同,这样才能提高匹配度。
当时做这道题的时候还没有学会使用BinDiff,而且通宵比赛,我的体力也跟不上,几个小时只能勉强逆向出这一堆opcode,后面和源码一比较发现什么都没变,也就是说我这几个小时什么都没逆出来。。。后来pizza醒了,把idb传到队伍里之后趴在桌子上歇了一会儿,估计pizza看到我这idb要气疯了(逃
如果BinDiff这种自动化工具不是很有效的匹配函数,那么我们只能通过手动的对照源代码来分析每个函数的作用了。
拿刚刚的LibTom举例,我们可以得到的信息有源码所在目录和文件,甚至是本行的代码或是Assertion信息,有的函数说不定直接把函数名信息写在了里面。通过这些信息去定位源代码的位置函数,可以用来匹配函数符号。
