声明:本文只为研究技术,如使用本文中的源码及技术产生了侵权或违法行为,本人概不负责。如有侵犯你版权的行为,请联系我,本文将立即改正!
在正式开篇之前我要感谢看雪ID:
十年寒窗 提供了ThreadHideFromDebugger.sys驱动程序的源码.以及另外几位不愿意透露姓名大牛的破解思路.感谢你们!
前言:大家好,我又回来了.承诺过许多事情,要一件一件去完成.本打算去年8月就写出来的.可惜一直没有时间整理这篇文章.
关于HShield的文章在网络上一搜一大把,我想也没什么秘密可言了.
当时在看雪第一篇搜索出来的帖子(
http://bbs.pediy.com/showthread.php?t=104951)
本想做一个从头到尾所有版本的帖子.可惜精力太有限了.今天送上的是 ehsvc.dll版本为 5.5.14.174.去年是多少我忘记了,只记录着它的驱动文件版本号EagleXNt.sys:1.0.0.36截止发帖时本文的一切内容都对该驱动有效.
本文使用操作系统:WindowsXP_SP3
本文完整代码在最下面下载
老规矩既是研究游戏保护总要有个研究对象,选定日本的DNF (アラド戦記)
简报:
NtClose [->0x9FD162F0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtDeviceIoControlFile [->0x9FD16190==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtOpenProcess [->0x9FD16400==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtGetContextThread [->0x9FD16DC0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtQueryPerformanceCounter[->0x9FD16FC0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtReadVirtualMemory [->0x9FD166C0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtSetContextThread [->0x9FD16C70==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtWriteVirtualMemory [->0x9FD16820==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
KiAttachProcess [->0x9FD15DB0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
IopXxxControlFile [->0x9FD163B0==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
PsSuspendThread [->0x9FD16F40==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
NtGetContextThread [->0x9FD16980==>C:\WINDOWS\system32\drivers\EagleXNt.sys]
另外有一个系统回调函数、一个DPC、两个系统线程
下面看看它下钩子的手法:
看看 NtOpenProcess
大家对照上面一张图可以看到它做得很隐蔽,
接着往下看
终于看到了熟悉的JMP
其它函数和这里处理的手法基本一致.
给出解决方案,很简单:
以NtOpenProcess 为例
在头5字节设置一个钩子,然后过滤.判断如果是游戏进程访问了这个函数则执行正常的流程
否则执行我们自己的流程.下面看代码
//////////////////////////////////////////////////////////////////////
// 名称: MyNtOpenProcess
// 功能: NtOpenProcess的中继函数
// 参数:
// 返回:
//////////////////////////////////////////////////////////////////////
BYTE *pOpenProcessCall = (PBYTE)0x804E3EA3;
ULONG NtOpenProcessAddress;
ULONG NtOpenProcessRetn1;
ULONG NtOpenProcessRetn2;
PEPROCESS processEPROCESS = NULL; //保存访问者的EPROCESS
ANSI_STRING p_str1,p_str2; //保存进程名称
static NAKED VOID Nakd_NtOpenProcess()
{
__asm
{
pushad
pushf
}
//获得调用者的EPROCESS
processEPROCESS = IoGetCurrentProcess();
//将调用者的进程名保存到str1中
RtlInitAnsiString(&p_str1,(ULONG)processEPROCESS+0x174);
//将我们要比对的进程名放入str2
RtlInitAnsiString(&p_str2,APPNAME);
if (RtlCompareString(&p_str1,&p_str2,TRUE) == 0)
{
//这里说明DNF 进程访问这里了
__asm
{
popf
popad
push 0xC4
push NtOpenProcessRetn1
retn
}
}
else
{
__asm
{
popf
popad
push 0x0C4
push 0x804F5308
call pOpenProcessCall
push NtOpenProcessRetn2
retn
}
}
}
其它的函数依次类推.但是NtGetContextThread不可以,从简报上面大家可以看到NtGetContextThread这个函数被HOOK 了两次
下面看看NtGetContextThread 被挂钩后的样子
大家清楚看到了吧,有2处.而第一处毋庸置疑的每次都会执行到.
看下NtGetContextThread被我们挂钩以后
mov edi, edi
push ebp
mov ebp, esp
push ecx
push esi
mov eax, dword ptr fs:[124]
mov al, byte ptr [eax+140]
push 0
mov byte ptr [ebp-4], al
lea eax, dword ptr [ebp+8]
push eax
push dword ptr [ebp-4]
push dword ptr [ntoskrnl.PsThreadType]
jmp A52756F0
call 8787BF08
mov esi, eax
test esi, esi
jl short 80636D34
push edi
mov edi, dword ptr [ebp+8]
test byte ptr [edi+248], 10
jne short 80636D27
push dword ptr [ebp-4]
push dword ptr [ebp+C]
push edi
jmp A52757A0
mov esi, eax
jmp short 80636D2C
mov esi, C0000008
mov ecx, edi
call 879F6050
pop edi
mov eax, esi
pop esi
leave
retn 8
而第二个挂钩处就是这次绕过游戏保护的妙笔生花之处了(详见下面给出的代码),原因追溯到游戏保护会在R3层判断是否有硬件断点
看了下MSDN
BOOL WINAPI GetThreadContext(
__in HANDLE hThread,
__in_out LPCONTEXT lpContext
);
大家看到了LPCONTEXT 参数前面写着 in out 意味着输入和输出
于是我们联想到,如果在半路截住NtGetContextThread设置它的参数lpContext为一些不敏感的内容呢?又或者?总之可以随心所欲的玩弄了
关于加载驱动以及挂载OD的工作顺序如下,
1.先加载ThreadHideFromDebugger.sys (相关技术细节大家GOOGLE SetInformationThread)
2.启动游戏
3.用XueTr删除系统回调函数和DPC,
4.用process explorer挂起两条系统线程(这两步我都用工具完成的)
5.加载驱动
6.挂载OD
因为HShield 的版本太多了.我的文章不一定能够帮到你,请见谅.
完整驱动源码下载:
sysCode.zip
ThreadHideFromDebugger.zip
到此本文结束
最后AD一下,我不想辛苦了半年的东西就这么扔掉了.由于日本DNF登陆的时候网页需要验证码,出售绕过该验证码的方案,既:直接启动客户端.以及大量的游戏特征码.可以让你的挂武装到脚趾甲
最后还想找个"这"方面的工作.自己做太累了.我累了
联系QQ:460874,(只联系业务内容,不提供技术咨询)
[课程]FART 脱壳王!加量不加价!FART作者讲授!