在我的上一篇文章中【Hook技术】实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展 介绍了X86下基于IAT Hook技术,通过Hook OpenProcess来实现从任务管理器中保护进程,看到一些评论,有朋友问该代码是否适用于64位系统? 答案是肯定的,需要修改两个地方: a. 编译时候,设置平台为X64 b.修改SetWindowsHookEx第三个参数为0,关于这点,是因为64为下和32为下调用SetWindowsHookEx略有不同,官方关于该函数的有一段解析为: SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names. 如果你希望在X64下通过HOOK技术实现进程的保护,不推荐Hook OpenProcess,可以考虑通过Hook Ntdll的函数(NtOpenProcess)实现,这也是楼主写此文的目的的,介绍通过MHook实现对NtOpenProcess的hook实现进程的保护. 1. Hook技术基础知识(Inline Hook) 在开始本文的实例前想先通过对Hook技术做些简单的介绍,帮助大家更好的理解所谓的Hook技术,所谓的hook技术其实就是修改函数行为的一种技术,通过对函数行为的修改可以实现例如:文件的监控/保护 , 进程的监控/隐藏等,例如大多数的安全软件都是基于这种技术实现的,还有些病毒木马技术也会涉及到hook技术。一般的hook函数的流程: { 目标API } ----- 【 Hook API 】 ------- 修改函数入口前几个字节,添加跳转指令 类似JMP DWORD Ptr Address \ { jump 我们的代码处 } |- a. 执行我们代码 |- b. 修复Hook |- c. 调用目标API 通过修改目标函数的前几个字节,然后跳转到我们的代码执行,等执行完我们定制的代码后,在调用真实的目标API返回结果给调用程序. 大多数的系统API,前几个字节都是对堆栈的操作,而hook技术就是利用了这几个字节实现jmp的,伪代码描述: 目标函数: mov edi, edi // HOOK Jmp DWORD PTR MyFunctionAddress jump后 MyFunctionAddress内部逻辑处理push ebp // 堆栈操作 < ==========> xor ecx ,exc <=========> 修复原函数堆栈操作 { mov edi,edi push ebp,...}mov ebp, esp // 跳到原函数执行JMP 【ADDRESS】xor ecx, ecx ==> 标记地址为【ADDRESS】 这是一种比较常用的HOOK思路,还有修改函数中部或者尾部的,思路相同,patch的位置不同 还有中Hook的思路是通过“跳板”函数实现,定制函数和目标函数之间的关系 { Hook Api } \ { Jump 定制函数 } \ { jump Trampoline(跳板函数) } \ ______ { Call 目标函数 } ------ { 结果返回给调用程序 } 成功Hook函数后,跳转我们定制的函数中执行,当我们定制的代码执行完后,并不是在函数内部调用原目标函数,而是调用一个叫Trampoline的函数,Trampoline的任务就是平衡堆栈,然后执行原目标函数, 最后将结果返回给调用程序 例如: edi, edi addr1 customFunction ; //执行完地址的逻辑后,跳到调用Trampoline函数 ebp < ==== JUMP ====> addr2 ecx,ecx ebp, esp addr2 ecx, ecx Trampoline函数: edi, edi ebp { 平衡堆栈 } ebp, esp addr2 ===> 然后跳到原函数某地址执行 这种方法相对于第一种方式来说,安全了很多至少在多线程的环境下 ,一般trampoline跳转函数都是被标记为naked的,很多情况都是通过汇编实现,由自己编码控制堆栈。 2. 实战,X64下Hook NtOpenProcess 本demo中使用的hook引擎是MHook,Mhook是开源的,采用的是第二种hook方式,相比于MinHook/easyHook来说,使用简单,只导出两个函数: //安装Hook//ppSystemFunction,原函数地址//pHookFunction ,定制的函数地址BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction);//卸载HOOK//ppHookedFuntion.原函数地址BOOL Mhook_Unhook(PVOID *ppHookedFunction); a. 下载Mhook,新建一个win32 DLL工程,名称:HookNtOpenProcessLib b. 声明NtOpenProcess函数和我们定制的Hook_NtOpenProcess ![]() 定制的Hook_NtOpenProcess,设置进程句柄为NULL,保护所有进程,针对某个进程保护,请通过ProcesssHandler获取PID然后做比较 //===========================================================//定制我们自己的NtOpenProcessULONG WINAPI Hook_pfnNtOpenProcess( __out PHANDLE ProcessHandle, __in ACCESS_MASK AccessMask , __in PVOID ObjectAttributes, __in PCLIENT_ID ClientId){ //ULONG result = _NtOpenProcess( ProcessHandle,AccessMask,ObjectAttributes,ClientId); //DWORD pid = GetProcessIdByHandle( ProcessHandle); //通过进程句柄获取PID,然后验证 //if(gProtectProcessID == pid ){ // return STATUS_ACCESS_DENIED; //} //return result; //=================================== //简单处理,直接设置ProcessHandle,保护所有 ProcessHandle = NULL; return _NtOpenProcess( ProcessHandle, AccessMask,ObjectAttributes,ClientId); } c. 安装消息钩子,跟一篇博文一样,通过SetWindowsHookEx,只是在调用该函数时候需要注意区别下32位系统和64位系统情况,例如: extern "C" __declspec(dllexport) BOOL InstallHook(DWORD pid) { BOOL bResult=FALSE; //这里需要注意X86和X64下处理是不一样的 #ifdef _M_IX86 glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,glhInstance, 0); #elif defined _M_X64 glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,0, 0); //第三参数为0,而不是当前模块的实例句柄 #endif if(glhHook!=NULL) { gProtectProcessID = pid; bResult=TRUE; } return bResult; } d.C#调用HOOKNtOpenProcessLib.dll ![]() e.程序运行效果读,第一张通过ARK工具查看inline hook了NtOpenProcess,NtOpenProcess进入内核后是通过调用ZwOpenProcess的,所以我们看到ZwOpenProcess也被Inline hook了,第2张通过任务管理器结束进程 关于程序中一些注意问题: 1. 编译HookNtOpenProcessLib.dll时候,如果要运行在64位系统下,通过“配置管理器”设置下平台X64(也就是你要编译两份DLL,一份是平台为win32的,一个是X64下的) 2. 附件中C#程序,如果希望运行在32位和64位系统上,请通过“配置管理器”设置平台为“AnyCPU” 3. 将编译好的dll(32位和64位)的放在测试demo下,测试demo在调用InstallHook时候,内部SetWindowsHookEx会根据当前平台调用对应的HookNtOpenProcessLib.dll |
|