[远程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位整数和浮点的方法也不复杂,都可以用汇编把对应寄存器的值写到内存里,但是情况比较多,懒得写了。

__EOF__

  • 本文作者: Ice
  • 本文链接: https://www.cnblogs.com/Icys/p/RemoteCall.html
  • 关于博主: I am a student.
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • © 版权声明
    THE END
    喜欢就支持一下吧
    点赞0

    Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYOaOJyH' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
    admin的头像-五八三
    评论 抢沙发
    头像
    欢迎您留下宝贵的见解!
    提交
    头像

    昵称

    图形验证码
    取消
    昵称代码图片