哇,我真的想出了足够的 angr 来做到这一点。考虑这个 C 程序(qt_metacall 的一个极其简化的比例模型):
#include <stdio.h>
int foo(void) {
return puts("foo");
}
int bar(void) {
return puts("bar");
}
int baz(void) {
return puts("baz");
}
int frob(int n) {
switch (n) {
case 1:
return foo();
case 2:
return bar();
case 3:
return baz();
default:
return -1;
}
}
int main(int argc, char **argv) {
return frob(argc) < 0;
}
我们编译它,我们使用angr来确定frob的地址,像这样:
import angr
b = angr.Project('a.out', load_options={'auto_load_libs':False})
b.analyses.CFG()
for addr in [f.addr for f in b.kb.functions.values() if f.name == 'frob']:
print hex(addr)
(在我的用例中,我被黑的 QtCore4.dll 将提供要反汇编的 qt_metacall 方法列表)
然后这个脚本,作为 script.py [可执行文件] [调度程序函数的地址] [方法索引] 调用,将打印具有指定索引的方法的地址:
import angr
def main(argv):
executable=argv[1]
dispatcher=int(argv[2], 0)
method_index=int(argv[3], 0)
# Load the executable
b = angr.Project(executable, load_options={'auto_load_libs': False})
# Prepare a call to the dispatcher function, with the method index as its argument
state = b.factory.call_state(dispatcher, method_index)
# Isn't there an easier way to make a closure in Python?!
class CallAddr:
value = None
def on_exit(self, state):
# When the code performs a call, we've found the method that corresponds to the index
if state.inspect.exit_jumpkind == 'Ijk_Call':
# Resolve the address of the exit target, that's our method
self.value = state.se.any_int(state.inspect.exit_target)
method_addr = CallAddr()
# Install breakpoint to analyze "exits" (i.e. jumps)
state.inspect.b('exit', action=method_addr.on_exit)
# Step through the dispatcher function
p = b.factory.path(state)
p.step()
# Keep running until either a conditional or a call
while len(p.successors) == 1 and method_addr.value is None:
p = p.successors[0]
p.step()
# No call was performed, method not found
if method_addr.value is None:
return 1
print hex(method_addr.value)
return 0
if __name__ == "__main__":
import sys
sys.exit(main(sys.argv))
考虑到 angr 有多么强大(以及我使用的它有多么少),感觉就像用核弹杀死蚂蚁,但它确实有效