首页
社区
课程
招聘
[原创]MFC 程序按钮事件快速定位实战教程
发表于: 2小时前 65

[原创]MFC 程序按钮事件快速定位实战教程

2小时前
65

???? MFC 程序按钮事件快速定位实战教程

核心原理

MFC(Microsoft Foundation Classes)程序在处理按钮点击时,其底层依然会调用 Win32 API。当用户点击按钮时,MFC 框架会通过 GetDlgItemText 或类似的函数去获取控件信息。
对于 32 位 x86 程序,传递控件 ID(如 1002、1003)到函数栈上的汇编指令是 push。在机器码层面,push 0x3EA 表现为 68 EA 03 00 00。因此,只要我们在内存中搜索这些特定的 push 指令并下断点,就能在点击按钮时精准拦截到事件处理函数。


????️ 前期准备工具

  1. x64dbg / OllyDbg:动态调试器。
  2. Spy++ (Visual Studio 自带工具):用于获取目标程序的控件 ID。


实战操作步骤

第一步:用 Spy++ 获取目标控件 ID

  1. 打开 Spy++(通常在 Visual Studio 的“工具”菜单中)。
  2. 在 Spy++ 中点击“查找窗口”图标(望远镜图标),拖动准星到目标程序的按钮上。
  3. 在“常规”选项卡中,你会看到该按钮的 Control ID(例如十进制 1002 或十六进制 0x3EA)。
    • 注意:MFC 对话框程序的控件 ID 通常从 1000 开始递增,常见如 0x3E8 (1000), 0x3E9 (1001), 0x3EA (1002)       等。

第二步:计算特征码(机器码)

将获取到的控件 ID 转换为汇编 push 指令的机器码:

  • 假设 ID 为 1002 (十六进制 0x3EA)。
  • 对应的汇编指令:push 0x3EA
  • 对应的机器码(小端序):68 EA 03 00 00
  • 假设 ID 为 1003 (十六进制 0x3EB)。
  • 对应的机器码:68 EB 03 00 00

第三步:在 x64dbg 中搜索并下断点(对应你的截图)

  1. 将程序拖入 x64dbg,程序会暂停在入口点(EP)。
  2. 右键 -> 当前模块 (Current      Module) -> 匹配特征 (Search for -> Sequence of bytes)
  3. 在弹出的“搜索特征码”窗口中:
    • 选择 十六进制 (Hex) 标签页。
    • 输入你计算好的机器码,例如:68 E9 03 00 00 或 68 EA 03 00       00。
    • 点击 确定,开始搜索。
  4. 搜索结果会列在“引用”窗口中。双击这些结果,跳转到对应的汇编指令行。
  5. 在 push 0x3EA 这一行上,按 F2 下断点。
  6. 重复搜索其他相关的控件 ID(如 1003),并下断点。
  7. 按 F9 运行程序,在弹出的程序窗口中点击那个按钮。
  8. 中断! 调试器会精准停在某个 push 指令处。

第四步:回溯分析并找到函数入口

  1. 当断点命中时,你位于函数的中间(因为 push 只是获取控件文本前的准备操作)。
  2. 此时,在反汇编窗口中,向上滚动,或者直接按键盘上的 Home (或 Ctrl      + Home),将光标跳到当前函数的开头。
  3. 函数的开头通常是经典的 push ebp / mov ebp, esp(或带有 push -1、SEH 异常处理的 64 位代码)。
  4. 关键识别
    • 在函数开头,右键 -> 当前模块 (Current Module) -> 在函数中 (Follow in       Function),或者直接看 x64dbg 状态栏是否显示 sub_xxxxxx。
    • 如果是 MFC 程序,函数开头通常会有 mov ecx, [ebp+...](因为 thiscall 调用约定)。此时 ECX 寄存器保存的就是 CWnd* this 指针。

第五步:转交 IDA Pro 进行静态分析

  1. 记下该函数的起始运行地址(例如你截图中的 009D24C0)。
  2. 回忆上一课的知识,利用 运行地址 - 模块基址 + IDA静态基址(通常是 00400000)的计算公式,计算出其在 IDA 中的静态地址(例如 004024C0)。
  3. 在 IDA Pro 中按 G 键,输入 004024C0,直接跳转到该函数进行伪代码分析(按 F5)。
  4. 你会发现,这个函数就是该按钮的 Click 事件处理函数


高阶技巧与避坑指南

  1. 为什么搜索结果很多?
    • 同一段代码可能在多个地方被调用,或者程序中有多个按钮使用了相同的 ID。
    • 有时编译器会优化 push 指令,例如使用 mov eax,       1002; push eax。
    • 遇到这种情况,直接在搜索框搜 E9 03 00 00(不加 68),或者搜 EA 03 00 00,扩大搜索范围。
  2. 函数入口特征识别
    • MFC 的按钮事件入口通常非常整洁:push ebp; mov ebp,       esp; ...
    • 如果是对话框消息处理,入口往往有一长串的 mov 和 lea 指令,最后跟一个 jmp 到真正的处理逻辑(这就是所谓的 Message       Map 跳转)。
  3. 分析函数内部逻辑
    • 一旦进入 sub_4024C0,你会发现类似的模式:获取 this 指针 -> 调用虚函数       -> GetDlgItemText -> 弹窗等。
    • 核心业务逻辑往往集中在函数的中间偏后位置(例如 IDA 伪代码中的 MessageBox 或核心数学计算)。
  4. 使用条件断点(精准过滤)
    • 如果程序有多个按钮,且它们都调用了同一个 GetDlgItemText,你可以在 push       0x3EA 处下条件断点:[esp] == 0x3EA,这样只有当栈顶确实是这个 ID 时才会断下。

总结

这条路径:Spy++ 获取 ID -> 计算特征码 -> x64dbg 搜索特征码 -> 下断 -> 触发点击 -> 按 Home 回溯 -> 转 IDA 分析,就是目前 MFC 逆向中最标准、最高效的“手术刀级”破解路径。掌握了这个方法论,你以后遇到任何 MFC 编写的软件(如各类小工具、管理软件),基本都能在几分钟内直捣黄龙。

 



传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

收藏
点赞 0
打赏
分享
最新回复 (1)
雪    币: 364
活跃值: (3092)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
好思路...
2小时前
0
游客
登录 | 注册 方可回帖
返回