BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / security / #31753同步于 2011/2/20
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Security机器人发帖

原创-《地下城》双开辅助逆向分析

aiai
2011/2/20镜像同步4 回复
《地下城与勇士》(简称DNF)我想就不用多介绍了,我也是这个游戏的一位爱好者。 熟悉DNF的人都知道,这个游戏主要就是分为刷图和PK两个部分,但是无论是哪个部分都可以利用双开工具收益,例如刷图双开还可以获得几次免费的深渊派队的机会,PK也可以用双开来刷决斗经验。 不过按理说DNF客户端并不允许大家双开,但是曾经见过网上流行一套驱动写的双开软件,是利用SSDT HOOK NtCreateMutant来实现的。最暴力但是有效的办法如下,其实就是拒绝掉所有创建的Mutant句柄: int __stdcall HookSSDT_NtCreateMutant(int a1, int a2, int a3, int a4) { Old_NtCreteMutant(a1, a2, a3, a4); return 0; } 但问题是这个方法很暴力有危险不说,更重要的是现在已经不能这么办了。先看看DNF游戏在运行的过程中情况吧:运行游戏先是DNFChina.exe、QQLogin.exe以及TenSafe.exe,它们负责登陆以及环境初始化,还有就是所谓的可疑模块检查和完整性检测。然后登陆之后,即DNF.exe开始运行,这个时候就会加载驱动TenSafe.sys,我们的第一个难点就在这里,即DNF反外挂中隐藏的白名单。 还是老样子,TenSafe把NtOpenProcess中的ObOpenObjectByPointer的调用改了: nt!NtOpenProcess+0x224: 805cc625 8d45dc lea eax,[ebp-24h] 805cc628 50 push eax 805cc629 ff75d4 push dword ptr [ebp-2Ch] 805cc62c e8c17a0000 call nt!PsLookupProcessByProcessId (805d40f2) 805cc631 ebde jmp nt!NtOpenProcess+0x1e7 (805cc611) 805cc633 8d45e0 lea eax,[ebp-20h] 805cc636 50 push eax 805cc637 ff75cc push dword ptr [ebp-34h] 805cc63a ff35b8495680 push dword ptr [nt!PsProcessType (805649b8)] 805cc640 56 push esi 805cc641 8d8548ffffff lea eax,[ebp-0B8h] 805cc647 50 push eax 805cc648 ff75c8 push dword ptr [ebp-38h] 805cc64b ff75dc push dword ptr [ebp-24h] 805cc64e e88d12bb28 call a917d8e0(还是老样子,把call nt!ObOpenObjectByPointer改了,不过里面的内容变化巨大。。。) 805cc653 8bf8 mov edi,eax 进入ObOpenObjectByPointer的函数之后,分为了3个板块:1、检查调用者是不是属于系统进程(即System、Csrss、smss一类的);2、检查是不是特殊的白名单进程(不过我的机器上好像没有这种情况);3、检查是不是腾讯相关软件的进程(例如QQ.exe、TXPlatform.exe)。如果说是白名单进程,TenSafe会直接放行,这样一来就给了我们一个可乘之机,找一个已知的白名单进程,并且可以注入的,我在那个表中果然找到了svchost.exe,因此这个进程就成了我们的载体(当然事实上后来才发现,对于用户名为SYSTEM的svchost进程,注入且运作才是有效的): lkd> dd 86c6a9ac 86c6a9ac 86d94504 86dd75ac 00000100 0a0a0007 lkd> dd 86d94504-24 86d944e0 86ccf888 00000500 000fffff b494762b PROCESS 86db0a88 SessionId: 0 Cid: 0354 Peb: 7ffdf000 ParentCid: 047c DirBase: 07700160 ObjectTable: e2f60b00 HandleCount: 174. Image: svchost.exe 因此,找到了载体,我们接下来就需要找对互斥句柄了,不过一些辅助工具给了我们明确的信息,其实甚至在网上都能查到,只不过别人的很多是加载驱动的版本,当然我们需要不利用加载驱动的方式而是通过用户模式来解决。要远程关掉DNF.exe进程中的互斥句柄,仅需要找对对象之后,利用Native函数ZwDuplicateObject来实现。具体的代码如下: void RunDNFSK() { NTSTATUS status = 0; DWORD buflen = 256, needlen = 0; DWORD HandleCnt = 0; OBJECT_ATTRIBUTES objatr; UINT i; PSYSTEM_HANDLE_INFORMATION pBuf = NULL; PSYSTEM_HANDLE_TABLE_ENTRY_INFO pSysHandleInfo = NULL; //初始化对对象属性 InitializeObjectAttributes(&objatr,0,0,0,0); //获得句柄表 do { //申请查询句柄信息所需的内存 ZwAllocateVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,0,&buflen,MEM_COMMIT,PAGE_READWRITE); //查询系统句柄信息 status=ZwQuerySystemInformation(SystemHandleInformation,(PVOID)pBuf,buflen,&needlen); if( status==STATUS_SUCCESS ) break; //申请成功,退出执行下步 //不成功:则释放内存,以返回的needlen可以作参考,需要申请一块足够大的内存 ZwFreeVirtualMemory(NtCurrentProcess(),(PVOID*)&pBuf,&buflen,MEM_RELEASE); //然后把要申请的内存大小乘2,直至成功为止 buflen*=2; pBuf=NULL; } while(1); //返回的缓冲区内容的第一个DWORD是总的句柄的个数 HandleCnt = pBuf->NumberOfHandles; //跳过句柄计数,句柄信息真正的开始 pSysHandleInfo = (PSYSTEM_HANDLE_TABLE_ENTRY_INFO)( (char*)pBuf + sizeof(DWORD) ); for( i = 0; i < HandleCnt; i++,pSysHandleInfo++/*指向下一个结构*/ ) { // 初始化句柄信息 HANDLE hOwner = NULL; HANDLE hDupHandle = NULL; // 以复制句柄方式打开进程:hOwner hOwner=OpenProcess(PROCESS_DUP_HANDLE,FALSE,pSysHandleInfo->UniqueProcessId); // 复制进程到可操作的范围:hDupHandle ZwDuplicateObject(hOwner,(HANDLE)pSysHandleInfo->HandleValue,GetCurrentProcess(), &hDupHandle,PROCESS_ALL_ACCESS, FALSE, DUPLICATE_SAME_ACCESS); if( hDupHandle == NULL ) { // PRINT("PID:%d DuplicateHandleFailed\n\n",pSysHandleInfo->UniqueProcessId); goto DuplicateHandleFailed; } // 句柄复制成功 if( hDupHandle ) { // 获取句柄的基本信息: OBJECT_BASIC_INFORMATION ObjBasicInfo = {0}; status=ZwQueryObject(hDupHandle,ObjectBasicInformation,&ObjBasicInfo, sizeof(ObjBasicInfo), NULL); // 获取句柄的类型信息 POBJECT_TYPE_INFORMATION pTypeInfo = NULL; pTypeInfo=(POBJECT_TYPE_INFORMATION)malloc( 2*ObjBasicInfo.TypeInfoSize ); memset( pTypeInfo, 0, 2*ObjBasicInfo.TypeInfoSize); status=ZwQueryObject(hDupHandle,ObjectTypeInformation,pTypeInfo,2*ObjBasicInfo.TypeInfoSize, NULL); // 类型名称判断 if( status == STATUS_SUCCESS && wcsncmp(pTypeInfo->TypeName.Buffer, L"Mutant", 6) == 0 || wcsncmp(pTypeInfo->TypeName.Buffer, L"Section", 7) == 0 ) { // 获取句柄的名称信息 if( ObjBasicInfo.NameInfoSize ) { POBJECT_NAME_INFORMATION pNameInfo = NULL; pNameInfo=(POBJECT_NAME_INFORMATION)malloc( 2*ObjBasicInfo.NameInfoSize ); memset( pNameInfo, 0, 2*ObjBasicInfo.NameInfoSize); status = ZwQueryObject(hDupHandle, ObjectNameInformation, pNameInfo, 2*ObjBasicInfo.NameInfoSize, NULL); // 对获取的句柄值进行筛选(Start); if(status == STATUS_SUCCESS && pNameInfo->Name.Buffer != NULL) { // PRINT("ObjName = %ws\n\n", pNameInfo->Name.Buffer); } else { // PRINT("\n\n"); } // 操作数进行操作 int OperateValue = 0; // 操作数 OperateValue = FindSpecialHandle( (PUNICODE_STRING)pNameInfo ); if( OperateValue == 1 ) { PRINT("%ws\n", pTypeInfo->TypeName.Buffer); PRINT("PID = %d\n", pSysHandleInfo->UniqueProcessId); PRINT("HandleValue = 0x%0.8X\n", pSysHandleInfo->HandleValue); PRINT("ObjName = %ws\n\n", pNameInfo->Name.Buffer); PRINT("Find The Handle Need to Close\n\n"); ZwDuplicateObject(hOwner, (HANDLE)pSysHandleInfo->HandleValue, 0, 0, 0, 0, DUPLICATE_CLOSE_SOURCE);//(关闭远程句柄) } // 对获取的句柄值进行筛选(End); } } // 关闭操作的相关句柄 if(hDupHandle != NULL) CloseHandle(hDupHandle); } // 关闭打开进程的句柄 DuplicateHandleFailed: if(hOwner != NULL) CloseHandle(hOwner); } } 我们只需要把这段代码注入到一个用户名为SYSTEM的svchost进程,然后就能利用TenSafe中自带的白名单机制,关闭远程进程(DNF.exe)的互斥句柄。但是,光是这样还不够,因为后来腾讯又增加了一种新的检测方案,既是窗口枚举,用Spy++可以看到DNF游戏的窗口句柄。 当我再开一个客户端的时候,扫描就会检测窗口句柄,一旦有“地下城与勇士”的窗口,新客户端游戏的窗口仍然不会显示出来,所以我们还需要加入其它的处理方式。 思路就是,把DNF.exe的“地下城与勇士”窗口,设置为一个已知窗口的子窗口进程(利用函数SetParent),然后再等到新游戏窗口出现后,重新将其恢复。 这样,就能再新开客户端的时候,躲避检测。因此执行流程就是:打开第一个DNF之后,远程关闭句柄,隐藏窗口,然后待打开第二个DNF之后,恢复第一个DNF的窗口即实现双开。利用SPY++显示打开了两个客户端之后的窗口情况(有两个“地下城与勇士”的窗口同时出现): 最后,我建了一个小号,通过下图你就可以看出双开的情况(注意喇叭黄字):
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
houlen机器人#1 · 2011/2/20
大牛,求带。
smilefufu机器人#2 · 2011/2/21
lz imba。。。。 话说以前用的双开工具经常有两边不同步的情况(非激活DNF窗口处于半掉线假死状态),不知lz这个方法是否能两边同步
aiai机器人#3 · 2011/2/21
游戏的进度不大可能完全同步,网络游戏本来有延迟的,这个在城镇里面很明显,属于秒级(我猜可能是城镇人多的情况),刷图和PK会好很多。 至于你说的那种情况没有遇到,倒是莫名其妙的卡死掉线多多得有,也不知道是谁的问题了,这游戏本来就有点问题吧 【 在 smilefufu 的大作中提到: 】 : lz imba。。。。 : 话说以前用的双开工具经常有两边不同步的情况(非激活DNF窗口处于半掉线假死状态),不知lz这个方法是否能两边同步 : -- : ...................
DrJan机器人#4 · 2011/2/21
这游戏刚出的时候双开过 用vmware 赞逆向