注入
2 注入 2.1 Hook Hook链表,由系统来维护,最新安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。如果钩子在尚未卸载之前就结束了,那么系统会自动为它做卸载钩子的操作。 参数2,不能定义成某个类的成员函数,只能定义为普通的C函数。不同类型回调函数,其参数意义不同。 参数3,若dwThreadId=0即系统钩子,则指向lpfn回调函数所在Dll的句柄,否则即是局部线程钩子,则置NULL 参数4,若0,则Hook所有线程,即指定线程为局部线程钩子,否则为系统钩子。 几点说明: (1)如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子,然后调用系统钩子。 (2)对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。当前钩子处理结束后应把钩子信息传递给下一个钩子函数。 (3)钩子特别是系统钩子会消耗消息处理时间,降低系统性能。只有在必要的时候才安装钩子,在使用完毕后要及时卸载。 局部线程钩子,本进程线程,钩子回调代码在本地,不需要Dll 系统钩子,分为所有线程和其他进程某个线程,都需要Dll(钩子回调放在Dll内)
2.2 CreateRemoteThread+Dll BOOL CRemoteInjectTool::Inject() { BOOL isRet = FALSE; if (m_strDllPath.GetLength() && m_dwPID) { //提权 EnableDebugPriv(); //获取进程句柄 HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwPID); if (hProcess) { //在目标进程内申请内存空间 PVOID lpBuff = VirtualAllocEx( hProcess, 0, m_strDllPath.GetLength() + 1, MEM_COMMIT, PAGE_READWRITE ); if ( lpBuff ) { DWORD dwWrite; if ( WriteProcessMemory( hProcess, lpBuff, (PVOID)m_strDllPath.GetBuffer(0), m_strDllPath.GetLength() + 1, &dwWrite ) ) { //取LoadLibrary地址 LPTHREAD_START_ROUTINE pfnLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress( GetModuleHandle("kernel32.dll"), "LoadLibraryA" ); if (pfnLoadLibrary) { //创建远程线程 DWORD dwTID; HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, pfnLoadLibrary, lpBuff, 0, &dwTID ); if (hThread) { //等待LoadLibrary结束 WaitForSingleObject( hThread, INFINITE ); //获取LoadLibrary返回值,释放DLL用 DWORD dwExitCode; GetExitCodeThread( hThread, &dwExitCode ); m_hDll = (HMODULE)dwExitCode; isRet = (BOOL)m_hDll; CloseHandle(hThread); hThread = NULL; } } } VirtualFreeEx( hProcess, lpBuff, 0/*0则释放所申请到的所有内存空间*/, MEM_RELEASE ); } CloseHandle(hProcess); hProcess = NULL; } } return isRet; } BOOL CRemoteInjectTool::Uninject() { BOOL isRet = FALSE; if (m_strDllPath.GetLength() && m_dwPID) { //获取进程句柄 HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_dwPID); if (hProcess) { //取LoadLibrary地址 LPTHREAD_START_ROUTINE pfnFreeLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibrary"); if (pfnFreeLibrary) { //创建远程线程 DWORD dwTID; HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, pfnFreeLibrary, m_hDll, 0, &dwTID); if (hThread) { //等待LoadLibrary结束 WaitForSingleObject( hThread, INFINITE ); //获取LoadLibrary返回值,释放DLL用 DWORD dwExitCode; GetExitCodeThread( hThread, &dwExitCode ); isRet = TRUE; CloseHandle(hThread); hThread = NULL; } } CloseHandle(hProcess); hProcess = NULL; } } return isRet; } 2.3 WriteProcessMemory+ CreateRemoteThread 不需要Dll,直接把代码复制到远程进程的内存中 编写ThreadFunc时必须遵守以下规则: 1. ThreadFunc不能调用除kernel32.dll和user32.dll之外动态库中的API函数。只有kernel32.dll和user32.dll(如果被加载)可以保证在本地和目的进程中的加载地址是一样的。(注意:user32并不一定被所有的Win32进程加载!) 如果你需要调用其他库中的函数,在注入的代码中使用LoadLibrary和GetProcessAddress强制加载。如果由于某种原因,你需要的动态库已经被映射进了目的进程,你也可以使用GetMoudleHandle代替LoadLibrary。 如果你想在ThreadFunc中调用你自己的函数,那么就分别复制这些函数到远程进程并通过INJDATA把地址提供给ThreadFunc。 2. 不要使用static字符串。把所有的字符串提供INJDATA传递。为什么?编译器会把所有的静态字符串放在可执行文件的“.data”段,而仅仅在代码中保留它们的引用(即指针)。这样,远程进程中的ThreadFunc就会执行不存在的内存数据(至少没有在它自己的内存空间中)。 3. 去掉编译器的/GZ编译选项。这个选项是默认的。 4. 要么把ThreadFunc和AfterThreadFunc声明为static,要么关闭编译器的“增量连接(incremental linking)”。 5. ThreadFunc中的局部变量总大小必须小于4k字节。注意,当degug编译时,这4k中大约有10个字节会被事先占用。 6. 如果有多于3个switch分支的case语句,必须像下面这样分割开,或用if-else if代替: switch( expression ) { case constant1: statement1; goto END; case constant2: statement2; goto END; case constant3: statement2; goto END; } switch( expression ) { case constant4: statement4; goto END; case constant5: statement5; goto END; case constant6: statement6; goto END; } 如果你不按照这些游戏规则玩的话,你注定会使目的进程挂掉!记住,不要妄想远程进程中的任何数据会和你本地进程中的数据存放在相同内存地址! (原话如此:You will almost certainly crash the target process if you don't play by those rules. Just remember: Don't assume anything in the target process is at the same address as it is in your process.) typedef LRESULT (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM); typedef struct { HWND hwnd; // handle to edit control or main window SENDMESSAGE fnSendMessage; // pointer to user32!SendMessageA char psText[128]; // buffer that is to receive the msg } INJDATA;//要注入远程进程的数据 static DWORD WINAPI ThreadFunc (INJDATA *pData) { pData->fnSendMessage( pData->hwnd, WM_GETTEXT, sizeof(pData->psText), (LPARAM)pData->psText ); return 0; } // int cbCodeSize = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc. static void AfterThreadFunc (void) { } // 空函数,标记用,便于计算大小。 //一般地,这不是最好的办法,因为编译器会改变你的函数中代码的顺序(比如它会把ThreadFunc放在AfterThreadFunc之后)。 //如果有必要,你可以使用/ORDER连接选项,或者,用反汇编工具确定ThreadFunc的大小,这个也许会更好。 步骤: 1. 得到远程进程的HANDLE(OpenProcess)。 2. 在远程进程中为要注入的数据分配内存(VirtualAllocEx)、 3. 把初始化后的INJDATA结构复制到分配的内存中(WriteProcessMemory)。复制代码 4. 在远程进程中为要注入的数据分配内存(VirtualAllocEx)。 5. 把ThreadFunc复制到分配的内存中(WriteProcessMemory)。 6. 用CreateRemoteThread启动远程的ThreadFunc。 7. 等待远程线程的结束(WaitForSingleObject)。 8. 从远程进程取回指执行结果(ReadProcessMemory 或 GetExitCodeThread)。 9. 释放相关内存(VirtualFreeEx)。 10. 关闭相关的句柄。 CloseHandle typedef LRESULT (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM); typedef struct { HWND hwnd; // handle to edit control or main window SENDMESSAGE fnSendMessage; // pointer to user32!SendMessageA char psText[128]; // buffer that is to receive the msg } INJDATA;//要注入远程进程的数据,功能是取目标窗口的标题 static DWORD WINAPI ThreadFunc (INJDATA *pData) { pData->fnSendMessage( pData->hwnd, WM_GETTEXT, sizeof(pData->psText), (LPARAM)pData->psText ); return 0; }//通过反汇编工具取得ThreadFunc大小比较可靠 45字节 // int cbCodeSize = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc. static void AfterThreadFunc (void) { } typedef struct _tagHwndPID { DWORD m_dwPID; HWND m_hwnd; }tagHwndPID; BOOL CALLBACK EnumWindowsProc( HWND hwnd, /* handle to parent window */ LPARAM lParam /* application-defined value */ ) { tagHwndPID* pHwndPID = (tagHwndPID*)lParam; DWORD dwPID, dwTID; dwTID = GetWindowThreadProcessId(hwnd, &dwPID); if (dwPID && dwPID == pHwndPID->m_dwPID) { pHwndPID->m_hwnd = hwnd; return FALSE; } return TRUE; // 继续遍历 } void CRemoteThreadDlg::OnBnClickedButton5() { OutputDebugString("RemoteInjectCode"); INJDATA injdata; memset(&injdata, 0, sizeof(injdata)); //取进程ID DWORD dwPID; BOOL isTranslated; dwPID = GetDlgItemInt(IDC_EDIT2, &isTranslated); if (!isTranslated) { AfxMessageBox("get pid failed."); return; } //取目标窗口句柄 tagHwndPID hwndPID; hwndPID.m_dwPID = dwPID; hwndPID.m_hwnd = NULL; EnumWindows(EnumWindowsProc, (LPARAM)&hwndPID); if (!hwndPID.m_hwnd) { AfxMessageBox("get hwnd failed."); return; } injdata.hwnd = hwndPID.m_hwnd; //取 SendMessage 地址 user32.dll HMODULE hMod = LoadLibrary("user32.dll"); if (hMod) { injdata.fnSendMessage = (SENDMESSAGE)GetProcAddress(hMod, "SendMessageA"); FreeLibrary(hMod); hMod = NULL; } if (!injdata.fnSendMessage) { AfxMessageBox("get fnSendMessage failed."); return; } //获取进程句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (hProcess) { OutputDebugString("OpenProcess success"); //在目标进程内申请内存空间,线程函数代码 //通过反汇编工具取得ThreadFunc大小比较可靠 45字节 DWORD dwLength = 45; PVOID lpBuff = VirtualAllocEx( hProcess, 0, dwLength, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE ); if ( lpBuff ) { OutputDebugString("VirtualAllocEx success"); DWORD dwWrite; if ( WriteProcessMemory( hProcess, lpBuff, (PVOID)ThreadFunc, dwLength, &dwWrite ) ) { OutputDebugString("WriteProcessMemory success"); //在目标进程内申请内存空间,线程参数数据 PVOID lpBuffParam = VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE ); if ( lpBuffParam ) { OutputDebugString("VirtualAllocEx success"); if ( WriteProcessMemory( hProcess, lpBuffParam, (PVOID)&injdata, sizeof(INJDATA), &dwWrite ) ) { OutputDebugString("WriteProcessMemory success"); //创建远程线程 DWORD dwTID; HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBuff, lpBuffParam, 0, &dwTID ); if (hThread) { OutputDebugString("CreateRemoteThread success"); //等待LoadLibrary结束 WaitForSingleObject( hThread, INFINITE ); //获取LoadLibrary返回值,释放DLL用 //读取信息 ReadProcessMemory(hProcess, (PBYTE)lpBuffParam+8, injdata.psText, 127, &dwWrite); AfxMessageBox(injdata.psText); DWORD dwExitCode; GetExitCodeThread( hThread, &dwExitCode ); if (dwExitCode) { OutputDebugString("GetExitCodeThread success"); //读取信息 ReadProcessMemory(hProcess, (PBYTE)lpBuffParam+8, injdata.psText, 127, &dwWrite); AfxMessageBox(injdata.psText); } CloseHandle(hThread); hThread = NULL; } } VirtualFreeEx( hProcess, lpBuffParam, 0/*0则释放所申请到的所有内存空间*/, MEM_RELEASE ); } } VirtualFreeEx( hProcess, lpBuff, 0/*0则释放所申请到的所有内存空间*/, MEM_RELEASE ); } CloseHandle(hProcess); hProcess = NULL; } }
posted on 2016-11-02 17:36 NoneButNow 阅读(357) 评论(0) 编辑 收藏 举报