【轉】日服巫術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有所了解

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM