[远程Call]32位远程多参数带返回调用

[远程Call]32位远程多参数带返回调用

引子

在Windows上可以使用CreateRemoteThread实现远程Call,但是有不带返回值且只能传递一个参数的限制。

解决思路

将多个参数利用VirtualAllocEx和WriteProcessMemory写入目标程序,再通过此方法注入一段shellcode,通过shellcode完成多参数的调用。

核心shellcode
push var_1 ... push var_n mov eax,function_addr /* 如果为 cdcel则需要平栈 add esp,count_param */ call eax 
实现c++代码
#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)&param[i], (PUCHAR)(&param[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)&paramSize, (PUCHAR)(&paramSize + 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); } 
实现缺陷
  1. 目前只能实现32位的远程调用,64位新增了内存的可执行权限,这样注入的shellcode没法执行。

  2. 返回值只能接受32位整数,其实实现64位整数和浮点的方法也不复杂,都可以用汇编把对应寄存器的值写到内存里,但是情况比较多,懒得写了。

发表评论

评论已关闭。

相关文章