飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 1005|回复: 0

[C/C++] CallRemoteAPI - 调用远程进程中的函数

[复制链接]
  • TA的每日心情
    开心
    2019-3-15 11:00
  • 签到天数: 262 天

    [LV.8]以坛为家I

    发表于 2022-2-15 16:20:19 | 显示全部楼层 |阅读模式
    翻译
    原文地址:https://www.x86matthew.com/view_post?id=call_remote_api
    功能:调用远程进程中的函数
    目前我们可以使用CreateRemoteThread来调用一个远程进程中的函数,但这只限于以下格式的函数:
    1. DWORD __stdcall ThreadProc(LPVOID lpParameter);
    复制代码

    我开发了一个通用函数,可以远程调用任何API。首先,自动生成代码存根并将其写入目标进程:
    1. push param_1
    2. push param_2
    3. push param_3
    4. ...
    5. mov eax, TargetFunction
    6. call eax
    7. push eax
    8. mov eax, RtlExitUserThread
    9. call eax
    复制代码

    这段代码调用目标函数,然后用原函数的返回值调用RtlExitUserThread。

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

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

    3. DWORD CallRemoteAPI(HANDLE hProcess, DWORD dwAddr, DWORD *pdwParamList, DWORD dwParamCount, DWORD *pdwReturnValue)
    4. {
    5.         DWORD dwThreadID = 0;
    6.         HANDLE hThread = NULL;
    7.         DWORD dwExitCode = 0;
    8.         DWORD dwRtlExitUserThread = 0;
    9.         DWORD dwExecFunctionCodeLength = 0;
    10.         BYTE bPushParamCode[] = { 0x68, 0x00, 0x00, 0x00, 0x00 };
    11.         BYTE bExecFunctionCode[] = { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x50, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0 };
    12.         BYTE *pRemoteExecFunctionCode = NULL;

    13.         // get RtlExitUserThread address
    14.         dwRtlExitUserThread = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlExitUserThread");
    15.         if(dwRtlExitUserThread == 0)
    16.         {
    17.                 return 1;
    18.         }

    19.         // calculate code length:
    20.         // push param_1
    21.         // push param_2
    22.         // push param_3
    23.         // ...
    24.         // mov eax, TargetFunction
    25.         // call eax
    26.         // push eax
    27.         // mov eax, RtlExitUserThread
    28.         // call eax
    29.         dwExecFunctionCodeLength = (dwParamCount * sizeof(bPushParamCode)) + sizeof(bExecFunctionCode);

    30.         // allocate memory in remote process
    31.         pRemoteExecFunctionCode = (BYTE*)VirtualAllocEx(hProcess, NULL, dwExecFunctionCodeLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    32.         if(pRemoteExecFunctionCode == NULL)
    33.         {
    34.                 return 1;
    35.         }

    36.         // write function parameter values
    37.         for(DWORD i = 0; i < dwParamCount; i++)
    38.         {
    39.                 // set current param value
    40.                 *(DWORD*)&bPushParamCode[1] = pdwParamList[dwParamCount - 1 - i];
    41.                 if(WriteProcessMemory(hProcess, (BYTE*)(pRemoteExecFunctionCode + (i * sizeof(bPushParamCode))), (void*)bPushParamCode, sizeof(bPushParamCode), NULL) == 0)
    42.                 {
    43.                         // error
    44.                         VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

    45.                         return 1;
    46.                 }
    47.         }

    48.         // set target function address
    49.         *(DWORD*)&bExecFunctionCode[1] = dwAddr;

    50.         // set RtlExitUserThread function address
    51.         *(DWORD*)&bExecFunctionCode[9] = dwRtlExitUserThread;

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

    57.                 return 1;
    58.         }

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

    65.                 return 1;
    66.         }

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

    69.         // get thread exit code (api return value)
    70.         if(GetExitCodeThread(hThread, &dwExitCode) == 0)
    71.         {
    72.                 // error
    73.                 CloseHandle(hThread);
    74.                 VirtualFreeEx(hProcess, pRemoteExecFunctionCode, 0, MEM_RELEASE);

    75.                 return 1;
    76.         }

    77.         // close thread handle
    78.         CloseHandle(hThread);

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

    81.         // store return value
    82.         *pdwReturnValue = dwExitCode;

    83.         return 0;
    84. }
    复制代码

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

    4.         // allocate memory in remote process
    5.         pRemoteDataAddr = (BYTE*)VirtualAllocEx(hProcess, NULL, dwDataLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    6.         if(pRemoteDataAddr == NULL)
    7.         {
    8.                 return NULL;
    9.         }

    10.         if(pData != NULL)
    11.         {
    12.                 // write data to remote process
    13.                 if(WriteProcessMemory(hProcess, pRemoteDataAddr, (void*)pData, dwDataLength, NULL) == 0)
    14.                 {
    15.                         // error
    16.                         VirtualFreeEx(hProcess, pRemoteDataAddr, 0, MEM_RELEASE);

    17.                         return NULL;
    18.                 }
    19.         }

    20.         return pRemoteDataAddr;
    21. }

    22. BYTE *AllocateRemoteString(HANDLE hProcess, char *pData)
    23. {
    24.         // allocate string data
    25.         return AllocateRemoteData(hProcess, (BYTE*)pData, strlen(pData) + 1);
    26. }
    复制代码

    例子 #1 - 在一个远程进程中调用MessageBoxA
    1. int main(int argc, char *argv[])
    2. {
    3.         DWORD dwPID = 0;
    4.         char *pMsgTextParam = NULL;
    5.         DWORD dwReturnValue = 0;
    6.         DWORD dwParamList[4];
    7.         HANDLE hProcess = NULL;
    8.         void *pMsgTitle = NULL;
    9.         void *pMsgText = NULL;

    10.         if(argc != 3)
    11.         {
    12.                 printf("Usage: %s [target_pid] [msg]\n\n", argv[0]);

    13.                 return 1;
    14.         }

    15.         // get command-line param values
    16.         dwPID = atoi(argv[1]);
    17.         pMsgTextParam = argv[2];

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

    19.         // open target process
    20.         hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPID);
    21.         if(hProcess == NULL)
    22.         {
    23.                 // error
    24.                 printf("Failed to open process: %u\n", dwPID);

    25.                 return 1;
    26.         }

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

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

    33.                 // error
    34.                 CloseHandle(hProcess);

    35.                 return 1;
    36.         }

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

    42.                 // error
    43.                 VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
    44.                 CloseHandle(hProcess);

    45.                 return 1;
    46.         }

    47.         // set MessageBox parameters
    48.         dwParamList[0] = 0;
    49.         dwParamList[1] = (DWORD)pMsgText;
    50.         dwParamList[2] = (DWORD)pMsgTitle;
    51.         dwParamList[3] = MB_OK;

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

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

    57.                 // error
    58.                 VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
    59.                 VirtualFreeEx(hProcess, pMsgText, 0, MEM_RELEASE);
    60.                 CloseHandle(hProcess);

    61.                 return 1;
    62.         }

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

    64.         // free remote memory
    65.         VirtualFreeEx(hProcess, pMsgTitle, 0, MEM_RELEASE);
    66.         VirtualFreeEx(hProcess, pMsgText, 0, MEM_RELEASE);
    67.         CloseHandle(hProcess);

    68.         return 0;
    69. }
    复制代码

    1.png

    例子#2 - 在一个远程进程中创建一个文件
    1. int main(int argc, char *argv[])
    2. {
    3.         DWORD dwPID = 0;
    4.         char *pFilePathParam = NULL;
    5.         char *pContentParam = NULL;
    6.         DWORD dwReturnValue = 0;
    7.         DWORD dwParamList[16];
    8.         HANDLE hProcess = NULL;
    9.         void *pFilePath = NULL;
    10.         void *pContent = NULL;
    11.         void *pBytesWritten = NULL;
    12.         HANDLE hFile = NULL;

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

    14.         if(argc != 4)
    15.         {
    16.                 printf("Usage: %s [target_pid] [file_path] [content]\n\n", argv[0]);

    17.                 return 1;
    18.         }

    19.         // get command-line param values
    20.         dwPID = atoi(argv[1]);
    21.         pFilePathParam = argv[2];
    22.         pContentParam = argv[3];

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

    24.         // open target process
    25.         hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, dwPID);
    26.         if(hProcess == NULL)
    27.         {
    28.                 // error
    29.                 printf("Failed to open process: %u\n", dwPID);

    30.                 return 1;
    31.         }

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

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

    38.                 // error
    39.                 CloseHandle(hProcess);

    40.                 return 1;
    41.         }

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

    47.                 // error
    48.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    49.                 CloseHandle(hProcess);

    50.                 return 1;
    51.         }

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

    57.                 // error
    58.                 VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    59.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    60.                 CloseHandle(hProcess);

    61.                 return 1;
    62.         }

    63.         // set CreateFile parameters
    64.         dwParamList[0] = (DWORD)pFilePath;
    65.         dwParamList[1] = GENERIC_WRITE;
    66.         dwParamList[2] = 0;
    67.         dwParamList[3] = 0;
    68.         dwParamList[4] = CREATE_ALWAYS;
    69.         dwParamList[5] = FILE_ATTRIBUTE_NORMAL;
    70.         dwParamList[6] = 0;

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

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

    76.                 // error
    77.                 VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
    78.                 VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    79.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    80.                 CloseHandle(hProcess);

    81.                 return 1;
    82.         }

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

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

    86.         // check if CreateFile failed
    87.         if(hFile == INVALID_HANDLE_VALUE)
    88.         {
    89.                 printf("CreateFileA failed\n");

    90.                 // error
    91.                 VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
    92.                 VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    93.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    94.                 CloseHandle(hProcess);

    95.                 return 1;
    96.         }

    97.         // set WriteFile parameters
    98.         dwParamList[0] = (DWORD)hFile;
    99.         dwParamList[1] = (DWORD)pContent;
    100.         dwParamList[2] = strlen(pContentParam);
    101.         dwParamList[3] = (DWORD)pBytesWritten;
    102.         dwParamList[4] = 0;

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

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

    108.                 // error
    109.                 VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
    110.                 VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    111.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    112.                 CloseHandle(hProcess);

    113.                 return 1;
    114.         }

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

    116.         // set CloseHandle parameters
    117.         dwParamList[0] = (DWORD)hFile;

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

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

    123.                 // error
    124.                 VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
    125.                 VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    126.                 VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    127.                 CloseHandle(hProcess);

    128.                 return 1;
    129.         }

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

    131.         // clean up
    132.         VirtualFreeEx(hProcess, pBytesWritten, 0, MEM_RELEASE);
    133.         VirtualFreeEx(hProcess, pContent, 0, MEM_RELEASE);
    134.         VirtualFreeEx(hProcess, pFilePath, 0, MEM_RELEASE);
    135.         CloseHandle(hProcess);

    136.         return 0;
    137. }
    复制代码

    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表