第五课:让钟自己走——动态分析
对应原书第 5 章《动态分析(GDB / 调试器)》
第五天,小林到铺子时,陈师傅正对着一只走不动的钟发愁。那只钟的齿轮看起来完好无损,表面也没有裂痕。
"师傅,这只钟怎么了?"
"你上回学到,拆开看(静态分析)能找到钥匙。但这只钟不一样——它表面上什么破绽都没有。"陈师傅敲了敲钟面,"它的机关,只有走起来才会露出来。"
"那就让它走啊。"
"说得对!"陈师傅笑了,"今天教你第二件本事:让钟自己走,然后盯着它每一步踩在哪。 我们管这叫'动态分析'。"
陈师傅把钟上好发条,拨到整点前。秒针开始滴答走动。
"你看——"他指着秒针,"它走到 59 秒的时候,会偷偷'停顿'一下,然后才咔哒到整点。这个停顿,静态看永远发现不了。只有让它走,才能看见。"
"那程序呢?"
"程序也一样。很多机关,只有运行起来才暴露。我们给它'上好发条',然后一步一停地盯着它。"
课程正文
动态分析 = 运行程序,观察它的行为。和静态分析(第 2-4 课)互补:静态看结构,动态看行为。
第一件工具:让程序"自报家门"(ltrace/strace)
上回我们学的 ltrace 就能让程序"说真话"。再复习一下,这次加深:
ltrace ./程序 # 跟踪它调用了哪些库函数
strace -f -s 500 ./程序 # 跟踪系统调用(-f 跟子进程,-s 显示长参数)
记住:strcmp 这类"比较函数"被调用时,两个参数一目了然——答案经常直接露出来。
第二件工具:GDB(调试器)
GDB 是"放大镜+慢动作":
gdb ./程序
(gdb) b main # 下断点:跑到 main 就停
(gdb) r # 运行
(gdb) s / n # 单步(一步一步走)
(gdb) c # 继续
(gdb) x/s $rsi # 查看寄存器指向的字符串
(gdb) x/20gx $rsp # 查看栈上的 20 个值
(gdb) quit
核心技巧:断在比较点(第五课的重点)
还记得第三课的三板斧吗?strcmp(你的输入, 钥匙) —— 动态分析的用法是:
1. 在 strcmp 上下断点: b strcmp
2. 运行: r
3. 程序停在比较那一刻
4. 看两个参数: x/s $rdi(你的输入) x/s $rsi(钥匙!)
$ gdb -q ./程序
(gdb) b strcmp
(gdb) r
Breakpoint 1, strcmp ()
(gdb) x/s $rsi
0x4052a: "s3cr3t_k3y_2024" ← 钥匙直接出现在眼前
一行搞定(不进入交互):
gdb -q -ex "b strcmp" -ex "run" -ex "x/s \$rsi" -ex "quit" ./程序
陈师傅的比喻
"静态分析是看图纸,动态分析是看表演。图纸上画不出的毛病,一表演就露馅。最好的钟表匠,两种都看。"
本课口诀
让钟自己走,断在比较点——它自己会把钥匙递到你面前。
动手做
- 对一个密码验证程序,用
ltrace和 GDB 两种方式找出钥匙,对比体验。 - 练习
b strcmp+x/s $rsi三板斧,直到闭着眼能敲出来。 - 想一想:如果程序把钥匙藏进算法里(不是直接比较),断点还找得到吗?(下节课见)
想学更深的
见原书 第 5 章《动态分析》——有内存转储、条件断点、watchpoint、rr 反向调试等进阶玩法。