BinDiff二进制比较简介

一、背景介绍

分析过old.so,做了大量繁琐的逆向工程,比如自定义了很多数据结构、重命名了很多函数。现在有new.so,想充分利用old.so的已有逆向成果。比如,想从old.i64迁移一批名为”Private_*”的函数名到new.i64中。再比如,已经卸掉old.so中的过期时间检查,想快速定位new.so中匹配代码,对之进行静态Patch。二进制比较工具正是为解决此类需求而生的。有相当大的应用场景是补丁分析,以此研究某个未公开细节漏洞的技术原理。

网上有很多BinDiff的使用介绍,本文没有新意。最近重新用到它,好久不用,手有些生,做点笔记。

二、环境准备

以Win10+IDA 7.6.1+BinDiff 7为例。

bindiff7.msi缺省安装到

C:\Program Files\BinDiff\

大多数Windows快捷方式的右键属性中可以看到真实目标程序,但有些快捷方式右键属性其目标栏是灰掉的,不可编辑,也看不出真实目标程序,比如”BinDiff 7″安装后的快捷方式就是这样。

若对此有好奇心,参看:

与BinDiff 4.2不同,BinDiff 7自带JRE环境

$ “C:\Program Files\BinDiff\jre\bin\java.exe” -version

openjdk version “16” 2021-03-16

OpenJDK Runtime Environment Zulu16.28+11-CA (build 16+36)

OpenJDK 64-Bit Server VM Zulu16.28+11-CA (build 16+36, mixed mode)

启动BinDiff 7,实际执行

“C:\Program Files\BinDiff\jre\bin\javaw.exe” -Xms128m -Xmx48987m -jar “C:\Program

Files\BinDiff\bin\bindiff.jar”

符号迁移

假设已有old.i64、new.i64,上述GUI可以直接对二者进行比较,生成比较结果。该过程不再依赖IDA,但还得用IDA打开保存后的比较结果,以进行有效查看。可以用上述GUI生成比较结果,也可以直接在IDA中用BinDiff插件生成比较结果,显然更推荐后一种用法。

为了在IDA中加载前述比较结果,需要向IDA安装相应BinDiff插件。我的IDA是绿色处理过的,注册表里没相应项,安装bindiff7.msi时不会自动向IDA目录复制BinDiff插件。

$ dir /B “C:\Program Files\BinDiff\Plugins\IDA Pro”

bindiff7_ida.dll

bindiff7_ida64.dll

binexport12_ida.dll

binexport12_ida64.dll

将这四个插件复制到

X:\Green\IDA\plugins\

这是两组插件,前两个是BinDiff插件。

参看

上文介绍的技术主要用于识别库函数,本文原始需求有所不同。假设old.i64中含有大量重命名过的函数,new.i64对应一个较新版本二进制,现在想充分利用old.i64中已有信息,利用二进制比较技术进行函数识别、符号迁移。07到09年间,我们部门用的是hume开发的nsdiff,现在我只能用BinDiff了。关于BinDiff 4.2的使用,参看:

BinDiff 7与BinDiff 4.2差别不大。先用IDA打开new.i64

Edit->Plugins->BinDiff (Ctrl-6)->Diff Database->选中old.i64

比较结束后会打开四个窗口

我一般将它们全关掉,然后在适当的子区域打开想查看的结果窗口。绝大多数情况下,只需要关心”Matched Functions”。

View->BinDiff->Matched functions

假设old.i64中有大量重命名为”Private_*”的函数,对”Name Secondary”列排序后可以集中看到它们。

“Matched Functions”窗口右键菜单->Modify filters (Ctrl-Shift-F)

可以设置多种过滤规则,比如”Name Secondary”以”Private”开头、大小写敏感。之后批量选中待迁移函数所在行,在右键菜单中选”Import symbols/comments”,将从old.i64迁移函数名、注释到new.i64。

另有”Import symbols/comments as external library”,区别是迁移过来的符号被当作库函数,在反汇编窗口显示的颜色不同。一般没啥用。

为了避免误导,只从old.i64迁移那些绿色、高相似度、高可信度的函数名到new.i64。可以在过滤之后对Change列排序,优先迁移Change列显示为”——-“的函数名。

用BinDiff迁移符号的要点是,先打开new,再比较old,最后右键Import符号。从前hume的nsdiff可以双向迁移符号,所以一直习惯性先打开old,但这个习惯会导致BinDiff迁移符号失败。

四、寻找匹配代码逻辑

假设已记录了old.i64中的虚拟地址,对应某个感兴趣的代码逻辑,现在想快速找到new.i64中相应虚拟地址。

假设old.i64中有如下代码片段,现在想找出new.i64中对应点。

用IDA打开old.i64,检查0x7fffed29922c所在函数名,假设为Private_func_a()。关闭old.i64,否则后面的BinDiff操作无法继续。

用IDA打开new.i64,与old.i64比较。在BinDiff的”Matched Functions”中找到Private_func_a()所在行,右键”View flow graphs”。

参看”BinDiff Manual”的”Function Flowgraphs”及”A basic walk-through Analyzing a Microsoft Patch”小节

在secondary中输入7fffed29922c,不要输0x前缀,选中0x7fffed29922c,此时所在block变色。

选中block,右键”Zoom to Basicblock”,放大所在block。

点击”Fit Graph Content”可以恢复原大小,或者

Graphs->Fit Graph (Ctrl-Shift-M)

点击”Toogle Proximity Browsing”可以切换显示模式,此时只显示目标块附近的一些块,缺省显示所有块。对于复杂函数,这种切换有助于聚焦目标块。或者

Mode->Proximity Browsing (F6)

在primary中选中匹配block,右键”Copy Basic Block Address”,假设是0x7fffed08d4a8。在new.i64中查看0x7fffed08d4a8附近代码

上例0x7fffed29922c正好位于block边界上,若不在block边界上呢?

假设old.i64中某处检查时间的代码逻辑位于Private_func_b()中

BinDiff中图形化比较Private_func_b()

Search->Jump to Secondary Address (Ctrl-Shift-J)

输入7fffed3383b1,不要输0x前缀。然后在primary中查看匹配block,与0x7fffed3383b1对应的地址是0x7fffed130b20,new.i64中匹配代码是

版权声明

本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author

C/ASM程序员

Leave Comment