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]