160個CrackMe之108 mfc程序 尋找按鈕事件,代碼還原(上)
查看原文可搜索【極安御信安全研究院】公眾號查看原文!
·前言?
雖然網(wǎng)上已經(jīng)有帖子寫160個CrackMe,我個人還是以正向的思路來逆向一部分的crackme,還有一些 代碼還原的小技巧,挑選出這160個CrackMe中由c,c++,匯編編寫的程序來來寫。vb,delphi現(xiàn)在用 的少些了就不拿來寫了。?
·思路分析?
先判斷該程序是啥語言寫的用工具查看一下?

是vc6的mfc編寫的現(xiàn)在先運行下程序 尋

?
找按鈕Check的按鈕事件 該程序是mfc編寫的,我自己寫個例子,來找按鈕事件?vs2019創(chuàng)建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之間有什么區(qū)別
?
_Pragma操作符具有與#pragma指令相同的功能
#pragma本身就是一個預(yù)處理器指令;它不能在#define指令中使用。
因此,這就是__pragma存在的原因:它提供了一種方法,可以從擴展使用它的宏的任何地方發(fā)出編譯指示。
這是一個非標準的編譯器擴展(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)是保存當前的編譯器警告狀態(tài); ?
__pragma(warning(pop)) 等于
#pragma warning(pop)是恢復(fù)原先的警告狀態(tài)。 ?
__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; ?
? ?} ?
現(xiàn)在替換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數(shù)組這個結(jié)構(gòu)體中,現(xiàn)在看看這個結(jié)構(gòu)體定義
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結(jié)構(gòu)體的值應(yīng)該為 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[]是靜態(tài)數(shù)組,會在exe的.data段
那我直接在內(nèi)存搜索結(jié)構(gòu)體btn的二進制就行了
btn的內(nèi)存呈現(xiàn)形式為
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打開該程序,內(nèi)存搜索?

·一定要用鼠標左鍵點擊 開始的00280000地址,這樣搜索就會從00280000開始查找,如果你從00c94000開始的話,00280000至00c94000這段內(nèi)存就不會搜索 了?


跟過去看看?

00CA07FB就是OnBnClickedButton1函數(shù)地址
