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