在 Linux 下进行反汇编并分析“函数调用(call / 调用关系)”,通常可以按下面几个层次来做。
objdump(最基础)objdump -d ./a.out
或针对某个函数:
objdump -d -M intel ./a.out | grep -A 30 "<main>:"
-d:反汇编-M intel:Intel 语法(比 AT&T 好看)call 指令就是函数调用示例:
call 0x401136 <foo>
或
call rax
gdb(动态看调用)gdb ./a.out
(gdb) disassemble main
(gdb) break main
(gdb) run
(gdb) stepi
查看调用栈:
(gdb) backtrace
(gdb) info frame
nm / readelf(看符号)nm ./a.out
readelf -s ./a.out
401125: call 401136 <foo>
说明:
401125 处调用了 foofoo 的地址是 401136如果函数是动态调用:
call rax
说明调用目标在运行时才确定(虚函数、函数指针)
(gdb) bt
#0 foo ()
#1 main ()
这就清楚知道:
main 调用了 foo常见函数开头:
push rbp
mov rbp, rsp
sub rsp, 0x10
或(优化后):
endbr64
返回:
ret
objdump + 地址objdump -d ./a.out | less
然后搜:
callretgdb + 断点(gdb) break *0x401136
(gdb) run
(gdb) bt
ftrace(内核/用户)用户态可用:
uftrace ./a.out
IDA / Ghidra(推荐逆向)C:
void foo(){}
int main(){
foo();
}
反汇编(Intel):
main:
call foo
ret
如果你愿意,可以告诉我:
我可以直接帮你分析具体反汇编代码。