Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程

这篇具有很好参考价值的文章主要介绍了Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本专栏上一篇文章中我们讲解了Win32程序入口识别,定位回调函数,具体事件处理的定位,这一章节中我们来讲解一下子窗口的创建,子窗口的回调函数,并且逆向分析子窗口消息处理过程。

一.子窗口按钮的创建

我在学到本课程中Win32的时候,实在是听不懂,所以我专门去学习了Win32应用程序设计,当然,我也在CSDN中分享出来了我的学习成果,大家如果不是很理解这里的子窗口的创建的话,可以到我的达内Windows/Win32编程中大致看一下:达内Windows/Win32编程专栏。
这里我们讲解子窗口:按钮的创建过程。
在windows内核中,不仅有我们注册进去的窗口类,还有一些系统已经帮我们注册好的窗口类,这里的按钮就是系统帮我们注册好的窗口类。我们在创建按钮的时候,直接调用就可以了。
我们来看看创建按钮的实操:

- 创建子窗口:

使用CreateWindow()函数:
MSDN官方文档解释该函数

	HWND hButton = CreateWindow(
		TEXT("Button"), 
		TEXT("anniu"),
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_DEFPUSHBUTTON,
		10, 10,
		80, 20,
		hwnd,
		(HMENU)1001,     //这是一个编号,我们后面对子串口消息做处理的时候会用到
		hIns,
		NULL);

注意这里的创建子窗口一定要在主窗口创建之后,因为我们在创建子窗口的时候需要用到父窗口句柄。
实际上这里创建了子窗口之后,正常编写显示窗口等等,按钮就被创建出来了:

// P74子窗口(按钮).cpp : 定义应用程序的入口点。
//
#define _CRT_SECURE_NO_WARNINGS 1
#include "framework.h"
#include "P74子窗口(按钮).h"
#include <stdio.h>
#define MAX_LOADSTRING 100

HANDLE g_hOUTPUT = 0;   //接收标准输出句柄
HINSTANCE hIns = 0;
LRESULT CALLBACK WindowProc(
	IN  HWND hwnd,
	IN  UINT uMsg,
	IN  WPARAM wParam,
	IN  LPARAM lParam
);        //普通窗口回调函数

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	hIns = hInstance;
	//窗口类名
	TCHAR className[] = TEXT("My First Windows.");
	//创建窗口对象
	WNDCLASS wndclass = { 0 };
	wndclass.hbrBackground = (HBRUSH)0;            //窗口背景颜色
	wndclass.lpfnWndProc = WindowProc;                    //窗口的过程函数
	wndclass.lpszClassName = className;                     //窗口的类名字
	wndclass.hInstance = hInstance;                         //定义窗口类的应用程序的实例句柄
	wndclass.lpszMenuName = NULL;
	//注册窗口
	RegisterClass(&wndclass);
	//创建窗口
	HWND hwnd = CreateWindow(
		className,                         //lpname类名
		TEXT("我的第一个窗口。"),          //窗口标题
		WS_OVERLAPPEDWINDOW,               //dwStyle
		10,
		10,
		600,
		300,
		NULL,
		NULL,
		hInstance,
		NULL);
	HWND hButton = CreateWindow(
		TEXT("Button"), 
		TEXT("按钮"),
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|BS_DEFPUSHBUTTON,
		10, 10,
		80, 20,
		hwnd,
		(HMENU)1001,
		hIns,
		NULL);

	//显示窗口
	ShowWindow(hwnd, SW_SHOW);

	// 主消息循环:
	MSG msg;
	while (1) {
		if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
			if (GetMessage(&msg, NULL, 0, 0)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else {
				return 0;
			}
		}
		else {
			//在空闲的时候,我们想让它做什么就可以填在这里
			//i++;
			//TCHAR std[256] = { 0 };
			//sprintf((char*)std,TEXT("进程无消息....%d\n"), i++);
			//WriteConsole(g_hOUTPUT, std,strlen((const char*)std), 0, 0);
		}
	}
	return (int)msg.wParam;
};
LRESULT CALLBACK WindowProc(
	IN  HWND hwnd,
	IN  UINT uMsg,
	IN  WPARAM wParam,
	IN  LPARAM lParam
)
{
	char output[256] = { 0 };
	switch (uMsg)
	{
		//常见消息
	case WM_DESTROY: {
		PostQuitMessage(0);
		return 0;
	}
	case WM_CREATE: {
		sprintf(output, "检测到WM_CREATE消息,将创建窗口。\n");
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_SIZE: {
		sprintf(output, "lParam:窗口宽变化为:%d,窗口高变化为:%d \n", HIWORD(lParam), LOWORD(lParam));
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	//键盘消息
	case WM_KEYDOWN: {
		sprintf(output, "检测到WM_KEYDOWN消息,键码值:%d.\n", wParam);
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_KEYUP: {
		sprintf(output, "检测到WM_KEYUP消息,键码值:%d.该按键被放开\n", wParam);
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	//鼠标消息
	case WM_LBUTTONDOWN: {
		sprintf(output, "检测到WM_LBUTTONDOWN消息,鼠标左键被按下。\n");
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_LBUTTONUP: {
		sprintf(output, "检测到WM_LBUTTONUP消息,鼠标左键被放开。\n");
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_RBUTTONDOWN: {
		sprintf(output, "检测到WM_RBUTTON消息,鼠标右键被按下。\n");
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_RBUTTONUP: {
		sprintf(output, "检测到WM_RBUTTON消息,鼠标右键被放开。\n");
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_MOUSEMOVE: {
		sprintf(output, "检测到WM_MOUSEMOVE消息,鼠标移动中,鼠标位置(%d,%d).\n", LOWORD(lParam), HIWORD(lParam));
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0; break;
	}
	case WM_MOUSEWHEEL: {
		sprintf(output, "鼠标滚轮滚动中,偏移量:%d,鼠标当前位置(%d,%d)\n", HIWORD(wParam), LOWORD(lParam), HIWORD(lParam));
		WriteConsole(g_hOUTPUT, output, strlen(output), 0, 0);
		return 0;
	}
	case WM_CONTEXTMENU: {
		TrackPopupMenu(
			CreatePopupMenu(),
			TPM_LEFTALIGN,
			0, 0, 0, hwnd, 0);
		return 0;
	}
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

这里我是用的很多代码都是之前在编写Windows32程序调试的代码,大家主要看一下创建按钮的过程函数就可以了,我们来看看创建效果:

Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程

获取系统注册的窗口类的信息

我们在使用按钮等系统帮我们注册的窗口类的时候,我们并不能知道类的内部成员的参数,那么既然我们是学底层的,我们就应该了解一下它内部的参数:

  • 获取类名:
    使用GetClassName()函数,MSDN官方文档解释
int GetClassName(
  [in]  HWND   hWnd,
  [out] LPTSTR lpClassName,
  [in]  int    nMaxCount
);

参数解释:
hWnd:我们已经创建了的窗口的句柄
lpClassName:这是一个OUT类型的参数,获取到的名称字符串将被存储进去
nMaxCount:最大长度

这个函数能获取已经创建了的窗口类名

  • 获取窗口类的完整参数:
    使用GetClassInfo()函数,MSDN官方文档解释
BOOL GetClassInfoA(
  [in, optional] HINSTANCE   hInstance,
  [in]           LPCSTR      lpClassName,
  [out]          LPWNDCLASSA lpWndClass
);

参数解释:
hInstance:当前应用程序实例句柄,也就是那个ImageBase,我们需要使用全局变量来取得
lpClassName:窗口类名
lpWndClass:这是一个OUT类型的参数,我们需要先定义一个WndClass类型的结构,用于存储获取到的参数,然后将这个结构的地址给这个参数,获取到的参数将会被存储到这个结构体中。

二.按钮事件处理

我们来看看按钮消息的处理过程:

按钮被点击,产生消息->操作系统WinProc->转化为WM_COMMAND类型的消息->父窗口的WinProc

这里其实子窗口的消息处理函数最后都会被传到主窗口的消息处理函数中,所以我们需要处理按钮消息的时候,只需要在主窗口的消息处理函数中处理即可:
这里给出一段伪代码,供大家理解:

主窗口WinProc(...){
	switch(uMsg){
		case WM_COMMAND:{
			switch(LOWORD(wParam){
				case(消息编号){
				.......//具体处理
				}
			}
		}
	}
}

看到这里,相信大家能看出来,这里的wParam的低两字节,就存储的是消息编号,我们根据这个,就可以对按钮消息做具体处理了。

三.消息堆栈

还记得我们在上一篇文章中对具体的事件做的条件断点的条件吗?
[esp+8] == WM_KEYDOWN
可能有很多人还是不理解这里为啥这里是esp+8,这里我们来看看消息堆栈,相信大家就会恍然大悟:
Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程

WinProc函数需要四个参数,在调用函数之前,就已经压入栈中了,在进入函数的时候,就会在栈中压入返回地址,所以这里的esp+8就是uMsg了。

四.逆向定位子窗口消息处理过程

我们在逆向过程中,必须要学会定位子窗口的消息处理。
我们来看看在逆向过程中定位子窗口消息处理的过程:

  • 定位入口函数
  • 定位主窗口回调函数
    在定位主窗口回调函数之后,结合我们之前讲解的,我们需要在回调函数中做消息断点即可,比如我们要定位的按钮编号为0x000003E9,这里我们将条件设置为[esp+8]==WM_COMMAND && [EXP+0XC]==0X00003E9即可得到断点。
  • 获取按钮编号:我们在OllyDbg中可以直接看到按钮的编号:
    Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程
  • 条件断点设置:
    Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程
    这样,当我们点击按钮的时候,程序就会断在这里了,我们就可以逆向分析出当点击按钮的时候,程序到底做了哪些处理:

Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程
今天的文章就分享到这里,希望对大家有所帮助,另外,如果大家发现了文章中的错误,还请大家指出来,我会非常虚心地学习。希望我们共同进步!!!文章来源地址https://www.toymoban.com/news/detail-463561.html

到了这里,关于Win32子窗口创建,子窗口回调函数,消息堆栈,逆向定位子窗口消息处理过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WEB攻防-JS应用&算法逆向&三重断点调试&调用堆栈&BP插件发包&安全结合

    1、JavaScript-作用域调用堆栈 2、JavaScript-断点调试全局搜索 3、JavaScript-Burp算法模块使用 简单来说就是运行后相关的数据值 简单来说就是代码的执行逻辑顺序 这四种方法针对不同对象(搜索一般用来对付简单的,复杂点的就得用断点了) -代码全局搜索 -文件流程断点(执行的代码

    2024年02月05日
    浏览(14)
  • Win32 GetDeviceCaps 函数学习

    GetDeviceCaps 函数检索指定设备的设备特定信息。 其第二个参数取不同的值,返回不同结果;

    2024年01月21日
    浏览(7)
  • Visual Studio 2022如何创建Win32项目

    1.点击创建新项目,下滑找到 “Windows桌面向导” 。  2.点击 “Windows桌面向导” 之后,点击“下一步”,配置不动,一般都和下面图片一样,点击“创建”  3.应用程序类型要选择“桌面应用程序(.exe)”,并勾选“空项目”。 4.源文件里面新建项。 5.如果运行不出来就设置一

    2024年02月11日
    浏览(16)
  • 【Win32绘图编程,GDI绘图对象】绘图基础,位图处理,绘图消息处理,画笔,画刷,文本绘制

    这一篇文章分享本人学习win32绘图编程,其中包括GDI绘图对象,绘图基础,基本图形的绘制,画笔画刷的使用,文本绘制,以及文本字体的更改。 绘图设备DC(Device Context),有时也叫做绘图上下文/绘图描述表/显示设备上下文 HDC-DC句柄,表示绘图设备 GDI-Windows graphics device

    2024年02月07日
    浏览(19)
  • vue(32) : win10创建vue2基础前端框架

    vue2 element-ui axios 含接口调用示例 开发工具为HBuilderX 3.7.3 等待创建项目 代理后端配置如下, 三个test改成相同的uri前缀即可, uri该签注会代理到后端 proxy: {       // 代理test开头的uri       \\\'/test\\\': {         target: \\\'http://192.168.1.1:8080\\\', // 后端地址         changeOrigin: true, // 开启代

    2024年02月06日
    浏览(13)
  • win32 API 文件夹操作函数整理

    常用操作文件目录的函数 1. CreateDirectory 创建文件夹 原型: 参数说明: lpPathName 要创建的文件夹名称 lpSecurityAttributes 忽略为NULL 返回: 成功返回非零,失败返回零 实例:   2.RemoveDirectory 删除文件夹 原型: 返回: 成功返回非零,失败返回零   3. PathIsDirectory 判断文件夹是否存在 原

    2024年02月05日
    浏览(18)
  • rabbitmq消息可靠性之消息回调机制

    rabbitmq消息可靠性之消息回调机制 rabbitmq在消息的发送与接收中,会经过上面的流程,这些流程中每一步都有可能导致消息丢失,或者消费失败甚至直接是服务器宕机等,这是我们服务接受不了的,为了保证消息的可靠性,rabbitmq提供了以下几种机制 生产者确认机制 消息持久

    2024年02月08日
    浏览(14)
  • stm32---在keil 5中使用printf函数输出到串口USART(printf函数的移植方法)以及补充窗口printf函数输出汉字

    在串口函数初始化的c文件中加上#include stdio.h 重写fputc函数 (fputc是printf函数的底层,printf就是不断调用fputc函数一个个打印,把fputc函数重定向到串口,这样子printf自然就输出到串口) 在主函数main.c编写如下代码后直接运行. 引入#include stdarg.h  对sprintf进行可变参数的函数封装 在主

    2024年02月05日
    浏览(14)
  • 利用win32的GetLastInputInfo函数实现锁屏(C#)

    前两天看到群里面讨论这个问题,刚好我们上一家公司的系统也有这个功能,就研究了一下,我们这边实现这个功能的目的如下:当用户长时间不操作系统时,自动退出系统并退回到登录界面,想要使用系统,就得重新输入账号和密码。 下面是网上搜集到的资料: https://ww

    2024年02月06日
    浏览(26)
  • c# 消息传递和其他用户界面操作的函数 [DllImport(“user32.dll“)]

    `user32.dll`是Windows操作系统的用户界面库,它包含了许多用于窗口管理、用户输入、消息传递和其他用户界面操作的函数。以下是一些常见的`user32.dll`函数的示例: - `MessageBox`: 显示一个消息框,用于向用户显示一条消息并等待用户响应。 - `CreateWindowEx`: 创建一个窗口或控件,

    2024年02月10日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包