目的
在目标程序远程注入代码,并执行注入的调用代码。
这是原来正常调用时弹出的消息
下图是经过了远程注入代码调用的消息
原理:将调用目标函数的代码,sellcode的形式写入到目标进程中,再远程调用写入的代码。
核心代码:
//构造的调用目标函数
void MsgCall(LPVOID lParam)
{
DWORD moduleBase = 0;
MessageParam* msgPara = (MessageParam*)(lParam);
_GetModuleHandle m = (_GetModuleHandle)(*(DWORD*)(lParam));
moduleBase = (DWORD)m(NULL);
DWORD nameBase = msgPara->maistrBase;
if (moduleBase)
{
DWORD _CALL = moduleBase + CALL_MSG_BASE;
_asm
{
push nameBase
mov eax, _CALL
call eax
add esp,4
}
}
}
//**************************************************************************************
//函数名:InSendFunc
//功能 :封装远程注入的函数
//参数 1:进程句柄
//参数 2:进程ID
//参数 3:被注入函数指针<函数名>
//参数 4:参数
//参数 5:参数长度
//参数 6:注入函数地址
//参数 7:注入的参数地址
//**************************************************************************************
void InSendFunc(HANDLE hProcess, DWORD dwProcId, LPVOID mFunc, LPVOID Param, DWORD ParamSize, LPVOID mFuncAddr, LPVOID ParamAddr)
{
HANDLE hThread = NULL; //线程句柄
DWORD NumberOfByte = NULL; //辅助返回值
//打开被注入的进程句柄
__try {
//写内存
if (!WriteProcessMemory(hProcess, mFuncAddr, mFunc, 128, &NumberOfByte)) {
__leave;
}
WriteProcessMemory(hProcess, ParamAddr, Param, ParamSize, &NumberOfByte);
//创建远程线程
hThread = ::CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)mFuncAddr,
ParamAddr, 0, &NumberOfByte);
if (hThread == NULL) {
__leave;
}
WaitForSingleObject(hThread, INFINITE); //等待线程结束
//释放申请有内存
}
__finally {
//释放远程句柄
if (hThread)
{
CloseHandle(hThread);
}
}
}
void CRemoteCallDemoDlg::OnBnClickedOk()
{
UpdateData(TRUE);
HWND hGameWnd = ::FindWindow(NULL, _T("演示DEMO"));
if (NULL == hGameWnd)
{
MessageBox(_T("未找到窗口"));
return;
}
DWORD dwProcessId = 0;
DWORD dwThreadId = ::GetWindowThreadProcessId(hGameWnd, &dwProcessId);
//获得目标进程中 LoadLibrary函数的地址
#if _UNICODE
void(*addrRemoteLoadLibrary)(wchar_t*) = (void(*)(wchar_t*))GetProcAddress(GetModuleHandle(_T("Kernel32.dll")), "GetModuleHandleW");
#else
void(*addrRemoteLoadLibrary)(char*) = (void(*)(char*))GetProcAddress(GetModuleHandle(_T("Kernel32.dll")), "GetModuleHandle");
#endif
//提权
ImproveProcPriv();
HANDLE hProcess = INVALID_HANDLE_VALUE;
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, TRUE, dwProcessId);
if (NULL == hProcess) {
MessageBox(_T("无法打开进程"));
return;
}
//先申请内存
LPVOID mFuncAddr = NULL;//申请函数内存地址
LPVOID ParamAddr = NULL;//申请参数内存地址
LPVOID MsgConAddr = NULL;
//申请内存 这里函数128个字节足够用了,如果以后写的调用函数更多,则这里需要加大字节数
mFuncAddr = ::VirtualAllocEx(hProcess, NULL, 128, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ParamAddr = ::VirtualAllocEx(hProcess, NULL, sizeof(MessageParam), MEM_COMMIT, PAGE_READWRITE);
std::wstring strName = CString(_T("Romte CALL Test Success!"));
//&str.c_str();
int len = strName.length()*2 +2 ;
//开始申请写入内容
MsgConAddr = ::VirtualAllocEx(hProcess, NULL, len, MEM_COMMIT, PAGE_READWRITE);
DDwrite(hProcess, MsgConAddr, strName.c_str(), strName.length()*2);
MessageParam mailP;
mailP.getModulBase = (DWORD)addrRemoteLoadLibrary;
mailP.maistrBase = (DWORD)MsgConAddr;
InSendFunc(hProcess, dwProcessId, MsgCall, &mailP, sizeof(MessageParam), mFuncAddr, ParamAddr);
if (MsgConAddr)
{
::VirtualFreeEx(hProcess, MsgConAddr, len, MEM_RELEASE);
}
if (mFuncAddr)
{
::VirtualFreeEx(hProcess, mFuncAddr, 128, MEM_RELEASE);
}
if (ParamAddr)
{
::VirtualFreeEx(hProcess, ParamAddr, sizeof(MessageParam), MEM_RELEASE);
}
UpdateData(FALSE);
}
代码实现都是相对简单的,难点在与,如何找到目标call,并分析出目标call的调用逻辑,堆栈平衡等问题,崩溃的原因往往是堆栈不平衡造成的。