您的位置:首页 > 编程语言

EasyHook远程代码注入

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

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

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

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#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,
/*(PVOID)0x12345678*/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,
/*(PVOID)0x12345678*/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");

// this will also invalidate "hHook", because it is a traced handle...
LhUninstallAllHooks();

// this will do nothing because the hook is already removed...
LhUninstallHook(hHookCreateFileA);
LhUninstallHook(hHookCreateFileW);

// now we can safely release the traced handle
delete hHookCreateFileA;
hHookCreateFileA = NULL;

delete hHookCreateFileW;
hHookCreateFileW = NULL;

// even if the hook is removed, we need to wait for memory release
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;
}
// HookSvr.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;
}


钩子这一部分我弄了比较久,主要是API不熟悉,不过好在弄好了。


// HookSvr.h

#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;


接下来是注入工具,这里指提供核心代码。本来EasyHook还提供了一个叫RhInjectLibrary()方法直接注入,这种方法相当稳定,推荐使用。我本来也用它,但是发现注入会失败,所以就采用了比较通用的远程注入代码,如下:

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,             // lookup privilege on local system
lpszPrivilege,    // privilege to lookup
&luid) )          // receives LUID of privilege
{
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;

// Enable the privilege or disable all privileges.
if( !AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
return FALSE;
}

if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
//The token does not have the specified privilege.
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;
//BOOL bIsWindowsXPorLater;

ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

GetVersionEx(&osvi);

if (osvi.dwMajorVersion == 6)
{
bHook = TRUE;
}
else
{
bHook = FALSE;
}

if(bHook)    // Vista, 7, Server2008
{
pFunc = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
if( pFunc == NULL )
{
//GetLastError());
return FALSE;
}

OutputDebugString(L"MyCreateRemoteThread");
((PFNTCREATETHREADEX)pFunc)(&hThread,
0x1FFFFF,
NULL,
hProcess,
pThreadProc,
pRemoteBuf,
FALSE,
NULL,
NULL,
NULL,
NULL);
if( hThread == NULL )
{
return FALSE;
}
}
else                    // 2000, XP, Server2003
{
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;
}

//判断dll是否存在
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");


这样就能保证注入的钩子能正常工作了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: