zoukankan      html  css  js  c++  java
  • 64位下Hook NtOpenProcess的实现进程保护 + 源码 (升级篇 )

    64位下Hook NtOpenProcess的实现进程保护 + 源码 (升级篇 )

    【PS: 如果在64位系统下,出现调用测试demo,返回false的情况下,请修改Hook Dll的代码】

    glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc, 0  , 0); 
    //改成跟X86下一样的
    glhHook = SetWindowsHookEx(WH_SHELL,ShellHookProc,glhInstance, 0);
    

    2013.09.11代码修改, 可以针对指定的进程进行保护( 编译DLL和测试DEMO的时候,请注意目标平台,X86还是X64)

    => 工程给出的是X86下的,X64请自行编译一份Hook dll然后改下名字在测试demo中调用 ,C#中队X86和X64的判断可以通过

    Environment.Is64BitOperatingSystem

    2013.09.11 HookNtOpenProcessLib Souces


    在我的上一篇文章中【Hook技术】实现从"任务管理器"中保护进程不被关闭 + 附带源码 + 进程保护知识扩展 介绍了X86下基于IAT Hook技术,通过Hook OpenProcess来实现从任务管理器中保护进程,看到一些评论,有朋友问该代码是否适用于64位系统? 答案是肯定的,需要修改两个地方:

    a. 编译时候,设置平台为X64

    b.修改SetWindowsHookEx第三个参数为0 (ps:该设置不是绝对的,如果你发现X64下该方法不成效,请尝试使用X86下的方法),关于这点,是因为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的任务就是平衡堆栈,然后执行原目标函数, 最后将结果返回给调用程序

    例如:

    复制代码
            mov edi, edi                                 addr1  jmp customFunction ; //执行完地址的逻辑后,跳到调用Trampoline函数
            push ebp           < ==== JUMP ====>         addr2  xor ecx,ecx
            mov ebp, esp    
    addr2   xor ecx, ecx
    
    Trampoline函数:
    mov edi, edi push ebp { 平衡堆栈 } mov ebp, esp jmp 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

     View Code

    //=========================================================
    // struct CLIENT_ID
    typedef struct _CLIENT_ID {
    DWORD_PTR UniqueProcess;
    DWORD_PTR UniqueThread;
    } CLIENT_ID, *PCLIENT_ID;

    //===========================================================
    // NtOpenProcess
    typedef ULONG (WINAPI *pfnNtOpenProcess)(
    __out PHANDLE ProcessHandle,
    __in ACCESS_MASK AccessMask ,
    __in PVOID ObjectAttributes,
    __in PCLIENT_ID ClientId);

    pfnNtOpenProcess _NtOpenProcess = (pfnNtOpenProcess)GetProcAddress( GetModuleHandle(L"ntdll"),"NtOpenProcess");

    定制的Hook_NtOpenProcess,设置进程句柄为NULL,保护所有进程,针对某个进程保护,请通过ProcesssHandler获取PID然后做比较

    复制代码
    //===========================================================
    //定制我们自己的NtOpenProcess
    ULONG 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

     View Code

    public partial class Form1 : Form {
    public Form1() {
    InitializeComponent();

    this.Text = "=> HookNtOpenProcess <= ";

    this.Load += new EventHandler(Form1_Load);
    }


    void Form1_Load(object sender, EventArgs e) {
    Label lb = new Label{ Width = 200 , Height = 50 , ForeColor = System.Drawing.SystemColors.GrayText };
    lb.Text = "By Andy, FZ " + Environment.NewLine + "专注于: Net分布式技术,移动服务端架构及系统安全学习及研究";

    _btnHook = new Button { Text = "sTarthOok" };
    _btnHook.Click += (sende, ex) => {
    bool result = false;
    if (_btnHook.Text.Equals("sTarthOok")) {
    result = NativeAPI.InstallHook(System.Diagnostics.Process.GetCurrentProcess().Id);
    _btnHook.Text = "sTophOok";
    }
    else if (_btnHook.Text.Equals("sTophOok")) {
    NativeAPI.UninstallHook();
    _btnHook.Text = "sTarthOok";
    }

    //MessageBox.Show(result.ToString());
    };

    this.Controls.Add( _btnHook );
    _btnHook.SetBounds( 0 , 5 , 350,40 );
    this.Controls.Add( lb);
    lb.SetBounds( 0 , 50 , 350,40 );
    }


    class NativeAPI{
    [DllImport("HookNtOpenProcessLib.dll",CallingConvention=CallingConvention.Cdecl)]
    public extern static bool InstallHook( int pid );
    [DllImport("HookNtOpenProcessLib.dll",CallingConvention=CallingConvention.Cdecl)]
    public extern static bool UninstallHook();
    }


    private Button _btnHook = null;

    }

    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


    如果在使用中还存在任何问题,可以给我留言或者通过我的邮箱wygandy1987@gamil.com

    { 后面有时间,将发表一些关于Mhook实现的文章和关于内核Hook的文章,游戏hook等 敬请关注  }

      【旧源码】HookNtOpenProcess Source 

    专注于: Net分布式技术,移动服务端架构及系统安全学习及研究  by Andy


     

     

     

     

     

    分类: System Hacker

  • 相关阅读:
    linux samba 配置
    实例解读 linux 网卡驱动
    Linux操作系统的安全管理设置
    找回Linux/Unix下各系统的密码
    CF441E Valera and Number
    CF1175F The Number of Subpermutations 题解
    CF1553 比赛记录
    P5618 [SDOI2015]道路修建 题解
    CF 1530 比赛记录
    AT2063 [AGC005E] Sugigma: The Showdown 题解
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3315133.html
Copyright © 2011-2022 走看看