zoukankan      html  css  js  c++  java
  • 【转】日服巫术online过驱动保护分析(纯工具)(工具+自写驱动)

    前言:
    最近在学外挂编程,基本都是利用CE,OD调试分析游戏数据,但现在游戏公司用各种保护手段防止我们调试游戏,虽然我们有CE,OD这样的利器但是仍然被游戏驱动保护挡在门外i,真可谓巧妇也难为无米之炊啊。
     不得已只好暂停学习各种找CALL技术,先了解下游戏驱动保护的门门道道。经过几天的学习,有所收获,特记录下来,以备日后查询。本贴为纯工具过掉保护,下面将用工具+自写驱动过掉它,算是最近学习驱动编程的一次实践吧,
    希望本文对 跟同我一样刚入门的菜鸟有所帮助,欢迎菜鸟一起交流,与君共勉! 
    这次用的游戏是日服目前仍然比较火爆的《巫术online》 记得没学驱动保护之前也分析过这个游戏,但被这个游戏保护搞的蓝屏N次,怀恨在心,这次就拿它开刀,废话不说啦,进入正题:
    使用工具:Kernel_Detective_1.4.1 ,XueTr_0.45, 郁金香OD2010,VE修改器汉化版(核心也是CE,原版CE挂上进游戏就出错)
    打开游戏后,用OD附加,提示错误。

    用XueTr看看这个游戏都动了什么手脚吧,让我们的利器都用不上,哼哼。

    这个GPP.dll就是游戏的驱动保护文件,万恶啊。。。不过我们不能直接卸载,否则就是蓝屏或者游戏退出。。

    看看内核:

    有2个系统回调,在未知模块,很可疑,干掉它。
    其他里没有什么异常了,看看内核钩子:

    果然有hook。。。 ssdt里4个hook,经测试NtAllocateVirtualMemory就是阻止我们OD附加的罪魁祸首。右键恢复一下看看,恢复掉后,OD 可以附加,但游戏直接就掉了。将NtReradVirtualMemory NtWriteVirtualMemory恢复后,游戏也跟着掉了,而且再上就上不去了,只能重启在上。现在这驱动还温和了很多,记得以前版本 一恢复直接就蓝屏了。。。
    看看ShadowSSDT

    看来直接恢复是不行的,想想别的办法吧。

    具体看一下它是怎么HOOK的吧,在Kernel_Detective的SSDT里找到
    NtWriteVirtualMemory,右键反汇编当前地址

    看到以下代码:
    jmp 895B6FB0
    dec ebp
    sub al, 8
    js short 805B53CF
    jmp dword ptr [ecx+24]
    add dword ptr [eax], eax
    add byte ptr [ebx+40878AF8], cl
    add dword ptr [eax], eax
    add byte ptr [eax+758BE045], cl
    adc al, 84
    Invalid Command

    退掉游戏,看看没有HOOK过的代码是怎么样的

    push 1C
    push 804DAF08
    call 8053CBE0
    mov eax, dword ptr fs:[124]
    mov edi, eax

    可以看出 jmp 895B6FB0 这里就跳转到游戏的驱动保护里执行了。但是简单的jmp 0x805B53CC 是不行的,直接就蓝屏了,

    在用Kernel_Detective看看别的。

     

     

    找到可疑的东东,有4个线程在未知模块运行,估计他们就是驱动的监测线程,右键 暂停它们。 

    在KD的SSDT里直看到NtQuerySystemInformation这个SSDT HOOK  那些重要的inline hook都看不到,而线程中这些可疑线程,xt也看不到

    看来不管怎么的,有什么工具全给它招呼上还是对滴。

    现在用xt恢复ssdt和shadow ssdt试试看会发生什么吧。

    游戏没有掉,恢复的HOOK,也没有再被HOOK,用OD附近试试看。
     果然可以附加啦!!经测试 VE查找数据,OD下断均没问题,可以继续我们找CALL事业了 HOHO。

    注:OD要将StrongOD插件选项里的 Anti Anti_Attach 勾选上,否则挂上游戏仍然退出

     

     

    用XT可以看到NTReadVirtualMemory  NTWRiteVirtualMemory  NTAllocateVirtualMemory 被inline hook了,以下为函数源代码。也就是需要恢复的代码。
    NTReadVirtualMemory  0x805B52C2
    push 1C
    push 804DAEF0
    call 8053CBE0
    mov eax, dword ptr fs:[124]
    mov edi, eax
    mov al, byte ptr [edi+140]
    mov byte ptr [ebp-20], al
    mov esi, dword ptr [ebp+14]
    test al, al
    je short 805B534C 应跳转至0X805B52E4继续执行 HOOK 32字节NTReadVirtualMemory +0x22
    --------------------
    NTReadVirtualMemory  HOOK后
    jmp 88E52C20
    dec ebp
    sub al, 12
    jns short 805B52C5
    jmp dword ptr [ecx+24]
    add dword ptr [eax], eax
    add byte ptr [ebx+40878AF8], cl
    add dword ptr [eax], eax
    add byte ptr [eax+758BE045], cl
    adc al, 84
    Invalid Command
    je short 805B534C
    -------------------------
    NTWRiteVirtualMemory  0x805B53CC
    push 1C
    push 804DAF08
    call 8053CBE0
    mov eax, dword ptr fs:[124]
    mov edi, eax
    mov al, byte ptr [edi+140]
    mov byte ptr [ebp-20], al
    mov esi, dword ptr [ebp+14]
    test al, al
    je short 80565456应跳转到0x805B53EE继续执行 NTWRiteVirtualMemory+0x22 
    -------------------
    NTWRiteVirtualMemory  HOOK后
    jmp 88E52FB0
    dec ebp
    sub al, 8
    js short 805B53CF
    jmp dword ptr [ecx+24]
    add dword ptr [eax], eax
    add byte ptr [ebx+40878AF8], cl
    add dword ptr [eax], eax
    add byte ptr [eax+758BE045], cl
    adc al, 84
    Invalid Command
    je short 805B5456 
    ---------------------------------
    NTAllocateVirtualMemory  0x805A9ABA
    push 118
    push 804DACB8 应跳转到0x805A9ABF hook5字节 NTAllocateVirtualMemory +5
    ----------------
    NTAllocateVirtualMemory  HOOK 后
    jmp 88E53070
    push 804DACB8

     

     

     

     

    首先感谢论坛的crazyearl 本文代码根据他发表的过HS保护中的源码 分析编写注释 十分感谢为我们新手提供那么好的文章!
    本篇文章适用于菜鸟级新手查看,分析。
    该代码是我学习过程中一个实践,关于写驱动框架结构,驱动层inline hook,分析,绕过游戏驱动保护HOOK函数方法。
    也是学习郁金香驱动保护部分课程的一个实践。
    希望给像我一样零编程基础学驱动的菜鸟们一些分享,帮助。 期待喜欢这方面的朋友交流 ^_^  与君共勉!
    前篇写了通过KD XT工具过日服巫术驱动保护 使OD CE 正常加载教程,上篇写了被驱动保护HOOK的函数具体分析,找到恢复位置,这篇写下如何写代码恢复被HOOK的函数。
    思路: 找到被HOOK函数的地址,然后HOOK它前5个字节,写个jmp 自写函数   让它按照函数正常流程运行,跳过游戏检测call。
    首先要做的仍然是用工具 挂起检测线程,干掉系统回调。然后加载我们自己的驱动。
    加载驱动软件:DriverMonitor       调试信息查看:DebugView 
      
    注意!!(本驱动在xp 32位win7 32位ddk编译通过。xp32位"系统下载吧GhostXP SP3 2011装机版V8.0"测试通过,因汇编部分有些硬编码,不同系统可能会有所不同,请加载驱动前先用Kernel_Detective或xuetr查看相关代码,适当修改,否则蓝屏是跑不了的啦 ^_^)
    驱动代码中注释掉一些关于进程比较的代码,思路是如果游戏访问关键函数,让它执行自己的检测代码,其他执行我们HOOK的代码。
    具体实现代码以后在补充。
     
    驱动代码见下文:  
    /********************************************************************
    * 创建时间:  2012/03/16
    * 文件名称:  ByPass.c
    * 文件作者:  月夜翔龙* ===================================================================
    * 功能说明:  入口文件
    * -------------------------------------------------------------------
    * 其他说明:  
    *********************************************************************/
    #include <ntddk.h>
    #include "ddk_proc.h"
    #include "GetAddrs.h"
    #define INITCODE code_seg("INIT")
    #define PAGECODE code_seg("PAGE")
    #pragma INITCODE 
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING B)

        hookWriteMemory(); //调用自写hook函数,恢复系统原函数,跳过游戏检测CALL
     HookReadVirtualMemory();
     HookAllocateVirtualMemory();
        //注册派遣例程 
    pDriverObject->MajorFunction[IRP_MJ_CREATE]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_READ]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=ddk_DispatchRoutine_CONTROL; //IRP_MJ_CREATE相关IRP处理函数
     CreatMyDevice(pDriverObject); //创建驱动设备 
     pDriverObject->DriverUnload=ddk_unload;  //驱动卸载例程
        //return (1);
     return STATUS_SUCCESS;
    }
    #pragma PAGECODE
    NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp )
    {
     //对相应的IPR进行处理
     pIrp->IoStatus.Information=0;//设置操作的字节数为0,这里无实际意义
     pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功
     IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP
     KdPrint(("离开派遣函数\n"));//调试信息
     return STATUS_SUCCESS; //返回成功
    }
    void ddk_unload(IN PDRIVER_OBJECT pDriverObject)
    {
     UNICODE_STRING  symboName;
     PDEVICE_OBJECT pdev; //用来卸载设备
     uninstall();  //恢复HOOK
     RtlInitUnicodeString(&symboName,L"\\??\\ByPass_symlink");
        pdev=pDriverObject->DeviceObject; 
     IoDeleteSymbolicLink(&symboName);//删除符号链接
     IoDeleteDevice(pdev); //删除设备对象
     KdPrint(("驱动卸载成功。。。。。。OK\n\n"));
    }
    ---------------------------------------------------------------------------------------
    /********************************************************************
    * 创建时间:  2012/03/16
    * 文件名称:  ddk_proc.h 头文件
    * 文件作者:  月夜翔龙
    * ===================================================================
    * 功能说明:  变量定义,函数声明部分
    * -------------------------------------------------------------------
    * 其他说明:  
    *********************************************************************/
    #include <windef.h>
    #include <ntddk.h>
    /************************************************
    ***              函数前置声明部分              ******
    ************************************************/
    NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp ); //派遣函数
    extern long KeServiceDescriptorTable ; //导出SSDT表
    void ddk_unload (IN PDRIVER_OBJECT pDriverObject); //前置说明 卸载历程
    void wpoff(); //关闭页面保护 具体实现过程在下面
    void wpon(); //开启页面保护  具体实现过程在下面
    NTKERNELAPI UCHAR * PsGetProcessImageFileName(PEPROCESS Process);
    NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(__in   HANDLE ProcessId,__out  PEPROCESS *Process);
    /**************************************************
    **********         全局变量       *****************
    **************************************************/
    ULONG WriteMemoryAddr,writeMemory_22,writeMemory_7; //HOOK writeMemory使用
    ULONG ReadMemoryAddr,readMemory_22; //HOOK readmemory 使用
    ULONG AllocateMemoryAddr,AllocateMemory_5; //HOOK AllocateMemory使用
    #define NAKED __declspec(naked)  //定义裸体函数
    //*******************************************************************
    //PEPROCESS WriteMemoryEPROCESS = NULL;  //进程比较使用 该游戏不需要 
    // ULONG WriteMemoryEPROCESS_174;  //
    //ANSI_STRING wm_str1,wm_str2;   //保存进程名称
    //#define APPNAME "WizardryOnline"
    /**********************************************************
    ***               函数实现部分                          ***
    **********************************************************/
    //////////////////////////////////////////////////////////////////////
    // 名称: CreatMyDevice 
    // 功能: 创建设备
    // 参数: 驱动对象 在入口函数传递
    // 返回: status 
    //////////////////////////////////////////////////////////////////////
    NTSTATUS CreatMyDevice(IN PDRIVER_OBJECT pDriverObject)
    {
     NTSTATUS status;
     PDEVICE_OBJECT pDevObj; //用来返回设备
     UNICODE_STRING devName; //设备名称
     UNICODE_STRING symlinkname;
     RtlInitUnicodeString(&devName,L"\\Device\\ByPass_Devcice"); //初始化设备名称
     //创建设备
     status=IoCreateDevice(pDriverObject,0,&devName,FILE_DEVICE_UNKNOWN,0,TRUE,&pDevObj);
        if(!NT_SUCCESS(status)) //如果创建设备失败
     {
      if (status==STATUS_INSUFFICIENT_RESOURCES)
      {
       KdPrint(("驱动资源不足.....++++++++++++"));
       
      }
      if (status==STATUS_OBJECT_NAME_EXISTS)
      {
       KdPrint(("驱动对象名已存在.....++++++++++++"));
       
      }
      if (status==STATUS_OBJECT_NAME_COLLISION)
      {
       KdPrint(("驱动对象名有冲突....++++++++++++"));
       
      }
      KdPrint(("设备创建失败..........+++++++"));
      return status;
     }
     pDevObj->Flags |= DO_BUFFERED_IO ;
     //创建符号链接
        RtlInitUnicodeString(&symlinkname,L"\\??\\ByPass_symlink");
     status=IoCreateSymbolicLink(&symlinkname,&devName);
     if (!NT_SUCCESS(status))
     {
      IoDeleteDevice(pDevObj); //如果创建设备符号链接不成功则删除
      return status;
     }
     KdPrint(("设备创建成功...............++\n"));
         return STATUS_SUCCESS;
    }
    //////////////////////////////////////////////////////////////////////
    // 名称: WPOFF
    // 功能: 关闭页面保护
    // 参数: 
    // 返回: 
    //////////////////////////////////////////////////////////////////////
    void wpoff()
    {
     __asm 
     {
      cli
      mov eax,cr0
      and eax,not 10000h
      mov cr0,eax
     }
    }
    //////////////////////////////////////////////////////////////////////
    // 名称: WPON
    // 功能: 开启页面保护
    // 参数: 
    // 返回: 
    //////////////////////////////////////////////////////////////////////
    void wpon()
    {
     __asm 
     {
      mov eax,cr0
      or eax,10000h
      mov cr0,eax
      sti
     }
    }
    //////////////////////////////////////////////////////////////////////
    // 名称: 卸载函数
    // 功能: 处理卸载驱动要做的事情,恢复自写HOOK
    // 参数: 
    // 返回: 
    //////////////////////////////////////////////////////////////////////
    void uninstall()
    {
     KIRQL Irql;
     //WriteMemoryAddr=CurNTWriteVirtualMemory();
     BYTE byWriteVirtualMemory[7] = {0x6A,0x1C,0x68,0x08,0xAF,0x4D,0x80};  //系统原WriteVirtualMemory前7字节 硬编码 请适当修改 
        BYTE byReadVirtualMemory[7]  = {0x6A,0x1C,0x68,0xF0,0xAE,0x4D,0x80}; //系统原ReadVirtualMemory前7字节 硬编码 请适当修改
     BYTE byAllocateVirtualMemory[5] = {0x68,0x18,0x01,0,0}; //系统原AllocateVirtualMemory前5字节 硬编码 请适当修改
     wpoff(); //关闭页面保护
     Irql=KeRaiseIrqlToDpcLevel(); //提升IRQ等级
     ////恢复WriteVirtualMemory
     RtlCopyMemory((BYTE*)WriteMemoryAddr,byWriteVirtualMemory,7);
     ////恢复ReadVirtualMemory
     RtlCopyMemory((BYTE*)ReadMemoryAddr,byReadVirtualMemory,7);
     ////恢复AllocateVirtualMemory
     RtlCopyMemory((BYTE*)AllocateMemoryAddr,byAllocateVirtualMemory,5);
     //恢复IRQ中断等级
     KeLowerIrql(Irql);
     //开启页面保护
     wpon();
    }
     
    ---------------------------------------------------------------------------------------------------------
     
    /********************************************************************
    * 创建时间:  2012/03/16
    * 文件名称:  GetAddrs.h 头文件
    * 文件作者:  月夜翔龙
    * ===================================================================
    * 功能说明:  获得函数首地址,自写HOOK,跳过游戏检测CALL
    * -------------------------------------------------------------------
    * 其他说明:  
    *********************************************************************/
    /*********************************************************
    **********功能: 获得当前ReadVirtualMemory地址 ************
    **********参数:    无  ***********************************
    *********返回值: 函数地址 ********************************
    *********公式: 函数地址=SSDT表基地址+函数标号*4 **********
    *********************************************************/
    ULONG CurNTReadVirtualMemory() 
    {
     ULONG ReadMemoryBase;
     __asm
     { 
      push eax //存放ssdt地址 
         push ebx //存放函数在SSDT表索引号 ReadVirtualMemory 十进制186 十六进制0XBA 不同系统索引号可能不同 KD查看SSDT表 
      mov eax,KeServiceDescriptorTable
      mov eax,[eax] //取出ssdt基地址
      mov ebx,0xBA //存放索引号
      shl ebx,2 //0xBA*4 shl ebx,2 == imul ebx,ebx,4
      add eax,ebx //KeServiceDescriptorTable+0xBA*4  
      mov eax,[eax] //取出函数地址
            mov ReadMemoryBase,eax //保存到ReadMemoryBase 
      pop eax
      pop ebx
     }
     KdPrint(("curReadMemory值为%x +++++++\n",ReadMemoryBase));
     return ReadMemoryBase;
    }
    /*********************************************************
    **********功能: 获得当前WriteVirtualMemory地址 ************
    **********参数:    无  ***********************************
    *********返回值: 函数地址 ********************************
    *********公式: 函数地址=SSDT表基地址+函数标号*4 **********
    *********************************************************/
    ULONG CurNTWriteVirtualMemory() 
    {
     ULONG WriteMemoryBase;
     __asm
     { 
      push eax //存放ssdt地址 
         push ebx //存放函数在SSDT表索引号 WriteVirtualMemory 十进制277 十六进制0X115 不同系统索引号可能不同 KD查看SSDT表
      mov eax,KeServiceDescriptorTable
      mov eax,[eax] //取出ssdt基地址
      mov ebx,0x115 //存放索引号
      shl ebx,2 //0xBA*4 shl ebx,2 == imul ebx,ebx,4
      add eax,ebx //KeServiceDescriptorTable+0x115*4  
      mov eax,[eax] //取出函数地址
            mov WriteMemoryBase,eax //保存到WriteMemoryBase 
      pop eax
      pop ebx
     }
     KdPrint(("curWriteMemory值为%x +++++++\n",WriteMemoryBase));
     return WriteMemoryBase;
    }
    /*********************************************************
    **********功能: 获得当前NTAllocateVirtualMemory地址 ******
    **********参数:    无  ***********************************
    *********返回值: 函数地址 ********************************
    *********公式: 函数地址=SSDT表基地址+函数索引号*4 ********
    *********************************************************/
    ULONG CurNTAllocateVirtualMemory() 
    {
     ULONG AllocateMemoryBase;
     __asm
     { 
      push eax //存放ssdt地址 
         push ebx //存放函数在SSDT表索引号 AllocateMemory  十进制17十六进制0X11 不同系统索引号可能不同 KD查看SSDT表
      mov eax,KeServiceDescriptorTable
      mov eax,[eax] //取出ssdt基地址
      mov ebx,0x11 //存放索引号
      shl ebx,2 //0x11*4    shl ebx,2 == imul ebx,ebx,4
      add eax,ebx //KeServiceDescriptorTable+0x11*4  
      mov eax,[eax] //取出函数地址
            mov AllocateMemoryBase,eax //保存到AllocateMemoryBase 
      pop eax
      pop ebx
     }
     KdPrint(("curAllocateMemory值为%x +++++++\n",AllocateMemoryBase));
     return AllocateMemoryBase;
    }
    /*********************************************************
    **********功能: 通过MmGetSystemRoutineAddress()获取地址***
    ****************         演示,功能同上             ******
    **********参数:    无                               ******
    *********返回值: 函数地址                           ******
    *********公式: 无                                   ******
    **********************************************************
    ULONG OldNTAllocateVirtualMemory() 
    {
          ULONG OldAllocateMemoryBase;
       UNICODE_STRING S_AllocateMemory;
       RtlInitUnicodeString(&S_AllocateMemory,L"NtAllocateVirtualMemory");//初始化字串
       OldAllocateMemoryBase=(ULONG)MmGetSystemRoutineAddress(&S_AllocateMemory);//获得地址
       KdPrint(("OldAllocateMemory值为%x +++\n",OldAllocateMemoryBase));
       return OldAllocateMemoryBase;
    }
    */
    /*********************************************************
    **********功能: 恢复WriteVirtualMemory正常流程      ******
    ****************      跳过游戏检测CALL              ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式: 无                                   ******
    *********************************************************/
    static NAKED void MyWriteVirtualMemory()
    {
     /*进程比较代码实现,该游戏不需要
     获得调用者的EPROCESS
     WriteMemoryEPROCESS = IoGetCurrentProcess();
     KdPrint(("WriteMemoryEPROCESS值为%x ++++\n",WriteMemoryEPROCESS));
     WriteMemoryEPROCESS_174=(ULONG)WriteMemoryEPROCESS+0x174;
     KdPrint(("WriteMemoryEPROCESS+0x174值为%x ++++\n",WriteMemoryEPROCESS_174));
     将调用者的进程名保存到str1中
     RtlInitAnsiString(&wm_str1,(PCSZ)WriteMemoryEPROCESS_174);   
     将我们要比对的进程名放入str2
     RtlInitAnsiString(&wm_str2,APPNAME);
     KdPrint(("当前进程名称值为:%x ++++\n",&wm_str1));
     KdPrint(("APPNAME值为:%x ++++\n",&wm_str2));
     if (RtlCompareString(&wm_str1,&wm_str2,FALSE) == 0)
     */
     __asm 
     {
      //0x805B53CC 
      push 0x1C
      push 0x804DAF08  //硬编码,不同系统可能有所不同,请按实际修改
      mov eax,0x8053CBE0  //硬编码,不同系统可能有所不同,请按实际修改
      call eax
            mov eax, dword ptr fs:[0x124]
            mov edi, eax
            mov al, byte ptr [edi+0x140]
            mov byte ptr [ebp-0x20], al
            mov esi, dword ptr [ebp+0x14]
            test al, al
      mov eax,writeMemory_22 
      jmp eax  //恢复writememory前32字节然后跳转到writememory+0x22正常执行,跳过游戏检测call
     } //end asm 
    }
    /*********************************************************
    **********功能: 恢复ReadVirtual Memory正常流程      ******
    ****************      跳过游戏检测CALL              ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式: 无                                   ******
    *********************************************************/
    static NAKED  void MyReadVirtualMemory()
    {
     __asm 
     {
      //0x805B52C2
            push 0x1C
            push 0x804DAEF0 //硬编码,不同系统可能有所不同,请按实际修改
            mov  eax,0x8053CBE0 //硬编码,不同系统可能有所不同,请按实际修改
            call eax
            mov eax, dword ptr fs:[0x124]
            mov edi, eax
            mov al, byte ptr [edi+0x140]
            mov byte ptr [ebp-0x20], al
            mov esi, dword ptr [ebp+0x14]
            test al, al
      mov eax,readMemory_22 //恢复readmemory前32字节然后跳转到readmemory+0x22正常执行,跳过游戏检测call
      jmp eax
     }
    }
    /*********************************************************
    **********功能: 恢复AllocateVirtualMemory正常流程   ******
    ****************      跳过游戏检测CALL              ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式: 无                                   ******
    *********************************************************/
    static NAKED  void MyAllocateVirtualMemory()
    {
     __asm 
     {
            //0x805A9ABA 
            push 0x118  //硬编码,不同系统可能有所不同,请按实际修改
            mov eax,AllocateMemory_5//恢复前5字节然后跳转到allocatememory+0x5正常执行,跳过游戏检测call
            jmp eax
     }
    }
    /*********************************************************
    **********功能:hook原函数头5个字节跳转到自写函数执行******
    ****************                                    ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式:jmp jmpaddr  jmp机器码E9              ******
    *********jmpaddr公式:新地址-(原地址+5)或-原地址-5   ******
    *********************************************************/
    void hookWriteMemory()
    {
     BYTE  JmpAddress[7] = {0xE9,0,0,0,0,0x90,0x90};
     //该数组首字节为E9,即是jmp指令,后四字节为跳转字节,故为0,
     //0x90为NOP指令,因WriteMemory汇编代码头部是两条指令7字节 故后2字节用nop填充
     KIRQL Irql;
     WriteMemoryAddr=CurNTWriteVirtualMemory();//获得当前WriteVirtualMemory地址 即原地址  
     writeMemory_22=WriteMemoryAddr+0x22; //WriteVirtualMemory+0x22 恢复前32字节然后跳转到这里继续执行  
     *(ULONG *)(JmpAddress+1)=(ULONG)MyWriteVirtualMemory - (WriteMemoryAddr+5); 
     //将jmpaddr 写入数组E9之后4字节 
     wpoff(); //关闭CR0
     Irql=KeRaiseIrqlToDpcLevel(); //提升IRQ中断等级
     //向WriteVirtualMemory首地址写入7字节,实现HOOK
     RtlCopyMemory((BYTE*)WriteMemoryAddr,JmpAddress,7);
     KeLowerIrql(Irql); //恢复Irql
     wpon();  //开启cr0
    }
    /*********************************************************
    **********功能:hook原函数头5个字节跳转到自写函数执行******
    ****************                                    ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式:jmp jmpaddr  jmp机器码E9              ******
    *********jmpaddr公式:新地址-(原地址+5)或-原地址-5   ******
    *********************************************************/
    void HookReadVirtualMemory()
    {
     BYTE JmpAddress[7] = {0xE9,0,0,0,0,0x90,0x90};
     KIRQL Irql;
     ReadMemoryAddr=CurNTReadVirtualMemory();
     readMemory_22=ReadMemoryAddr+0x22;
     *(ULONG*)(JmpAddress+1)=(ULONG)MyReadVirtualMemory  - (ReadMemoryAddr+5);
     wpoff();
     Irql=KeRaiseIrqlToDpcLevel();
     RtlCopyMemory((BYTE*)ReadMemoryAddr,JmpAddress,7);
     KeLowerIrql(Irql);
     wpon();
    }
    /*********************************************************
    **********功能:hook原函数头5个字节跳转到自写函数执行******
    ****************                                    ******
    **********参数:    无                               ******
    *********返回值: 无                                 ******
    *********公式:jmp jmpaddr  jmp机器码E9              ******
    *********jmpaddr公式:新地址-(原地址+5)或-原地址-5   ******
    *********************************************************/
    void HookAllocateVirtualMemory()
    {
        BYTE Jmpaddress[5] = {0xE9,0,0,0,0}; 
     //因AllocateVirtualMemory汇编头部为push 118占5字节 与jmp xxxx 相同 故只需hook一条指令即可 
     KIRQL Irql;
     AllocateMemoryAddr=CurNTAllocateVirtualMemory();
     AllocateMemory_5=AllocateMemoryAddr+0x5;
     *(ULONG*)(Jmpaddress+1)=(ULONG)MyAllocateVirtualMemory - (AllocateMemoryAddr+5);
     wpoff();
     Irql=KeRaiseIrqlToDpcLevel();
     RtlCopyMemory((BYTE*)AllocateMemoryAddr,Jmpaddress,5);
     KeLowerIrql(Irql);
     wpon();
    }

    该驱动代码 可根据自己系统改变硬编码后 用XT KD 可以看到加载后和卸载 HOOK的几个函数代码变化,无需使用游戏。
    相信新手会对inline hook有所了解

     

     

     

    本人新博客网址为:http://www.hizds.com
    本博客注有“转”字样的为转载文章,其余为本人原创文章,转载请务必注明出处或保存此段。c++/lua/windows逆向交流群:69148232
  • 相关阅读:
    HDU 5135(再思考)
    HDU 5105
    HDU 5135
    Codeforces 985E
    Codeforces 985D
    Codeforces 975D
    Codeforces 975C
    Codeforces 976D
    HDU 1024 Max Sum Plus Plus (DP,水题)
    HDU 1003 Max Sum(DP,水题)
  • 原文地址:https://www.cnblogs.com/zhangdongsheng/p/2795483.html
Copyright © 2011-2022 走看看