小实例与atl基本概念
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
using namespace ATL;
// 自定义消息(仿你的 0x8007/0x8009/0x37F)
constexpr UINT WM_APP_8007 = 0x8007;
constexpr UINT WM_APP_8009 = 0x8009;
constexpr UINT WM_APP_037F = 0x037F;
// 按钮 ID
enum : int {
IDC_BTN_SEND8007 = 1001,
IDC_BTN_ASK8009 = 1002,
IDC_BTN_SEND037F = 1003
};
// 用来模拟你看到的 *(*(this+32)+32)=1(handled flag)
struct DispatchState
{
BYTE pad[32]; // 0..31
int handledFlag; // offset 32
DispatchState() : handledFlag(0) {}
};
class CMainWindow : public CWindowImpl<CMainWindow>
{
public:
// 避免 DECLARE_WND_CLASSW 在某些工程配置下宏解析异常,使用最稳的 GetWndClassInfo
static ATL::CWndClassInfo& GetWndClassInfo()
{
static ATL::CWndClassInfo wc =
{
{ sizeof(WNDCLASSEXW),
CS_HREDRAW | CS_VREDRAW,
StartWindowProc,
0, 0,
nullptr,
nullptr,
nullptr,
(HBRUSH)(COLOR_WINDOW + 1),
nullptr,
L"ATLProject1_MainWindow",
nullptr },
nullptr, nullptr, IDC_ARROW, TRUE, 0, _T("")
};
return wc;
}
BEGIN_MSG_MAP(CMainWindow)
MESSAGE_HANDLER(WM_CREATE, OnAnyMessage)
MESSAGE_HANDLER(WM_DESTROY, OnAnyMessage)
MESSAGE_HANDLER(WM_CLOSE, OnAnyMessage)
MESSAGE_HANDLER(WM_COMMAND, OnCommand)
MESSAGE_HANDLER(WM_APP_8007, OnAnyMessage)
MESSAGE_HANDLER(WM_APP_8009, OnAnyMessage)
MESSAGE_HANDLER(WM_APP_037F, OnAnyMessage)
// 其他消息走默认处理
END_MSG_MAP()
CMainWindow()
{
m_state = new DispatchState();
}
~CMainWindow()
{
delete m_state;
m_state = nullptr;
}
private:
DispatchState* m_state = nullptr;
HWND m_forwardHwnd = nullptr; // 对应你反编译里的 *(this+64)
int m_counter = 0;
private:
// 仿 sub_7217A0(this, lParam)
int sub_7217A0_like(LPARAM /*lParam*/)
{
m_forwardHwnd = ::CreateWindowExW(
0, L"STATIC", L"(Forward target: STATIC)",
WS_CHILD | WS_VISIBLE,
20, 20, 320, 24,
m_hWnd, nullptr, ::GetModuleHandleW(nullptr), nullptr);
::CreateWindowExW(0, L"BUTTON", L"Send 0x8007",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
20, 60, 140, 32,
m_hWnd, (HMENU)(INT_PTR)IDC_BTN_SEND8007, ::GetModuleHandleW(nullptr), nullptr);
::CreateWindowExW(0, L"BUTTON", L"Ask 0x8009",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
170, 60, 140, 32,
m_hWnd, (HMENU)(INT_PTR)IDC_BTN_ASK8009, ::GetModuleHandleW(nullptr), nullptr);
::CreateWindowExW(0, L"BUTTON", L"Send 0x037F",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
320, 60, 140, 32,
m_hWnd, (HMENU)(INT_PTR)IDC_BTN_SEND037F, ::GetModuleHandleW(nullptr), nullptr);
return 0;
}
// 仿 sub_721920(this)
void sub_721920_like()
{
m_forwardHwnd = nullptr;
}
// 仿 sub_721780()
void sub_721780_like()
{
::MessageBoxW(m_hWnd, L"WM_CLOSE intercepted (sub_721780-like).", L"ATLProject1", MB_OK);
}
// 仿 sub_721980(this, lParam, wParam)
int sub_721980_like(LPARAM lp, WPARAM wp)
{
wchar_t buf[128]{};
::wsprintfW(buf, L"Handled 0x037F: wp=%llu lp=%llu",
(unsigned long long)wp, (unsigned long long)lp);
::MessageBoxW(m_hWnd, buf, L"0x037F", MB_OK);
return 123;
}
// ====== 核心:仿你那个 maybe3 的 switch(但用 ATL handler 包起来)======
BOOL maybe3_like(UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& outResult, int a7_like)
{
if (a7_like) // 对应 if(a7) return 0;
return FALSE;
switch (Msg)
{
case WM_CREATE: // 1
m_state->handledFlag = 1;
outResult = sub_7217A0_like(lParam);
return TRUE;
case WM_DESTROY: // 2
m_state->handledFlag = 1;
sub_721920_like();
outResult = 0;
return TRUE;
case WM_CLOSE: // 0x10
m_state->handledFlag = 1;
sub_721780_like();
outResult = 0;
return TRUE;
case WM_APP_8007: // 0x8007
m_state->handledFlag = 1;
outResult = (m_forwardHwnd)
? ::SendMessageW(m_forwardHwnd, WM_APP_8007, wParam, lParam)
: 0;
return TRUE;
case WM_APP_8009: // 0x8009
m_state->handledFlag = 1;
outResult = 1;
return TRUE;
case WM_APP_037F: // 0x37F
m_state->handledFlag = 1;
outResult = sub_721980_like(lParam, wParam);
return TRUE;
}
return FALSE;
}
LRESULT OnAnyMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
LRESULT lr = 0;
// 这里的 a7_like 我们固定传 0,等价于“允许处理”
if (maybe3_like(uMsg, wParam, lParam, lr, 0))
{
bHandled = TRUE;
// 对应你反编译的:if(flag) return 1;
return lr;
}
bHandled = FALSE;
return 0;
}
LRESULT OnCommand(UINT, WPARAM wParam, LPARAM, BOOL& bHandled)
{
if (HIWORD(wParam) != BN_CLICKED)
{
bHandled = FALSE;
return 0;
}
switch (LOWORD(wParam))
{
case IDC_BTN_SEND8007:
::SendMessageW(m_hWnd, WM_APP_8007, 0x11, 0x22);
bHandled = TRUE;
return 0;
case IDC_BTN_ASK8009:
{
LRESULT r = ::SendMessageW(m_hWnd, WM_APP_8009, 0, 0);
wchar_t buf[64]{};
::wsprintfW(buf, L"0x8009 returned: %lld", (long long)r);
::MessageBoxW(m_hWnd, buf, L"Ask 0x8009", MB_OK);
bHandled = TRUE;
return 0;
}
case IDC_BTN_SEND037F:
::SendMessageW(m_hWnd, WM_APP_037F, 0xAA, 0xBB);
bHandled = TRUE;
return 0;
}
bHandled = FALSE;
return 0;
}
};
// ====== ATL EXE Module(你的模板风格)======
class CATLProject1Module : public ATL::CAtlExeModuleT<CATLProject1Module>
{
public:
DECLARE_LIBID(LIBID_ATLProject1Lib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_ATLPROJECT1, "{2f5aaa8a-ac5d-490a-aabe-66c834990abe}")
int Run(int nShowCmd) throw()
{
CMainWindow wnd;
HWND hWnd = wnd.Create(nullptr, CWindow::rcDefault,
L"ATLProject1 - maybe3-like (no ProcessWindowMessage override)",
WS_OVERLAPPEDWINDOW);
if (!hWnd)
return 0;
::ShowWindow(hWnd, nShowCmd);
::UpdateWindow(hWnd);
MSG msg{};
while (::GetMessageW(&msg, nullptr, 0, 0))
{
::TranslateMessage(&msg); // ✅ 正确:没有 TranslateMessageW
::DispatchMessageW(&msg);
}
return (int)msg.wParam;
}
};
CATLProject1Module _AtlModule;
// ✅ 用 SAL 注解,解决 /analyze 下 “wWinMain 批注不一致”
// (_tWinMain 在 UNICODE 下就是 wWinMain,但这里我们按模板签名加注解)
extern "C" int WINAPI _tWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nShowCmd)
{
(void)hInstance; (void)hPrevInstance; (void)lpCmdLine;
return _AtlModule.WinMain(nShowCmd);
}ATL框架
C++模板库用于简化COM组件和windows窗口开发
窗口类:CWindowImpl
1
class CMainWindow : public CWindowImpl<CMainWindow>
CWindowImpl<T>是ATL窗口类的基本模板,派生类CMainWindow将自己作为模板参数传入这个主要是负责窗口创建和消息循环之类的底层细节,跟逆向关系不大
windows消息ID
消息ID划分
系统保留信息(0x0000 - 0x03FF),用户自定义消息(0x0400 - 0x7FFF),应用程序注册消息(0x8000 - 0xBFFF)
在代码中就是:
1
2
3constexpr UINT WM_APP_8007 = 0x8007;
constexpr UINT WM_APP_8009 = 0x8009;
constexpr UINT WM_APP_037F = 0x037F;定义了三个应用程序注册信息
消息映射:BEGIN_MSG_MAP / END_MSG_MAP
1
2
3
4
5
6
7
8
9
10
11
12
13BEGIN_MSG_MAP(CMainWindow)
MESSAGE_HANDLER(WM_CREATE, OnAnyMessage)
MESSAGE_HANDLER(WM_DESTROY, OnAnyMessage)
MESSAGE_HANDLER(WM_CLOSE, OnAnyMessage)
MESSAGE_HANDLER(WM_COMMAND, OnCommand)
MESSAGE_HANDLER(WM_APP_8007, OnAnyMessage)
MESSAGE_HANDLER(WM_APP_8009, OnAnyMessage)
MESSAGE_HANDLER(WM_APP_037F, OnAnyMessage)
// 其他消息走默认处理
END_MSG_MAP()这个是ATL最重要的一部分,可以看到其有四个win32标准消息,三个用户自定义的消息
MESSAGE_HANDLER(消息ID,处理函数)函数代表其会把对应的消息路由至成员函数OnAnyMessage进行处理ATL内部会生成并维护一份代码
ProcessWindowMessage用于查找消息映射表大概类似这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
LRESULT& lResult)
{
// uMsg = 0x8007
// 遍历消息映射表
if (uMsg == WM_CREATE) { /* ... */ }
if (uMsg == WM_DESTROY) { /* ... */ }
if (uMsg == WM_CLOSE) { /* ... */ }
if (uMsg == WM_COMMAND) { /* ... */ }
// ✅ 匹配到这里!
if (uMsg == WM_APP_8007)
{
BOOL bHandled = TRUE;
lResult = OnAnyMessage(uMsg, wParam, lParam, bHandled); // 调用 OnAnyMessage
if (bHandled)
return TRUE;
}
// ... 其他消息
}在用户点击自定义消息
WM_APP_8007对应的按钮时:1
2
3case IDC_BTN_SEND8007:
::SendMessageW(m_hWnd, WM_APP_8007, 0x11, 0x22); // 发送消息
// 此时程序会 "跳入" 到消息处理流程其会进入
ProcessWindowMessage进行消息映射查找,并根据里面的代码调用OnAnyMessageOnAnyMessage中:1
2
3
4
5
6
7
8
9
10
11
12
13LRESULT OnAnyMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
LRESULT lr = 0;
// 这里的 a7_like 我们固定传 0,等价于“允许处理”
if (maybe3_like(uMsg, wParam, lParam, lr, 0))
{
bHandled = TRUE;
// 对应你反编译的:if(flag) return 1;
return lr;
}
bHandled = FALSE;
return 0;
}又会调用
maybe3_like进行二次分发,在switch语句中走case WM_APP_8007的分支进行消息转发逆向分析
需要用spy++
对于刚刚那个小程序的exe进行逆向分析,spy++的日志中全部过滤只留下WM_COMMAND
当按下第一个按钮时:

spy++的消息意思是发送了
WM_COMMAND的消息,且包含了参数1001WM_COMMAND是win32框架内的,在WinUser.h中已经定义好了消息ID为0x111也就是在ida逆向出的
ProcessWindowMessage函数中,对应的这一段:1
2
3
4
5
6
7if ( uMsg == 0x111 )
{
bHandled[0] = 1;
*lResult = CMainWindow::OnCommand(this, 0x111u, wParam, lParam, bHandled);
if ( bHandled[0] )
return 1;
}这里的
wParam就是刚刚捕捉到的参数1001那么跳转到
OnCommand函数实现中:
可以看到这里
wParam==1001时,其调用了SendMessageW来发送0x8007而按钮2、3所对应的参数值就是1002和1003,其经过同样的调用链,进入这里的不同分支中
实操
目标是某v开头的软件
点击目标按钮后得到的是 WM_COMMAND wID:8002
由于没有符号表,不能直接搜索到
ProcessWindowMessage函数用alt-i搜索WM_COMMAND对应的消息ID
0x111
显示有很多种,但是不太会筛,大致挨个点过去一遍,发现这个的上半部分符合
ProcessWindowMessage的特征,左边是目标程序,右边是刚刚的实例:

两者的数据类型差不多,而且都是通过第三个参数
n0x132/uMsg做选择判断所以猜测这个函数上面就是
ProcessWindowMessage而下面则是对应的
OnCommand
所以8002对应的函数就是:
1
2
3
4
5case 0x8002:
*(this[6] + 32) = 1;
sub_608590(this, HIWORD(wParam), 32770, lParam);
*a6 = 0;
goto LABEL_5;
ATL框架逆向初学
- 本文链接: http://noone40404.github.io/2026/01/13/ATL框架逆向初学/
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!