远程线程的注入和注出
2016-03-29 21:24
387 查看
前言
昨天做远程线程的注入注出试验,出现了2个问题
* 注出时崩溃
* 注出时窗口属性变了(e.g. Unicode版变成了Ascii版)
现在问题已经解决, 可以稳定的连续注入和注出. 如果以后要用到远程线程, 下面的代码就直接能用了
试验环境: win7X64 + vs2013 + 控制台版测试程序 + SDK版DLL
试验对象: x86版的calc.exe和x64版的calc.exe
试验操作: VK_HOME键弹框, VK_END键弹框并卸载注入DLL
现在编码熟练度确实好很多, 只需要IDE和本地MSDN就可以完成工程了.
工程下载点
src_calcInject.zip
注入管理程序
注入用DLL
昨天做远程线程的注入注出试验,出现了2个问题
* 注出时崩溃
* 注出时窗口属性变了(e.g. Unicode版变成了Ascii版)
现在问题已经解决, 可以稳定的连续注入和注出. 如果以后要用到远程线程, 下面的代码就直接能用了
试验环境: win7X64 + vs2013 + 控制台版测试程序 + SDK版DLL
试验对象: x86版的calc.exe和x64版的calc.exe
试验操作: VK_HOME键弹框, VK_END键弹框并卸载注入DLL
现在编码熟练度确实好很多, 只需要IDE和本地MSDN就可以完成工程了.
工程下载点
src_calcInject.zip
注入管理程序
// calcInjectManager.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <tchar.h> #include <conio.h> #include <ctype.h> #include <psapi.h> #pragma comment(lib, "psapi.lib") #define OBJ_CLASS_NAME _T("CalcFrame") #define INJECT_DLL_NAME _T("calcInjectDll.dll") #define MEMORY_MAP_NAME _T("for Inject dll") #pragma pack(push) #pragma pack(1) typedef struct _tag_obj_exe_info { DWORD dwPID; TCHAR szClassName[MAX_PATH]; _tag_obj_exe_info() { dwPID = 0; ZeroMemory(szClassName, sizeof(szClassName)); } }TAG_OBJ_EXE_INFO; #pragma pack(pop) /// 注入DLL到计算器, x86/x64均可, /// 管理程序和注入用DLL和目标程序要编译成相同的x86 or x64 void fnInjectDll(); int _tmain(int argc, _TCHAR* argv[]) { do { fnInjectDll(); _tprintf(_T("if need inject dll, press c, other key to quit\n")); } while ('c' == _getch()); _tsystem(_T("pause")); return 0; } void fnInjectDll() { HWND hWnd = NULL; DWORD dwPID = 0; HANDLE hProcess = NULL; HANDLE hThread = NULL; DWORD dwThreadID = 0; TCHAR szBuf[MAX_PATH] = { _T('\0') }; TCHAR* pTmp = NULL; FILE * pFile = NULL; LPVOID lpAddress = NULL; SIZE_T NumberOfBytesWritten = 0; DWORD dwRc = 0; HANDLE hFileMap = NULL; LPVOID lpMapBuf = NULL; TAG_OBJ_EXE_INFO ObjExeInfo; _tprintf(_T("inject to calc\n")); do { hWnd = FindWindow(OBJ_CLASS_NAME, NULL); if (NULL == hWnd) { _tprintf(_T("can't find calc\n")); break; } _tcscpy_s(ObjExeInfo.szClassName, OBJ_CLASS_NAME); GetWindowThreadProcessId(hWnd, &dwPID); ObjExeInfo.dwPID = dwPID; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (NULL == hProcess) { _tprintf(_T("can't open process\n")); break; } /// inject.dll on my dir GetModuleFileName(NULL, szBuf, sizeof(szBuf) / sizeof(TCHAR)); pTmp = _tcsrchr(szBuf, _T('\\')); if (NULL == pTmp) { _tprintf(_T("can't make inject dll' name\n")); break; } _tcscpy_s(pTmp + 1, MAX_PATH - ((DWORD)pTmp + 1 - (DWORD)szBuf), INJECT_DLL_NAME); if ((0 != _tfopen_s(&pFile, szBuf, _T("rb"))) || (NULL == pFile)) { _tprintf(_T("can't find inject dll [%s]\n"), szBuf); break; } fclose(pFile); lpAddress = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (NULL == lpAddress) { _tprintf(_T("VirtualAllocEx failed\n")); } if (!WriteProcessMemory(hProcess, lpAddress, szBuf, (_tcslen(szBuf) + 1) * sizeof(TCHAR), &NumberOfBytesWritten)) { _tprintf(_T("can't WriteProcessMemory for dll name\n")); break; } /// write ObjExeInfo to MemoryMap hFileMap = CreateFileMapping(NULL, NULL, PAGE_READWRITE, 0x0, 01000, MEMORY_MAP_NAME); if (NULL == hFileMap) { _tprintf(_T("CreateFileMapping failed\n")); break; } lpMapBuf = MapViewOfFile( hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, MAX_PATH); if (NULL == lpMapBuf) { _tprintf(_T("MapViewOfFile failed\n")); break; } memcpy(lpMapBuf, &ObjExeInfo, sizeof(ObjExeInfo)); UnmapViewOfFile(lpMapBuf); hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, lpAddress, 0, &dwThreadID); if (NULL == hThread) { _tprintf(_T("CreateRemoteThread failed\n")); break; } if ((WAIT_OBJECT_0 != WaitForSingleObject(hThread, INFINITE)) || (0 == GetExitCodeThread(hThread, &dwRc))) { _tprintf(_T("thread execute failed\n")); break; } _tprintf(_T("dll inject ok\n")); } while (0); if (NULL != hFileMap) { CloseHandle(hFileMap); } if (NULL != hThread) { CloseHandle(hThread); } if (NULL != hProcess) { if (NULL != lpAddress) { VirtualFreeEx(hProcess, lpAddress, 0x0, MEM_RELEASE); } CloseHandle(hProcess); } }
注入用DLL
// dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include <windows.h> #include <tchar.h> #include <assert.h> #include <process.h> #define MEMORY_MAP_NAME _T("for Inject dll") #pragma pack(push) #pragma pack(1) typedef struct _tag_obj_exe_info { DWORD dwPID; TCHAR szClassName[MAX_PATH]; _tag_obj_exe_info() { dwPID = 0; ZeroMemory(szClassName, sizeof(szClassName)); } }TAG_OBJ_EXE_INFO; typedef struct _tag_find_obj_exe { TAG_OBJ_EXE_INFO Obj; BOOL bFindObj; HWND hWnd; _tag_find_obj_exe() { bFindObj = FALSE; hWnd = NULL; } }TAG_FIND_OBJ_EXE; #pragma pack(pop) TAG_FIND_OBJ_EXE g_FindObjExe; WNDPROC g_pWndProcOrg = NULL; ///< 用GetWindowLong得到的原始窗口过程处理函数地址 WNDPROC g_pWndProcPrev = NULL; ///< 用SetWindowLong返回的原始窗口过程处理函数地址 /// assert(g_pWndProcOrg == g_pWndProcPrev); ///< 必定成立 HMODULE g_hDllModule = NULL; /// 必须在EXE传来目标窗口时,确定是Unicode版还是Ascii版的目标程序 /// 等恢复原始窗口过程时, 再判断, 会得到错误的结果 BOOL g_bObjWindowIsUnicode = FALSE; void OnDllAttach(); ///< Dll被加载 void OnDllDetach(); ///< Dll被卸载 void fnSubClass(); ///< 子类化 void fnUnSubClass(); ///< 反子类化 /// 注入后的新窗口处理过程函数 LRESULT CALLBACK WndProcNew(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); /// 枚举回调, 用来验证EXE传来的参数是否正确 BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam); /// 卸载DLL用的线程 void __cdecl ThreadProc(void *); BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { g_hDllModule = hModule; ///< 保存Dll句柄 OnDllAttach(); } break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: { } break; case DLL_PROCESS_DETACH: { OnDllDetach(); } break; } return TRUE; } void OnDllAttach() { HANDLE hFileMap = NULL; ///< 注入管理程序EXE创建的参数内存映射 LPVOID lpMapBuf = NULL; ///< 打开内存映射后的缓冲区指针 TCHAR szBuf[MAX_PATH] = { _T('\0') }; ///< 临时缓冲区 OutputDebugString(_T("load calcInjectDll\n")); do { /// read paramter from memory map hFileMap = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, MEMORY_MAP_NAME); if (NULL == hFileMap) { OutputDebugString(_T("OpenFileMapping failed")); break; } if (NULL != hFileMap) { lpMapBuf = MapViewOfFile( hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, MAX_PATH); if (NULL == lpMapBuf) { OutputDebugString(_T("MapViewOfFile failed\n")); break; } memcpy(&g_FindObjExe.Obj, lpMapBuf, sizeof(g_FindObjExe.Obj)); UnmapViewOfFile(lpMapBuf); /// find obj exe by param, the parameter is right ? EnumWindows(EnumWindowsProc, (LPARAM)&g_FindObjExe); if (!g_FindObjExe.bFindObj) { OutputDebugString(_T("can't find obj exe\n")); break; } /// 第一时间判断目标窗口是W版还是A版 ! g_bObjWindowIsUnicode = ::IsWindowUnicode(g_FindObjExe.hWnd); /// @todo is my host is the g_FindObjExe ? /// 接收键盘消息的是子窗口 /// 计算器 /// - CalcFrame /// -- Static /// -- #32770 /// --- Static /// --- Static /// --- Static => find it! /// No.1子窗口A assert(NULL != g_FindObjExe.hWnd); g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_CHILD); ///< CalcFrame /// A的No.2子窗口B assert(NULL != g_FindObjExe.hWnd); g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_CHILD); ///< Static g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_HWNDNEXT); ///< #32770 /// B的No.3子窗口C g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_CHILD); ///< Static assert(NULL != g_FindObjExe.hWnd); g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_HWNDNEXT); ///< Static g_FindObjExe.hWnd = GetWindow(g_FindObjExe.hWnd, GW_HWNDNEXT); ///< Static, find! /// 计算器输入区输入几个数字, 看看是否找的对? GetClassName(g_FindObjExe.hWnd, szBuf, sizeof(szBuf) / sizeof(TCHAR)); GetWindowText(g_FindObjExe.hWnd, szBuf, sizeof(szBuf) / sizeof(TCHAR)); fnSubClass(); _stprintf_s(szBuf, sizeof(szBuf) / sizeof(TCHAR), _T(">> g_FindObjExe.hWnd = 0x%p, g_pWndProcOrg = 0x%p"), g_FindObjExe.hWnd, g_pWndProcOrg); OutputDebugString(szBuf); } } while (0); if (NULL != hFileMap) { CloseHandle(hFileMap); } } void OnDllDetach() { OutputDebugString(_T("unload calcInjectDll\n")); fnUnSubClass(); } LRESULT CALLBACK WndProcNew(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szBuf[MAX_PATH] = { _T('\0') }; LRESULT lRc = 0; assert(NULL != g_pWndProcOrg); /// lParam bit 30 is last key status, bit30 = 0 is last key was up if (WM_KEYDOWN == uMsg) { if (0 == (lParam & 0x40000000)) { if (VK_HOME == wParam) { OutputDebugString(_T("WM_KEYDOWN : VK_HOME")); /// show a dialog ::MessageBox(hWnd, _T("VK_HOME press down"), _T("calcInjectDll"), MB_OK); } else if (VK_END == wParam) { OutputDebugString(_T("WM_KEYDOWN : VK_END")); /// unload inject dll ::MessageBox(hWnd, _T("VK_END press down, will be unload dll"), _T("calcInjectDll"), MB_OK); _stprintf_s(szBuf, sizeof(szBuf) / sizeof(TCHAR), _T("<< g_FindObjExe.hWnd = 0x%p, g_pWndProcOrg = 0x%p"), g_FindObjExe.hWnd, g_pWndProcOrg); OutputDebugString(szBuf); /// 使DLL卸载稳定的做法 /// * 先执行原始的消息处理 lRc = g_pWndProcOrg(hWnd, uMsg, wParam, lParam); /// * 还原窗口过程 if (NULL != g_pWndProcOrg) { (WNDPROC)::SetWindowLongPtrA( g_FindObjExe.hWnd, GWLP_WNDPROC, (LONG_PTR)g_pWndProcOrg); } /// * 起线程卸载DLL, 不返回 ! _beginthread(ThreadProc, 0, NULL); /// 返回原始窗口过程处理函数的结果, 下一次就不会进这里了:) return lRc; } } } return g_pWndProcOrg(hWnd, uMsg, wParam, lParam); } void __cdecl ThreadProc(void *) { Sleep(1); /// ! 必须使用FreeLibraryAndExitThread FreeLibraryAndExitThread(g_hDllModule, 0x1000); } BOOL CALLBACK EnumWindowsProc( _In_ HWND hwnd, _In_ LPARAM lParam ) { BOOL bNeedFindNext = TRUE; TCHAR szBuf[MAX_PATH] = { _T('\0') }; TAG_FIND_OBJ_EXE* pFindObjExe = (TAG_FIND_OBJ_EXE*)lParam; do { if (NULL == pFindObjExe) { OutputDebugString(_T("paramter error")); bNeedFindNext = FALSE; break; } if (0 == GetClassName(hwnd, szBuf, sizeof(szBuf) / sizeof(TCHAR))) { break; } if (0 == _tcscmp(szBuf, pFindObjExe->Obj.szClassName)) { pFindObjExe->bFindObj = TRUE; pFindObjExe->hWnd = hwnd; bNeedFindNext = FALSE; } } while (0); return bNeedFindNext; } void fnSubClass() { /// subclass, 必须按照被注入的目标程序来确定子类化API的W或A版 ! /// 否则子类化失败 /// 注入管理程序,注入用DLL,目标程序必须配套, all x86 or all x64 ! /// x86程序只能注入x86目标程序, x64程序只能注入x64程序 if (::IsWindowUnicode(g_FindObjExe.hWnd)) { OutputDebugString(_T("fnSubClass by [Unicode]")); g_pWndProcOrg = (WNDPROC)::GetWindowLongPtrW(g_FindObjExe.hWnd, GWLP_WNDPROC); g_pWndProcPrev = (WNDPROC)::SetWindowLongPtrW( g_FindObjExe.hWnd, GWLP_WNDPROC, (LONG_PTR)WndProcNew); } else { OutputDebugString(_T("fnSubClass by [Ascii]")); g_pWndProcOrg = (WNDPROC)::GetWindowLongPtrA(g_FindObjExe.hWnd, GWLP_WNDPROC); g_pWndProcPrev = (WNDPROC)::SetWindowLongPtrA( g_FindObjExe.hWnd, GWLP_WNDPROC, (LONG_PTR)WndProcNew); } assert(g_pWndProcOrg == g_pWndProcPrev); ///< 必定相等 } void fnUnSubClass() { /// subclass, 必须按照被注入的目标程序来确定子类化API的W或A版 ! /// 否则还原原始窗口过程后,按键的反应完全不对了:) /// 不能现判断,必须使用子类化之前就判断好的标志 g_bObjWindowIsUnicode /// 防止恢复窗口过程时再判断,得出错误的结果 if (g_bObjWindowIsUnicode) { OutputDebugString(_T("fnUnSubClass by [Unicode]")); ::SetWindowLongPtrW( g_FindObjExe.hWnd, GWLP_WNDPROC, (LONG_PTR)g_pWndProcOrg); } else { OutputDebugString(_T("fnUnSubClass by [Ascii]")); ::SetWindowLongPtrA( g_FindObjExe.hWnd, GWLP_WNDPROC, (LONG_PTR)g_pWndProcOrg); } }
相关文章推荐
- leetcode之旅(9)-Reverse Linked List
- leetcode之旅(9)-Reverse Linked List
- Check failed: error == cudaSuccess (8 vs. 0) invalid device function
- 欧几里德算法求最大公约数
- iOS个人整理35-即时通信1 XMPP openfire 登录注册
- Android Studio--android:descendantFocusability用法简析
- c# 作业2
- 无向图的欧拉路
- BZOJ 3049: [Usaco2013 Jan]Island Travels
- java守护线程
- javascript 跨域请求
- Linux开发环境搭建 二 (Ubuntu串口工具minicom的安装及使用)
- Zlib库的安装与使用
- redis入门及java操作
- 软件测试homework3
- css中clip:rect矩形剪裁功能
- Stick ------ 剪枝神题
- 分布式事务最终一致性常用方案
- [SIMD]单指令多数据指令集(二)—— SIMD指令集在非对称算法中的应用
- Unity Shaders and Effects Cookbook (2-7)实现 Photoshop 色阶效果