什么是消息-事件
Windows中的事件是一个动作,这个动作可能是用户操作应用程序产生的,也可能是Windows自己产生的。
那么又有其他的问题来了:
这个动作是什么时候产生的?哪个应用程序产生的?在什么位置产生的?...
Windows为了能够准确的描述这些信息,提供了一个结构体:MSG,该结构体里面记录的事件的详细信息.
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
参数说明:
-
hwnd:表示消息所属的窗口,一个消息一般都是与某个窗口相关联的,在Windows中 HWND类型的变量通常用来标识窗口。
-
message:在Windows中,消息是由一个数值来表示的,但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM == Window Message),鼠标左键按下WM_LBUTTONDOWN,键盘按下 WM_KEYDOWN
-
wParam 和 lParam:32位消息的特定附加信息,具体表示什么处决于message
-
time:消息创建时的时间
-
pt:消息创建时的鼠标位置
消息触发与处理过程
-
系统/用户触发的某个动作
-
系统将这些信息存储到MSG结构体中
-
系统将该消息存储到相关应用程序的消息队列中
-
MSG Msg;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
-
DispatchMessage将加工过的消息传递给操作系统
-
系统调用窗口过程函数
-
LRESULT CALLBACK WindowProc( //回调函数
IN HWND hwnd,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
);
过程图示:
系统消息队列与应用程序消息队列:
代码
// 消息.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Tools.h"
LRESULT CALLBACK WindowProc(
IN HWND hwnd,
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
switch(uMsg)
{
//窗口消息
case WM_CREATE:
{
DbgPrintf("WM_CREATE %d %dn",wParam,lParam);
CREATESTRUCT* createst = (CREATESTRUCT*)lParam;
DbgPrintf("CREATESTRUCT %sn",createst->lpszClass);
return 0;
}
case WM_MOVE:
{
DbgPrintf("WM_MOVE %d %dn",wParam,lParam);
POINTS points = MAKEPOINTS(lParam);
DbgPrintf("X Y %d %dn",points.x,points.y);
return 0;
}
case WM_SIZE:
{
DbgPrintf("WM_SIZE %d %dn",wParam,lParam);
int newWidth = (int)(short) LOWORD(lParam);
int newHeight = (int)(short) HIWORD(lParam);
DbgPrintf("WM_SIZE %d %dn",newWidth,newHeight);
return 0;
}
case WM_DESTROY:
{
DbgPrintf("WM_DESTROY %d %dn",wParam,lParam);
PostQuitMessage(0);
return 0;
}
//键盘消息
case WM_KEYUP:
{
DbgPrintf("WM_KEYUP %d %dn",wParam,lParam);
return 0;
}
case WM_KEYDOWN:
{
DbgPrintf("WM_KEYDOWN %d %dn",wParam,lParam);
return 0;
}
//鼠标消息
case WM_LBUTTONDOWN:
{
DbgPrintf("WM_LBUTTONDOWN %d %dn",wParam,lParam);
POINTS points = MAKEPOINTS(lParam);
DbgPrintf("WM_LBUTTONDOWN %d %dn",points.x,points.y);
return 0;
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
//窗口的类名
TCHAR className[] = "My First Window";
// 创建窗口类的对象
WNDCLASS wndclass = {0}; //一定要先将所有值赋值
wndclass.hbrBackground = (HBRUSH)COLOR_MENU; //窗口的背景色
wndclass.lpfnWndProc = WindowProc; //窗口过程函数
wndclass.lpszClassName = className; //窗口类的名字
wndclass.hInstance = hInstance; //定义窗口类的应用程序的实例句柄
//注册窗口类
RegisterClass(&wndclass);
// 创建窗口
HWND hwnd = CreateWindow(
className, //类名
TEXT("我的第一个窗口"), //窗口标题
WS_OVERLAPPEDWINDOW, //窗口外观样式
10, //相对于父窗口的X坐标
10, //相对于父窗口的Y坐标
600, //窗口的宽度
300, //窗口的高度
NULL, //父窗口句柄,为NULL
NULL, //菜单句柄,为NULL
hInstance, //当前应用程序的句柄
NULL); //附加数据一般为NULL
if(hwnd == NULL) //是否创建成功
return 0;
// 显示窗口
ShowWindow(hwnd, SW_SHOW);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// Tools.cpp: implementation of the Tools class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Tools.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void __cdecl OutputDebugStringF(const char *format, ...)
{
va_list vlArgs;
char *strBuffer = (char*)GlobalAlloc(GPTR, 4096);
va_start(vlArgs, format);
_vsnprintf(strBuffer, 4096 - 1, format, vlArgs);
va_end(vlArgs);
strcat(strBuffer, "n");
OutputDebugStringA(strBuffer);
GlobalFree(strBuffer);
return;
}
// Tools.h: interface for the Tools class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_TOOLS_H__0D7FE55E_21D9_445D_9CC3_340759DED8A2__INCLUDED_)
#define AFX_TOOLS_H__0D7FE55E_21D9_445D_9CC3_340759DED8A2__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
void __cdecl OutputDebugStringF(const char *format, ...);
#ifdef _DEBUG
#define DbgPrintf OutputDebugStringF
#else
#define DbgPrintf
#endif
#endif // !defined(AFX_TOOLS_H__0D7FE55E_21D9_445D_9CC3_340759DED8A2__INCLUDED_)
OD分析
-
生成Release版本
-
开始分析:
-
OD打开时:
-
会找到一个GetModuleHandleA,该函数返回的是一个窗口句柄,那么返回值返回到eax中,所以,下面的PUSH EAX,就是将窗口句柄传入call 消息.00401060函数中,那么该函数应该就是入口函数了。
-
跟进该函数中,我们发现了一个RegisterClassA函数,根据我们的代码,那么这个call上面的
PUSH EDX
应该就是我们的wndclass
类,将断点下到该处: -
查看edx对应的堆栈,记住,该edx对应的就是wndclass地址。目前我们发现都是0,没关系,我们将代码继续执行,为了方便观察,我们锁定堆栈窗口
-
-
接着,我们继续执行代码,执行到CALL指令:
-
根据上图,可以知道,我们的回调函数,就是该函数指针的第二个位置。我们跟进去
-
找到esp+0x8,这个地方是什么呢?
-
-
根据我们的回调函数,我们知道,这个是消息ID,因此,我们可以通过条件断点,找我们需要的消息ID。
现在,我们知道如何对我们需要的消息下断点了。
原文始发于微信公众号(loochSec):OD定位消息-事件
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论