Files
LeechCore/leechagent_linux/leechrpcserver.c
2026-01-03 14:49:27 +01:00

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;
}