本实训旨在帮助学员掌握动态调试方法,通过实际操作 x32dbg 调试器,分析一个受保护的 Windows 32位 GUI 程序(login.exe),深入理解程序运行时的行为,并学会利用调试技术突破软件保护机制。
本次实训包含两项核心任务,均需完成:
分析样本程序 login.exe 来自学习通本课程"资料"中的 login.zip(注意:不是 login2.zip)。
该程序是一个单机版需要登录的 Win32 GUI 程序,只有一个正确的用户名和密码,当前未知,需要通过调试分析获取。
在 VMware 中编辑 FlareVM 虚拟机设置,将虚拟机内存容量调整到 8GB,以确保调试器和其他工具能够流畅运行。
图:VMware 虚拟机内存设置
将 login.zip 文件拷贝到虚拟机中,使用以下解压密码进行解压缩:
解压后得到样本文件 login.exe。
使用 PEID 工具查看 login.exe 的文件属性,确认其为 Win32 GUI(32位图形界面程序)。这决定了我们需要使用 x32dbg(32位调试器)而非 x64dbg。
图:PEID 显示 login.exe 为 Win32 GUI 程序
在虚拟机中双击运行 login.exe,观察程序界面。程序会弹出一个登录窗口,要求输入用户名和密码。
图:login.exe 登录界面
这是一个单机版需要登录的程序,只有一个正确的用户名和密码,但当前我们并不知道。如果输入错误的凭据,程序会拒绝登录。
由于我们不知道正确的用户名和密码,常规手段无法进入程序主界面。因此,我们需要借助动态调试工具 x32dbg 来分析程序运行时的行为,找出校验逻辑,进而:
在 FlareVM 中找到并运行 x32dbg(32位调试器)。x32dbg 是 x64dbg 的 32 位版本,专门用于调试 32 位 Windows 程序。
图:x32dbg 调试器主界面
在 x32dbg 中,点击菜单栏的 "文件" -> "打开",选择虚拟机中的 login.exe 样本文件。
图:x32dbg 打开 login.exe
点击 x32dbg 工具栏上的 "运行" 按钮(或按 F9 键),程序会自动运行并停在地址 00460C21 处的断点上。这是程序的入口点(Entry Point)。
此时程序已经被加载到内存中,但尚未完全执行,我们可以对其进行各种调试操作。
在 x32dbg 的 CPU 指令区中,我们可以观察到 x86 汇编代码的几种典型结构:
从图中可以看出,这是一个函数,并且这个函数还调用了其他函数。
理解高级语言(如 C)与汇编指令之间的映射关系,是动态分析的基础:
push ebp / mov ebp, espretpush 参数,再 call 函数
图:C 代码与汇编指令的对应关系
push ebp; mov ebp, esp,这在后续定位登录处理函数时会非常关键。login.exe 的登录流程逻辑如下:
要分析登录校验逻辑,关键在于定位到弹窗指令。因为:
因此,我们可以在 x32dbg 中搜索字符串 "Wrong username or password",找到调用弹窗的代码位置,然后向上回溯分析校验逻辑。
在 x32dbg 的 CPU 指令区任意位置点击鼠标右键,选择:
图:右键菜单选择搜索所有模块字符串
在搜索框中输入 username or(无需输入完整字符串,部分匹配即可)。
图:字符串搜索结果
搜索到一个结果后,双击该搜索结果,x32dbg 会自动跳转到指令区对应位置。可以看到:
004011EA 处的 push 指令使用了这个字符串
图:弹窗函数调用位置的汇编代码
从图中可以看到,此处就是调用弹窗函数的位置。参数入栈后调用了 call login.401252,这就是弹窗函数的地址。
切回"引用"页,删除搜索框中的关键字,显示全部字符串,观察程序中还包含哪些有用的字符串信息。
图:程序中的字符串列表(部分)
图:切回引用页
图:显示全部字符串
在众多字符串中,我们发现有一个字符串 msctls_updown32,其地址为 498C2C。这个字符串将在下一步中被用到。
图:发现 msctls_updown32 字符串
切回 CPU 指令区的弹窗调用位置,我们来修改弹窗函数传入的字符串参数:
push login.481B73 指令push 0x481B73 改成 push 0x498C2C
图:按空格键修改指令
其中:
481B73 是 "Wrong username or password" 字符串的地址498C2C 是 "msctls_updown32" 字符串的地址
图:修改完成后的指令
修改完成后,点击取消按钮关闭指令修改对话框(注意:这里点击取消并不会撤销修改,只是关闭对话框)。
点击 x32dbg 的"运行"按钮,调试运行样本程序。在登录界面输入任意用户名和密码,观察弹窗内容。
图:运行程序并输入任意凭据
图:弹窗报错字符串已改为 msctls_updown32
可以看到,弹窗报错的字符串已经从 "Wrong username or password" 变成了 "msctls_updown32"。这验证了我们可以通过修改函数参数来改变程序功能。
在 x32dbg 中点击"重新运行"按钮,将程序还原到未修改的状态(之前修改的指令失效)。
图:重新运行按钮
重新搜索字符串定位到弹窗函数调用位置(参考步骤 6 的操作)。
在 CPU 指令区中,从弹窗调用位置往上滚动,查看前面的指令。你会发现两个关键字符串:
难道这就是账号和密码?让我们继续验证!
图:在弹窗位置上方发现 zhangsan 和 10086 字符串
在 zhangsan 字符串入栈指令的再上方,可以看到:
这说明这里是某个函数的起始指令,而这个函数很可能就是登录处理函数。
图:函数起始指令 push ebp / mov ebp, esp
通过鼠标点击 push ebp 指令最左边的小灰点,让它变成红色,给该指令下一个断点。这样后续可以快速定位到这个登录处理函数的入口。
图:在 push ebp 处下断点
点击 x32dbg 的"运行"按钮调试运行样本程序。如果途中遇到断点,直接点"运行"继续,直到桌面或任务栏出现程序图标。
在登录界面输入以下凭据:
点击"登录"按钮后,x32dbg 会停在我们下的断点处。这说明此函数就是登录处理函数!
图:程序停在登录处理函数的断点处
继续点击 x32dbg 的"运行"按钮,程序继续执行,登录成功,进入主界面窗口!
图:登录成功,进入主界面(含字符串 xiaojidunmuogu)
可见,正确的用户名和密码就是 zhangsan / 10086。✅ 任务目标 1 完成!
在 x32dbg 中重新运行 login.exe。输入错误的用户名和密码:
点击"登录"按钮,指令停在登录处理函数入口,地址为 4010A9。
图:输入错误凭据后停在登录处理函数入口 4010A9
按 F8 键单步执行,动态分析这个登录处理函数的工作逻辑。逐条观察指令的执行流程。
图:F8 单步执行动态分析
通过单步跟踪,我们发现以下关键地址:
图:错误处理跳转逻辑
而 地址 401168 处就是登录成功、将进入主界面的指令!
前面分析已得出:
40115B 处是登录错误的处理指令401168 处是登录成功的入口指令因此,在登录处理函数中,将判断用户名错误时要跳到 40115B 的条件转移指令,修改为直接跳到 401168。
图:分析跳转关系
选中地址 4010FD 处的 je login.40115B 指令,按空格键,将其修改为 jmp 0x401168:
图:选中 je 指令并准备修改
简而言之,当 EIP 停在 004010A9 处的断点时,将 4010FD 处的 je login.40115B 修改为 jmp 0x401168,不论用户名是否正确,无条件跳转到0x401168。
图:修改为 jmp 0x401168
点击 x32dbg 的"运行"按钮,程序继续运行,无需输入正确的用户名和密码,直接进入主界面!
图:修改后直接绕过登录进入主界面
✅ 任务目标 2 完成!
前面修改指令的操作,都是修改内存中的指令。当重新运行程序时,也就是把硬盘中的 login.exe 文件重新加载到内存,之前修改的指令会被重新覆盖,导致修改失效。
如果要让修改持久化生效,需要通过 x32dbg 的补丁(Patch)功能,将指令修改后的程序保存回硬盘。
在 x32dbg 中:
nologin.exe
图:x32dbg 补丁功能界面
图:保存补丁程序到桌面
双击运行桌面的 nologin.exe,不填用户名和密码,直接点击"登录",即可直接进入主界面。这证明补丁已永久生效。
针对学习通本课程“资料”login2.zip里的login2.exe进行动态分析(解压密码cmd.goodstudy.fun),并确认以下两项成果是否已经完成:
| 检查项 | 说明 | 状态 |
|---|---|---|
| 第 1 项 | 当输错用户名或密码时,弹窗报错显示其他字符串(EDIT)的补丁程序 | 参考步骤 7 |
| 第 2 项 | 无需输入用户名和密码即可登录的补丁程序 | 参考步骤 10-11 |
通过本次实训,你应该掌握了以下知识和技能: