Message process of the mfc Program

Source: Internet
Author: User

I remember some time ago, when I first came into contact with software cracking and reverse engineering, I tried many methods for some software to track button messages without knowing where, that is, they could not be broken, in the system module, the system often gets dizzy and gets nothing.

The MFC program is a common type of program. I calmed down and studied the message process of the MFC. After figuring out the source Committee, everything suddenly went on, and found that tracking the MFC program and Message Processing turned out to be so..., tracking button event processing also became particularly simple.

As a result, I have written these studies for future reference. I hope it will be helpful for cainiao like me. If there are any mistakes, please correct them.

The purpose of this article is to take a standard Dialog Box program of MFC as an example, at the same time from the source code and disassembly code to study the process of the MFC message, find out all the sites of the MFC message path, in this way, all message events of MFC can be located at will, and the processing process of MFC can be tracked and analyzed from any site. You can even start from the PumpMessage base camp and keep track of the entire process.

The Startup Process of the dialog box is very simple. After the program enters the WinMain function, it will call the DoModal function of the dialog box and then enter the RunModalLoop function. The message loop starts here. Limited space, I will not talk about this article. If you are interested, please refer to the source code of MFC. This article focuses on analyzing the message delivery and processing process of MFC.
Let's take a look at the source code of the RunModalLoop function:

Int CWnd: RunModalLoop (DWORD dwFlags)
{...
For (;;)
{...
Do
{If (! AfxGetThread ()-> PumpMessage () // pump message, but quit on WM_QUIT
{
AfxPostQuitMessage (0 );
Return-1;
}
...
} While (: PeekMessage (pMsg, NULL, PM_NOREMOVE ));
}
...
}

Here, AfxGetThread ()-> PumpMessage () is the base camp of MFC message processing. All the messages in the MFC program start from here. After many path transformations, they go through the mountains and go straight to the Windows kernel, return to the MFC field, and find the final destination-message function address after many twists and turns. It can be said that there is no way to recover from problems.

The process of clicking an event with a button is as follows:
CWinThread: PumpMessage-> CWnd: PretranslateMessage-> CWnd: audio-> CD1Dlg: audio-> CDialog: PreTranslateMessage-> CWnd: PreTranslateInput-> CWnd :: isDialogMessageA-> USER32 kernel-> AfxWndProc-> AfxCallWndProc-> CWnd: WindowProc-> CWnd: OnWndMsg-> CWnd: OnCommand-> CDialog :: on‑msg-> c‑target: on‑msg-> _ afxdispatch‑msg-> CD1Dlg: OnButton1 ()

Under VC, you can write a standard Dialog Box program by hand. Put a button above and click the button to bring up a message box. We will analyze the message process from PumpMessage:

1. CWinThread: PumpMessage function (Message pump)
BOOL CWinThread: PumpMessage ()
{// GetMessage: if the message is WM_QUIT, 0 is returned. If the message is other messages, TRUE is returned. If the message is incorrect,-1 is returned.
If (! : GetMessage (& m_msgCur, NULL) return FALSE;
If (m_msgCur.message! = WM_KICKIDLE &&! PreTranslateMessage (& m_msgCur ))
{
: TranslateMessage (& m_msgCur );
: DispatchMessage (& m_msgCur );
}
Return TRUE;
}
PumpMessage returns FALSE only when the WM_QUIT message is received. In other cases, TRUE is returned. Since the CWinThread: PumpMessage () function is used to obtain, translate, and distribute messages from a message queue, this function is often called a "message pump ".
In the PumpMessage function, the PreTranslateMessage function is crucial. It is with this PreTranslateMessage () that MFC can flexibly control the message delivery mode. It can be said that PreTranslateMessage () is the tool for implementing the Message Delivery Mode of MFC.

PumpMessage function disassembly code:
73D31194> 56 PUSH ESI
...
73D311A1 FF15 B0B6DC73 call dword ptr ds: [<& USER32.GetMessageA>]
73D311A7 85C0 test eax, EAX
73D311A9 74 26 je short MFC42.73D311D1; Receive WM_QUIT and exit the program
73D311AB 817E 38 6A030000 cmp dword ptr ds: [ESI + 38], 36A
73D311B2 74 1A je short MFC42.73D311CE
73D311B4 8B06 mov eax, dword ptr ds: [ESI]
73D311B6 57 PUSH EDI
73D311B7 8BCE mov ecx, ESI
73D311B9 FF50 60 call dword ptr ds: [EAX + 60]; PreTranslateMessage (Message preprocessing)
73D311BC 85C0 test eax, EAX
73D311BE 75 0E jnz short MFC42.73D311CE
73D311C0 57 push edi; message preprocessing returns FALSE
73D311C1 FF15 ACB6DC73 call dword ptr ds: [<& USER32.TranslateMessage>]
73D311C7 57 PUSH EDI
73D311C8 FF15 30B6DC73 call dword ptr ds: [<& USER32.DispatchMessageA>]
;
73D311CE 6A 01 PUSH 1; return TRUE
73D311D0 58 POP EAX
73D311D1 5F POP EDI
73D311D2 5E POP ESI
73D311D3 C3 RETN

Tip:
A. OD after the program is loaded, call up the MFC42.dll module and locate the PumpMessage code entry.
B. Set the condition breakpoint [[esp] + 4] = 202 on the CALL DWORD PTR DS: [EAX + 60] statement to set the left mouse button to release the breakpoint.
Note: call [eax + 60] calls the PreTranslateMessage function. The entry parameter is MSG * pMsg, so:
[Esp] Is pMsg, while [[esp] Is pMsg-> hWnd, and [[esp] + 4] Is pMsg-> Message
C. [[esp] = 002407B4 & [[esp] + 4] = 202 you can set a breakpoint for a specified button. Here 002407B4 is the handle of the target button.

2. CWinThread: PreTranslateMessage Function
BOOL CWinThread: PreTranslateMessage (MSG * pMsg)
{// If this is a thread-message, short-circuit this function
If (pMsg-> hwnd = NULL & DispatchThreadMessageEx (pMsg) return TRUE;
CWnd * pMainWnd = AfxGetMainWnd ();
// Distribute messages through inclupretranslatetree
If (CWnd: inclupretranslatetree (pMainWnd-> GetSafeHwnd (), pMsg) return TRUE; // key to message distribution
If (pMainWnd! = NULL)
{
CWnd * pWnd = CWnd: FromHandle (pMsg-> hwnd );
If (pWnd-> GetTopLevelParent ()! = PMainWnd)
Return pMainWnd-> PreTranslateMessage (pMsg); // The main program framework processes messages.
}
Return FALSE; // no special processing
}

PreTranslateMessage function disassembly code
73D313D0> PUSH ESI
73D313D1 PUSH EDI
73D313D2 mov edi, dword ptr ss: [ESP + C]
73D313D6 cmp dword ptr ds: [EDI], 0
73D313D9 JE MFC42.73D8E9A1
73D313DF CALL MFC42. #6575 _? AfxGetMainWnd @ YGPAVCW>
73D313E4 mov esi, EAX
73D313E6 test esi, ESI
73D313E8 je short MFC42.73D313ED
73D313EA mov eax, dword ptr ds: [ESI + 20]
73D313ED PUSH EDI
73D313EE PUSH EAX
73D313EF CALL MFC42. #6367 _? WalkPreTranslateTree @ C>
73D313F4 test eax, EAX
73D313F6 jnz short MFC42.73D31415
73D313F8> test esi, ESI
73D313FA je short MFC42.73D3140E
73D313FC push dword ptr ds: [EDI]
73D313FE CALL MFC42. #2864 _? FromHandle @ CWnd @ SGPAV>
73D31403 mov ecx, EAX
73D31405 CALL MFC42. #3815 _? GetTopLevelParent @ CWnd>
73D3140A cmp eax, ESI
73D3140C jnz short MFC42.73D3141A
73D3140E xor eax, EAX
73D31410 POP EDI
73D31411 POP ESI
73D31412 RETN 4
Tip:
A. OD after the program is loaded, call up the MFC42.dll module and locate the PreTranslateMessage code entry.
B. Set the condition breakpoint [[esp + 4] + 4] = 202 at the function entrance to set the left mouse button to release the breakpoint.
Note: The entry parameter of this function is MSG * pMsg. At the entrance, [esp] is the return address of the function, so:
[Esp + 4] Is pMsg, and [[esp + 4] Is pMsg-> hWnd, [[esp + 4] + 4] Is pMsg-> Message
C. [[esp + 4] = 002407B4 & [[esp + 4] + 4] = 202 you can set a click breakpoint for a specified button. Here 002407B4 is the handle of the target button.

3. CWnd: extends pretranslatetree Function
The policy used by CWnd: Define pretranslatetree () is very simple. It has the right to process the message first in the message window. If it does not want to process the message (the PreTranslateMessage () of the window object () if the function returns FALSE), the processing permission is handed over to its parent window, so that the tree is traversed to the root until hWndStop (in CWinThread: PreTranslateMessage, hWndStop indicates the handle of the main thread window ).
Remember the transfer direction of this message processing right. It is transmitted to the root of the tree by a common node or leaf node of the tree!

Bool pascal CWnd: FIG (HWND hWndStop, MSG * pMsg)
{For (HWND hWnd = pMsg-> hwnd; hWnd! = NULL; hWnd =: GetParent (hWnd) // from the current window to the parent window, layer by layer
{CWnd * pWnd = CWnd: FromHandlePermanent (hWnd );
If (pWnd! = NULL)
{// Target window is a C ++ window
If (pWnd-> PreTranslateMessage (pMsg) return TRUE; // if the message is processed by a window, return
}
If (hWnd = hWndStop) break; // got to hWndStop window without interest
}
Return false; // no special processing
}
It is this if (pwnd-> pretranslatemessage (PMSG) return true; that achieves the flexible message distribution and processing mechanism of MFC. The pretranslatemessage virtual functions that are reloaded in various window classes of the MFC program come in from here.
MFC searches and executes the pretranslatemessage function of each class step by step from the current message window class, as long as there is a pretranslatemessage Function
True is returned. If the parameter pretranslatetree is returned, the search is aborted and true is returned. Otherwise, false is returned.
In the pumpmessage function, the final result is to determine whether to process and distribute messages in Windows based on the return value of the paipretranslatetree function.

The disassembly code of the walkpretranslatetree function is as follows:
73d31389 mov EDI, EDI; d1.0040308c
73d3138b push ESI
73d3138c push EDI
73d3138d mov EDI, dword ptr ss: [esp + 10]
73d31391 mov ESI, dword ptr ds: [EDI]
73d31393 JMP short mfc42.73d313bd
73d31395/push ESI
73d31396 | call mfc42. #2867 _? Fromhandlepermanent @ cwnd @ sgpav>; obtain the cwnd pointer value.
73D3139B | test eax, EAX; when the value of CWnd * is not NULL, CWnd: PreTranslateMessage () is called ()
73D3139D | je short MFC42.73D313AE
73D3139F | mov edx, dword ptr ds: [EAX]
73D313A1 | PUSH EDI
73D313A2 | mov ecx, EAX
73D313A4 | call dword ptr ds: [EDX + 98]; <JMP. & MFC42. #5280 _? PreTranslateMessage>; call through virtual functions
73D313AA | test eax, EAX
73D313AC | jnz short MFC42.73D313C8; if the message is processed, TRUE is returned.
73D313AE | cmp esi, dword ptr ss: [ESP + C]
73D313B2 | je short MFC42.73D313C1
73D313B4 | push esi;/hWnd
73D313B5 | call dword ptr ds: [<& USER32.GetParent>]; GetParent
73D313BB | mov esi, EAX
73D313BD test esi, ESI
73D313BF jnz short MFC42.73D31395
73D313C1 xor eax, EAX; FALSE
73D313C3 POP EDI
73D313C4 POP ESI
73D313C5 RETN 8
73D313C8 xor eax, EAX
73D313CA inc eax; returns TRUE
73D313CB jmp short MFC42.73D313C3
Tracking instructions:
In the above sentence 73D313A4 call dword ptr ds: [EDX + 98], click the set button to set the condition breakpoint: [[esp] = 002407B4 & [[esp] + 4] = 202
It can be found that when the button is clicked, the event function code will be executed after the button is clicked. After the event function code is executed, the CALL will return TRUE.

4. CD1Dlg: PreTranslateMessage Function
BOOL CDialog: PreTranslateMessage (MSG * pMsg)
{...
Return CDialog: PreTranslateMessage (pMsg );
}
If the window class for receiving messages reloads the PreTranslateMessage function, it will be called at this time; otherwise, step 2 will be taken. In practical application, it is likely to be a watershed in the message process and may go two different ways. This depends entirely on the code added by the application. If the application returns TRUE here, the message flow will return. Otherwise, the execution will continue.
When tracing a button message, this should be taken as a note, and the best position for setting the breakpoint is the position stated in the previous javaspretranslatetree function. Follow up and pay attention to the Message flow.

5. CDialog: PreTranslateMessage Function
BOOL CDialog: PreTranslateMessage (MSG * pMsg)
{
If (CWnd: PreTranslateMessage (pMsg) return TRUE;
CFrameWnd * pFrameWnd = GetTopLevelFrame ();
If (pFrameWnd! = NULL & pFrameWnd-> m_bHelpMode) return FALSE;
If (pMsg-> message = WM_KEYDOWN & (pMsg-> wParam = VK_ESCAPE | pMsg-> wParam = VK_CANCEL )&&
(: GetWindowLong (pMsg-> hwnd, GWL_STYLE) & ES_MULTILINE) & _ AfxCompareClassName (pMsg-> hwnd, _ T ("Edit ")))
{
HWND hItem =: GetDlgItem (m_hWnd, IDCANCEL );
If (hItem = NULL |: isw.wenabled (hItem ))
{
SendMessage (WM_COMMAND, IDCANCEL, 0 );
Return TRUE;
}
}
Return PreTranslateInput (pMsg); // message inflow here
}

CDialog: PreTranslateMessage () The disassembly code is as follows:
73D468A4> PUSH ESI
73D468A5 PUSH EDI
73D468A6 mov edi, dword ptr ss: [ESP + C]
73D468AA mov esi, ECX
73D468AC PUSH EDI
73D468AD CALL MFC42. #5290 _? PreTranslateMessage @ CWnd @ UAEHPAUtagMSG @>
73D468B2 test eax, EAX
73D468B4 JNZ MFC42.73D8D490
73D468BA mov ecx, ESI
73D468BC CALL MFC42. #3813 _? GetTopLevelFrame @ CWnd QBEPAVCFrameWnd>
73D468C1 test eax, EAX
73D468C3 JNZ MFC42.73D8D429
73D468C9 cmp dword ptr ds: [EDI + 4], 100
73D468D0 je short MFC42.73D468DF
73D468D2 PUSH EDI
73D468D3 mov ecx, ESI
73D468D5 CALL MFC42. #5278 _? PreTranslateInput @ CWnd @ QAEHPAUtagMSG>; the message flows from here
73D468DA POP EDI
73D468DB POP ESI
73D468DC RETN 4

6. CWnd: PreTranslateInput Function
BOOL CWnd: PreTranslateInput (LPMSG lpMsg)
{
If (lpMsg-> message <WM_KEYFIRST | lpMsg-> message> WM_KEYLAST )&&
(LpMsg-> message <WM_MOUSEFIRST | lpMsg-> message> WM_MOUSELAST) // filter messages
Return FALSE;
Return IsDialogMessage (lpMsg );
}
From the source code, we can see that this function is used to filter messages. For button messages and mouse messages, FALSE is directly returned, and then return to the PumpMessge function, and the TranslageMessage () and DispatchMessage () are called () function to convert and distribute messages, and then enter the MFC. For other messages, call the CWnd: IsDialogMessage () function for next processing.
CWnd: PreTranslateInput () function disassembly code is as follows:
73D34009> mov edx, dword ptr ss: [ESP + 4]
73D3400D mov eax, dword ptr ds: [EDX + 4]
73D34010 cmp eax, 100
73D34015 jnb short MFC42.73D34023
73D34017 cmp eax, 200
73D3401C jnb short MFC42.73D34032
73D3401E xor eax, EAX
73D34020 RETN 4
73D34023 cmp eax, 108
73d34028 ^ ja short mfc42.73d34017
73d3402a push edX
73d3402b call mfc42. #4047 _? Isdialogmessagea @ cwnd qaehpautagmsg @ Z
73d34030 ^ JMP short mfc42.73d34020
73d34032 CMP eax, 209
73d34037 ^ jbe short mfc42.73d3402a
73d34039 ^ JMP short mfc42.73d3401e
7. cwnd: isdialogmessagea Function
Bool cwnd: isdialogmessage (lpmsg)
{
If (m_nflags & wf_olectlcontainer)
Return afxoccmanager-> isdialogmessage (this, lpmsg );
Else
Return: isdialogmessage (m_hwnd, lpmsg );
}
Here, the user32.isdialogmessagea function is transferred to the system kernel, and the windows system is responsible for transmitting messages to various target Windows.
Note: User32.IsDialogMessage is not used to check the dialog box message as its name, but to explain or convert the message. The more appropriate name is TranslateDialogMessage. CWnd: IsDialogMessage is actually a package function that uses LPMSG as the parameter and adds the m_hWnd parameter to call User32.IsDialogMessage. In this way, each dialog box in MFC will explain its input. Therefore, if you run the five dialogs at the same time, the PreTranslateMessage of each dialog box will automatically call User32.IsDialogMessage, and it works well. We can skip programming. MFC is really awesome.

CWnd: IsDialogMessageA function disassembly code:
73D468F5> PUSH ESI
73D468F6 mov esi, ECX
73D468F8 test byte ptr ds: [ESI + 29], 1
73D468FC JNZ MFC42.73D8E273
73D46902 push dword ptr ss: [ESP + 8]
73D46906 push dword ptr ds: [ESI + 20]
73D46909 call dword ptr ds: [<& USER32.IsDialogMessageA>]; enter the system kernel
73D4690F POP ESI
73D46910 RETN 4
Tip:
1. OD disconnection: bp IsDialogMessageA MSG = 202, when the left mouse button is released, it will be interrupted at the User32.IsDialogMessageA function entry.
2. If you know the handle of a button and require that the program be interrupted on IsDialogMessageA when you click this button, you can make the following settings:
BP isdialogmessagea [[esp + 8] ===00060350 & MSG = 202.
3. After interruption, return to the code of the cwnd: isdialogmessagea function through the stack.
========================================================== ========================================================== ======================================
8. USER32 kernel processing without Analysis
In this process, we can use it as a black box. In general, you don't need to worry about it. Because we believe in it.
========================================================== ========================================================== ======================================
When the message arrives here, And before entering the MFC field. Step 1, it can be said that the peak is often turned back and the mountains are heavy. After step 2, it is a dark flower, you can sing a song all the way, go straight to the destination.

I want to know what to do later, and listen to the next decomposition!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.