1 // Copyright (c) 2014-2017, The Lemon Man, All rights reserved. LGPLv3
2 
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 3.0 of the License, or (at your option) any later version.
7 
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library.
15 
16 #include <r_asm.h>
17 #include <r_debug.h>
18 #include <winkd.h>
19 #include <kd.h>
20 
21 static WindCtx *wctx = NULL;
22 
r_debug_winkd_step(RDebug * dbg)23 static int r_debug_winkd_step(RDebug *dbg) {
24 	return true;
25 }
26 
r_debug_winkd_reg_read(RDebug * dbg,int type,ut8 * buf,int size)27 static int r_debug_winkd_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
28 	int ret = winkd_read_reg(wctx, buf, size);
29 	if (!ret || size != ret) {
30 		return -1;
31 	}
32 	r_reg_read_regs (dbg->reg, buf, ret);
33 	// Report as if no register has been written as we've already updated the arena here
34 	return 0;
35 }
36 
r_debug_winkd_reg_write(RDebug * dbg,int type,const ut8 * buf,int size)37 static int r_debug_winkd_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
38 	if (!dbg->reg) {
39 		return false;
40 	}
41 	int arena_size;
42 	ut8 *arena = r_reg_get_bytes (dbg->reg, R_REG_TYPE_ALL, &arena_size);
43 	if (!arena) {
44 		eprintf ("Could not retrieve the register arena!\n");
45 		return false;
46 	}
47 	int ret = winkd_write_reg (wctx, arena, arena_size);
48 	free (arena);
49 	return ret;
50 }
51 
r_debug_winkd_continue(RDebug * dbg,int pid,int tid,int sig)52 static int r_debug_winkd_continue(RDebug *dbg, int pid, int tid, int sig) {
53 	return winkd_continue(wctx);
54 }
55 
r_debug_winkd_wait(RDebug * dbg,int pid)56 static RDebugReasonType r_debug_winkd_wait(RDebug *dbg, int pid) {
57 	RDebugReasonType reason = R_DEBUG_REASON_UNKNOWN;
58 	kd_packet_t *pkt = NULL;
59 	kd_stc_64 *stc;
60 	winkd_lock_enter (wctx);
61 	for (;;) {
62 		void *bed = r_cons_sleep_begin ();
63 		int ret = winkd_wait_packet (wctx, KD_PACKET_TYPE_STATE_CHANGE64, &pkt);
64 		r_cons_sleep_end (bed);
65 		if (ret != KD_E_OK || !pkt) {
66 			reason = R_DEBUG_REASON_ERROR;
67 			break;
68 		}
69 		stc = (kd_stc_64 *) pkt->data;
70 		dbg->reason.addr = stc->pc;
71 		dbg->reason.tid = stc->kthread;
72 		dbg->reason.signum = stc->state;
73 		winkd_set_cpu (wctx, stc->cpu);
74 		if (stc->state == DbgKdExceptionStateChange) {
75 			dbg->reason.type = R_DEBUG_REASON_INT;
76 			reason = R_DEBUG_REASON_INT;
77 			break;
78 		} else if (stc->state == DbgKdLoadSymbolsStateChange) {
79 			dbg->reason.type = R_DEBUG_REASON_NEW_LIB;
80 			reason = R_DEBUG_REASON_NEW_LIB;
81 			break;
82 		}
83 		R_FREE (pkt);
84 	}
85 	winkd_lock_leave (wctx);
86 	free (pkt);
87 	return reason;
88 }
89 
r_debug_winkd_attach(RDebug * dbg,int pid)90 static int r_debug_winkd_attach(RDebug *dbg, int pid) {
91 	RIODesc *desc = dbg->iob.io->desc;
92 
93 	if (!desc || !desc->plugin || !desc->plugin->name || !desc->data) {
94 		return false;
95 	}
96 	if (strncmp (desc->plugin->name, "winkd", 6)) {
97 		return false;
98 	}
99 	if (dbg->arch && strcmp (dbg->arch, "x86")) {
100 		return false;
101 	}
102 	wctx = (WindCtx *)desc->data;
103 
104 	// Handshake
105 	if (!winkd_sync (wctx)) {
106 		eprintf ("Could not connect to winkd\n");
107 		winkd_ctx_free ((WindCtx **)&desc->data);
108 		return false;
109 	}
110 	if (!winkd_read_ver (wctx)) {
111 		winkd_ctx_free ((WindCtx **)&desc->data);
112 		return false;
113 	}
114 	dbg->bits = winkd_get_bits (wctx);
115 	// Make r_debug_is_dead happy
116 	dbg->pid = 0;
117 	return true;
118 }
119 
r_debug_winkd_detach(RDebug * dbg,int pid)120 static int r_debug_winkd_detach(RDebug *dbg, int pid) {
121 	eprintf ("Detaching...\n");
122 	return true;
123 }
124 
r_debug_winkd_reg_profile(RDebug * dbg)125 static char *r_debug_winkd_reg_profile(RDebug *dbg) {
126 	if (!dbg) {
127 		return NULL;
128 	}
129 	if (dbg->arch && strcmp (dbg->arch, "x86")) {
130 		return NULL;
131 	}
132 	r_debug_winkd_attach (dbg, 0);
133 	if (dbg->bits == R_SYS_BITS_32) {
134 #include "native/reg/windows-x86.h"
135 	} else if (dbg->bits == R_SYS_BITS_64) {
136 #include "native/reg/windows-x64.h"
137 	}
138 	return NULL;
139 }
140 
r_debug_winkd_breakpoint(RBreakpoint * bp,RBreakpointItem * b,bool set)141 static int r_debug_winkd_breakpoint(RBreakpoint *bp, RBreakpointItem *b, bool set) {
142 	int *tag;
143 	if (!b) {
144 		return false;
145 	}
146 	// Use a 32 bit word here to keep this compatible with 32 bit hosts
147 	if (!b->data) {
148 		b->data = (char *)R_NEW0 (int);
149 		if (!b->data) {
150 			return 0;
151 		}
152 	}
153 	tag = (int *)b->data;
154 	return winkd_bkpt (wctx, b->addr, set, b->hw, tag);
155 }
156 
r_debug_winkd_init(RDebug * dbg)157 static int r_debug_winkd_init(RDebug *dbg) {
158 	return true;
159 }
160 
r_debug_winkd_pids(RDebug * dbg,int pid)161 static RList *r_debug_winkd_pids(RDebug *dbg, int pid) {
162 	RListIter *it;
163 	WindProc *p;
164 
165 	RList *ret = r_list_newf (free);
166 	if (!ret) {
167 		return NULL;
168 	}
169 
170 	RList *pids = winkd_list_process(wctx);
171 	if (!pids) {
172 		return ret;
173 	}
174 	r_list_foreach (pids, it, p) {
175 		RDebugPid *newpid = R_NEW0 (RDebugPid);
176 		if (!newpid) {
177 			r_list_free (ret);
178 			return NULL;
179 		}
180 		newpid->path = strdup (p->name);
181 		newpid->pid = p->uniqueid;
182 		newpid->status = 's';
183 		newpid->runnable = true;
184 		r_list_append (ret, newpid);
185 	}
186 	// r_list_free (pids);
187 	return ret;
188 }
189 
r_debug_winkd_select(RDebug * dbg,int pid,int tid)190 static int r_debug_winkd_select(RDebug *dbg, int pid, int tid) {
191 	ut32 old = winkd_get_target (wctx);
192 	int ret = winkd_set_target (wctx, pid);
193 	if (!ret) {
194 		return false;
195 	}
196 	ut64 base = winkd_get_target_base (wctx);
197 	if (!base) {
198 		winkd_set_target (wctx, old);
199 		return false;
200 	}
201 	eprintf ("Process base is 0x%"PFMT64x"\n", base);
202 	return true;
203 }
204 
r_debug_winkd_threads(RDebug * dbg,int pid)205 static RList *r_debug_winkd_threads(RDebug *dbg, int pid) {
206 	RListIter *it;
207 	WindThread *t;
208 
209 	RList *ret = r_list_newf (free);
210 	if (!ret) {
211 		return NULL;
212 	}
213 
214 	RList *threads = winkd_list_threads (wctx);
215 	if (!threads) {
216 		r_list_free (ret);
217 		return NULL;
218 	}
219 
220 	r_list_foreach (threads, it, t) {
221 		RDebugPid *newpid = R_NEW0 (RDebugPid);
222 		if (!newpid) {
223 			r_list_free (ret);
224 			return NULL;
225 		}
226 		newpid->pid = t->uniqueid;
227 		newpid->status = t->status;
228 		newpid->runnable = t->runnable;
229 		r_list_append (ret, newpid);
230 	}
231 
232 	return ret;
233 }
234 
r_debug_winkd_modules(RDebug * dbg)235 static RList *r_debug_winkd_modules(RDebug *dbg) {
236 	RListIter *it;
237 	WindModule *m;
238 
239 	RList *ret = r_list_newf (free);
240 	if (!ret) {
241 		return NULL;
242 	}
243 
244 	RList *modules = winkd_list_modules (wctx);
245 	if (!modules) {
246 		r_list_free (ret);
247 		return NULL;
248 	}
249 
250 	r_list_foreach (modules, it, m) {
251 		RDebugMap *mod = R_NEW0 (RDebugMap);
252 		if (!mod) {
253 			r_list_free (modules);
254 			r_list_free (ret);
255 			return NULL;
256 		}
257 		mod->file = m->name;
258 		mod->size = m->size;
259 		mod->addr = m->addr;
260 		mod->addr_end = m->addr + m->size;
261 		r_list_append (ret, mod);
262 	}
263 
264 	r_list_free (modules);
265 	return ret;
266 }
267 
268 RDebugPlugin r_debug_plugin_winkd = {
269 	.name = "winkd",
270 	.license = "LGPL3",
271 	.arch = "x86",
272 	.bits = R_SYS_BITS_32 | R_SYS_BITS_64,
273 	.init = &r_debug_winkd_init,
274 	.step = &r_debug_winkd_step,
275 	.cont = &r_debug_winkd_continue,
276 	.attach = &r_debug_winkd_attach,
277 	.detach = &r_debug_winkd_detach,
278 	.pids = &r_debug_winkd_pids,
279 	.wait = &r_debug_winkd_wait,
280 	.select = &r_debug_winkd_select,
281 	.breakpoint = r_debug_winkd_breakpoint,
282 	.reg_read = &r_debug_winkd_reg_read,
283 	.reg_write = &r_debug_winkd_reg_write,
284 	.reg_profile = &r_debug_winkd_reg_profile,
285 	.threads = &r_debug_winkd_threads,
286 	.modules_get = &r_debug_winkd_modules
287 };
288 
289 #ifndef R2_PLUGIN_INCORE
290 R_API RLibStruct radare_plugin = {
291 	.type = R_LIB_TYPE_DBG,
292 	.data = &r_debug_plugin_winkd,
293 	.version = R2_VERSION
294 };
295 #endif
296