
我昨天终于把Ghidra打开了,不是下载完就扔桌面的那种,是真的点开一个自己写的“密码校验小程序”,找到了main函数,还看懂了那行cmp eax, 12345678h——原来它真的在拿我输的数字跟内存里存的值比。没用IDA,没看破解视频,也没人教,就照着一份小白写的四步清单,花了三小时,干成了。
以前总以为逆向是黑进微信改红包,后来才知道,连自己编译的exe点双击后怎么开始跑,都稀里糊涂。它先加载到哪块内存?参数放哪?返回地址藏在哪?没人问我这些,我也根本不会问。直到有次调试时在x64dbg里看到RSP指针突然跳了一下,我才意识到:哦,原来函数调用不是魔法,只是寄存器挪了挪位置。
学汇编不用背指令,记五个寄存器够用。EAX存结果,ESP管栈顶,EBP当栈底锚点,ECX常作循环计数,EDX配合EAX做除法。我写了个for循环,gcc -S生成.s文件,左边C代码,右边汇编,中间用铅笔画箭头连变量名和寄存器,连三次就明白为什么局部变量叫local_10——因为从RBP往下数16个字节,就是它。

strings命令比我想象中好用。直接拖一个exe进去,回车,满屏乱码里真能找到“Access Denied”“please input password”。原来字符串真就躺在.data节里,没加密,没隐藏,只是我们以前懒得看。用PE Explorer点开,切到“String References”,双击就能跳到汇编位置。这不是破译,是查户口。
Ghidra反编译出来的C代码看着像,但变量名全是local_8、param_1,第一次看真懵。后来试着手动重命名:把local_10改成input_buf,把param_2改成key_ptr,整段逻辑突然顺了。命名不是小事,是大脑在给未知贴标签。你不愿起名,说明还没真正看懂它。
卡得最狠那次是打开一个程序全是??,IDA报错。查了才知道是UPX壳。没硬刚,先用file命令扫一眼,再下Detect-It-Easy,扫出UPX 3.96,接着upx -d解包,再拖进去——这次有东西了。不是所有程序都要硬啃,识别壳比脱壳更重要。

调试不等于狂按F9。我在scanf后设断点,停住,AG庄闲和游戏看RSP指向的栈位置,手输的字符串真就躺在那里。再看RDI,里面是字符串首地址——原来printf(“%s”, buf)里buf传进去,真就是把地址塞进RDI。不用记规则,看一次记一辈子。
学的时候别贪多。我删了所有公众号收藏夹,只留Ghidra官方help文档、x64dbg快捷键图、还有自己写的三行笔记:“1. 程序跑在内存里,不是真空里;2. 函数调用=压栈+跳转+弹栈;3. 所有高级语法,最后都是mov/call/jmp”。写在便签上,贴在显示器边。
上周我只干了一件事:搞懂printf在Linux x64下怎么传参。前两天还不知道rdi、rsi、rdx是干啥的,现在知道第一个字符串地址进rdi,第二个进rsi,第三个进rdx。不为破解啥,就为确认一件事:机器没骗我,它真按文档写的干。

第一个完整项目是分析busybox里的ls。没看源码,只用Ghidra打开静态编译版,定位main,顺argv[1]找到strcmp调用,发现-h分支跳转到help函数。然后自己输ls -h,再进gdb看同一位置,果然停住了。两次操作,一次验证,心里踏实了。
工具装太多反而不知道用哪个。我就留三个:Ghidra看结构,x64dbg跟运行,VS Code写笔记加注释。Python偶尔跑个strings过滤,没别的。学不会的时候就关掉所有窗口,重开一个终端,敲file ./a.out,就这一个命令,看三遍,再开。
有次调试卡住两小时,最后发现是自己忘了在main开头设断点,程序一闪就结束了。没骂工具,也没骂自己笨,就截图存下来,标题写:“2024年9月17日,第7次搞丢main入口”。

现在我不怕看到汇编了。看到jmp,先找它跳去哪;看到call,就查栈顶有没有返回地址;看到mov eax, dword ptr [ebp-4],就知道这是在取一个int型局部变量。不是全懂,是知道下一步该看哪。
逆向不是为了改程序,是为让自己别再当个瞎子。程序跑起来的时候,内存在动,寄存器在变,栈在涨落——这些事一直发生,只是以前没人告诉我可以去看。
我今天又打开了那个密码程序。没改一行代码,只是在Ghidra里把main函数右侧的Decompile窗口,手动把v1重命名为user_input,把v2改成stored_key。改完那一瞬间,代码读起来,像人话了。
