2015-04-07 12:47:20 +00:00
|
|
|
// Copyright (c) 2014-2015, The Lemon Man, All rights reserved. LGPLv3
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// 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 <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
2015-09-23 14:17:19 +00:00
|
|
|
#include <stdbool.h>
|
2014-08-31 16:09:25 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <r_list.h>
|
2014-12-08 22:38:13 +00:00
|
|
|
#include "transport.h"
|
2014-08-31 16:09:25 +00:00
|
|
|
#include "wind.h"
|
|
|
|
#include "kd.h"
|
|
|
|
|
|
|
|
enum {
|
2015-09-23 14:17:19 +00:00
|
|
|
K_PaeEnabled = 0x036,
|
|
|
|
K_PsActiveProcessHead = 0x050,
|
|
|
|
K_CmNtCSDVersion = 0x268,
|
2014-08-31 16:09:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
2015-09-23 14:17:19 +00:00
|
|
|
E_ActiveProcessLinks, // EPROCESS
|
|
|
|
E_UniqueProcessId, // EPROCESS
|
|
|
|
E_Peb, // EPROCESS
|
|
|
|
E_ImageFileName, // EPROCESS
|
|
|
|
E_VadRoot, // EPROCESS
|
|
|
|
P_DirectoryTableBase, // PCB
|
|
|
|
P_ImageBaseAddress, // PEB
|
|
|
|
P_ProcessParameters, // PEB
|
|
|
|
R_ImagePathName, // RTL_USER_PROCESS_PARAMETERS
|
2014-08-31 16:09:25 +00:00
|
|
|
O_Max,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define O_FLAG_XPVAD 1
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
#define WIND_DBG if (false)
|
|
|
|
|
2014-08-31 16:09:25 +00:00
|
|
|
typedef struct {
|
|
|
|
int build;
|
|
|
|
int sp;
|
|
|
|
int bits;
|
|
|
|
int flags;
|
|
|
|
int f[O_Max];
|
|
|
|
} Profile;
|
|
|
|
|
|
|
|
#define O_(n) ctx->os_profile->f[n]
|
|
|
|
|
|
|
|
#include "profiles.h"
|
|
|
|
|
|
|
|
Profile *p_table[] = {
|
|
|
|
&XP_SP2_X86,
|
|
|
|
&XP_SP3_X86,
|
|
|
|
&WIN7_SP0_X86,
|
|
|
|
&WIN7_SP1_X86,
|
|
|
|
&WIN7_SP0_X64,
|
|
|
|
&WIN7_SP1_X64,
|
|
|
|
&VISTA_SP0_X86,
|
|
|
|
&VISTA_SP0_X64,
|
|
|
|
&VISTA_SP1_X86,
|
|
|
|
&VISTA_SP1_X64,
|
|
|
|
&VISTA_SP2_X86,
|
|
|
|
&VISTA_SP2_X64,
|
|
|
|
&WIN2003_SP0_X86,
|
|
|
|
&WIN2003_SP1_X86,
|
|
|
|
&WIN2003_SP1_X64,
|
|
|
|
&WIN2003_SP2_X86,
|
|
|
|
&WIN2003_SP2_X64,
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
Profile *wind_get_profile (int bits, int build, int sp) {
|
2014-08-31 16:09:25 +00:00
|
|
|
int i;
|
|
|
|
for (i = 0; p_table[i]; i++) {
|
2015-09-23 14:17:19 +00:00
|
|
|
if (p_table[i]->build != build)
|
|
|
|
continue;
|
|
|
|
if (p_table[i]->sp != sp)
|
|
|
|
continue;
|
|
|
|
if (p_table[i]->bits != bits)
|
|
|
|
continue;
|
|
|
|
return p_table[i];
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
#define LOG_PKT(p) { \
|
2015-04-30 00:18:51 +00:00
|
|
|
eprintf("Leader\t: %08x\nType\t: %08x\nLength\t: %08x\nID\t: %08x\nCheck\t: %08x [%s]\n", \
|
2014-08-31 16:09:25 +00:00
|
|
|
(p)->leader, \
|
|
|
|
(p)->type, \
|
|
|
|
(p)->length, \
|
|
|
|
(p)->id, \
|
|
|
|
(p)->checksum, \
|
|
|
|
(kd_data_checksum((p)->data, (p)->length) == (p)->checksum)?"Ok":"Wrong" \
|
|
|
|
); \
|
|
|
|
}
|
2015-09-23 14:17:19 +00:00
|
|
|
#define LOG_REQ(r) { \
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Request : %08x\nProcessor : %08x\nReturn : %08x\n", \
|
2014-08-31 16:09:25 +00:00
|
|
|
(r)->req, \
|
|
|
|
(r)->cpu, \
|
|
|
|
(r)->ret \
|
|
|
|
); \
|
|
|
|
}
|
|
|
|
|
|
|
|
struct _WindCtx {
|
|
|
|
void *io_ptr;
|
|
|
|
uint32_t seq_id;
|
|
|
|
int syncd;
|
|
|
|
int cpu_count;
|
|
|
|
int cpu;
|
|
|
|
int pae;
|
|
|
|
int is_x64;
|
|
|
|
Profile *os_profile;
|
|
|
|
RList *plist_cache;
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 dbg_addr;
|
2014-08-31 16:09:25 +00:00
|
|
|
WindProc *target;
|
|
|
|
};
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
int wind_get_cpus (WindCtx *ctx) {
|
|
|
|
if (!ctx) return -1;
|
2014-08-31 16:09:25 +00:00
|
|
|
return ctx->cpu_count;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
bool wind_set_cpu (WindCtx *ctx, int cpu) {
|
2014-08-31 16:09:25 +00:00
|
|
|
if (!ctx || cpu > ctx->cpu_count)
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
ctx->cpu = cpu;
|
2015-09-23 14:17:19 +00:00
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
int wind_get_cpu (WindCtx *ctx) {
|
|
|
|
if (!ctx) return -1;
|
2014-08-31 16:09:25 +00:00
|
|
|
return ctx->cpu;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
bool wind_set_target (WindCtx *ctx, uint32_t pid) {
|
2014-08-31 16:09:25 +00:00
|
|
|
WindProc *p;
|
|
|
|
RListIter *it;
|
2015-09-23 14:17:19 +00:00
|
|
|
if (pid) {
|
|
|
|
RList *l = wind_list_process (ctx);
|
|
|
|
r_list_foreach (l, it, p) {
|
|
|
|
if (p->uniqueid == pid) {
|
|
|
|
ctx->target = p;
|
|
|
|
return true;
|
|
|
|
}
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
2015-09-23 14:17:19 +00:00
|
|
|
ctx->target = NULL;
|
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
uint32_t wind_get_target (WindCtx *ctx) {
|
2014-08-31 16:09:25 +00:00
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
2015-09-23 14:17:19 +00:00
|
|
|
return ctx->target? ctx->target->uniqueid: 0;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 wind_get_target_base (WindCtx *ctx) {
|
|
|
|
ut64 ppeb;
|
|
|
|
ut64 base = 0;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd || !ctx->target)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!wind_va_to_pa(ctx, ctx->target->peb, &ppeb))
|
|
|
|
return 0;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
if (!wind_read_at_phys (ctx, (uint8_t *)&base,
|
|
|
|
ppeb + O_(P_ImageBaseAddress), 4 << ctx->is_x64))
|
2014-08-31 16:09:25 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WindCtx *wind_ctx_new (void *io_ptr) {
|
2014-08-31 16:09:25 +00:00
|
|
|
WindCtx *ctx = calloc(1, sizeof(WindCtx));
|
2015-09-23 14:17:19 +00:00
|
|
|
if (!ctx) return NULL;
|
2014-08-31 16:09:25 +00:00
|
|
|
ctx->io_ptr = io_ptr;
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
void wind_ctx_free (WindCtx *ctx) {
|
|
|
|
if (!ctx) return;
|
2014-08-31 16:09:25 +00:00
|
|
|
r_list_free(ctx->plist_cache);
|
|
|
|
iob_close(ctx->io_ptr);
|
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
#define PKT_REQ(p) ( (kd_req_t *)(((kd_packet_t *)p)->data) )
|
|
|
|
#define PKT_STC(p) ( (kd_stc_64 *)(((kd_packet_t *)p)->data) )
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
dump_stc (kd_packet_t *p) {
|
|
|
|
kd_stc_64 *stc = PKT_STC(p);
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("New state : %08x\n", stc->state);
|
|
|
|
eprintf("eip : %016"PFMT64x" kthread : %016"PFMT64x"\n",
|
2015-04-12 16:00:10 +00:00
|
|
|
(ut64)stc->pc, (ut64)stc->kthread);
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("On cpu %i/%i\n", stc->cpu + 1, stc->cpu_count);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (stc->state == 0x3030) {
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("ex\n");
|
|
|
|
eprintf("\tCode : %08x\n", stc->exception.code);
|
|
|
|
eprintf("\tFlags : %08x\n", stc->exception.flags);
|
2015-04-12 16:00:10 +00:00
|
|
|
eprintf("\tRecord : %016"PFMT64x"\n", (ut64)stc->exception.ex_record);
|
|
|
|
eprintf("\tAddr : %016"PFMT64x"\n", (ut64)stc->exception.ex_addr);
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
static int do_io_reply (WindCtx *ctx, kd_packet_t *pkt) {
|
|
|
|
kd_ioc_t ioc = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
int ret;
|
|
|
|
ioc.req = 0x3430;
|
|
|
|
ioc.ret = KD_RET_ENOENT;
|
2015-09-23 14:17:19 +00:00
|
|
|
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_IO,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&ioc, sizeof (kd_ioc_t), NULL, 0);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
|
|
|
WIND_DBG eprintf("Waiting for io_reply ack...\n");
|
2014-08-31 16:09:25 +00:00
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
|
|
|
WIND_DBG eprintf("Ack received, restore flow\n");
|
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int wind_wait_packet (WindCtx *ctx, const uint32_t type, kd_packet_t **p) {
|
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret, retries = 10;
|
|
|
|
|
|
|
|
// r_sys_backtrace();
|
|
|
|
|
|
|
|
pkt = NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
free(pkt);
|
|
|
|
// Try to read a whole packet
|
|
|
|
ret = kd_read_packet(ctx->io_ptr, &pkt);
|
2015-04-07 12:47:20 +00:00
|
|
|
// eprintf("kd_read_packet() = %i\n", ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
break;
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
// eprintf("Received %08x, expected %08x\n", pkt->type, type);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (pkt->leader == KD_PACKET_DATA && pkt->type == KD_PACKET_TYPE_STATE_CHANGE)
|
|
|
|
dump_stc(pkt);
|
|
|
|
if (pkt->leader == KD_PACKET_DATA && pkt->type == KD_PACKET_TYPE_IO)
|
|
|
|
do_io_reply(ctx, pkt);
|
|
|
|
|
|
|
|
// Check for RESEND
|
|
|
|
// The host didn't like our request
|
|
|
|
if (pkt->leader == KD_PACKET_CTRL && pkt->type == KD_PACKET_TYPE_RESEND) {
|
|
|
|
ret = KD_E_MALFORMED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(pkt->type != type && retries--);
|
|
|
|
|
|
|
|
if (ret != KD_E_OK) {
|
|
|
|
free(pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-09 16:45:44 +00:00
|
|
|
if (p) {
|
|
|
|
*p = pkt;
|
|
|
|
} else {
|
|
|
|
free (pkt);
|
|
|
|
}
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
return KD_E_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// http://dfrws.org/2007/proceedings/p62-dolan-gavitt.pdf
|
|
|
|
typedef struct {
|
|
|
|
char tag[4];
|
|
|
|
uint32_t start_vpn;
|
|
|
|
uint32_t end_vpn;
|
|
|
|
uint32_t parent;
|
|
|
|
uint32_t left, right;
|
|
|
|
uint32_t flags;
|
|
|
|
} __attribute__((packed)) mmvad_short;
|
|
|
|
|
|
|
|
int
|
2015-10-01 16:33:37 +00:00
|
|
|
wind_walk_vadtree (WindCtx *ctx, ut64 address, ut64 parent) {
|
2015-08-24 19:29:12 +00:00
|
|
|
mmvad_short entry = {{0}};
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 start, end;
|
2014-08-31 16:09:25 +00:00
|
|
|
int prot;
|
|
|
|
|
2014-12-09 16:45:44 +00:00
|
|
|
if (wind_read_at(ctx, (uint8_t *)&entry, address - 0x4, sizeof(mmvad_short)) != sizeof (mmvad_short)) {
|
2015-04-12 16:00:10 +00:00
|
|
|
eprintf("0x%"PFMT64x" Could not read the node!\n", (ut64)address);
|
2014-08-31 16:09:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parent != UT64_MAX && entry.parent != parent) {
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Wrong parent!\n");
|
2014-08-31 16:09:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = entry.start_vpn << 12;
|
|
|
|
end = ((entry.end_vpn + 1) << 12) - 1;
|
|
|
|
prot = (entry.flags >> 24)&0x1F;
|
|
|
|
|
2014-12-08 22:38:13 +00:00
|
|
|
eprintf ("Start 0x%016"PFMT64x" End 0x%016"PFMT64x" Prot 0x%08"PFMT64x"\n",
|
2015-04-12 16:00:10 +00:00
|
|
|
(ut64)start, (ut64)end, (ut64)prot);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (entry.left)
|
|
|
|
wind_walk_vadtree(ctx, entry.left, address);
|
|
|
|
if (entry.right)
|
|
|
|
wind_walk_vadtree(ctx, entry.right, address);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
RList*
|
|
|
|
wind_list_process (WindCtx *ctx) {
|
|
|
|
RList *ret;
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 ptr, base;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ctx->plist_cache)
|
|
|
|
return ctx->plist_cache;
|
|
|
|
|
|
|
|
ptr = 0;
|
|
|
|
// Grab the PsActiveProcessHead from _KDDEBUGGER_DATA64
|
2015-09-23 14:17:19 +00:00
|
|
|
wind_read_at(ctx, (uint8_t *)&ptr, ctx->dbg_addr + K_PsActiveProcessHead,
|
|
|
|
4 << ctx->is_x64);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
base = ptr;
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("Process list head : 0x%016"PFMT64x"\n", ptr);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// Walk the LIST_ENTRY
|
|
|
|
wind_read_at(ctx, (uint8_t *)&ptr, ptr, 4 << ctx->is_x64);
|
|
|
|
|
|
|
|
ret = r_list_newf(free);
|
|
|
|
|
|
|
|
do {
|
|
|
|
uint8_t buf[17];
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 next;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
next = 0;
|
|
|
|
// Read the ActiveProcessLinks entry
|
|
|
|
wind_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
|
|
|
|
wind_read_at(ctx, (uint8_t *)&buf, ptr + O_(E_ImageFileName), 16);
|
|
|
|
buf[16] = '\0';
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 vadroot = 0;
|
|
|
|
ut64 uniqueid = 0;
|
|
|
|
ut64 peb = 0;
|
|
|
|
ut64 dir_base_table = 0;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
wind_read_at(ctx, (uint8_t *)&vadroot, ptr + O_(E_VadRoot), 4 << ctx->is_x64);
|
|
|
|
wind_read_at(ctx, (uint8_t *)&uniqueid, ptr + O_(E_UniqueProcessId), 4 << ctx->is_x64);
|
|
|
|
wind_read_at(ctx, (uint8_t *)&peb, ptr + O_(E_Peb), 4 << ctx->is_x64);
|
|
|
|
wind_read_at(ctx, (uint8_t *)&dir_base_table, ptr + O_(P_DirectoryTableBase), 4 << ctx->is_x64);
|
|
|
|
|
|
|
|
WindProc *proc = calloc(1, sizeof(WindProc));
|
|
|
|
|
2014-12-08 22:38:13 +00:00
|
|
|
strcpy(proc->name, (const char *)buf);
|
2014-08-31 16:09:25 +00:00
|
|
|
proc->vadroot = vadroot;
|
|
|
|
proc->uniqueid = uniqueid;
|
|
|
|
proc->dir_base_table = dir_base_table;
|
|
|
|
proc->peb = peb;
|
|
|
|
|
|
|
|
r_list_append(ret, proc);
|
|
|
|
|
|
|
|
// wind_walk_vadtree(ctx, vadroot, -1);
|
|
|
|
ptr = next;
|
|
|
|
} while(ptr != base);
|
|
|
|
|
|
|
|
ctx->plist_cache = ret;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
#define PTE_VALID 0x0001
|
|
|
|
#define PTE_LARGEPAGE 0x0080
|
|
|
|
#define PTE_PROTOTYPE 0x0400
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// 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
|
2015-10-01 16:33:37 +00:00
|
|
|
bool wind_va_to_pa (WindCtx *ctx, ut64 va, ut64 *pa) {
|
|
|
|
ut64 pml4i, pdpi, pdi, pti;
|
|
|
|
ut64 tmp, mask;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// We shouldn't really reach this
|
|
|
|
if (!ctx->target)
|
|
|
|
return 0;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("VA : %016"PFMT64x"\n", va);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (ctx->is_x64) {
|
|
|
|
pti = (va >> 12)&0x1ff;
|
|
|
|
pdi = (va >> 21)&0x1ff;
|
|
|
|
pdpi = (va >> 30)&0x1ff;
|
|
|
|
pml4i = (va >> 39)&0x1ff;
|
|
|
|
// Grab the PageFrameNumber field off the _HARDWARE_PTE entry
|
|
|
|
mask = 0x000000fffffff000;
|
|
|
|
} else {
|
|
|
|
if (ctx->pae) {
|
|
|
|
pti = (va >> 12)&0x1ff;
|
|
|
|
pdi = (va >> 21)&0x1ff;
|
|
|
|
pdpi = (va >> 30)&0x3;
|
|
|
|
pml4i = 0;
|
|
|
|
} else {
|
|
|
|
pti = (va >> 12)&0x3ff;
|
|
|
|
pdi = (va >> 22)&0x3ff;
|
|
|
|
pdpi = 0;
|
|
|
|
pml4i = 0;
|
|
|
|
}
|
|
|
|
// Grab the PageFrameNumber field off the _HARDWARE_PTE entry
|
|
|
|
mask = 0xfffff000;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = ctx->target->dir_base_table;
|
|
|
|
tmp &= ~0x1f;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("cr3 : %016"PFMT64x"\n", tmp);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (ctx->is_x64) {
|
|
|
|
// PML4 lookup
|
|
|
|
if (!wind_read_at_phys(ctx, (uint8_t *)&tmp, tmp + pml4i * 8, 8))
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
tmp &= mask;
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("PML4 : %016"PFMT64x"\n", tmp);
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ctx->pae) {
|
|
|
|
// PDPT lookup
|
|
|
|
if (!wind_read_at_phys(ctx, (uint8_t *)&tmp, tmp + pdpi * 8, 8))
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
tmp &= mask;
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("PDPE : %016"PFMT64x"\n", tmp);
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PDT lookup
|
|
|
|
if (!wind_read_at_phys(ctx, (uint8_t *)&tmp, tmp + pdi * (4 << ctx->pae), 4 << ctx->pae))
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
|
|
|
WIND_DBG eprintf("PDE : %016"PFMT64x"\n", tmp);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// Large page entry
|
|
|
|
// The page size differs between pae and non-pae systems, the former points to 2MB pages while
|
|
|
|
// the latter points to 4MB pages
|
|
|
|
if (tmp & PTE_LARGEPAGE) {
|
|
|
|
*pa = ctx->pae ?
|
|
|
|
(tmp&(~0x1fffff)) | (va&0x1fffff):
|
|
|
|
(tmp&(~0x3fffff)) | (va&0x3fffff);
|
2015-09-23 14:17:19 +00:00
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PT lookup
|
|
|
|
if (!wind_read_at_phys(ctx, (uint8_t *)&tmp, (tmp&mask) + pti * (4 << ctx->pae), 4 << ctx->pae))
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
|
|
|
WIND_DBG eprintf("PTE : %016"PFMT64x"\n", tmp);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (tmp & PTE_VALID) {
|
|
|
|
*pa = (tmp&mask) | (va&0xfff);
|
2015-09-23 14:17:19 +00:00
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp & PTE_PROTOTYPE) {
|
|
|
|
// TODO : prototype PTE support
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Prototype PTE lookup is currently missing!\n");
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
bool wind_read_ver (WindCtx *ctx) {
|
|
|
|
kd_req_t req = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
req.req = 0x3146;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req, sizeof(kd_req_t), NULL, 0);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
/* LOG_PKT(pkt); */
|
|
|
|
/* LOG_REQ(rr); */
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG {
|
|
|
|
eprintf("Major : %i Minor %i\n", rr->r_ver.major, rr->r_ver.minor);
|
|
|
|
eprintf("Protocol version : %i.%i\n", rr->r_ver.proto_major, rr->r_ver.proto_minor);
|
|
|
|
eprintf("Flags : %08x\n", rr->r_ver.flags);
|
|
|
|
eprintf("Machine : %08x\n", rr->r_ver.machine);
|
2015-10-04 21:47:54 +00:00
|
|
|
eprintf("Module list : %016"PFMT64x"\n", (ut64)rr->r_ver.mod_addr);
|
|
|
|
eprintf("Debug block : %016"PFMT64x"\n", (ut64)rr->r_ver.dbg_addr);
|
2015-09-23 14:17:19 +00:00
|
|
|
}
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (rr->r_ver.machine != KD_MACH_I386 && rr->r_ver.machine != KD_MACH_AMD64) {
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Unsupported target host\n");
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
if (!(rr->r_ver.flags & DBGKD_VERS_FLAG_DATA)) {
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("No _KDDEBUGGER_DATA64 pointer has been supplied by the debugee!\n");
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->is_x64 = (rr->r_ver.machine == KD_MACH_AMD64);
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
ut64 ptr = 0;
|
2014-08-31 16:09:25 +00:00
|
|
|
if (!wind_read_at(ctx, (uint8_t *)&ptr, rr->r_ver.dbg_addr, 4 << ctx->is_x64)) {
|
|
|
|
free(pkt);
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx->dbg_addr = ptr;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("_KDDEBUGGER_DATA64 at 0x%016"PFMT64x"\n", ctx->dbg_addr);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// Thanks to this we don't have to find a way to read the cr4
|
|
|
|
uint16_t pae_enabled;
|
2015-09-23 14:17:19 +00:00
|
|
|
if (!wind_read_at (ctx, (uint8_t *)&pae_enabled, ctx->dbg_addr + K_PaeEnabled, sizeof(uint16_t))) {
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Grab the CmNtCSDVersion field to extract the Service Pack number
|
|
|
|
wind_read_at(ctx, (uint8_t *)&ptr, ctx->dbg_addr + K_CmNtCSDVersion, 8);
|
|
|
|
wind_read_at(ctx, (uint8_t *)&ptr, ptr, 4 << ctx->is_x64);
|
|
|
|
|
|
|
|
ctx->pae = pae_enabled&1;
|
|
|
|
ctx->os_profile = wind_get_profile(32 << ctx->is_x64, rr->r_ver.minor, (ptr >> 8)&0xff);
|
|
|
|
if (!ctx->os_profile) {
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Could not find a suitable profile for the target OS\n");
|
2015-09-23 14:17:19 +00:00
|
|
|
free (pkt);
|
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
2015-09-23 14:17:19 +00:00
|
|
|
free (pkt);
|
|
|
|
return true;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
int wind_sync (WindCtx *ctx) {
|
2014-08-31 16:09:25 +00:00
|
|
|
int ret;
|
|
|
|
kd_packet_t *s;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Send the breakin packet
|
2014-12-09 16:45:44 +00:00
|
|
|
if (iob_write (ctx->io_ptr, (const uint8_t*)"b", 1) != 1)
|
|
|
|
return 0;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// Reset the host
|
|
|
|
ret = kd_send_ctrl_packet(ctx->io_ptr, KD_PACKET_TYPE_RESET, 0);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Wait for the response
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_RESET, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Syncronize with the first KD_PACKET_TYPE_STATE_CHANGE packet
|
|
|
|
wind_wait_packet(ctx, KD_PACKET_TYPE_STATE_CHANGE, &s);
|
|
|
|
|
|
|
|
// Reset the sequence id
|
|
|
|
ctx->seq_id = 0x80800001;
|
|
|
|
|
|
|
|
ctx->cpu = PKT_STC(s)->cpu;
|
|
|
|
ctx->cpu_count = PKT_STC(s)->cpu_count;
|
|
|
|
ctx->target = NULL;
|
|
|
|
ctx->plist_cache = NULL;
|
|
|
|
ctx->pae = 0;
|
|
|
|
// We're ready to go
|
|
|
|
ctx->syncd = 1;
|
|
|
|
|
|
|
|
free(s);
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("Sync done! (%i cpus found)\n", ctx->cpu_count);
|
2014-08-31 16:09:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
int wind_continue (WindCtx *ctx) {
|
|
|
|
kd_req_t req = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
req.req = 0x313C;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
req.r_cont.reason = 0x10001;
|
2015-09-23 14:17:19 +00:00
|
|
|
// The meaning of 0x400 is unknown, but Windows doesn't
|
|
|
|
// behave like suggested by ReactOS source
|
2014-08-31 16:09:25 +00:00
|
|
|
req.r_cont.tf = 0x400;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf ("Sending continue...\n");
|
|
|
|
|
|
|
|
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req, sizeof (kd_req_t), NULL, 0);
|
|
|
|
if (ret == KD_E_OK) {
|
|
|
|
ret = wind_wait_packet (ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret == KD_E_OK) {
|
|
|
|
r_list_free (ctx->plist_cache);
|
|
|
|
ctx->plist_cache = NULL;
|
|
|
|
WIND_DBG eprintf ("Done!\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
bool wind_write_reg (WindCtx *ctx, const uint8_t *buf, int size) {
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
2015-09-23 14:17:19 +00:00
|
|
|
kd_req_t req = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
2015-09-23 14:17:19 +00:00
|
|
|
return false;
|
2014-08-31 16:09:25 +00:00
|
|
|
req.req = 0x3133;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
req.r_ctx.flags = 0x1003F;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("Regwrite() size : %x\n", size);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req, sizeof(kd_req_t), buf, size);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
free (pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
wind_read_reg (WindCtx *ctx, uint8_t *buf, int size) {
|
|
|
|
kd_req_t req;
|
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(kd_req_t));
|
|
|
|
|
|
|
|
req.req = 0x3132;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
|
|
|
|
req.r_ctx.flags = 0x1003F;
|
|
|
|
|
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP, (ctx->seq_id ^= 1), (uint8_t *)&req,
|
|
|
|
sizeof(kd_req_t), NULL, 0);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, rr->data, size);
|
|
|
|
|
|
|
|
free(pkt);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2015-10-01 16:33:37 +00:00
|
|
|
wind_query_mem (WindCtx *ctx, const ut64 addr, int *address_space, int *flags) {
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_req_t req;
|
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(kd_req_t));
|
|
|
|
|
|
|
|
req.req = 0x315c;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
|
|
|
|
req.r_query_mem.addr = addr;
|
|
|
|
req.r_query_mem.address_space = 0; // Tells the kernel that 'addr' is a virtual address
|
|
|
|
|
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP, (ctx->seq_id ^= 1), (uint8_t *)&req,
|
|
|
|
sizeof(kd_req_t), NULL, 0);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
|
|
|
#ifdef WIND_LOG
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
#endif
|
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (address_space)
|
|
|
|
*address_space = rr->r_query_mem.address_space;
|
|
|
|
if (flags)
|
|
|
|
*flags = rr->r_query_mem.flags;
|
|
|
|
|
|
|
|
free(pkt);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
int wind_bkpt (WindCtx *ctx, const ut64 addr, const int set, const int hw, int *handle) {
|
2015-04-07 12:47:20 +00:00
|
|
|
kd_req_t req = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
req.req = set? 0x3134: 0x3135;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
if (set) req.r_set_bp.addr = addr;
|
|
|
|
else req.r_del_bp.handle = *handle;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
ret = kd_send_data_packet (ctx->io_ptr, KD_PACKET_TYPE_MANIP, (ctx->seq_id ^= 1), (uint8_t *)&req,
|
2014-08-31 16:09:25 +00:00
|
|
|
sizeof(kd_req_t), NULL, 0);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
|
|
|
#ifdef WIND_LOG
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
#endif
|
2015-04-07 12:47:20 +00:00
|
|
|
free (pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*handle = rr->r_set_bp.handle;
|
|
|
|
ret = !!rr->ret;
|
2015-04-07 12:47:20 +00:00
|
|
|
free (pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
int wind_read_at_phys (WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
2015-09-23 14:17:19 +00:00
|
|
|
kd_req_t req = {0}, *rr;
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
req.req = 0x313D;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
req.r_mem.addr = offset;
|
|
|
|
req.r_mem.length = R_MIN(count, KD_MAX_PAYLOAD);
|
|
|
|
req.r_mem.read = 0; // Default caching option
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP, (ctx->seq_id ^= 1),
|
|
|
|
(uint8_t *)&req, sizeof(kd_req_t), NULL, 0);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
rr = PKT_REQ(pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
|
|
|
#ifdef WIND_LOG
|
2015-04-07 12:47:20 +00:00
|
|
|
eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
#endif
|
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, rr->data, rr->r_mem.read);
|
|
|
|
ret = rr->r_mem.read;
|
|
|
|
free(pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
int wind_read_at (WindCtx *ctx, uint8_t *buf, const ut64 offset, const int count) {
|
2015-04-07 12:47:20 +00:00
|
|
|
kd_req_t *rr, req = {0};
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
req.req = 0x3130;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
req.r_mem.addr = offset;
|
|
|
|
req.r_mem.length = R_MIN(count, KD_MAX_PAYLOAD);
|
2015-04-07 12:47:20 +00:00
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req, sizeof(kd_req_t), NULL, 0);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
2015-04-07 12:47:20 +00:00
|
|
|
rr = PKT_REQ(pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf, rr->data, rr->r_mem.read);
|
|
|
|
ret = rr->r_mem.read;
|
2015-04-07 12:47:20 +00:00
|
|
|
free (pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-10-01 16:33:37 +00:00
|
|
|
int wind_write_at (WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
2015-04-07 12:47:20 +00:00
|
|
|
kd_req_t req = {0}, *rr;
|
|
|
|
int payload, ret;
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
payload = R_MIN (count, KD_MAX_PAYLOAD - sizeof(kd_req_t));
|
2014-08-31 16:09:25 +00:00
|
|
|
req.req = 0x3131;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
req.r_mem.addr = offset;
|
|
|
|
req.r_mem.length = payload;
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req,
|
|
|
|
sizeof(kd_req_t), buf, payload);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
2015-04-07 12:47:20 +00:00
|
|
|
rr = PKT_REQ(pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 13:59:56 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
2014-08-31 16:09:25 +00:00
|
|
|
free(pkt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = rr->r_mem.read;
|
|
|
|
free(pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2015-10-01 16:33:37 +00:00
|
|
|
wind_write_at_phys (WindCtx *ctx, const uint8_t *buf, const ut64 offset, const int count) {
|
2014-08-31 16:09:25 +00:00
|
|
|
kd_packet_t *pkt;
|
|
|
|
kd_req_t req;
|
|
|
|
int ret;
|
|
|
|
int payload;
|
|
|
|
|
|
|
|
if (!ctx || !ctx->io_ptr || !ctx->syncd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
payload = R_MIN(count, KD_MAX_PAYLOAD - sizeof(kd_req_t));
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(kd_req_t));
|
|
|
|
|
|
|
|
req.req = 0x313e;
|
|
|
|
req.cpu = ctx->cpu;
|
|
|
|
|
|
|
|
req.r_mem.addr = offset;
|
|
|
|
req.r_mem.length = payload;
|
|
|
|
req.r_mem.read = 0; // Default caching option
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
ret = kd_send_data_packet(ctx->io_ptr, KD_PACKET_TYPE_MANIP,
|
|
|
|
(ctx->seq_id ^= 1), (uint8_t *)&req, sizeof(kd_req_t), buf, payload);
|
2014-08-31 16:09:25 +00:00
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_ACK, NULL);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = wind_wait_packet(ctx, KD_PACKET_TYPE_MANIP, &pkt);
|
|
|
|
if (ret != KD_E_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
kd_req_t *rr = PKT_REQ(pkt);
|
|
|
|
|
|
|
|
// LOG_PKT(pkt);
|
|
|
|
// LOG_REQ(rr);
|
|
|
|
|
|
|
|
if (rr->ret) {
|
2015-09-23 14:17:19 +00:00
|
|
|
WIND_DBG eprintf("%s : req returned %08x\n", __FUNCTION__, rr->ret);
|
|
|
|
free (pkt);
|
2014-08-31 16:09:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = rr->r_mem.read;
|
|
|
|
free(pkt);
|
|
|
|
return ret;
|
|
|
|
}
|
2015-04-22 13:53:45 +00:00
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
bool wind_break (WindCtx *ctx) {
|
|
|
|
return (iob_write (ctx->io_ptr, (const uint8_t*)"b", 1) == 1);
|
2015-04-22 13:53:45 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 14:17:19 +00:00
|
|
|
int wind_break_read (WindCtx *ctx) {
|
2015-04-22 13:53:45 +00:00
|
|
|
#if __WINDOWS__
|
2015-05-05 16:08:01 +00:00
|
|
|
static BOOL WINAPI (*w32_CancelIoEx)(HANDLE, LPOVERLAPPED) = NULL;
|
|
|
|
if (!w32_CancelIoEx) {
|
|
|
|
HANDLE lib;
|
|
|
|
lib = LoadLibrary ("psapi.dll");
|
|
|
|
w32_CancelIoEx = (BOOL WINAPI (*)(HANDLE, LPOVERLAPPED))
|
|
|
|
GetProcAddress (GetModuleHandle ("kernel32"),
|
|
|
|
"CancelIoEx");
|
|
|
|
}
|
|
|
|
if (w32_CancelIoEx)
|
|
|
|
w32_CancelIoEx(ctx->io_ptr,NULL);
|
2015-04-22 13:53:45 +00:00
|
|
|
#endif
|
|
|
|
return 1;
|
|
|
|
}
|