1 /* radare - LGPL - Copyright 2020 - GustavoLCR */
2 
3 #include <r_debug.h>
4 #include <DbgEng.h>
5 
6 #ifndef CONTEXT_ARM
7 #define CONTEXT_ARM 0x00200000L
8 #endif
9 #ifndef CONTEXT_ARM64
10 #define CONTEXT_ARM64 0x00400000L
11 #endif
12 #ifndef CONTEXT_AMD64
13 #define CONTEXT_AMD64 0x00100000L
14 #endif
15 #ifndef CONTEXT_i386
16 #define CONTEXT_i386 0x00010000L
17 #endif
18 #ifndef IMAGE_FILE_MACHINE_ARM64
19 #define IMAGE_FILE_MACHINE_ARM64 0xAA64
20 #endif
21 #ifndef DEBUG_DUMP_ACTIVE
22 #define DEBUG_DUMP_ACTIVE 1030
23 #endif
24 
25 #define TIMEOUT 500
26 #define THISCALL(dbginterface, function, ...) dbginterface->lpVtbl->function (dbginterface, __VA_ARGS__)
27 #define ITHISCALL(dbginterface, function, ...) THISCALL (idbg->dbginterface, function, __VA_ARGS__)
28 #define RELEASE(I) if (I) THISCALL (I, Release);
29 
30 typedef struct { // Keep in sync with io_windbg.c
31 	bool initialized;
32 	ULONG64 server;
33 	ULONG64 processBase;
34 	DWORD lastExecutionStatus;
35 	PDEBUG_CLIENT5 dbgClient;
36 	PDEBUG_CONTROL4 dbgCtrl;
37 	PDEBUG_DATA_SPACES4 dbgData;
38 	PDEBUG_REGISTERS2 dbgReg;
39 	PDEBUG_SYSTEM_OBJECTS4 dbgSysObj;
40 	PDEBUG_SYMBOLS3 dbgSymbols;
41 	PDEBUG_ADVANCED3 dbgAdvanced;
42 } DbgEngContext;
43 
__is_target_kernel(DbgEngContext * idbg)44 static bool __is_target_kernel(DbgEngContext *idbg) {
45 	ULONG Class, Qualifier;
46 	if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
47 		if (Class == DEBUG_CLASS_KERNEL) {
48 			return true;
49 		}
50 	}
51 	return false;
52 }
53 
windbg_init(RDebug * dbg)54 static int windbg_init(RDebug *dbg) {
55 	DbgEngContext *idbg = dbg->user;
56 	if (!idbg || !idbg->initialized) {
57 		return 0;
58 	}
59 	return 1;
60 }
61 
windbg_step(RDebug * dbg)62 static int windbg_step(RDebug *dbg) {
63 	DbgEngContext *idbg = dbg->user;
64 	r_return_val_if_fail (idbg && idbg->initialized, 0);
65 	idbg->lastExecutionStatus = DEBUG_STATUS_STEP_INTO;
66 	return SUCCEEDED (ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_STEP_INTO));
67 }
68 
windbg_select(RDebug * dbg,int pid,int tid)69 static int windbg_select(RDebug *dbg, int pid, int tid) {
70 	DbgEngContext *idbg = dbg->user;
71 	r_return_val_if_fail (idbg && idbg->initialized, 0);
72 	ULONG Id = tid;
73 	if (!__is_target_kernel (idbg)) {
74 		ITHISCALL (dbgSysObj, GetThreadIdBySystemId, tid, &Id);
75 	}
76 	if (SUCCEEDED (ITHISCALL (dbgSysObj, SetCurrentThreadId, Id))) {
77 		return 1;
78 	}
79 	return 0;
80 }
81 
windbg_continue(RDebug * dbg,int pid,int tid,int sig)82 static int windbg_continue(RDebug *dbg, int pid, int tid, int sig) {
83 	DbgEngContext *idbg = dbg->user;
84 	r_return_val_if_fail (idbg && idbg->initialized, 0);
85 	idbg->lastExecutionStatus = DEBUG_STATUS_GO;
86 	ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_GO);
87 	return tid;
88 }
89 
90 // nicked from windows_debug.c
exception_to_reason(DWORD ExceptionCode)91 static RDebugReasonType exception_to_reason(DWORD ExceptionCode) {
92 	switch (ExceptionCode) {
93 	case EXCEPTION_ACCESS_VIOLATION:
94 	case EXCEPTION_GUARD_PAGE:
95 		return R_DEBUG_REASON_SEGFAULT;
96 	case EXCEPTION_BREAKPOINT:
97 		return R_DEBUG_REASON_BREAKPOINT;
98 	case EXCEPTION_FLT_DENORMAL_OPERAND:
99 	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
100 	case EXCEPTION_FLT_INEXACT_RESULT:
101 	case EXCEPTION_FLT_INVALID_OPERATION:
102 	case EXCEPTION_FLT_OVERFLOW:
103 	case EXCEPTION_FLT_STACK_CHECK:
104 	case EXCEPTION_FLT_UNDERFLOW:
105 		return R_DEBUG_REASON_FPU;
106 	case EXCEPTION_ILLEGAL_INSTRUCTION:
107 		return R_DEBUG_REASON_ILLEGAL;
108 	case EXCEPTION_INT_DIVIDE_BY_ZERO:
109 		return R_DEBUG_REASON_DIVBYZERO;
110 	case EXCEPTION_SINGLE_STEP:
111 		return R_DEBUG_REASON_STEP;
112 	default:
113 		return R_DEBUG_REASON_TRAP;
114 	}
115 }
116 
windbg_stop(RDebug * dbg)117 static int windbg_stop(RDebug *dbg) {
118 	DbgEngContext *idbg = dbg->user;
119 	r_return_val_if_fail (idbg && idbg->initialized, 0);
120 	return SUCCEEDED (ITHISCALL (dbgCtrl, SetInterrupt, DEBUG_INTERRUPT_ACTIVE));
121 }
122 
123 static bool do_break = false;
124 
__break(void * user)125 static void __break(void *user) {
126 	RDebug *dbg = (RDebug *)user;
127 	DbgEngContext *idbg = dbg->user;
128 	if (__is_target_kernel (idbg)) {
129 		windbg_stop (dbg);
130 	}
131 	do_break = true;
132 }
133 
windbg_wait(RDebug * dbg,int pid)134 static int windbg_wait(RDebug *dbg, int pid) {
135 	DbgEngContext *idbg = dbg->user;
136 	r_return_val_if_fail (idbg && idbg->initialized, 0);
137 	ULONG Type, ProcessId, ThreadId;
138 	r_cons_break_push (__break, dbg);
139 	const ULONG timeout = __is_target_kernel (idbg) ? INFINITE : TIMEOUT;
140 	HRESULT hr;
141 	while ((hr = ITHISCALL (dbgCtrl, WaitForEvent, DEBUG_WAIT_DEFAULT, timeout)) == S_FALSE) {
142 		if (do_break) {
143 			ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_BREAK);
144 			do_break = false;
145 			r_cons_break_pop ();
146 			return R_DEBUG_REASON_USERSUSP;
147 		}
148 	}
149 	r_cons_break_pop ();
150 	if (FAILED (hr)) {
151 		return R_DEBUG_REASON_DEAD;
152 	}
153 	ITHISCALL (dbgCtrl, GetLastEventInformation, &Type, &ProcessId, &ThreadId, NULL, 0, NULL, NULL, 0, NULL);
154 	if (!__is_target_kernel (idbg)) {
155 		ITHISCALL (dbgSysObj, GetCurrentProcessSystemId, (PULONG)&dbg->pid);
156 		ITHISCALL (dbgSysObj, GetCurrentThreadSystemId, (PULONG)&dbg->tid);
157 	} else {
158 		dbg->pid = ProcessId;
159 		dbg->tid = ThreadId;
160 	}
161 	int ret;
162 	switch (Type) {
163 	case 0:
164 		// I dont really get why Type is zero here
165 		if (idbg->lastExecutionStatus == DEBUG_STATUS_STEP_INTO
166 			|| idbg->lastExecutionStatus == DEBUG_STATUS_STEP_OVER) {
167 			ret = R_DEBUG_REASON_STEP;
168 		} else {
169 			ret = R_DEBUG_REASON_ERROR;
170 		}
171 		break;
172 	case DEBUG_EVENT_BREAKPOINT:
173 		ret = R_DEBUG_REASON_BREAKPOINT;
174 		break;
175 	case DEBUG_EVENT_EXCEPTION: {
176 		EXCEPTION_RECORD64 exr;
177 		ITHISCALL (dbgCtrl, GetLastEventInformation, &Type, &ProcessId, &ThreadId, &exr, sizeof (exr), NULL, NULL, 0, NULL);
178 		dbg->reason.type = exception_to_reason (exr.ExceptionCode);
179 		dbg->reason.tid = dbg->tid;
180 		dbg->reason.addr = exr.ExceptionAddress;
181 		dbg->reason.timestamp = r_time_now ();
182 		ret = dbg->reason.type;
183 		break;
184 	}
185 	case DEBUG_EVENT_EXIT_PROCESS:
186 		ret = R_DEBUG_REASON_EXIT_PID;
187 		break;
188 	case DEBUG_EVENT_CREATE_PROCESS:
189 		ret = R_DEBUG_REASON_NEW_PID;
190 		break;
191 	default:
192 		ret = R_DEBUG_REASON_ERROR;
193 		break;
194 	}
195 
196 	return ret;
197 }
198 
windbg_step_over(RDebug * dbg)199 static int windbg_step_over(RDebug *dbg) {
200 	DbgEngContext *idbg = dbg->user;
201 	r_return_val_if_fail (idbg && idbg->initialized, 0);
202 	idbg->lastExecutionStatus = DEBUG_STATUS_STEP_OVER;
203 	if (SUCCEEDED (ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_STEP_OVER))) {
204 		return windbg_wait (dbg, dbg->pid) != R_DEBUG_REASON_ERROR;
205 	}
206 	return 0;
207 }
208 
windbg_breakpoint(RBreakpoint * bp,RBreakpointItem * b,bool set)209 static int windbg_breakpoint(RBreakpoint *bp, RBreakpointItem *b, bool set) {
210 	static volatile LONG bp_idx = 0;
211 	RDebug *dbg = bp->user;
212 	r_return_val_if_fail (dbg, 0);
213 	DbgEngContext *idbg = dbg->user;
214 	r_return_val_if_fail (idbg && idbg->initialized, 0);
215 	ULONG type = b->hw ? DEBUG_BREAKPOINT_DATA : DEBUG_BREAKPOINT_CODE;
216 	PDEBUG_BREAKPOINT bkpt;
217 	if (FAILED (ITHISCALL (dbgCtrl, GetBreakpointById, b->internal, &bkpt))) {
218 		HRESULT hr;
219 		do {
220 			b->internal = InterlockedIncrement (&bp_idx);
221 			hr = ITHISCALL (dbgCtrl, AddBreakpoint, type, b->internal, &bkpt);
222 		} while (hr == E_INVALIDARG);
223 		if (FAILED (hr)) {
224 			return 0;
225 		}
226 	}
227 	ULONG flags;
228 	THISCALL (bkpt, GetFlags, &flags);
229 	flags = set ? flags | DEBUG_BREAKPOINT_ENABLED : flags & ~DEBUG_BREAKPOINT_ENABLED;
230 	if (b->hw) {
231 		ULONG access_type = 0;
232 		if (b->perm & R_BP_PROT_EXEC) {
233 			access_type |= DEBUG_BREAK_EXECUTE;
234 		}
235 		if (b->perm & R_BP_PROT_READ) {
236 			access_type |= DEBUG_BREAK_READ;
237 		}
238 		if (b->perm & R_BP_PROT_WRITE) {
239 			access_type |= DEBUG_BREAK_WRITE;
240 		}
241 		if (b->perm & R_BP_PROT_ACCESS) {
242 			access_type |= DEBUG_BREAK_READ;
243 			access_type |= DEBUG_BREAK_WRITE;
244 		}
245 		THISCALL (bkpt, SetDataParameters, b->size, access_type);
246 	}
247 	THISCALL (bkpt, SetFlags, flags);
248 	THISCALL (bkpt, GetCurrentPassCount, (PULONG)&b->togglehits);
249 	THISCALL (bkpt, SetOffset, b->addr);
250 	return 1;
251 }
252 
windbg_reg_profile(RDebug * dbg)253 static char *windbg_reg_profile(RDebug *dbg) {
254 	DbgEngContext *idbg = dbg->user;
255 	ULONG type;
256 	if (!idbg || !idbg->initialized || FAILED (ITHISCALL (dbgCtrl, GetActualProcessorType, &type))) {
257 		if (dbg->bits & R_SYS_BITS_64) {
258 #include "native/reg/windows-x64.h"
259 		} else {
260 #include "native/reg/windows-x86.h"
261 		}
262 		return NULL;
263 	}
264 	if (type == IMAGE_FILE_MACHINE_IA64 || type == IMAGE_FILE_MACHINE_AMD64) {
265 #include "native/reg/windows-x64.h"
266 	} else if (type == IMAGE_FILE_MACHINE_I386) {
267 #include "native/reg/windows-x86.h"
268 	} else if (type == IMAGE_FILE_MACHINE_ARM) {
269 #include "native/reg/windows-arm.h"
270 	} else if (type == IMAGE_FILE_MACHINE_ARM64) {
271 #include "native/reg/windows-arm64.h"
272 	}
273 	return NULL;
274 }
275 
windbg_reg_read(RDebug * dbg,int type,ut8 * buf,int size)276 static int windbg_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
277 	DbgEngContext *idbg = dbg->user;
278 	r_return_val_if_fail (idbg && idbg->initialized, 0);
279 	ULONG ptype;
280 	if (!idbg || !idbg->initialized || FAILED (ITHISCALL (dbgCtrl, GetActualProcessorType, &ptype))) {
281 		return 0;
282 	}
283 	if (ptype == IMAGE_FILE_MACHINE_IA64 || ptype == IMAGE_FILE_MACHINE_AMD64) {
284 		DWORD *b = (DWORD *)(buf + 0x30);
285 		*b |= 0xff | CONTEXT_AMD64;
286 	} else if (ptype == IMAGE_FILE_MACHINE_I386) {
287 		DWORD *b = (DWORD *)buf;
288 		*b |= 0xff | CONTEXT_i386;
289 	} else if (ptype == IMAGE_FILE_MACHINE_ARM64) {
290 		DWORD *b = (DWORD *)buf;
291 		*b |= 0xff | CONTEXT_ARM64;
292 	} else if (ptype == IMAGE_FILE_MACHINE_ARM) {
293 		DWORD *b = (DWORD *)buf;
294 		*b |= 0xff | CONTEXT_ARM;
295 	}
296 	if (SUCCEEDED (ITHISCALL (dbgAdvanced, GetThreadContext, (PVOID)buf, size))) {
297 		return size;
298 	}
299 	return 0;
300 }
windbg_reg_write(RDebug * dbg,int type,const ut8 * buf,int size)301 static int windbg_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
302 	DbgEngContext *idbg = dbg->user;
303 	r_return_val_if_fail (idbg && idbg->initialized, 0);
304 	if (SUCCEEDED (ITHISCALL (dbgAdvanced, SetThreadContext, (PVOID)buf, size))) {
305 		return size;
306 	}
307 	return 0;
308 }
309 
windbg_frames(RDebug * dbg,ut64 at)310 static RList *windbg_frames(RDebug *dbg, ut64 at) {
311 	DbgEngContext *idbg = dbg->user;
312 	r_return_val_if_fail (idbg && idbg->initialized, 0);
313 	const size_t frame_cnt = 128;
314 	PDEBUG_STACK_FRAME dbgframes = R_NEWS (DEBUG_STACK_FRAME, frame_cnt);
315 	if (!dbgframes) {
316 		return NULL;
317 	}
318 	ULONG frames_filled;
319 	if (FAILED (ITHISCALL (dbgCtrl, GetStackTrace, 0, 0, 0, dbgframes, frame_cnt, &frames_filled))) {
320 		free (dbgframes);
321 		return NULL;
322 	}
323 	RList *frames = r_list_newf (free);
324 	size_t i;
325 	for (i = 0; i < frames_filled; i++) {
326 		RDebugFrame *f = R_NEW0 (RDebugFrame);
327 		if (!f) {
328 			break;
329 		}
330 		f->sp = dbgframes[i].StackOffset;
331 		f->bp = dbgframes[i].FrameOffset;
332 		f->addr = dbgframes[i].ReturnOffset;
333 		f->size = f->bp - f->sp;
334 		r_list_append (frames, f);
335 	}
336 	return frames;
337 }
338 
windbg_modules_get(RDebug * dbg)339 static RList *windbg_modules_get(RDebug *dbg) {
340 	DbgEngContext *idbg = dbg->user;
341 	r_return_val_if_fail (idbg && idbg->initialized, 0);
342 	ULONG mod_cnt, mod_un_cnt;
343 	if (FAILED (ITHISCALL (dbgSymbols, GetNumberModules, &mod_cnt, &mod_un_cnt))) {
344 		return NULL;
345 	}
346 	if (!mod_cnt) {
347 		return NULL;
348 	}
349 	PDEBUG_MODULE_PARAMETERS params = R_NEWS (DEBUG_MODULE_PARAMETERS, mod_cnt);
350 	if (!params) {
351 		return NULL;
352 	}
353 	if (FAILED (ITHISCALL (dbgSymbols, GetModuleParameters, mod_cnt, 0, 0, params))) {
354 		return NULL;
355 	}
356 	RList *modules_list = r_list_newf ((RListFree)r_debug_map_free);
357 	if (!modules_list) {
358 		return NULL;
359 	}
360 	size_t i;
361 	for (i = 0; i < mod_cnt; i++) {
362 		char *mod_name = malloc (params[i].ModuleNameSize);
363 		char *image_name = malloc (params[i].ImageNameSize);
364 		if (!mod_name || !image_name) {
365 			free (mod_name);
366 			free (image_name);
367 			break;
368 		}
369 		if (FAILED (
370 			    ITHISCALL (dbgSymbols, GetModuleNames,
371 				    DEBUG_ANY_ID, params[i].Base,
372 				    image_name, params[i].ImageNameSize, NULL,
373 				    mod_name, params[i].ModuleNameSize, NULL,
374 				    NULL, 0, NULL))) {
375 			free (mod_name);
376 			free (image_name);
377 			break;
378 		}
379 		RDebugMap *mod = r_debug_map_new (mod_name, params[i].Base, params[i].Base + params[i].Size, 0, params[i].Size);
380 		if (mod) {
381 			mod->file = strdup (image_name);
382 			r_list_append (modules_list, mod);
383 		}
384 		free (mod_name);
385 		free (image_name);
386 	}
387 	return modules_list;
388 }
389 
windbg_map_get(RDebug * dbg)390 static RList *windbg_map_get(RDebug *dbg) {
391 	DbgEngContext *idbg = dbg->user;
392 	r_return_val_if_fail (idbg && idbg->initialized, NULL);
393 	int perm;
394 	ULONG64 to = 0ULL;
395 	MEMORY_BASIC_INFORMATION64 mbi;
396 	RList *mod_list = windbg_modules_get (dbg);
397 	RList *map_list = r_list_newf ((RListFree)r_debug_map_free);
398 	const int mod_cnt = mod_list ? r_list_length (mod_list) : 0;
399 	PIMAGE_NT_HEADERS64 h = R_NEWS (IMAGE_NT_HEADERS64, mod_cnt);
400 	PIMAGE_SECTION_HEADER *s = R_NEWS0 (PIMAGE_SECTION_HEADER, mod_cnt);
401 	RListIter *it;
402 	RDebugMap *mod = NULL;
403 	size_t i = 0;
404 	r_list_foreach (mod_list, it, mod) {
405 		if (FAILED (ITHISCALL (dbgData, ReadImageNtHeaders, mod->addr, h + i))) {
406 			memset (h + i, 0, sizeof (IMAGE_NT_HEADERS64));
407 		} else {
408 			IMAGE_DOS_HEADER dos;
409 			ITHISCALL (dbgData, ReadVirtual, mod->addr, (PVOID)&dos, sizeof (IMAGE_DOS_HEADER), NULL);
410 			const size_t header_size = h[i].OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
411 				? sizeof (IMAGE_NT_HEADERS32)
412 				: sizeof (IMAGE_NT_HEADERS64);
413 			ULONG64 offset = mod->addr + dos.e_lfanew + header_size;
414 			const ULONG size = sizeof (IMAGE_SECTION_HEADER) * h[i].FileHeader.NumberOfSections;
415 			s[i] = malloc (size);
416 			ITHISCALL (dbgData, ReadVirtual, offset, (PVOID)s[i], size, NULL);
417 		}
418 		i++;
419 	}
420 	ULONG page_size = 1;
421 	ITHISCALL (dbgCtrl, GetPageSize, &page_size);
422 	ULONG p_mask = page_size - 1;
423 	while (SUCCEEDED (ITHISCALL (dbgData, QueryVirtual, to, &mbi))) {
424 		to = mbi.BaseAddress + mbi.RegionSize;
425 		perm = 0;
426 		perm |= mbi.Protect & PAGE_READONLY ? R_PERM_R : 0;
427 		perm |= mbi.Protect & PAGE_READWRITE ? R_PERM_RW : 0;
428 		perm |= mbi.Protect & PAGE_EXECUTE ? R_PERM_X : 0;
429 		perm |= mbi.Protect & PAGE_EXECUTE_READ ? R_PERM_RX : 0;
430 		perm |= mbi.Protect & PAGE_EXECUTE_READWRITE ? R_PERM_RWX : 0;
431 		perm = mbi.Protect & PAGE_NOACCESS ? 0 : perm;
432 		if (!perm) {
433 			continue;
434 		}
435 		char *name = "";
436 		if (mbi.Type == MEM_IMAGE) {
437 			i = 0;
438 			r_list_foreach (mod_list, it, mod) {
439 				if (mbi.BaseAddress >= mod->addr && mbi.BaseAddress < mod->addr + mod->size) {
440 					break;
441 				}
442 				i++;
443 			}
444 			if (i < mod_cnt && mod) {
445 				size_t j;
446 				for (j = 0; j < h[i].FileHeader.NumberOfSections; j++) {
447 					ut64 sect_vaddr = mod->addr + s[i][j].VirtualAddress;
448 					ut64 sect_vsize = (((ut64)s[i][j].Misc.VirtualSize) + p_mask) & ~p_mask;
449 					if (mbi.BaseAddress >= sect_vaddr && mbi.BaseAddress < sect_vaddr + sect_vsize) {
450 						name = sdb_fmt ("%s | %.8s", mod->name, s[i][j].Name);
451 						break;
452 					}
453 				}
454 				if (!*name) {
455 					name = mod->name;
456 				}
457 			}
458 		}
459 		RDebugMap *map = r_debug_map_new (name, mbi.BaseAddress, to, perm, 0);
460 		r_list_append (map_list, map);
461 	}
462 	for (i = 0; i < mod_cnt; i++) {
463 		free (s[i]);
464 	}
465 	free (s);
466 	free (h);
467 	r_list_free (mod_list);
468 	return map_list;
469 }
470 
windbg_attach(RDebug * dbg,int pid)471 static int windbg_attach(RDebug *dbg, int pid) {
472 	ULONG Id = 0;
473 	DbgEngContext *idbg = dbg->user;
474 	r_return_val_if_fail (idbg && idbg->initialized, -1);
475 	if (SUCCEEDED (ITHISCALL (dbgSysObj, GetCurrentProcessSystemId, &Id))) {
476 		if (Id == pid && SUCCEEDED (ITHISCALL (dbgSysObj, GetCurrentThreadSystemId, &Id))) {
477 			return Id;
478 		}
479 	}
480 	if (SUCCEEDED (ITHISCALL (dbgClient, AttachProcess, idbg->server, pid, DEBUG_ATTACH_DEFAULT))) {
481 		return windbg_wait (dbg, pid);
482 	}
483 	return -1;
484 }
485 
windbg_detach(RDebug * dbg,int pid)486 static int windbg_detach(RDebug *dbg, int pid) {
487 	DbgEngContext *idbg = dbg->user;
488 	r_return_val_if_fail (idbg && idbg->initialized, 0);
489 	return SUCCEEDED (ITHISCALL (dbgClient, DetachProcesses));
490 }
491 
windbg_kill(RDebug * dbg,int pid,int tid,int sig)492 static bool windbg_kill(RDebug *dbg, int pid, int tid, int sig) {
493 	DbgEngContext *idbg = dbg->user;
494 	r_return_val_if_fail (idbg && idbg->initialized, false);
495 	if (!sig) {
496 		ULONG exit_code, class, qualifier;
497 		if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &class, &qualifier))) {
498 			if (class == DEBUG_CLASS_UNINITIALIZED) {
499 				return false;
500 			}
501 			if (qualifier >= DEBUG_DUMP_SMALL && qualifier <= DEBUG_DUMP_ACTIVE) {
502 				return true;
503 			}
504 		}
505 		if (FAILED (ITHISCALL (dbgClient, GetExitCode, &exit_code))) {
506 			return false;
507 		}
508 		return exit_code == STILL_ACTIVE;
509 	}
510 	HRESULT hr = ITHISCALL (dbgClient, TerminateProcesses);
511 	return SUCCEEDED (hr);
512 }
513 
windbg_threads(RDebug * dbg,int pid)514 static RList *windbg_threads(RDebug *dbg, int pid) {
515 	DbgEngContext *idbg = dbg->user;
516 	r_return_val_if_fail (idbg && idbg->initialized, NULL);
517 	ULONG thread_cnt = 0;
518 	ITHISCALL (dbgSysObj, GetNumberThreads, &thread_cnt);
519 	if (!thread_cnt) {
520 		return NULL;
521 	}
522 	PULONG threads_ids = R_NEWS (ULONG, thread_cnt);
523 	PULONG threads_sysids = R_NEWS (ULONG, thread_cnt);
524 	RList *list = r_list_newf ((RListFree)r_debug_pid_free);
525 	if (!list || !threads_ids || !threads_sysids) {
526 		free (list);
527 		free (threads_ids);
528 		free (threads_sysids);
529 		return NULL;
530 	}
531 	ITHISCALL (dbgSysObj, GetThreadIdsByIndex, 0, thread_cnt, threads_ids, threads_sysids);
532 	size_t i;
533 	for (i = 0; i < thread_cnt; i++) {
534 		ULONG64 pc;
535 		ITHISCALL (dbgSysObj, SetCurrentThreadId, threads_ids[i]);
536 		ITHISCALL (dbgReg, GetInstructionOffset, &pc);
537 		r_list_append (list, r_debug_pid_new (NULL, threads_sysids[i], 0, 's', pc));
538 	}
539 	windbg_select (dbg, dbg->pid, dbg->tid);
540 	free (threads_ids);
541 	free (threads_sysids);
542 	return list;
543 }
544 
windbg_info(RDebug * dbg,const char * arg)545 static RDebugInfo *windbg_info(RDebug *dbg, const char *arg) {
546 	DbgEngContext *idbg = dbg->user;
547 	r_return_val_if_fail (idbg && idbg->initialized, NULL);
548 	char exeinfo[MAX_PATH];
549 	char cmdline[MAX_PATH];
550 	if (SUCCEEDED (ITHISCALL (dbgClient, GetRunningProcessDescription, idbg->server, dbg->pid, DEBUG_PROC_DESC_NO_SERVICES | DEBUG_PROC_DESC_NO_MTS_PACKAGES, exeinfo, MAX_PATH, NULL, cmdline, MAX_PATH, NULL))) {
551 		RDebugInfo *info = R_NEW0 (RDebugInfo);
552 		if (!info) {
553 			return NULL;
554 		}
555 		info->pid = dbg->pid;
556 		info->tid = dbg->tid;
557 		info->exe = strdup (exeinfo);
558 		info->cmdline = strdup (cmdline);
559 	}
560 	return NULL;
561 }
562 
windbg_gcore(RDebug * dbg,RBuffer * dest)563 static bool windbg_gcore(RDebug *dbg, RBuffer *dest) {
564 	DbgEngContext *idbg = dbg->user;
565 	r_return_val_if_fail (idbg && idbg->initialized, false);
566 	char *path = r_sys_getenv (R_SYS_TMP);
567 	if (R_STR_ISEMPTY (path)) {
568 		free (path);
569 		path = r_sys_getdir ();
570 		if (R_STR_ISEMPTY (path)) {
571 			free (path);
572 			return false;
573 		}
574 	}
575 	path = r_str_appendf (path, "\\core.%d", dbg->pid);
576 	ITHISCALL (dbgClient, WriteDumpFile, path, DEBUG_DUMP_DEFAULT);
577 	free (path);
578 	return true;
579 }
580 
windbg_pids(RDebug * dbg,int pid)581 RList *windbg_pids(RDebug *dbg, int pid) {
582 	DbgEngContext *idbg = dbg->user;
583 	r_return_val_if_fail (idbg && idbg->initialized, NULL);
584 	RList *list = r_list_newf ((RListFree)r_debug_pid_free);
585 	ULONG ids[1000];
586 	ULONG ids_cnt;
587 	if (SUCCEEDED (ITHISCALL (dbgClient, GetRunningProcessSystemIds,
588 		idbg->server, ids, _countof (ids), &ids_cnt))) {
589 		size_t i;
590 		for (i = 0; i < ids_cnt; i++) {
591 			char path[MAX_PATH];
592 			if (SUCCEEDED (ITHISCALL (dbgClient, GetRunningProcessDescription,
593 				    idbg->server, ids[i], DEBUG_PROC_DESC_DEFAULT,
594 					path, sizeof (path), NULL, NULL, 0, NULL))) {
595 				RDebugPid *pid = r_debug_pid_new (path, ids[i], 0, 'r', 0);
596 				r_list_append (list, pid);
597 			}
598 		}
599 	}
600 	return list;
601 }
602 
603 RDebugPlugin r_debug_plugin_windbg = {
604 	.name = "windbg",
605 	.license = "LGPL3",
606 	.bits = R_SYS_BITS_64,
607 	.arch = "x86,x64,arm,arm64",
608 	.canstep = 1,
609 	.init = windbg_init,
610 	.attach = windbg_attach,
611 	.detach = windbg_detach,
612 	.breakpoint = windbg_breakpoint,
613 	.frames = windbg_frames,
614 	.kill = windbg_kill,
615 	.select = windbg_select,
616 	.step = windbg_step,
617 	.step_over = windbg_step_over,
618 	.threads = windbg_threads,
619 	.cont = windbg_continue,
620 	.wait = windbg_wait,
621 	.stop = windbg_stop,
622 	.reg_read = windbg_reg_read,
623 	.reg_write = windbg_reg_write,
624 	.reg_profile = windbg_reg_profile,
625 	.map_get = windbg_map_get,
626 	.modules_get = windbg_modules_get,
627 	.info = windbg_info,
628 	.gcore = windbg_gcore,
629 	.pids = windbg_pids
630 };
631 
632 #ifndef R2_PLUGIN_INCORE
633 R_API RLibStruct radare_plugin = {
634 	.type = R_LIB_TYPE_DBG,
635 	.data = &r_debug_plugin_windbg,
636 	.version = R2_VERSION
637 };
638 #endif // R2_PLUGIN_INCORE
639