梦幻的彼岸 发表于 2022-2-15 16:20:19

CallRemoteAPI - 调用远程进程中的函数

翻译
原文地址:https://www.x86matthew.com/view_post?id=call_remote_api
功能:调用远程进程中的函数
目前我们可以使用CreateRemoteThread来调用一个远程进程中的函数,但这只限于以下格式的函数:
DWORD __stdcall ThreadProc(LPVOID lpParameter);
我开发了一个通用函数,可以远程调用任何API。首先,自动生成代码存根并将其写入目标进程:
push param_1
push param_2
push param_3
...
mov eax, TargetFunction
call eax
push eax
mov eax, RtlExitUserThread
call eax
这段代码调用目标函数,然后用原函数的返回值调用RtlExitUserThread。

我们可以使用CreateRemoteThread在目标进程中执行上述代码,使用WaitForSingleObject等待线程退出,并使用GetExitCodeThread获取返回值。

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

DWORD CallRemoteAPI(HANDLE hProcess, DWORD dwAddr, DWORD *pdwParamList, DWORD dwParamCount, DWORD *pdwReturnValue)
{
        DWORD dwThreadID = 0;
        HANDLE hThread = NULL;
        DWORD dwExitCode = 0;
        DWORD dwRtlExitUserThread = 0;
        DWORD dwExecFunctionCodeLength = 0;
        BYTE bPushParamCode[] = { 0x68, 0x00, 0x00, 0x00, 0x00 };
        BYTE bExecFunctionCode[] = { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x50, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0 };
        BYTE *pRemoteExecFunctionCode = NULL;

        // get RtlExitUserThread address
        dwRtlExitUserThread = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlExitUserThread");
        if(dwRtlExitUserThread == 0)
        {
                return 1;
        }

        // calculate code length:
        // push param_1
        // push param_2
        // push param_3
        // ...
        // mov eax, TargetFunction
        // call eax
        // push eax
        // mov eax, RtlExitUserThread
        // call eax
        dwExecFunctionCodeLength = (dwParamCount * sizeof(bPushParamCode)) + sizeof(bExecFunctionCode);

        // allocate memory in remote process
        pRemoteExecFunctionCode = (BYTE*)VirtualAllocEx(hProcess, NULL, dwExecFunctionCodeLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if(pRemoteExecFunctionCode == NULL)
        {
                return 1;
        }

        // write function parameter values
        for(DWORD i = 0; i < dwParamCount; i++)
        {
                // set current param value
                *(DWORD*)&bPushParamCode = pdwParamList;
                if(WriteProcessMemory(hProcess, (BYTE*)(pRemoteExecFunctionCode + (i * sizeof(bPushParamCode))), (void*)bPushParamCode, sizeof(bPushParamCode), NULL) == 0)
                {
                        // error
                        VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

                        return 1;
                }
        }

        // set target function address
        *(DWORD*)&bExecFunctionCode = dwAddr;

        // set RtlExitUserThread function address
        *(DWORD*)&bExecFunctionCode = dwRtlExitUserThread;

        // write function execution code
        if(WriteProcessMemory(hProcess, (BYTE*)(pRemoteExecFunctionCode + (dwParamCount * sizeof(bPushParamCode))), (void*)bExecFunctionCode, sizeof(bExecFunctionCode), NULL) == 0)
        {
                // error
                VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

                return 1;
        }

        // create a thread in the remote process
        hThread = CreateRemoteThread(hProcess, NULL, (128 * 1024), (LPTHREAD_START_ROUTINE)pRemoteExecFunctionCode, NULL, 0, &dwThreadID);
        if(hThread == NULL)
        {
                // error
                VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

                return 1;
        }

        // wait for thread to complete
        WaitForSingleObject(hThread, INFINITE);

        // get thread exit code (api return value)
        if(GetExitCodeThread(hThread, &dwExitCode) == 0)
        {
                // error
                CloseHandle(hThread);
                VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

                return 1;
        }

        // close thread handle
        CloseHandle(hThread);

        // free remote code block
        VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

        // store return value
        *pdwReturnValue = dwExitCode;

        return 0;
}
如果我们需要在远程进程中分配更多的数据(例如字符串参数),我们可以使用以下函数:
BYTE *AllocateRemoteData(HANDLE hProcess, BYTE *pData, DWORD dwDataLength)
{
        BYTE *pRemoteDataAddr = NULL;

        // allocate memory in remote process
        pRemoteDataAddr = (BYTE*)VirtualAllocEx(hProcess, NULL, dwDataLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if(pRemoteDataAddr == NULL)
        {
                return NULL;
        }

        if(pData != NULL)
        {
                // write data to remote process
                if(WriteProcessMemory(hProcess, pRemoteDataAddr, (void*)pData, dwDataLength, NULL) == 0)
                {
                        // error
                        VirtualFreeEx(hProcess, pRemoteDataAddr, 0, MEM_RELEASE);

                        return NULL;
                }
        }

        return pRemoteDataAddr;
}

BYTE *AllocateRemoteString(HANDLE hProcess, char *pData)
{
        // allocate string data
        return AllocateRemoteData(hProcess, (BYTE*)pData, strlen(pData) + 1);
}
例子 #1 - 在一个远程进程中调用MessageBoxA
int main(int argc, char *argv[])
{
        DWORD dwPID = 0;
        char *pMsgTextParam = NULL;
        DWORD dwReturnValue = 0;
        DWORD dwParamList;
        HANDLE hProcess = NULL;
        void *pMsgTitle = NULL;
        void *pMsgText = NULL;

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

                return 1;
        }

        // get command-line param values
        dwPID = atoi(argv);
        pMsgTextParam = argv;

        printf("Opening process: %u...\n", dwPID);

        // open target process
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPID);
        if(hProcess == NULL)
        {
                // error
                printf("Failed to open process: %u\n", dwPID);

                return 1;
        }

        printf("Allocating strings in remote process...\n\n");

        // allocate string in remote process
        pMsgTitle = AllocateRemoteString(hProcess, "CallRemoteAPI");
        if(pMsgTitle == NULL)
        {
                printf("Failed to allocate string\n");

                // error
                CloseHandle(hProcess);

                return 1;
        }

        // allocate string in remote process
        pMsgText = AllocateRemoteString(hProcess, pMsgTextParam);
        if(pMsgText == NULL)
        {
                printf("Failed to allocate string\n");

                // error
                VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        // set MessageBox parameters
        dwParamList = 0;
        dwParamList = (DWORD)pMsgText;
        dwParamList = (DWORD)pMsgTitle;
        dwParamList = MB_OK;

        printf("Calling MessageBoxA in remote process...\n");

        // call MessageBox in target process
        if(CallRemoteAPI(hProcess, (DWORD)MessageBoxA, dwParamList, 4, &dwReturnValue) != 0)
        {
                printf("Failed to call remote API\n");

                // error
                VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pMsgText, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        printf("MessageBoxA returned: %u\n", dwReturnValue);

        // free remote memory
        VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
        VirtualFreeEx(hProcess, pMsgText, 0, MEM_RELEASE);
        CloseHandle(hProcess);

        return 0;
}


例子#2 - 在一个远程进程中创建一个文件
int main(int argc, char *argv[])
{
        DWORD dwPID = 0;
        char *pFilePathParam = NULL;
        char *pContentParam = NULL;
        DWORD dwReturnValue = 0;
        DWORD dwParamList;
        HANDLE hProcess = NULL;
        void *pFilePath = NULL;
        void *pContent = NULL;
        void *pBytesWritten = NULL;
        HANDLE hFile = NULL;

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

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

                return 1;
        }

        // get command-line param values
        dwPID = atoi(argv);
        pFilePathParam = argv;
        pContentParam = argv;

        printf("Opening process: %u...\n", dwPID);

        // open target process
        hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPID);
        if(hProcess == NULL)
        {
                // error
                printf("Failed to open process: %u\n", dwPID);

                return 1;
        }

        printf("Allocating data in remote process...\n\n");

        // allocate string in remote process
        pFilePath = AllocateRemoteString(hProcess, pFilePathParam);
        if(pFilePath == NULL)
        {
                printf("Failed to allocate string\n");

                // error
                CloseHandle(hProcess);

                return 1;
        }

        // allocate string in remote process
        pContent = AllocateRemoteString(hProcess, pContentParam);
        if(pContent == NULL)
        {
                printf("Failed to allocate string\n");

                // error
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        // allocate dword value (BytesWritten) in remote process
        pBytesWritten = AllocateRemoteData(hProcess, NULL, sizeof(DWORD));
        if(pBytesWritten == NULL)
        {
                printf("Failed to allocate value\n");

                // error
                VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        // set CreateFile parameters
        dwParamList = (DWORD)pFilePath;
        dwParamList = GENERIC_WRITE;
        dwParamList = 0;
        dwParamList = 0;
        dwParamList = CREATE_ALWAYS;
        dwParamList = FILE_ATTRIBUTE_NORMAL;
        dwParamList = 0;

        printf("Calling CreateFileA...\n");

        // call CreateFileA
        if(CallRemoteAPI(hProcess, (DWORD)CreateFileA, dwParamList, 7, &dwReturnValue) != 0)
        {
                printf("Failed to call remote API\n");

                // error
                VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        printf("CreateFileA returned 0x%08x\n\n", dwReturnValue);

        // store the returned file handle
        hFile = (HANDLE)dwReturnValue;

        // check if CreateFile failed
        if(hFile == INVALID_HANDLE_VALUE)
        {
                printf("CreateFileA failed\n");

                // error
                VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        // set WriteFile parameters
        dwParamList = (DWORD)hFile;
        dwParamList = (DWORD)pContent;
        dwParamList = strlen(pContentParam);
        dwParamList = (DWORD)pBytesWritten;
        dwParamList = 0;

        printf("Calling WriteFile...\n");

        // call WriteFile
        if(CallRemoteAPI(hProcess, (DWORD)WriteFile, dwParamList, 5, &dwReturnValue) != 0)
        {
                printf("Failed to call remote API\n");

                // error
                VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        printf("WriteFile returned 0x%08x\n\n", dwReturnValue);

        // set CloseHandle parameters
        dwParamList = (DWORD)hFile;

        printf("Calling CloseHandle...\n");

        // call CloseHandle
        if(CallRemoteAPI(hProcess, (DWORD)CloseHandle, dwParamList, 1, &dwReturnValue) != 0)
        {
                printf("Failed to call remote API\n");

                // error
                VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
                VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
                CloseHandle(hProcess);

                return 1;
        }

        printf("CloseHandle returned 0x%08x\n\n", dwReturnValue);

        // clean up
        VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
        VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
        VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
        CloseHandle(hProcess);

        return 0;
}
页: [1]
查看完整版本: CallRemoteAPI - 调用远程进程中的函数