1 /* radare - LGPL - Copyright 2017-2019 - pancake */
2 
3 #include "r_types_base.h"
4 #include "r_io.h"
5 #include "r_lib.h"
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9 
10 static RSocket *gs = NULL;
11 
12 R_PACKED (struct winedbg_x86_32 {
13 	ut16 cs;
14 	ut16 ss;
15 	ut16 ds;
16 	ut16 es;
17 	ut16 fs;
18 	ut16 gs;
19 	ut32 eip;
20 	ut32 esp;
21 	ut32 ebp;
22 	ut32 eflags;
23 	ut32 eax;
24 	ut32 ebx;
25 	ut32 ecx;
26 	ut32 edx;
27 	ut32 esi;
28 	ut32 edi;
29 });
30 
31 // TODO: make it vargarg...
runcmd(const char * cmd)32 static char *runcmd(const char *cmd) {
33 	char buf[4096] = {0};
34 	if (cmd) {
35 		r_socket_printf (gs, "%s\n", cmd);
36 	}
37 	int timeout = 1000000;
38 	char *str = NULL;
39 	r_socket_block_time (gs, 1, timeout, 0);
40 	while (true) {
41 		memset (buf, 0, sizeof (buf));
42 		int rc = r_socket_read (gs, (ut8*)buf, sizeof (buf) - 1); // NULL-terminate the string always
43 		if (rc == -1) {
44 			break;
45 		}
46 		char *promptFound = strstr (buf, "Wine-dbg>");
47 		if (promptFound) {
48 			*promptFound = 0;
49 			return r_str_append (str, buf);
50 		}
51 		str = r_str_append (str, buf);
52 	}
53 	free (str);
54 	return NULL;
55 }
56 
__write(RIO * io,RIODesc * fd,const ut8 * buf,int count)57 static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
58 	if (!fd || !fd->data) {
59 		return -1;
60 	}
61 	int wordSize = 4;
62 	ut32 *w = (ut32*)buf;
63 	int i;
64 	int words = count / wordSize; // XXX must pad align to 4
65 	for (i = 0; i < words ; i++) {
66 		ut64 addr = io->off + (i * wordSize);
67 		char *cmd = r_str_newf ("set *0x%"PFMT64x" = 0x%x", addr, w[i]);
68 		free (runcmd (cmd));
69 		free (cmd);
70 	}
71 
72 	int left = count % wordSize;
73 	if (left > 0) {
74 		ut32 leftW = -1;
75 		memcpy (&leftW, w + words, left);
76 		ut64 addr = io->off + (words * wordSize);
77 		char *cmd = r_str_newf ("set *0x%"PFMT64x" = 0x%x", addr, leftW);
78 		free (runcmd (cmd));
79 		free (cmd);
80 	}
81 	return count;
82 }
83 
__read(RIO * io,RIODesc * fd,ut8 * buf,int count)84 static int __read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
85 	if (!fd || !fd->data) {
86 		return -1;
87 	}
88 	if (count > (1024*128)) {
89 		// cannot read that much
90 		return -1;
91 	}
92 #if 0
93 // TODO: use x/${count}b for performance and solve alignment issues
94 Wine-dbg>x/128b 0x7b444730
95 0x7b444730 _start_process+0x10a:  cc 83 ec 08 57 56 e8 b5 fe ff ff 83 c4 04 50 e8
96 0x7b444740 _start_process+0x11a:  24 2f 01 00 83 c4 0c 8b 44 24 68 83 ec 08 ff 70
97 0x7b444750 _start_process+0x12a:  5c 6a fe e8 27 2f 01 00 83 c4 08 e8 34 de 01 00
98 0x7b444760 _debugstr_w:  55 89 e5 83 ec 08 83 ec 08 6a ff 51 e8 45 e0 01
99 0x7b444770 _debugstr_w+0x10:  00 83 c4 18 5d c3 55 89 e5 53 57 56 83 e4 f0 81
100 0x7b444780 ___wine_kernel_init+0xa:  ec e0 0e 00 00 e8 00 00 00 00 5e 64 a1 18 00 00
101 0x7b444790 ___wine_kernel_init+0x1a:  00 89 44 24 40 8b 40 30 89 44 24 44 8b 78 10 8b
102 0x7b4447a0 ___wine_kernel_init+0x2a:  86 ca 48 1b 00 83 ec 08 31 db 53 ff 30 e8 e4 de
103 Wine-dbg>
104 #endif
105 	int wordSize = 4;
106 	ut32 *w = (ut32*)buf;
107 	int i;
108 	memset (buf, 0xff, count);
109 	int words = count / wordSize; // XXX must pad align to 4
110 	for (i = 0; i < words ; i++) {
111 		ut64 addr = io->off + (i * wordSize);
112 		char *cmd = r_str_newf ("x 0x%"PFMT64x, addr);
113 		char *res = runcmd (cmd);
114 		if (res) {
115 			sscanf (res, "%x", &w[i]);
116 			free (res);
117 		}
118 		free (cmd);
119 	}
120 
121 	int left = count % wordSize;
122 	if (left > 0) {
123 		ut32 n = 0xff;
124 		ut8 *wn = (ut8*)&n;
125 		ut64 addr = io->off + (i * wordSize);
126 		char *cmd = r_str_newf ("x 0x%"PFMT64x, addr);
127 		char *res = runcmd (cmd);
128 		sscanf (res, "%x", &n);
129 		free (res);
130 		free (cmd);
131 		memcpy (buf + (words * wordSize), wn, left);
132 	}
133 	return count;
134 }
135 
__close(RIODesc * fd)136 static int __close(RIODesc *fd) {
137 	if (!fd || !fd->data) {
138 		return -1;
139 	}
140 	// XXX
141 	r_sys_cmdf ("pkill rarun2");
142 	return 0;
143 }
144 
__lseek(RIO * io,RIODesc * fd,ut64 offset,int whence)145 static ut64 __lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
146 	switch (whence) {
147 	case R_IO_SEEK_SET:
148 		io->off = offset;
149 		break;
150 	case R_IO_SEEK_CUR:
151 		io->off += offset;
152 		break;
153 	case R_IO_SEEK_END:
154 		io->off = ST64_MAX;
155 	}
156 	io->off = offset;
157 	return offset;
158 }
159 
__plugin_open(RIO * io,const char * pathname,bool many)160 static bool __plugin_open(RIO *io, const char *pathname, bool many) {
161 	return (!strncmp (pathname, "winedbg://", 10));
162 }
163 
__open(RIO * io,const char * pathname,int rw,int mode)164 static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) {
165 	if (__plugin_open (io, pathname, 0)) {
166 		if (gs) {
167 			return NULL;
168 		}
169 		gs = r_socket_new (0);
170 		char *cmd = r_str_newf ("winedbg '%s'", pathname + 10);
171 		int res = r_socket_spawn (gs, cmd, 1000);
172 		free (cmd);
173 		if (!res) {
174 			return NULL;
175 		}
176 		char *reply = runcmd (NULL);
177 		if (reply) {
178 			int rw = 7;
179 			free (reply);
180 			eprintf ("Wine-dbg is ready to go!\n");
181 			return r_io_desc_new (io, &r_io_plugin_winedbg, pathname, rw, mode, gs);
182 		}
183 		eprintf ("Can't find the Wine-dbg prompt\n");
184 	}
185 	return NULL;
186 }
187 
printcmd(RIO * io,const char * cmd)188 static void printcmd (RIO *io, const char *cmd) {
189 	char *res = runcmd (cmd);
190 	io->cb_printf ("%s\n", res);
191 	free (res);
192 }
193 
regState(void)194 static struct winedbg_x86_32 regState(void) {
195 	struct winedbg_x86_32 r = {0};
196 	char *res = runcmd ("info reg");
197 	if (res) {
198 		char *line = strstr (res, "EIP:");
199 		if (line) {
200 			ut32 eip, esp, ebp, eflags;
201 			(void)sscanf (line, "EIP:%08x ESP:%08x EBP:%08x EFLAGS:%08x",
202 				&eip, &esp, &ebp, &eflags);
203 			r.eip = eip;
204 			r.esp = esp;
205 			r.ebp = ebp;
206 			r.eflags = eflags;
207 			line = strstr (line, "EAX:");
208 			if (line) {
209 				ut32 eax, ebx, ecx, edx;
210 				(void)sscanf (line, "EAX:%08x EBX:%08x ECX:%08x EDX:%08x",
211 					&eax, &ebx, &ecx, &edx);
212 				r.eax = eax;
213 				r.ebx = ebx;
214 				r.ecx = ecx;
215 				r.edx = edx;
216 				line = strstr (line, "ESI:");
217 				if (line) {
218 					ut32 esi, edi;
219 					(void)sscanf (line, "ESI:%08x EDI:%08x", &esi, &edi);
220 					r.esi = esi;
221 					r.edi = edi;
222 				}
223 			}
224 		}
225 		free (res);
226 	}
227 	return r;
228 }
229 
__system(RIO * io,RIODesc * fd,const char * cmd)230 static char *__system(RIO *io, RIODesc *fd, const char *cmd) {
231 	if (!strcmp (cmd, "")) {
232 		return NULL;
233 	}
234 	if (!strncmp (cmd, "?", 1)) {
235 		eprintf ("dr  : show registers\n");
236 		eprintf ("dr* : show registers as flags\n");
237 		eprintf ("drp : show reg profile\n");
238 		eprintf ("dr8 : show hexpairs with regstate\n");
239 		eprintf ("ds  : step into\n");
240 		eprintf ("dp  : show process info\n");
241 		eprintf ("dc  : continue\n");
242 		eprintf ("dm  : show maps\n");
243 		eprintf ("pid : show current process id\n");
244 	} else if (!strncmp (cmd, "dr8", 3)) {
245 		struct winedbg_x86_32 r = regState ();
246 		ut8 *arena = (ut8*)calloc (3, sizeof (struct winedbg_x86_32));
247 		if (arena) {
248 			r_hex_bin2str ((ut8*)&r, sizeof (r), (char *)arena);
249 			return (char *)arena;
250 		}
251 	} else if (!strncmp (cmd, "drp", 3)) {
252 const char *msg =
253 "=PC	eip\n"\
254 "=SP	esp\n"\
255 "=BP	ebp\n"\
256 "=A0	eax\n"\
257 "=A1	ebx\n"\
258 "=A2	ecx\n"\
259 "=A3	edx\n"\
260 "=A4	esi\n"\
261 "=A5	edi\n"\
262 "=SN	eax\n"\
263 
264 "seg	cs	.16	0	0\n"\
265 "seg	ss	.16	2	0\n"\
266 "seg	ds	.16	4	0\n"\
267 "seg	es	.16	6	0\n"\
268 "seg	fs	.16	8	0\n"\
269 "seg	gs	.16	10	0\n"\
270 
271 "gpr	eip	.32	12	0\n"\
272 "gpr	esp	.32	16	0\n"\
273 "gpr	ebp	.32	20	0\n"\
274 "gpr	eflags	.32	24	0\n"\
275 
276 "gpr	eax	.32	28	0\n"\
277 "gpr	ebx	.32	32	0\n"\
278 "gpr	ecx	.32	36	0\n"\
279 "gpr	edx	.32	40	0\n"\
280 "gpr	esi	.32	44	0\n"\
281 "gpr	edi	.32	48	0\n"\
282 
283 "flg	flags	.16	24	0\n"\
284 "flg	cf	.1	.192	0\n"\
285 "flg	pf	.1	.193	0\n"\
286 "flg	af	.1	.194	0\n"\
287 "flg	zf	.1	.195	0\n"\
288 "flg	sf	.1	.196	0\n"\
289 "flg	tf	.1	.197	0\n"\
290 "flg	if	.1	.198	0\n"\
291 "flg	df	.1	.199	0\n"\
292 "flg	of	.1	.200	0\n"\
293 "flg	nt	.1	.201	0\n"\
294 "flg	rf	.1	.202	0\n"\
295 "flg	vm	.1	.203	0\n";
296 		return strdup (msg);
297 	} else if (!strncmp (cmd, "dr*", 3)) {
298 		struct winedbg_x86_32 r = regState ();
299 		io->cb_printf ("f eip = 0x%08x\n", r.eip);
300 		io->cb_printf ("f esp = 0x%08x\n", r.esp);
301 		io->cb_printf ("f ebp = 0x%08x\n", r.ebp);
302 		io->cb_printf ("f eax = 0x%08x\n", r.eax);
303 		io->cb_printf ("f ebx = 0x%08x\n", r.ebx);
304 		io->cb_printf ("f ecx = 0x%08x\n", r.ecx);
305 		io->cb_printf ("f edx = 0x%08x\n", r.edx);
306 		io->cb_printf ("f esi = 0x%08x\n", r.esi);
307 		io->cb_printf ("f edi = 0x%08x\n", r.edi);
308 		io->cb_printf ("f eflags = 0x%08x\n", r.eflags);
309 		io->cb_printf ("f cs = 0x%08x\n", r.cs);
310 		io->cb_printf ("f ss = 0x%08x\n", r.ss);
311 		io->cb_printf ("f ds = 0x%08x\n", r.ds);
312 		io->cb_printf ("f es = 0x%08x\n", r.es);
313 		io->cb_printf ("f fs = 0x%08x\n", r.fs);
314 		io->cb_printf ("f gs = 0x%08x\n", r.gs);
315 	} else if (!strncmp (cmd, "dr", 2)) {
316 		printcmd (io, "info reg");
317 	} else if (!strncmp (cmd, "db ", 3)) {
318 		free (runcmd (sdb_fmt ("break *%x", r_num_get (NULL, cmd + 3) || io->off)));
319 	} else if (!strncmp (cmd, "ds", 2)) {
320 		free (runcmd ("stepi"));
321 	} else if (!strncmp (cmd, "dc", 2)) {
322 		free (runcmd ("cont"));
323 	} else if (!strncmp (cmd, "dso", 3)) {
324 		eprintf ("TODO: dso\n");
325 	} else if (!strncmp (cmd, "dp", 3)) {
326 		printcmd (io, "info thread");
327 	} else if (!strncmp (cmd, "dm", 3)) {
328 		char *wineDbgMaps = runcmd ("info maps");
329 		char *res = NULL;
330 		if (wineDbgMaps) {
331 			const char *perm;
332 			char *ptr = wineDbgMaps;
333 			for (;;) {
334 				char *nl = strchr (ptr, '\n');
335 				if (!nl) {
336 					break;
337 				}
338 				*nl++ = 0;
339 				perm = "r-x";
340 				ut64 from = 0, to = 0;
341 				if (strstr (ptr, " commit ")) {
342 					if (strstr (ptr, "RW")) {
343 						perm = "rw-";
344 					}
345 					sscanf (ptr, "%08"PFMT64x" %08"PFMT64x, &from, &to);
346 				}
347 				char *row = r_str_newf ("0x%08"PFMT64x" - 0x%08" PFMT64x" %s %s\n", from, to, perm, "");
348 				ptr = nl;
349 				if (row) {
350 					res = r_str_append (res, row);
351 					free (row);
352 				}
353 			}
354 			free (wineDbgMaps);
355 			return res;
356 		}
357 	} else if (!strncmp (cmd, "pid", 3)) {
358 		return r_str_newf ("%d", fd->fd);
359 	} else {
360 		printcmd (io, cmd);
361 	}
362 	return NULL;
363 }
364 
365 RIOPlugin r_io_plugin_winedbg = {
366 	.name = "winedbg",
367 	.desc = "Wine-dbg io and debug.io plugin",
368 	.uris = "winedbg://",
369 	.license = "MIT",
370 	.open = __open,
371 	.close = __close,
372 	.read = __read,
373 	.check = __plugin_open,
374 	.lseek = __lseek,
375 	.write = __write,
376 	.system = __system,
377 	.isdbg = true
378 };
379 
380 #ifndef R2_PLUGIN_INCORE
381 R_API RLibStruct radare_plugin = {
382 	.type = R_LIB_TYPE_IO,
383 	.data = &r_io_plugin_winedbg,
384 	.version = R2_VERSION
385 };
386 #endif
387