BinDiff二进制比较简介
2021-09-13 21:52:09 Author: mp.weixin.qq.com(查看原文) 阅读量:213 收藏

创建: 2021-09-13 13:35
http://scz.617.cn:8/misc/202109131335.txt

目录:

☆ 背景介绍
☆ 环境准备
☆ 符号迁移
☆ 寻找匹配代码逻辑

☆ 背景介绍

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

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

☆ 环境准备

以Win10+IDA 7.6.1+BinDiff 7为例。

https://www.zynamics.com/bindiff.html
https://www.zynamics.com/bindiff/manual/index.html (在线文档)
https://www.zynamics.com/software.html
https://storage.googleapis.com/bindiff-releases/updated-20210607/bindiff7.msi

bindiff7.msi缺省安装到

C:\Program Files\BinDiff\

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

若对此有好奇心,参看:

《Standard Shortcuts/Advertised Shortcuts》
http://scz.617.cn:8/windows/202109091619.txt

与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插件。

参看

《IoT设备逆向工程中的函数识别》
http://scz.617.cn:8/misc/201905081756.txt

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

《浅析Nessus、Nmap针对MS17-010的远程精确扫描方案》
http://scz.617.cn:8/windows/201706221521.txt

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

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

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

Matched Functions

    在new.i64old.i64中相匹配的函数

Statistics

Primary Unmatched

    在new.i64中存在,但在old.i64中未找到匹配

Secondary Unmatched

    在old.i64中存在,但在new.i64中未找到匹配

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

View->BinDiff->Matched functions

单行颜色

    越绿表示相似度最高,越红表示相似度越低

Similarity

    [0,1]区间的值,指明new与old的相似度。1表示完全一样。

    缺省对Similarity降序排列显示

Confidence

    [0,1]区间的值,指明Similarity的可信度,值越接近1表示Similarity可信度越高。Confidence实际代表了识别算法的强弱。

    高Similarity、低Confidence表示一个弱算法找到一个强匹配

    低Similarity、高Confidence表示一个强算法找到一个弱匹配

    显然,强算法找到的强匹配是最佳匹配

Change

    "-------"表示newold相比没有变化,其他可取值见下

    G   Graph

        there have been structural changes in the function. Either the number of basic blocks or the number of edges differs or unmatched edges exist.

    I   Instruction

        either the number of instructions differs or at least one mnemonic has changed.

    O   Operand

        not yet implemented

    J   Jump

        indicates a branch inversion.

    E   Entrypoint

        the entry point basic blocks have not been matched or are different.

    L   Loop

        the number of loops has changed.

    C   Call

        at least one of the call targets hasn't been matched.

EA Primary / Name Primary

    new.i64中地址、函数名

EA Secondary / Name Secondary

    old.i64中地址、函数名

Algorithm

    识别算法

假设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中对应点。

00007FFFED29922C mov     raxcs:off_7FFFED4ABA20
00007FFFED299233 mov     rbx[rax+rdx*8]
00007FFFED299237 mov     raxcs:off_7FFFED4ABA30

用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"小节

BinDiff displays functions from IDA as highlighted flowgraphs with colors indicating special properties of edges and code blocks.

Green arrows

    represent conditional branches that need to satisfy a certain condition to be taken

Red arrows

    represent conditional branches if the branch condition is not met as well as unconditional branches.

Green nodes

    indicate basic blocks that have identical instruction mnemonics in both executables (although operands to individual assembly instructions might have changed)

Red nodes

    indicate basic blocks to which our comparison algorithms were unable to find equivalents.

Yellow nodes

    indicates nodes for which the algorithms could find equivalents, but which had some instructions changed between versions.

在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附近代码

00007FFFED08D4A8 mov     raxcs:off_7FFFED2AA3E8
00007FFFED08D4AF mov     rbx[rax+rdx*8]
00007FFFED08D4B3 mov     raxcs:off_7FFFED2AA3F8

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

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

00007FFFED3383B1 mov     rdx, [rcx+200h]
00007FFFED3383B8 add     rdx, 86400
00007FFFED3383BF cmp     rdx, rax

BinDiff中图形化比较Private_func_b()

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


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

00007FFFED130B20 mov     rdx, [rcx+200h]
00007FFFED130B27 add     rdx, 86400
00007FFFED130B2E cmp     rdx, rax

BTW,我真地是程序员,不是天桥茶馆的说书人。


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247484796&idx=1&sn=934342904ecbd17120b02f0cc5f25cfc&chksm=fab2c643cdc54f55a08bc0ab64c5218f76c27333e63af6945669c3ead6ea70ccba1ee64f72fe#rd
如有侵权请联系:admin#unsafe.sh