前言:
windows窗口编程就是创造一个窗口并实现消息循环,我们需要逆向的是窗口消息处理函数
流程:
入口点:
窗口的入口点是WinMain()函数
1 | int WINAPI WinMain( |
HINSTANCE hInstance :
含义:当前模块(process module)的实例句柄。
现代 Windows(32/64 位)中
HINSTANCE与HMODULE等价,表示模块基址(即 exe 或 dll 的加载基址)。也就是说HINSTANCE == HMODULE。常用场景:作为资源加载的句柄参数(
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APP))、FindResource(hInstance, ...)等);也常用来创建窗口类WNDCLASSEX.hInstance。获取方式:程序入口
WinMain会直接给出;也可以在任意地方用GetModuleHandle(NULL)获取当前可执行模块句柄,或GetModuleHandle("mylib.dll")获取指定 DLL 的句柄。x86/x64 区别:无差别。都是指向模块基址的句柄(底层为值型,大小随平台指针宽度而定)。
只有在16位可执行程序里会有差别,因为16位同时多开exe,并不是独立的分割内存,而如今都是每个进程分配4gb
HINSTANCE hPreInstance 已废弃,填null即可
LPSTR lpcmdeline:含义:指向以空字符结尾的命令行字符串(
char*,ANSI 版WinMain使用)。int nCmdShow:含义:程序窗口的初始显示状态,由操作系统或调用者(例如从快捷方式的“运行方式”设置或
ShowWindow参数)传入。通常传给ShowWindow(hwnd, nCmdShow)。
1.创建一个窗口类
1 | WNDCLASSW myClass = { 0 }; |
其中WNDCLASSW的定义:
1 | typedef struct tagWNDCLASSEX { |
其中最重要的就是 WNDPROC lpfnWndProc; // 窗口过程指针。做逆向只需要学会它的用法
2.注册窗口类
RegisterClassW(&myClass);
3.创建窗口
用 CreateWindowW
1 | //3.创建窗口 |
函数定义:
1 | HWND CreateWindowEx( |
dwExStyle/dwStyle:窗口扩展样式 / 样式(WS、WS_EX)lpClassName:类名(或 Atom)lpWindowName:窗口标题(Caption)hMenu:菜单或子控件 ID(对于子窗口/控件是控件 ID)lpParam:传递给WM_CREATE的CREATESTRUCT*的lpCreateParams字段(常用于传递指针)
逆向:CreateWindowEx返回的HWND常会被存到全局或成员变量中,搜索mov [global], eax(x86)或mov [rip+..], rax(x64)可定位。若使用类 atom(整数),
lpClassName参数的高位为小值。
补充:winapi中A版本和W版本(就是函数后的字母)区别只有参数可不可以是unicode的区别,W版本可以用unicode编码,比如说可以写字符串L’这是unicode编码’
4.显示窗口
ShowWindow(hwindow, SW_SHOWNORMAL);
1 | BOOL ShowWindow(HWND hWnd, int nCmdShow); |
ShowWindow常在窗口创建后调用以显示窗口(nCmdShow=SW_SHOW, SW_SHOWNORMAL 等)UpdateWindow触发WM_PAINT(如果需要)
5.消息循环
1 | MSG msg; |
GetMessage:
获取消息,如果不是WM_quit就接着循环
TranslateMessage / DispatchMessage
TranslateMessage:将虚拟键消息转换为字符消息(WM_KEYDOWN -> WM_CHAR)DispatchMessage:把消息派发到目标窗口的 WndProc(最终调用CallWindowProc)
6.分析WndProc
1 | LRESULT CALLBACK WindowProc( //消息处理函数 |
其中函数参数:
| 参数 | 类型 | 典型用途 | 注意点 |
|---|---|---|---|
HWND hwnd |
窗口句柄 | 唯一标识窗口实例 | 用于区分不同窗口 |
UINT uMsg |
消息ID | 指定当前消息类型 | 用于 switch 分发 |
WPARAM wParam |
辅助参数 | 消息相关状态/标志/ID | 含义因消息而异 |
LPARAM lParam |
扩展参数 | 附加数据,如坐标、句柄 | 依赖消息类型解释 |
最常见的wparam和lparam的用法:
| 消息类型 | wParam 含义 |
|---|---|
WM_KEYDOWN |
虚拟键码(VK_XXX) |
WM_LBUTTONDOWN |
鼠标按键状态(MK_CONTROL / MK_SHIFT 等标志) |
WM_COMMAND |
高16位是通知码(如按钮点击),低16位是控件ID(父窗口内的代号) |
WM_TIMER |
定时器ID |
| 消息 | lParam 含义 |
|---|---|
WM_MOUSEMOVE(鼠标移动), WM_LBUTTONDOWN(鼠标左键被按下) 等 |
低16位 = X坐标, 高16位 = Y坐标 |
WM_COMMAND(操作菜单、控件,快捷键、加速键,或程序调用 SendMessage(hwnd, WM_COMMAND, …) 时,系统就会发送这个消息给对应的窗口过程。) |
如果来自控件(子窗口):lParam 是该控件的 HWND。如果来自菜单/加速键:lParam 为 0(因此可以用来区分) |
具体消息和处理逆向我们还需要进一步积累,这里只是起抛砖引玉的作用
实际例子:
1 |
|