·前言 

虽然网上已经有帖子写160个CrackMe,我个人还是以正向的思路来逆向一部分的crackme,还有一些 代码还原的小技巧,挑选出这160个CrackMe中由c,c++,汇编编写的程序来来写。vb,delphi现在用 的少些了就不拿来写了。

·思路分析

先判断该程序是啥语言写的用工具查看一下

是vc6的mfc编写的现在先运行下程序 寻

找按钮Check的按钮事件 该程序是mfc编写的,我自己写个例子,来找按钮事件 vs2019创建mfc工程后增加个按钮事件

双击Button1 写一个弹出对话框的代码

mfc是怎么知道这个按钮事件的呢,实际是通过映射消息,代码为

这些都是宏定义,按下F12进去看

·把这些宏代码展开为 

PTM_WARNING_DISABLE \ const AFX_MSGMAP* theClass::GetMessageMap() const \    { return GetThisMessageMap(); } \ const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \ typedef theClass ThisClass;                            \    typedef baseClass TheBaseClass;                    \ __pragma(warning(push))                           \ __pragma(warning(disable: 4640))  \ static const AFX_MSGMAP_ENTRY _messageEntries[] =  \ { ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON()             ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication3Dlg::OnBnClickedButton1) }; \       {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \ __pragma(warning(pop)) \static const AFX_MSGMAP messageMap = \ { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \ return &messageMap; \ }                                 \
PTM_WARNING_RESTORE

· __pragma和#pragma之间有什么区别

_Pragma操作符具有与#pragma指令相同的功能
#pragma本身就是一个预处理器指令;它不能在#define指令中使用。
因此,这就是__pragma存在的原因:它提供了一种方法,可以从扩展使用它的宏的任何地方发出编译指示。 这是一个非标准的编译器扩展(MSVC,Intel和一些C编译器在不同程度上支持它). #define PTM_WARNING_DISABLE \ __pragma(warning( push )) \__pragma(warning( disable : 4867 )) #define PTM_WARNING_RESTORE \ __pragma(warning( pop )) __pragma(warning(push)) 等于
#pragma warning(push)是保存当前的编译器警告状态;  __pragma(warning(pop)) 等于
#pragma warning(pop)是恢复原先的警告状态。  __pragma(warning( disable : 4867 ))
warning disable 作用:让编译器忽略指定编号的警告,跳过警告直接运行程序,可用来忽略一部分不重要的警告参考资料
https://blog.csdn.net/qq_45481381/article/details/110875019

·去掉不要的宏定义与代码

const AFX_MSGMAP* theClass::GetMessageMap() const    { return GetThisMessageMap(); } \ const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap()
{                   static const AFX_MSGMAP_ENTRY _messageEntries[] =   { ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication3Dlg::OnBnClickedButton1)  {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};      static const AFX_MSGMAP messageMap =  { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };       return &messageMap;  }

现在替换ON_BN_CLICKED宏

#define ON_BN_CLICKED(id, memberFxn) \ ON_CONTROL(BN_CLICKED, id, memberFxn) ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication3Dlg::OnBnClickedButton1) 等于
ON_CONTROL(BN_CLICKED, IDC_BUTTON1, CMFCApplication3Dlg::OnBnClickedButton1) 进一步替换
#define ON_CONTROL(wNotifyCode, id, memberFxn) \ { WM_COMMAND, (WORD)wNotifyCode, (WORD)id, (WORD)id, AfxSigCmd_v, \(static_cast< AFX_PMSG > (memberFxn)) }, ON_CONTROL(BN_CLICKED, IDC_BUTTON1, CMFCApplication3Dlg::OnBnClickedButton1)等于
{ WM_COMMAND, (WORD)BN_CLICKED, (WORD)IDC_BUTTON1, (WORD)IDC_BUTTON1, AfxSigCmd_v, \ (static_cast< AFX_PMSG > (CMFCApplication3Dlg::OnBnClickedButton1)) }, 

·替换后的代码

const AFX_MSGMAP* theClass::GetMessageMap() const    { return GetThisMessageMap(); } \ const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap()
{               static const AFX_MSGMAP_ENTRY _messageEntries[] =   { { WM_COMMAND, (WORD)BN_CLICKED, (WORD)IDC_BUTTON1, (WORD)IDC_BUTTON1, AfxSigCmd_v, (static_cast< AFX_PMSG > (CMFCApplication3Dlg::OnBnClickedButton1)) }, {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }  };       static const AFX_MSGMAP messageMap =  { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] };       return &messageMap;  }  

·OnBnClickedButton1地址写在了_messageEntries数组这个结构体中,现在看看这个结构体定义

struct AFX_MSGMAP_ENTRY
{ UINT nMessage;   // windows message UINT nCode;      // control code or WM_NOTIFY code UINT nID;        // control ID (or 0 for windows messages) UINT nLastID;    // used for entries specifying a range of control id's    UINT_PTR nSig;       // signature type (action) or pointer to message # AFX_PMSG pfn;    // routine to call (or special value)
}; 

·那我的按钮事件就为

AFX_MSGMAP_ENTRY btn; btn.nMessage=WM_COMMAND; btn.nCode=BN_CLICKED; btn.nID=IDC_BUTTON1; btn.nLastID=IDC_BUTTON1; btn.nSig=AfxSigCmd_v;
btn.pfn=CMFCApplication3Dlg::OnBnClickedButton1; 查看WM_COMMAND,BN_CLICKED,IDC_BUTTON1宏定义的值,btn结构体的值应该为 btn.nMessage=0x0111; btn.nCode=0; btn.nID=1000; btn.nLastID=1000; btn.nSig=AfxSigCmd_v;
btn.pfn=CMFCApplication3Dlg::OnBnClickedButton1; 因为static const AFX_MSGMAP_ENTRY _messageEntries[]是静态数组,会在exe的.data段
那我直接在内存搜索结构体btn的二进制就行了 btn的内存呈现形式为
nMessage,nCode,nID,nLastID,nSig,pfn
可以不用管nSig,pfn的值,只用搜索前四项就够了,等价替换为
0x0111,  0,   1000,1000,nSig,pfn       等价替换为
11 01 00 00, 00 00 00 00, e8 03 00 00, e8 03 00 00 ,nSig,pfn 等价替换为
11 01 00 00 00 00 00 00 e8 03 00 00 e8 03 00 00  

·用x64dbg打开该程序,内存搜索 

·一定要用鼠标左键点击 开始的00280000地址,这样搜索就会从00280000开始查找,如果你从00c94000开始的话,00280000至00c94000这段内存就不会搜索 了 

跟过去看看 

00CA07FB就是OnBnClickedButton1函数地址

160个CrackMe之108 mfc程序 寻找按钮事件,代码还原(上)相关推荐

  1. c语言特征码搜索,[学习笔记]通过各语言特征码寻找按钮事件

    今天的课件都无壳. 一  Delphi和BC++ DIE检测一下,是Delphi OD载入 反汇编窗口右键---查找---二进制字符串 查看一下特征码 复制Delphi的特征码,粘贴进刚才打开的查找二 ...

  2. 转用特征码秒杀各程序语言按钮事件

    作者:小童 工具:OllyDbg.Delphi程序一个.易语言程序一个.MFC程序一个 -------------------------------------------------------- ...

  3. 用特征码秒杀各程序语言按钮事件

    作者:小童 工具:OllyDbg.Delphi程序一个.易语言程序一个.MFC程序一个 -------------------------------------------------------- ...

  4. android hook截取其他程序的按钮事件_Hook技术

    概述 Hook,英文直译是"钩子"的意思.在程序中将其理解为"劫持"可能会更好理解,我们可以通过hook技术来劫持某个对象,从而控制它与其他对象的交互. Hoo ...

  5. 小程序监听android返回键,如何监听小程序返回按钮事件?

    写在前面 为了能及时的将自己踩到的前端坑(包括ionic,angular,react,ReactNative,小程序,APICloud)分享给大家,以后会逐渐将文章转移到微信公众号:前端e家(fron ...

  6. 如何监听小程序返回按钮事件?

    2020-06-09更新 //--------------------------2020-06-09更新-------------------开始-------------------------- ...

  7. MFC程序逆向 – 消息篇(上)+(下)

    费尔托斯特:单用户终生版,费尔软件 杀毒软件 65.0元   标 题: [原创]MFC程序逆向 – 消息篇(上)+(下) 11楼 作 者: szdbg 时 间: 2007-10-31,06:26 链 ...

  8. MFC程序打开控制台

    转自:http://blog.csdn.NET/acaiacc/article/details/5543669 利用AllocConsole()   在你的MFC程序中添加这些代码,可以获得控制台的输 ...

  9. MFC程序的生死因果

    MFC程序的来龙去脉(causal relations)  MFC的程序如何运行,第一件事情就是找出MFC程序的进入点.MFC程序也是Windows程序.所以它应该也有一个WinMain.但在程序中好 ...

最新文章

  1. MapReduce: 提高MapReduce性能的七点建议【译】
  2. 浅析如何让企业网站实现精准营销?
  3. php 正则获取数字,php结合正则获取字符串中数字的几种方法
  4. Python打牢基础,从12个语法开始!
  5. 零基础逆向工程28_Win32_02_事件_消息_消息处理函数
  6. 在Xcode6中搭建Python开发环境
  7. elementui图片上传php,vue+element-ui+富文本————图片上传
  8. linux连接svn上代码,代码管理平台介绍、安装svn、客户端上使用svn(linux)、客户端上使用svn(windows)...
  9. 3W | 跟着小小学会这些 Java 工程师面试题,月薪至少 3 W
  10. HDUOJ---老人是真饿了
  11. phpstorm设置xdebug调试
  12. 轻松学习JavaScript二十一:DOM编程学习之获取元素节点的子节点和属性节点
  13. greensock下载_面向初学者的GreenSock(第2部分):GSAP的时间表
  14. access如何保存小数点后_你知道PDF文件旋转页面后如何保存吗?
  15. Chloe and the sequence
  16. 最短路径算法----Floyd-warshall(十字交叉算法证明)
  17. 网店系统SHOP++、V5shop、shopex全程分析
  18. openstack资料
  19. A类计算机机房温度变化,夏季什么样的温度才是机房适合的?
  20. 如何二叉树里面查找一个数

热门文章

  1. 2021双十一活动:华为云服务器体验活动,免费领取50G云硬盘,邀请参加再送价值200元华为无线鼠标键盘套装
  2. RabbitMQ-2-工作模式及参数配置
  3. 微信公众号开发 如何发布图文并茂的文章?
  4. 为什么A能ping通B,B不能ping通A?
  5. 移动周刊第 184 期:Android 开发终极指南
  6. 关于bootstrap-table冻结列生成多个冻结表头和表格主体的问题
  7. DICOM:fo-dicom之C-STORE再分析‘解决System.ObjectDisposedException异常’
  8. vue向后台请求数据的配置和方法
  9. 为什么容器内存占用居高不下,频频 OOM(续)
  10. Kotlin Native - 原生平台 Hollo World!