我有二进制A,这是一个带有随附符号的调试版本——多年前构建的。我也有二进制B ,一个没有附带符号的发布版本,并且是更新的。我正在寻找将二进制 A 中的符号与二进制 B 中的潜在候选匹配的最有效方法。
鉴于调试版本要大得多(进行更多的输入验证,打印更多的东西stderr
等)并且函数总是随着时间而变化,我认为尝试对各个函数进行指纹识别将浪费时间。
因此,我已经决定 - 完全凭空,所以我可能会叫错树 - 指纹函数的最佳方法是创建两个二进制文件的调用图并尝试匹配顶点(即职能)。
我已经做了一些预处理,所以我有以下数据结构:
# binary A
[[60, 60, 8734], # function 0 is called by functions 60 (twice) and 8734
[193, 441, 505], # function 1 is called by functions 193, 441 and 505
[193, 742],
[23],
[21],
[21],
[26],
[26, 1508, 1509, 1573],
[24],
[25],
...] # (~10k functions)
# binary B
[[8999], # function 0 is called by function 8999
[9016], # function 1 is called by function 9016
[1126],
[7904, 7904, 7913],
[182, 336, 396, 396],
[9010],
[407],
[182, 632],
[20],
[24],
...] # (~10k functions)
需要注意的重要一点是,二进制A中的函数“0”和二进制B中的函数“0”之间没有对应关系。这些是我为每个二进制文件中的每个函数分配的任意 ID。
下一步是让我感到困惑的。我的算法很弱,我想不出一个聪明的方法来继续。我(非常有限)的理解是,为了解决这个问题,我想采用某种形式的不精确图形匹配。换句话说,哪一组映射 Ai -> Bi 将使两个调用图的相似性最大化?
鉴于二进制A中有额外的调试功能,并且程序随着时间的推移而发展的明显事实,可能没有完全匹配。理想情况下,我想要以下形式的输出:
[[(37, 0.998), (8432, 0.912), (442, 0.75)], # matching-ness of function "0" in binary A with function "37" in binary B is 0.998, second most likely candidate is function "8432" in binary B with score 0.912, etc.
[(42, 0.973), (7751, 0.788)], # matching-ness of function "1" in binary A with function "42" in binary B is 0.973, second most likely candidate is function "7751" in binary B with score 0.788, etc.
[(4579, 0.996), (123, 0.934)],
...] # around ~10k mappings
实际上,如果我只需要一名候选人并且没有提供排名,我会很高兴,但可以梦想。
任何 SO-goers 都知道我应该从哪里开始?