(资料图)
[远程Call]32位远程多参数带返回调用引子解决思路在Windows上可以使用CreateRemoteThread实现远程Call,但是有不带返回值且只能传递一个参数的限制。
核心shellcode将多个参数利用VirtualAllocEx和WriteProcessMemory写入目标程序,再通过此方法注入一段shellcode,通过shellcode完成多参数的调用。
push var_1...push var_nmov eax,function_addr/*如果为 cdcel则需要平栈add esp,count_param*/call eax
实现c++代码#include #include #include #include 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 param, bool cdcelCall, bool waitRemoteThread ){ if (remoteFuncAddr == NULL) return FALSE; vector 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位整数和浮点的方法也不复杂,都可以用汇编把对应寄存器的值写到内存里,但是情况比较多,懒得写了。
关键词: