mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-26 22:50:48 +00:00
Add DbgEng based debug backend for Windows ##debug (#17491)
* Rename `windbg` plugin to `winkd` ##debug * Add DbgEng based debug backend for Windows ##debug
This commit is contained in:
parent
d8d7edf470
commit
489538e02b
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@ -138,8 +138,8 @@ java:
|
||||
- shlr/java/**/*
|
||||
|
||||
WinDbg:
|
||||
- shlr/windbg/**/*
|
||||
- libr/io/p/io_windbg.c
|
||||
- shlr/winkd/**/*
|
||||
- libr/io/p/io_winkd.c
|
||||
|
||||
webui:
|
||||
- shlr/www/**/*
|
||||
|
@ -33,5 +33,5 @@ shlr/ptrace-wrap/ @thestr4ng3r
|
||||
shlr/radare2-shell-parser/ @ret2libc
|
||||
shlr/tcc/ @XVilka @trufae
|
||||
shlr/w32dbg_wrap/ @yossizap
|
||||
shlr/windbg/ @yossizap
|
||||
shlr/winkd/ @yossizap
|
||||
doc/fortunes.nsfw @thestr4ng3r
|
||||
|
@ -208,11 +208,11 @@ See doc/qnx
|
||||
|
||||
See doc/rap
|
||||
|
||||
### libr/debug/p/debug_windbg.c
|
||||
### libr/debug/p/debug_winkd.c
|
||||
|
||||
A debugger plugin that enables debugging code remotely via WinDbg protocol. WinDbg protocol
|
||||
parser is located in shlr/windbg. Corresponding IO plugin located in libr/io/p/io_windbg.c
|
||||
See doc/windbg
|
||||
parser is located in shlr/winkd. Corresponding IO plugin located in libr/io/p/io_winkd.c
|
||||
See doc/winkd
|
||||
|
||||
## Conclusion
|
||||
|
||||
|
@ -34,24 +34,24 @@ Configure the VirtualBox Machine like this:
|
||||
Port Number: [_COM1_______[v]]
|
||||
Port Mode: [_Host_Pipe__[v]]
|
||||
[v] Create Pipe
|
||||
Port/File Path: [_/tmp/windbg.pipe____]
|
||||
Port/File Path: [_/tmp/winkd.pipe____]
|
||||
|
||||
Or just spawn the VM with qemu like this:
|
||||
|
||||
$ qemu-system-x86_64 -chardev socket,id=serial0,\
|
||||
path=/tmp/windbg.pipe,nowait,server \
|
||||
path=/tmp/winkd.pipe,nowait,server \
|
||||
-serial chardev:serial0 -hda Windows7-VM.vdi
|
||||
|
||||
|
||||
Radare2 will use the 'windbg' io plugin to connect to a socket file
|
||||
created by virtualbox or qemu. Also, the 'windbg' debugger plugin and
|
||||
Radare2 will use the 'winkd' io plugin to connect to a socket file
|
||||
created by virtualbox or qemu. Also, the 'winkd' debugger plugin and
|
||||
we should specify the x86-32 too. (32 and 64 bit debugging is supported)
|
||||
|
||||
$ r2 -a x86 -b 32 -D windbg windbg:///tmp/windbg.pipe
|
||||
$ r2 -a x86 -b 32 -D winkd winkd:///tmp/winkd.pipe
|
||||
|
||||
On Windows you should run the following line:
|
||||
|
||||
$ radare2 -D windbg windbg://\\.\pipe\com_1
|
||||
$ radare2 -D winkd winkd://\\.\pipe\com_1
|
||||
|
||||
At this point, we will get stuck here:
|
||||
|
||||
|
@ -113,7 +113,7 @@ E+=../shlr/grub/libgrubfs.${EXT_AR}
|
||||
endif
|
||||
E+=../shlr/yxml/libyxml.${EXT_AR}
|
||||
E+=../shlr/ar/libr_ar.${EXT_AR}
|
||||
E+=../shlr/windbg/libr_windbg.${EXT_AR}
|
||||
E+=../shlr/winkd/libr_winkd.${EXT_AR}
|
||||
E+=../shlr/qnx/lib/libqnxr.${EXT_AR}
|
||||
E+=../shlr/bochs/lib/libbochs.${EXT_AR}
|
||||
E+=../shlr/radare2-shell-parser/libshell-parser.${EXT_AR}
|
||||
|
@ -18,7 +18,7 @@ LDFLAGS+=$(STOP)/sdb/src/libsdb.a
|
||||
|
||||
include $(STOP)/java/deps.mk
|
||||
include $(STOP)/gdb/deps.mk
|
||||
include $(STOP)/windbg/deps.mk
|
||||
include $(STOP)/winkd/deps.mk
|
||||
|
||||
LDFLAGS+=${LINK}
|
||||
|
||||
|
@ -21,7 +21,7 @@ r_debug_sources = [
|
||||
'p/debug_null.c',
|
||||
'p/debug_qnx.c',
|
||||
'p/debug_rap.c',
|
||||
'p/debug_windbg.c',
|
||||
'p/debug_winkd.c',
|
||||
#'p/native/arm.c',
|
||||
#'p/native/bt/fuzzy-all.c',
|
||||
#'p/native/bt/generic-x64.c',
|
||||
@ -45,7 +45,7 @@ r_debug_deps = [
|
||||
r_cons_dep,
|
||||
r_lang_dep,
|
||||
r_egg_dep,
|
||||
windbg_dep,
|
||||
winkd_dep,
|
||||
qnx_dep,
|
||||
gdb_dep,
|
||||
bochs_dep,
|
||||
@ -61,6 +61,7 @@ endif
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
r_debug_sources += [
|
||||
'p/debug_windbg.c',
|
||||
'p/native/maps/windows_maps.c',
|
||||
'p/native/windows/windows_debug.c',
|
||||
'p/native/windows/windows_message.c',
|
||||
|
@ -6,7 +6,7 @@ CFLAGS+=-I../../include -Wall ${PIC_FLAGS} ${LDFLAGS_LIB} ${LDFLAGS_LINKPATH}..
|
||||
all: ${ALL_TARGETS}
|
||||
|
||||
ALL_TARGETS=
|
||||
DEBUGS=native.mk gdb.mk qnx.mk windbg.mk bochs.mk
|
||||
DEBUGS=native.mk gdb.mk qnx.mk winkd.mk bochs.mk
|
||||
include $(DEBUGS)
|
||||
|
||||
pre:
|
||||
|
@ -1,289 +1,628 @@
|
||||
// Copyright (c) 2014-2017, The Lemon Man, All rights reserved. LGPLv3
|
||||
/* radare - LGPL - Copyright 2020 - GustavoLCR */
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
#include <r_asm.h>
|
||||
#include <r_debug.h>
|
||||
#include <windbg.h>
|
||||
#include <kd.h>
|
||||
#include <DbgEng.h>
|
||||
|
||||
static WindCtx *wctx = NULL;
|
||||
#ifndef CONTEXT_ARM
|
||||
#define CONTEXT_ARM 0x00200000L
|
||||
#endif
|
||||
#ifndef CONTEXT_ARM64
|
||||
#define CONTEXT_ARM64 0x00400000L
|
||||
#endif
|
||||
#ifndef CONTEXT_AMD64
|
||||
#define CONTEXT_AMD64 0x00100000L
|
||||
#endif
|
||||
#ifndef CONTEXT_i386
|
||||
#define CONTEXT_i386 0x00010000L
|
||||
#endif
|
||||
#ifndef IMAGE_FILE_MACHINE_ARM64
|
||||
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
|
||||
#endif
|
||||
#ifndef DEBUG_DUMP_ACTIVE
|
||||
#define DEBUG_DUMP_ACTIVE 1030
|
||||
#endif
|
||||
|
||||
static int r_debug_windbg_step(RDebug *dbg) {
|
||||
return true;
|
||||
#define TIMEOUT 500
|
||||
#define THISCALL(dbginterface, function, ...) dbginterface->lpVtbl->function (dbginterface, __VA_ARGS__)
|
||||
#define ITHISCALL(dbginterface, function, ...) THISCALL (idbg->dbginterface, function, __VA_ARGS__)
|
||||
#define RELEASE(I) if (I) THISCALL (I, Release);
|
||||
|
||||
typedef struct { // Keep in sync with io_windbg.c
|
||||
bool initialized;
|
||||
ULONG64 server;
|
||||
ULONG64 processBase;
|
||||
DWORD lastExecutionStatus;
|
||||
PDEBUG_CLIENT5 dbgClient;
|
||||
PDEBUG_CONTROL4 dbgCtrl;
|
||||
PDEBUG_DATA_SPACES4 dbgData;
|
||||
PDEBUG_REGISTERS2 dbgReg;
|
||||
PDEBUG_SYSTEM_OBJECTS4 dbgSysObj;
|
||||
PDEBUG_SYMBOLS3 dbgSymbols;
|
||||
PDEBUG_ADVANCED3 dbgAdvanced;
|
||||
} DbgEngContext;
|
||||
|
||||
static bool __is_target_kernel(DbgEngContext *idbg) {
|
||||
ULONG Class, Qualifier;
|
||||
if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
|
||||
if (Class == DEBUG_CLASS_KERNEL) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
|
||||
int ret = windbg_read_reg(wctx, buf, size);
|
||||
if (!ret || size != ret) {
|
||||
return -1;
|
||||
static int windbg_init(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
if (!idbg || !idbg->initialized) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int windbg_step(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
idbg->lastExecutionStatus = DEBUG_STATUS_STEP_INTO;
|
||||
return SUCCEEDED (ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_STEP_INTO));
|
||||
}
|
||||
|
||||
static int windbg_step_over(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
idbg->lastExecutionStatus = DEBUG_STATUS_STEP_OVER;
|
||||
return SUCCEEDED (ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_STEP_OVER));
|
||||
}
|
||||
|
||||
static int windbg_select(RDebug *dbg, int pid, int tid) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
ULONG Id = tid, Class, Qualifier;
|
||||
if (!__is_target_kernel (idbg)) {
|
||||
ITHISCALL (dbgSysObj, GetThreadIdBySystemId, tid, &Id);
|
||||
}
|
||||
if (SUCCEEDED (ITHISCALL (dbgSysObj, SetCurrentThreadId, Id))) {
|
||||
return 1;
|
||||
}
|
||||
r_reg_read_regs (dbg->reg, buf, ret);
|
||||
// Report as if no register has been written as we've already updated the arena here
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
|
||||
if (!dbg->reg) {
|
||||
return false;
|
||||
static int windbg_continue(RDebug *dbg, int pid, int tid, int sig) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
idbg->lastExecutionStatus = DEBUG_STATUS_GO;
|
||||
ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_GO);
|
||||
return tid;
|
||||
}
|
||||
|
||||
// nicked from windows_debug.c
|
||||
static RDebugReasonType exception_to_reason(DWORD ExceptionCode) {
|
||||
switch (ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_GUARD_PAGE:
|
||||
return R_DEBUG_REASON_SEGFAULT;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
return R_DEBUG_REASON_BREAKPOINT;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
return R_DEBUG_REASON_FPU;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
return R_DEBUG_REASON_ILLEGAL;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
return R_DEBUG_REASON_DIVBYZERO;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
return R_DEBUG_REASON_STEP;
|
||||
default:
|
||||
return R_DEBUG_REASON_TRAP;
|
||||
}
|
||||
int arena_size;
|
||||
ut8 *arena = r_reg_get_bytes (dbg->reg, R_REG_TYPE_ALL, &arena_size);
|
||||
if (!arena) {
|
||||
eprintf ("Could not retrieve the register arena!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static int windbg_stop(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
return SUCCEEDED (ITHISCALL (dbgCtrl, SetInterrupt, DEBUG_INTERRUPT_ACTIVE));
|
||||
}
|
||||
|
||||
static bool do_break = false;
|
||||
|
||||
static void __break(void *user) {
|
||||
RDebug *dbg = (RDebug *)user;
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
if (__is_target_kernel (idbg)) {
|
||||
windbg_stop (dbg);
|
||||
}
|
||||
int ret = windbg_write_reg (wctx, arena, arena_size);
|
||||
free (arena);
|
||||
do_break = true;
|
||||
}
|
||||
|
||||
static int windbg_wait(RDebug *dbg, int pid) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
ULONG Type, ProcessId, ThreadId;
|
||||
r_cons_break_push (__break, dbg);
|
||||
const ULONG timeout = __is_target_kernel (idbg) ? INFINITE : TIMEOUT;
|
||||
HRESULT hr;
|
||||
while ((hr = ITHISCALL (dbgCtrl, WaitForEvent, DEBUG_WAIT_DEFAULT, timeout)) == S_FALSE) {
|
||||
if (do_break) {
|
||||
ITHISCALL (dbgCtrl, SetExecutionStatus, DEBUG_STATUS_BREAK);
|
||||
do_break = false;
|
||||
r_cons_break_pop ();
|
||||
return R_DEBUG_REASON_USERSUSP;
|
||||
}
|
||||
}
|
||||
r_cons_break_pop ();
|
||||
if (FAILED (hr)) {
|
||||
return R_DEBUG_REASON_DEAD;
|
||||
}
|
||||
ITHISCALL (dbgCtrl, GetLastEventInformation, &Type, &ProcessId, &ThreadId, NULL, 0, NULL, NULL, 0, NULL);
|
||||
if (!__is_target_kernel (idbg)) {
|
||||
ITHISCALL (dbgSysObj, GetCurrentProcessSystemId, &dbg->pid);
|
||||
ITHISCALL (dbgSysObj, GetCurrentThreadSystemId, &dbg->tid);
|
||||
} else {
|
||||
dbg->pid = ProcessId;
|
||||
dbg->tid = ThreadId;
|
||||
}
|
||||
int ret;
|
||||
switch (Type) {
|
||||
case 0:
|
||||
// I dont really get why Type is zero here
|
||||
if (idbg->lastExecutionStatus == DEBUG_STATUS_STEP_INTO
|
||||
|| idbg->lastExecutionStatus == DEBUG_STATUS_STEP_OVER) {
|
||||
ret = R_DEBUG_REASON_STEP;
|
||||
} else {
|
||||
ret = R_DEBUG_REASON_ERROR;
|
||||
}
|
||||
break;
|
||||
case DEBUG_EVENT_BREAKPOINT:
|
||||
ret = R_DEBUG_REASON_BREAKPOINT;
|
||||
break;
|
||||
case DEBUG_EVENT_EXCEPTION: {
|
||||
EXCEPTION_RECORD64 exr;
|
||||
ITHISCALL (dbgCtrl, GetLastEventInformation, &Type, &ProcessId, &ThreadId, &exr, sizeof (exr), NULL, NULL, 0, NULL);
|
||||
dbg->reason.type = exception_to_reason (exr.ExceptionCode);
|
||||
dbg->reason.tid = dbg->tid;
|
||||
dbg->reason.addr = exr.ExceptionAddress;
|
||||
dbg->reason.timestamp = r_time_now ();
|
||||
ret = dbg->reason.type;
|
||||
break;
|
||||
}
|
||||
case DEBUG_EVENT_EXIT_PROCESS:
|
||||
ret = R_DEBUG_REASON_EXIT_PID;
|
||||
break;
|
||||
case DEBUG_EVENT_CREATE_PROCESS:
|
||||
ret = R_DEBUG_REASON_NEW_PID;
|
||||
break;
|
||||
default:
|
||||
ret = R_DEBUG_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_continue(RDebug *dbg, int pid, int tid, int sig) {
|
||||
return windbg_continue(wctx);
|
||||
}
|
||||
|
||||
static RDebugReasonType r_debug_windbg_wait(RDebug *dbg, int pid) {
|
||||
RDebugReasonType reason = R_DEBUG_REASON_UNKNOWN;
|
||||
kd_packet_t *pkt = NULL;
|
||||
kd_stc_64 *stc;
|
||||
windbg_lock_enter (wctx);
|
||||
for (;;) {
|
||||
void *bed = r_cons_sleep_begin ();
|
||||
int ret = windbg_wait_packet (wctx, KD_PACKET_TYPE_STATE_CHANGE64, &pkt);
|
||||
r_cons_sleep_end (bed);
|
||||
if (ret != KD_E_OK || !pkt) {
|
||||
reason = R_DEBUG_REASON_ERROR;
|
||||
break;
|
||||
static int windbg_breakpoint(RBreakpoint *bp, RBreakpointItem *b, bool set) {
|
||||
static int bp_idx = 0;
|
||||
RDebug *dbg = bp->user;
|
||||
r_return_val_if_fail (dbg, 0);
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
ULONG type = b->hw ? DEBUG_BREAKPOINT_DATA : DEBUG_BREAKPOINT_CODE;
|
||||
PDEBUG_BREAKPOINT bkpt;
|
||||
if (FAILED (ITHISCALL (dbgCtrl, GetBreakpointById, b->internal, &bkpt))) {
|
||||
HRESULT hr;
|
||||
do {
|
||||
b->internal = InterlockedIncrement (&bp_idx);
|
||||
hr = ITHISCALL (dbgCtrl, AddBreakpoint, type, b->internal, &bkpt);
|
||||
} while (hr == E_INVALIDARG);
|
||||
if (FAILED (hr)) {
|
||||
return 0;
|
||||
}
|
||||
stc = (kd_stc_64 *) pkt->data;
|
||||
dbg->reason.addr = stc->pc;
|
||||
dbg->reason.tid = stc->kthread;
|
||||
dbg->reason.signum = stc->state;
|
||||
windbg_set_cpu (wctx, stc->cpu);
|
||||
if (stc->state == DbgKdExceptionStateChange) {
|
||||
dbg->reason.type = R_DEBUG_REASON_INT;
|
||||
reason = R_DEBUG_REASON_INT;
|
||||
break;
|
||||
} else if (stc->state == DbgKdLoadSymbolsStateChange) {
|
||||
dbg->reason.type = R_DEBUG_REASON_NEW_LIB;
|
||||
reason = R_DEBUG_REASON_NEW_LIB;
|
||||
break;
|
||||
}
|
||||
ULONG flags;
|
||||
THISCALL (bkpt, GetFlags, &flags);
|
||||
flags = set ? flags | DEBUG_BREAKPOINT_ENABLED : flags & ~DEBUG_BREAKPOINT_ENABLED;
|
||||
if (b->hw) {
|
||||
ULONG access_type = 0;
|
||||
if (b->perm & R_BP_PROT_EXEC) {
|
||||
access_type |= DEBUG_BREAK_EXECUTE;
|
||||
}
|
||||
R_FREE (pkt);
|
||||
if (b->perm & R_BP_PROT_READ) {
|
||||
access_type |= DEBUG_BREAK_READ;
|
||||
}
|
||||
if (b->perm & R_BP_PROT_WRITE) {
|
||||
access_type |= DEBUG_BREAK_WRITE;
|
||||
}
|
||||
if (b->perm & R_BP_PROT_ACCESS) {
|
||||
access_type |= DEBUG_BREAK_READ;
|
||||
access_type |= DEBUG_BREAK_WRITE;
|
||||
}
|
||||
THISCALL (bkpt, SetDataParameters, b->size, access_type);
|
||||
}
|
||||
windbg_lock_leave (wctx);
|
||||
free (pkt);
|
||||
return reason;
|
||||
THISCALL (bkpt, SetFlags, flags);
|
||||
THISCALL (bkpt, GetCurrentPassCount, &b->togglehits);
|
||||
THISCALL (bkpt, SetOffset, b->addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_attach(RDebug *dbg, int pid) {
|
||||
RIODesc *desc = dbg->iob.io->desc;
|
||||
|
||||
if (!desc || !desc->plugin || !desc->plugin->name || !desc->data) {
|
||||
return false;
|
||||
}
|
||||
if (strncmp (desc->plugin->name, "windbg", 6)) {
|
||||
return false;
|
||||
}
|
||||
if (dbg->arch && strcmp (dbg->arch, "x86")) {
|
||||
return false;
|
||||
}
|
||||
wctx = (WindCtx *)desc->data;
|
||||
|
||||
// Handshake
|
||||
if (!windbg_sync (wctx)) {
|
||||
eprintf ("Could not connect to windbg\n");
|
||||
windbg_ctx_free ((WindCtx **)&desc->data);
|
||||
return false;
|
||||
}
|
||||
if (!windbg_read_ver (wctx)) {
|
||||
windbg_ctx_free ((WindCtx **)&desc->data);
|
||||
return false;
|
||||
}
|
||||
dbg->bits = windbg_get_bits (wctx);
|
||||
// Make r_debug_is_dead happy
|
||||
dbg->pid = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_detach(RDebug *dbg, int pid) {
|
||||
eprintf ("Detaching...\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *r_debug_windbg_reg_profile(RDebug *dbg) {
|
||||
if (!dbg) {
|
||||
return NULL;
|
||||
}
|
||||
if (dbg->arch && strcmp (dbg->arch, "x86")) {
|
||||
return NULL;
|
||||
}
|
||||
r_debug_windbg_attach (dbg, 0);
|
||||
if (dbg->bits == R_SYS_BITS_32) {
|
||||
#include "native/reg/windows-x86.h"
|
||||
} else if (dbg->bits == R_SYS_BITS_64) {
|
||||
static char *windbg_reg_profile(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
ULONG type;
|
||||
if (!idbg || !idbg->initialized || FAILED (ITHISCALL (dbgCtrl, GetActualProcessorType, &type))) {
|
||||
if (dbg->bits & R_SYS_BITS_64) {
|
||||
#include "native/reg/windows-x64.h"
|
||||
} else {
|
||||
#include "native/reg/windows-x86.h"
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (type == IMAGE_FILE_MACHINE_IA64 || type == IMAGE_FILE_MACHINE_AMD64) {
|
||||
#include "native/reg/windows-x64.h"
|
||||
} else if (type == IMAGE_FILE_MACHINE_I386) {
|
||||
#include "native/reg/windows-x86.h"
|
||||
} else if (type == IMAGE_FILE_MACHINE_ARM) {
|
||||
#include "native/reg/windows-arm.h"
|
||||
} else if (type == IMAGE_FILE_MACHINE_ARM64) {
|
||||
#include "native/reg/windows-arm64.h"
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_breakpoint(RBreakpoint *bp, RBreakpointItem *b, bool set) {
|
||||
int *tag;
|
||||
if (!b) {
|
||||
return false;
|
||||
static int windbg_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
if (!idbg || !idbg->initialized || FAILED (ITHISCALL (dbgCtrl, GetActualProcessorType, &type))) {
|
||||
return 0;
|
||||
}
|
||||
// Use a 32 bit word here to keep this compatible with 32 bit hosts
|
||||
if (!b->data) {
|
||||
b->data = (char *)R_NEW0 (int);
|
||||
if (!b->data) {
|
||||
return 0;
|
||||
}
|
||||
if (type == IMAGE_FILE_MACHINE_IA64 || type == IMAGE_FILE_MACHINE_AMD64) {
|
||||
DWORD *b = (DWORD *)(buf + 0x30);
|
||||
*b |= 0xff | CONTEXT_AMD64;
|
||||
} else if (type == IMAGE_FILE_MACHINE_I386) {
|
||||
DWORD *b = (DWORD *)buf;
|
||||
*b |= 0xff | CONTEXT_i386;
|
||||
} else if (type == IMAGE_FILE_MACHINE_ARM64) {
|
||||
DWORD *b = (DWORD *)buf;
|
||||
*b |= 0xff | CONTEXT_ARM64;
|
||||
} else if (type == IMAGE_FILE_MACHINE_ARM64) {
|
||||
DWORD *b = (DWORD *)buf;
|
||||
*b |= 0xff | CONTEXT_ARM;
|
||||
}
|
||||
tag = (int *)b->data;
|
||||
return windbg_bkpt (wctx, b->addr, set, b->hw, tag);
|
||||
if (SUCCEEDED (ITHISCALL (dbgAdvanced, GetThreadContext, (PVOID)buf, size))) {
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int windbg_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
if (SUCCEEDED (ITHISCALL (dbgAdvanced, SetThreadContext, (PVOID)buf, size))) {
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_init(RDebug *dbg) {
|
||||
static RList *windbg_frames(RDebug *dbg, ut64 at) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
const size_t frame_cnt = 128;
|
||||
PDEBUG_STACK_FRAME dbgframes = R_NEWS (DEBUG_STACK_FRAME, frame_cnt);
|
||||
if (!dbgframes) {
|
||||
return NULL;
|
||||
}
|
||||
ULONG frames_filled;
|
||||
if (FAILED (ITHISCALL (dbgCtrl, GetStackTrace, 0, 0, 0, dbgframes, frame_cnt, &frames_filled))) {
|
||||
free (dbgframes);
|
||||
return NULL;
|
||||
}
|
||||
RList *frames = r_list_newf (free);
|
||||
size_t i;
|
||||
for (i = 0; i < frames_filled; i++) {
|
||||
RDebugFrame *f = R_NEW0 (RDebugFrame);
|
||||
if (!f) {
|
||||
break;
|
||||
}
|
||||
f->sp = dbgframes[i].StackOffset;
|
||||
f->bp = dbgframes[i].FrameOffset;
|
||||
f->addr = dbgframes[i].ReturnOffset;
|
||||
f->size = f->bp - f->sp;
|
||||
r_list_append (frames, f);
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
static RList *windbg_modules_get(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
ULONG mod_cnt, mod_un_cnt;
|
||||
if (FAILED (ITHISCALL (dbgSymbols, GetNumberModules, &mod_cnt, &mod_un_cnt))) {
|
||||
return NULL;
|
||||
}
|
||||
if (!mod_cnt) {
|
||||
return NULL;
|
||||
}
|
||||
PDEBUG_MODULE_PARAMETERS params = R_NEWS (DEBUG_MODULE_PARAMETERS, mod_cnt);
|
||||
if (!params) {
|
||||
return NULL;
|
||||
}
|
||||
if (FAILED (ITHISCALL (dbgSymbols, GetModuleParameters, mod_cnt, 0, 0, params))) {
|
||||
return NULL;
|
||||
}
|
||||
RList *modules_list = r_list_newf ((RListFree)r_debug_map_free);
|
||||
if (!modules_list) {
|
||||
return NULL;
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < mod_cnt; i++) {
|
||||
char *mod_name = malloc (params[i].ModuleNameSize);
|
||||
char *image_name = malloc (params[i].ImageNameSize);
|
||||
if (!mod_name || !image_name) {
|
||||
free (mod_name);
|
||||
free (image_name);
|
||||
break;
|
||||
}
|
||||
if (FAILED (
|
||||
ITHISCALL (dbgSymbols, GetModuleNames,
|
||||
DEBUG_ANY_ID, params[i].Base,
|
||||
image_name, params[i].ImageNameSize, NULL,
|
||||
mod_name, params[i].ModuleNameSize, NULL,
|
||||
NULL, 0, NULL))) {
|
||||
free (mod_name);
|
||||
free (image_name);
|
||||
break;
|
||||
}
|
||||
RDebugMap *mod = r_debug_map_new (mod_name, params[i].Base, params[i].Base + params[i].Size, 0, params[i].Size);
|
||||
if (mod) {
|
||||
mod->file = strdup (image_name);
|
||||
r_list_append (modules_list, mod);
|
||||
}
|
||||
free (mod_name);
|
||||
free (image_name);
|
||||
}
|
||||
return modules_list;
|
||||
}
|
||||
|
||||
static RList *windbg_map_get(RDebug *dbg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, NULL);
|
||||
int perm;
|
||||
ULONG64 to = 0ULL;
|
||||
MEMORY_BASIC_INFORMATION64 mbi;
|
||||
RList *mod_list = windbg_modules_get (dbg);
|
||||
RList *map_list = r_list_newf ((RListFree)r_debug_map_free);
|
||||
const int mod_cnt = mod_list ? r_list_length (mod_list) : 0;
|
||||
PIMAGE_NT_HEADERS64 h = R_NEWS (IMAGE_NT_HEADERS64, mod_cnt);
|
||||
PIMAGE_SECTION_HEADER *s = R_NEWS0 (PIMAGE_SECTION_HEADER, mod_cnt);
|
||||
RListIter *it;
|
||||
RDebugMap *mod = NULL;
|
||||
size_t i = 0;
|
||||
r_list_foreach (mod_list, it, mod) {
|
||||
if (FAILED (ITHISCALL (dbgData, ReadImageNtHeaders, mod->addr, h + i))) {
|
||||
memset (h + i, 0, sizeof (IMAGE_NT_HEADERS64));
|
||||
} else {
|
||||
IMAGE_DOS_HEADER dos;
|
||||
ITHISCALL (dbgData, ReadVirtual, mod->addr, (PVOID)&dos, sizeof (IMAGE_DOS_HEADER), NULL);
|
||||
const size_t header_size = h[i].OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
|
||||
? sizeof (IMAGE_NT_HEADERS32)
|
||||
: sizeof (IMAGE_NT_HEADERS64);
|
||||
ULONG64 offset = mod->addr + dos.e_lfanew + header_size;
|
||||
const ULONG size = sizeof (IMAGE_SECTION_HEADER) * h[i].FileHeader.NumberOfSections;
|
||||
s[i] = malloc (size);
|
||||
ITHISCALL (dbgData, ReadVirtual, offset, (PVOID)s[i], size, NULL);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ULONG page_size = 1;
|
||||
ITHISCALL (dbgCtrl, GetPageSize, &page_size);
|
||||
ULONG p_mask = page_size - 1;
|
||||
while (SUCCEEDED (ITHISCALL (dbgData, QueryVirtual, to, &mbi))) {
|
||||
to = mbi.BaseAddress + mbi.RegionSize;
|
||||
perm = 0;
|
||||
perm |= mbi.Protect & PAGE_READONLY ? R_PERM_R : 0;
|
||||
perm |= mbi.Protect & PAGE_READWRITE ? R_PERM_RW : 0;
|
||||
perm |= mbi.Protect & PAGE_EXECUTE ? R_PERM_X : 0;
|
||||
perm |= mbi.Protect & PAGE_EXECUTE_READ ? R_PERM_RX : 0;
|
||||
perm |= mbi.Protect & PAGE_EXECUTE_READWRITE ? R_PERM_RWX : 0;
|
||||
perm = mbi.Protect & PAGE_NOACCESS ? 0 : perm;
|
||||
if (!perm) {
|
||||
continue;
|
||||
}
|
||||
char *name = "";
|
||||
if (mbi.Type == MEM_IMAGE) {
|
||||
i = 0;
|
||||
r_list_foreach (mod_list, it, mod) {
|
||||
if (mbi.BaseAddress >= mod->addr && mbi.BaseAddress < mod->addr + mod->size) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i < mod_cnt && mod) {
|
||||
size_t j;
|
||||
for (j = 0; j < h[i].FileHeader.NumberOfSections; j++) {
|
||||
ut64 sect_vaddr = mod->addr + s[i][j].VirtualAddress;
|
||||
ut64 sect_vsize = (((ut64)s[i][j].Misc.VirtualSize) + p_mask) & ~p_mask;
|
||||
if (mbi.BaseAddress >= sect_vaddr && mbi.BaseAddress < sect_vaddr + sect_vsize) {
|
||||
name = sdb_fmt ("%s | %.8s", mod->name, s[i][j].Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*name) {
|
||||
name = mod->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
RDebugMap *map = r_debug_map_new (name, mbi.BaseAddress, to, perm, 0);
|
||||
r_list_append (map_list, map);
|
||||
}
|
||||
for (i = 0; i < mod_cnt; i++) {
|
||||
free (s[i]);
|
||||
}
|
||||
free (s);
|
||||
free (h);
|
||||
r_list_free (mod_list);
|
||||
return map_list;
|
||||
}
|
||||
|
||||
static int windbg_attach(RDebug *dbg, int pid) {
|
||||
ULONG Id = 0;
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, -1);
|
||||
if (SUCCEEDED (ITHISCALL (dbgSysObj, GetCurrentProcessSystemId, &Id))) {
|
||||
if (Id == pid && SUCCEEDED (ITHISCALL (dbgSysObj, GetCurrentThreadSystemId, &Id))) {
|
||||
return Id;
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED (ITHISCALL (dbgClient, AttachProcess, idbg->server, pid, DEBUG_ATTACH_DEFAULT))) {
|
||||
return windbg_wait (dbg, pid);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int windbg_detach(RDebug *dbg, int pid) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, 0);
|
||||
return SUCCEEDED (ITHISCALL (dbgClient, DetachProcesses));
|
||||
}
|
||||
|
||||
static bool windbg_kill(RDebug *dbg, int pid, int tid, int sig) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, false);
|
||||
if (!sig) {
|
||||
ULONG exit_code, class, qualifier;
|
||||
if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &class, &qualifier))) {
|
||||
if (class == DEBUG_CLASS_UNINITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
if (qualifier >= DEBUG_DUMP_SMALL && qualifier <= DEBUG_DUMP_ACTIVE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (FAILED (ITHISCALL (dbgClient, GetExitCode, &exit_code))) {
|
||||
return false;
|
||||
}
|
||||
return exit_code == STILL_ACTIVE;
|
||||
}
|
||||
HRESULT hr = ITHISCALL (dbgClient, TerminateProcesses);
|
||||
return SUCCEEDED (hr);
|
||||
}
|
||||
|
||||
static RList *windbg_threads(RDebug *dbg, int pid) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, NULL);
|
||||
ULONG thread_cnt = 0;
|
||||
ITHISCALL (dbgSysObj, GetNumberThreads, &thread_cnt);
|
||||
if (!thread_cnt) {
|
||||
return NULL;
|
||||
}
|
||||
PULONG threads_ids = R_NEWS (ULONG, thread_cnt);
|
||||
PULONG threads_sysids = R_NEWS (ULONG, thread_cnt);
|
||||
RList *list = r_list_newf ((RListFree)r_debug_pid_free);
|
||||
if (!list || !threads_ids || !threads_sysids) {
|
||||
free (list);
|
||||
free (threads_ids);
|
||||
free (threads_sysids);
|
||||
return NULL;
|
||||
}
|
||||
ITHISCALL (dbgSysObj, GetThreadIdsByIndex, 0, thread_cnt, threads_ids, threads_sysids);
|
||||
size_t i;
|
||||
for (i = 0; i < thread_cnt; i++) {
|
||||
ULONG64 pc;
|
||||
ITHISCALL (dbgSysObj, SetCurrentThreadId, threads_ids[i]);
|
||||
ITHISCALL (dbgReg, GetInstructionOffset, &pc);
|
||||
r_list_append (list, r_debug_pid_new (NULL, threads_sysids[i], 0, 's', pc));
|
||||
}
|
||||
windbg_select (dbg, dbg->pid, dbg->tid);
|
||||
free (threads_ids);
|
||||
free (threads_sysids);
|
||||
return list;
|
||||
}
|
||||
|
||||
static RDebugInfo *windbg_info(RDebug *dbg, const char *arg) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, NULL);
|
||||
char exeinfo[MAX_PATH];
|
||||
char cmdline[MAX_PATH];
|
||||
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))) {
|
||||
RDebugInfo *info = R_NEW0 (RDebugInfo);
|
||||
if (!info) {
|
||||
return NULL;
|
||||
}
|
||||
info->pid = dbg->pid;
|
||||
info->tid = dbg->tid;
|
||||
info->exe = strdup (exeinfo);
|
||||
info->cmdline = strdup (cmdline);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool windbg_gcore(RDebug *dbg, RBuffer *dest) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, false);
|
||||
char *path = r_sys_getenv (R_SYS_TMP);
|
||||
if (R_STR_ISEMPTY (path)) {
|
||||
free (path);
|
||||
path = r_sys_getdir ();
|
||||
if (R_STR_ISEMPTY (path)) {
|
||||
free (path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
path = r_str_appendf (path, "\\core.%d", dbg->pid);
|
||||
ITHISCALL (dbgClient, WriteDumpFile, path, DEBUG_DUMP_DEFAULT);
|
||||
free (path);
|
||||
return true;
|
||||
}
|
||||
|
||||
static RList *r_debug_windbg_pids(RDebug *dbg, int pid) {
|
||||
RListIter *it;
|
||||
WindProc *p;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *pids = windbg_list_process(wctx);
|
||||
if (!pids) {
|
||||
return ret;
|
||||
}
|
||||
r_list_foreach (pids, it, p) {
|
||||
RDebugPid *newpid = R_NEW0 (RDebugPid);
|
||||
if (!newpid) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
RList *windbg_pids(RDebug *dbg, int pid) {
|
||||
DbgEngContext *idbg = dbg->user;
|
||||
r_return_val_if_fail (idbg && idbg->initialized, NULL);
|
||||
RList *list = r_list_newf ((RListFree)r_debug_pid_free);
|
||||
ULONG ids[1000];
|
||||
ULONG ids_cnt;
|
||||
if (SUCCEEDED (ITHISCALL (dbgClient, GetRunningProcessSystemIds,
|
||||
idbg->server, ids, _countof (ids), &ids_cnt))) {
|
||||
size_t i;
|
||||
for (i = 0; i < ids_cnt; i++) {
|
||||
char path[MAX_PATH];
|
||||
if (SUCCEEDED (ITHISCALL (dbgClient, GetRunningProcessDescription,
|
||||
idbg->server, ids[i], DEBUG_PROC_DESC_DEFAULT,
|
||||
path, sizeof (path), NULL, NULL, 0, NULL))) {
|
||||
RDebugPid *pid = r_debug_pid_new (path, ids[i], 0, 'r', 0);
|
||||
r_list_append (list, pid);
|
||||
}
|
||||
}
|
||||
newpid->path = strdup (p->name);
|
||||
newpid->pid = p->uniqueid;
|
||||
newpid->status = 's';
|
||||
newpid->runnable = true;
|
||||
r_list_append (ret, newpid);
|
||||
}
|
||||
// r_list_free (pids);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int r_debug_windbg_select(RDebug *dbg, int pid, int tid) {
|
||||
ut32 old = windbg_get_target (wctx);
|
||||
int ret = windbg_set_target (wctx, pid);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
ut64 base = windbg_get_target_base (wctx);
|
||||
if (!base) {
|
||||
windbg_set_target (wctx, old);
|
||||
return false;
|
||||
}
|
||||
eprintf ("Process base is 0x%"PFMT64x"\n", base);
|
||||
return true;
|
||||
}
|
||||
|
||||
static RList *r_debug_windbg_threads(RDebug *dbg, int pid) {
|
||||
RListIter *it;
|
||||
WindThread *t;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *threads = windbg_list_threads (wctx);
|
||||
if (!threads) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_list_foreach (threads, it, t) {
|
||||
RDebugPid *newpid = R_NEW0 (RDebugPid);
|
||||
if (!newpid) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
newpid->pid = t->uniqueid;
|
||||
newpid->status = t->status;
|
||||
newpid->runnable = t->runnable;
|
||||
r_list_append (ret, newpid);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RList *r_debug_windbg_modules(RDebug *dbg) {
|
||||
RListIter *it;
|
||||
WindModule *m;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *modules = windbg_list_modules (wctx);
|
||||
if (!modules) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_list_foreach (modules, it, m) {
|
||||
RDebugMap *mod = R_NEW0 (RDebugMap);
|
||||
if (!mod) {
|
||||
r_list_free (modules);
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
mod->file = m->name;
|
||||
mod->size = m->size;
|
||||
mod->addr = m->addr;
|
||||
mod->addr_end = m->addr + m->size;
|
||||
r_list_append (ret, mod);
|
||||
}
|
||||
|
||||
r_list_free (modules);
|
||||
return ret;
|
||||
return list;
|
||||
}
|
||||
|
||||
RDebugPlugin r_debug_plugin_windbg = {
|
||||
.name = "windbg",
|
||||
.license = "LGPL3",
|
||||
.arch = "x86",
|
||||
.bits = R_SYS_BITS_32 | R_SYS_BITS_64,
|
||||
.init = &r_debug_windbg_init,
|
||||
.step = &r_debug_windbg_step,
|
||||
.cont = &r_debug_windbg_continue,
|
||||
.attach = &r_debug_windbg_attach,
|
||||
.detach = &r_debug_windbg_detach,
|
||||
.pids = &r_debug_windbg_pids,
|
||||
.wait = &r_debug_windbg_wait,
|
||||
.select = &r_debug_windbg_select,
|
||||
.breakpoint = r_debug_windbg_breakpoint,
|
||||
.reg_read = &r_debug_windbg_reg_read,
|
||||
.reg_write = &r_debug_windbg_reg_write,
|
||||
.reg_profile = &r_debug_windbg_reg_profile,
|
||||
.threads = &r_debug_windbg_threads,
|
||||
.modules_get = &r_debug_windbg_modules
|
||||
.bits = R_SYS_BITS_64,
|
||||
.arch = "x86,x64,arm,arm64",
|
||||
.canstep = 1,
|
||||
.init = windbg_init,
|
||||
.attach = windbg_attach,
|
||||
.detach = windbg_detach,
|
||||
.breakpoint = windbg_breakpoint,
|
||||
.frames = windbg_frames,
|
||||
.kill = windbg_kill,
|
||||
.select = windbg_select,
|
||||
.step = windbg_step,
|
||||
.step_over = windbg_step_over,
|
||||
.threads = windbg_threads,
|
||||
.cont = windbg_continue,
|
||||
.wait = windbg_wait,
|
||||
.stop = windbg_stop,
|
||||
.reg_read = windbg_reg_read,
|
||||
.reg_write = windbg_reg_write,
|
||||
.reg_profile = windbg_reg_profile,
|
||||
.map_get = windbg_map_get,
|
||||
.modules_get = windbg_modules_get,
|
||||
.info = windbg_info,
|
||||
.gcore = windbg_gcore,
|
||||
.pids = windbg_pids
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
@ -292,4 +631,4 @@ R_API RLibStruct radare_plugin = {
|
||||
.data = &r_debug_plugin_windbg,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
||||
#endif // R2_PLUGIN_INCORE
|
||||
|
295
libr/debug/p/debug_winkd.c
Normal file
295
libr/debug/p/debug_winkd.c
Normal file
@ -0,0 +1,295 @@
|
||||
// Copyright (c) 2014-2017, The Lemon Man, All rights reserved. LGPLv3
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
#include <r_asm.h>
|
||||
#include <r_debug.h>
|
||||
#include <winkd.h>
|
||||
#include <kd.h>
|
||||
|
||||
static WindCtx *wctx = NULL;
|
||||
|
||||
static int r_debug_winkd_step(RDebug *dbg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_reg_read(RDebug *dbg, int type, ut8 *buf, int size) {
|
||||
int ret = winkd_read_reg(wctx, buf, size);
|
||||
if (!ret || size != ret) {
|
||||
return -1;
|
||||
}
|
||||
r_reg_read_regs (dbg->reg, buf, ret);
|
||||
// Report as if no register has been written as we've already updated the arena here
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_reg_write(RDebug *dbg, int type, const ut8 *buf, int size) {
|
||||
if (!dbg->reg) {
|
||||
return false;
|
||||
}
|
||||
int arena_size;
|
||||
ut8 *arena = r_reg_get_bytes (dbg->reg, R_REG_TYPE_ALL, &arena_size);
|
||||
if (!arena) {
|
||||
eprintf ("Could not retrieve the register arena!\n");
|
||||
return false;
|
||||
}
|
||||
int ret = winkd_write_reg (wctx, arena, arena_size);
|
||||
free (arena);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_continue(RDebug *dbg, int pid, int tid, int sig) {
|
||||
return winkd_continue(wctx);
|
||||
}
|
||||
|
||||
static RDebugReasonType r_debug_winkd_wait(RDebug *dbg, int pid) {
|
||||
RDebugReasonType reason = R_DEBUG_REASON_UNKNOWN;
|
||||
kd_packet_t *pkt = NULL;
|
||||
kd_stc_64 *stc;
|
||||
winkd_lock_enter (wctx);
|
||||
for (;;) {
|
||||
void *bed = r_cons_sleep_begin ();
|
||||
int ret = winkd_wait_packet (wctx, KD_PACKET_TYPE_STATE_CHANGE64, &pkt);
|
||||
r_cons_sleep_end (bed);
|
||||
if (ret != KD_E_OK || !pkt) {
|
||||
reason = R_DEBUG_REASON_ERROR;
|
||||
break;
|
||||
}
|
||||
stc = (kd_stc_64 *) pkt->data;
|
||||
dbg->reason.addr = stc->pc;
|
||||
dbg->reason.tid = stc->kthread;
|
||||
dbg->reason.signum = stc->state;
|
||||
winkd_set_cpu (wctx, stc->cpu);
|
||||
if (stc->state == DbgKdExceptionStateChange) {
|
||||
dbg->reason.type = R_DEBUG_REASON_INT;
|
||||
reason = R_DEBUG_REASON_INT;
|
||||
break;
|
||||
} else if (stc->state == DbgKdLoadSymbolsStateChange) {
|
||||
dbg->reason.type = R_DEBUG_REASON_NEW_LIB;
|
||||
reason = R_DEBUG_REASON_NEW_LIB;
|
||||
break;
|
||||
}
|
||||
R_FREE (pkt);
|
||||
}
|
||||
winkd_lock_leave (wctx);
|
||||
free (pkt);
|
||||
return reason;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_attach(RDebug *dbg, int pid) {
|
||||
RIODesc *desc = dbg->iob.io->desc;
|
||||
|
||||
if (!desc || !desc->plugin || !desc->plugin->name || !desc->data) {
|
||||
return false;
|
||||
}
|
||||
if (strncmp (desc->plugin->name, "winkd", 6)) {
|
||||
return false;
|
||||
}
|
||||
if (dbg->arch && strcmp (dbg->arch, "x86")) {
|
||||
return false;
|
||||
}
|
||||
wctx = (WindCtx *)desc->data;
|
||||
|
||||
// Handshake
|
||||
if (!winkd_sync (wctx)) {
|
||||
eprintf ("Could not connect to winkd\n");
|
||||
winkd_ctx_free ((WindCtx **)&desc->data);
|
||||
return false;
|
||||
}
|
||||
if (!winkd_read_ver (wctx)) {
|
||||
winkd_ctx_free ((WindCtx **)&desc->data);
|
||||
return false;
|
||||
}
|
||||
dbg->bits = winkd_get_bits (wctx);
|
||||
// Make r_debug_is_dead happy
|
||||
dbg->pid = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_detach(RDebug *dbg, int pid) {
|
||||
eprintf ("Detaching...\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *r_debug_winkd_reg_profile(RDebug *dbg) {
|
||||
if (!dbg) {
|
||||
return NULL;
|
||||
}
|
||||
if (dbg->arch && strcmp (dbg->arch, "x86")) {
|
||||
return NULL;
|
||||
}
|
||||
r_debug_winkd_attach (dbg, 0);
|
||||
if (dbg->bits == R_SYS_BITS_32) {
|
||||
#include "native/reg/windows-x86.h"
|
||||
} else if (dbg->bits == R_SYS_BITS_64) {
|
||||
#include "native/reg/windows-x64.h"
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_breakpoint(RBreakpoint *bp, RBreakpointItem *b, bool set) {
|
||||
int *tag;
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
// Use a 32 bit word here to keep this compatible with 32 bit hosts
|
||||
if (!b->data) {
|
||||
b->data = (char *)R_NEW0 (int);
|
||||
if (!b->data) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
tag = (int *)b->data;
|
||||
return winkd_bkpt (wctx, b->addr, set, b->hw, tag);
|
||||
}
|
||||
|
||||
static int r_debug_winkd_init(RDebug *dbg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static RList *r_debug_winkd_pids(RDebug *dbg, int pid) {
|
||||
RListIter *it;
|
||||
WindProc *p;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *pids = winkd_list_process(wctx);
|
||||
if (!pids) {
|
||||
return ret;
|
||||
}
|
||||
r_list_foreach (pids, it, p) {
|
||||
RDebugPid *newpid = R_NEW0 (RDebugPid);
|
||||
if (!newpid) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
newpid->path = strdup (p->name);
|
||||
newpid->pid = p->uniqueid;
|
||||
newpid->status = 's';
|
||||
newpid->runnable = true;
|
||||
r_list_append (ret, newpid);
|
||||
}
|
||||
// r_list_free (pids);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int r_debug_winkd_select(RDebug *dbg, int pid, int tid) {
|
||||
ut32 old = winkd_get_target (wctx);
|
||||
int ret = winkd_set_target (wctx, pid);
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
ut64 base = winkd_get_target_base (wctx);
|
||||
if (!base) {
|
||||
winkd_set_target (wctx, old);
|
||||
return false;
|
||||
}
|
||||
eprintf ("Process base is 0x%"PFMT64x"\n", base);
|
||||
return true;
|
||||
}
|
||||
|
||||
static RList *r_debug_winkd_threads(RDebug *dbg, int pid) {
|
||||
RListIter *it;
|
||||
WindThread *t;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *threads = winkd_list_threads (wctx);
|
||||
if (!threads) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_list_foreach (threads, it, t) {
|
||||
RDebugPid *newpid = R_NEW0 (RDebugPid);
|
||||
if (!newpid) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
newpid->pid = t->uniqueid;
|
||||
newpid->status = t->status;
|
||||
newpid->runnable = t->runnable;
|
||||
r_list_append (ret, newpid);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RList *r_debug_winkd_modules(RDebug *dbg) {
|
||||
RListIter *it;
|
||||
WindModule *m;
|
||||
|
||||
RList *ret = r_list_newf (free);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RList *modules = winkd_list_modules (wctx);
|
||||
if (!modules) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r_list_foreach (modules, it, m) {
|
||||
RDebugMap *mod = R_NEW0 (RDebugMap);
|
||||
if (!mod) {
|
||||
r_list_free (modules);
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
mod->file = m->name;
|
||||
mod->size = m->size;
|
||||
mod->addr = m->addr;
|
||||
mod->addr_end = m->addr + m->size;
|
||||
r_list_append (ret, mod);
|
||||
}
|
||||
|
||||
r_list_free (modules);
|
||||
return ret;
|
||||
}
|
||||
|
||||
RDebugPlugin r_debug_plugin_winkd = {
|
||||
.name = "winkd",
|
||||
.license = "LGPL3",
|
||||
.arch = "x86",
|
||||
.bits = R_SYS_BITS_32 | R_SYS_BITS_64,
|
||||
.init = &r_debug_winkd_init,
|
||||
.step = &r_debug_winkd_step,
|
||||
.cont = &r_debug_winkd_continue,
|
||||
.attach = &r_debug_winkd_attach,
|
||||
.detach = &r_debug_winkd_detach,
|
||||
.pids = &r_debug_winkd_pids,
|
||||
.wait = &r_debug_winkd_wait,
|
||||
.select = &r_debug_winkd_select,
|
||||
.breakpoint = r_debug_winkd_breakpoint,
|
||||
.reg_read = &r_debug_winkd_reg_read,
|
||||
.reg_write = &r_debug_winkd_reg_write,
|
||||
.reg_profile = &r_debug_winkd_reg_profile,
|
||||
.threads = &r_debug_winkd_threads,
|
||||
.modules_get = &r_debug_winkd_modules
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
R_API RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_DBG,
|
||||
.data = &r_debug_plugin_winkd,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
@ -201,7 +201,7 @@ static void proc_mem_img(HANDLE h_proc, RList *map_list, RList *mod_list, RWinMo
|
||||
sect_found = 2;
|
||||
}
|
||||
if (sect_found) {
|
||||
char *map_name = r_str_newf ("%s | %s", mod->map->name, sect_hdr->Name);
|
||||
char *map_name = r_str_newf ("%s | %.8s", mod->map->name, sect_hdr->Name);
|
||||
if (!map_name) {
|
||||
perror ("r_str_newf");
|
||||
return;
|
||||
|
71
libr/debug/p/native/reg/windows-arm.h
Normal file
71
libr/debug/p/native/reg/windows-arm.h
Normal file
@ -0,0 +1,71 @@
|
||||
return strdup (
|
||||
"=PC pc\n"
|
||||
"=SP sp\n"
|
||||
"=BP fp\n"
|
||||
"=A0 r0\n"
|
||||
"=A1 r1\n"
|
||||
"=A2 r2\n"
|
||||
"=A3 r3\n"
|
||||
"=ZF zf\n"
|
||||
"=SF nf\n"
|
||||
"=OF vf\n"
|
||||
"=CF cf\n"
|
||||
"gpr r0 .32 4 0\n"
|
||||
"gpr r1 .32 8 0\n"
|
||||
"gpr r2 .32 12 0\n"
|
||||
"gpr r3 .32 16 0\n"
|
||||
"gpr r4 .32 20 0\n"
|
||||
"gpr r5 .32 24 0\n"
|
||||
"gpr r6 .32 28 0\n"
|
||||
"gpr r7 .32 32 0\n"
|
||||
"gpr r8 .32 36 0\n"
|
||||
"gpr r9 .32 40 0\n"
|
||||
"gpr r10 .32 44 0\n"
|
||||
"gpr r11 .32 48 0\n"
|
||||
"gpr r12 .32 52 0\n"
|
||||
"gpr sp .32 56 0\n"
|
||||
"gpr lr .32 60 0\n"
|
||||
"gpr pc .32 64 0\n"
|
||||
"flg cpsr .32 68 0 _____tfiae_____________j__qvczn\n"
|
||||
"flg vf .1 68.28 0 overflow\n"
|
||||
"flg cf .1 68.29 0 carry\n"
|
||||
"flg zf .1 68.30 0 zero\n"
|
||||
"flg nf .1 68.31 0 sign\n"
|
||||
"gpr fpsr .32 72 0\n"
|
||||
"fpu q0 .128 76 0\n"
|
||||
"fpu q1 .128 92 0\n"
|
||||
"fpu q2 .128 108 0\n"
|
||||
"fpu q3 .128 124 0\n"
|
||||
"fpu q4 .128 140 0\n"
|
||||
"fpu q5 .128 156 0\n"
|
||||
"fpu q6 .128 172 0\n"
|
||||
"fpu q7 .128 188 0\n"
|
||||
"fpu q8 .128 204 0\n"
|
||||
"fpu q9 .128 220 0\n"
|
||||
"fpu q10 .128 236 0\n"
|
||||
"fpu q11 .128 252 0\n"
|
||||
"fpu q12 .128 268 0\n"
|
||||
"fpu q13 .128 284 0\n"
|
||||
"fpu q14 .128 300 0\n"
|
||||
"fpu q15 .128 316 0\n"
|
||||
"drx bcr0 .32 332 0\n"
|
||||
"drx bcr1 .32 336 0\n"
|
||||
"drx bcr2 .32 340 0\n"
|
||||
"drx bcr3 .32 344 0\n"
|
||||
"drx bcr4 .32 348 0\n"
|
||||
"drx bcr5 .32 352 0\n"
|
||||
"drx bcr6 .32 356 0\n"
|
||||
"drx bcr7 .32 360 0\n"
|
||||
"drx bvr0 .32 364 0\n"
|
||||
"drx bvr1 .32 368 0\n"
|
||||
"drx bvr2 .32 372 0\n"
|
||||
"drx bvr3 .32 376 0\n"
|
||||
"drx bvr4 .32 380 0\n"
|
||||
"drx bvr5 .32 384 0\n"
|
||||
"drx bvr6 .32 388 0\n"
|
||||
"drx bvr7 .32 392 0\n"
|
||||
"drx wcr0 .32 396 0\n"
|
||||
"drx wcr1 .32 400 0\n"
|
||||
"drx wvr0 .32 404 0\n"
|
||||
"drx wvr1 .32 408 0\n"
|
||||
);
|
106
libr/debug/p/native/reg/windows-arm64.h
Normal file
106
libr/debug/p/native/reg/windows-arm64.h
Normal file
@ -0,0 +1,106 @@
|
||||
return strdup (
|
||||
"=PC pc\n"
|
||||
"=SP sp\n"
|
||||
"=BP fp\n"
|
||||
"=A0 x0\n"
|
||||
"=A1 x1\n"
|
||||
"=A2 x2\n"
|
||||
"=A3 x3\n"
|
||||
"=ZF zf\n"
|
||||
"=SF nf\n"
|
||||
"=OF vf\n"
|
||||
"=CF cf\n"
|
||||
"=SN x16\n"
|
||||
"flg cpsr .32 4 0 _____tfiae_____________j__qvczn\n"
|
||||
"flg vf .1 4.28 0 overflow\n"
|
||||
"flg cf .1 4.29 0 carry\n"
|
||||
"flg zf .1 4.30 0 zero\n"
|
||||
"flg nf .1 4.31 0 sign\n"
|
||||
"gpr x0 .64 8 0\n"
|
||||
"gpr x1 .64 16 0\n"
|
||||
"gpr x2 .64 24 0\n"
|
||||
"gpr x3 .64 32 0\n"
|
||||
"gpr x4 .64 40 0\n"
|
||||
"gpr x5 .64 48 0\n"
|
||||
"gpr x6 .64 56 0\n"
|
||||
"gpr x7 .64 64 0\n"
|
||||
"gpr x8 .64 72 0\n"
|
||||
"gpr x9 .64 80 0\n"
|
||||
"gpr x10 .64 88 0\n"
|
||||
"gpr x11 .64 96 0\n"
|
||||
"gpr x12 .64 104 0\n"
|
||||
"gpr x13 .64 112 0\n"
|
||||
"gpr x14 .64 120 0\n"
|
||||
"gpr x15 .64 128 0\n"
|
||||
"gpr x16 .64 136 0\n"
|
||||
"gpr x17 .64 144 0\n"
|
||||
"gpr x18 .64 152 0\n"
|
||||
"gpr x19 .64 160 0\n"
|
||||
"gpr x20 .64 168 0\n"
|
||||
"gpr x21 .64 176 0\n"
|
||||
"gpr x22 .64 184 0\n"
|
||||
"gpr x23 .64 192 0\n"
|
||||
"gpr x24 .64 200 0\n"
|
||||
"gpr x25 .64 208 0\n"
|
||||
"gpr x26 .64 216 0\n"
|
||||
"gpr x27 .64 224 0\n"
|
||||
"gpr x28 .64 232 0\n"
|
||||
"gpr fp .64 240 0\n"
|
||||
"gpr lr .64 248 0\n"
|
||||
"gpr sp .64 256 0\n"
|
||||
"gpr pc .64 264 0\n"
|
||||
"fpu v0 .128 272 0\n"
|
||||
"fpu v1 .128 288 0\n"
|
||||
"fpu v2 .128 304 0\n"
|
||||
"fpu v3 .128 320 0\n"
|
||||
"fpu v4 .128 336 0\n"
|
||||
"fpu v5 .128 352 0\n"
|
||||
"fpu v6 .128 368 0\n"
|
||||
"fpu v7 .128 384 0\n"
|
||||
"fpu v8 .128 400 0\n"
|
||||
"fpu v9 .128 416 0\n"
|
||||
"fpu v10 .128 432 0\n"
|
||||
"fpu v11 .128 448 0\n"
|
||||
"fpu v12 .128 464 0\n"
|
||||
"fpu v13 .128 480 0\n"
|
||||
"fpu v14 .128 496 0\n"
|
||||
"fpu v15 .128 512 0\n"
|
||||
"fpu v16 .128 528 0\n"
|
||||
"fpu v17 .128 544 0\n"
|
||||
"fpu v18 .128 560 0\n"
|
||||
"fpu v19 .128 576 0\n"
|
||||
"fpu v20 .128 592 0\n"
|
||||
"fpu v21 .128 608 0\n"
|
||||
"fpu v22 .128 624 0\n"
|
||||
"fpu v23 .128 640 0\n"
|
||||
"fpu v24 .128 656 0\n"
|
||||
"fpu v25 .128 672 0\n"
|
||||
"fpu v26 .128 688 0\n"
|
||||
"fpu v27 .128 704 0\n"
|
||||
"fpu v28 .128 720 0\n"
|
||||
"fpu v29 .128 736 0\n"
|
||||
"fpu v30 .128 752 0\n"
|
||||
"fpu v31 .128 768 0\n"
|
||||
"gpr fpcr .32 784 0\n"
|
||||
"gpr fpsr .32 788 0\n"
|
||||
"drx bcr0 .32 792 0\n"
|
||||
"drx bcr1 .32 796 0\n"
|
||||
"drx bcr2 .32 800 0\n"
|
||||
"drx bcr3 .32 804 0\n"
|
||||
"drx bcr4 .32 808 0\n"
|
||||
"drx bcr5 .32 812 0\n"
|
||||
"drx bcr6 .32 816 0\n"
|
||||
"drx bcr7 .32 820 0\n"
|
||||
"drx bvr0 .64 824 0\n"
|
||||
"drx bvr1 .64 832 0\n"
|
||||
"drx bvr2 .64 840 0\n"
|
||||
"drx bvr3 .64 848 0\n"
|
||||
"drx bvr4 .64 856 0\n"
|
||||
"drx bvr5 .64 864 0\n"
|
||||
"drx bvr6 .64 872 0\n"
|
||||
"drx bvr7 .64 880 0\n"
|
||||
"drx wcr0 .32 888 0\n"
|
||||
"drx wcr1 .32 892 0\n"
|
||||
"drx wvr0 .64 896 0\n"
|
||||
"drx wvr1 .64 904 0\n"
|
||||
);
|
@ -37,14 +37,10 @@ int w32_init(RDebug *dbg) {
|
||||
W32DbgWInst *wrap = dbg->user;
|
||||
if (!wrap) {
|
||||
if (dbg->iob.io->w32dbg_wrap) {
|
||||
wrap = (W32DbgWInst *)dbg->iob.io->w32dbg_wrap;
|
||||
dbg->user = (W32DbgWInst *)dbg->iob.io->w32dbg_wrap;
|
||||
} else {
|
||||
wrap = w32dbg_wrap_new ();
|
||||
dbg->iob.io->w32dbg_wrap = (struct w32dbg_wrap_instance_t *)wrap;
|
||||
wrap->pi.dwProcessId = dbg->pid;
|
||||
wrap->pi.dwThreadId = dbg->tid;
|
||||
return 0;
|
||||
}
|
||||
dbg->user = wrap;
|
||||
}
|
||||
// escalate privs (required for win7/vista)
|
||||
setup_debug_privileges (true);
|
||||
|
@ -1,24 +0,0 @@
|
||||
CFLAGS+=-I$(SHLR)/windbg/
|
||||
LIB_PATH=$(SHLR)/windbg/
|
||||
|
||||
-include ../../global.mk
|
||||
-include ../../../global.mk
|
||||
LDFLAGS+=-L$(LTOP)/util -lr_util
|
||||
LDFLAGS+=-L$(LTOP)/cons -lr_cons
|
||||
LDFLAGS+=-L$(LTOP)/parse -lr_parse
|
||||
LDFLAGS+=-L$(LTOP)/anal -lr_anal
|
||||
LDFLAGS+=-L$(LTOP)/reg -lr_reg
|
||||
LDFLAGS+=-L$(LTOP)/bp -lr_bp
|
||||
LDFLAGS+=-L$(LTOP)/io -lr_io
|
||||
|
||||
include $(STOP)/windbg/deps.mk
|
||||
|
||||
OBJ_WINDBG=debug_windbg.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_WINDBG}
|
||||
TARGET_WINDBG=debug_windbg.${EXT_SO}
|
||||
|
||||
ALL_TARGETS+=${TARGET_WINDBG}
|
||||
|
||||
${TARGET_WINDBG}: ${OBJ_WINDBG}
|
||||
${CC} $(call libname,debug_windbg) ${OBJ_WINDBG} ${CFLAGS} ${LDFLAGS}
|
24
libr/debug/p/winkd.mk
Normal file
24
libr/debug/p/winkd.mk
Normal file
@ -0,0 +1,24 @@
|
||||
CFLAGS+=-I$(SHLR)/winkd/
|
||||
LIB_PATH=$(SHLR)/winkd/
|
||||
|
||||
-include ../../global.mk
|
||||
-include ../../../global.mk
|
||||
LDFLAGS+=-L$(LTOP)/util -lr_util
|
||||
LDFLAGS+=-L$(LTOP)/cons -lr_cons
|
||||
LDFLAGS+=-L$(LTOP)/parse -lr_parse
|
||||
LDFLAGS+=-L$(LTOP)/anal -lr_anal
|
||||
LDFLAGS+=-L$(LTOP)/reg -lr_reg
|
||||
LDFLAGS+=-L$(LTOP)/bp -lr_bp
|
||||
LDFLAGS+=-L$(LTOP)/io -lr_io
|
||||
|
||||
include $(STOP)/winkd/deps.mk
|
||||
|
||||
OBJ_WINKD=debug_winkd.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_WINKD}
|
||||
TARGET_WINKD=debug_winkd.${EXT_SO}
|
||||
|
||||
ALL_TARGETS+=${TARGET_WINKD}
|
||||
|
||||
${TARGET_WINKD}: ${OBJ_WINKD}
|
||||
${CC} $(call libname,debug_winkd) ${OBJ_WINKD} ${CFLAGS} ${LDFLAGS}
|
@ -621,6 +621,7 @@ extern RDebugPlugin r_debug_plugin_rap;
|
||||
extern RDebugPlugin r_debug_plugin_gdb;
|
||||
extern RDebugPlugin r_debug_plugin_bf;
|
||||
extern RDebugPlugin r_debug_plugin_io;
|
||||
extern RDebugPlugin r_debug_plugin_winkd;
|
||||
extern RDebugPlugin r_debug_plugin_windbg;
|
||||
extern RDebugPlugin r_debug_plugin_bochs;
|
||||
extern RDebugPlugin r_debug_plugin_qnx;
|
||||
|
@ -478,6 +478,7 @@ extern RIOPlugin r_io_plugin_malloc;
|
||||
extern RIOPlugin r_io_plugin_sparse;
|
||||
extern RIOPlugin r_io_plugin_ptrace;
|
||||
extern RIOPlugin r_io_plugin_w32dbg;
|
||||
extern RIOPlugin r_io_plugin_windbg;
|
||||
extern RIOPlugin r_io_plugin_mach;
|
||||
extern RIOPlugin r_io_plugin_debug;
|
||||
extern RIOPlugin r_io_plugin_shm;
|
||||
@ -492,7 +493,7 @@ extern RIOPlugin r_io_plugin_default;
|
||||
extern RIOPlugin r_io_plugin_ihex;
|
||||
extern RIOPlugin r_io_plugin_self;
|
||||
extern RIOPlugin r_io_plugin_gzip;
|
||||
extern RIOPlugin r_io_plugin_windbg;
|
||||
extern RIOPlugin r_io_plugin_winkd;
|
||||
extern RIOPlugin r_io_plugin_r2pipe;
|
||||
extern RIOPlugin r_io_plugin_r2web;
|
||||
extern RIOPlugin r_io_plugin_qnx;
|
||||
|
@ -35,7 +35,7 @@ r_io_sources = [
|
||||
'p/io_shm.c',
|
||||
'p/io_sparse.c',
|
||||
'p/io_tcp.c',
|
||||
'p/io_windbg.c',
|
||||
'p/io_winkd.c',
|
||||
'p/io_winedbg.c',
|
||||
'p/io_zip.c',
|
||||
]
|
||||
@ -43,6 +43,7 @@ r_io_sources = [
|
||||
if host_machine.system() == 'windows'
|
||||
r_io_sources += [
|
||||
'p/io_r2k_windows.c',
|
||||
'p/io_windbg.c',
|
||||
'p/io_w32.c',
|
||||
'p/io_w32dbg.c',
|
||||
]
|
||||
@ -54,7 +55,7 @@ r_io_deps = [
|
||||
r_socket_dep,
|
||||
bochs_dep,
|
||||
gdb_dep,
|
||||
windbg_dep,
|
||||
winkd_dep,
|
||||
qnx_dep,
|
||||
zip_dep,
|
||||
ar_dep,
|
||||
|
@ -15,7 +15,7 @@ endif
|
||||
all: ${ALL_TARGETS}
|
||||
|
||||
ALL_TARGETS=
|
||||
PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk shm.mk mach.mk w32dbg.mk procpid.mk windbg.mk bochs.mk qnx.mk r2k.mk ar.mk rbuf.mk gprobe.mk
|
||||
PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk shm.mk mach.mk w32dbg.mk procpid.mk winkd.mk bochs.mk qnx.mk r2k.mk ar.mk rbuf.mk gprobe.mk
|
||||
#zip.mk
|
||||
#PLUGINS=ptrace.mk debug.mk gdb.mk malloc.mk mach.mk w32dbg.mk procpid.mk
|
||||
include ${PLUGINS}
|
||||
|
@ -1,106 +1,687 @@
|
||||
// Copyright (c) 2014-2017, The Lemon Man, All rights reserved. LGPLv3
|
||||
/* radare - LGPL - Copyright 2020 - GustavoLCR */
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
#define INITGUID
|
||||
#include <r_core.h>
|
||||
#include <DbgEng.h>
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
typedef HRESULT (__stdcall *DebugCreate_t)(
|
||||
_In_ REFIID InterfaceId,
|
||||
_Out_ PVOID *Interface
|
||||
);
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
typedef HRESULT (__stdcall *DebugConnectWide_t)(
|
||||
_In_ PCWSTR RemoteOptions,
|
||||
_In_ REFIID InterfaceId,
|
||||
_Out_ PVOID *Interface
|
||||
);
|
||||
|
||||
#include <r_io.h>
|
||||
#include <r_lib.h>
|
||||
#include <r_socket.h>
|
||||
#include <r_util.h>
|
||||
#include <transport.h>
|
||||
#include <windbg.h>
|
||||
static DebugCreate_t w32_DebugCreate = NULL;
|
||||
static DebugConnectWide_t w32_DebugConnectWide = NULL;
|
||||
|
||||
static bool __plugin_open(RIO *io, const char *file, bool many) {
|
||||
return (!strncmp (file, "windbg://", 9));
|
||||
#define WINDBGURI "windbg://"
|
||||
|
||||
typedef struct { // Keep in sync with debug_windbg.c
|
||||
bool initialized;
|
||||
ULONG64 server;
|
||||
ULONG64 processBase;
|
||||
DWORD lastExecutionStatus;
|
||||
PDEBUG_CLIENT5 dbgClient;
|
||||
PDEBUG_CONTROL4 dbgCtrl;
|
||||
PDEBUG_DATA_SPACES4 dbgData;
|
||||
PDEBUG_REGISTERS2 dbgReg;
|
||||
PDEBUG_SYSTEM_OBJECTS4 dbgSysObj;
|
||||
PDEBUG_SYMBOLS3 dbgSymbols;
|
||||
PDEBUG_ADVANCED3 dbgAdvanced;
|
||||
} DbgEngContext;
|
||||
|
||||
#define THISCALL(dbginterface, function, ...) dbginterface->lpVtbl->function (dbginterface, __VA_ARGS__)
|
||||
#define ITHISCALL(dbginterface, function, ...) THISCALL (idbg->dbginterface, function, __VA_ARGS__)
|
||||
|
||||
#define DECLARE_CALLBACKS_IMPL(Type, IFace) \
|
||||
typedef struct IFace##_impl { \
|
||||
IFace *lpVtbl; \
|
||||
DbgEngContext *m_idbg; \
|
||||
ULONG m_ref; \
|
||||
} Type##_IMPL, *P##Type##_IMPL; \
|
||||
|
||||
#define INIT_IUNKNOWN_CALLBACKS(IFace, lpVtbl) \
|
||||
lpVtbl->QueryInterface = IFace##_QueryInterface_impl; \
|
||||
lpVtbl->AddRef = IFace##_AddRef_impl; \
|
||||
lpVtbl->Release = IFace##_Release_impl \
|
||||
|
||||
#define DECLARE_NEW(IFace, IVtbl) \
|
||||
static P##IFace IFace##_impl_new( \
|
||||
DbgEngContext *idbg) { \
|
||||
if (!idbg) { \
|
||||
return NULL; \
|
||||
} \
|
||||
P##IFace##_IMPL callbacks = R_NEW (IFace##_IMPL); \
|
||||
if (!callbacks) { \
|
||||
return NULL; \
|
||||
} \
|
||||
callbacks->lpVtbl = R_NEW (IVtbl); \
|
||||
if (!callbacks->lpVtbl) { \
|
||||
free (callbacks); \
|
||||
return NULL; \
|
||||
} \
|
||||
IFace##_vtbl_init ((P##IFace)callbacks); \
|
||||
callbacks->m_idbg = idbg; \
|
||||
callbacks->m_ref = 1; \
|
||||
return (P##IFace)callbacks; \
|
||||
}
|
||||
|
||||
static RIODesc *__open(RIO *io, const char *file, int rw, int mode) {
|
||||
if (!__plugin_open (io, file, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!iob_select ("pipe")) {
|
||||
eprintf("Could not initialize the IO backend\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *io_ctx = iob_open (file + 9);
|
||||
if (!io_ctx) {
|
||||
eprintf ("Could not open the pipe\n");
|
||||
return NULL;
|
||||
}
|
||||
eprintf ("Opened pipe %s with fd %p\n", file + 9, io_ctx);
|
||||
|
||||
WindCtx *ctx = windbg_ctx_new (io_ctx);
|
||||
if (!ctx) {
|
||||
eprintf ("Failed to initialize windbg context\n");
|
||||
return NULL;
|
||||
}
|
||||
return r_io_desc_new (io, &r_io_plugin_windbg, file, rw, mode, ctx);
|
||||
#define DECLARE_QUERYINTERFACE(IFace, IFaceIID) \
|
||||
static STDMETHODIMP IFace##_QueryInterface_impl ( \
|
||||
P##IFace This, \
|
||||
_In_ REFIID InterfaceId, \
|
||||
_Out_ PVOID *Interface) { \
|
||||
*Interface = NULL; \
|
||||
if (IsEqualIID (InterfaceId, &IID_IUnknown) || \
|
||||
IsEqualIID (InterfaceId, &IFaceIID)) { \
|
||||
*Interface = This; \
|
||||
THISCALL (This, AddRef); \
|
||||
return S_OK; \
|
||||
} else { \
|
||||
return E_NOINTERFACE; \
|
||||
} \
|
||||
}
|
||||
|
||||
static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
||||
if (!fd) {
|
||||
return -1;
|
||||
}
|
||||
if (windbg_get_target (fd->data)) {
|
||||
return windbg_write_at_uva (fd->data, buf, io->off, count);
|
||||
}
|
||||
return windbg_write_at (fd->data, buf, io->off, count);
|
||||
#define DECLARE_ADDREF(IFace) \
|
||||
static ULONG IFace##_AddRef_impl(P##IFace This) { \
|
||||
P##IFace##_IMPL impl = (P##IFace##_IMPL)This; \
|
||||
return InterlockedIncrement (&impl->m_ref); \
|
||||
}
|
||||
|
||||
static ut64 __lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
|
||||
#define DECLARE_RELEASE(IFace) \
|
||||
static ULONG IFace##_Release_impl(P##IFace This) { \
|
||||
P##IFace##_IMPL impl = (P##IFace##_IMPL)This; \
|
||||
ULONG ret = InterlockedDecrement (&impl->m_ref); \
|
||||
if (!ret) { \
|
||||
free (This->lpVtbl); \
|
||||
free (This); \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
DECLARE_CALLBACKS_IMPL (DEBUG_EVENT_CALLBACKS, IDebugEventCallbacksVtbl)
|
||||
DECLARE_CALLBACKS_IMPL (DEBUG_INPUT_CALLBACKS, IDebugInputCallbacksVtbl)
|
||||
DECLARE_CALLBACKS_IMPL (DEBUG_OUTPUT_CALLBACKS, IDebugOutputCallbacksVtbl)
|
||||
|
||||
static STDMETHODIMP __interest_mask(PDEBUG_EVENT_CALLBACKS This, PULONG Mask) {
|
||||
*Mask = DEBUG_EVENT_BREAKPOINT | DEBUG_EVENT_CREATE_PROCESS;
|
||||
*Mask |= DEBUG_EVENT_EXCEPTION | DEBUG_EVENT_SYSTEM_ERROR;
|
||||
*Mask |= DEBUG_EVENT_EXIT_PROCESS;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __createprocess_cb(
|
||||
PDEBUG_EVENT_CALLBACKS This,
|
||||
ULONG64 ImageFileHandle,
|
||||
ULONG64 Handle,
|
||||
ULONG64 BaseOffset,
|
||||
ULONG ModuleSize,
|
||||
PCSTR ModuleName,
|
||||
PCSTR ImageName,
|
||||
ULONG CheckSum,
|
||||
ULONG TimeDateStamp,
|
||||
ULONG64 InitialThreadHandle,
|
||||
ULONG64 ThreadDataOffset,
|
||||
ULONG64 StartOffset) {
|
||||
PDEBUG_EVENT_CALLBACKS_IMPL impl = (PDEBUG_EVENT_CALLBACKS_IMPL)This;
|
||||
impl->m_idbg->processBase = BaseOffset;
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __breakpoint_cb(PDEBUG_EVENT_CALLBACKS This, PDEBUG_BREAKPOINT Bp) {
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __exception_cb(PDEBUG_EVENT_CALLBACKS This, PEXCEPTION_RECORD64 Exception, ULONG FirstChance) {
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __exit_process_cb(PDEBUG_EVENT_CALLBACKS This, ULONG ExitCode) {
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __system_error_cb(PDEBUG_EVENT_CALLBACKS This, ULONG Error, ULONG Level) {
|
||||
return DEBUG_STATUS_BREAK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __input_cb(PDEBUG_INPUT_CALLBACKS This, ULONG BufferSize) {
|
||||
char prompt[512];
|
||||
PDEBUG_INPUT_CALLBACKS_IMPL impl = (PDEBUG_INPUT_CALLBACKS_IMPL)This;
|
||||
DbgEngContext *idbg = impl->m_idbg;
|
||||
ITHISCALL (dbgCtrl, GetPromptText, prompt, sizeof (prompt), NULL);
|
||||
r_line_set_prompt (prompt);
|
||||
const char *str = r_line_readline ();
|
||||
char *ret = r_str_ndup (str, R_MIN (strlen (str), BufferSize));
|
||||
ITHISCALL (dbgCtrl, ReturnInput, ret);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __input_end_cb(PDEBUG_INPUT_CALLBACKS This) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP __output_cb(PDEBUG_OUTPUT_CALLBACKS This, ULONG Mask, PCSTR Text) {
|
||||
eprintf (Text);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
DECLARE_QUERYINTERFACE (DEBUG_EVENT_CALLBACKS, IID_IDebugEventCallbacks)
|
||||
DECLARE_QUERYINTERFACE (DEBUG_INPUT_CALLBACKS, IID_IDebugInputCallbacks)
|
||||
DECLARE_QUERYINTERFACE (DEBUG_OUTPUT_CALLBACKS, IID_IDebugOutputCallbacks)
|
||||
|
||||
DECLARE_ADDREF (DEBUG_EVENT_CALLBACKS)
|
||||
DECLARE_ADDREF (DEBUG_INPUT_CALLBACKS)
|
||||
DECLARE_ADDREF (DEBUG_OUTPUT_CALLBACKS)
|
||||
|
||||
DECLARE_RELEASE (DEBUG_EVENT_CALLBACKS)
|
||||
DECLARE_RELEASE (DEBUG_INPUT_CALLBACKS)
|
||||
DECLARE_RELEASE (DEBUG_OUTPUT_CALLBACKS)
|
||||
|
||||
static void DEBUG_EVENT_CALLBACKS_vtbl_init(PDEBUG_EVENT_CALLBACKS callbacks) {
|
||||
INIT_IUNKNOWN_CALLBACKS (DEBUG_EVENT_CALLBACKS, callbacks->lpVtbl);
|
||||
callbacks->lpVtbl->GetInterestMask = __interest_mask;
|
||||
callbacks->lpVtbl->Breakpoint = __breakpoint_cb;
|
||||
callbacks->lpVtbl->Exception = __exception_cb;
|
||||
callbacks->lpVtbl->CreateProcess = __createprocess_cb;
|
||||
callbacks->lpVtbl->ExitProcess = __exit_process_cb;
|
||||
callbacks->lpVtbl->SystemError = __system_error_cb;
|
||||
}
|
||||
|
||||
static void DEBUG_INPUT_CALLBACKS_vtbl_init(PDEBUG_INPUT_CALLBACKS callbacks) {
|
||||
INIT_IUNKNOWN_CALLBACKS (DEBUG_INPUT_CALLBACKS, callbacks->lpVtbl);
|
||||
callbacks->lpVtbl->StartInput = __input_cb;
|
||||
callbacks->lpVtbl->EndInput = __input_end_cb;
|
||||
}
|
||||
|
||||
static void DEBUG_OUTPUT_CALLBACKS_vtbl_init(PDEBUG_OUTPUT_CALLBACKS callbacks) {
|
||||
INIT_IUNKNOWN_CALLBACKS (DEBUG_OUTPUT_CALLBACKS, callbacks->lpVtbl);
|
||||
callbacks->lpVtbl->Output = __output_cb;
|
||||
}
|
||||
|
||||
DECLARE_NEW (DEBUG_EVENT_CALLBACKS, IDebugEventCallbacksVtbl)
|
||||
DECLARE_NEW (DEBUG_INPUT_CALLBACKS, IDebugInputCallbacksVtbl)
|
||||
DECLARE_NEW (DEBUG_OUTPUT_CALLBACKS, IDebugOutputCallbacksVtbl)
|
||||
|
||||
static void __free_context(DbgEngContext *idbg) {
|
||||
#define RELEASE(I) \
|
||||
if (idbg->I) { \
|
||||
ITHISCALL (I, Release); \
|
||||
idbg->I = NULL; \
|
||||
}
|
||||
RELEASE (dbgAdvanced);
|
||||
RELEASE (dbgClient);
|
||||
RELEASE (dbgCtrl);
|
||||
RELEASE (dbgData);
|
||||
RELEASE (dbgReg);
|
||||
RELEASE (dbgSymbols);
|
||||
RELEASE (dbgSysObj);
|
||||
free (idbg);
|
||||
#undef RELEASE
|
||||
}
|
||||
|
||||
static bool init_callbacks(DbgEngContext *idbg) {
|
||||
#define RELEASE(I) if (I) THISCALL (I, Release);
|
||||
if (!idbg->dbgClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PDEBUG_EVENT_CALLBACKS event_callbacks = DEBUG_EVENT_CALLBACKS_impl_new (idbg);
|
||||
PDEBUG_INPUT_CALLBACKS input_callbacks = DEBUG_INPUT_CALLBACKS_impl_new (idbg);
|
||||
PDEBUG_OUTPUT_CALLBACKS output_callbacks = DEBUG_OUTPUT_CALLBACKS_impl_new (idbg);
|
||||
|
||||
if (!event_callbacks || !output_callbacks || !event_callbacks) {
|
||||
RELEASE (event_callbacks);
|
||||
RELEASE (input_callbacks);
|
||||
RELEASE (output_callbacks);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED (ITHISCALL (dbgClient, SetEventCallbacks, event_callbacks)) ||
|
||||
FAILED (ITHISCALL (dbgClient, SetInputCallbacks, input_callbacks)) ||
|
||||
FAILED (ITHISCALL (dbgClient, SetOutputCallbacks, output_callbacks))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
RELEASE (event_callbacks);
|
||||
RELEASE (input_callbacks);
|
||||
RELEASE (output_callbacks);
|
||||
return true;
|
||||
fail:
|
||||
ITHISCALL (dbgClient, SetEventCallbacks, NULL);
|
||||
ITHISCALL (dbgClient, SetInputCallbacks, NULL);
|
||||
ITHISCALL (dbgClient, SetOutputCallbacks, NULL);
|
||||
return false;
|
||||
#undef RELEASE
|
||||
}
|
||||
|
||||
static DbgEngContext *create_remote_context(const char *opts) {
|
||||
DbgEngContext *idbg = R_NEW0 (DbgEngContext);
|
||||
|
||||
if (!idbg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LPWSTR wopts = (LPWSTR)r_utf8_to_utf16 (opts);
|
||||
|
||||
// Initialize interfaces
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugClient5, &idbg->dbgClient) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugControl4, &idbg->dbgCtrl) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugDataSpaces4, &idbg->dbgData) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugRegisters2, &idbg->dbgReg) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugSystemObjects4, &idbg->dbgSysObj) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugAdvanced3, &idbg->dbgAdvanced) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugConnectWide (wopts, &IID_IDebugSymbols3, &idbg->dbgSymbols) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (!init_callbacks (idbg)) {
|
||||
goto fail;
|
||||
}
|
||||
idbg->initialized = true;
|
||||
return idbg;
|
||||
fail:
|
||||
__free_context (idbg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DbgEngContext *create_context(void) {
|
||||
DbgEngContext *idbg = R_NEW0 (DbgEngContext);
|
||||
|
||||
if (!idbg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize interfaces
|
||||
if (w32_DebugCreate (&IID_IDebugClient5, &idbg->dbgClient) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugControl4, &idbg->dbgCtrl) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugDataSpaces4, &idbg->dbgData) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugRegisters2, &idbg->dbgReg) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugSystemObjects4, &idbg->dbgSysObj) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugAdvanced3, &idbg->dbgAdvanced) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (w32_DebugCreate (&IID_IDebugSymbols3, &idbg->dbgSymbols) != S_OK) {
|
||||
goto fail;
|
||||
}
|
||||
if (!init_callbacks (idbg)) {
|
||||
goto fail;
|
||||
}
|
||||
idbg->initialized = true;
|
||||
return idbg;
|
||||
fail:
|
||||
__free_context (idbg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int windbg_init(void) {
|
||||
if (w32_DebugCreate && w32_DebugConnectWide) {
|
||||
return 1;
|
||||
}
|
||||
char *ext_path = r_sys_getenv ("_NT_DEBUGGER_EXTENSION_PATH");
|
||||
HANDLE h = NULL;
|
||||
if (R_STR_ISNOTEMPTY (ext_path)) {
|
||||
char *s = strtok (ext_path, ";");
|
||||
do {
|
||||
PWCHAR dir = r_utf8_to_utf16 (s);
|
||||
SetDllDirectoryW (dir);
|
||||
free (dir);
|
||||
h = LoadLibrary (TEXT ("dbgeng.dll"));
|
||||
} while (!h && (s = strtok (NULL, ";")));
|
||||
SetDllDirectoryW (NULL);
|
||||
}
|
||||
free (ext_path);
|
||||
if (!h) {
|
||||
h = LoadLibrary (TEXT ("dbgeng.dll"));
|
||||
}
|
||||
if (!h) {
|
||||
r_sys_perror ("LoadLibrary (\"dbgeng.dll\")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
w32_DebugCreate = (DebugCreate_t)GetProcAddress (h, "DebugCreate");
|
||||
if (!w32_DebugCreate) {
|
||||
r_sys_perror ("GetProcAddress (\"DebugCreate\")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
w32_DebugConnectWide = (DebugConnectWide_t)GetProcAddress (h, "DebugConnectWide");
|
||||
if (!w32_DebugConnectWide) {
|
||||
r_sys_perror ("GetProcAddress (\"DebugConnectWide\")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool windbg_check(RIO *io, const char *uri, bool many) {
|
||||
return !strncmp (uri, WINDBGURI, strlen (WINDBGURI));
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
TARGET_LOCAL_SPAWN,
|
||||
TARGET_LOCAL_ATTACH,
|
||||
TARGET_LOCAL_KERNEL,
|
||||
TARGET_DUMP_FILE,
|
||||
TARGET_KERNEL,
|
||||
} DbgEngTarget;
|
||||
|
||||
static RIODesc *windbg_open(RIO *io, const char *uri, int perm, int mode) {
|
||||
if (!windbg_check (io, uri, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!windbg_init ()) {
|
||||
return NULL;
|
||||
}
|
||||
HRESULT hr = E_FAIL;
|
||||
RIODesc *fd = NULL;
|
||||
RCore *core = io->corebind.core;
|
||||
DbgEngContext *idbg = NULL;
|
||||
const char *args = uri + strlen (WINDBGURI);
|
||||
if (r_str_startswith (args, "-remote")) {
|
||||
args += strlen ("-remote") + 1;
|
||||
idbg = create_remote_context (args);
|
||||
if (idbg) {
|
||||
goto remote_client;
|
||||
}
|
||||
} else {
|
||||
idbg = create_context ();
|
||||
if (idbg && r_str_startswith (args, "-premote")) {
|
||||
args += strlen ("-premote") + 1;
|
||||
if (FAILED (ITHISCALL (dbgClient, ConnectProcessServer, args, &idbg->server))) {
|
||||
__free_context (idbg);
|
||||
return NULL;
|
||||
}
|
||||
goto remote_client;
|
||||
}
|
||||
}
|
||||
if (!idbg) {
|
||||
return NULL;
|
||||
}
|
||||
ITHISCALL (dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_INITIAL_BREAK);
|
||||
ITHISCALL (dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_FINAL_BREAK);
|
||||
ITHISCALL (dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS);
|
||||
ITHISCALL (dbgCtrl, SetCodeLevel, DEBUG_LEVEL_ASSEMBLY);
|
||||
int argc;
|
||||
char **argv = r_str_argv (args, &argc);
|
||||
const size_t argv_sz = sizeof (char *) * ((size_t)argc + 2);
|
||||
char **tmp = realloc (argv, argv_sz);
|
||||
if (!tmp) {
|
||||
__free_context (idbg);
|
||||
r_str_argv_free (argv);
|
||||
return NULL;
|
||||
}
|
||||
argv = tmp;
|
||||
memmove (argv + 1, argv, argv_sz - sizeof (char *));
|
||||
argv[0] = strdup (WINDBGURI);
|
||||
argc++;
|
||||
const char *command = NULL;
|
||||
bool image_path_set = false, symbol_path_set = false;
|
||||
DbgEngTarget target = TARGET_LOCAL_SPAWN;
|
||||
DWORD spawn_options = DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE;
|
||||
DWORD attach_options = DEBUG_ATTACH_DEFAULT;
|
||||
DWORD pid = 0;
|
||||
int c;
|
||||
RGetopt opt;
|
||||
r_getopt_init (&opt, argc, argv, "c:dgGh:i:k:op:y:z:");
|
||||
while ((c = r_getopt_next (&opt)) != -1) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
command = opt.arg;
|
||||
break;
|
||||
case 'd':
|
||||
ITHISCALL (dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_INITIAL_MODULE_BREAK);
|
||||
break;
|
||||
case 'g':
|
||||
ITHISCALL (dbgCtrl, RemoveEngineOptions, DEBUG_ENGOPT_INITIAL_BREAK);
|
||||
break;
|
||||
case 'G':
|
||||
ITHISCALL (dbgCtrl, RemoveEngineOptions, DEBUG_ENGOPT_FINAL_BREAK);
|
||||
break;
|
||||
case 'h':
|
||||
if (strcmp (opt.arg, "d")) {
|
||||
spawn_options |= DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
ITHISCALL (dbgSymbols, SetImagePath, opt.arg);
|
||||
image_path_set = true;
|
||||
break;
|
||||
case 'k':
|
||||
if (strcmp (opt.arg, "l")) {
|
||||
target = TARGET_LOCAL_KERNEL;
|
||||
} else if (strcmp (opt.arg, "qm")) {
|
||||
ITHISCALL (dbgCtrl, AddEngineOptions, DEBUG_ENGOPT_KD_QUIET_MODE);
|
||||
} else {
|
||||
target = TARGET_KERNEL;
|
||||
args = opt.arg;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
spawn_options &= ~DEBUG_ONLY_THIS_PROCESS;
|
||||
spawn_options |= DEBUG_PROCESS;
|
||||
break;
|
||||
case 'p':
|
||||
if (r_str_isnumber (opt.arg)) {
|
||||
target = TARGET_LOCAL_ATTACH;
|
||||
pid = atoi (opt.arg);
|
||||
} else {
|
||||
if (strcmp (opt.arg, "b")) {
|
||||
attach_options |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
|
||||
} else if (strcmp (opt.arg, "e")) {
|
||||
attach_options |= DEBUG_ATTACH_EXISTING;
|
||||
} else if (strcmp (opt.arg, "v")) {
|
||||
attach_options |= DEBUG_ATTACH_NONINVASIVE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
symbol_path_set = true;
|
||||
ITHISCALL (dbgSymbols, SetSymbolPath, opt.arg);
|
||||
break;
|
||||
case 'z':
|
||||
target = TARGET_DUMP_FILE;
|
||||
args = opt.arg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!symbol_path_set) {
|
||||
const char *store = io->corebind.cfgGet (core, "pdb.symstore");
|
||||
const char *server = io->corebind.cfgGet (core, "pdb.server");
|
||||
char *s = strdup (server);
|
||||
r_str_replace_ch (s, ';', '*', true);
|
||||
char *sympath = r_str_newf ("cache*;srv*%s*%s", store, s);
|
||||
ITHISCALL (dbgSymbols, SetSymbolPath, sympath);
|
||||
free (s);
|
||||
free (sympath);
|
||||
}
|
||||
if (!image_path_set) {
|
||||
char *path = r_sys_getenv ("PATH");
|
||||
ITHISCALL (dbgSymbols, AppendImagePath, path);
|
||||
free (path);
|
||||
}
|
||||
switch (target) {
|
||||
case TARGET_LOCAL_SPAWN:
|
||||
if (argv[opt.ind]) {
|
||||
char *cmd = r_str_format_msvc_argv ((size_t)opt.argc - opt.ind, argv + opt.ind);
|
||||
hr = ITHISCALL (dbgClient, CreateProcess, 0ULL, cmd, spawn_options);
|
||||
free (cmd);
|
||||
} else {
|
||||
eprintf ("Missing argument for local spawn\n");
|
||||
}
|
||||
break;
|
||||
case TARGET_LOCAL_ATTACH: // -p (PID)
|
||||
hr = ITHISCALL (dbgClient, AttachProcess, 0ULL, pid, attach_options);
|
||||
break;
|
||||
case TARGET_LOCAL_KERNEL: // -kl
|
||||
if (ITHISCALL (dbgClient, IsKernelDebuggerEnabled) == S_FALSE) {
|
||||
eprintf ("Live Kernel debug not available. Set the /debug boot switch to enable it\n");
|
||||
} else {
|
||||
hr = ITHISCALL (dbgClient, AttachKernel, DEBUG_ATTACH_LOCAL_KERNEL, args);
|
||||
}
|
||||
break;
|
||||
case TARGET_DUMP_FILE: // -z
|
||||
hr = ITHISCALL (dbgClient, OpenDumpFile, args);
|
||||
break;
|
||||
case TARGET_KERNEL: // -k
|
||||
hr = ITHISCALL (dbgClient, AttachKernel, DEBUG_ATTACH_KERNEL_CONNECTION, args);
|
||||
break;
|
||||
}
|
||||
if (hr != S_OK) {
|
||||
r_str_argv_free (argv);
|
||||
__free_context (idbg);
|
||||
return NULL;
|
||||
}
|
||||
ITHISCALL (dbgCtrl, WaitForEvent, DEBUG_WAIT_DEFAULT, INFINITE);
|
||||
if (command) {
|
||||
ITHISCALL (dbgCtrl, Execute, DEBUG_OUTCTL_ALL_CLIENTS, command, DEBUG_EXECUTE_DEFAULT);
|
||||
}
|
||||
r_str_argv_free (argv);
|
||||
remote_client:
|
||||
fd = r_io_desc_new (io, &r_io_plugin_windbg, uri, perm | R_PERM_X, mode, idbg);
|
||||
fd->name = strdup (args);
|
||||
core->dbg->user = idbg;
|
||||
io->corebind.cmd (io->corebind.core, "dL windbg");
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int windbg_close(RIODesc *fd) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
if (idbg->server) {
|
||||
ITHISCALL (dbgClient, EndSession, DEBUG_END_DISCONNECT);
|
||||
ITHISCALL (dbgClient, DisconnectProcessServer, idbg->server);
|
||||
idbg->server = 0ULL;
|
||||
} else {
|
||||
ITHISCALL (dbgClient, EndSession, DEBUG_END_PASSIVE);
|
||||
}
|
||||
__free_context (idbg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ut64 windbg_lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
|
||||
switch (whence) {
|
||||
case R_IO_SEEK_SET:
|
||||
return io->off = offset;
|
||||
io->off = offset;
|
||||
break;
|
||||
case R_IO_SEEK_CUR:
|
||||
return io->off + offset;
|
||||
io->off += (st64)offset;
|
||||
break;
|
||||
case R_IO_SEEK_END:
|
||||
return ST64_MAX;
|
||||
default:
|
||||
return offset;
|
||||
io->off = UT64_MAX;
|
||||
break;
|
||||
}
|
||||
return io->off;
|
||||
}
|
||||
|
||||
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
|
||||
if (!fd) {
|
||||
return -1;
|
||||
static int windbg_read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
ULONG bytesRead = 0ULL;
|
||||
if (FAILED (ITHISCALL (dbgData, ReadVirtual, io->off, (PVOID)buf, count, &bytesRead))) {
|
||||
ULONG64 ValidBase;
|
||||
ULONG ValidSize;
|
||||
if (SUCCEEDED (ITHISCALL (dbgData, GetValidRegionVirtual, io->off, count, &ValidBase, &ValidSize))) {
|
||||
if (ValidSize && ValidBase < io->off + count) {
|
||||
const ULONG64 skipped = ValidBase - io->off;
|
||||
const ULONG toRead = count - skipped;
|
||||
ITHISCALL (dbgData, ReadVirtual, ValidBase, (PVOID)(buf + skipped), toRead, &bytesRead);
|
||||
bytesRead += skipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (windbg_get_target (fd->data)) {
|
||||
return windbg_read_at_uva (fd->data, buf, io->off, count);
|
||||
}
|
||||
|
||||
return windbg_read_at (fd->data, buf, io->off, count);
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
static int __close(RIODesc *fd) {
|
||||
windbg_ctx_free ((WindCtx**)&fd->data);
|
||||
static int windbg_write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
ULONG bytesWritten = 0ULL;
|
||||
ITHISCALL (dbgData, WriteVirtual, io->off, (PVOID)buf, count, &bytesWritten);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
static int windbg_getpid(RIODesc *fd) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
ULONG Id = 0, Class, Qualifier;
|
||||
if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
|
||||
if (Class == DEBUG_CLASS_KERNEL) {
|
||||
ITHISCALL (dbgSysObj, GetCurrentProcessId, &Id);
|
||||
} else {
|
||||
ITHISCALL (dbgSysObj, GetCurrentProcessSystemId, &Id);
|
||||
}
|
||||
}
|
||||
return Id;
|
||||
}
|
||||
|
||||
static int windbg_gettid(RIODesc *fd) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
ULONG Id = 0, Class, Qualifier;
|
||||
if (SUCCEEDED (ITHISCALL (dbgCtrl, GetDebuggeeType, &Class, &Qualifier))) {
|
||||
if (Class == DEBUG_CLASS_KERNEL) {
|
||||
ITHISCALL (dbgSysObj, GetCurrentThreadId, &Id);
|
||||
} else {
|
||||
ITHISCALL (dbgSysObj, GetCurrentThreadSystemId, &Id);
|
||||
}
|
||||
}
|
||||
return Id;
|
||||
}
|
||||
|
||||
static bool windbg_getbase(RIODesc *fd, ut64 *base) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
*base = idbg->processBase;
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *windbg_system(RIO *io, RIODesc *fd, const char *cmd) {
|
||||
DbgEngContext *idbg = fd->data;
|
||||
if (R_STR_ISEMPTY (cmd) || !strncmp ("pid", cmd, 3)) {
|
||||
return NULL;
|
||||
}
|
||||
ITHISCALL (dbgCtrl, Execute, DEBUG_OUTCTL_ALL_CLIENTS, cmd, DEBUG_EXECUTE_DEFAULT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RIOPlugin r_io_plugin_windbg = {
|
||||
.name = "windbg",
|
||||
.desc = "Attach to a KD debugger",
|
||||
.uris = "windbg://",
|
||||
.desc = "WinDBG (DbgEng.dll) based io plugin for Windows",
|
||||
.license = "LGPL3",
|
||||
.open = __open,
|
||||
.close = __close,
|
||||
.read = __read,
|
||||
.check = __plugin_open,
|
||||
.lseek = __lseek,
|
||||
.write = __write,
|
||||
.isdbg = true
|
||||
.uris = WINDBGURI,
|
||||
.isdbg = true,
|
||||
.init = windbg_init,
|
||||
.open = windbg_open,
|
||||
.lseek = windbg_lseek,
|
||||
.read = windbg_read,
|
||||
.write = windbg_write,
|
||||
.system = windbg_system,
|
||||
.close = windbg_close,
|
||||
.getpid = windbg_getpid,
|
||||
.gettid = windbg_gettid,
|
||||
.getbase = windbg_getbase,
|
||||
.check = windbg_check,
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
|
112
libr/io/p/io_winkd.c
Normal file
112
libr/io/p/io_winkd.c
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2014-2017, The Lemon Man, All rights reserved. LGPLv3
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
#include <r_io.h>
|
||||
#include <r_lib.h>
|
||||
#include <r_socket.h>
|
||||
#include <r_util.h>
|
||||
#include <transport.h>
|
||||
#include <winkd.h>
|
||||
|
||||
static bool __plugin_open(RIO *io, const char *file, bool many) {
|
||||
return (!strncmp (file, "winkd://", 8));
|
||||
}
|
||||
|
||||
static RIODesc *__open(RIO *io, const char *file, int rw, int mode) {
|
||||
if (!__plugin_open (io, file, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!iob_select ("pipe")) {
|
||||
eprintf("Could not initialize the IO backend\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *io_ctx = iob_open (file + 9);
|
||||
if (!io_ctx) {
|
||||
eprintf ("Could not open the pipe\n");
|
||||
return NULL;
|
||||
}
|
||||
eprintf ("Opened pipe %s with fd %p\n", file + 9, io_ctx);
|
||||
|
||||
WindCtx *ctx = winkd_ctx_new (io_ctx);
|
||||
if (!ctx) {
|
||||
eprintf ("Failed to initialize winkd context\n");
|
||||
return NULL;
|
||||
}
|
||||
return r_io_desc_new (io, &r_io_plugin_winkd, file, rw, mode, ctx);
|
||||
}
|
||||
|
||||
static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
||||
if (!fd) {
|
||||
return -1;
|
||||
}
|
||||
if (winkd_get_target (fd->data)) {
|
||||
return winkd_write_at_uva (fd->data, buf, io->off, count);
|
||||
}
|
||||
return winkd_write_at (fd->data, buf, io->off, count);
|
||||
}
|
||||
|
||||
static ut64 __lseek(RIO *io, RIODesc *fd, ut64 offset, int whence) {
|
||||
switch (whence) {
|
||||
case R_IO_SEEK_SET:
|
||||
return io->off = offset;
|
||||
case R_IO_SEEK_CUR:
|
||||
return io->off + offset;
|
||||
case R_IO_SEEK_END:
|
||||
return ST64_MAX;
|
||||
default:
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
static int __read(RIO *io, RIODesc *fd, ut8 *buf, int count) {
|
||||
if (!fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (winkd_get_target (fd->data)) {
|
||||
return winkd_read_at_uva (fd->data, buf, io->off, count);
|
||||
}
|
||||
|
||||
return winkd_read_at (fd->data, buf, io->off, count);
|
||||
}
|
||||
|
||||
static int __close(RIODesc *fd) {
|
||||
winkd_ctx_free ((WindCtx**)&fd->data);
|
||||
return true;
|
||||
}
|
||||
|
||||
RIOPlugin r_io_plugin_winkd = {
|
||||
.name = "winkd",
|
||||
.desc = "Attach to a KD debugger",
|
||||
.uris = "winkd://",
|
||||
.license = "LGPL3",
|
||||
.open = __open,
|
||||
.close = __close,
|
||||
.read = __read,
|
||||
.check = __plugin_open,
|
||||
.lseek = __lseek,
|
||||
.write = __write,
|
||||
.isdbg = true
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
R_API RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_IO,
|
||||
.data = &r_io_plugin_winkd,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
@ -1,21 +0,0 @@
|
||||
OBJ_WINDBG=io_windbg.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_WINDBG}
|
||||
TARGET_WINDBG=io_windbg.${EXT_SO}
|
||||
ALL_TARGETS+=${TARGET_WINDBG}
|
||||
|
||||
LIB_PATH=$(SHLR)/windbg
|
||||
CFLAGS+=-I$(SHLR)/windbg
|
||||
LDFLAGS+=$(SHLR)/windbg/libr_windbg.$(EXT_AR)
|
||||
|
||||
ifeq (${WITHPIC},0)
|
||||
LINKFLAGS+=../../util/libr_util.a
|
||||
LINKFLAGS+=../../io/libr_io.a
|
||||
else
|
||||
LINKFLAGS+=-L../../util -lr_util
|
||||
LINKFLAGS+=-L.. -lr_io
|
||||
endif
|
||||
|
||||
${TARGET_WINDBG}: ${OBJ_WINDBG}
|
||||
${CC} $(call libname,io_windbg) ${OBJ_WINDBG} ${CFLAGS} \
|
||||
${LINKFLAGS} ${LDFLAGS_LIB} $(LDFLAGS)
|
21
libr/io/p/winkd.mk
Normal file
21
libr/io/p/winkd.mk
Normal file
@ -0,0 +1,21 @@
|
||||
OBJ_WINKD=io_winkd.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_WINKD}
|
||||
TARGET_WINKD=io_winkd.${EXT_SO}
|
||||
ALL_TARGETS+=${TARGET_WINKD}
|
||||
|
||||
LIB_PATH=$(SHLR)/winkd
|
||||
CFLAGS+=-I$(SHLR)/winkd
|
||||
LDFLAGS+=$(SHLR)/winkd/libr_winkd.$(EXT_AR)
|
||||
|
||||
ifeq (${WITHPIC},0)
|
||||
LINKFLAGS+=../../util/libr_util.a
|
||||
LINKFLAGS+=../../io/libr_io.a
|
||||
else
|
||||
LINKFLAGS+=-L../../util -lr_util
|
||||
LINKFLAGS+=-L.. -lr_io
|
||||
endif
|
||||
|
||||
${TARGET_WINKD}: ${OBJ_WINKD}
|
||||
${CC} $(call libname,io_winkd) ${OBJ_WINKD} ${CFLAGS} \
|
||||
${LINKFLAGS} ${LDFLAGS_LIB} $(LDFLAGS)
|
@ -230,7 +230,7 @@ debug_plugins = [
|
||||
'null',
|
||||
'qnx',
|
||||
'rap',
|
||||
'windbg'
|
||||
'winkd'
|
||||
]
|
||||
|
||||
egg_plugins = [
|
||||
@ -290,16 +290,18 @@ io_plugins = [
|
||||
'shm',
|
||||
'sparse',
|
||||
'tcp',
|
||||
'windbg',
|
||||
'winkd',
|
||||
'winedbg',
|
||||
'zip'
|
||||
]
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
io_plugins += [
|
||||
'windbg',
|
||||
'w32dbg',
|
||||
'w32',
|
||||
]
|
||||
debug_plugins += 'windbg'
|
||||
endif
|
||||
|
||||
lang_plugins = [
|
||||
|
@ -207,7 +207,7 @@ debug.gdb
|
||||
debug.qnx
|
||||
debug.native
|
||||
debug.rap
|
||||
debug.windbg
|
||||
debug.winkd
|
||||
debug.bochs
|
||||
debug.null
|
||||
egg.exec
|
||||
@ -255,7 +255,7 @@ io.self
|
||||
io.shm
|
||||
io.w32
|
||||
io.w32dbg
|
||||
io.windbg
|
||||
io.winkd
|
||||
io.winedbg
|
||||
io.zip
|
||||
io.r2k
|
||||
|
@ -96,7 +96,7 @@ debug.esil
|
||||
debug.gdb
|
||||
debug.native
|
||||
debug.rap
|
||||
debug.windbg
|
||||
debug.winkd
|
||||
egg.exec
|
||||
egg.xor
|
||||
fs.posix
|
||||
@ -119,7 +119,7 @@ io.self
|
||||
io.shm
|
||||
io.w32
|
||||
io.w32dbg
|
||||
io.windbg
|
||||
io.winkd
|
||||
io.zip
|
||||
lang.vala
|
||||
parse.6502_pseudo
|
||||
|
@ -160,7 +160,7 @@ debug.gdb
|
||||
debug.qnx
|
||||
debug.native
|
||||
debug.rap
|
||||
debug.windbg
|
||||
debug.winkd
|
||||
debug.bochs
|
||||
debug.null
|
||||
egg.exec
|
||||
@ -207,7 +207,7 @@ io.self
|
||||
io.shm
|
||||
io.w32
|
||||
io.w32dbg
|
||||
io.windbg
|
||||
io.winkd
|
||||
io.zip
|
||||
io.r2k
|
||||
io.ar
|
||||
|
@ -157,7 +157,7 @@ debug.gdb
|
||||
debug.qnx
|
||||
debug.native
|
||||
debug.rap
|
||||
debug.windbg
|
||||
debug.winkd
|
||||
debug.bochs
|
||||
debug.null
|
||||
egg.exec
|
||||
@ -189,7 +189,7 @@ io.self
|
||||
io.shm
|
||||
io.w32
|
||||
io.w32dbg
|
||||
io.windbg
|
||||
io.winkd
|
||||
io.zip
|
||||
io.r2k
|
||||
io.ar
|
||||
|
@ -60,7 +60,7 @@ CS_REV=
|
||||
CS_PATCHES=1
|
||||
endif
|
||||
|
||||
.PHONY: capstone-sync capstone-build all clean mrproper libgdbr libwindbg bochs tree-sitter-sync sdbs
|
||||
.PHONY: capstone-sync capstone-build all clean mrproper libgdbr libwinkd bochs tree-sitter-sync sdbs
|
||||
|
||||
ifeq ($(shell gcc -v > /dev/null 2>&1 && echo works),works)
|
||||
HOST_CC?=gcc
|
||||
@ -94,14 +94,14 @@ all:
|
||||
exit 1
|
||||
endif
|
||||
|
||||
preall: libwindbg capstone-build tree-sitter-build radare2-shell-parser-build bochs
|
||||
preall: libwinkd capstone-build tree-sitter-build radare2-shell-parser-build bochs
|
||||
@for MOD in ${MODS} ; do \
|
||||
echo $(MAKE) -C $$MOD ; \
|
||||
$(MAKE) -C $$MOD HAVE_VALA= ROOT="${PWD}/../" CC="${CC}" ; \
|
||||
done
|
||||
|
||||
SDBFILES=sdb/src/.sdb${EXT_EXE} sdb/sdb${EXT_EXE} sdb/src/.sdb sdb/sdb
|
||||
PREMODS=capstone gdb windbg sdb bochs ar
|
||||
PREMODS=capstone gdb winkd sdb bochs ar
|
||||
|
||||
clean mrproper:
|
||||
rm -f ${SDBFILES}
|
||||
@ -154,8 +154,8 @@ I=../libr/include
|
||||
libgdbr:
|
||||
$(MAKE) -C gdb all
|
||||
|
||||
libwindbg:
|
||||
$(MAKE) -C windbg all
|
||||
libwinkd:
|
||||
$(MAKE) -C winkd all
|
||||
|
||||
bochs:
|
||||
$(MAKE) -C bochs all
|
||||
@ -375,7 +375,7 @@ SHLRS+=java/libr_java.a
|
||||
SHLRS+=lz4/liblz4.a
|
||||
SHLRS+=qnx/lib/libqnxr.a
|
||||
SHLRS+=yxml/libyxml.a
|
||||
SHLRS+=windbg/libr_windbg.a
|
||||
SHLRS+=winkd/libr_winkd.a
|
||||
SHLRS+=zip/librz.a
|
||||
|
||||
libr_shlr.${EXT_AR}:
|
||||
|
@ -527,25 +527,25 @@ grub_dep = declare_dependency(
|
||||
)
|
||||
|
||||
|
||||
# handle windbg dependency
|
||||
windbg_files = [
|
||||
'windbg/iob_pipe.c',
|
||||
'windbg/kd.c',
|
||||
'windbg/transport.c',
|
||||
'windbg/windbg.c',
|
||||
# handle winkd dependency
|
||||
winkd_files = [
|
||||
'winkd/iob_pipe.c',
|
||||
'winkd/kd.c',
|
||||
'winkd/transport.c',
|
||||
'winkd/winkd.c',
|
||||
]
|
||||
|
||||
windbg_inc = [platform_inc, include_directories('windbg')]
|
||||
winkd_inc = [platform_inc, include_directories('winkd')]
|
||||
|
||||
libr2windbg = static_library('r2windbg', windbg_files,
|
||||
libr2winkd = static_library('r2winkd', winkd_files,
|
||||
dependencies: [r_util_dep],
|
||||
include_directories: windbg_inc,
|
||||
include_directories: winkd_inc,
|
||||
implicit_include_directories: false
|
||||
)
|
||||
|
||||
windbg_dep = declare_dependency(
|
||||
link_with: libr2windbg,
|
||||
include_directories: windbg_inc
|
||||
winkd_dep = declare_dependency(
|
||||
link_with: libr2winkd,
|
||||
include_directories: winkd_inc
|
||||
)
|
||||
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
LINK+=$(STOP)/windbg/libr_windbg.${EXT_AR}
|
@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2014, The Lemon Man, All rights reserved.
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
#ifndef _windbg_H_
|
||||
#define _windbg_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kd.h"
|
||||
|
||||
typedef struct _WindCtx WindCtx;
|
||||
|
||||
typedef struct WindProc {
|
||||
ut64 eprocess;
|
||||
ut32 uniqueid;
|
||||
ut64 vadroot;
|
||||
ut64 dir_base_table;
|
||||
ut64 peb;
|
||||
char name[17];
|
||||
} WindProc;
|
||||
|
||||
typedef struct WindThread {
|
||||
ut32 uniqueid;
|
||||
bool runnable;
|
||||
char status;
|
||||
ut64 ethread;
|
||||
ut64 entrypoint;
|
||||
} WindThread;
|
||||
|
||||
typedef struct WindModule {
|
||||
char *name;
|
||||
ut64 addr;
|
||||
ut64 size;
|
||||
} WindModule;
|
||||
|
||||
enum {
|
||||
K_PaeEnabled = 0x036,
|
||||
K_PsActiveProcessHead = 0x050,
|
||||
K_CmNtCSDVersion = 0x268,
|
||||
};
|
||||
|
||||
enum {
|
||||
E_ActiveProcessLinks, // EPROCESS
|
||||
E_UniqueProcessId, // EPROCESS
|
||||
E_Peb, // EPROCESS
|
||||
E_ImageFileName, // EPROCESS
|
||||
E_VadRoot, // EPROCESS
|
||||
E_ThreadListHead, // EPROCESS
|
||||
P_DirectoryTableBase, // PCB
|
||||
P_ImageBaseAddress, // PEB
|
||||
P_ProcessParameters, // PEB
|
||||
R_ImagePathName, // RTL_USER_PROCESS_PARAMETERS
|
||||
ET_Tcb, // ETHREAD
|
||||
ET_ThreadListEntry, // ETHREAD
|
||||
ET_Win32StartAddress, // ETHREAD
|
||||
ET_Cid, // ETHREAD
|
||||
C_UniqueThread, // CLIENT_ID
|
||||
O_Max,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int build;
|
||||
int sp;
|
||||
int bits;
|
||||
int flags;
|
||||
int f[O_Max];
|
||||
} Profile;
|
||||
|
||||
// grep -e "^windbg_" shlr/wind/wind.c | sed -e 's/ {$/;/' -e 's/^/int /'
|
||||
int windbg_get_bits(WindCtx *ctx);
|
||||
ut64 windbg_get_target_base(WindCtx *ctx);
|
||||
ut32 windbg_get_target(WindCtx *ctx);
|
||||
bool windbg_set_target(WindCtx *ctx, ut32 pid);
|
||||
RList *windbg_list_process(WindCtx *ctx);
|
||||
RList *windbg_list_threads(WindCtx *ctx);
|
||||
RList *windbg_list_modules(WindCtx *ctx);
|
||||
int windbg_get_cpus(WindCtx *ctx);
|
||||
bool windbg_set_cpu(WindCtx *ctx, int cpu);
|
||||
int windbg_get_cpu(WindCtx *ctx);
|
||||
WindCtx * windbg_ctx_new(void *io_ptr);
|
||||
void windbg_ctx_free(WindCtx **ctx);
|
||||
int windbg_wait_packet(WindCtx *ctx, const ut32 type, kd_packet_t **p);
|
||||
int windbg_sync(WindCtx *ctx);
|
||||
bool windbg_read_ver(WindCtx *ctx);
|
||||
int windbg_continue(WindCtx *ctx);
|
||||
bool windbg_write_reg(WindCtx *ctx, const uint8_t *buf, int size);
|
||||
int windbg_read_reg(WindCtx *ctx, uint8_t *buf, int size);
|
||||
int windbg_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *flags);
|
||||
int windbg_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int *handle);
|
||||
int windbg_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count);
|
||||
int windbg_read_at_uva(WindCtx *ctx, uint8_t *buf, ut64 offset, int count);
|
||||
int windbg_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count);
|
||||
int windbg_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count);
|
||||
int windbg_write_at_uva(WindCtx *ctx, const uint8_t *buf, ut64 offset, int count);
|
||||
int windbg_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count);
|
||||
bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa);
|
||||
void windbg_break(void *ctx);
|
||||
int windbg_break_read(WindCtx *ctx);
|
||||
bool windbg_lock_enter(WindCtx *ctx);
|
||||
bool windbg_lock_leave(WindCtx *ctx);
|
||||
bool windbg_lock_tryenter(WindCtx *ctx);
|
||||
#endif
|
@ -6,13 +6,13 @@ include ../../mk/${COMPILER}.mk
|
||||
CFLAGS+=${PIC_CFLAGS}
|
||||
|
||||
CFLAGS+=-I../../libr/include
|
||||
LIBAR=libr_windbg.${EXT_AR}
|
||||
LIBAR=libr_winkd.${EXT_AR}
|
||||
LDFLAGS+=-L../../libr/util
|
||||
LIBS=-lr_util
|
||||
|
||||
include ../../shlr/sdb.mk
|
||||
|
||||
OFILES=transport.o kd.o windbg.o iob_pipe.o
|
||||
OFILES=transport.o kd.o winkd.o iob_pipe.o
|
||||
|
||||
all: ${LIBAR}
|
||||
|
1
shlr/winkd/deps.mk
Normal file
1
shlr/winkd/deps.mk
Normal file
@ -0,0 +1 @@
|
||||
LINK+=$(STOP)/winkd/libr_winkd.${EXT_AR}
|
@ -8,7 +8,7 @@
|
||||
#include <r_cons.h>
|
||||
#include <r_list.h>
|
||||
#include "transport.h"
|
||||
#include "windbg.h"
|
||||
#include "winkd.h"
|
||||
#include "kd.h"
|
||||
|
||||
#define O_FLAG_XPVAD 1
|
||||
@ -43,7 +43,7 @@ Profile *p_table[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
Profile *windbg_get_profile(int bits, int build, int sp) {
|
||||
Profile *winkd_get_profile(int bits, int build, int sp) {
|
||||
int i;
|
||||
for (i = 0; p_table[i]; i++) {
|
||||
if (p_table[i]->build != build) {
|
||||
@ -84,38 +84,38 @@ struct _WindCtx {
|
||||
RThreadLock *dontmix;
|
||||
};
|
||||
|
||||
bool windbg_lock_enter(WindCtx *ctx) {
|
||||
r_cons_break_push (windbg_break, ctx);
|
||||
bool winkd_lock_enter(WindCtx *ctx) {
|
||||
r_cons_break_push (winkd_break, ctx);
|
||||
r_th_lock_enter (ctx->dontmix);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool windbg_lock_tryenter(WindCtx *ctx) {
|
||||
bool winkd_lock_tryenter(WindCtx *ctx) {
|
||||
if (!r_th_lock_tryenter (ctx->dontmix)) {
|
||||
return false;
|
||||
}
|
||||
r_cons_break_push (windbg_break, ctx);
|
||||
r_cons_break_push (winkd_break, ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool windbg_lock_leave(WindCtx *ctx) {
|
||||
bool winkd_lock_leave(WindCtx *ctx) {
|
||||
r_cons_break_pop ();
|
||||
r_th_lock_leave (ctx->dontmix);
|
||||
return true;
|
||||
}
|
||||
|
||||
int windbg_get_bits(WindCtx *ctx) {
|
||||
int winkd_get_bits(WindCtx *ctx) {
|
||||
return ctx->is_x64 ? R_SYS_BITS_64 : R_SYS_BITS_32;
|
||||
}
|
||||
|
||||
int windbg_get_cpus(WindCtx *ctx) {
|
||||
int winkd_get_cpus(WindCtx *ctx) {
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
return ctx->cpu_count;
|
||||
}
|
||||
|
||||
bool windbg_set_cpu(WindCtx *ctx, int cpu) {
|
||||
bool winkd_set_cpu(WindCtx *ctx, int cpu) {
|
||||
if (!ctx || cpu > ctx->cpu_count) {
|
||||
return false;
|
||||
}
|
||||
@ -123,18 +123,18 @@ bool windbg_set_cpu(WindCtx *ctx, int cpu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int windbg_get_cpu(WindCtx *ctx) {
|
||||
int winkd_get_cpu(WindCtx *ctx) {
|
||||
if (!ctx) {
|
||||
return -1;
|
||||
}
|
||||
return ctx->cpu;
|
||||
}
|
||||
|
||||
bool windbg_set_target(WindCtx *ctx, uint32_t pid) {
|
||||
bool winkd_set_target(WindCtx *ctx, uint32_t pid) {
|
||||
WindProc *p;
|
||||
RListIter *it;
|
||||
if (pid) {
|
||||
RList *l = windbg_list_process (ctx);
|
||||
RList *l = winkd_list_process (ctx);
|
||||
r_list_foreach (l, it, p) {
|
||||
if (p->uniqueid == pid) {
|
||||
ctx->target = p;
|
||||
@ -147,21 +147,21 @@ bool windbg_set_target(WindCtx *ctx, uint32_t pid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t windbg_get_target(WindCtx *ctx) {
|
||||
uint32_t winkd_get_target(WindCtx *ctx) {
|
||||
if (!ctx || !ctx->io_ptr || !ctx->syncd) {
|
||||
return 0;
|
||||
}
|
||||
return ctx->target? ctx->target->uniqueid: 0;
|
||||
}
|
||||
|
||||
ut64 windbg_get_target_base(WindCtx *ctx) {
|
||||
ut64 winkd_get_target_base(WindCtx *ctx) {
|
||||
ut64 base = 0;
|
||||
|
||||
if (!ctx || !ctx->io_ptr || !ctx->syncd || !ctx->target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!windbg_read_at_uva (ctx, (uint8_t *) &base,
|
||||
if (!winkd_read_at_uva (ctx, (uint8_t *) &base,
|
||||
ctx->target->peb + O_(P_ImageBaseAddress), 4 << ctx->is_x64)) {
|
||||
return 0;
|
||||
}
|
||||
@ -169,7 +169,7 @@ ut64 windbg_get_target_base(WindCtx *ctx) {
|
||||
return base;
|
||||
}
|
||||
|
||||
WindCtx *windbg_ctx_new(void *io_ptr) {
|
||||
WindCtx *winkd_ctx_new(void *io_ptr) {
|
||||
WindCtx *ctx = calloc (1, sizeof(WindCtx));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
@ -179,7 +179,7 @@ WindCtx *windbg_ctx_new(void *io_ptr) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void windbg_ctx_free(WindCtx **ctx) {
|
||||
void winkd_ctx_free(WindCtx **ctx) {
|
||||
if (!ctx || !*ctx) {
|
||||
return;
|
||||
}
|
||||
@ -224,7 +224,7 @@ static int do_io_reply(WindCtx *ctx, kd_packet_t *pkt) {
|
||||
int ret;
|
||||
ioc.req = 0x3430;
|
||||
ioc.ret = KD_RET_ENOENT;
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
id = pkt->id;
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_FILE_IO,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &ioc, sizeof (kd_ioc_t), NULL, 0);
|
||||
@ -232,21 +232,21 @@ static int do_io_reply(WindCtx *ctx, kd_packet_t *pkt) {
|
||||
goto error;
|
||||
}
|
||||
WIND_DBG eprintf("Waiting for io_reply ack...\n");
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
id = 0;
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
WIND_DBG eprintf("Ack received, restore flow\n");
|
||||
return true;
|
||||
error:
|
||||
id = 0;
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_wait_packet(WindCtx *ctx, const uint32_t type, kd_packet_t **p) {
|
||||
int winkd_wait_packet(WindCtx *ctx, const uint32_t type, kd_packet_t **p) {
|
||||
kd_packet_t *pkt = NULL;
|
||||
int ret;
|
||||
int retries = 10;
|
||||
@ -310,12 +310,12 @@ R_PACKED (
|
||||
uint32_t flags;
|
||||
}) mmvad_short;
|
||||
|
||||
int windbg_walk_vadtree(WindCtx *ctx, ut64 address, ut64 parent) {
|
||||
int winkd_walk_vadtree(WindCtx *ctx, ut64 address, ut64 parent) {
|
||||
mmvad_short entry = { { 0 } };
|
||||
ut64 start, end;
|
||||
int prot;
|
||||
|
||||
if (windbg_read_at (ctx, (uint8_t *) &entry, address - 0x4, sizeof(mmvad_short)) != sizeof (mmvad_short)) {
|
||||
if (winkd_read_at (ctx, (uint8_t *) &entry, address - 0x4, sizeof(mmvad_short)) != sizeof (mmvad_short)) {
|
||||
eprintf ("0x%"PFMT64x " Could not read the node!\n", (ut64) address);
|
||||
return 0;
|
||||
}
|
||||
@ -333,16 +333,16 @@ int windbg_walk_vadtree(WindCtx *ctx, ut64 address, ut64 parent) {
|
||||
(ut64) start, (ut64) end, (ut64) prot);
|
||||
|
||||
if (entry.left) {
|
||||
windbg_walk_vadtree (ctx, entry.left, address);
|
||||
winkd_walk_vadtree (ctx, entry.left, address);
|
||||
}
|
||||
if (entry.right) {
|
||||
windbg_walk_vadtree (ctx, entry.right, address);
|
||||
winkd_walk_vadtree (ctx, entry.right, address);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
RList *windbg_list_process(WindCtx *ctx) {
|
||||
RList *winkd_list_process(WindCtx *ctx) {
|
||||
RList *ret;
|
||||
ut64 ptr, base;
|
||||
|
||||
@ -356,14 +356,14 @@ RList *windbg_list_process(WindCtx *ctx) {
|
||||
|
||||
ptr = 0;
|
||||
// Grab the PsActiveProcessHead from _KDDEBUGGER_DATA64
|
||||
windbg_read_at (ctx, (uint8_t *) &ptr, ctx->dbg_addr + K_PsActiveProcessHead,
|
||||
winkd_read_at (ctx, (uint8_t *) &ptr, ctx->dbg_addr + K_PsActiveProcessHead,
|
||||
4 << ctx->is_x64);
|
||||
|
||||
base = ptr;
|
||||
WIND_DBG eprintf("Process list head : 0x%016"PFMT64x "\n", ptr);
|
||||
|
||||
// Walk the LIST_ENTRY
|
||||
windbg_read_at (ctx, (uint8_t *) &ptr, ptr, 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &ptr, ptr, 4 << ctx->is_x64);
|
||||
|
||||
ret = r_list_newf (free);
|
||||
|
||||
@ -373,14 +373,14 @@ RList *windbg_list_process(WindCtx *ctx) {
|
||||
|
||||
next = 0;
|
||||
// Read the ActiveProcessLinks entry
|
||||
windbg_read_at (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
|
||||
// This points to the 'ActiveProcessLinks' list, adjust the ptr so that it point to the
|
||||
// EPROCESS base
|
||||
ptr -= O_(E_ActiveProcessLinks);
|
||||
|
||||
// Read the short name
|
||||
windbg_read_at (ctx, (uint8_t *) &buf, ptr + O_(E_ImageFileName), 16);
|
||||
winkd_read_at (ctx, (uint8_t *) &buf, ptr + O_(E_ImageFileName), 16);
|
||||
buf[16] = '\0';
|
||||
|
||||
ut64 vadroot = 0;
|
||||
@ -388,10 +388,10 @@ RList *windbg_list_process(WindCtx *ctx) {
|
||||
ut64 peb = 0;
|
||||
ut64 dir_base_table = 0;
|
||||
|
||||
windbg_read_at (ctx, (uint8_t *) &vadroot, ptr + O_(E_VadRoot), 4 << ctx->is_x64);
|
||||
windbg_read_at (ctx, (uint8_t *) &uniqueid, ptr + O_(E_UniqueProcessId), 4 << ctx->is_x64);
|
||||
windbg_read_at (ctx, (uint8_t *) &peb, ptr + O_(E_Peb), 4 << ctx->is_x64);
|
||||
windbg_read_at (ctx, (uint8_t *) &dir_base_table, ptr + O_(P_DirectoryTableBase), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &vadroot, ptr + O_(E_VadRoot), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &uniqueid, ptr + O_(E_UniqueProcessId), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &peb, ptr + O_(E_Peb), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &dir_base_table, ptr + O_(P_DirectoryTableBase), 4 << ctx->is_x64);
|
||||
|
||||
WindProc *proc = calloc (1, sizeof(WindProc));
|
||||
|
||||
@ -404,7 +404,7 @@ RList *windbg_list_process(WindCtx *ctx) {
|
||||
|
||||
r_list_append (ret, proc);
|
||||
|
||||
// windbg_walk_vadtree(ctx, vadroot, -1);
|
||||
// winkd_walk_vadtree(ctx, vadroot, -1);
|
||||
ptr = next;
|
||||
} while (ptr != base);
|
||||
|
||||
@ -413,15 +413,15 @@ RList *windbg_list_process(WindCtx *ctx) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int windbg_write_at_uva(WindCtx *ctx, const uint8_t *buf, ut64 offset, int count) {
|
||||
int winkd_write_at_uva(WindCtx *ctx, const uint8_t *buf, ut64 offset, int count) {
|
||||
ut64 pa;
|
||||
ut32 totwritten = 0;
|
||||
while (totwritten < count) {
|
||||
if (!windbg_va_to_pa (ctx, offset, &pa)) {
|
||||
if (!winkd_va_to_pa (ctx, offset, &pa)) {
|
||||
return 0;
|
||||
}
|
||||
ut32 restOfPage = 0x1000 - (offset & 0xfff);
|
||||
int written = windbg_write_at_phys (ctx, buf + totwritten, pa, R_MIN (count - totwritten, restOfPage));
|
||||
int written = winkd_write_at_phys (ctx, buf + totwritten, pa, R_MIN (count - totwritten, restOfPage));
|
||||
if (!written) {
|
||||
break;
|
||||
}
|
||||
@ -431,15 +431,15 @@ int windbg_write_at_uva(WindCtx *ctx, const uint8_t *buf, ut64 offset, int count
|
||||
return totwritten;
|
||||
}
|
||||
|
||||
int windbg_read_at_uva(WindCtx *ctx, uint8_t *buf, ut64 offset, int count) {
|
||||
int winkd_read_at_uva(WindCtx *ctx, uint8_t *buf, ut64 offset, int count) {
|
||||
ut64 pa;
|
||||
ut32 totread = 0;
|
||||
while (totread < count) {
|
||||
if (!windbg_va_to_pa (ctx, offset, &pa)) {
|
||||
if (!winkd_va_to_pa (ctx, offset, &pa)) {
|
||||
return 0;
|
||||
}
|
||||
ut32 restOfPage = 0x1000 - (offset & 0xfff);
|
||||
int read = windbg_read_at_phys (ctx, buf + totread, pa, R_MIN (count - totread, restOfPage));
|
||||
int read = winkd_read_at_phys (ctx, buf + totread, pa, R_MIN (count - totread, restOfPage));
|
||||
if (!read) {
|
||||
break;
|
||||
}
|
||||
@ -449,7 +449,7 @@ int windbg_read_at_uva(WindCtx *ctx, uint8_t *buf, ut64 offset, int count) {
|
||||
return totread;
|
||||
}
|
||||
|
||||
RList *windbg_list_modules(WindCtx *ctx) {
|
||||
RList *winkd_list_modules(WindCtx *ctx) {
|
||||
RList *ret;
|
||||
ut64 ptr, base;
|
||||
|
||||
@ -471,7 +471,7 @@ RList *windbg_list_modules(WindCtx *ctx) {
|
||||
ut64 ldroff = ctx->is_x64 ? 0x18 : 0xC;
|
||||
|
||||
// Grab the _PEB_LDR_DATA from PEB
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &ptr, ctx->target->peb + ldroff, 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &ptr, ctx->target->peb + ldroff, 4 << ctx->is_x64);
|
||||
|
||||
WIND_DBG eprintf("_PEB_LDR_DATA : 0x%016"PFMT64x "\n", ptr);
|
||||
|
||||
@ -480,7 +480,7 @@ RList *windbg_list_modules(WindCtx *ctx) {
|
||||
|
||||
base = ptr + mlistoff;
|
||||
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &ptr, base, 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &ptr, base, 4 << ctx->is_x64);
|
||||
|
||||
WIND_DBG eprintf ("InMemoryOrderModuleList : 0x%016"PFMT64x "\n", ptr);
|
||||
|
||||
@ -493,7 +493,7 @@ RList *windbg_list_modules(WindCtx *ctx) {
|
||||
do {
|
||||
|
||||
ut64 next = 0;
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
WIND_DBG eprintf ("_LDR_DATA_TABLE_ENTRY : 0x%016"PFMT64x "\n", next);
|
||||
|
||||
if (!next) {
|
||||
@ -507,21 +507,21 @@ RList *windbg_list_modules(WindCtx *ctx) {
|
||||
if (!mod) {
|
||||
break;
|
||||
}
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &mod->addr, ptr + baseoff, 4 << ctx->is_x64);
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &mod->size, ptr + sizeoff, 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &mod->addr, ptr + baseoff, 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &mod->size, ptr + sizeoff, 4 << ctx->is_x64);
|
||||
|
||||
ut16 length;
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &length, ptr + nameoff, sizeof (ut16));
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &length, ptr + nameoff, sizeof (ut16));
|
||||
|
||||
ut64 bufferaddr = 0;
|
||||
windbg_read_at_uva (ctx, (uint8_t *) &bufferaddr, ptr + nameoff + sizeof (ut32), 4 << ctx->is_x64);
|
||||
winkd_read_at_uva (ctx, (uint8_t *) &bufferaddr, ptr + nameoff + sizeof (ut32), 4 << ctx->is_x64);
|
||||
|
||||
wchar_t *unname = calloc ((ut64)length + 2, 1);
|
||||
if (!unname) {
|
||||
break;
|
||||
}
|
||||
|
||||
windbg_read_at_uva (ctx, (uint8_t *)unname, bufferaddr, length);
|
||||
winkd_read_at_uva (ctx, (uint8_t *)unname, bufferaddr, length);
|
||||
|
||||
mod->name = calloc ((ut64)length + 1, 1);
|
||||
if (!mod->name) {
|
||||
@ -538,7 +538,7 @@ RList *windbg_list_modules(WindCtx *ctx) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
RList *windbg_list_threads(WindCtx *ctx) {
|
||||
RList *winkd_list_threads(WindCtx *ctx) {
|
||||
RList *ret;
|
||||
ut64 ptr, base;
|
||||
|
||||
@ -562,7 +562,7 @@ RList *windbg_list_threads(WindCtx *ctx) {
|
||||
}
|
||||
|
||||
// Grab the ThreadListHead from _EPROCESS
|
||||
windbg_read_at (ctx, (uint8_t *) &ptr, ptr + O_(E_ThreadListHead), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &ptr, ptr + O_(E_ThreadListHead), 4 << ctx->is_x64);
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
@ -574,7 +574,7 @@ RList *windbg_list_threads(WindCtx *ctx) {
|
||||
do {
|
||||
ut64 next = 0;
|
||||
|
||||
windbg_read_at (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &next, ptr, 4 << ctx->is_x64);
|
||||
if (!next) {
|
||||
eprintf ("Corrupted ThreadListEntry found at: 0x%"PFMT64x"\n", ptr);
|
||||
break;
|
||||
@ -584,10 +584,10 @@ RList *windbg_list_threads(WindCtx *ctx) {
|
||||
ptr -= O_(ET_ThreadListEntry);
|
||||
|
||||
ut64 entrypoint = 0;
|
||||
windbg_read_at (ctx, (uint8_t *) &entrypoint, ptr + O_(ET_Win32StartAddress), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &entrypoint, ptr + O_(ET_Win32StartAddress), 4 << ctx->is_x64);
|
||||
|
||||
ut64 uniqueid = 0;
|
||||
windbg_read_at (ctx, (uint8_t *) &uniqueid, ptr + O_(ET_Cid) + O_(C_UniqueThread), 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &uniqueid, ptr + O_(ET_Cid) + O_(C_UniqueThread), 4 << ctx->is_x64);
|
||||
if (uniqueid) {
|
||||
WindThread *thread = calloc (1, sizeof(WindThread));
|
||||
thread->uniqueid = uniqueid;
|
||||
@ -614,7 +614,7 @@ RList *windbg_list_threads(WindCtx *ctx) {
|
||||
// http://blogs.msdn.com/b/ntdebugging/archive/2010/02/05/understanding-pte-part-1-let-s-get-physical.aspx
|
||||
// http://blogs.msdn.com/b/ntdebugging/archive/2010/04/14/understanding-pte-part2-flags-and-large-pages.aspx
|
||||
// http://blogs.msdn.com/b/ntdebugging/archive/2010/06/22/part-3-understanding-pte-non-pae-and-x64.aspx
|
||||
bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
bool winkd_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
ut64 pml4i, pdpi, pdi, pti;
|
||||
ut64 tmp, mask;
|
||||
|
||||
@ -655,7 +655,7 @@ bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
|
||||
if (ctx->is_x64) {
|
||||
// PML4 lookup
|
||||
if (!windbg_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pml4i * 8, 8)) {
|
||||
if (!winkd_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pml4i * 8, 8)) {
|
||||
return false;
|
||||
}
|
||||
tmp &= mask;
|
||||
@ -664,7 +664,7 @@ bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
|
||||
if (ctx->pae) {
|
||||
// PDPT lookup
|
||||
if (!windbg_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pdpi * 8, 8)) {
|
||||
if (!winkd_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pdpi * 8, 8)) {
|
||||
return false;
|
||||
}
|
||||
tmp &= mask;
|
||||
@ -672,7 +672,7 @@ bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
}
|
||||
|
||||
// PDT lookup
|
||||
if (!windbg_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pdi * (4 << ctx->pae), 4 << ctx->pae)) {
|
||||
if (!winkd_read_at_phys (ctx, (uint8_t *) &tmp, tmp + pdi * (4 << ctx->pae), 4 << ctx->pae)) {
|
||||
return false;
|
||||
}
|
||||
WIND_DBG eprintf("PDE : %016"PFMT64x "\n", tmp);
|
||||
@ -688,7 +688,7 @@ bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
}
|
||||
|
||||
// PT lookup
|
||||
if (!windbg_read_at_phys (ctx, (uint8_t *) &tmp, (tmp & mask) + pti * (4 << ctx->pae), 4 << ctx->pae)) {
|
||||
if (!winkd_read_at_phys (ctx, (uint8_t *) &tmp, (tmp & mask) + pti * (4 << ctx->pae), 4 << ctx->pae)) {
|
||||
return false;
|
||||
}
|
||||
WIND_DBG eprintf("PTE : %016"PFMT64x "\n", tmp);
|
||||
@ -706,7 +706,7 @@ bool windbg_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool windbg_read_ver(WindCtx *ctx) {
|
||||
bool winkd_read_ver(WindCtx *ctx) {
|
||||
kd_req_t req = {
|
||||
0
|
||||
};
|
||||
@ -720,7 +720,7 @@ bool windbg_read_ver(WindCtx *ctx) {
|
||||
req.req = 0x3146;
|
||||
req.cpu = ctx->cpu;
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &req, sizeof(kd_req_t), NULL, 0);
|
||||
@ -728,17 +728,17 @@ bool windbg_read_ver(WindCtx *ctx) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -772,7 +772,7 @@ bool windbg_read_ver(WindCtx *ctx) {
|
||||
ctx->is_x64 = (rr->r_ver.machine == KD_MACH_AMD64);
|
||||
|
||||
ut64 ptr = 0;
|
||||
if (!windbg_read_at (ctx, (uint8_t *) &ptr, rr->r_ver.dbg_addr, 4 << ctx->is_x64)) {
|
||||
if (!winkd_read_at (ctx, (uint8_t *) &ptr, rr->r_ver.dbg_addr, 4 << ctx->is_x64)) {
|
||||
free (pkt);
|
||||
return false;
|
||||
}
|
||||
@ -783,17 +783,17 @@ bool windbg_read_ver(WindCtx *ctx) {
|
||||
|
||||
// Thanks to this we don't have to find a way to read the cr4
|
||||
uint16_t pae_enabled;
|
||||
if (!windbg_read_at (ctx, (uint8_t *) &pae_enabled, ctx->dbg_addr + K_PaeEnabled, sizeof(uint16_t))) {
|
||||
if (!winkd_read_at (ctx, (uint8_t *) &pae_enabled, ctx->dbg_addr + K_PaeEnabled, sizeof(uint16_t))) {
|
||||
free (pkt);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grab the CmNtCSDVersion field to extract the Service Pack number
|
||||
windbg_read_at (ctx, (uint8_t *) &ptr, ctx->dbg_addr + K_CmNtCSDVersion, 8);
|
||||
windbg_read_at (ctx, (uint8_t *) &ptr, ptr, 4 << ctx->is_x64);
|
||||
winkd_read_at (ctx, (uint8_t *) &ptr, ctx->dbg_addr + K_CmNtCSDVersion, 8);
|
||||
winkd_read_at (ctx, (uint8_t *) &ptr, ptr, 4 << ctx->is_x64);
|
||||
|
||||
ctx->pae = pae_enabled & 1;
|
||||
ctx->os_profile = windbg_get_profile (32 << ctx->is_x64, rr->r_ver.minor, (ptr >> 8) & 0xff);
|
||||
ctx->os_profile = winkd_get_profile (32 << ctx->is_x64, rr->r_ver.minor, (ptr >> 8) & 0xff);
|
||||
if (!ctx->os_profile) {
|
||||
eprintf ("Could not find a suitable profile for the target OS\n");
|
||||
free (pkt);
|
||||
@ -802,11 +802,11 @@ bool windbg_read_ver(WindCtx *ctx) {
|
||||
free (pkt);
|
||||
return true;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_sync(WindCtx *ctx) {
|
||||
int winkd_sync(WindCtx *ctx) {
|
||||
int ret = -1;
|
||||
kd_packet_t *s;
|
||||
|
||||
@ -818,7 +818,7 @@ int windbg_sync(WindCtx *ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
// Send the breakin packet
|
||||
if (iob_write (ctx->io_ptr, (const uint8_t *) "b", 1) != 1) {
|
||||
@ -834,14 +834,14 @@ int windbg_sync(WindCtx *ctx) {
|
||||
}
|
||||
|
||||
// Wait for the response
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_RESET, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_RESET, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Syncronize with the first KD_PACKET_TYPE_STATE_CHANGE64 packet
|
||||
windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_CHANGE64, &s);
|
||||
winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_CHANGE64, &s);
|
||||
|
||||
// Reset the sequence id
|
||||
ctx->seq_id = 0x80800001;
|
||||
@ -863,11 +863,11 @@ int windbg_sync(WindCtx *ctx) {
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int windbg_continue(WindCtx *ctx) {
|
||||
int winkd_continue(WindCtx *ctx) {
|
||||
kd_req_t req = {
|
||||
0
|
||||
};
|
||||
@ -883,12 +883,12 @@ int windbg_continue(WindCtx *ctx) {
|
||||
// behave like suggested by ReactOS source
|
||||
req.r_cont.tf = 0x400;
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &req, sizeof (kd_req_t), NULL, 0);
|
||||
if (ret == KD_E_OK) {
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret == KD_E_OK) {
|
||||
r_list_free (ctx->plist_cache);
|
||||
ctx->plist_cache = NULL;
|
||||
@ -899,11 +899,11 @@ int windbg_continue(WindCtx *ctx) {
|
||||
ret = false;
|
||||
|
||||
end:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool windbg_write_reg(WindCtx *ctx, const uint8_t *buf, int size) {
|
||||
bool winkd_write_reg(WindCtx *ctx, const uint8_t *buf, int size) {
|
||||
kd_packet_t *pkt;
|
||||
kd_req_t req = {
|
||||
0
|
||||
@ -919,7 +919,7 @@ bool windbg_write_reg(WindCtx *ctx, const uint8_t *buf, int size) {
|
||||
|
||||
WIND_DBG eprintf("Regwrite() size: %x\n", size);
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &req, sizeof(kd_req_t), buf, size);
|
||||
@ -927,17 +927,17 @@ bool windbg_write_reg(WindCtx *ctx, const uint8_t *buf, int size) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -951,11 +951,11 @@ bool windbg_write_reg(WindCtx *ctx, const uint8_t *buf, int size) {
|
||||
|
||||
return size;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_read_reg(WindCtx *ctx, uint8_t *buf, int size) {
|
||||
int winkd_read_reg(WindCtx *ctx, uint8_t *buf, int size) {
|
||||
kd_req_t req;
|
||||
kd_packet_t *pkt = NULL;
|
||||
int ret;
|
||||
@ -973,7 +973,7 @@ int windbg_read_reg(WindCtx *ctx, uint8_t *buf, int size) {
|
||||
|
||||
// Don't wait on the lock in read_reg since it's frequently called. Otherwise the user
|
||||
// will be forced to interrupt exit read_reg constantly while another task is in progress
|
||||
if (!windbg_lock_tryenter (ctx)) {
|
||||
if (!winkd_lock_tryenter (ctx)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -983,17 +983,17 @@ int windbg_read_reg(WindCtx *ctx, uint8_t *buf, int size) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1009,11 +1009,11 @@ int windbg_read_reg(WindCtx *ctx, uint8_t *buf, int size) {
|
||||
|
||||
return size;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *flags) {
|
||||
int winkd_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *flags) {
|
||||
kd_req_t req;
|
||||
kd_packet_t *pkt;
|
||||
int ret;
|
||||
@ -1030,7 +1030,7 @@ int windbg_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *fla
|
||||
req.r_query_mem.addr = addr;
|
||||
req.r_query_mem.address_space = 0; // Tells the kernel that 'addr' is a virtual address
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE, (ctx->seq_id ^= 1), (uint8_t *) &req,
|
||||
sizeof(kd_req_t), NULL, 0);
|
||||
@ -1038,17 +1038,17 @@ int windbg_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *fla
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1068,12 +1068,12 @@ int windbg_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *fla
|
||||
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int windbg_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int *handle) {
|
||||
int winkd_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int *handle) {
|
||||
kd_req_t req = {
|
||||
0
|
||||
};
|
||||
@ -1093,7 +1093,7 @@ int windbg_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int
|
||||
req.r_del_bp.handle = *handle;
|
||||
}
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE, (ctx->seq_id ^= 1), (uint8_t *) &req,
|
||||
sizeof(kd_req_t), NULL, 0);
|
||||
@ -1101,17 +1101,17 @@ int windbg_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1124,11 +1124,11 @@ int windbg_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int
|
||||
free (pkt);
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
||||
int winkd_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
||||
kd_req_t req = {
|
||||
0
|
||||
}, *rr;
|
||||
@ -1146,7 +1146,7 @@ int windbg_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int
|
||||
|
||||
// Don't wait on the lock in read_reg since it's frequently called. Otherwise the user
|
||||
// will be forced to interrupt exit read_at_phys constantly while another task is in progress
|
||||
if (!windbg_lock_tryenter (ctx)) {
|
||||
if (!winkd_lock_tryenter (ctx)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1156,17 +1156,17 @@ int windbg_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1180,11 +1180,11 @@ int windbg_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int
|
||||
free (pkt);
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
||||
int winkd_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
||||
kd_req_t *rr, req = {
|
||||
0
|
||||
};
|
||||
@ -1202,7 +1202,7 @@ int windbg_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int coun
|
||||
// Don't wait on the lock in read_at since it's frequently called, including each
|
||||
// time "enter" is pressed. Otherwise the user will be forced to interrupt exit
|
||||
// read_registers constantly while another task is in progress
|
||||
if (!windbg_lock_tryenter (ctx)) {
|
||||
if (!winkd_lock_tryenter (ctx)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1212,16 +1212,16 @@ int windbg_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int coun
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1235,11 +1235,11 @@ int windbg_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int coun
|
||||
free (pkt);
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
||||
int winkd_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
||||
kd_packet_t *pkt;
|
||||
kd_req_t req = {
|
||||
0
|
||||
@ -1256,7 +1256,7 @@ int windbg_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const i
|
||||
req.r_mem.addr = offset;
|
||||
req.r_mem.length = payload;
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &req,
|
||||
@ -1265,17 +1265,17 @@ int windbg_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const i
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1288,11 +1288,11 @@ int windbg_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const i
|
||||
free (pkt);
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int windbg_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
||||
int winkd_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
||||
kd_packet_t *pkt;
|
||||
kd_req_t req;
|
||||
int ret;
|
||||
@ -1313,7 +1313,7 @@ int windbg_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, co
|
||||
req.r_mem.length = payload;
|
||||
req.r_mem.read = 0; // Default caching option
|
||||
|
||||
windbg_lock_enter (ctx);
|
||||
winkd_lock_enter (ctx);
|
||||
|
||||
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_STATE_MANIPULATE,
|
||||
(ctx->seq_id ^= 1), (uint8_t *) &req, sizeof(kd_req_t), buf, payload);
|
||||
@ -1321,17 +1321,17 @@ int windbg_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, co
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_ACKNOWLEDGE, NULL);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = windbg_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
ret = winkd_wait_packet (ctx, KD_PACKET_TYPE_STATE_MANIPULATE, &pkt);
|
||||
if (ret != KD_E_OK) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
|
||||
kd_req_t *rr = PKT_REQ (pkt);
|
||||
|
||||
@ -1343,18 +1343,18 @@ int windbg_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, co
|
||||
free (pkt);
|
||||
return ret;
|
||||
error:
|
||||
windbg_lock_leave (ctx);
|
||||
winkd_lock_leave (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void windbg_break(void *arg) {
|
||||
void winkd_break(void *arg) {
|
||||
// This command shouldn't be wrapped by locks since it can always be sent and we don't
|
||||
// want break queued up after another background task
|
||||
WindCtx *ctx = (WindCtx *)arg;
|
||||
(void)iob_write (ctx->io_ptr, (const uint8_t *)"b", 1);
|
||||
}
|
||||
|
||||
int windbg_break_read(WindCtx *ctx) {
|
||||
int winkd_break_read(WindCtx *ctx) {
|
||||
#if __WINDOWS__ && !defined(_MSC_VER)
|
||||
static BOOL WINAPI (*w32_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
|
||||
if (!w32_CancelIoEx) {
|
113
shlr/winkd/winkd.h
Normal file
113
shlr/winkd/winkd.h
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2014, The Lemon Man, All rights reserved.
|
||||
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library.
|
||||
|
||||
#ifndef _winkd_H_
|
||||
#define _winkd_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kd.h"
|
||||
|
||||
typedef struct _WindCtx WindCtx;
|
||||
|
||||
typedef struct WindProc {
|
||||
ut64 eprocess;
|
||||
ut32 uniqueid;
|
||||
ut64 vadroot;
|
||||
ut64 dir_base_table;
|
||||
ut64 peb;
|
||||
char name[17];
|
||||
} WindProc;
|
||||
|
||||
typedef struct WindThread {
|
||||
ut32 uniqueid;
|
||||
bool runnable;
|
||||
char status;
|
||||
ut64 ethread;
|
||||
ut64 entrypoint;
|
||||
} WindThread;
|
||||
|
||||
typedef struct WindModule {
|
||||
char *name;
|
||||
ut64 addr;
|
||||
ut64 size;
|
||||
} WindModule;
|
||||
|
||||
enum {
|
||||
K_PaeEnabled = 0x036,
|
||||
K_PsActiveProcessHead = 0x050,
|
||||
K_CmNtCSDVersion = 0x268,
|
||||
};
|
||||
|
||||
enum {
|
||||
E_ActiveProcessLinks, // EPROCESS
|
||||
E_UniqueProcessId, // EPROCESS
|
||||
E_Peb, // EPROCESS
|
||||
E_ImageFileName, // EPROCESS
|
||||
E_VadRoot, // EPROCESS
|
||||
E_ThreadListHead, // EPROCESS
|
||||
P_DirectoryTableBase, // PCB
|
||||
P_ImageBaseAddress, // PEB
|
||||
P_ProcessParameters, // PEB
|
||||
R_ImagePathName, // RTL_USER_PROCESS_PARAMETERS
|
||||
ET_Tcb, // ETHREAD
|
||||
ET_ThreadListEntry, // ETHREAD
|
||||
ET_Win32StartAddress, // ETHREAD
|
||||
ET_Cid, // ETHREAD
|
||||
C_UniqueThread, // CLIENT_ID
|
||||
O_Max,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int build;
|
||||
int sp;
|
||||
int bits;
|
||||
int flags;
|
||||
int f[O_Max];
|
||||
} Profile;
|
||||
|
||||
// grep -e "^winkd_" shlr/wind/wind.c | sed -e 's/ {$/;/' -e 's/^/int /'
|
||||
int winkd_get_bits(WindCtx *ctx);
|
||||
ut64 winkd_get_target_base(WindCtx *ctx);
|
||||
ut32 winkd_get_target(WindCtx *ctx);
|
||||
bool winkd_set_target(WindCtx *ctx, ut32 pid);
|
||||
RList *winkd_list_process(WindCtx *ctx);
|
||||
RList *winkd_list_threads(WindCtx *ctx);
|
||||
RList *winkd_list_modules(WindCtx *ctx);
|
||||
int winkd_get_cpus(WindCtx *ctx);
|
||||
bool winkd_set_cpu(WindCtx *ctx, int cpu);
|
||||
int winkd_get_cpu(WindCtx *ctx);
|
||||
WindCtx * winkd_ctx_new(void *io_ptr);
|
||||
void winkd_ctx_free(WindCtx **ctx);
|
||||
int winkd_wait_packet(WindCtx *ctx, const ut32 type, kd_packet_t **p);
|
||||
int winkd_sync(WindCtx *ctx);
|
||||
bool winkd_read_ver(WindCtx *ctx);
|
||||
int winkd_continue(WindCtx *ctx);
|
||||
bool winkd_write_reg(WindCtx *ctx, const uint8_t *buf, int size);
|
||||
int winkd_read_reg(WindCtx *ctx, uint8_t *buf, int size);
|
||||
int winkd_query_mem(WindCtx *ctx, const ut64 addr, int *address_space, int *flags);
|
||||
int winkd_bkpt(WindCtx *ctx, const ut64 addr, const int set, const int hw, int *handle);
|
||||
int winkd_read_at(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count);
|
||||
int winkd_read_at_uva(WindCtx *ctx, uint8_t *buf, ut64 offset, int count);
|
||||
int winkd_read_at_phys(WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count);
|
||||
int winkd_write_at(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count);
|
||||
int winkd_write_at_uva(WindCtx *ctx, const uint8_t *buf, ut64 offset, int count);
|
||||
int winkd_write_at_phys(WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count);
|
||||
bool winkd_va_to_pa(WindCtx *ctx, ut64 va, ut64 *pa);
|
||||
void winkd_break(void *ctx);
|
||||
int winkd_break_read(WindCtx *ctx);
|
||||
bool winkd_lock_enter(WindCtx *ctx);
|
||||
bool winkd_lock_leave(WindCtx *ctx);
|
||||
bool winkd_lock_tryenter(WindCtx *ctx);
|
||||
#endif
|
@ -84,8 +84,8 @@ RebuildGdb() {
|
||||
Rebuild libr/debug
|
||||
}
|
||||
|
||||
RebuildWindbg() {
|
||||
Rebuild shlr/windbg
|
||||
RebuildWinkd() {
|
||||
Rebuild shlr/winkd
|
||||
Rebuild libr/io
|
||||
Rebuild libr/debug
|
||||
}
|
||||
@ -104,7 +104,7 @@ case "$1" in
|
||||
grub|fs)RebuildFs; ;;
|
||||
bin) RebuildBin ; ;;
|
||||
gdb) RebuildGdb ; ;;
|
||||
windbg) RebuildWindbg ; ;;
|
||||
winkd) RebuildWinkd ; ;;
|
||||
sdb) RebuildSdb ; ;;
|
||||
spp) RebuildSpp ; ;;
|
||||
tcc) RebuildTcc ; ;;
|
||||
|
@ -11,6 +11,6 @@ EXPECT=<<EOF
|
||||
6 --- null MIT
|
||||
7 --- qnx LGPL3
|
||||
8 --- rap LGPL3
|
||||
9 --- windbg LGPL3
|
||||
9 --- winkd LGPL3
|
||||
EOF
|
||||
RUN
|
||||
|
Loading…
Reference in New Issue
Block a user