Skip to content

Commit

Permalink
Add Raw TCP device (#77)
Browse files Browse the repository at this point in the history
  • Loading branch information
Synacktiv authored and ufrisk committed Jan 3, 2019
1 parent b839641 commit 8f3f9ce
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pcileech/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC=gcc
CFLAGS=-I. -D LINUX -pthread `pkg-config libusb-1.0 --libs --cflags`
DEPS = pcileech.h
OBJ = pcileech oscompatibility.o pcileech.o device.o device3380.o 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)
Expand Down
4 changes: 4 additions & 0 deletions pcileech/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
265 changes: 265 additions & 0 deletions pcileech/devicerawtcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
// devicerawtcp.c : implementation related to dummy device backed by a TCP service.
//

#ifdef WIN32

#include <winsock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

#else

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define SOCKET int

#define closesocket(_s_) close((_s_))

#define INVALID_SOCKET -1
#define SOCKET_ERROR -1

#endif

#ifdef WIN32
#include <PshPack1.h>
#endif

#ifdef WIN32
#include <PopPack.h>
#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;
}
16 changes: 16 additions & 0 deletions pcileech/devicerawtcp.h
Original file line number Diff line number Diff line change
@@ -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__ */
2 changes: 2 additions & 0 deletions pcileech/pcileech.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion pcileech/pcileech.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 8f3f9ce

Please sign in to comment.