#行家计划#书接上文,逆向学习如积沙成塔,如古人言:“不积跬步,无以至千里.不积小流,无以成江海”。逆向学习非常枯燥,非常需要时间。废话不多说,直接进入主题。
上文我们在反汇编找到了winmain函数,接下来我们需要寻找到窗口的处理函数,才能针对不同的消息(如针对鼠标左右击等)下条件断点。
typedef struct { UINT style; WNDPROC lpfnWndProc; //窗口处理函数 int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; //实例句柄,winmain的第一个参数,ImageBase HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; //背景画刷 LPCTSTR lpszMenuName; LPCTSTR lpszClassName; //一类窗口类名} WNDCLASS, *PWNDCLASS;
The WNDCLASS structure contains the window class attributes that are registered by the RegisterClass function.
结构WNDCLASS包含一个窗口类的全部信息,也是Windows编程中使用的基本数据结构之一,应用程序通过定义一个窗口类确定窗口的属性,为了快速进入主题,在此只介绍比较重要的成员。其他的成员可以通过MSDN Library或网络进行查询。
WNDPROC lpfnWndProc;
Pointer to the window procedure. You must use the CallWindowProc function to call the window procedure.
指向窗口处理函数的指针,而具体的窗口处理函数形式如下:
LRESULT CALLBACK WindowProc(HWND hwnd, //窗口句柄 UINT uMsg, //消息类型,常量标识 WPARAM wParam,//消息的附加信息 LPARAM lParam);//消息的附加信息
The WindowProc function is an application-defined function that processes messages sent to a window. The WNDPROC type defines a pointer to this callback function. WindowProc is a placeholder for the application-defined function name.
窗口处理函数的主要作用是处理该窗口所需的消息,即从应用程序消息队列中取出消息进行处理。如针对该窗口的移动,初始化,拉伸等等。其成员组成和MSG结构体成员很类似。如下是一个简单的消息处理函数:
LRESULT CALLBACK WindowProc( HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg){case WM_CREATE: {//窗口创建return 0;}case WM_MOVE:{//窗口移动return 0;}case WM_DESTROY:{//窗口销毁return 0;}case WM_KEYUP:{//按下键return 0;}case WM_KEYDOWN:{//抬起键return 0;}case WM_LBUTTONDOWN:{//鼠标左击return 0;}}return DefWindowProc(hwnd,uMsg,wParam,lParam);//不需要的消息,交由系统处理}
其他成员可以初始化为0,窗口类属性定义好以后,还需要注册。而RegisterClass()就是在系统注册某一类型的窗体。也就是将你提供的WNDCLASS数据注册为一个窗口类,在WNDCLASS.lpszClassName中定义该WNDCLASS的标识。
typedef WORD ATOM;ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
根据上一篇文章的步骤进入winmain领空:
winmain领空
图片的标号1是将wndclass的地址放到eax寄存器中,标号2就是RegisterClassA的参数也就是wndclass结构体的地址。所以我在标号2处下断点就可以知道wndclass结构体在哪。按F2下断点,然后放开程序,让程序停到断点处,此时eax存的就是wndclass地址。
程序停到断点处
将鼠标放在eax上单击鼠标右键,选择follow in stack (此时EBP 0019FF70,ESP 0019FE9C,eax 0019FEC0,此地址在栈中)
wndclass所在栈图
此时标号1就是第一个成员,标识2就是第二个成员,也就是窗口处理函数所在地址,标识3就是最后一个成员即窗口的类名。然后将鼠标放置在第二成员上,然后单击鼠标右键,选择Follow in Disassembler(追到反汇编)。窗口处理函数领空如下图:
窗口处理函数领空
esp+8就是窗口处理函数的第二参数即消息类型。
消息类型
为什么esp+8就是消息类型?初步推理,上层调用消息处理函数时,压栈4个参数(从右向左压栈,窗口处理函数使用stdcall),然后使用call 0x4xxxx,即将自身下一行地址压栈。
上层函数调用窗口处理函数
鼠标左击时窗口处理函数栈图
下个条件断点证明一下,条件断点方法如下图
步骤1
步骤2
步骤3
//左右击常量#define WM_LBUTTONDOWN 513#define WM_LBUTTONUP 514#define WM_RBUTTONDOWN 516#define WM_RBUTTONUP 517
返回反汇编界面
然后在该应用程序的窗口中点击鼠标左键。
左击触发
此时我们看到[esp+8]为0x201,即十进制的513,而左击常量WM_LBUTTONDOWN为513。故esp+8为消息类型。
进制转换
此篇到此结束,欲知后事如何,且看下文分解(可能还没写)。该文仅为学习记录,如有不足,望海涵批评指正。本文及该合集文章仅限学习,不可用于非法用途,一切后果与本人无关。
留言与评论(共有 0 条评论) “” |