用SSDT方法恢复冒险岛的部分函数

 看了那么多文章、视频,现在自己跟着做下恢复的驱动程序吧。今天拿冒险岛的HS驱动做为例子吧。冒险岛游戏对Xuetr进行检测了,打开XueTr不久就会游戏发现非法模块,最终游戏关闭。就拿上了一款叫Kernel Detective的ARK工具进行检测冒险岛的驱动吧。

  因为Kernel Detective这款工具不能检测到有任何SSDT函数的挂钩,而使用一般的打开进程工具却不能打开它的进程,可知道,这款游戏驱动对NtOpenProcess函数进行了InlineHook,InlineHook如果比较简单的,用XueTr可以检测到的,我们用Kernel Detective工具转到NtOpenProcess的原始地址看看前15个字节是否有存在JMP XXXXXXXX之类的不如真实的指令,我们就知道它是否对NtOpenProcess进行了简单的InlineHook,如此分析

最终分析出:HS这个游戏保护对SSDT表的函数HOOK了三个函数。NtOpenProcess,NtReadVirtualMemory,NtWriteVirtualMemory。

NtOpenProcess的原指令:2011年06月27日

NtOpenProcess的HOOK后指令:2011年06月27日


NtReadVirtualMemory的原指令:2011年06月27日

NtReadVirtualMemory的Hook后指令:2011年06月27日

NtWriteVirtualMemory的原指令:2011年06月27日

NtWriteVirtualMemory 的Hook后指令2011年06月27日


跟住上面几幅图片已经可以看到,冒险岛的驱动保护并不是很强。我们编写代码恢复这几个被HOOK的函数

 

#include <ntddk.h>
#include <windef.h>
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
PVOID ServiceTableBase;
PULONG ServiceCounterTableBase;
ULONG NumberTableBase;
ULONG ParamTableBase;
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE;  //定义一个SSDT表的结构
extern PSERVICE_DESCRIPTOR_TABLE    KeServiceDescriptorTable;//这个的变量名是不能变的
typedef NTSTATUS(*NTOPENTHREAD)(OUT PHANDLE ThreadHandle,
                 IN ACCESS_MASK DesiredAccess,
                 IN POBJECT_ATTRIBUTES ObjectAttributes,
                 IN PCLIENT_ID ClientId);
typedef NTSTATUS (*ZWOPENPROCESS)(OUT PHANDLE ProcessHandle,
                 IN ACCESS_MASK AccessMask,
                 IN POBJECT_ATTRIBUTES ObjectAttributes,
                 IN PCLIENT_ID ClientId);
typedef NTSTATUS(*NTREADVIRTUALMEMORY)(IN HANDLE ProcessHandle,
                     IN PVOID BaseAddress,
                     OUT PVOID Buffer,
                     IN ULONG BufferLength,
                     OUT PULONG ReturnLength OPTIONAL);
typedef NTSTATUS(*NTWRITEVIRTUALMEMORY)(IN HANDLE ProcessHandle,
                     IN PVOID BaseAddress,
                     IN PVOID Buffer,
                     IN ULONG BufferLength,
                     OUT PULONG ReturnLength OPTIONAL);     //声明一系列被HOOK函数的原型      
NTOPENTHREAD     RealNtOpenThread;//接着定义这些结构的变量
ZWOPENPROCESS    RealZwOpenProcess;
NTREADVIRTUALMEMORY  RealNtReadVirtualMemory;
NTWRITEVIRTUALMEMORY RealNtWriteVirtualMemory;
VOID Hook();//挂钩SSDT表的函数,也就是恢复的过程函数
VOID UnHook();//恢复SSDT表的函数过程
VOID TD_DRIVER_UNLOAD(PDRIVER_OBJECT DriverObject);//驱动卸载例程
NTSTATUS returnvalue;
ULONG NtOpenProcess_15;
ULONG NtOpenThread_15;
ULONG NtReadVirtualMemory_12;
ULONG NtWriteVirtualMemory_12;
ULONG OldServiceAddress1,OldServiceAddress2,OldServiceAddress3,OldServiceAddress4;
__declspec(naked) NTSTATUS __stdcall My_NtReadVirtualMemory(HANDLE ProcessHandle,PVOID BaseAddress,PVOID Buffer,ULONG BufferLength,ULONG ReturnLength)//自定义的要替换的新的NtOpenProcess函数过程
{
 returnvalue =(NTSTATUS)(NTREADVIRTUALMEMORY)RealNtReadVirtualMemory(ProcessHandle,BaseAddress,Buffer,BufferLength,ReturnLength);//调用原函数,
 __asm
 {
  push 1Ch
  push 804DA4E0h
  mov eax,80538FB0h
  call eax
  jmp [NtReadVirtualMemory_12]
 }//恢复原指令。。。。。。
}
__declspec(naked) NTSTATUS __stdcall My_NtWriteVirtualMemory(HANDLE ProcessHandle,PVOID BaseAddress,PVOID Buffer,ULONG BufferLength,PULONG ReturnLength)//与此类推这就是恢复NtWriteVirtualMemory的自定义函数过程
{
 returnvalue =(NTSTATUS)(NTWRITEVIRTUALMEMORY)RealNtWriteVirtualMemory(ProcessHandle,BaseAddress,Buffer,BufferLength,ReturnLength);
 __asm
 {
  push 1Ch
  push 804DA4F8h
  mov eax,80538FB0h//恢复原指令
  call eax
  jmp [NtWriteVirtualMemory_12]//跳转到恢复后的下一个地址继续执行
 }
}
__declspec(naked) NTSTATUS __stdcall My_NtOpenProcess(PHANDLE ProcessHandle,ACCESS_MASK AccessMask,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId)
{
 returnvalue =(NTSTATUS)(ZWOPENPROCESS)RealZwOpenProcess(ProcessHandle,AccessMask,ObjectAttributes,ClientId);
 __asm
 {
  push 0C4h
  push 804DAAB0h
  mov eax,80538FB0h
  call eax
  jmp  [NtOpenProcess_15]
 }//如此类推。。。。。。
}
__declspec(naked) NTSTATUS __stdcall My_NtOpenThread(PHANDLE ThreadHandle,ACCESS_MASK AccessMask,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId)
{
 returnvalue =(NTSTATUS)(NTOPENTHREAD)RealNtOpenThread(ThreadHandle,AccessMask,ObjectAttributes,ClientId);
 __asm
 {
  push 0C0h
  push 804DAAD8h
  mov eax,80538FB0h
  call eax
  jmp  [NtOpenThread_15]
 }
}//这个是多余的。我只是为了方便如果其他游戏保护HOOK了NtOpenThread的几个字节可以恢复而已。
VOID Hook()
{
 ULONG NtOpenProcess_Cur_Addr;
 ULONG NtOpenThread_Cur_Addr;
 ULONG NtReadVirtualMemory_Cur_Addr;
 ULONG NtWriteVirtualMemory_Cur_Addr;
 NtOpenProcess_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;
 NtOpenThread_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x80 * 4;
 NtReadVirtualMemory_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x0BA * 4;
 NtWriteVirtualMemory_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x115 * 4;
 OldServiceAddress1=*(ULONG*)NtOpenProcess_Cur_Addr;
 OldServiceAddress2=*(ULONG*)NtOpenThread_Cur_Addr;
 OldServiceAddress3=*(ULONG*)NtReadVirtualMemory_Cur_Addr;
 OldServiceAddress4=*(ULONG*)NtWriteVirtualMemory_Cur_Addr;
 RealZwOpenProcess=(ZWOPENPROCESS)OldServiceAddress1;
 RealNtOpenThread=(NTOPENTHREAD)OldServiceAddress2; 
 RealNtReadVirtualMemory=(NTREADVIRTUALMEMORY)OldServiceAddress3;
 RealNtWriteVirtualMemory=(NTWRITEVIRTUALMEMORY)OldServiceAddress4; 
 NtOpenProcess_15 = OldServiceAddress1+15;
 NtOpenThread_15 = OldServiceAddress2+15;
 NtReadVirtualMemory_12=OldServiceAddress3+12;
 NtWriteVirtualMemory_12=OldServiceAddress4+12;
 __asm
 {
  cli
  mov eax,cr0
  and eax,not 10000h
  mov cr0,eax
 }
 *((ULONG*)NtOpenProcess_Cur_Addr) = (ULONG)My_NtOpenProcess;
 *((ULONG*)NtOpenThread_Cur_Addr) = (ULONG)My_NtOpenThread;
 *((ULONG*)NtReadVirtualMemory_Cur_Addr) = (ULONG)My_NtReadVirtualMemory;
 *((ULONG*)NtWriteVirtualMemory_Cur_Addr) = (ULONG)My_NtWriteVirtualMemory;
 __asm
 {
  mov eax,cr0
  or eax,10000h
  mov cr0,eax
  sti
 }
 KdPrint(("编程部落超级过游戏保护驱动恢复成功...\n"));

 KdPrint((URL:DangDang.5d6d.com\));
}
VOID UnHook()
{
 ULONG NtOpenProcess_Cur_Addr;
 ULONG NtOpenThread_Cur_Addr;
 ULONG NtReadVirtualMemory_Cur_Addr;
 ULONG NtWriteVirtualMemory_Cur_Addr;
 NtOpenProcess_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x7A * 4;
 NtOpenThread_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x80 * 4;
 NtReadVirtualMemory_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x0BA * 4;
 NtWriteVirtualMemory_Cur_Addr = (ULONG)KeServiceDescriptorTable->ServiceTableBase + 0x115 * 4;
 __asm
 {
  cli
  mov eax,cr0
  and eax,not 10000h
  mov cr0,eax
 }
 *((ULONG*)NtOpenProcess_Cur_Addr) = (ULONG)OldServiceAddress1;
 *((ULONG*)NtOpenThread_Cur_Addr) = (ULONG)OldServiceAddress2;
 *((ULONG*)NtReadVirtualMemory_Cur_Addr) = (ULONG)OldServiceAddress3;
 *((ULONG*)NtWriteVirtualMemory_Cur_Addr) = (ULONG)OldServiceAddress4;
 __asm
 {
  mov eax,cr0
  or eax,10000h
  mov cr0,eax
  sti
 }
 KdPrint(("编程部落超级过游戏保护驱动卸载成功...\n"));

 KdPrint((URL:DangDang.5d6d.com\));
}
VOID TD_DRIVER_UNLOAD(PDRIVER_OBJECT DriverObject)
{
 KdPrint(("The Driver Ready to End...\n"));
 UnHook();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING Register)
{
 KdPrint(("The TDang Writting this Driver...\n"));
 Hook();
 DriverObject->DriverUnload =TD_DRIVER_UNLOAD;
 return STATUS_SUCCESS;
}
   为了方便上面就不打那么多字了。打字累啊。就这个驱动可以恢复到了冒险岛HOOK的前几个字节。但是恢复后。进程可以打开了。但是使用OD不能附加冒险岛的进程,刚刚忘记了分析还有一个函数就是KeAttachProcess和KiAttachProcess这两个函数,如果这两个函数被HOOK了,就不能正常的附加进程了,KeAttachProcess是个导出函数,使用MmGetSystemRoutineAddress这个内核函数很容易地就可以读出他的原始地址,好了。这次就分析到这里了。

做下广告吧。。。欢迎大家来DangDang.5d6d.com编程部落前来学习于观摩。好了。下次我们就来分析下腾讯的游戏吧。本文章是本人第一次写的文章,累死了,真体谅那些写那么长文章那些人了。顶你们。2011年06月27日

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值