1.先檢查目標程式是不是有保護殼,如果有就先進行脫殼處理;
2.脫殼後修改目標程式的資源,在對話方塊中新增一個自己的按鈕,並賦予一個新的控制元件ID
可以使用ResHacker或者VC++對資源進行修改;這樣就有一個我們自己的功能按鈕了,接下來要新增一個訊息對映和響應函式
3.通常我們會在一個已經存在的對話方塊上新增一個按鈕,因此我們先摸索一下原來對話方塊的一些功能按鈕,最好有MessageBox
呼叫的函式,這樣方便設斷點。
4.根據對MFC的程式碼,知道MFC程式有個訊息響應函式CCmdTarget::OnCmdMsg(),繼而定位到訊息查詢匹配函式_AfxFindMessageEntry
被呼叫的地方。
5.假如找到一個功能按鈕並能彈出MessageBox的。在按下該按鈕前我們先在_AfxFindMessageEntry被呼叫的地方設上斷點,然後按下按鈕
可能會有很多訊息進入斷點,因此我們可以設定一個條件斷點,只攔截WM_COMMAND(0x111h)訊息
6.如果一切順利的話,我們已經在斷點出攔截到功能按鈕的呼叫了。
下面是CCmdTarget::OnCmdMsg()的程式碼片斷
CCmdTarget::OnCmdMsg()
PUSH
EBP
MOV EBP,ESP
MOV EAX,DWORD PTR
[EBP+C]
PUSH EBX
PUSH ESI
; Sample.00402308
PUSH
EDI
CMP EAX,-2
; Switch (cases FFFFFFFD..FFFFFFFF)
MOV
EDI,ECX
JE 6BC9E571
; MFC42.6BC9E571
CMP
EAX,-3
JE 6BC9E592
; MFC42.6BC9E592
CMP
EAX,-1
JNZ SHORT 6BC42287
; MFC42.6BC42287
MOV
EBX,111
; Case FFFFFFFF of switch 6BC42245
MOV EAX,DWORD
PTR [EDI] ; Sample.00402310
MOV
ECX,EDI
CALL NEAR DWORD PTR [EAX+30]
; MFC42.GetMessageMap()
MOV ESI,EAX
; Sample.00402308
TEST
ESI,ESI
; Sample.00402308
JE SHORT 6BC422B0
; MFC42.6BC422B0
PUSH
DWORD PTR [EBP+8] ;
/Arg4 = 000003E8
PUSH DWORD PTR [EBP+C]
; |Arg3 = 00000000
PUSH EBX
; |Arg2
= 00000111
PUSH DWORD PTR [ESI+4]
; |ESI + 4 == lpEntris, You Can Modify it to Chang MsgMap
CALL
6BC42088
; \#1145_AfxFindMessageEntry <----- 斷點停在這裡
TEST
EAX,EAX
; Sample.00402308
7.現在有必要介紹一下比較重要的兩個資料結構
第一個是“訊息對映結構”
struct
AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const
AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
在這個結構中,我們只關心lpEntries這個值,因為這個值指向“訊息處理對映入口”陣列的首地址
第二個是“訊息處理對映入口”資料結構
AFX_MSGMAP_ENTRY
{
nMessage;
nCode ;
nID ;
nLastID ;
nSig ;
lpEntry ;
}
8.檢視一下MFC關於呼叫_AfxFindMessageEntry的原始碼。
這個函式作用是,輪詢查詢和nMsg、nCode、nID匹配的AFX_MSGMAP_ENTRY結構,並從中提取出處理函式的入口地址
MS為了提高效能,所以這個函式是用匯編寫程式的。
AFX_MSGMAP
*pMessageMap;
pMessageMap = GetMessageMap()
lpEntry = _AfxFindMessageEntry(pMessageMap->lpEntries,
nMsg, nCode, nID);
我們可以發現pMessageMap指向我們需要的AFX_MSGMAP資料結構,因此在彙編程式碼中“ESI
+ 4”就是指向lpEntries的地址
9.我們現在所要做的就是,找到資料段空白的地方,然後將原來的“訊息處理對映入口”陣列複製到這裡來,然後用新的
陣列入口地址改寫“ESI
+ 4”所指向的資料。(因為沒有空間,所以不在原來的陣列後面新增)
10.現在我們可以在新的陣列中新增一個我們自己的“訊息處理對映入口”結構了。
下面是處理按鈕訊息的例子
AFX_MSGMAP_ENTRY
{
nMessage = 0x111 WM_COMMAND
nCode = 0
nID
= (ID) 按鈕控制元件的ID
nLastID = (ID) 按鈕控制元件的ID
nSig
= 0xC
lpEntry (訊息響應函式入口)
}
11.在程式碼段的空白地方寫入自己的訊息響應函式,然後把這個函式的入口地址寫入到我們自己構造的訊息對映入口結構
的成員lpEntry中
12.基本上大致的流程就是這樣了。