逆向学习记录3:寻找窗口处理函数与条件断点

#行家计划#书接上文,逆向学习如积沙成塔,如古人言:“不积跬步,无以至千里.不积小流,无以成江海”。逆向学习非常枯燥,非常需要时间。废话不多说,直接进入主题。

所需知识

上文我们在反汇编找到了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 条评论) “”
   
验证码:

相关文章

推荐文章