最近一段時間因爲使用MinHook的API掛鉤不穩定,常常由於掛鉤地址錯誤而致使宿主進程崩潰。聽同事介紹了一款智能強大的掛鉤引擎EasyHook。它比微軟的detours好的一點是它的x64注入支持是免費開源的。不想微軟的detours,想搞x64還得購買。web
好了,閒話很少說,先下載EasyHook的開發庫,固然有興趣的同窗能夠下載源碼進行學習。下載地址:http://easyhook.codeplex.com/releases/view/24401。我給的這個是2.6版本的。swift
EasyHook提供了兩種模式的注入管理。一種是託管代碼的注入,另外一種是非託管代碼的注入。我是學習C++的,因此直接學習了例子中的非託管項目UnmanagedHook。裏面給了一個簡單的掛鉤MessageBeep API的示例。我須要將其改形成支持遠程注入的。下面先給出鉤子DLL代碼:app
-
- #include "stdafx.h"
- #include "HookApi.h"
- #include "easyhook.h"
- #include "ntstatus.h"
-
- ptrCreateFileW realCreateFileW = NULL;
- ptrCreateFileA realCreateFileA = NULL;
- HMODULE hKernel32 = NULL;
- TRACED_HOOK_HANDLE hHookCreateFileW = new HOOK_TRACE_INFO();
- TRACED_HOOK_HANDLE hHookCreateFileA = new HOOK_TRACE_INFO();
- NTSTATUS statue;
- ULONG HookCreateFileW_ACLEntries[1] = {0};
- ULONG HookCreateFileA_ACLEntries[1] = {0};
-
- int PrepareRealApiEntry()
- {
- OutputDebugString(L"PrepareRealApiEntry()\n");
-
-
- HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
- if (hKernel32 == NULL)
- {
- OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") Error\n");
- return -6002;
- }
- OutputDebugString(L"LoadLibrary(L\"Kernel32.dll\") OK\n");
-
- realCreateFileW = (ptrCreateFileW)GetProcAddress(hKernel32, "CreateFileW");
- if (realCreateFileW == NULL)
- {
- OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") Error\n");
- return -6007;
- }
- OutputDebugString(L"(ptrCreateFileW)GetProcAddress(hKernel32, \"CreateFileW\") OK\n");
-
- realCreateFileA = (ptrCreateFileA)GetProcAddress(hKernel32, "CreateFileA");
- if (realCreateFileA == NULL)
- {
- OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") Error\n");
- return -6007;
- }
- OutputDebugString(L"(ptrCreateFileA)GetProcAddress(hKernel32, \"CreateFileA\") OK\n");
-
- return 0;
- }
-
- void DoHook()
- {
- OutputDebugString(L"DoHook()\n");
-
- statue = LhInstallHook(realCreateFileW,
- MyCreateFileW,
- NULL,
- hHookCreateFileW);
- if(!SUCCEEDED(statue))
- {
- switch (statue)
- {
- case STATUS_NO_MEMORY:
- OutputDebugString(L"STATUS_NO_MEMORY\n");
- break;
- case STATUS_NOT_SUPPORTED:
- OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
- break;
- case STATUS_INSUFFICIENT_RESOURCES:
- OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
- break;
- default:
- WCHAR dbgstr[512] = {0};
- wsprintf(dbgstr, L"%d\n", statue);
- OutputDebugString(dbgstr);
- }
- OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileW\"),MyCreateFileW,(PVOID)0x12345678,hHookCreateFileW); Error\n");
- return;
- }
- OutputDebugString(L"Hook CreateFileW OK\n");
-
- statue = LhInstallHook(realCreateFileA,
- MyCreateFileA,
- NULL,
- hHookCreateFileA);
- if(!SUCCEEDED(statue))
- {
- switch (statue)
- {
- case STATUS_NO_MEMORY:
- OutputDebugString(L"STATUS_NO_MEMORY\n");
- break;
- case STATUS_NOT_SUPPORTED:
- OutputDebugString(L"STATUS_NOT_SUPPORTED\n");
- break;
- case STATUS_INSUFFICIENT_RESOURCES:
- OutputDebugString(L"STATUS_INSUFFICIENT_RESOURCES\n");
- break;
- default:
- WCHAR dbgstr[512] = {0};
- wsprintf(dbgstr, L"%d\n", statue);
- OutputDebugString(dbgstr);
- }
- OutputDebugString(L"LhInstallHook(GetProcAddress(hKernel32, \"CreateFileA\"),MyCreateFileA,(PVOID)0x12345678,hHookCreateFileA); Error\n");
- return;
- }
- OutputDebugString(L"Hook CreateFileA OK\n");
-
-
-
- LhSetExclusiveACL(HookCreateFileA_ACLEntries, 1, hHookCreateFileA);
- LhSetExclusiveACL(HookCreateFileW_ACLEntries, 1, hHookCreateFileW);
-
- }
-
- void DoneHook()
- {
- OutputDebugString(L"DoneHook()\n");
-
-
- LhUninstallAllHooks();
-
-
- LhUninstallHook(hHookCreateFileA);
- LhUninstallHook(hHookCreateFileW);
-
-
- delete hHookCreateFileA;
- hHookCreateFileA = NULL;
-
- delete hHookCreateFileW;
- hHookCreateFileW = NULL;
-
-
- LhWaitForPendingRemovals();
- }
-
- BOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
- {
- switch (ul_reason_for_call)
- {
- case DLL_PROCESS_ATTACH:
- {
- OutputDebugString(L"DllMain::DLL_PROCESS_ATTACH\n");
-
-
- int errCode = PrepareRealApiEntry();
- if (errCode != 0)
- {
- OutputDebugString(L"PrepareRealApiEntry() Error\n");
- return FALSE;
- }
-
-
- DoHook();
-
- break;
- }
- case DLL_THREAD_ATTACH:
- {
- OutputDebugString(L"DllMain::DLL_THREAD_ATTACH\n");
-
- break;
- }
- case DLL_THREAD_DETACH:
- {
- OutputDebugString(L"DllMain::DLL_THREAD_DETACH\n");
-
- break;
- }
-
- case DLL_PROCESS_DETACH:
- {
- OutputDebugString(L"DllMain::DLL_PROCESS_DETACH\n");
-
-
- DoneHook();
-
- break;
- }
- }
- return TRUE;
- }
- <pre name="code" class="cpp">
-
- #include "stdafx.h"
- #include "HookApi.h"
- #include "easyhook.h"
-
- HANDLE WINAPI MyCreateFileW(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- )
- {
- HANDLE hHandle = NULL;
-
-
- if (realCreateFileW == NULL)
- {
- OutputDebugString(L"realCreateFileW is NULL\n");
- return INVALID_HANDLE_VALUE;
- }
- else
- {
- OutputDebugString(L"realCreateFileW is not NULL\n");
- hHandle = (realCreateFileW)(lpFileName, dwDesiredAccess, dwShareMode,
- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
-
- OutputDebugString(L"MyCreateFileW : ");
- OutputDebugString(lpFileName);
- OutputDebugString(L"\n");
- }
-
- return hHandle;
- }
-
- HANDLE WINAPI MyCreateFileA(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- )
- {
- HANDLE hHandle = NULL;
-
-
- if (realCreateFileA == NULL)
- {
- OutputDebugString(L"realCreateFileA is NULL\n");
- return INVALID_HANDLE_VALUE;
- }
- else
- {
- OutputDebugString(L"realCreateFileA is not NULL\n");
- hHandle = (realCreateFileA)(lpFileName, dwDesiredAccess, dwShareMode,
- lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
-
- OutputDebugString(L"MyCreateFileW : ");
- OutputDebugStringA(lpFileName);
- OutputDebugString(L"\n");
- }
-
- return hHandle;
- }</pre><br>
- 鉤子這一部分我弄了比較久,主要是API不熟悉,不過好在弄好了。
- <pre></pre>
- <p><br>
- </p>
- <p></p><pre name="code" class="cpp">
-
- #pragma once
- #include <Windows.h>
-
- #ifndef _M_X64
- #pragma comment(lib, "EasyHook32.lib")
- #else
- #pragma comment(lib, "EasyHook64.lib")
- #endif
-
- HANDLE WINAPI MyCreateFileW(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
-
- typedef HANDLE (WINAPI *ptrCreateFileW)(
- __in LPCWSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
-
- extern ptrCreateFileW realCreateFileW;
-
- HANDLE WINAPI MyCreateFileA(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
-
- typedef HANDLE (WINAPI *ptrCreateFileA)(
- __in LPCSTR lpFileName,
- __in DWORD dwDesiredAccess,
- __in DWORD dwShareMode,
- __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- __in DWORD dwCreationDisposition,
- __in DWORD dwFlagsAndAttributes,
- __in_opt HANDLE hTemplateFile
- );
-
- extern ptrCreateFileA realCreateFileA;</pre><br>
- <br>
- <p></p>
- <p>接下來是注入工具,這裏指提供核心代碼。原本EasyHook還提供了一個叫<span style="color:black">Rh</span>InjectLibrary()方法直接注入,這種方法至關穩定,推薦使用。我原本也用它,可是發現注入會失敗,因此就採用了比較通用的遠程注入代碼,以下:</p>
- <pre name="code" class="cpp">BOOL RtlFileExists(WCHAR* InPath)
- {
- HANDLE hFile;
-
- if((hFile = CreateFileW(InPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
- return FALSE;
-
- CloseHandle(hFile);
-
- return TRUE;
- }
-
- BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
- {
- TOKEN_PRIVILEGES tp;
- HANDLE hToken;
- LUID luid;
-
- if( !OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &hToken) )
- {
- return FALSE;
- }
-
- if( !LookupPrivilegeValue(NULL,
- lpszPrivilege,
- &luid) )
- {
- return FALSE;
- }
-
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- if( bEnablePrivilege )
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- else
- tp.Privileges[0].Attributes = 0;
-
-
- if( !AdjustTokenPrivileges(hToken,
- FALSE,
- &tp,
- sizeof(TOKEN_PRIVILEGES),
- (PTOKEN_PRIVILEGES) NULL,
- (PDWORD) NULL) )
- {
- return FALSE;
- }
-
- if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
- {
-
- return FALSE;
- }
-
- return TRUE;
- }
-
- typedef DWORD (WINAPI *PFNTCREATETHREADEX)
- (
- PHANDLE ThreadHandle,
- ACCESS_MASK DesiredAccess,
- LPVOID ObjectAttributes,
- HANDLE ProcessHandle,
- LPTHREAD_START_ROUTINE lpStartAddress,
- LPVOID lpParameter,
- BOOL CreateSuspended,
- DWORD dwStackSize,
- DWORD dw1,
- DWORD dw2,
- LPVOID Unknown
- );
-
- BOOL MyCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE pThreadProc, LPVOID pRemoteBuf)
- {
- HANDLE hThread = NULL;
- FARPROC pFunc = NULL;
- BOOL bHook;
-
-
- OSVERSIONINFO osvi;
-
-
- ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-
- GetVersionEx(&osvi);
-
- if (osvi.dwMajorVersion == 6)
- {
- bHook = TRUE;
- }
- else
- {
- bHook = FALSE;
- }
-
- if(bHook)
- {
- pFunc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
- if( pFunc == NULL )
- {
-
- return FALSE;
- }
-
- OutputDebugString(L"MyCreateRemoteThread");
- ((PFNTCREATETHREADEX)pFunc)(&hThread,
- 0x1FFFFF,
- NULL,
- hProcess,
- pThreadProc,
- pRemoteBuf,
- FALSE,
- NULL,
- NULL,
- NULL,
- NULL);
- if( hThread == NULL )
- {
- return FALSE;
- }
- }
- else
- {
- hThread = CreateRemoteThread(hProcess,
- NULL,
- 0,
- pThreadProc,
- pRemoteBuf,
- 0,
- NULL);
- if( hThread == NULL )
- {
- return FALSE;
- }
- }
-
- if( WAIT_FAILED == WaitForSingleObject(hThread, INFINITE) )
- {
- return FALSE;
- }
-
- return TRUE;
- }
-
- BOOL InjectDll(DWORD dwPID, const wchar_t *szDllName)
- {
- HANDLE hProcess = NULL;
- LPVOID pRemoteBuf = NULL;
- FARPROC pThreadProc = NULL;
- DWORD dwBufSize = wcslen(szDllName)*sizeof(wchar_t)+2;
-
- if ( !(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) )
- {
- return FALSE;
- }
-
- pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize,
- MEM_COMMIT, PAGE_READWRITE);
-
- WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName,
- dwBufSize, NULL);
-
- pThreadProc = GetProcAddress(GetModuleHandle(L"kernel32.dll"),
- "LoadLibraryW");
-
- if( !MyCreateRemoteThread(hProcess, (LPTHREAD_START_ROUTINE)pThreadProc, pRemoteBuf) )
- {
- return FALSE;
- }
-
- VirtualFreeEx(hProcess, pRemoteBuf, dwBufSize, MEM_RELEASE);
- CloseHandle(hProcess);
- return TRUE;
- }
-
- int DoInject(DWORD aPid, const WCHAR *aFullpath)
- {
- if (wcslen(aFullpath) <= 0)
- {
- return -1;
- }
-
-
- HANDLE hFile = CreateFile(aFullpath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
- if(hFile != INVALID_HANDLE_VALUE)
- {
- DWORD dwsize = GetFileSize(hFile, NULL);
- CloseHandle(hFile);
- if (dwsize < 10)
- {
- return -2;
- }
- }
- else
- {
- return -3;
- }
-
- BOOL bSuc=SetPrivilege(SE_DEBUG_NAME, TRUE);
- bSuc=InjectDll((DWORD)aPid, aFullpath);
- if (bSuc)
- {
- return -4;
- }
-
- return 0;
- }
-
-
-
- DoInject(m_processId, L"E:\\src\\easyhook\\trunk\\Debug\\x86\\HookSvr.dll");
-
-
- </pre><br>
- 這樣就能保證注入的鉤子能正常工做了。