滴水逆向-ESP_EBP寻址_定位回调函数

ESP寻址

ESP作为堆栈指针寄存器,存储栈顶指针指向的地址。但是当出现堆栈传参之类的操作时,栈顶发生了变化,就需要先对栈顶指针进行修正后再用ESP进行寻址,比较麻烦

EBP寻址

EBP指向的是栈底,如果栈顶发生变化,也只会改变ESP的值。这时我们就可以通过EBP来寻址更为方便

回调函数的定位

下面有一个简单的窗口程序:

#include "stdafx.h"
#include "Tools.h"

HINSTANCE hAppInstance;

LRESULT CALLBACK WindowProc(  
	IN  HWND hwnd,  
	IN  UINT uMsg,  
	IN  WPARAM wParam,  
	IN  LPARAM lParam  
	);  


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	// TODO: Place code here.
	hAppInstance = hInstance;
	
	//窗口的类名
	PSTR className = "My First Window"; 
	
	// 创建窗口类的对象 
	WNDCLASS wndclass = {0};						//一定要先将所有值赋值
	wndclass.hbrBackground = (HBRUSH)COLOR_MENU;	//窗口的背景色
	wndclass.lpfnWndProc = WindowProc;				//窗口过程函数
	wndclass.lpszClassName = className;				//窗口类的名字	
	wndclass.hInstance = hInstance;					//定义窗口类的应用程序的实例句柄

	
	// 注册窗口类  
	// 参加MSDN文档RegisterClass->Parameters:
	// You must fill the structure with the appropriate class attributes 
	// before passing it to the function. 
	RegisterClass(&wndclass);  
	
	// 创建窗口  
	HWND hwnd = CreateWindow(  
		className,				//类名
		"我的第一个窗口",		//窗口标题
		WS_OVERLAPPEDWINDOW,	//窗口外观样式  
		10,						//相对于父窗口的X坐标
		10,						//相对于父窗口的Y坐标
		600,					//窗口的宽度  
		300,					//窗口的高度  
		NULL,					//父窗口句柄,为NULL  
		NULL,					//菜单句柄,为NULL  
		hInstance,				//当前应用程序的句柄  
		NULL);					//附加数据一般为NULL
	
	if(hwnd == NULL)			//是否创建成功  
		return 0;  
	
	// 显示窗口  
	ShowWindow(hwnd, SW_SHOW);  
	
	// 更新窗口  
	UpdateWindow(hwnd);  
	
	// 消息循环  
	MSG msg;  
	while(GetMessage(&msg, NULL, 0, 0))  
	{  
		TranslateMessage(&msg);  
		DispatchMessage(&msg);  
	}  
	
	return 0;  
}


LRESULT CALLBACK WindowProc(  
	IN  HWND hwnd,  
	IN  UINT uMsg,  
	IN  WPARAM wParam,  
	IN  LPARAM lParam  
	)  
{  
	switch(uMsg)
	{
		//窗口消息
		case WM_CREATE: 
			{
				DbgPrintf("WM_CREATE %d %d\n",wParam,lParam);
				CREATESTRUCT* createst = (CREATESTRUCT*)lParam;
				DbgPrintf("CREATESTRUCT %s\n",createst->lpszClass);
				break;
			}
		case WM_MOVE:
			{
				DbgPrintf("WM_MOVE %d %d\n",wParam,lParam);
				POINTS points = MAKEPOINTS(lParam);
				DbgPrintf("X Y %d %d\n",points.x,points.y);
				break;
			}
		case WM_SIZE:
			{
				DbgPrintf("WM_SIZE %d %d\n",wParam,lParam);
				int newWidth  = (int)(short) LOWORD(lParam);    
				int newHeight  = (int)(short) HIWORD(lParam);   
				DbgPrintf("WM_SIZE %d %d\n",newWidth,newHeight);
				break;
			}
		case WM_DESTROY:
			{
				DbgPrintf("WM_DESTROY %d %d\n",wParam,lParam);
				PostQuitMessage(0);
				return 0;
				break;
			}
		//键盘消息
		case WM_KEYUP:
			{
				DbgPrintf("WM_KEYUP %d %d\n",wParam,lParam);
				break;
			}
		case WM_KEYDOWN:
			{
				DbgPrintf("WM_KEYDOWN %d %d\n",wParam,lParam);
				break;
			}
		//鼠标消息
		case WM_LBUTTONDOWN:
			{
				DbgPrintf("WM_LBUTTONDOWN %d %d\n",wParam,lParam);
				POINTS points = MAKEPOINTS(lParam);
				DbgPrintf("WM_LBUTTONDOWN %d %d\n",points.x,points.y);
				break;
			}
		default:  
			return DefWindowProc(hwnd,uMsg,wParam,lParam);
	}
	return 0;  
}  

这个窗口程序一共有六步:创建窗口类、注册窗口类、创建窗口、显示窗口、消息循环以及回调函数。在创建窗口类的时候会初始化窗口结构体的一些值,其中就包括了lpfnWndProc。lpfnWndProc储存了回调函数的地址,在而注册窗口类时用到的函数RegisterClass()会将这个窗口类的信息拿去注册。也就是说,只要找到RegisterClass()函数,再从它注册的内容中找到lpfnWndProc指向的地址,就能定位到这个回调函数

F8下来找到函数RegisterClass()在这里插入图片描述
RegisterClass()函数只有一个参数,我们有理由猜测004010BC处的PUSH EDX语句就是传递的这个参数

然后我们单步到这个位置,查看堆栈
在这里插入图片描述
我们发现现在堆栈里面有连续的十个0,而刚好WNDCLASS类有十个成员,与我们的猜想有些印证。所以接下来我们锁定堆栈,单步到call,我们发现这四个mov指令刚好传进来4个参数,和我们初始化wndclass的成员数量一样
在这里插入图片描述
我们查文档,发现第二个参数就是lpfnWndClass
在这里插入图片描述
所以我们就找到了回调函数的地址
在这里插入图片描述

具体事件的消息定位

假设我们捕获鼠标左键的消息,我们先反汇编跟到上面这个回调函数的地方
在这里插入图片描述
由于消息是一直都在循环的,打开一个窗口就会出现好几十个事件,如果断在这里,会一直触发事件,不停地在这里下断点,因此我们在这里下一个条件断点在这里插入图片描述
而由于MSG结构体里面的第二个成员就是消息ID,所以我们把条件加在[esp+8]处(假设只捕获鼠标左键的消息)

所有内容均参考滴水逆向三期

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值