论文复现_LibAM: An Area Matching Framework for Detecting Third-Party Libraries in Binaries

1. 引言

LibAM 是一个用于第三方库(Third Party Library,TPL)检测的区域匹配框架,该框架将独立的函数连接到函数调用图(Function Call Graph,FCG)上的函数区域(Function Area,FA),并通过比较这些 FA 的相似性来检测 TPL,从而显著减轻不同优化选项和架构的影响。LibAM 的原理图如下图所示。

LibAM 的源代码可从 Github下载,源代码的结构如下图所示。

2. preprocess 代码分析

binary_preprocess_module.getAllFiles(DATA_PATH+"2_target/timecost", DATA_PATH+"1_binary/target", DATA_PATH+"2_target/", mode="1")
binary_preprocess_module.getAllFiles(DATA_PATH+"3_candidate/timecost", DATA_PATH + "1_binary/candidate", DATA_PATH + "3_candidate/", mode="1")

 这部分代码使用 IDA Pro 从 Target Binary 和 TPL Binary 中提取 Target ACFG、TPL ACFG、Target FCG、TPL FCG。代码主要调用了 binary_preprocess.py 中的 getAllFiles(),该方法首先根据 filePath 获取二进制文件的路径,之后通过不同参数的 multi_process_extract() 实现二进制文件特征的提取与二进制文件函数调用图的生成。

注:ACFG 是函数粒度的,FCG 是文件粒度的

multi_process_extract() 的主要功能是通过多个进程处理二进制文件,该函数会调用 extract() 以实现二进制文件的处理。

extract() 的主要功能是实现二进制文件特征和函数调用图的提取,该函数的执行依赖于 IDA 指令的执行如下所示。

ida_cmd = 'TVHEADLESS=1 ' + IDA_PATH + ' -L/data/lisiyuan/work2023/code/libAE/libAE_github/libae/idalog.txt -c -A -B -S\'' + idapython + " " + save_name + '\' ' + os.path.join(bpath, bbianry+"_", bbianry)
s, o = subprocess.getstatusoutput(ida_cmd)

在 IDA 指令中特征提取和调用图的提取可由 idapython 对应的 IDA 脚本(ida_get_features.py,ida_get_func_call.py)实现。

3. embedding 代码分析

embeddings_generate_module.subfcg_embedding(DATA_PATH+"4_embedding/timecost",
                                            DATA_PATH+"2_target/feature",
                                            DATA_PATH+"4_embedding/target_in9_bl5_embedding.json",
                                            model_path=WORK_PATH + "/code/embeddings_generate/gnn-best.pt")
embeddings_generate_module.subfcg_embedding(DATA_PATH+"4_embedding/timecost",
                                            DATA_PATH+"3_candidate/feature",
                                            DATA_PATH+"4_embedding/candidate_in9_bl5_embedding.json",
                                            model_path=WORK_PATH + "/code/embeddings_generate/gnn-best.pt")

embeddings_generate_module.generate_afcg(DATA_PATH+"4_embedding/tar_afcg",
                                        os.path.join(DATA_PATH, "2_target/fcg"), 
                                        DATA_PATH+"4_embedding/target_in9_embedding.json",
                                        model_path=os.path.join(WORK_PATH, "code/reuse_area_exploration/Embeded-GNN/fcg_gnn-best-0.01.pt"))

embeddings_generate_module.generate_subgraph(DATA_PATH+"4_embedding/tar_subgraph",
                                        os.path.join(DATA_PATH, "2_target/fcg"), 
                                        DATA_PATH+"4_embedding/target_in9_embedding.json",
                                        model_path=os.path.join(WORK_PATH, "code/reuse_area_exploration/Embeded-GNN/fcg_gnn-best-0.01.pt"))

embeddings_generate_module.generate_afcg(DATA_PATH+"4_embedding/cdd_afcg",
                                        os.path.join(DATA_PATH, "3_candidate/fcg"), 
                                        DATA_PATH+"4_embedding/candidate_in9_embedding.json",
                                        model_path=os.path.join(WORK_PATH, "code/reuse_area_exploration/Embeded-GNN/fcg_gnn-best-0.01.pt"))

embeddings_generate_module.generate_subgraph(DATA_PATH+"4_embedding/cdd_subgraph",
                                        os.path.join(DATA_PATH, "3_candidate/fcg"), 
                                        DATA_PATH+"4_embedding/candidate_in9_embedding.json",
                                        model_path=os.path.join(WORK_PATH, "code/reuse_area_exploration/Embeded-GNN/fcg_gnn-best-0.01.pt"))

这部分代码使用 GNN 对 Target ACFG、TPL ACFG、Target FCG、TLP FCG 进行嵌入,生成对应的嵌入向量 V(*)。代码调用了 Generate_func_embedding.py 中的 subfcg_embedding()generate_afcg()generate_subgraph()。

subfcg_embedding():加载神经网络模型、遍历测试数据集中的JSON文件,计算每个文件的嵌入特征、记录处理时间并保存嵌入结果、根据条件过滤出特征数量符合要求的数据并生成对应的嵌入。生成 Target ACFG 与 TPL ACFG 的函数嵌入

generate_afcg():创建保存 ACFG 的目录、创建保存 ACFG 的目录、遍历所有函数,检查是否已生成 ACFG、加载对应的 FCG,获取函数的子节点、将生成的 ACFG 保存为 JSON 文件。生成 ACFG 对应的 JSON 文件

generate_subgraph():创建用于保存子图的目录、加载图神经网络模型、读取函数嵌入信息、遍历每个函数,加载相应的控制流图、遍历每个函数加载相应的控制流图、递归地构建子图并计算其嵌入特征、将所有生成的子图存储为 JSON 文件。生成 SUBGRAPH 对应的 JSON 文件

4. func_compare 代码分析

anchor_detection_module.func_compare_annoy_fast_multi(os.path.join(DATA_PATH, "4_embedding/target_in9_embedding.json"), 
    os.path.join(DATA_PATH, "4_embedding/candidate_in9_embedding.json"), 
    os.path.join(DATA_PATH, "5_func_compare_result/score"), 
    os.path.join(DATA_PATH, "5_func_compare_result/score_top50"), 
    os.path.join(DATA_PATH, "5_func_compare_result"),
    os.path.join(DATA_PATH, "5_func_compare_result/embedding_annoy"))

5. tpl_detection 代码分析

save_path = "6_tpl_fast_result/"
anchor_reinforcement_module.tpl_detection_fast_annoy(os.path.join(DATA_PATH, "2_target/fcg"),
                    os.path.join(DATA_PATH, "3_candidate/fcg"), 
                    os.path.join(DATA_PATH, "5_func_compare_result/score/"), 
                    os.path.join(DATA_PATH, save_path+"tpl_fast_result"), 
                    os.path.join(DATA_PATH, save_path+"tpl_fast_area"), 
                    os.path.join(DATA_PATH, save_path+"tpl_fast_time"),
                    os.path.join(DATA_PATH, "4_embedding"),
                    os.path.join(DATA_PATH, save_path+"sim_func_list"),
                    os.path.join(DATA_PATH, "4_embedding/target_in9_bl5_embedding.json"), 
                    os.path.join(DATA_PATH, "4_embedding/candidate_in9_bl5_embedding.json"),
                    os.path.join(WORK_PATH, "code/reuse_area_exploration/Embeded-GNN/fcg_gnn-best-0.01.pt"),
                    DATA_PATH+"4_embedding/tar_afcg",
                    DATA_PATH+"4_embedding/cdd_afcg",
                    DATA_PATH+"4_embedding/tar_subgraph",
                    DATA_PATH+"4_embedding/cdd_subgraph")
TPL_detection_module2.get_result_json(os.path.join(DATA_PATH, save_path+"tpl_fast_result"), os.path.join(DATA_PATH, save_path+"tpl_fast_result.json"))
TPL_detection_module3.cal_libae_result(os.path.join(DATA_PATH, save_path+"tpl_fast_result.json")

6. area_detection 代码分析

if "dataset2" in DATA_PATH:
    reuse_area_detection_module.get_area_result_several(os.path.join(DATA_PATH, "7_reuse_detection_result/reuse_detection_area/"), 
        os.path.join(DATA_PATH, "8_reuse_area_result/reuse_detection_area"), 
        os.path.join(GT_PATH, "area_ground_truth.json"),
        os.path.join(DATA_PATH, "2_target/fcg"), 
        os.path.join(DATA_PATH, "3_candidate/fcg") )
elif "dataset3" in DATA_PATH:
    reuse_area_detection_module.get_area_result_for_each(os.path.join(DATA_PATH, "7_reuse_detection_result/reuse_detection_area/"), 
        os.path.join(DATA_PATH, "8_reuse_area_result/reuse_detection_area_for_each"), 
        os.path.join(GT_PATH, "area_ground_truth.json"),
        os.path.join(DATA_PATH, "2_target/fcg"), 
        os.path.join(DATA_PATH, "3_candidate/fcg") )   

7. 数据集构建

sudo apt-get install xz-utils

 为了全面评估LibAM在不同环境中的准确性,论文利用一个独立的数据集训练模型,并利用三个额外的数据集进行评估。数据集信息如下表所示。

其中,Dataset_ISRD来自ISRD实用的现实世界数据集,该数据集包含来自24个流行开源项目的85个二进制文件,实用x64中的默认优化选项进行编译,并包含74个真正的部分重用。下面将详细介绍如何获取 85 个二进制文件。

minizip-ng:在GitHub 下载 minizip-ng 源码,并通过 cmake 进行编译:

# 克隆 minizip-ng 仓库
!git clone https://github.com/zlib-ng/minizip-ng.git

# 进入项目目录
%cd minizip-ng

# 创建构建目录并进行配置
!cmake -S . -B build -D MZ_BUILD_TESTS=ON

# 编译项目
!cmake --build build

# 测试minizip
!./build/minizip

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name minizip -type f -executable

bzip2:在 sourceware 下载 bzip2 源码,并通过 make 进行编译:

# 克隆 bzip2 仓库
!git clone git://sourceware.org/git/bzip2.git

# 进入项目目录
%cd bzip2

# 编译项目
!make install

# 测试bzip2
!./bzip2 --help

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name bzip2 -type f -executable

xz_utils:在 GitHub 下载 xz_utils 源码,并通过 cmake 进行编译:

# 克隆 xz 仓库
!git clone https://github.com/tukaani-project/xz

# 进入项目目录
%cd xz

# 创建build目录
!mkdir build

# 进入build目录
%cd build

# 编译项目
!cmake ..

!make

# 测试xz
!./xz --help

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name xz -type f -executable

zstd:在 GitHub 下载 zstd 源码​​​​​​,并通过 make 进行编译:

# 克隆 zstd 仓库
!git clone https://github.com/facebook/zstd.git

# 进入项目目录
%cd zstd

# 创建构建目录并进行配置
!make clean

!make

# 测试minizip
!chmod +x ./programs/zstd

!./programs/zstd -h

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name zstd -type f -executable

precomp:在 GitHub 下载 precomp 源码​​​​​​,并通过 cmake 进行编译:

# 克隆 zstd 仓库
!git clone https://github.com/schnaader/precomp-cpp.git

# 进入项目目录
%cd precomp-cpp

# 创建build目录
!mkdir build

# 进入build目录
%cd build

# 编译项目
!cmake ..

!make

# 测试precomp
!./precomp

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name precomp -type f -executable

turbobench:在 GitHub 下载 turbobench 源码​​​​​​,并通过 make 进行编译:

# 克隆 zstd 仓库
!git clone --depth=1 --recursive https://github.com/powturbo/TurboBench.git
!git submodule update --init --recursive

# 进入项目目录
%cd TurboBench

# 创建构建目录并进行配置
!make clean

!make

# 测试precomp
!./turbobench 

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name turbobench -type f -executable

lzbench:在 GitHub 下载 turbobench 源码​​​​​​,并通过 make 进行编译:

# 克隆 turbobench 仓库
!git clone https://github.com/inikep/lzbench.git

# 进入项目目录
%cd lzbench

# 创建构建目录并进行配置
!make clean

!make

# 测试 turbobench
!./lzbench -h

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!find . -name lzbench -type f -executable

lzlib:无法成功编译。LUA

libblosc:无法成功编译。R

exjson:无法成功编译。Erlang

cknit:无法成功编译。

brotli:在 GitHub 下载 turbobench 源码​​​​​​,并通过 cmake 进行编译:

# 克隆 brotli 仓库
!git clone https://github.com/google/brotli.git

# 进入项目目录
%cd brotli

!mkdir out

%cd out

# 编译项目
!cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=./installed ..
!cmake --build . --config Release --target install

# 测试 brotli
!./brotli -h

!find . -name brotli -type f -executable

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

gipfeli: 在 GitHub 下载 gipfeli 源码​​​​​​,并通过 make 进行编译:

# 克隆 gipfeli 仓库
!git clone https://github.com/google/gipfeli.git

# 进入项目目录
%cd gipfeli

# 创建构建目录并进行配置
!make clean

!make

# 测试 gipfeli
!./gipfeli_test

!find . -name gipfeli_test -type f -executable

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

libdeflate:在 GitHub 下载 gipfeli 源码​​​​​​,并通过 cmake 进行编译:

# 克隆 brotli 仓库
!git clone https://github.com/ebiggers/libdeflate.git

# 进入项目目录
%cd libdeflate

# 编译项目
!cmake -B build
!cmake --build build

# 测试 brotli
!./build/programs/libdeflate-gzip -h

!find . -name libdeflate-gzip -type f -executable

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

liblzg:无法成功编译。需要修改编译脚本

lzfse:在 GitHub 下载 lzfse 源码​​​​​​,并通过 cmake 进行编译:

# 克隆 lzfse 仓库
!git clone https://github.com/lzfse/lzfse.git

# 进入项目目录
%cd lzfse

!mkdir build

!cd build

# 编译项目
!cmake ..
!make install

!find . -name lzfse -type f -executable

# 退出项目目录
%cd '/content/drive/MyDrive/TPL_Download'

!./lzfse/build/bin/lzfse -h

zlib-ng:编译成功但未找到可执行文件。

zlib:编译成功但未找到可执行文件。

quicklz:编译成功但未找到可执行文件。

8. TPL 检测复现

TPLsizefunctionpreprocessdetection
minizip-ng340KB-
bzip2291KB1.0000
xz_utils373KB0.6000
zstd1233KB0.6666
precomp2394KB0.7142
turbobench4528KB0.8571
lzbench64849KB×
brotli38KB×0.0000
gipfeli80KB-
libdeflate99KB-
lzfse47KB-

实验结果表明,LibAM 性能并不稳定。除了 bzip2 相关实验,实验结果均低于 90%。对于变动较大的 brotli 精度为 0%。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值