Skip to content

Commit

Permalink
Version 3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ufrisk committed Mar 12, 2018
1 parent f321f2c commit de6ce1f
Show file tree
Hide file tree
Showing 34 changed files with 7,047 additions and 3,944 deletions.
2 changes: 1 addition & 1 deletion pcileech/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ LOCAL_CFLAGS := -D ANDROID
LOCAL_LDLIBS := -L$(LOCAL_PATH)/lib -llog -g

LOCAL_C_INCLUDES := bionic
LOCAL_SRC_FILES:= pcileech.c oscompatibility.c device.c device3380.c devicefpga.c device605_tcp.c executor.c extra.c help.c kmd.c memdump.c mempatch.c statistics.c tlp.c util.c vfs.c
LOCAL_SRC_FILES:= pcileech.c oscompatibility.c device.c device3380.c devicefile.c devicefpga.c device605_tcp.c executor.c extra.c help.c kmd.c memdump.c mempatch.c statistics.c tlp.c util.c vfs.c vmm.c vmmproc.c

LOCAL_MODULE := pcileech
LOCAL_SHARED_LIBRARIES += libusb1.0
Expand Down
2 changes: 1 addition & 1 deletion pcileech/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC=gcc
CFLAGS=-I. -D LINUX -pthread `pkg-config libusb-1.0 --libs --cflags`
DEPS = pcileech.h
OBJ = pcileech oscompatibility.o pcileech.o device.o device3380.o devicefpga.o device605_tcp.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o tlp.o util.o vfs.o
OBJ = pcileech oscompatibility.o pcileech.o device.o device3380.o devicefile.o devicefpga.o device605_tcp.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o tlp.o util.o vfs.o vmm.o vmmproc.o

%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
Expand Down
305 changes: 178 additions & 127 deletions pcileech/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,178 +7,229 @@
#include "kmd.h"
#include "statistics.h"
#include "device3380.h"
#include "devicefile.h"
#include "devicefpga.h"
#include "device605_tcp.h"

typedef struct tdREAD_DMA_EX_MEMORY_MAP {
BOOL fProbeExecuted;
QWORD qwAddrBase;
DWORD cPages;
PBYTE pb;
} READ_DMA_EX_MEMORY_MAP, *PREAD_DMA_EX_MEMORY_MAP;

BOOL DeviceReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags)
{
if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) {
return DeviceReadDMA(ctx, qwAddr, pb, cb, 0) || DeviceReadDMA(ctx, qwAddr, pb, cb, 0);
}
return ctx->cfg->dev.pfnReadDMA ? ctx->cfg->dev.pfnReadDMA(ctx, qwAddr, pb, cb) : FALSE;
BOOL result;
DMA_IO_SCATTER_HEADER pDMAs[0x30], *ppDMAs[0x30];
DWORD cDMAs, cDMAsSuccess, o;
// 1: Prefer scatter DMA (if existing)
if(ctx->cfg->dev.pfnReadScatterDMA) {
if((cb > ctx->cfg->dev.qwAddrMaxNative) || (cb > 0x24000)) { return FALSE; }
ZeroMemory(pDMAs, 0x30 * sizeof(DMA_IO_SCATTER_HEADER));
for(cDMAs = 0, o = 0; o < cb; cDMAs++, o += 0x1000) {
pDMAs[cDMAs].qwA = qwAddr + o;
pDMAs[cDMAs].cbMax = min(0x1000, cb - o);
pDMAs[cDMAs].pb = pb + o;
ppDMAs[cDMAs] = pDMAs + cDMAs;
}
DeviceReadScatterDMA(ctx, ppDMAs, cDMAs, &cDMAsSuccess);
return (cDMAsSuccess == cDMAs);
}
// 2: Standard DMA
if(!ctx->cfg->dev.pfnReadDMA) { return FALSE; }
if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) {
return DeviceReadDMA(ctx, qwAddr, pb, cb, 0) || DeviceReadDMA(ctx, qwAddr, pb, cb, 0);
}
EnterCriticalSection(&ctx->cfg->dev.LockDMA);
result = ctx->cfg->dev.pfnReadDMA(ctx, qwAddr, pb, cb);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
return result;
}

BOOL DeviceReadScatterDMA(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pcpDMAsRead)
{
if(!ctx->cfg->dev.pfnReadScatterDMA) { return FALSE; }
EnterCriticalSection(&ctx->cfg->dev.LockDMA);
ctx->cfg->dev.pfnReadScatterDMA(ctx, ppDMAs, cpDMAs, pcpDMAsRead);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
return TRUE;
}

BOOL DeviceReadDMAEx_IsMemoryMapOK(_In_ PREAD_DMA_EX_MEMORY_MAP pMemoryMap, _In_ QWORD qwAddr, _In_ DWORD dwSize)
DWORD DeviceReadDMAEx_DoWork_Scatter(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat)
{
DWORD i;
DWORD cPages = (dwSize + 0xfff) / 0x1000;
DWORD cPageStart = (DWORD)(((qwAddr + 0xfff) - pMemoryMap->qwAddrBase) / 0x1000);
for(i = cPageStart; i < cPageStart + cPages; i++) {
if(0 == pMemoryMap->pb[i]) {
return FALSE;
}
}
return TRUE;
PBYTE pbBuffer;
PDMA_IO_SCATTER_HEADER pDMAs, *ppDMAs;
DWORD i, o, cDMAs, cDMAsRead;
cDMAs = cb >> 12;
pbBuffer = (PBYTE)LocalAlloc(LMEM_ZEROINIT, cDMAs * (sizeof(PDMA_IO_SCATTER_HEADER) + sizeof(DMA_IO_SCATTER_HEADER)));
if(!pbBuffer) { return 0; }
ppDMAs = (PDMA_IO_SCATTER_HEADER*)pbBuffer;
pDMAs = (PDMA_IO_SCATTER_HEADER)(pbBuffer + cDMAs * sizeof(PDMA_IO_SCATTER_HEADER));
for(i = 0, o = 0; i < cDMAs; i++, o += 0x1000) {
ppDMAs[i] = pDMAs + i;
pDMAs[i].qwA = qwAddr + o;
pDMAs[i].cbMax = min(0x1000, cb - o);
pDMAs[i].pb = pb + o;
}
DeviceReadScatterDMA(ctx, ppDMAs, cDMAs, &cDMAsRead);
for(i = 0; i < cDMAs; i++) {
if(pDMAs[i].cb == 0x1000) {
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 1, 0);
} else {
PageStatUpdate(pPageStat, pDMAs[i].qwA + 0x1000, 0, 1);
ZeroMemory(pDMAs[i].pb, 0x1000);
}
}
LocalFree(pbBuffer);
return cDMAsRead << 12;
}

#define CHUNK_FAIL_DIVISOR 16
DWORD DeviceReadDMAEx_DoWork(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat, _In_ DWORD cbMaxSizeIo, _Inout_ PREAD_DMA_EX_MEMORY_MAP pMemoryMap, _In_ QWORD flags)
#define CHUNK_FAIL_DIVISOR 16
DWORD DeviceReadDMAEx_DoWork(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat, _In_ DWORD cbMaxSizeIo, _In_ QWORD flags)
{
DWORD cbRd, cbRdOff;
DWORD cbChunk, cChunkTotal, cChunkSuccess = 0;
DWORD i, cbSuccess = 0;
BOOL result;
// calculate current chunk sizes
cbChunk = ~0xfff & min(cb, cbMaxSizeIo);
cbChunk = (cbChunk > 0x3000) ? cbChunk : 0x1000;
cChunkTotal = (cb / cbChunk) + ((cb % cbChunk) ? 1 : 0);
// try read memory
memset(pb, 0, cb);
for(i = 0; i < cChunkTotal; i++) {
cbRdOff = i * cbChunk;
cbRd = ((i == cChunkTotal - 1) && (cb % cbChunk)) ? (cb % cbChunk) : cbChunk; // (last chunk may be smaller)
result =
DeviceReadDMAEx_IsMemoryMapOK(pMemoryMap, qwAddr + cbRdOff, cbRd) &&
DeviceReadDMA(ctx, qwAddr + cbRdOff, pb + cbRdOff, cbRd, 0);
if(!result && !pMemoryMap->fProbeExecuted && ctx->cfg->dev.pfnProbeDMA) { // probe memory on 1st fail (if supported)
memset(pMemoryMap->pb, 0, pMemoryMap->cPages);
DeviceProbeDMA(ctx, pMemoryMap->qwAddrBase, pMemoryMap->cPages, pMemoryMap->pb);
pMemoryMap->fProbeExecuted = TRUE;
}
if(result) {
cbSuccess += cbRd;
PageStatUpdate(pPageStat, qwAddr + cbRdOff + cbRd, cbRd / 0x1000, 0);
} else if(flags & PCILEECH_FLAG_MEM_EX_FASTFAIL) {
PageStatUpdate(pPageStat, qwAddr + cb, 0, (cb - cbRdOff) / 0x1000);
return cbSuccess;
} else if(cbRd == 0x1000) {
ZeroMemory(pb + cbRdOff, cbRd);
PageStatUpdate(pPageStat, qwAddr + cbRdOff + cbRd, 0, 1);
} else {
cbSuccess += DeviceReadDMAEx_DoWork(ctx, qwAddr + cbRdOff, pb + cbRdOff, cbRd, pPageStat, cbRd / CHUNK_FAIL_DIVISOR, pMemoryMap, flags);
}
}
return cbSuccess;
DWORD cbRd, cbRdOff;
DWORD cbChunk, cChunkTotal, cChunkSuccess = 0;
DWORD i, cbSuccess = 0;
BOOL result;
// calculate current chunk sizes
cbChunk = ~0xfff & min(cb, cbMaxSizeIo);
cbChunk = (cbChunk > 0x3000) ? cbChunk : 0x1000;
cChunkTotal = (cb / cbChunk) + ((cb % cbChunk) ? 1 : 0);
// try read memory
memset(pb, 0, cb);
for(i = 0; i < cChunkTotal; i++) {
cbRdOff = i * cbChunk;
cbRd = ((i == cChunkTotal - 1) && (cb % cbChunk)) ? (cb % cbChunk) : cbChunk; // (last chunk may be smaller)
if(ctx->cfg->dev.fScatterReadSupported) {
// scatter read, if available
cbSuccess = DeviceReadDMAEx_DoWork_Scatter(ctx, qwAddr + cbRdOff, pb + cbRdOff, cbRd, pPageStat);
} else {
// traditional read
result = DeviceReadDMA(ctx, qwAddr + cbRdOff, pb + cbRdOff, cbRd, 0);
if(result) {
cbSuccess += cbRd;
PageStatUpdate(pPageStat, qwAddr + cbRdOff + cbRd, cbRd / 0x1000, 0);
} else if(flags & PCILEECH_FLAG_MEM_EX_FASTFAIL) {
PageStatUpdate(pPageStat, qwAddr + cb, 0, (cb - cbRdOff) / 0x1000);
return cbSuccess;
} else if(cbRd == 0x1000) {
ZeroMemory(pb + cbRdOff, cbRd);
PageStatUpdate(pPageStat, qwAddr + cbRdOff + cbRd, 0, 1);
} else {
cbSuccess += DeviceReadDMAEx_DoWork(ctx, qwAddr + cbRdOff, pb + cbRdOff, cbRd, pPageStat, cbRd / CHUNK_FAIL_DIVISOR, flags);
}
}
}
return cbSuccess;
}

DWORD DeviceReadDMAEx(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD flags)
{
READ_DMA_EX_MEMORY_MAP oMemoryMap;
BYTE pbWorkaround[4096];
DWORD cbDataRead;
// set probe memory map to all mem readable
oMemoryMap.fProbeExecuted = FALSE;
oMemoryMap.qwAddrBase = qwAddr & ~0xfff;
oMemoryMap.cPages = (cb + 0xfff) / 0x1000;
oMemoryMap.pb = LocalAlloc(0, oMemoryMap.cPages);
if(!oMemoryMap.pb) { return 0; }
memset(oMemoryMap.pb, 0x01, oMemoryMap.cPages);
// read memory (with strange workaround for 1-page reads...)
if(cb != 0x1000) {
cbDataRead = DeviceReadDMAEx_DoWork(ctx, qwAddr, pb, cb, pPageStat, (DWORD)ctx->cfg->qwMaxSizeDmaIo, &oMemoryMap, flags);
} else {
// why is this working ??? if not here console is screwed up... (threading issue?)
cbDataRead = DeviceReadDMAEx_DoWork(ctx, qwAddr, pbWorkaround, 0x1000, pPageStat, (DWORD)ctx->cfg->qwMaxSizeDmaIo, &oMemoryMap, flags);
memcpy(pb, pbWorkaround, 0x1000);
}
LocalFree(oMemoryMap.pb);
return cbDataRead;
BYTE pbWorkaround[4096];
DWORD cbDataRead;
// read memory (with strange workaround for 1-page reads...)
if(cb != 0x1000) {
cbDataRead = DeviceReadDMAEx_DoWork(ctx, qwAddr, pb, cb, pPageStat, (DWORD)ctx->cfg->qwMaxSizeDmaIo, flags);
} else {
// why is this working ??? if not here console is screwed up... (threading issue?)
cbDataRead = DeviceReadDMAEx_DoWork(ctx, qwAddr, pbWorkaround, 0x1000, pPageStat, (DWORD)ctx->cfg->qwMaxSizeDmaIo, flags);
memcpy(pb, pbWorkaround, 0x1000);
}
return cbDataRead;
}

BOOL DeviceWriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags)
{
PBYTE pbV;
BOOL result = FALSE;
if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) {
return DeviceWriteDMA(ctx, qwAddr, pb, cb, 0) || DeviceWriteDMA(ctx, qwAddr, pb, cb, 0);
}
result = ctx->cfg->dev.pfnWriteDMA ? ctx->cfg->dev.pfnWriteDMA(ctx, qwAddr, pb, cb) : FALSE;
if(!result) { return FALSE; }
if(flags & PCILEECH_MEM_FLAG_VERIFYWRITE) {
pbV = LocalAlloc(0, cb + 0x2000);
if(!pbV) { return FALSE; }
result =
DeviceReadDMA(ctx, qwAddr & ~0xfff, pbV, (cb + 0xfff + (qwAddr & 0xfff)) & ~0xfff, flags) &&
(0 == memcmp(pb, pbV + (qwAddr & 0xfff), cb));
LocalFree(pbV);
}
return result;
PBYTE pbV;
BOOL result = FALSE;
if(!ctx->cfg->dev.pfnWriteDMA) { return FALSE; }
if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) {
return DeviceWriteDMA(ctx, qwAddr, pb, cb, 0) || DeviceWriteDMA(ctx, qwAddr, pb, cb, 0);
}
EnterCriticalSection(&ctx->cfg->dev.LockDMA);
result = ctx->cfg->dev.pfnWriteDMA(ctx, qwAddr, pb, cb);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
if(!result) { return FALSE; }
if(flags & PCILEECH_MEM_FLAG_VERIFYWRITE) {
pbV = LocalAlloc(0, cb + 0x2000);
if(!pbV) { return FALSE; }
result =
DeviceReadDMA(ctx, qwAddr & ~0xfff, pbV, (cb + 0xfff + (qwAddr & 0xfff)) & ~0xfff, flags) &&
(0 == memcmp(pb, pbV + (qwAddr & 0xfff), cb));
LocalFree(pbV);
}
return result;
}

BOOL DeviceProbeDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ DWORD cPages, _Inout_ __bcount(cPages) PBYTE pbResultMap)
{
if(!ctx->cfg->dev.pfnProbeDMA) { return FALSE; }
ctx->cfg->dev.pfnProbeDMA(ctx, qwAddr, cPages, pbResultMap);
return TRUE;
if(!ctx->cfg->dev.pfnProbeDMA) { return FALSE; }
EnterCriticalSection(&ctx->cfg->dev.LockDMA);
ctx->cfg->dev.pfnProbeDMA(ctx, qwAddr, cPages, pbResultMap);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
return TRUE;
}

BOOL DeviceWriteTlp(_Inout_ PPCILEECH_CONTEXT ctx, _In_ PBYTE pb, _In_ DWORD cb)
{
if(!ctx->cfg->dev.pfnWriteTlp) { return FALSE; }
return ctx->cfg->dev.pfnWriteTlp(ctx, pb, cb);
BOOL result;
if(!ctx->cfg->dev.pfnWriteTlp) { return FALSE; }
EnterCriticalSection(&ctx->cfg->dev.LockDMA);
result = ctx->cfg->dev.pfnWriteTlp(ctx, pb, cb);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
return result;
}

BOOL DeviceListenTlp(_Inout_ PPCILEECH_CONTEXT ctx, _In_ DWORD dwTime)
{
if(!ctx->cfg->dev.pfnListenTlp) { return FALSE; }
return ctx->cfg->dev.pfnListenTlp(ctx, dwTime);
BOOL result;
if(!ctx->cfg->dev.pfnListenTlp) { return FALSE; }
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
result = ctx->cfg->dev.pfnListenTlp(ctx, dwTime);
LeaveCriticalSection(&ctx->cfg->dev.LockDMA);
return result;
}

VOID DeviceClose(_Inout_ PPCILEECH_CONTEXT ctx)
{
if(ctx->hDevice && ctx->cfg->dev.pfnClose) {
ctx->cfg->dev.pfnClose(ctx);
}
if(ctx->hDevice && ctx->cfg->dev.pfnClose) {
DeleteCriticalSection(&ctx->cfg->dev.LockDMA);
ctx->cfg->dev.pfnClose(ctx);
}
}

BOOL DeviceOpen(_Inout_ PPCILEECH_CONTEXT ctx)
{
BOOL result = FALSE;
if(PCILEECH_DEVICE_USB3380 == ctx->cfg->dev.tp || PCILEECH_DEVICE_NA == ctx->cfg->dev.tp) {
result = Device3380_Open(ctx);
}
if(PCILEECH_DEVICE_FPGA == ctx->cfg->dev.tp || PCILEECH_DEVICE_NA == ctx->cfg->dev.tp) {
result = DeviceFPGA_Open(ctx);
}
if(PCILEECH_DEVICE_SP605_TCP == ctx->cfg->dev.tp) {
result = Device605_TCP_Open(ctx);
}
return result;
BOOL result = FALSE;
if(PCILEECH_DEVICE_USB3380 == ctx->cfg->dev.tp || PCILEECH_DEVICE_NA == ctx->cfg->dev.tp) {
result = Device3380_Open(ctx);
}
if(PCILEECH_DEVICE_FPGA == ctx->cfg->dev.tp || PCILEECH_DEVICE_NA == ctx->cfg->dev.tp) {
result = DeviceFPGA_Open(ctx);
}
if(PCILEECH_DEVICE_SP605_TCP == ctx->cfg->dev.tp) {
result = Device605_TCP_Open(ctx);
}
if(PCILEECH_DEVICE_FILE == ctx->cfg->dev.tp) {
result = DeviceFile_Open(ctx);
}
if(result) {
ctx->cfg->dev.fScatterReadSupported = (ctx->cfg->dev.pfnReadScatterDMA != NULL);
InitializeCriticalSection(&ctx->cfg->dev.LockDMA);
}
return result;
}

BOOL DeviceWriteMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags)
{
if(ctx->phKMD) {
return KMDWriteMemory(ctx, qwAddr, pb, cb);
} else {
return DeviceWriteDMA(ctx, qwAddr, pb, cb, flags);
}
if(ctx->phKMD) {
return KMDWriteMemory(ctx, qwAddr, pb, cb);
} else {
return DeviceWriteDMA(ctx, qwAddr, pb, cb, flags);
}
}

BOOL DeviceReadMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags)
{
if(ctx->phKMD) {
return KMDReadMemory(ctx, qwAddr, pb, cb);
} else if(flags || cb == 0x1000) {
return DeviceReadDMA(ctx, qwAddr, pb, cb, flags);
} else {
return cb == DeviceReadDMAEx(ctx, qwAddr, pb, cb, NULL, 0);
}
if(ctx->phKMD) {
return KMDReadMemory(ctx, qwAddr, pb, cb);
} else if(flags || cb == 0x1000) {
return DeviceReadDMA(ctx, qwAddr, pb, cb, flags);
} else {
return cb == DeviceReadDMAEx(ctx, qwAddr, pb, cb, NULL, 0);
}
}
Loading

0 comments on commit de6ce1f

Please sign in to comment.