From 8f3f9ce0f3086ae7ec9ea5fed48ad8d95f312f62 Mon Sep 17 00:00:00 2001 From: Synacktiv Date: Thu, 3 Jan 2019 18:23:46 +0100 Subject: [PATCH] Add Raw TCP device (#77) --- pcileech/Makefile | 2 +- pcileech/device.c | 4 + pcileech/devicerawtcp.c | 265 ++++++++++++++++++++++++++++++++++++++++ pcileech/devicerawtcp.h | 16 +++ pcileech/pcileech.c | 2 + pcileech/pcileech.h | 3 +- 6 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 pcileech/devicerawtcp.c create mode 100644 pcileech/devicerawtcp.h diff --git a/pcileech/Makefile b/pcileech/Makefile index cb078d2..84dd182 100644 --- a/pcileech/Makefile +++ b/pcileech/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-I. -D LINUX -pthread `pkg-config libusb-1.0 --libs --cflags` DEPS = pcileech.h -OBJ = pcileech oscompatibility.o pcileech.o device.o device3380.o devicefile.o devicefpga.o device605_tcp.o devicetmd.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o tlp.o util.o vfs.o vmm.o vmmproc.o +OBJ = pcileech oscompatibility.o pcileech.o device.o device3380.o devicefile.o devicefpga.o device605_tcp.o devicerawtcp.o devicetmd.o executor.o extra.o help.o kmd.o memdump.o mempatch.o statistics.o tlp.o util.o vfs.o vmm.o vmmproc.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/pcileech/device.c b/pcileech/device.c index e45f188..040d021 100644 --- a/pcileech/device.c +++ b/pcileech/device.c @@ -11,6 +11,7 @@ #include "devicefpga.h" #include "device605_tcp.h" #include "devicetmd.h" +#include "devicerawtcp.h" BOOL DeviceReadDMA(_Inout_ PPCILEECH_CONTEXT ctx, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb, _In_ QWORD flags) { @@ -211,6 +212,9 @@ BOOL DeviceOpen(_Inout_ PPCILEECH_CONTEXT ctx) if(PCILEECH_DEVICE_TOTALMELTDOWN == ctx->cfg->dev.tp) { result = DeviceTMD_Open(ctx); } + if(PCILEECH_DEVICE_RAW_TCP == ctx->cfg->dev.tp) { + result = DeviceRawTCP_Open(ctx); + } if(result) { ctx->cfg->dev.fScatterReadSupported = (ctx->cfg->dev.pfnReadScatterDMA != NULL); InitializeCriticalSection(&ctx->cfg->dev.LockDMA); diff --git a/pcileech/devicerawtcp.c b/pcileech/devicerawtcp.c new file mode 100644 index 0000000..0390023 --- /dev/null +++ b/pcileech/devicerawtcp.c @@ -0,0 +1,265 @@ +// devicerawtcp.c : implementation related to dummy device backed by a TCP service. +// + +#ifdef WIN32 + +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +#else + +#include +#include +#include + +#define SOCKET int + +#define closesocket(_s_) close((_s_)) + +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 + +#endif + +#ifdef WIN32 +#include +#endif + +#ifdef WIN32 +#include +#endif + +#include "devicerawtcp.h" +#include "device.h" +#include "util.h" + +#define RAWTCP_MAX_SIZE_RX 0x1000000 +#define RAWTCP_MAX_SIZE_TX 0x100000 + +#define DEFAULT_PORT 8888 + +typedef struct tdDEVICE_CONTEXT_RAWTCP { + SOCKET Sock; + struct { + PBYTE pb; + DWORD cb; + DWORD cbMax; + } rxbuf; + struct { + PBYTE pb; + DWORD cb; + DWORD cbMax; + } txbuf; +} DEVICE_CONTEXT_RAWTCP, *PDEVICE_CONTEXT_RAWTCP; + +typedef struct tdRAWTCP_PROTO_PACKET { + RawTCPCmd cmd; + QWORD addr; + QWORD cb; +} RAWTCP_PROTO_PACKET, *PRAWTCP_PROTO_PACKET; + +SOCKET DeviceRawTCP_Connect(_In_ DWORD Addr, _In_ WORD Port) +{ + SOCKET Sock = 0; + struct sockaddr_in sAddr; + sAddr.sin_family = AF_INET; + sAddr.sin_port = htons(Port); + sAddr.sin_addr.s_addr = Addr; + if ((Sock = socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) { + if (connect(Sock, (struct sockaddr *)&sAddr, sizeof(sAddr)) != SOCKET_ERROR) { return Sock; } + fprintf(stderr, "ERROR: connect() fails\n"); + closesocket(Sock); + } + else { + fprintf(stderr, "ERROR: socket() fails\n"); + } + return 0; +} + +BOOL DeviceRawTCP_Status(_In_ PDEVICE_CONTEXT_RAWTCP ctxrawtcp) +{ + RAWTCP_PROTO_PACKET Rx = {0}, Tx = {0}; + DWORD cbRead; + BYTE ready; + DWORD len; + + Tx.cmd = STATUS; + + if (send(ctxrawtcp->Sock, (const char *)&Tx, sizeof(Tx), 0) != sizeof(Tx)) { + fprintf(stderr, "ERROR: send() fails\n"); + return 0; + } + + cbRead = 0; + while (cbRead < sizeof(Rx)) { + len = recv(ctxrawtcp->Sock, (char *)&Rx + cbRead, sizeof(Rx) - cbRead, 0); + if (len == SOCKET_ERROR || len == 0) { + fprintf(stderr, "ERROR: recv() fails\n"); + return 0; + } + cbRead += len; + } + + len = recv(ctxrawtcp->Sock, (char *)&ready, sizeof(ready), 0); + if (len == SOCKET_ERROR || len != sizeof(ready)) { + fprintf(stderr, "ERROR: recv() fails\n"); + return 0; + } + + if (Rx.cmd != STATUS || Rx.cb != sizeof(ready)) { + fprintf(stderr, "ERROR: Fail getting device status\n"); + } + + return ready != 0; +} + +VOID DeviceRawTCP_Close(_Inout_ PPCILEECH_CONTEXT ctxPcileech) +{ + PDEVICE_CONTEXT_RAWTCP ctx = (PDEVICE_CONTEXT_RAWTCP)ctxPcileech->hDevice; + if (!ctx) { return; } + if (ctx->Sock) { closesocket(ctx->Sock); } + if (ctx->rxbuf.pb) { LocalFree(ctx->rxbuf.pb); } + if (ctx->txbuf.pb) { LocalFree(ctx->txbuf.pb); } + LocalFree(ctx); + ctxPcileech->hDevice = 0; +} + +BOOL DeviceRawTCP_ReadDMA(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _Out_ PBYTE pb, _In_ DWORD cb) +{ + PDEVICE_CONTEXT_RAWTCP ctxrawtcp = (PDEVICE_CONTEXT_RAWTCP)ctxPcileech->hDevice; + RAWTCP_PROTO_PACKET Rx = {0}, Tx = {0}; + DWORD cbRead; + DWORD len; + + if (cb > RAWTCP_MAX_SIZE_RX) { return FALSE; } + if (qwAddr % 0x1000) { return FALSE; } + if ((cb >= 0x1000) && (cb % 0x1000)) { return FALSE; } + if ((cb < 0x1000) && (cb % 0x8)) { return FALSE; } + + Tx.cmd = MEM_READ; + Tx.addr = qwAddr; + Tx.cb = cb; + + if (send(ctxrawtcp->Sock, (const char *)&Tx, sizeof(Tx), 0) != sizeof(Tx)) { + fprintf(stderr, "ERROR: send() fails\n"); + return 0; + } + + cbRead = 0; + while (cbRead < sizeof(Rx)) { + len = recv(ctxrawtcp->Sock, (char *)&Rx + cbRead, sizeof(Rx) - cbRead, 0); + if (len == SOCKET_ERROR || len == 0) { + fprintf(stderr, "ERROR: recv() fails\n"); + return 0; + } + cbRead += len; + } + + + cbRead = 0; + while (cbRead < Rx.cb) { + len = recv(ctxrawtcp->Sock, (char *)pb + cbRead, Rx.cb - cbRead, 0); + if (len == SOCKET_ERROR || len == 0) { + fprintf(stderr, "ERROR: recv() fails\n"); + return 0; + } + cbRead += len; + } + + if (Rx.cmd != MEM_READ) { + fprintf(stderr, "ERROR: Memory read fail (0x%x bytes read)\n", cbRead); + } + + return Rx.cb >= cb; +} + +BOOL DeviceRawTCP_WriteDMA(_Inout_ PPCILEECH_CONTEXT ctxPcileech, _In_ QWORD qwAddr, _In_ PBYTE pb, _In_ DWORD cb) +{ + PDEVICE_CONTEXT_RAWTCP ctxrawtcp = (PDEVICE_CONTEXT_RAWTCP)ctxPcileech->hDevice; + RAWTCP_PROTO_PACKET Rx = {0}, Tx = {0}; + DWORD cbRead, cbWritten; + DWORD len; + + Tx.cmd = MEM_WRITE; + Tx.addr = qwAddr; + Tx.cb = cb; + + if (send(ctxrawtcp->Sock, (const char *)&Tx, sizeof(Tx), 0) != sizeof(Tx)) { + fprintf(stderr, "ERROR: send() fails\n"); + return 0; + } + + cbWritten = 0; + while (cbWritten < cb) { + len = send(ctxrawtcp->Sock, (char *)pb + cbWritten, cb - cbWritten, 0); + if (len == SOCKET_ERROR || len == 0) { + fprintf(stderr, "ERROR: send() fails\n"); + return 0; + } + cbWritten += len; + } + + + cbRead = 0; + while (cbRead < sizeof(Rx)) { + len = recv(ctxrawtcp->Sock, (char *)&Rx + cbRead, sizeof(Rx) - cbRead, 0); + if (len == SOCKET_ERROR || len == 0) { + fprintf(stderr, "ERROR: recv() fails\n"); + return 0; + } + cbRead += len; + } + + if (Rx.cmd != MEM_WRITE) { + fprintf(stderr, "ERROR: Memory write fail\n", cbRead); + } + + return cbWritten >= cb; +} + +BOOL DeviceRawTCP_Open(_Inout_ PPCILEECH_CONTEXT ctxPcileech) +{ + PDEVICE_CONTEXT_RAWTCP ctx; +#ifdef WIN32 + + WSADATA WsaData; + WSAStartup(MAKEWORD(2, 2), &WsaData); + +#endif + if (ctxPcileech->cfg->TcpAddr == 0) { + fprintf(stderr, "ERROR: Remote address is not specified\n"); + return FALSE; + } + ctx = LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_RAWTCP)); + if (!ctx) { return FALSE; } + ctxPcileech->hDevice = (HANDLE)ctx; + // open device connection + if (ctxPcileech->cfg->TcpPort == 0) { ctxPcileech->cfg->TcpPort = DEFAULT_PORT; } + ctx->Sock = DeviceRawTCP_Connect(ctxPcileech->cfg->TcpAddr, ctxPcileech->cfg->TcpPort); + if (!ctx->Sock) { goto fail; } + if(!DeviceRawTCP_Status(ctx)) { printf("Error: remote service is not ready\n"); goto fail; } + ctx->rxbuf.cbMax = RAWTCP_MAX_SIZE_RX; + ctx->rxbuf.pb = LocalAlloc(0, ctx->rxbuf.cbMax); + if (!ctx->rxbuf.pb) { goto fail; } + ctx->txbuf.cbMax = RAWTCP_MAX_SIZE_TX; + ctx->txbuf.pb = LocalAlloc(0, ctx->txbuf.cbMax); + if (!ctx->txbuf.pb) { goto fail; } + + // set callback functions and fix up config + ctxPcileech->cfg->dev.tp = PCILEECH_DEVICE_RAW_TCP; + ctxPcileech->cfg->dev.qwMaxSizeDmaIo = 0x1000000; // 16MB + ctxPcileech->cfg->dev.qwAddrMaxNative = 0x0000ffffffffffff; + ctxPcileech->cfg->dev.fPartialPageReadSupported = TRUE; + ctxPcileech->cfg->dev.pfnClose = DeviceRawTCP_Close; + ctxPcileech->cfg->dev.pfnReadDMA = DeviceRawTCP_ReadDMA; + ctxPcileech->cfg->dev.pfnWriteDMA = DeviceRawTCP_WriteDMA; + + // return + if (ctxPcileech->cfg->fVerbose) { printf("Device Info: Raw TCP.\n"); } + return TRUE; +fail: + DeviceRawTCP_Close(ctxPcileech); + return FALSE; +} \ No newline at end of file diff --git a/pcileech/devicerawtcp.h b/pcileech/devicerawtcp.h new file mode 100644 index 0000000..8c4a728 --- /dev/null +++ b/pcileech/devicerawtcp.h @@ -0,0 +1,16 @@ +// devicerawtcp.h : implementation related to dummy device backed by a TCP service. +// + +#ifndef __DEVICERAWTCP_H__ +#define __DEVICERAWTCP_H__ +#include "pcileech.h" + +BOOL DeviceRawTCP_Open(_Inout_ PPCILEECH_CONTEXT ctx); + +typedef enum tdRawTCPCmd { + STATUS, + MEM_READ, + MEM_WRITE +} RawTCPCmd; + +#endif /* __DEVICERAWTCP_H__ */ \ No newline at end of file diff --git a/pcileech/pcileech.c b/pcileech/pcileech.c index 456df51..590b6ad 100644 --- a/pcileech/pcileech.c +++ b/pcileech/pcileech.c @@ -145,6 +145,8 @@ BOOL PCILeechConfigIntialize(_In_ DWORD argc, _In_ char* argv[], _Inout_ PPCILEE ctx->cfg->dev.tp = PCILEECH_DEVICE_SP605_TCP; } else if(0 == _stricmp(argv[i + 1], "totalmeltdown")) { ctx->cfg->dev.tp = PCILEECH_DEVICE_TOTALMELTDOWN; + } else if(0 == _stricmp(argv[i + 1], "rawtcp")) { + ctx->cfg->dev.tp = PCILEECH_DEVICE_RAW_TCP; } else if((Util_GetFileSize(argv[i + 1]) >= 0x1000)) { strcpy_s(ctx->cfg->dev.szFileNameOptTpFile, MAX_PATH, argv[i + 1]); ctx->cfg->dev.tp = PCILEECH_DEVICE_FILE; diff --git a/pcileech/pcileech.h b/pcileech/pcileech.h index 186d7e2..21caef4 100644 --- a/pcileech/pcileech.h +++ b/pcileech/pcileech.h @@ -56,7 +56,8 @@ typedef enum tdPCILEECH_DEVICE_TYPE { PCILEECH_DEVICE_FPGA, PCILEECH_DEVICE_SP605_TCP, PCILEECH_DEVICE_FILE, - PCILEECH_DEVICE_TOTALMELTDOWN + PCILEECH_DEVICE_TOTALMELTDOWN, + PCILEECH_DEVICE_RAW_TCP } PCILEECH_DEVICE_TYPE; typedef struct tdDMA_IO_SCATTER_HEADER {