梦幻的彼岸 发表于 2022-2-10 10:34:02

CreateSvcRpc - 一个自定义的RPC客户端,以SYSTEM用户身份执行程序

翻译
原文地址:https://www.x86matthew.com/view_post?id=create_svc_rpc
功能: 一个自定义的RPC客户端,以SYSTEM用户身份执行程序

static/image/hrline/1.gif

Windows RPC协议是一个我以前没有做过很多实验的领域。我现在已经创建了一个自定义的RPC客户端,它使用原始数据与ntsvcs管道进行通信。这意味着可以只使用CreateFile和WriteFile APIs来创建和执行一个Windows服务。

RPC协议似乎有一些记录,但相关的信息非常零散,我发现从头开始逆向工程更容易。

我通过拦截NtWriteFile、NtReadFile和NtFsControlFile函数,记录了Windows服务API的通信。我分析了这个数据流,以逐步建立我自己的RPC客户端。

在我的第一个版本运行后,我在Wireshark文档中发现了一些有用的信息,这些信息帮助我在RPC头文件中标注了剩余的未知字段。

以下是完整的程序代码:
#include <stdio.h>
#include <windows.h>

// rpc command ids
#define RPC_CMD_ID_OPEN_SC_MANAGER 27
#define RPC_CMD_ID_CREATE_SERVICE 24
#define RPC_CMD_ID_START_SERVICE 31
#define RPC_CMD_ID_DELETE_SERVICE 2

// rpc command output lengths
#define RPC_OUTPUT_LENGTH_OPEN_SC_MANAGER 24
#define RPC_OUTPUT_LENGTH_CREATE_SERVICE 28
#define RPC_OUTPUT_LENGTH_START_SERVICE 4
#define RPC_OUTPUT_LENGTH_DELETE_SERVICE 4

#define MAX_RPC_PACKET_LENGTH 4096
#define MAX_PROCEDURE_DATA_LENGTH 2048

#define CALC_ALIGN_PADDING(VALUE_LENGTH, ALIGN_BYTES) ((((VALUE_LENGTH + ALIGN_BYTES - 1) / ALIGN_BYTES) * ALIGN_BYTES) - VALUE_LENGTH)

struct RpcBaseHeaderStruct
{
        WORD wVersion;
        BYTE bPacketType;
        BYTE bPacketFlags;
        DWORD dwDataRepresentation;
        WORD wFragLength;
        WORD wAuthLength;
        DWORD dwCallIndex;
};

struct RpcRequestHeaderStruct
{
        DWORD dwAllocHint;
        WORD wContextID;
        WORD wProcedureNumber;
};

struct RpcResponseHeaderStruct
{
        DWORD dwAllocHint;
        WORD wContextID;
        BYTE bCancelCount;
        BYTE bAlign;
};

struct RpcBindRequestContextEntryStruct
{
        WORD wContextID;
        WORD wTransItemCount;
        BYTE bInterfaceUUID;
        DWORD dwInterfaceVersion;
        BYTE bTransferSyntaxUUID;
        DWORD dwTransferSyntaxVersion;
};

struct RpcBindRequestHeaderStruct
{
        WORD wMaxSendFrag;
        WORD wMaxRecvFrag;
        DWORD dwAssocGroup;
        BYTE bContextCount;
        BYTE bAlign;

        RpcBindRequestContextEntryStruct Context;
};

struct RpcBindResponseContextEntryStruct
{
        WORD wResult;
        WORD wAlign;
        BYTE bTransferSyntax;
        DWORD dwTransferSyntaxVersion;
};

struct RpcBindResponseHeader1Struct
{
        WORD wMaxSendFrag;
        WORD wMaxRecvFrag;
        DWORD dwAssocGroup;
};

struct RpcBindResponseHeader2Struct
{
        DWORD dwContextResultCount;
        RpcBindResponseContextEntryStruct Context;
};

struct RpcConnectionStruct
{
        HANDLE hFile;
        DWORD dwCallIndex;

        DWORD dwInputError;

        DWORD dwRequestInitialised;

        BYTE bProcedureInputData;
        DWORD dwProcedureInputDataLength;

        BYTE bProcedureOutputData;
        DWORD dwProcedureOutputDataLength;
};

DWORD RpcConvertUUID(char *pString, BYTE *pUUID, DWORD dwMaxLength)
{
        BYTE bUUID;
        BYTE bFixedUUID;
        DWORD dwUUIDLength = 0;
        BYTE bCurrInputChar = 0;
        BYTE bConvertedByte = 0;
        DWORD dwProcessedByteCount = 0;
        BYTE bCurrOutputByte = 0;

        // ensure output buffer is large enough
        if(dwMaxLength < 16)
        {
                return 1;
        }

        // check uuid length
        dwUUIDLength = strlen("00000000-0000-0000-0000-000000000000");
        if(strlen(pString) != dwUUIDLength)
        {
                return 1;
        }

        // convert string to uuid
        for(DWORD i = 0; i < dwUUIDLength; i++)
        {
                // get current input character
                bCurrInputChar = *(BYTE*)((BYTE*)pString + i);

                // check if a dash character is expected here
                if(i == 8 || i == 13 || i == 18 || i == 23)
                {
                        if(bCurrInputChar == '-')
                        {
                                continue;
                        }
                        else
                        {
                                return 1;
                        }
                }
                else
                {
                        // check current input character value
                        if(bCurrInputChar >= 'a' && bCurrInputChar <= 'f')
                        {
                                bConvertedByte = 0xA + (bCurrInputChar - 'a');
                        }
                        else if(bCurrInputChar >= 'A' && bCurrInputChar <= 'F')
                        {
                                bConvertedByte = 0xA + (bCurrInputChar - 'A');
                        }
                        else if(bCurrInputChar >= '0' && bCurrInputChar <= '9')
                        {
                                bConvertedByte = 0 + (bCurrInputChar - '0');
                        }
                        else
                        {
                                // invalid character
                                return 1;
                        }

                        if((dwProcessedByteCount % 2) == 0)
                        {
                                bCurrOutputByte = bConvertedByte * 0x10;
                        }
                        else
                        {
                                bCurrOutputByte += bConvertedByte;

                                // store current uuid byte
                                bUUID[(dwProcessedByteCount - 1) / 2] = bCurrOutputByte;
                        }
                        dwProcessedByteCount++;
                }
        }

        // fix uuid endianness
        memcpy((void*)bFixedUUID, (void*)bUUID, sizeof(bUUID));
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;
        bFixedUUID = bUUID;

        // store uuid
        memcpy((void*)pUUID, (void*)bFixedUUID, sizeof(bUUID));

        return 0;
}

DWORD RpcBind(RpcConnectionStruct *pRpcConnection, char *pInterfaceUUID, DWORD dwInterfaceVersion)
{
        RpcBaseHeaderStruct RpcBaseHeader;
        RpcBindRequestHeaderStruct RpcBindRequestHeader;
        DWORD dwBytesWritten = 0;
        DWORD dwBytesRead = 0;
        BYTE bResponseData;
        RpcBaseHeaderStruct *pRpcResponseBaseHeader = NULL;
        RpcBindResponseHeader1Struct *pRpcBindResponseHeader1 = NULL;
        RpcBindResponseHeader2Struct *pRpcBindResponseHeader2 = NULL;
        BYTE *pSecondaryAddrHeaderBlock = NULL;
        WORD wSecondaryAddrLen = 0;
        DWORD dwSecondaryAddrAlign = 0;

        // set base header details
        memset((void*)&RpcBaseHeader, 0, sizeof(RpcBaseHeader));
        RpcBaseHeader.wVersion = 5;
        RpcBaseHeader.bPacketType = 11;
        RpcBaseHeader.bPacketFlags = 3;
        RpcBaseHeader.dwDataRepresentation = 0x10;
        RpcBaseHeader.wFragLength = sizeof(RpcBaseHeader) + sizeof(RpcBindRequestHeader);
        RpcBaseHeader.wAuthLength = 0;
        RpcBaseHeader.dwCallIndex = pRpcConnection->dwCallIndex;

        // set bind request header details
        memset((void*)&RpcBindRequestHeader, 0, sizeof(RpcBindRequestHeader));
        RpcBindRequestHeader.wMaxSendFrag = MAX_RPC_PACKET_LENGTH;
        RpcBindRequestHeader.wMaxRecvFrag = MAX_RPC_PACKET_LENGTH;
        RpcBindRequestHeader.dwAssocGroup = 0;
        RpcBindRequestHeader.bContextCount = 1;
        RpcBindRequestHeader.Context.wContextID = 0;
        RpcBindRequestHeader.Context.wTransItemCount = 1;
        RpcBindRequestHeader.Context.dwTransferSyntaxVersion = 2;

        // get interface UUID
        if(RpcConvertUUID(pInterfaceUUID, RpcBindRequestHeader.Context.bInterfaceUUID, sizeof(RpcBindRequestHeader.Context.bInterfaceUUID)) != 0)
        {
                return 1;
        }
        RpcBindRequestHeader.Context.dwInterfaceVersion = dwInterfaceVersion;

        // {8a885d04-1ceb-11c9-9fe8-08002b104860} (NDR)
        if(RpcConvertUUID("8a885d04-1ceb-11c9-9fe8-08002b104860", RpcBindRequestHeader.Context.bTransferSyntaxUUID, sizeof(RpcBindRequestHeader.Context.bTransferSyntaxUUID)) != 0)
        {
                return 1;
        }

        // write base header
        if(WriteFile(pRpcConnection->hFile, (void*)&RpcBaseHeader, sizeof(RpcBaseHeader), &dwBytesWritten, NULL) == 0)
        {
                return 1;
        }

        // write bind request header
        if(WriteFile(pRpcConnection->hFile, (void*)&RpcBindRequestHeader, sizeof(RpcBindRequestHeader), &dwBytesWritten, NULL) == 0)
        {
                return 1;
        }

        // increase call index
        pRpcConnection->dwCallIndex++;

        // get bind response
        memset((void*)&bResponseData, 0, sizeof(bResponseData));
        if(ReadFile(pRpcConnection->hFile, (void*)bResponseData, sizeof(bResponseData), &dwBytesRead, NULL) == 0)
        {
                return 1;
        }

        // get a ptr to the base response header
        pRpcResponseBaseHeader = (RpcBaseHeaderStruct*)bResponseData;

        // validate base response header
        if(pRpcResponseBaseHeader->wVersion != 5)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->bPacketType != 12)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->bPacketFlags != 3)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->wFragLength != dwBytesRead)
        {
                return 1;
        }

        // get a ptr to the main bind response header body
        pRpcBindResponseHeader1 = (RpcBindResponseHeader1Struct*)((BYTE*)pRpcResponseBaseHeader + sizeof(RpcBaseHeaderStruct));

        // get secondary addr header ptr
        pSecondaryAddrHeaderBlock = (BYTE*)pRpcBindResponseHeader1 + sizeof(RpcBindResponseHeader1Struct);
        wSecondaryAddrLen = *(WORD*)pSecondaryAddrHeaderBlock;

        // validate secondary addr length
        if(wSecondaryAddrLen > 256)
        {
                return 1;
        }

        // calculate padding for secondary addr value if necessary
        dwSecondaryAddrAlign = CALC_ALIGN_PADDING((sizeof(WORD) + wSecondaryAddrLen), 4);

        // get a ptr to the main bind response header body (after the variable-length secondary addr field)
        pRpcBindResponseHeader2 = (RpcBindResponseHeader2Struct*)((BYTE*)pSecondaryAddrHeaderBlock + sizeof(WORD) + wSecondaryAddrLen + dwSecondaryAddrAlign);

        // validate context count
        if(pRpcBindResponseHeader2->dwContextResultCount != 1)
        {
                return 1;
        }

        // ensure the result value for context #1 was successful
        if(pRpcBindResponseHeader2->Context.wResult != 0)
        {
                return 1;
        }

        return 0;
}

DWORD RpcConnect(char *pPipeName, char *pInterfaceUUID, DWORD dwInterfaceVersion, RpcConnectionStruct *pRpcConnection)
{
        HANDLE hFile = NULL;
        char szPipePath;
        RpcConnectionStruct RpcConnection;

        // set pipe path
        memset(szPipePath, 0, sizeof(szPipePath));
        _snprintf(szPipePath, sizeof(szPipePath) - 1, "\\\\.\\pipe\\%s", pPipeName);

        // open rpc pipe
        hFile = CreateFile(szPipePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if(hFile == INVALID_HANDLE_VALUE)
        {
                return 1;
        }

        // initialise rpc connection data
        memset((void*)&RpcConnection, 0, sizeof(RpcConnection));
        RpcConnection.hFile = hFile;
        RpcConnection.dwCallIndex = 1;

        // bind rpc connection
        if(RpcBind(&RpcConnection, pInterfaceUUID, dwInterfaceVersion) != 0)
        {
                return 1;
        }

        // store connection data
        memcpy((void*)pRpcConnection, (void*)&RpcConnection, sizeof(RpcConnection));

        return 0;
}

DWORD RpcSendRequest(RpcConnectionStruct *pRpcConnection, DWORD dwProcedureNumber)
{
        RpcBaseHeaderStruct RpcBaseHeader;
        RpcRequestHeaderStruct RpcRequestHeader;
        DWORD dwBytesWritten = 0;
        BYTE bResponseData;
        RpcBaseHeaderStruct *pRpcResponseBaseHeader = NULL;
        RpcResponseHeaderStruct *pRpcResponseHeader = NULL;
        DWORD dwProcedureResponseDataLength = 0;
        DWORD dwBytesRead = 0;
        BYTE *pTempProcedureResponseDataPtr = NULL;

        // ensure rpc request has been initialised
        if(pRpcConnection->dwRequestInitialised == 0)
        {
                return 1;
        }

        // clear initialised flag
        pRpcConnection->dwRequestInitialised = 0;

        // check for input errors
        if(pRpcConnection->dwInputError != 0)
        {
                return 1;
        }

        // set base header details
        memset((void*)&RpcBaseHeader, 0, sizeof(RpcBaseHeader));
        RpcBaseHeader.wVersion = 5;
        RpcBaseHeader.bPacketType = 0;
        RpcBaseHeader.bPacketFlags = 3;
        RpcBaseHeader.dwDataRepresentation = 0x10;
        RpcBaseHeader.wFragLength = sizeof(RpcBaseHeader) + sizeof(RpcRequestHeader) + pRpcConnection->dwProcedureInputDataLength;
        RpcBaseHeader.wAuthLength = 0;
        RpcBaseHeader.dwCallIndex = pRpcConnection->dwCallIndex;

        // set request header details
        memset((void*)&RpcRequestHeader, 0, sizeof(RpcRequestHeader));
        RpcRequestHeader.dwAllocHint = 0;
        RpcRequestHeader.wContextID = 0;
        RpcRequestHeader.wProcedureNumber = (WORD)dwProcedureNumber;

        // write base header
        if(WriteFile(pRpcConnection->hFile, (void*)&RpcBaseHeader, sizeof(RpcBaseHeader), &dwBytesWritten, NULL) == 0)
        {
                return 1;
        }

        // write request header
        if(WriteFile(pRpcConnection->hFile, (void*)&RpcRequestHeader, sizeof(RpcRequestHeader), &dwBytesWritten, NULL) == 0)
        {
                return 1;
        }

        // write request body
        if(WriteFile(pRpcConnection->hFile, (void*)pRpcConnection->bProcedureInputData, pRpcConnection->dwProcedureInputDataLength, &dwBytesWritten, NULL) == 0)
        {
                return 1;
        }

        // increase call index
        pRpcConnection->dwCallIndex++;

        // get bind response
        memset((void*)&bResponseData, 0, sizeof(bResponseData));
        if(ReadFile(pRpcConnection->hFile, (void*)bResponseData, sizeof(bResponseData), &dwBytesRead, NULL) == 0)
        {
                return 1;
        }

        // get a ptr to the base response header
        pRpcResponseBaseHeader = (RpcBaseHeaderStruct*)bResponseData;

        // validate base response header
        if(pRpcResponseBaseHeader->wVersion != 5)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->bPacketType != 2)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->bPacketFlags != 3)
        {
                return 1;
        }
        if(pRpcResponseBaseHeader->wFragLength != dwBytesRead)
        {
                return 1;
        }

        // get a ptr to the main response header body
        pRpcResponseHeader = (RpcResponseHeaderStruct*)((BYTE*)pRpcResponseBaseHeader + sizeof(RpcBaseHeaderStruct));

        // context ID must be 0
        if(pRpcResponseHeader->wContextID != 0)
        {
                return 1;
        }

        // calculate command response data length
        dwProcedureResponseDataLength = pRpcResponseBaseHeader->wFragLength - sizeof(RpcBaseHeaderStruct) - sizeof(RpcResponseHeaderStruct);

        // store response data
        if(dwProcedureResponseDataLength > sizeof(pRpcConnection->bProcedureOutputData))
        {
                return 1;
        }
        pTempProcedureResponseDataPtr = (BYTE*)pRpcResponseHeader + sizeof(RpcResponseHeaderStruct);
        memcpy(pRpcConnection->bProcedureOutputData, pTempProcedureResponseDataPtr, dwProcedureResponseDataLength);

        // store response data length
        pRpcConnection->dwProcedureOutputDataLength = dwProcedureResponseDataLength;

        return 0;
}

DWORD RpcInitialiseRequestData(RpcConnectionStruct *pRpcConnection)
{
        // initialise request data
        memset(pRpcConnection->bProcedureInputData, 0, sizeof(pRpcConnection->bProcedureInputData));
        pRpcConnection->dwProcedureInputDataLength = 0;
        memset(pRpcConnection->bProcedureOutputData, 0, sizeof(pRpcConnection->bProcedureOutputData));
        pRpcConnection->dwProcedureOutputDataLength = 0;

        // reset input error flag
        pRpcConnection->dwInputError = 0;

        // set initialised flag
        pRpcConnection->dwRequestInitialised = 1;

        return 0;
}

DWORD RpcAppendRequestData_Binary(RpcConnectionStruct *pRpcConnection, BYTE *pData, DWORD dwDataLength)
{
        DWORD dwBytesAvailable = 0;

        // ensure the request has been initialised
        if(pRpcConnection->dwRequestInitialised == 0)
        {
                return 1;
        }

        // calculate number of bytes remaining in the input buffer
        dwBytesAvailable = sizeof(pRpcConnection->bProcedureInputData) - pRpcConnection->dwProcedureInputDataLength;
        if(dwDataLength > dwBytesAvailable)
        {
                // set input error flag
                pRpcConnection->dwInputError = 1;

                return 1;
        }

        // store data in buffer
        memcpy((void*)&pRpcConnection->bProcedureInputData, pData, dwDataLength);
        pRpcConnection->dwProcedureInputDataLength += dwDataLength;

        // align to 4 bytes if necessary
        pRpcConnection->dwProcedureInputDataLength += CALC_ALIGN_PADDING(dwDataLength, 4);

        return 0;
}

DWORD RpcAppendRequestData_Dword(RpcConnectionStruct *pRpcConnection, DWORD dwValue)
{
        // add dword value
        if(RpcAppendRequestData_Binary(pRpcConnection, (BYTE*)&dwValue, sizeof(DWORD)) != 0)
        {
                return 1;
        }

        return 0;
}

DWORD RpcDisconnect(RpcConnectionStruct *pRpcConnection)
{
        // close pipe handle
        CloseHandle(pRpcConnection->hFile);

        return 0;
}

int main(int argc, char *argv[])
{
        RpcConnectionStruct RpcConnection;
        BYTE bServiceManagerObject;
        BYTE bServiceObject;
        DWORD dwReturnValue = 0;
        char szServiceName;
        DWORD dwServiceNameLength = 0;
        char szServiceCommandLine;
        DWORD dwServiceCommandLineLength = 0;
        char *pExecCmd = NULL;

        printf("CreateSvcRpc - www.x86matthew.com\n\n");

        if(argc != 2)
        {
                printf("Usage: %s \n\n", argv);

                return 1;
        }

        // get cmd param
        pExecCmd = argv;

        // generate a temporary service name
        memset(szServiceName, 0, sizeof(szServiceName));
        _snprintf(szServiceName, sizeof(szServiceName) - 1, "CreateSvcRpc_%u", GetTickCount());
        dwServiceNameLength = strlen(szServiceName) + 1;

        // set service command line
        memset(szServiceCommandLine, 0, sizeof(szServiceCommandLine));
        _snprintf(szServiceCommandLine, sizeof(szServiceCommandLine) - 1, "cmd /c start %s", pExecCmd);
        dwServiceCommandLineLength = strlen(szServiceCommandLine) + 1;

        printf("Connecting to SVCCTL RPC pipe...\n");

        // open SVCCTL v2.0
        if(RpcConnect("ntsvcs", "367abb81-9844-35f1-ad32-98f038001003", 2, &RpcConnection) != 0)
        {
                printf("Failed to connect to RPC pipe\n");

                return 1;
        }

        printf("Opening service manager...\n");

        // OpenSCManager
        RpcInitialiseRequestData(&RpcConnection);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, SC_MANAGER_ALL_ACCESS);
        if(RpcSendRequest(&RpcConnection, RPC_CMD_ID_OPEN_SC_MANAGER) != 0)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // validate rpc output data length
        if(RpcConnection.dwProcedureOutputDataLength != RPC_OUTPUT_LENGTH_OPEN_SC_MANAGER)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // get return value
        dwReturnValue = *(DWORD*)&RpcConnection.bProcedureOutputData;

        // check return value
        if(dwReturnValue != 0)
        {
                printf("OpenSCManager error: %u\n", dwReturnValue);

                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // store service manager object
        memcpy(bServiceManagerObject, (void*)&RpcConnection.bProcedureOutputData, sizeof(bServiceManagerObject));

        printf("Creating temporary service...\n");

        // CreateService
        RpcInitialiseRequestData(&RpcConnection);
        RpcAppendRequestData_Binary(&RpcConnection, bServiceManagerObject, sizeof(bServiceManagerObject));
        RpcAppendRequestData_Dword(&RpcConnection, dwServiceNameLength);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, dwServiceNameLength);
        RpcAppendRequestData_Binary(&RpcConnection, (BYTE*)szServiceName, dwServiceNameLength);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, SERVICE_ALL_ACCESS);
        RpcAppendRequestData_Dword(&RpcConnection, SERVICE_WIN32_OWN_PROCESS);
        RpcAppendRequestData_Dword(&RpcConnection, SERVICE_DEMAND_START);
        RpcAppendRequestData_Dword(&RpcConnection, SERVICE_ERROR_IGNORE);
        RpcAppendRequestData_Dword(&RpcConnection, dwServiceCommandLineLength);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, dwServiceCommandLineLength);
        RpcAppendRequestData_Binary(&RpcConnection, (BYTE*)szServiceCommandLine, dwServiceCommandLineLength);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        if(RpcSendRequest(&RpcConnection, RPC_CMD_ID_CREATE_SERVICE) != 0)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // validate rpc output data length
        if(RpcConnection.dwProcedureOutputDataLength != RPC_OUTPUT_LENGTH_CREATE_SERVICE)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // get return value
        dwReturnValue = *(DWORD*)&RpcConnection.bProcedureOutputData;

        // check return value
        if(dwReturnValue != 0)
        {
                printf("CreateService error: %u\n", dwReturnValue);

                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // store service object
        memcpy(bServiceObject, (void*)&RpcConnection.bProcedureOutputData, sizeof(bServiceObject));

        printf("Executing '%s' as SYSTEM user...\n", pExecCmd);

        // StartService
        RpcInitialiseRequestData(&RpcConnection);
        RpcAppendRequestData_Binary(&RpcConnection, bServiceObject, sizeof(bServiceObject));
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        RpcAppendRequestData_Dword(&RpcConnection, 0);
        if(RpcSendRequest(&RpcConnection, RPC_CMD_ID_START_SERVICE) != 0)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // validate rpc output data length
        if(RpcConnection.dwProcedureOutputDataLength != RPC_OUTPUT_LENGTH_START_SERVICE)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // get return value
        dwReturnValue = *(DWORD*)&RpcConnection.bProcedureOutputData;

        // check return value
        if(dwReturnValue != 0 && dwReturnValue != ERROR_SERVICE_REQUEST_TIMEOUT)
        {
                printf("StartService error: %u\n", dwReturnValue);

                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        printf("Deleting temporary service...\n");

        // DeleteService
        RpcInitialiseRequestData(&RpcConnection);
        RpcAppendRequestData_Binary(&RpcConnection, bServiceObject, sizeof(bServiceObject));
        if(RpcSendRequest(&RpcConnection, RPC_CMD_ID_DELETE_SERVICE) != 0)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // validate rpc output data length
        if(RpcConnection.dwProcedureOutputDataLength != RPC_OUTPUT_LENGTH_DELETE_SERVICE)
        {
                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        // get return value
        dwReturnValue = *(DWORD*)&RpcConnection.bProcedureOutputData;

        // check return value
        if(dwReturnValue != 0)
        {
                printf("DeleteService error: %u\n", dwReturnValue);

                // error
                RpcDisconnect(&RpcConnection);

                return 1;
        }

        printf("Finished\n");

        // disconnect from rpc pipe
        if(RpcDisconnect(&RpcConnection) != 0)
        {
                return 1;
        }

        return 0;
}
页: [1]
查看完整版本: CreateSvcRpc - 一个自定义的RPC客户端,以SYSTEM用户身份执行程序