mirror of
https://github.com/ufrisk/LeechCore.git
synced 2026-05-07 22:20:24 +08:00
524 lines
20 KiB
C
524 lines
20 KiB
C
// leechrpc.c : implementation of RPC server-side functionality.
|
|
//
|
|
// (c) Ulf Frisk, 2018-2026
|
|
// Author: Ulf Frisk, pcileech@frizk.net
|
|
//
|
|
#include "leechagent.h"
|
|
#include "leechagent_proc.h"
|
|
#include "leechrpc.h"
|
|
#include <stdio.h>
|
|
|
|
#define error_status_t DWORD
|
|
|
|
typedef struct tdLEECHRPC_SERVER_CONTEXT {
|
|
BOOL fValid;
|
|
LEECHRPC_COMPRESS Compress;
|
|
BOOL fInactivityWatcherThread;
|
|
BOOL fInactivityWatcherThreadIsRunning;
|
|
CRITICAL_SECTION LockClientList;
|
|
struct {
|
|
HANDLE hLC;
|
|
HANDLE hPP; // parent/child process context (used for child-process vfs operations)
|
|
DWORD dwRpcClientID;
|
|
DWORD cActiveRequests;
|
|
QWORD qwLastTickCount64;
|
|
} ClientList[LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS];
|
|
} LEECHRPC_SERVER_CONTEXT, *PLEECHRPC_SERVER_CONTEXT;
|
|
|
|
LEECHRPC_SERVER_CONTEXT ctxLeechRpc = { 0 };
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CLIENT TRACK / KEEPALIVE FUNCTIONALITY BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
_Success_(return != NULL)
|
|
HANDLE LeechRPC_LcHandle_GetExisting(_In_ DWORD dwRpcClientID, _Out_opt_ PHANDLE* pphPP)
|
|
{
|
|
DWORD i;
|
|
HANDLE hLC = NULL;
|
|
if(!dwRpcClientID) { return NULL; }
|
|
EnterCriticalSection(&ctxLeechRpc.LockClientList);
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if(ctxLeechRpc.ClientList[i].dwRpcClientID == dwRpcClientID) {
|
|
ctxLeechRpc.ClientList[i].cActiveRequests++;
|
|
ctxLeechRpc.ClientList[i].qwLastTickCount64 = GetTickCount64();
|
|
if(pphPP) { *pphPP = &ctxLeechRpc.ClientList[i].hPP; }
|
|
hLC = ctxLeechRpc.ClientList[i].hLC;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
return hLC;
|
|
}
|
|
|
|
_Success_(return)
|
|
BOOL LeechRPC_LcHandle_New(_In_ DWORD dwRpcClientID, _In_ HANDLE hLC)
|
|
{
|
|
DWORD i;
|
|
EnterCriticalSection(&ctxLeechRpc.LockClientList);
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if(!ctxLeechRpc.ClientList[i].dwRpcClientID) {
|
|
ctxLeechRpc.ClientList[i].hLC = hLC;
|
|
ctxLeechRpc.ClientList[i].dwRpcClientID = dwRpcClientID;
|
|
ctxLeechRpc.ClientList[i].cActiveRequests = 0;
|
|
ctxLeechRpc.ClientList[i].qwLastTickCount64 = GetTickCount64();
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
return TRUE;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
return FALSE;
|
|
}
|
|
|
|
VOID LeechRPC_LcHandle_Return(_In_opt_ HANDLE hLC, _In_ DWORD dwRpcClientID)
|
|
{
|
|
DWORD i;
|
|
if(!hLC) { return; }
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if((ctxLeechRpc.ClientList[i].hLC == hLC) && (ctxLeechRpc.ClientList[i].dwRpcClientID == dwRpcClientID)) {
|
|
EnterCriticalSection(&ctxLeechRpc.LockClientList);
|
|
ctxLeechRpc.ClientList[i].cActiveRequests--;
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID LeechRPC_LcHandle_Close(_In_ DWORD dwRpcClientID, _In_ BOOL fReasonTimeout)
|
|
{
|
|
DWORD i;
|
|
CHAR szTime[32];
|
|
HANDLE hLC = NULL, hPP = NULL;
|
|
EnterCriticalSection(&ctxLeechRpc.LockClientList);
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if(ctxLeechRpc.ClientList[i].dwRpcClientID == dwRpcClientID) {
|
|
while(ctxLeechRpc.ClientList[i].cActiveRequests) {
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
Sleep(10);
|
|
EnterCriticalSection(&ctxLeechRpc.LockClientList);
|
|
}
|
|
hLC = ctxLeechRpc.ClientList[i].hLC;
|
|
hPP = ctxLeechRpc.ClientList[i].hPP;
|
|
ctxLeechRpc.ClientList[i].hLC = NULL;
|
|
ctxLeechRpc.ClientList[i].hPP = NULL;
|
|
ctxLeechRpc.ClientList[i].dwRpcClientID = 0;
|
|
ctxLeechRpc.ClientList[i].qwLastTickCount64 = 0;
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&ctxLeechRpc.LockClientList);
|
|
if(hPP) {
|
|
// TODO: IMPLEMENT THIS
|
|
//LeechAgent_ProcParent_Close(hPP);
|
|
}
|
|
if(hLC) {
|
|
LcClose(hLC);
|
|
LeechSvc_GetTimeStamp(szTime);
|
|
if(fReasonTimeout) {
|
|
printf("[%s] LeechAgent: CLOSE: Client ID %08X timeout after %is.\n", szTime, dwRpcClientID, (LEECHAGENT_CLIENTKEEPALIVE_TIMEOUT_MS / 1000));
|
|
} else {
|
|
printf("[%s] LeechAgent: CLOSE: Client ID %08X\n", szTime, dwRpcClientID);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID LeechRPC_LcHandle_CloseAll()
|
|
{
|
|
DWORD i;
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if(ctxLeechRpc.ClientList[i].dwRpcClientID) {
|
|
LeechRPC_LcHandle_Close(ctxLeechRpc.ClientList[i].dwRpcClientID, FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID LeechRPC_LcHandle_InactivityWatcherThread(PVOID pv)
|
|
{
|
|
DWORD i;
|
|
ctxLeechRpc.fInactivityWatcherThread = TRUE;
|
|
ctxLeechRpc.fInactivityWatcherThreadIsRunning = TRUE;
|
|
while(ctxLeechRpc.fInactivityWatcherThread) {
|
|
Sleep(1000);
|
|
for(i = 0; i < LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS; i++) {
|
|
if(ctxLeechRpc.ClientList[i].qwLastTickCount64 && (ctxLeechRpc.ClientList[i].qwLastTickCount64 + LEECHAGENT_CLIENTKEEPALIVE_TIMEOUT_MS < GetTickCount64())) {
|
|
LeechRPC_LcHandle_Close(ctxLeechRpc.ClientList[i].dwRpcClientID, TRUE);
|
|
}
|
|
}
|
|
}
|
|
ctxLeechRpc.fInactivityWatcherThreadIsRunning = FALSE;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GENERAL FUNCTIONALITY BELOW:
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID LeechRpcOnLoadInitialize()
|
|
{
|
|
ctxLeechRpc.fValid = TRUE;
|
|
LeechRPC_CompressInitialize(&ctxLeechRpc.Compress);
|
|
InitializeCriticalSection(&ctxLeechRpc.LockClientList);
|
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)LeechRPC_LcHandle_InactivityWatcherThread, NULL, 0, NULL);
|
|
}
|
|
|
|
VOID LeechRpcOnUnloadClose()
|
|
{
|
|
ctxLeechRpc.fInactivityWatcherThread = FALSE;
|
|
while(ctxLeechRpc.fInactivityWatcherThreadIsRunning) {
|
|
SwitchToThread();
|
|
}
|
|
LeechRPC_LcHandle_CloseAll();
|
|
DeleteCriticalSection(&ctxLeechRpc.LockClientList);
|
|
LeechRPC_CompressClose(&ctxLeechRpc.Compress);
|
|
ZeroMemory(&ctxLeechRpc, sizeof(LEECHRPC_SERVER_CONTEXT));
|
|
}
|
|
|
|
error_status_t LeechRpc_CommandReadScatter(_In_ HANDLE hLC, _In_ PLEECHRPC_MSG_BIN pReq, QWORD *pcbOut, BYTE **ppbOut)
|
|
{
|
|
BOOL fOK;
|
|
PLEECHRPC_MSG_BIN pRsp = NULL;
|
|
PMEM_SCATTER pMEM_Src, pMEM_Dst;
|
|
PPMEM_SCATTER ppMEMs = NULL;
|
|
DWORD i, cMEMs, cbMax;
|
|
PBYTE pbData = NULL, pbDataDst;
|
|
DWORD cbDataOffset = 0, cbRead = 0;
|
|
DWORD cbRsp;
|
|
cMEMs = (DWORD)pReq->qwData[0];
|
|
cbMax = (DWORD)pReq->qwData[1];
|
|
// 1: verify incoming result
|
|
fOK = (pReq->cb == cMEMs * sizeof(MEM_SCATTER)) && (cMEMs <= 0x2000) && (cbMax <= (cMEMs << 12));
|
|
if(!fOK) { goto fail; }
|
|
// 2: allocate read data buffer, ppMEMs & prepare LeechCore call
|
|
if(!(ppMEMs = LocalAlloc(LMEM_ZEROINIT, cMEMs * sizeof(PMEM_SCATTER)))) { goto fail; }
|
|
if(!(pbData = LocalAlloc(0, cbMax))) { goto fail; }
|
|
pMEM_Src = (PMEM_SCATTER)pReq->pb;
|
|
for(i = 0; i < cMEMs; i++) {
|
|
pMEM_Src->pb = pbData + cbDataOffset;
|
|
cbDataOffset += pMEM_Src->cb;
|
|
ppMEMs[i] = pMEM_Src;
|
|
pMEM_Src = pMEM_Src + 1;
|
|
}
|
|
if(cbDataOffset > cbMax) { goto fail; }
|
|
// 4: call & count read data
|
|
LcReadScatter(hLC, cMEMs, ppMEMs);
|
|
pMEM_Src = (PMEM_SCATTER)pReq->pb;
|
|
for(i = 0, cbRead = 0; i < cMEMs; i++) {
|
|
if(pMEM_Src->f) {
|
|
cbRead += pMEM_Src->cb;
|
|
}
|
|
pMEM_Src = pMEM_Src + 1;
|
|
}
|
|
// 5: allocate and prepare result
|
|
cbRsp = sizeof(LEECHRPC_MSG_BIN) + cMEMs * sizeof(MEM_SCATTER) + cbRead;
|
|
if(!(pRsp = LocalAlloc(0, cbRsp))) { goto fail; }
|
|
ZeroMemory(pRsp, sizeof(LEECHRPC_MSG_BIN));
|
|
pRsp->cbMsg = cbRsp;
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_READSCATTER_RSP;
|
|
memcpy(pRsp->pb, pReq->pb, pReq->cb); // all MEMs
|
|
pbDataDst = pRsp->pb + pReq->cb; // rsp data buffer
|
|
pMEM_Dst = (PMEM_SCATTER)pRsp->pb;
|
|
for(i = 0, cbRead = 0; i < cMEMs; i++) {
|
|
if(pMEM_Dst->f) {
|
|
memcpy(pbDataDst, pMEM_Dst->pb, pMEM_Dst->cb);
|
|
pbDataDst = pbDataDst + pMEM_Dst->cb;
|
|
cbRead += pMEM_Dst->cb;
|
|
}
|
|
pMEM_Dst = pMEM_Dst + 1;
|
|
}
|
|
pRsp->cb = pReq->cb + cbRead;
|
|
pRsp->qwData[0] = cMEMs;
|
|
LeechRPC_Compress(&ctxLeechRpc.Compress, pRsp, (pReq->flags & LEECHRPC_FLAG_NOCOMPRESS));
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
LocalFree(ppMEMs);
|
|
LocalFree(pbData);
|
|
return 0;
|
|
fail:
|
|
*pcbOut = 0;
|
|
*ppbOut = NULL;
|
|
LocalFree(pRsp);
|
|
LocalFree(ppMEMs);
|
|
LocalFree(pbData);
|
|
return (error_status_t)-1;
|
|
}
|
|
|
|
error_status_t LeechRpc_CommandWriteScatter(_In_ HANDLE hLC, _In_ PLEECHRPC_MSG_BIN pReq, QWORD *pcbOut, BYTE **ppbOut)
|
|
{
|
|
PBOOL pfRsp;
|
|
PLEECHRPC_MSG_BIN pRsp = NULL;
|
|
PMEM_SCATTER pMEM, pMEMs;
|
|
PPMEM_SCATTER ppMEMs = NULL;
|
|
DWORD i, cMEMs, cbRsp;
|
|
PBYTE pbData = NULL;
|
|
cMEMs = (DWORD)pReq->qwData[0];
|
|
// 1: verify and fixup incoming data
|
|
pMEMs = (PMEM_SCATTER)pReq->pb;
|
|
pbData = pReq->pb + cMEMs * sizeof(MEM_SCATTER);
|
|
if(pReq->cb != cMEMs * (sizeof(MEM_SCATTER) + 0x1000)) { goto fail; }
|
|
if(!(ppMEMs = LocalAlloc(LMEM_ZEROINIT, cMEMs * sizeof(PMEM_SCATTER)))) { goto fail; }
|
|
for(i = 0; i < cMEMs; i++) {
|
|
ppMEMs[i] = pMEM = pMEMs + i;
|
|
if((pMEM->cb > 0x1000) || (pMEM->iStack > MEM_SCATTER_STACK_SIZE - 4)) { goto fail; }
|
|
pMEM->pb = pbData;
|
|
pbData += pMEM->cb;
|
|
}
|
|
// 2: call & return result
|
|
LcWriteScatter(hLC, cMEMs, ppMEMs);
|
|
cbRsp = sizeof(LEECHRPC_MSG_BIN) + cMEMs * sizeof(BOOL);
|
|
if(!(pRsp = LocalAlloc(LMEM_ZEROINIT, cbRsp))) { goto fail; }
|
|
pRsp->cbMsg = cbRsp;
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_WRITESCATTER_RSP;
|
|
pRsp->cb = cMEMs * sizeof(BOOL);
|
|
pfRsp = (PBOOL)pRsp->pb;
|
|
for(i = 0; i < cMEMs; i++) {
|
|
pfRsp[i] = pMEMs[i].f;
|
|
}
|
|
pRsp->qwData[0] = cMEMs;
|
|
LeechRPC_Compress(&ctxLeechRpc.Compress, pRsp, (pReq->flags & LEECHRPC_FLAG_NOCOMPRESS));
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
LocalFree(ppMEMs);
|
|
return 0;
|
|
fail:
|
|
*pcbOut = 0;
|
|
*ppbOut = NULL;
|
|
LocalFree(pRsp);
|
|
LocalFree(ppMEMs);
|
|
return (error_status_t)-1;
|
|
}
|
|
|
|
/*
|
|
* NOTE! Remote agent command functionality is not currently supported by the Linux LeechAgent.
|
|
* Transfer commands/data to/from the remote service (if it exists).
|
|
* NB! USER-FREE: ppbDataOut (LocalFree)
|
|
* -- hLC
|
|
* -- phPP
|
|
* -- fOption = the command as specified by LC_CMD_AGENT_*
|
|
* -- cbDataIn
|
|
* -- pbDataIn
|
|
* -- ppbDataOut = ptr to receive function allocated output - must be LocalFree'd by caller!
|
|
* -- pcbDataOut = ptr to receive length of *pbDataOut.
|
|
* -- return
|
|
*/
|
|
_Success_(return)
|
|
BOOL LeechRpc_CommandAgent(_In_ HANDLE hLC, _In_opt_ PHANDLE phPP, _In_ QWORD fOption, _In_ DWORD cbDataIn, _In_reads_(cbDataIn) PBYTE pbDataIn, _Out_writes_opt_(*pcbDataOut) PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut)
|
|
{
|
|
if(ppbDataOut) { *ppbDataOut = NULL; }
|
|
if(pcbDataOut) { *pcbDataOut = 0; }
|
|
switch(fOption & 0xffffffff00000000) {
|
|
case LC_CMD_AGENT_EXIT_PROCESS:
|
|
exit(EXIT_SUCCESS);
|
|
return FALSE; // not reached ...
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
error_status_t LeechRpc_CommandOpen(_In_ PLEECHRPC_MSG_OPEN pReq, QWORD *pcbOut, BYTE **ppbOut)
|
|
{
|
|
DWORD cbRsp;
|
|
CHAR szTime[32];
|
|
HANDLE hLC = NULL;
|
|
PLEECHRPC_MSG_OPEN pRsp = NULL;
|
|
PLC_CONFIG_ERRORINFO pLcErrorInfo = NULL;
|
|
hLC = LcCreateEx(&pReq->cfg, &pLcErrorInfo);
|
|
if(hLC && !LeechRPC_LcHandle_New(pReq->dwRpcClientID, hLC)) {
|
|
LcClose(hLC);
|
|
hLC = NULL;
|
|
}
|
|
pReq->cfg.pfn_printf_opt = NULL;
|
|
cbRsp = sizeof(LEECHRPC_MSG_OPEN) + (pLcErrorInfo ? (pLcErrorInfo->cbStruct - sizeof(LC_CONFIG_ERRORINFO)) : 0);
|
|
if(!(pRsp = LocalAlloc(LMEM_ZEROINIT, cbRsp))) {
|
|
*pcbOut = 0;
|
|
*ppbOut = NULL;
|
|
return (error_status_t)-1;
|
|
}
|
|
pRsp->cbMsg = cbRsp;
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->fValidOpen = hLC ? TRUE : FALSE;
|
|
if(pRsp->fValidOpen) {
|
|
LeechSvc_GetTimeStamp(szTime);
|
|
printf("[%s] LeechAgent: OPEN: Client ID %08X\n", szTime, pReq->dwRpcClientID);
|
|
memcpy(&pRsp->cfg, &pReq->cfg, sizeof(LC_CONFIG));
|
|
pRsp->cfg.fRemoteDisableCompress = pRsp->cfg.fRemoteDisableCompress || !ctxLeechRpc.Compress.fValid;
|
|
pRsp->flags = 0;
|
|
}
|
|
if(pLcErrorInfo) {
|
|
memcpy(&pRsp->errorinfo, pLcErrorInfo, pLcErrorInfo->cbStruct);
|
|
}
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_OPEN_RSP;
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
LocalFree(pLcErrorInfo);
|
|
return 0;
|
|
}
|
|
|
|
error_status_t LeechRpc_ReservedSubmitCommand(
|
|
/* [in] */ HANDLE hBinding,
|
|
/* [in] */ QWORD cbIn,
|
|
/* [size_is][in] */ BYTE *pbIn,
|
|
/* [out] */ QWORD *pcbOut,
|
|
/* [size_is][size_is][out] */ BYTE **ppbOut)
|
|
{
|
|
HANDLE hLC = NULL, *phPP = NULL;
|
|
BOOL fTMP = FALSE;
|
|
DWORD cbTMP = 0;
|
|
PBYTE pbTMP = NULL;
|
|
BOOL fFreeReqBin = FALSE;
|
|
error_status_t status = 0;
|
|
PLEECHRPC_MSG_HDR pReq = NULL;
|
|
PLEECHRPC_MSG_HDR pRsp = NULL;
|
|
PLEECHRPC_MSG_OPEN pReqOpen = NULL;
|
|
PLEECHRPC_MSG_OPEN pRspOpen = NULL;
|
|
PLEECHRPC_MSG_DATA pReqData = NULL;
|
|
PLEECHRPC_MSG_DATA pRspData = NULL;
|
|
PLEECHRPC_MSG_BIN pReqBin = NULL;
|
|
PLEECHRPC_MSG_BIN pRspBin = NULL;
|
|
// 1: sanity checks in incoming data
|
|
if(!ctxLeechRpc.fValid) { return status; }
|
|
if(cbIn < sizeof(LEECHRPC_MSG_HDR)) { return status; }
|
|
pReq = (PLEECHRPC_MSG_HDR)pbIn;
|
|
if((pReq->dwMagic != LEECHRPC_MSGMAGIC) || (pReq->tpMsg > LEECHRPC_MSGTYPE_MAX) || (pReq->cbMsg < sizeof(LEECHRPC_MSG_HDR))) { return status; }
|
|
hLC = LeechRPC_LcHandle_GetExisting(pReq->dwRpcClientID, &phPP);
|
|
if(!hLC && !((pReq->tpMsg == LEECHRPC_MSGTYPE_PING_REQ) || (pReq->tpMsg == LEECHRPC_MSGTYPE_OPEN_REQ) || (pReq->tpMsg == LEECHRPC_MSGTYPE_CLOSE_REQ))) { goto fail; }
|
|
switch(pReq->tpMsg) {
|
|
case LEECHRPC_MSGTYPE_PING_REQ:
|
|
case LEECHRPC_MSGTYPE_CLOSE_REQ:
|
|
case LEECHRPC_MSGTYPE_KEEPALIVE_REQ:
|
|
if(pReq->cbMsg != sizeof(LEECHRPC_MSG_HDR)) { goto fail; }
|
|
break;
|
|
case LEECHRPC_MSGTYPE_OPEN_REQ:
|
|
if(pReq->cbMsg != sizeof(LEECHRPC_MSG_OPEN)) { goto fail; }
|
|
pReqOpen = (PLEECHRPC_MSG_OPEN)pReq;
|
|
break;
|
|
case LEECHRPC_MSGTYPE_GETOPTION_REQ:
|
|
case LEECHRPC_MSGTYPE_SETOPTION_REQ:
|
|
if(pReq->cbMsg != sizeof(LEECHRPC_MSG_DATA)) { goto fail; }
|
|
pReqData = (PLEECHRPC_MSG_DATA)pReq;
|
|
break;
|
|
case LEECHRPC_MSGTYPE_READSCATTER_REQ:
|
|
case LEECHRPC_MSGTYPE_WRITESCATTER_REQ:
|
|
case LEECHRPC_MSGTYPE_COMMAND_REQ:
|
|
if(pReq->cbMsg != sizeof(LEECHRPC_MSG_BIN) + ((PLEECHRPC_MSG_BIN)pReq)->cb) { goto fail; }
|
|
if(((PLEECHRPC_MSG_BIN)pReq)->cbDecompress) {
|
|
if(!LeechRPC_Decompress(&ctxLeechRpc.Compress, (PLEECHRPC_MSG_BIN)pReq, &pReqBin)) { goto fail; }
|
|
fFreeReqBin = TRUE; // data allocated by decompress function must be free'd
|
|
} else {
|
|
pReqBin = ((PLEECHRPC_MSG_BIN)pReq);
|
|
}
|
|
break;
|
|
default:
|
|
goto fail;
|
|
}
|
|
// 2: dispatch
|
|
switch(pReq->tpMsg) {
|
|
case LEECHRPC_MSGTYPE_PING_REQ:
|
|
if(!(pRsp = LocalAlloc(0, sizeof(LEECHRPC_MSG_HDR)))) { goto fail; }
|
|
pRsp->cbMsg = sizeof(LEECHRPC_MSG_HDR);
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_PING_RSP;
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_KEEPALIVE_REQ:
|
|
if(!(pRsp = LocalAlloc(0, sizeof(LEECHRPC_MSG_HDR)))) { goto fail; }
|
|
pRsp->cbMsg = sizeof(LEECHRPC_MSG_HDR);
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_KEEPALIVE_RSP;
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_OPEN_REQ:
|
|
if(pReqOpen) {
|
|
LeechRpc_CommandOpen(pReqOpen, pcbOut, ppbOut);
|
|
}
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_READSCATTER_REQ:
|
|
status = LeechRpc_CommandReadScatter(hLC, pReqBin, pcbOut, ppbOut);
|
|
if(fFreeReqBin) { LocalFree(pReqBin); pReqBin = NULL; } // only free locally allocated decompressed bindata
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_WRITESCATTER_REQ:
|
|
status = LeechRpc_CommandWriteScatter(hLC, pReqBin, pcbOut, ppbOut);
|
|
if(fFreeReqBin) { LocalFree(pReqBin); pReqBin = NULL; } // only free locally allocated decompressed bindata
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_CLOSE_REQ:
|
|
LeechRPC_LcHandle_Return(hLC, pReq->dwRpcClientID);
|
|
hLC = NULL;
|
|
LeechRPC_LcHandle_Close(pReq->dwRpcClientID, FALSE);
|
|
if(!(pRsp = LocalAlloc(0, sizeof(LEECHRPC_MSG_HDR)))) { goto fail; }
|
|
pRsp->cbMsg = sizeof(LEECHRPC_MSG_HDR);
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = TRUE;
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_CLOSE_RSP;
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_GETOPTION_REQ:
|
|
if(!(pRspData = LocalAlloc(0, sizeof(LEECHRPC_MSG_DATA)))) { goto fail; }
|
|
pRspData->cbMsg = sizeof(LEECHRPC_MSG_DATA);
|
|
pRspData->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRspData->fMsgResult = pReqData && LcGetOption(hLC, pReqData->qwData[0], &pRspData->qwData[0]);
|
|
pRspData->tpMsg = LEECHRPC_MSGTYPE_GETOPTION_RSP;
|
|
*pcbOut = pRspData->cbMsg;
|
|
*ppbOut = (PBYTE)pRspData;
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_SETOPTION_REQ:
|
|
if(!(pRsp = LocalAlloc(0, sizeof(LEECHRPC_MSG_HDR)))) { goto fail; }
|
|
pRsp->cbMsg = sizeof(LEECHRPC_MSG_HDR);
|
|
pRsp->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRsp->fMsgResult = pReqData && LcSetOption(hLC, pReqData->qwData[0], pReqData->qwData[1]);
|
|
pRsp->tpMsg = LEECHRPC_MSGTYPE_SETOPTION_RSP;
|
|
*pcbOut = pRsp->cbMsg;
|
|
*ppbOut = (PBYTE)pRsp;
|
|
goto finish;
|
|
case LEECHRPC_MSGTYPE_COMMAND_REQ:
|
|
fTMP = (pReqBin->qwData[0] >> 63) ?
|
|
LeechRpc_CommandAgent(hLC, phPP, pReqBin->qwData[0], pReqBin->cb, pReqBin->pb, &pbTMP, &cbTMP) :
|
|
LcCommand(hLC, pReqBin->qwData[0], pReqBin->cb, pReqBin->pb, &pbTMP, &cbTMP);
|
|
if(!fTMP) { cbTMP = 0; }
|
|
if(!(pRspBin = LocalAlloc(LMEM_ZEROINIT, sizeof(LEECHRPC_MSG_BIN) + cbTMP))) {
|
|
goto fail;
|
|
}
|
|
pRspBin->fMsgResult = fTMP;
|
|
pRspBin->cb = cbTMP;
|
|
memcpy(pRspBin->pb, pbTMP, cbTMP);
|
|
LocalFree(pbTMP); pbTMP = NULL;
|
|
pRspBin->tpMsg = LEECHRPC_MSGTYPE_COMMAND_RSP;
|
|
pRspBin->dwMagic = LEECHRPC_MSGMAGIC;
|
|
pRspBin->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pRspBin->cb;
|
|
LeechRPC_Compress(&ctxLeechRpc.Compress, pRspBin, (pReq->flags & LEECHRPC_FLAG_NOCOMPRESS));
|
|
*pcbOut = pRspBin->cbMsg;
|
|
*ppbOut = (PBYTE)pRspBin;
|
|
if(fFreeReqBin) { LocalFree(pReqBin); pReqBin = NULL; } // only free locally allocated decompressed bindata
|
|
goto finish;
|
|
default:
|
|
goto fail;
|
|
}
|
|
finish:
|
|
if(pReq) { LeechRPC_LcHandle_Return(hLC, pReq->dwRpcClientID); }
|
|
return status;
|
|
fail:
|
|
LeechRPC_LcHandle_Return(hLC, pReq->dwRpcClientID);
|
|
if(fFreeReqBin) { LocalFree(pReqBin); pReqBin = NULL; } // only free locally allocated decompressed bindata
|
|
*pcbOut = 0;
|
|
*ppbOut = NULL;
|
|
return (error_status_t)-1;
|
|
}
|
|
|
|
VOID LeechGRPC_ReservedSubmitCommand(_In_opt_ PVOID ctx, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut)
|
|
{
|
|
QWORD cbOut = 0;
|
|
LeechRpc_ReservedSubmitCommand(NULL, cbIn, pbIn, &cbOut, ppbOut);
|
|
*pcbOut = (SIZE_T)cbOut;
|
|
}
|