转:EasyHook远程代码注入

时间:2023-03-08 20:21:32

最近一段时间由于使用MinHook的API挂钩不稳定,经常因为挂钩地址错误而导致宿主进程崩溃。听同事介绍了一款智能强大的挂钩引擎EasyHook。它比微软的detours好的一点是它的x64注入支持是免费开源的。不想微软的detours,想搞x64还得购买。

好了,闲话不多说,先下载EasyHook的开发库,当然有兴趣的同学可以下载源码进行学习。下载地址:http://easyhook.codeplex.com/releases/view/24401。我给的这个是2.6版本的。

EasyHook提供了两种模式的注入管理。一种是托管代码的注入,另一种是非托管代码的注入。我是学习C++的,所以直接学习了例子中的非托管项目UnmanagedHook。里面给了一个简单的挂钩MessageBeep API的示例。我需要将其改造成支持远程注入的。下面先给出钩子DLL代码:

  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "stdafx.h"
  3. #include "HookApi.h"
  4. #include "easyhook.h"
  5. #include "ntstatus.h"
  6. ptrCreateFileW realCreateFileW = NULL;
  7. ptrCreateFileA realCreateFileA = NULL;
  8. HMODULE                 hKernel32 = NULL;
  9. TRACED_HOOK_HANDLE      hHookCreateFileW = new HOOK_TRACE_INFO();
  10. TRACED_HOOK_HANDLE      hHookCreateFileA = new HOOK_TRACE_INFO();
  11. NTSTATUS                statue;
  12. ULONG                   HookCreateFileW_ACLEntries[1] = {0};
  13. ULONG                   HookCreateFileA_ACLEntries[1] = {0};
  14. int PrepareRealApiEntry()
  15. {
  16. OutputDebugString(L"PrepareRealApiEntry()\n");
  17. // 获取真实函数地址
  18. HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
  19. if (hKernel32 == NULL)
  20. {
  21. OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") Error\n");
  22. return -6002;
  23. }
  24. OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") OK\n");
  25. realCreateFileW = (ptrCreateFileW)GetProcAddress(hKernel32, "CreateFileW");
  26. if (realCreateFileW == NULL)
  27. {
  28. OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") Error\n");
  29. return -6007;
  30. }
  31. OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") OK\n");
  32. realCreateFileA = (ptrCreateFileA)GetProcAddress(hKernel32, "CreateFileA");
  33. if (realCreateFileA == NULL)
  34. {
  35. OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") Error\n");
  36. return -6007;
  37. }
  38. OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") OK\n");
  39. return 0;
  40. }
  41. void DoHook()
  42. {
  43. OutputDebugString(L"DoHook()\n");
  44. statue = LhInstallHook(realCreateFileW,
  45. MyCreateFileW,
  46. /*(PVOID)0x12345678*/NULL,
  47. hHookCreateFileW);
  48. if(!SUCCEEDED(statue))
  49. {
  50. switch (statue)
  51. {
  52. case STATUS_NO_MEMORY:
  53. OutputDebugString(L"STATUS_NO_MEMORY\n");
  54. break;
  55. case STATUS_NOT_SUPPORTED:
  56. OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
  57. break;
  58. case STATUS_INSUFFICIENT_RESOURCES:
  59. OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
  60. break;
  61. default:
  62. WCHAR dbgstr[512] = {0};
  63. wsprintf(dbgstr, L"%d\n", statue);
  64. OutputDebugString(dbgstr);
  65. }
  66. OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileW\"),MyCreateFileW,(PVOID)0x12345678,hHookCreateFileW); Error\n");
  67. return;
  68. }
  69. OutputDebugString(L"Hook CreateFileW OK\n");
  70. statue = LhInstallHook(realCreateFileA,
  71. MyCreateFileA,
  72. /*(PVOID)0x12345678*/NULL,
  73. hHookCreateFileA);
  74. if(!SUCCEEDED(statue))
  75. {
  76. switch (statue)
  77. {
  78. case STATUS_NO_MEMORY:
  79. OutputDebugString(L"STATUS_NO_MEMORY\n");
  80. break;
  81. case STATUS_NOT_SUPPORTED:
  82. OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
  83. break;
  84. case STATUS_INSUFFICIENT_RESOURCES:
  85. OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
  86. break;
  87. default:
  88. WCHAR dbgstr[512] = {0};
  89. wsprintf(dbgstr, L"%d\n", statue);
  90. OutputDebugString(dbgstr);
  91. }
  92. OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileA\"),MyCreateFileA,(PVOID)0x12345678,hHookCreateFileA); Error\n");
  93. return;
  94. }
  95. OutputDebugString(L"Hook CreateFileA OK\n");
  96. // 一定要调用这个函数,否则注入的钩子无法正常运行。
  97. LhSetExclusiveACL(HookCreateFileA_ACLEntries, 1, hHookCreateFileA);
  98. LhSetExclusiveACL(HookCreateFileW_ACLEntries, 1, hHookCreateFileW);
  99. }
  100. void DoneHook()
  101. {
  102. OutputDebugString(L"DoneHook()\n");
  103. // this will also invalidate "hHook", because it is a traced handle...
  104. LhUninstallAllHooks();
  105. // this will do nothing because the hook is already removed...
  106. LhUninstallHook(hHookCreateFileA);
  107. LhUninstallHook(hHookCreateFileW);
  108. // now we can safely release the traced handle
  109. delete hHookCreateFileA;
  110. hHookCreateFileA = NULL;
  111. delete hHookCreateFileW;
  112. hHookCreateFileW = NULL;
  113. // even if the hook is removed, we need to wait for memory release
  114. LhWaitForPendingRemovals();
  115. }
  116. BOOL APIENTRY DllMain( HMODULE hModule,
  117. DWORD  ul_reason_for_call,
  118. LPVOID lpReserved
  119. )
  120. {
  121. switch (ul_reason_for_call)
  122. {
  123. case DLL_PROCESS_ATTACH:
  124. {
  125. OutputDebugString(L"DllMain::DLL_PROCESS_ATTACH\n");
  126. // 准备好原始地址与目的地址
  127. int errCode = PrepareRealApiEntry();
  128. if (errCode != 0)
  129. {
  130. OutputDebugString(L"PrepareRealApiEntry() Error\n");
  131. return FALSE;
  132. }
  133. // 开始挂钩
  134. DoHook();
  135. break;
  136. }
  137. case DLL_THREAD_ATTACH:
  138. {
  139. OutputDebugString(L"DllMain::DLL_THREAD_ATTACH\n");
  140. break;
  141. }
  142. case DLL_THREAD_DETACH:
  143. {
  144. OutputDebugString(L"DllMain::DLL_THREAD_DETACH\n");
  145. break;
  146. }
  147. case DLL_PROCESS_DETACH:
  148. {
  149. OutputDebugString(L"DllMain::DLL_PROCESS_DETACH\n");
  150. // 卸载钩子
  151. DoneHook();
  152. break;
  153. }
  154. }
  155. return TRUE;
  156. }
  1. <pre name="code" class="cpp">// HookSvr.cpp
  2. #include "stdafx.h"
  3. #include "HookApi.h"
  4. #include "easyhook.h"
  5. HANDLE WINAPI MyCreateFileW(
  6. __in     LPCWSTR lpFileName,
  7. __in     DWORD dwDesiredAccess,
  8. __in     DWORD dwShareMode,
  9. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  10. __in     DWORD dwCreationDisposition,
  11. __in     DWORD dwFlagsAndAttributes,
  12. __in_opt HANDLE hTemplateFile
  13. )
  14. {
  15. HANDLE hHandle = NULL;
  16. // 执行钩子
  17. if (realCreateFileW == NULL)
  18. {
  19. OutputDebugString(L"realCreateFileW is NULL\n");
  20. return INVALID_HANDLE_VALUE;
  21. }
  22. else
  23. {
  24. OutputDebugString(L"realCreateFileW is not NULL\n");
  25. hHandle = (realCreateFileW)(lpFileName, dwDesiredAccess, dwShareMode,
  26. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  27. OutputDebugString(L"MyCreateFileW : ");
  28. OutputDebugString(lpFileName);
  29. OutputDebugString(L"\n");
  30. }
  31. return hHandle;
  32. }
  33. HANDLE WINAPI MyCreateFileA(
  34. __in     LPCSTR lpFileName,
  35. __in     DWORD dwDesiredAccess,
  36. __in     DWORD dwShareMode,
  37. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  38. __in     DWORD dwCreationDisposition,
  39. __in     DWORD dwFlagsAndAttributes,
  40. __in_opt HANDLE hTemplateFile
  41. )
  42. {
  43. HANDLE hHandle = NULL;
  44. // 执行钩子
  45. if (realCreateFileA == NULL)
  46. {
  47. OutputDebugString(L"realCreateFileA is NULL\n");
  48. return INVALID_HANDLE_VALUE;
  49. }
  50. else
  51. {
  52. OutputDebugString(L"realCreateFileA is not NULL\n");
  53. hHandle = (realCreateFileA)(lpFileName, dwDesiredAccess, dwShareMode,
  54. lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
  55. OutputDebugString(L"MyCreateFileW : ");
  56. OutputDebugStringA(lpFileName);
  57. OutputDebugString(L"\n");
  58. }
  59. return hHandle;
  60. }</pre><br>
  61. 钩子这一部分我弄了比较久,主要是API不熟悉,不过好在弄好了。
  62. <pre></pre>
  63. <p><br>
  64. </p>
  65. <p></p><pre name="code" class="cpp">// HookSvr.h
  66. #pragma once
  67. #include <Windows.h>
  68. #ifndef _M_X64
  69. #pragma comment(lib, "EasyHook32.lib")
  70. #else
  71. #pragma comment(lib, "EasyHook64.lib")
  72. #endif
  73. HANDLE WINAPI MyCreateFileW(
  74. __in     LPCWSTR lpFileName,
  75. __in     DWORD dwDesiredAccess,
  76. __in     DWORD dwShareMode,
  77. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  78. __in     DWORD dwCreationDisposition,
  79. __in     DWORD dwFlagsAndAttributes,
  80. __in_opt HANDLE hTemplateFile
  81. );
  82. typedef HANDLE (WINAPI *ptrCreateFileW)(
  83. __in     LPCWSTR lpFileName,
  84. __in     DWORD dwDesiredAccess,
  85. __in     DWORD dwShareMode,
  86. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  87. __in     DWORD dwCreationDisposition,
  88. __in     DWORD dwFlagsAndAttributes,
  89. __in_opt HANDLE hTemplateFile
  90. );
  91. extern ptrCreateFileW realCreateFileW;
  92. HANDLE WINAPI MyCreateFileA(
  93. __in     LPCSTR lpFileName,
  94. __in     DWORD dwDesiredAccess,
  95. __in     DWORD dwShareMode,
  96. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  97. __in     DWORD dwCreationDisposition,
  98. __in     DWORD dwFlagsAndAttributes,
  99. __in_opt HANDLE hTemplateFile
  100. );
  101. typedef HANDLE (WINAPI *ptrCreateFileA)(
  102. __in     LPCSTR lpFileName,
  103. __in     DWORD dwDesiredAccess,
  104. __in     DWORD dwShareMode,
  105. __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  106. __in     DWORD dwCreationDisposition,
  107. __in     DWORD dwFlagsAndAttributes,
  108. __in_opt HANDLE hTemplateFile
  109. );
  110. extern ptrCreateFileA realCreateFileA;</pre><br>
  111. <br>
  112. <p></p>
  113. <p>接下来是注入工具,这里指提供核心代码。本来EasyHook还提供了一个叫<span style="color:black">Rh</span>InjectLibrary()方法直接注入,这种方法相当稳定,推荐使用。我本来也用它,但是发现注入会失败,所以就采用了比较通用的远程注入代码,如下:</p>
  114. <pre name="code" class="cpp">BOOL RtlFileExists(WCHAR* InPath)
  115. {
  116. HANDLE          hFile;
  117. if((hFile = CreateFileW(InPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
  118. return FALSE;
  119. CloseHandle(hFile);
  120. return TRUE;
  121. }
  122. BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
  123. {
  124. TOKEN_PRIVILEGES tp;
  125. HANDLE hToken;
  126. LUID luid;
  127. if( !OpenProcessToken(GetCurrentProcess(),
  128. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  129. &hToken) )
  130. {
  131. return FALSE;
  132. }
  133. if( !LookupPrivilegeValue(NULL,             // lookup privilege on local system
  134. lpszPrivilege,    // privilege to lookup
  135. &luid) )          // receives LUID of privilege
  136. {
  137. return FALSE;
  138. }
  139. tp.PrivilegeCount = 1;
  140. tp.Privileges[0].Luid = luid;
  141. if( bEnablePrivilege )
  142. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  143. else
  144. tp.Privileges[0].Attributes = 0;
  145. // Enable the privilege or disable all privileges.
  146. if( !AdjustTokenPrivileges(hToken,
  147. FALSE,
  148. &tp,
  149. sizeof(TOKEN_PRIVILEGES),
  150. (PTOKEN_PRIVILEGES) NULL,
  151. (PDWORD) NULL) )
  152. {
  153. return FALSE;
  154. }
  155. if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
  156. {
  157. //The token does not have the specified privilege.
  158. return FALSE;
  159. }
  160. return TRUE;
  161. }
  162. typedef DWORD (WINAPI *PFNTCREATETHREADEX)
  163. (
  164. PHANDLE                 ThreadHandle,
  165. ACCESS_MASK             DesiredAccess,
  166. LPVOID                  ObjectAttributes,
  167. HANDLE                  ProcessHandle,
  168. LPTHREAD_START_ROUTINE  lpStartAddress,
  169. LPVOID                  lpParameter,
  170. BOOL                   CreateSuspended,
  171. DWORD                   dwStackSize,
  172. DWORD                   dw1,
  173. DWORD                   dw2,
  174. LPVOID                  Unknown
  175. );
  176. BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf)
  177. {
  178. HANDLE      hThread = NULL;
  179. FARPROC     pFunc = NULL;
  180. BOOL bHook;
  181. // 判断系统版本
  182. OSVERSIONINFO osvi;
  183. //BOOL bIsWindowsXPorLater;
  184. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  185. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  186. GetVersionEx(&osvi);
  187. if (osvi.dwMajorVersion == 6)
  188. {
  189. bHook = TRUE;
  190. }
  191. else
  192. {
  193. bHook = FALSE;
  194. }
  195. if(bHook)    // Vista, 7, Server2008
  196. {
  197. pFunc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
  198. if( pFunc == NULL )
  199. {
  200. //GetLastError());
  201. return FALSE;
  202. }
  203. OutputDebugString(L"MyCreateRemoteThread");
  204. ((PFNTCREATETHREADEX)pFunc)(&hThread,
  205. 0x1FFFFF,
  206. NULL,
  207. hProcess,
  208. pThreadProc,
  209. pRemoteBuf,
  210. FALSE,
  211. NULL,
  212. NULL,
  213. NULL,
  214. NULL);
  215. if( hThread == NULL )
  216. {
  217. return FALSE;
  218. }
  219. }
  220. else                    // 2000, XP, Server2003
  221. {
  222. hThread = CreateRemoteThread(hProcess,
  223. NULL,
  224. 0,
  225. pThreadProc,
  226. pRemoteBuf,
  227. 0,
  228. NULL);
  229. if( hThread == NULL )
  230. {
  231. return FALSE;
  232. }
  233. }
  234. if( WAIT_FAILED == WaitForSingleObject(hThread, INFINITE) )
  235. {
  236. return FALSE;
  237. }
  238. return TRUE;
  239. }
  240. BOOL InjectDll(DWORD dwPID, const wchar_t *szDllName)
  241. {
  242. HANDLE hProcess = NULL;
  243. LPVOID pRemoteBuf = NULL;
  244. FARPROC pThreadProc = NULL;
  245. DWORD dwBufSize = wcslen(szDllName)*sizeof(wchar_t)+2;
  246. if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
  247. {
  248. return FALSE;
  249. }
  250. pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
  251. MEM_COMMIT, PAGE_READWRITE);
  252. WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName,
  253. dwBufSize, NULL);
  254. pThreadProc = GetProcAddress(GetModuleHandle(L"kernel32.dll"),
  255. "LoadLibraryW");
  256. if( !MyCreateRemoteThread(hProcess, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf) )
  257. {
  258. return FALSE;
  259. }
  260. VirtualFreeEx(hProcess, pRemoteBuf, dwBufSize, MEM_RELEASE);
  261. CloseHandle(hProcess);
  262. return TRUE;
  263. }
  264. int DoInject(DWORD aPid, const WCHAR *aFullpath)
  265. {
  266. if (wcslen(aFullpath) <= 0)
  267. {
  268. return -1;
  269. }
  270. //判断dll是否存在
  271. HANDLE hFile = CreateFile(aFullpath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  272. if(hFile != INVALID_HANDLE_VALUE)
  273. {
  274. DWORD dwsize = GetFileSize(hFile, NULL);
  275. CloseHandle(hFile);
  276. if (dwsize < 10)
  277. {
  278. return -2;
  279. }
  280. }
  281. else
  282. {
  283. return -3;
  284. }
  285. BOOL bSuc=SetPrivilege(SE_DEBUG_NAME, TRUE);
  286. bSuc=InjectDll((DWORD)aPid, aFullpath);
  287. if (bSuc)
  288. {
  289. return -4;
  290. }
  291. return 0;
  292. }
  293. // 真实注入的时候应该这样调用
  294. DoInject(m_processId, L"E:\\src\\easyhook\\trunk\\Debug\\x86\\HookSvr.dll");
  295. </pre><br>
  296. 这样就能保证注入的钩子能正常工作了。
分享到: 

查看评论
4楼 SpiritMFC 2013-03-26 15:43发表 [回复]
转:EasyHook远程代码注入
你好~ 能提供能运行的源码嘛?
我用你的方法正常exe可以hook成功,
但是DLL注入后钩子无法工作。
困扰数天的问题了。
求帮助!
还有 C++的话这个库能实现全局钩子嘛?
Re: baggiowangyu 2013-03-29 09:24发表 [回复]
转:EasyHook远程代码注入
回复SpiritMFC:我给的例子就是源代码了哇,那时候研究到那里就没有继续往下了。应该是你注入之后挂钩写的不对导致的。

你指的全局钩子是什么概念?全局消息钩子么?目前我知道的是这个可以实现指定进程的挂钩。

3楼 lsssml1990 2012-10-26 12:22发表 [回复]
转:EasyHook远程代码注入
这个代码可以直接用不?
2楼 baggiowangyu 2012-06-23 14:02发表 [回复]
转:EasyHook远程代码注入
一同学习,一同学习
1楼 Wentasy 2012-06-19 11:46发表 [回复]
转:EasyHook远程代码注入
不错,学习了。