mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-28 01:56:12 +00:00
380 lines
9.2 KiB
C
380 lines
9.2 KiB
C
/* radare - LGPL - Copyright 2017-2019 - pancake */
|
|
|
|
#include "r_types_base.h"
|
|
#include "r_io.h"
|
|
#include "r_lib.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
|
|
static RSocket *gs = NULL;
|
|
|
|
R_PACKED (struct winedbg_x86_32 {
|
|
ut16 cs;
|
|
ut16 ss;
|
|
ut16 ds;
|
|
ut16 es;
|
|
ut16 fs;
|
|
ut16 gs;
|
|
ut32 eip;
|
|
ut32 esp;
|
|
ut32 ebp;
|
|
ut32 eflags;
|
|
ut32 eax;
|
|
ut32 ebx;
|
|
ut32 ecx;
|
|
ut32 edx;
|
|
ut32 esi;
|
|
ut32 edi;
|
|
});
|
|
|
|
// TODO: make it vargarg...
|
|
static char *runcmd (const char *cmd) {
|
|
char buf[4096] = {0};
|
|
if (cmd) {
|
|
r_socket_printf (gs, "%s\n", cmd);
|
|
}
|
|
int timeout = 1000000;
|
|
char *str = NULL;
|
|
r_socket_block_time (gs, 1, timeout, 0);
|
|
while (true) {
|
|
memset (buf, 0, sizeof (buf));
|
|
r_socket_read (gs, (ut8*)buf, sizeof (buf) - 1); // NULL-terminate the string always
|
|
char *promptFound = strstr (buf, "Wine-dbg>");
|
|
if (promptFound) {
|
|
*promptFound = 0;
|
|
return r_str_append (str, buf);
|
|
}
|
|
str = r_str_append (str, buf);
|
|
}
|
|
free (str);
|
|
return NULL;
|
|
}
|
|
|
|
static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
|
if (!fd || !fd->data) {
|
|
return -1;
|
|
}
|
|
int wordSize = 4;
|
|
ut32 *w = (ut32*)buf;
|
|
int i;
|
|
int words = count / wordSize; // XXX must pad align to 4
|
|
for (i = 0; i < words ; i++) {
|
|
ut64 addr = io->off + (i * wordSize);
|
|
char *cmd = r_str_newf ("set *0x%"PFMT64x" = 0x%x", addr, w[i]);
|
|
free (runcmd (cmd));
|
|
free (cmd);
|
|
}
|
|
|
|
int left = count % wordSize;
|
|
if (left > 0) {
|
|
ut32 leftW = -1;
|
|
memcpy (&leftW, w + words, left);
|
|
ut64 addr = io->off + (words * wordSize);
|
|
char *cmd = r_str_newf ("set *0x%"PFMT64x" = 0x%x", addr, leftW);
|
|
free (runcmd (cmd));
|
|
free (cmd);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
|
|
if (!fd || !fd->data) {
|
|
return -1;
|
|
}
|
|
if (count > (1024*128)) {
|
|
// cannot read that much
|
|
return -1;
|
|
}
|
|
#if 0
|
|
// TODO: use x/${count}b for performance and solve alignment issues
|
|
Wine-dbg>x/128b 0x7b444730
|
|
0x7b444730 _start_process+0x10a: cc 83 ec 08 57 56 e8 b5 fe ff ff 83 c4 04 50 e8
|
|
0x7b444740 _start_process+0x11a: 24 2f 01 00 83 c4 0c 8b 44 24 68 83 ec 08 ff 70
|
|
0x7b444750 _start_process+0x12a: 5c 6a fe e8 27 2f 01 00 83 c4 08 e8 34 de 01 00
|
|
0x7b444760 _debugstr_w: 55 89 e5 83 ec 08 83 ec 08 6a ff 51 e8 45 e0 01
|
|
0x7b444770 _debugstr_w+0x10: 00 83 c4 18 5d c3 55 89 e5 53 57 56 83 e4 f0 81
|
|
0x7b444780 ___wine_kernel_init+0xa: ec e0 0e 00 00 e8 00 00 00 00 5e 64 a1 18 00 00
|
|
0x7b444790 ___wine_kernel_init+0x1a: 00 89 44 24 40 8b 40 30 89 44 24 44 8b 78 10 8b
|
|
0x7b4447a0 ___wine_kernel_init+0x2a: 86 ca 48 1b 00 83 ec 08 31 db 53 ff 30 e8 e4 de
|
|
Wine-dbg>
|
|
#endif
|
|
int wordSize = 4;
|
|
ut32 *w = (ut32*)buf;
|
|
int i;
|
|
memset (buf, 0xff, count);
|
|
int words = count / wordSize; // XXX must pad align to 4
|
|
for (i = 0; i < words ; i++) {
|
|
ut64 addr = io->off + (i * wordSize);
|
|
char *cmd = r_str_newf ("x 0x%"PFMT64x, addr);
|
|
char *res = runcmd (cmd);
|
|
if (res) {
|
|
sscanf (res, "%x", &w[i]);
|
|
free (res);
|
|
}
|
|
free (cmd);
|
|
}
|
|
|
|
int left = count % wordSize;
|
|
if (left > 0) {
|
|
ut32 n = 0xff;
|
|
ut8 *wn = (ut8*)&n;
|
|
ut64 addr = io->off + (i * wordSize);
|
|
char *cmd = r_str_newf ("x 0x%"PFMT64x, addr);
|
|
char *res = runcmd (cmd);
|
|
sscanf (res, "%x", &n);
|
|
free (res);
|
|
free (cmd);
|
|
memcpy (buf + (words * wordSize), wn, left);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int __close(RIODesc *fd) {
|
|
if (!fd || !fd->data) {
|
|
return -1;
|
|
}
|
|
// XXX
|
|
r_sys_cmdf ("pkill rarun2");
|
|
return 0;
|
|
}
|
|
|
|
static ut64 __lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
io->off = offset;
|
|
return offset;
|
|
case SEEK_CUR:
|
|
return io->off + offset;
|
|
case SEEK_END:
|
|
return UT64_MAX;
|
|
}
|
|
io->off = offset;
|
|
return offset;
|
|
}
|
|
|
|
static bool __plugin_open(RIO *io, const char *pathname, bool many) {
|
|
return (!strncmp (pathname, "winedbg://", 10));
|
|
}
|
|
|
|
static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) {
|
|
if (__plugin_open (io, pathname, 0)) {
|
|
if (gs) {
|
|
return NULL;
|
|
}
|
|
gs = r_socket_new (0);
|
|
char *cmd = r_str_newf ("winedbg '%s'", pathname + 10);
|
|
int res = r_socket_spawn (gs, cmd, 1000);
|
|
free (cmd);
|
|
if (!res) {
|
|
return NULL;
|
|
}
|
|
char *reply = runcmd (NULL);
|
|
if (reply) {
|
|
int rw = 7;
|
|
free (reply);
|
|
eprintf ("Wine-dbg is ready to go!\n");
|
|
return r_io_desc_new (io, &r_io_plugin_winedbg, pathname, rw, mode, gs);
|
|
}
|
|
eprintf ("Can't find the Wine-dbg prompt\n");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void printcmd (RIO *io, const char *cmd) {
|
|
char *res = runcmd (cmd);
|
|
io->cb_printf ("%s\n", res);
|
|
free (res);
|
|
}
|
|
|
|
static struct winedbg_x86_32 regState() {
|
|
struct winedbg_x86_32 r = {0};
|
|
char *res = runcmd ("info reg");
|
|
if (res) {
|
|
char *line = strstr (res, "EIP:");
|
|
if (line) {
|
|
ut32 eip, esp, ebp, eflags;
|
|
(void)sscanf (line, "EIP:%08x ESP:%08x EBP:%08x EFLAGS:%08x",
|
|
&eip, &esp, &ebp, &eflags);
|
|
r.eip = eip;
|
|
r.esp = esp;
|
|
r.ebp = ebp;
|
|
r.eflags = eflags;
|
|
line = strstr (line, "EAX:");
|
|
if (line) {
|
|
ut32 eax, ebx, ecx, edx;
|
|
(void)sscanf (line, "EAX:%08x EBX:%08x ECX:%08x EDX:%08x",
|
|
&eax, &ebx, &ecx, &edx);
|
|
r.eax = eax;
|
|
r.ebx = ebx;
|
|
r.ecx = ecx;
|
|
r.edx = edx;
|
|
line = strstr (line, "ESI:");
|
|
if (line) {
|
|
ut32 esi, edi;
|
|
(void)sscanf (line, "ESI:%08x EDI:%08x", &esi, &edi);
|
|
r.esi = esi;
|
|
r.edi = edi;
|
|
}
|
|
}
|
|
}
|
|
free (res);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static char *__system(RIO *io, RIODesc *fd, const char *cmd) {
|
|
if (!strncmp (cmd, "?", 1)) {
|
|
eprintf ("dr : show registers\n");
|
|
eprintf ("dr* : show registers as flags\n");
|
|
eprintf ("drp : show reg profile\n");
|
|
eprintf ("dr8 : show hexpairs with regstate\n");
|
|
eprintf ("ds : step into\n");
|
|
eprintf ("dp : show process info\n");
|
|
eprintf ("dc : continue\n");
|
|
eprintf ("dm : show maps\n");
|
|
eprintf ("pid : show current process id\n");
|
|
} else if (!strncmp (cmd, "dr8", 3)) {
|
|
struct winedbg_x86_32 r = regState ();
|
|
ut8 *arena = (ut8*)calloc (3, sizeof (struct winedbg_x86_32));
|
|
if (arena) {
|
|
r_hex_bin2str ((ut8*)&r, sizeof (r), (char *)arena);
|
|
return (char *)arena;
|
|
}
|
|
} else if (!strncmp (cmd, "drp", 3)) {
|
|
const char *msg =
|
|
"=PC eip\n"\
|
|
"=SP esp\n"\
|
|
"=BP ebp\n"\
|
|
"=A0 eax\n"\
|
|
"=A1 ebx\n"\
|
|
"=A2 ecx\n"\
|
|
"=A3 edx\n"\
|
|
"=A4 esi\n"\
|
|
"=A5 edi\n"\
|
|
"=SN eax\n"\
|
|
|
|
"seg cs .16 0 0\n"\
|
|
"seg ss .16 2 0\n"\
|
|
"seg ds .16 4 0\n"\
|
|
"seg es .16 6 0\n"\
|
|
"seg fs .16 8 0\n"\
|
|
"seg gs .16 10 0\n"\
|
|
|
|
"gpr eip .32 12 0\n"\
|
|
"gpr esp .32 16 0\n"\
|
|
"gpr ebp .32 20 0\n"\
|
|
"gpr eflags .32 24 0\n"\
|
|
|
|
"gpr eax .32 28 0\n"\
|
|
"gpr ebx .32 32 0\n"\
|
|
"gpr ecx .32 36 0\n"\
|
|
"gpr edx .32 40 0\n"\
|
|
"gpr esi .32 44 0\n"\
|
|
"gpr edi .32 48 0\n"\
|
|
|
|
"flg flags .16 24 0\n"\
|
|
"flg cf .1 .192 0\n"\
|
|
"flg pf .1 .193 0\n"\
|
|
"flg af .1 .194 0\n"\
|
|
"flg zf .1 .195 0\n"\
|
|
"flg sf .1 .196 0\n"\
|
|
"flg tf .1 .197 0\n"\
|
|
"flg if .1 .198 0\n"\
|
|
"flg df .1 .199 0\n"\
|
|
"flg of .1 .200 0\n"\
|
|
"flg nt .1 .201 0\n"\
|
|
"flg rf .1 .202 0\n"\
|
|
"flg vm .1 .203 0\n";
|
|
return strdup (msg);
|
|
} else if (!strncmp (cmd, "dr*", 2)) {
|
|
struct winedbg_x86_32 r = regState ();
|
|
io->cb_printf ("f eip = 0x%08x\n", r.eip);
|
|
io->cb_printf ("f esp = 0x%08x\n", r.esp);
|
|
io->cb_printf ("f ebp = 0x%08x\n", r.ebp);
|
|
io->cb_printf ("f eax = 0x%08x\n", r.eax);
|
|
io->cb_printf ("f ebx = 0x%08x\n", r.ebx);
|
|
io->cb_printf ("f ecx = 0x%08x\n", r.ecx);
|
|
io->cb_printf ("f edx = 0x%08x\n", r.edx);
|
|
io->cb_printf ("f esi = 0x%08x\n", r.esi);
|
|
io->cb_printf ("f edi = 0x%08x\n", r.edi);
|
|
io->cb_printf ("f eflags = 0x%08x\n", r.eflags);
|
|
io->cb_printf ("f cs = 0x%08x\n", r.cs);
|
|
io->cb_printf ("f ss = 0x%08x\n", r.ss);
|
|
io->cb_printf ("f ds = 0x%08x\n", r.ds);
|
|
io->cb_printf ("f es = 0x%08x\n", r.es);
|
|
io->cb_printf ("f fs = 0x%08x\n", r.fs);
|
|
io->cb_printf ("f gs = 0x%08x\n", r.gs);
|
|
} else if (!strncmp (cmd, "dr", 2)) {
|
|
printcmd (io, "info reg");
|
|
} else if (!strncmp (cmd, "db ", 3)) {
|
|
free (runcmd (sdb_fmt ("break *%"PFMT64x, r_num_get (NULL, cmd + 3) || io->off)));
|
|
} else if (!strncmp (cmd, "ds", 2)) {
|
|
free (runcmd ("stepi"));
|
|
} else if (!strncmp (cmd, "dc", 2)) {
|
|
free (runcmd ("cont"));
|
|
} else if (!strncmp (cmd, "dso", 3)) {
|
|
eprintf ("TODO: dso\n");
|
|
} else if (!strncmp (cmd, "dp", 3)) {
|
|
printcmd (io, "info thread");
|
|
} else if (!strncmp (cmd, "dm", 3)) {
|
|
char *wineDbgMaps = runcmd ("info maps");
|
|
char *res = NULL;
|
|
if (wineDbgMaps) {
|
|
const char *perm;
|
|
char *ptr = wineDbgMaps;
|
|
for (;;) {
|
|
char *nl = strchr (ptr, '\n');
|
|
if (!nl) {
|
|
break;
|
|
}
|
|
*nl++ = 0;
|
|
perm = "r-x";
|
|
ut64 from = 0, to = 0;
|
|
if (strstr (ptr, " commit ")) {
|
|
if (strstr (ptr, "RW")) {
|
|
perm = "rw-";
|
|
}
|
|
sscanf (ptr, "%08"PFMT64x" %08"PFMT64x, &from, &to);
|
|
}
|
|
char *row = r_str_newf ("0x%08"PFMT64x" - 0x%08" PFMT64x" %s %s\n", from, to, perm, "");
|
|
ptr = nl;
|
|
if (row) {
|
|
res = r_str_append (res, row);
|
|
free (row);
|
|
}
|
|
}
|
|
free (wineDbgMaps);
|
|
return res;
|
|
}
|
|
} else if (!strncmp (cmd, "pid", 3)) {
|
|
return r_str_newf ("%d", fd->fd);
|
|
} else {
|
|
printcmd (io, cmd);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
RIOPlugin r_io_plugin_winedbg = {
|
|
.name = "winedbg",
|
|
.desc = "Wine-dbg io and debug.io plugin",
|
|
.uris = "winedbg://",
|
|
.license = "MIT",
|
|
.open = __open,
|
|
.close = __close,
|
|
.read = __read,
|
|
.check = __plugin_open,
|
|
.lseek = __lseek,
|
|
.write = __write,
|
|
.system = __system,
|
|
.isdbg = true
|
|
};
|
|
|
|
#ifndef CORELIB
|
|
R_API RLibStruct radare_plugin = {
|
|
.type = R_LIB_TYPE_IO,
|
|
.data = &r_io_plugin_winedbg,
|
|
.version = R2_VERSION
|
|
};
|
|
#endif
|