1 /* radare2 - LGPL - Copyright 2019 - GustavoLCR */
2 #include <r_debug.h>
3 #include "windows_message.h"
4
5 static char *msg_types_arr[] = {
6 "WM_NULL=0x0000",
7 "WM_CREATE=0x0001",
8 "WM_DESTROY=0x0002",
9 "WM_MOVE=0x0003",
10 "WM_SIZE=0x0005",
11 "WM_ACTIVATE=0x0006",
12 "WM_SETFOCUS=0x0007",
13 "WM_KILLFOCUS=0x0008",
14 "WM_ENABLE=0x000A",
15 "WM_SETREDRAW=0x000B",
16 "WM_SETTEXT=0x000C",
17 "WM_GETTEXT=0x000D",
18 "WM_GETTEXTLENGTH=0x000E",
19 "WM_PAINT=0x000F",
20 "WM_CLOSE=0x0010",
21 "WM_QUERYENDSESSION=0x0011",
22 "WM_QUIT=0x0012",
23 "WM_QUERYOPEN=0x0013",
24 "WM_ERASEBKGND=0x0014",
25 "WM_SYSCOLORCHANGE=0x0015",
26 "WM_ENDSESSION=0x0016",
27 "WM_SHOWWINDOW=0x0018",
28 "WM_WININICHANGE=0x001A",
29 "WM_DEVMODECHANGE=0x001B",
30 "WM_ACTIVATEAPP=0x001C",
31 "WM_FONTCHANGE=0x001D",
32 "WM_TIMECHANGE=0x001E",
33 "WM_CANCELMODE=0x001F",
34 "WM_SETCURSOR=0x0020",
35 "WM_MOUSEACTIVATE=0x0021",
36 "WM_CHILDACTIVATE=0x0022",
37 "WM_QUEUESYNC=0x0023",
38 "WM_GETMINMAXINFO=0x0024",
39 "WM_PAINTICON=0x0026",
40 "WM_ICONERASEBKGND=0x0027",
41 "WM_NEXTDLGCTL=0x0028",
42 "WM_SPOOLERSTATUS=0x002A",
43 "WM_DRAWITEM=0x002B",
44 "WM_MEASUREITEM=0x002C",
45 "WM_DELETEITEM=0x002D",
46 "WM_VKEYTOITEM=0x002E",
47 "WM_CHARTOITEM=0x002F",
48 "WM_SETFONT=0x0030",
49 "WM_GETFONT=0x0031",
50 "WM_SETHOTKEY=0x0032",
51 "WM_GETHOTKEY=0x0033",
52 "WM_QUERYDRAGICON=0x0037",
53 "WM_COMPAREITEM=0x0039",
54 "WM_GETOBJECT=0x003D",
55 "WM_COMPACTING=0x0041",
56 "WM_COMMNOTIFY=0x0044",
57 "WM_WINDOWPOSCHANGING=0x0046",
58 "WM_WINDOWPOSCHANGED=0x0047",
59 "WM_POWER=0x0048",
60 "WM_COPYDATA=0x004A",
61 "WM_CANCELJOURNAL=0x004B",
62 "WM_NOTIFY=0x004E",
63 "WM_INPUTLANGCHANGEREQUEST=0x0050",
64 "WM_INPUTLANGCHANGE=0x0051",
65 "WM_TCARD=0x0052",
66 "WM_HELP=0x0053",
67 "WM_USERCHANGED=0x0054",
68 "WM_NOTIFYFORMAT=0x0055",
69 "WM_CONTEXTMENU=0x007B",
70 "WM_STYLECHANGING=0x007C",
71 "WM_STYLECHANGED=0x007D",
72 "WM_DISPLAYCHANGE=0x007E",
73 "WM_GETICON=0x007F",
74 "WM_SETICON=0x0080",
75 "WM_NCCREATE=0x0081",
76 "WM_NCDESTROY=0x0082",
77 "WM_NCCALCSIZE=0x0083",
78 "WM_NCHITTEST=0x0084",
79 "WM_NCPAINT=0x0085",
80 "WM_NCACTIVATE=0x0086",
81 "WM_GETDLGCODE=0x0087",
82 "WM_SYNCPAINT=0x0088",
83 "WM_NCMOUSEMOVE=0x00A0",
84 "WM_NCLBUTTONDOWN=0x00A1",
85 "WM_NCLBUTTONUP=0x00A2",
86 "WM_NCLBUTTONDBLCLK=0x00A3",
87 "WM_NCRBUTTONDOWN=0x00A4",
88 "WM_NCRBUTTONUP=0x00A5",
89 "WM_NCRBUTTONDBLCLK=0x00A6",
90 "WM_NCMBUTTONDOWN=0x00A7",
91 "WM_NCMBUTTONUP=0x00A8",
92 "WM_NCMBUTTONDBLCLK=0x00A9",
93 "WM_NCXBUTTONDOWN=0x00AB",
94 "WM_NCXBUTTONUP=0x00AC",
95 "WM_NCXBUTTONDBLCLK=0x00AD",
96 "WM_INPUT=0x00FF",
97 "WM_KEYFIRST=0x0100",
98 "WM_KEYDOWN=0x0100",
99 "WM_KEYUP=0x0101",
100 "WM_CHAR=0x0102",
101 "WM_DEADCHAR=0x0103",
102 "WM_SYSKEYDOWN=0x0104",
103 "WM_SYSKEYUP=0x0105",
104 "WM_SYSCHAR=0x0106",
105 "WM_SYSDEADCHAR=0x0107",
106 "WM_UNICHAR=0x0109",
107 "WM_KEYLAST=0x0109",
108 "WM_KEYLAST=0x0108",
109 "WM_INITDIALOG=0x0110",
110 "WM_COMMAND=0x0111",
111 "WM_SYSCOMMAND=0x0112",
112 "WM_TIMER=0x0113",
113 "WM_HSCROLL=0x0114",
114 "WM_VSCROLL=0x0115",
115 "WM_INITMENU=0x0116",
116 "WM_INITMENUPOPUP=0x0117",
117 "WM_GESTURE=0x0119",
118 "WM_GESTURENOTIFY=0x011A",
119 "WM_MENUSELECT=0x011F",
120 "WM_MENUCHAR=0x0120",
121 "WM_ENTERIDLE=0x0121",
122 "WM_MENURBUTTONUP=0x0122",
123 "WM_MENUDRAG=0x0123",
124 "WM_MENUGETOBJECT=0x0124",
125 "WM_UNINITMENUPOPUP=0x0125",
126 "WM_MENUCOMMAND=0x0126",
127 "WM_CHANGEUISTATE=0x0127",
128 "WM_UPDATEUISTATE=0x0128",
129 "WM_QUERYUISTATE=0x0129",
130 "WM_CTLCOLORMSGBOX=0x0132",
131 "WM_CTLCOLOREDIT=0x0133",
132 "WM_CTLCOLORLISTBOX=0x0134",
133 "WM_CTLCOLORBTN=0x0135",
134 "WM_CTLCOLORDLG=0x0136",
135 "WM_CTLCOLORSCROLLBAR=0x0137",
136 "WM_CTLCOLORSTATIC=0x0138",
137 "WM_MOUSEFIRST=0x0200",
138 "WM_MOUSEMOVE=0x0200",
139 "WM_LBUTTONDOWN=0x0201",
140 "WM_LBUTTONUP=0x0202",
141 "WM_LBUTTONDBLCLK=0x0203",
142 "WM_RBUTTONDOWN=0x0204",
143 "WM_RBUTTONUP=0x0205",
144 "WM_RBUTTONDBLCLK=0x0206",
145 "WM_MBUTTONDOWN=0x0207",
146 "WM_MBUTTONUP=0x0208",
147 "WM_MBUTTONDBLCLK=0x0209",
148 "WM_MOUSEWHEEL=0x020A",
149 "WM_XBUTTONDOWN=0x020B",
150 "WM_XBUTTONUP=0x020C",
151 "WM_XBUTTONDBLCLK=0x020D",
152 "WM_MOUSEHWHEEL=0x020E",
153 "WM_MOUSELAST=0x020E",
154 "WM_MOUSELAST=0x020D",
155 "WM_MOUSELAST=0x020A",
156 "WM_MOUSELAST=0x0209",
157 "WM_PARENTNOTIFY=0x0210",
158 "WM_ENTERMENULOOP=0x0211",
159 "WM_EXITMENULOOP=0x0212",
160 "WM_NEXTMENU=0x0213",
161 "WM_SIZING=0x0214",
162 "WM_CAPTURECHANGED=0x0215",
163 "WM_MOVING=0x0216",
164 "WM_POWERBROADCAST=0x0218",
165 "WM_DEVICECHANGE=0x0219",
166 "WM_MDICREATE=0x0220",
167 "WM_MDIDESTROY=0x0221",
168 "WM_MDIACTIVATE=0x0222",
169 "WM_MDIRESTORE=0x0223",
170 "WM_MDINEXT=0x0224",
171 "WM_MDIMAXIMIZE=0x0225",
172 "WM_MDITILE=0x0226",
173 "WM_MDICASCADE=0x0227",
174 "WM_MDIICONARRANGE=0x0228",
175 "WM_MDIGETACTIVE=0x0229",
176 "WM_MDISETMENU=0x0230",
177 "WM_ENTERSIZEMOVE=0x0231",
178 "WM_EXITSIZEMOVE=0x0232",
179 "WM_DROPFILES=0x0233",
180 "WM_MDIREFRESHMENU=0x0234",
181 "WM_POINTERDEVICECHANGE=0x238",
182 "WM_POINTERDEVICEINRANGE=0x239",
183 "WM_POINTERDEVICEOUTOFRANGE=0x23A",
184 "WM_TOUCH=0x0240",
185 "WM_NCPOINTERUPDATE=0x0241",
186 "WM_NCPOINTERDOWN=0x0242",
187 "WM_NCPOINTERUP=0x0243",
188 "WM_POINTERUPDATE=0x0245",
189 "WM_POINTERDOWN=0x0246",
190 "WM_POINTERUP=0x0247",
191 "WM_POINTERENTER=0x0249",
192 "WM_POINTERLEAVE=0x024A",
193 "WM_POINTERACTIVATE=0x024B",
194 "WM_POINTERCAPTURECHANGED=0x024C",
195 "WM_TOUCHHITTESTING=0x024D",
196 "WM_POINTERWHEEL=0x024E",
197 "WM_POINTERHWHEEL=0x024F",
198 "WM_POINTERROUTEDTO=0x0251",
199 "WM_POINTERROUTEDAWAY=0x0252",
200 "WM_POINTERROUTEDRELEASED=0x0253",
201 "WM_MOUSEHOVER=0x02A1",
202 "WM_MOUSELEAVE=0x02A3",
203 "WM_NCMOUSEHOVER=0x02A0",
204 "WM_NCMOUSELEAVE=0x02A2",
205 "WM_DPICHANGED=0x02E0",
206 "WM_GETDPISCALEDSIZE=0x02E4",
207 "WM_CUT=0x0300",
208 "WM_COPY=0x0301",
209 "WM_PASTE=0x0302",
210 "WM_CLEAR=0x0303",
211 "WM_UNDO=0x0304",
212 "WM_RENDERFORMAT=0x0305",
213 "WM_RENDERALLFORMATS=0x0306",
214 "WM_DESTROYCLIPBOARD=0x0307",
215 "WM_DRAWCLIPBOARD=0x0308",
216 "WM_PAINTCLIPBOARD=0x0309",
217 "WM_VSCROLLCLIPBOARD=0x030A",
218 "WM_SIZECLIPBOARD=0x030B",
219 "WM_ASKCBFORMATNAME=0x030C",
220 "WM_CHANGECBCHAIN=0x030D",
221 "WM_HSCROLLCLIPBOARD=0x030E",
222 "WM_QUERYNEWPALETTE=0x030F",
223 "WM_PALETTEISCHANGING=0x0310",
224 "WM_PALETTECHANGED=0x0311",
225 "WM_HOTKEY=0x0312",
226 "WM_PRINT=0x0317",
227 "WM_PRINTCLIENT=0x0318",
228 "WM_APPCOMMAND=0x0319",
229 "WM_THEMECHANGED=0x031A",
230 "WM_CLIPBOARDUPDATE=0x031D",
231 "WM_DWMCOMPOSITIONCHANGED=0x031E",
232 "WM_DWMNCRENDERINGCHANGED=0x031F",
233 "WM_DWMCOLORIZATIONCOLORCHANGED=0x0320",
234 "WM_DWMWINDOWMAXIMIZEDCHANGE=0x0321",
235 "WM_DWMSENDICONICTHUMBNAIL=0x0323",
236 "WM_DWMSENDICONICLIVEPREVIEWBITMAP=0x0326",
237 "WM_GETTITLEBARINFOEX=0x033F",
238 "WM_HANDHELDFIRST=0x0358",
239 "WM_HANDHELDLAST=0x035F",
240 "WM_AFXFIRST=0x0360",
241 "WM_AFXLAST=0x037F",
242 "WM_PENWINFIRST=0x0380",
243 "WM_PENWINLAST=0x038F",
244 "WM_APP=0x8000",
245 "WM_USER=0x0400",
246 NULL
247 };
248
__free_window(void * ptr)249 void __free_window (void *ptr) {
250 window *win = ptr;
251 free (win->name);
252 free (win);
253 }
254
__window_from_handle(HANDLE hwnd)255 static window *__window_from_handle(HANDLE hwnd) {
256 r_return_val_if_fail (hwnd, NULL);
257 window *win = R_NEW0 (window);
258 if (!win) {
259 return NULL;
260 }
261 win->h = hwnd;
262 win->tid = GetWindowThreadProcessId (hwnd, &win->pid);
263 win->proc = GetClassLongPtrW (hwnd, GCLP_WNDPROC);
264 const size_t sz = MAX_CLASS_NAME * sizeof (WCHAR);
265 wchar_t *tmp = malloc (sz);
266 if (!tmp) {
267 free (win);
268 return NULL;
269 }
270 GetClassNameW (hwnd, tmp, MAX_CLASS_NAME);
271 win->name = r_utf16_to_utf8 (tmp);
272 free (tmp);
273 if (!win->name) {
274 win->name = strdup ("");
275 }
276 return win;
277 }
278
__create_window_table(void)279 static RTable *__create_window_table(void) {
280 RTable *tbl = r_table_new ("windows");
281 if (!tbl) {
282 return NULL;
283 }
284 r_table_add_column (tbl, r_table_type ("number"), "Handle", ST32_MAX);
285 r_table_add_column (tbl, r_table_type ("number"), "PID", ST32_MAX);
286 r_table_add_column (tbl, r_table_type ("number"), "TID", ST32_MAX);
287 r_table_add_column (tbl, r_table_type ("string"), "Class Name", ST32_MAX);
288 return tbl;
289 }
290
__add_window_to_table(RTable * tbl,window * win)291 static void __add_window_to_table(RTable *tbl, window *win) {
292 r_return_if_fail (tbl && win);
293 char *handle = r_str_newf ("0x%08"PFMT64x"", (ut64)win->h);
294 char *pid = r_str_newf ("%lu", win->pid);
295 char *tid = r_str_newf ("%lu", win->tid);
296 r_table_add_row (tbl, handle, pid, tid, win->name, NULL);
297 free (handle);
298 free (tid);
299 free (pid);
300 }
301
r_w32_identify_window(void)302 R_API void r_w32_identify_window(void) {
303 while (!r_cons_yesno ('y', "Move cursor to the window to be identified. Ready?"));
304 POINT p;
305 GetCursorPos (&p);
306 HANDLE hwnd = WindowFromPoint (p);
307 window *win = NULL;
308 if (hwnd) {
309 if (r_cons_yesno ('y', "Try to get the child?")) {
310 HANDLE child = ChildWindowFromPoint (hwnd, p);
311 hwnd = child ? child : hwnd;
312 }
313 win = __window_from_handle (hwnd);
314 } else {
315 eprintf ("No window found\n");
316 return;
317 }
318 if (!win) {
319 eprintf ("Error trying to get information from 0x%08"PFMT64x"\n", (ut64)hwnd);
320 return;
321 }
322 RTable *tbl = __create_window_table ();
323 if (!tbl) {
324 return;
325 }
326 __add_window_to_table (tbl, win);
327 char *tbl_str = r_table_tofancystring (tbl);
328 r_cons_print (tbl_str);
329 free (tbl_str);
330 r_table_free (tbl);
331 }
332
__enum_childs(_In_ HWND hwnd,_In_ LPARAM lParam)333 static BOOL CALLBACK __enum_childs(
334 _In_ HWND hwnd,
335 _In_ LPARAM lParam
336 ) {
337 RList *windows = (RList *)lParam;
338 window *win = __window_from_handle (hwnd);
339 if (!win) {
340 return false;
341 }
342 r_list_push (windows, win);
343 return true;
344 }
345
__get_windows(RDebug * dbg)346 static RList *__get_windows(RDebug *dbg) {
347 RList *windows = r_list_newf ((RListFree)__free_window);
348 HWND hCurWnd = NULL;
349 do {
350 hCurWnd = FindWindowEx (NULL, hCurWnd, NULL, NULL);
351 DWORD dwProcessID = 0;
352 GetWindowThreadProcessId (hCurWnd, &dwProcessID);
353 if (dbg->pid == dwProcessID) {
354 EnumChildWindows (hCurWnd, __enum_childs, (LPARAM)windows);
355 window *win = __window_from_handle (hCurWnd);
356 if (!win) {
357 r_list_free (windows);
358 return NULL;
359 }
360 r_list_push (windows, win);
361 }
362 } while (hCurWnd != NULL);
363 return windows;
364 }
365
__get_dispatchmessage_offset(RDebug * dbg)366 static ut64 __get_dispatchmessage_offset(RDebug *dbg) {
367 RList *modlist = r_debug_modules_list (dbg);
368 RListIter *it;
369 RDebugMap *mod;
370 bool found = false;
371 r_list_foreach (modlist, it, mod) {
372 if (!strnicmp (mod->name, "user32.dll", sizeof ("user32.dll"))) {
373 found = true;
374 break;
375 }
376 }
377 if (!found) {
378 return 0;
379 }
380 char *res = dbg->corebind.cmdstr (dbg->corebind.core, "f~DispatchMessageW");
381 if (!*res) {
382 free (res);
383 return 0;
384 }
385 char *line = strtok (res, "\n");
386 ut64 offset = 0;
387 do {
388 char *sym = strrchr (line, ' ');
389 if (sym && r_str_startswith (sym + 1, "sym.imp")) {
390 offset = r_num_math (NULL, line);
391 dbg->iob.read_at (dbg->iob.io, offset, (ut8 *)&offset, sizeof (offset));
392 break;
393 }
394 } while ((line = strtok (NULL, "\n")));
395 free (res);
396 return offset;
397 }
398
__init_msg_types(Sdb ** msg_types)399 static void __init_msg_types(Sdb **msg_types) {
400 *msg_types = sdb_new0 ();
401 int i;
402 char *cur_type;
403 for (i = 0; (cur_type = msg_types_arr[i]); i++) {
404 sdb_query (*msg_types, cur_type);
405 }
406 }
407
__get_msg_type(char * name)408 static DWORD __get_msg_type(char *name) {
409 static Sdb *msg_types = NULL;
410 if (!msg_types) {
411 __init_msg_types (&msg_types);
412 }
413 ut32 found;
414 const char *type_str = sdb_const_get (msg_types, name, &found);
415 if (found) {
416 int type = r_num_math (NULL, type_str);
417 return type;
418 }
419 return 0;
420 }
421
__print_windows(RDebug * dbg,RList * windows)422 static void __print_windows(RDebug *dbg, RList *windows) {
423 RTable *tbl = __create_window_table ();
424 if (!tbl) {
425 return;
426 }
427 RListIter *it;
428 window *win;
429 r_list_foreach (windows, it, win) {
430 __add_window_to_table (tbl, win);
431 }
432 char *t = r_table_tofancystring (tbl);
433 dbg->cb_printf (t);
434 free (t);
435 r_table_free (tbl);
436 }
437
r_w32_print_windows(RDebug * dbg)438 R_API void r_w32_print_windows(RDebug *dbg) {
439 RList *windows = __get_windows (dbg);
440 if (windows) {
441 if (!windows->length) {
442 dbg->cb_printf ("No windows for this process.\n");
443 return;
444 }
445 __print_windows (dbg, windows);
446 }
447 r_list_free (windows);
448 }
449
r_w32_add_winmsg_breakpoint(RDebug * dbg,const char * input)450 R_API bool r_w32_add_winmsg_breakpoint(RDebug *dbg, const char *input) {
451 r_return_val_if_fail (dbg && input, false);
452 char *name = strdup (input);
453 r_str_trim (name);
454 char *window_id = strchr (name, ' ');
455 if (window_id) {
456 *window_id = 0;
457 window_id++;
458 }
459 DWORD type = __get_msg_type (name);
460 if (!type) {
461 free (name);
462 return false;
463 }
464 ut64 offset = 0;
465 if (window_id) {
466 RList *windows = __get_windows (dbg);
467 if (windows && !windows->length) {
468 dbg->cb_printf ("No windows for this process.\n");
469 }
470 ut64 win_h = r_num_math (NULL, window_id);
471 RListIter *it;
472 window *win;
473 r_list_foreach (windows, it, win) {
474 if ((ut64)win->h == win_h || !strnicmp (win->name, window_id, strlen (window_id))) {
475 offset = win->proc;
476 break;
477 }
478 }
479 if (!offset) {
480 dbg->cb_printf ("Window not found, try these:\n");
481 __print_windows (dbg, windows);
482 }
483 r_list_free (windows);
484 } else {
485 offset = __get_dispatchmessage_offset (dbg);
486 }
487 if (!offset) {
488 free (name);
489 return false;
490 }
491 r_debug_bp_add (dbg, offset, 0, 0, 0, NULL, 0);
492 char *cond;
493 if (window_id) {
494 cond = r_str_newf ("?= `ae %lu,edx,-`", type);
495 } else {
496 char *reg;
497 if (dbg->bits == R_SYS_BITS_64) {
498 reg = "rcx";
499 } else {
500 reg = "ecx";
501 }
502 cond = r_str_newf ("?= `ae %lu,%s,%d,+,[4],-`", type, reg, dbg->bits);
503 }
504 dbg->corebind.cmdf (dbg->corebind.core, "\"dbC 0x%"PFMT64x" %s\"", offset, cond);
505 free (name);
506 return true;
507 }
508