在Windows上可以使用CreateRemoteThread實現遠端Call,但是有不帶返回值且只能傳遞一個引數的限制。
將多個引數利用VirtualAllocEx和WriteProcessMemory寫入目標程式,再通過此方法注入一段shellcode,通過shellcode完成多引數的呼叫。
push var_1
...
push var_n
mov eax,function_addr
/*
如果為 cdcel則需要平棧
add esp,count_param
*/
call eax
#include <iostream>
#include <Windows.h>
#include <vector>
#include <thread>
using namespace std;
LPVOID RemoteNew(HANDLE hProcess, PUCHAR data,size_t size)
{
auto hMem=VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (hMem == NULL)
{
return FALSE;
}
if (WriteProcessMemory(hProcess, hMem, data, size,NULL) == FALSE)
{
VirtualFreeEx(hProcess, hMem, 0, MEM_RELEASE);
return FALSE;
}
return hMem;
}
BOOL RemoteCall(
HANDLE hProcess,
LPVOID remoteFuncAddr,
vector<LPVOID> param,
bool cdcelCall,
bool waitRemoteThread
)
{
if (remoteFuncAddr == NULL)
return FALSE;
vector<UCHAR> shellcode;
//push 結構
for (int i = param.size() - 1; i >= 0; i--)//呼叫棧是個棧
{
if (((UINT)param[i]) <= 255) //小引數可以只傳低位
shellcode.push_back(106), shellcode.push_back((UCHAR)param[i]); //push byte
else
shellcode.push_back(104), shellcode.insert(shellcode.end(), (PUCHAR)¶m[i], (PUCHAR)(¶m[i] + 1)); //push dword
}
//把addr塞入暫存器
shellcode.push_back(184); //mov
shellcode.insert(shellcode.end(), (PUCHAR)&remoteFuncAddr, (PUCHAR)(&remoteFuncAddr + 1)); //eax,addr
shellcode.push_back(255),shellcode.push_back(208);//call eax
if (cdcelCall)
{
size_t paramSize = param.size() * sizeof(LPVOID);
//cdcel是函數呼叫後平棧,stdcall是函數自己平
shellcode.push_back(129), shellcode.push_back(196);//add esp
shellcode.insert(shellcode.end(), (PUCHAR)¶mSize, (PUCHAR)(¶mSize + 1));
}
shellcode.push_back(195);//ret
auto shellcodeAddr=RemoteNew(hProcess, shellcode.data(), shellcode.size() * sizeof(UCHAR));
if (shellcodeAddr == NULL)
return FALSE;
auto hThread=CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)shellcodeAddr, NULL, NULL, NULL);
if (hThread == NULL)
{
VirtualFreeEx(hProcess, shellcodeAddr, 0, MEM_RELEASE);
return FALSE;
}
thread waiter([hThread, hProcess, shellcodeAddr] {
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(hProcess, shellcodeAddr, 0, MEM_RELEASE);
DWORD retCode;
GetExitCodeThread(hThread, &retCode);
cout <<"Ret: " << retCode << endl;
});
if (waitRemoteThread)
waiter.join();
else
waiter.detach();
return TRUE;
}
int add(int a, int b)
{
return a + b;
}
int main()
{
char a[] = "hello world";
char b[] = "C++ YES";
//-1是自己
RemoteCall((HANDLE)-1, add, { (LPVOID)1,(LPVOID)3 }, true, true);
auto p1 = RemoteNew((HANDLE)-1, (PUCHAR)a, sizeof(a));
auto p2 = RemoteNew((HANDLE)-1, (PUCHAR)b, sizeof(b));
RemoteCall((HANDLE)-1, MessageBoxA, { 0, p1,p2,(LPVOID)64 }, true, true);
std::cout << "Hello World!\n";
Sleep(-1);
}
目前只能實現32位元的遠端呼叫,64位元新增了記憶體的可執行許可權,這樣注入的shellcode沒法執行。
返回值只能接受32位元整數,其實實現64位元整數和浮點的方法也不復雜,都可以用組合把對應暫存器的值寫到記憶體裡,但是情況比較多,懶得寫了。