打开Ai,让Ai给你生成一个x64的windows 要求输入许可证的程序,不要防护,就要一个简单的验证m 因为我们的目的是在熟悉完整的流程。
本次分析目标是一个 Win32 GUI 注册码验证程序。
程序运行后弹出一个窗口,要求输入 ESN 注册码,
目标是通过静态分析找到正确的注册码,不修改程序、不动调试器。
工具:Ghidra 11.0.3
方法:纯静态分析
14001abb0 unicode u"https://discord.gg/KWFrnnqBQu"为什么从字符串入手
注册码验证程序有一个天然的弱点:
正确的注册码必须存在于程序内部某处,用于和用户输入做比对。
字符串常量在编译后存储在 PE 文件的 .rdata(只读数据)段,
不会被混淆,明文可见。
对于入门级程序,这是最快的分析路径:
找到注册码字符串 → 追踪引用 → 定位验证函数 → 分析逻辑现在我们进行定位字符串地查看引用 [ 1400labb0 ]
关闭String Search 窗口 然后在ghidra主窗口G键,输入地址:14001abb0 ,跳转到.rdata段。
然后在搜索到的
1400117f0MOV RDX=>u_https://discord.gg/KWFrnnqBQu_14001abb0,qword ptr [PTR_u_https://discord.gg/KWFrnnqBQu_14001e000]PARAM👇解释1
14001l7f0 PARAM:这是代码引用,某个函数把这个字符串作为参数传递,这就是验证函数 CheckESN 调用 wcscmp 时传入注册码的那一行
214001e000PTR_u_https://discord.gg/KWFrnnqBQu_14001e000addr u_https://discord.gg/KWFrnnqBQu_14001abb0DATA下👇解释214001e000 DATA:这是数据引用,某个指针指向这个字符串,对应源码中const wchar_t* ESNNO = L"..." 这个全局指针变量
为什么看 XREF(交叉引用)
字符串本身只是数据,存在 .rdata 里不会自己执行。 要找到"谁在用这个字符串",就需要看交叉引用。
如上两个图的解释。我们关心的只有 代码引用 ,所只看第一个。
现在我们到了传统的分析汇编代码时刻。
看图:
这里丢给Ai解释以下最好。
FUN_1400117d0:14001l7d0 MOV qword ptr [RSP + local_res8], param_1 ; 保存参数到栈14001l7d5 PUSH RBP14001l7d6 PUSH RDI14001l7d7 SUB RSP, 0xf8 ; 开辟栈空间14001l7de LEA RBP, [RSP + 0x20]14001l7e3 LEA param_1, [DAT_1400240e8]14001l7ea CALL __CheckForDebuggerJustMyCode ; MSVC 调试检查,忽略14001l7ef NOP14001l7f0 MOV RDX, u_https://discord.gg/KWFrnnqBQu ; ← 注册码装入 RDX14001l7f7 MOV param_1, qword ptr [RBP + local_res8] ; ← 用户输入装入 RCX14001l7fe CALL qword ptr [->UCRTBASED.DLL::wcscmp] ; ← 调用 wcscmp 比较14001l804 TEST EAX, EAX ; ← 检查返回值14001l806 JNZ LAB_140011814 ; ← 不等则跳到失败分支14001l808 MOV dword ptr [RBP + local_28], 0x1 ; ← 等于则设置返回值为 true14001l812 JMP LAB_14001181e14001l814: ; 失败分支...
为什么这样读汇编
x64 调用约定(Windows)规定函数前四个参数依次放入:RCX、RDX、R8、R9wcscmp(param_1, ESNNO)对应:
第一参数(用户输入)→ RCX
第二参数(注册码)→ RDX
所以 MOV RDX, u_https://...就是把注册码字符串地址装入第二参数寄存器, 这行之后紧接着 CALL wcscmp,逻辑非常清晰。wcscmp返回值放在 EAX:
返回 0:两字符串相等
返回非 0:不相等
TEST EAX, EAX等价于 EAX & EAX,结果为 0 则 ZF 标志位置 1。JNZ(Jump if Not Zero):ZF=0 时跳转,即 wcscmp返回非 0 时跳到失败分支。
这是最典型的字符串比较 + 条件跳转结构,是逆向分析中最常见的模式之一。
boolFUN_1400117d0(wchar_t *param_1){int iVar1;__CheckForDebuggerJustMyCode(&DAT_1400240e8);iVar1 = wcscmp(param_1, (wchar_t *)PTR_u_https://discord.gg/KWFrnnqBQu);return iVar1 == 0;}👇表格是对照源码的结果
CheckESN函数 | |
input参数 | |
ESNNO | |
反编译结果与源码逻辑完全吻合,分析正确。 __CheckForDebuggerJustMyCode 是 MSVC Debug 模式自动插入的调试辅助函数, 与验证逻辑无关,忽略即可。Release 模式编译的版本不会有这行。
分析结论:
注册码:https://discord.gg/KWFrnnqBQu
.rdata 段是干什么的——存字符串常量和只读数据
为什么注册码会"裸露"在 .rdata 里——编译器的行为
unicode 和 string 的区别——wchar_t vs char 在内存里的差异
三:x64汇编常识
Windows x64 调用约定:参数怎么通过 RCX RDX R8 R9 传递
TEST EAX, EAX + JNZ 这个组合的含义——最常见的条件判断模式
看到 CALL wcscmp 怎么判断它的两个参数分别是什么
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……




发表评论