BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / security / #30643同步于 2010/11/3
Security机器人发帖

重新静态方式看了看“扣扣”

ridiculous
2010/11/3镜像同步0 回复
上次主要是看的360扣扣的钩子函数,其主要是阻止QQ的加载模块来阻止QQ的组件加载,其实如果我们熟悉了某个DLL对应的服务,我们也可以这么玩。后来测试发现,有的DLL其实可以在QQ运行之后再进行卸载,比如我们可以把Today.dll强制卸载,然后你就死活点不开“每日新闻”了。 但是腾讯和360“口水战”的焦点就在于360说腾讯“扫描磁盘”,这个问题还真的没有验证过,不管别人怎么说,有机会的话最好还是自己看看。 PS:说起来要看的话,最好把360安全卫士卸载了只装“360扣扣”,不然感觉有的PEDIY很麻烦。我之前没有卸载,所以麻烦死了,好多以静态看。 不过360说可以阻止腾讯扫描磁盘,那么最好就从360的实现来反推一下,腾讯是不是真的在扫磁盘。参考ZenZero同学的数据http://forum.byr.edu.cn/article/Security/30614,可以知道,在360扣扣运行时做了些什么,于是找到相关的函数: void __cdecl StartHook_Entry(LPCWSTR lpLibFileName) { HANDLE v1; // eax@10 HANDLE v2; // eax@16 LPVOID Args; // [sp+8h] [bp-Ch]@3 DWORD ThreadId; // [sp+Ch] [bp-8h]@16 LPTHREAD_START_ROUTINE lpStartAddress; // [sp+10h] [bp-4h]@3 WriteLog(L"[StartHook] begin"); ExpandEnvironmentStringsW(L"%APPDATA%\\360QGuard\\UserConfig.ini", (LPWSTR)&FileName, 0x104u); PathCombineW((LPWSTR)&g_Config_INI, lpLibFileName, L"..\\Config.ini"); memset(&Filename, 0, 0x208u); GetModuleFileNameW(0, &Filename, 0x104u); PathRemoveFileSpecW(&Filename); WriteLog(L"[StartHook] QQDir=%s", &Filename); CheckBadVersion(); if ( sub_10001730() ) { WriteLog(L"[StartHook]This version is a bad version"); } else { if ( Initial2ParametersByVersion((int)&lpStartAddress, (int)&Args) ) { LoadLibraryW(lpLibFileName); WriteLog(L"[StartHook]before hook CoLoadLibray"); //HOOK the Common.dll IAT,Function CoLoadLibrary is Exported by ole32.dll IatHook(L"Common.dll","ole32.dll",(int)"CoLoadLibrary", lpLibFileName,(int)CoLoadLibrary,(const WCHAR *)new_CoLoadLibrary); if ( !SetUserConfigINI(L"News", 1) || !SetUserConfigINI(L"Risk", 1) || !SetUserConfigINI(L"Announce", 1) || IsSetUserConfigINIScanOK() ) //HOOK the Common.dll IAT,Function SetWindowPos is Exported by GF.dll IatHook(L"GF.dll","USER32.dll",(int)"SetWindowPos", lpLibFileName,(int)SetWindowPos,(const WCHAR *)new_SetWindowsPos); sub_1000C640(); v1 = GetCurrentThread(); sub_1000CAA0(v1); WriteLog(L"[StartHook] Before Hook LoadLibraryW"); g_Ori_LoadLibraryW = (int (__stdcall *)(_DWORD))CheckFunctionIsOK("kernel32.dll", "LoadLibraryW"); if ( g_Ori_LoadLibraryW ) InlineHookFunctionStub((int)&g_Ori_LoadLibraryW, New_LoadLibraryW); WriteLog(L"[StartHook] Before Hook CreateProcessInternalW"); g_Ori_CreateProcessInternalW = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD, _DWORD))CheckFunctionIsOK("kernel32.dll", "CreateProcessInternalW"); if ( g_Ori_CreateProcessInternalW ) InlineHookFunctionStub((int)&g_Ori_CreateProcessInternalW, New_CreateProcessInternalW); WriteLog(L"[StartHook] Before Hook ShellExecuteExW"); g_Ori_ShellExecuteExW = (int (__stdcall *)(_DWORD))CheckFunctionIsOK("shell32.dll", "ShellExecuteExW"); if ( g_Ori_ShellExecuteExW ) InlineHookFunctionStub((int)&g_Ori_ShellExecuteExW, New_ShellExecuteExW); sub_1000C7F0(); WriteLog(L"[StartHook]before RemoveAD, nParamId=%d", Args); ThreadId = 0; v2 = CreateThread(0, 0, lpStartAddress, Args, 0, &ThreadId);// ThreadFunc_RemoveAD if ( v2 ) CloseHandle(v2); }else{ WriteLog(L"[StartHook]This version is not supported"); } } } 这个是DLLMain中运行的一个函数,也是初始话的一些列工作了,然后360扣扣HOOK了几个函数,其中这里有个Initial2ParametersByVersion根据你的QQ版本有相应的nParamId数据,不过lpStartAddress最后都是一个定值,估计目前可能就是这样吧。我的是DgbView打印数据是: ...... [StartHook]before RemoveAD, nParamId=200910600 [RemoveAD] Begin [RemoveAD] Replace ID=200910600 On 7 Positions,index=8 ...... 如果说ZenZero同学的值是nParamId = 201010200,其版本值貌似是范围为01.55.1861.0000~01.55.9999.0000,不是传统的QQ2010(版本是01.51.1760.0),也许是QQ2010的SP某版本,若问求解释。 在CreateThread中lpStartAddress指的位置是sub_10001CE0,这个下面会根据不同的nParamId(其实就是不同的QQ版本)计算出来需要HOOK多少个地方,index其实是一个表偏移的位置,在QGuard.dll的0x115F8位置开始有个很大的表,其实是个结构体表,可以简单的看成是: struct Table { ULONG nParamId_QQVersion; ULONG anotherStruct; ULONG NeedHookPostion; } 比如我的QQ为了屏蔽安全检查就需要打7个补丁。事实上我做了个实验:没有“360扣扣”的时候我的QQ有35个补丁;有“360扣扣”的时候,QQ有47个补丁。其中新增补丁中CreateProcessInteralW(inline)、LoadLibraryW(inline)、CoLoadLibrary(inline&IAT)、ShellExecuteExW(inline)和SetWindowsPos(IAT)以及7个其它的。 然后在sub_10001CE0(ThreadFunc_RemoveAD)中,有个查表然后进行补丁的操作: v5 = 12 * v2; // v2=8 WriteLog(L"[RemoveAD] Replace ID=%d On %d Positions,index=%d", nParamId, dword_10011600[3 * v2], v2); for ( i = 0; i < *(int *)((char *)dword_10011600 + v5); ++i )// 相对于我的版本循环7次 HookSomeDllReferenceArgs((**(wchar_t *(**)[90])((char *)&off_100115FC + v5))[i]); IsSetUserConfigINIScanOK(); WriteLog(L"[RemoveAD] End"); 如果,对DLL中修改下: .text:10001D42 mov ecx, off_100115FC[esi] .text:10001D48 mov edx, [ecx+edi*4] .text:10001D4B push edx ( NOP填充 ) .text:10001D4C call HookSomeDllReferenceArgs ( NOP填充 ) .text:10001D51 mov eax, dword_10011600[esi] .text:10001D57 add esp, 4 ( NOP填充 ) .text:10001D5A inc edi .text:10001D5B cmp edi, eax .text:10001D5D jl short loc_10001D42 则QQ加载之后正好是40个补丁,说明之前的情况是35(正常情况)+5(扣扣阻止模块加载)+7(扣扣实现RemoveAD补丁功能) 然后就是扣扣做的这个RemoveAD功能了,这7个补丁分别在:ChatFrame、MsgMgr、AppMisc、ConfigCenter(ZenZero同学好像也是)上面。其中AppMisc.dll有个地方引起了注意: 01300A20 PUSH EBP 01300A21 MOV EBP,ESP 01300A23 CMP DWORD PTR SS:[EBP+8],64 01300A27 JNZ SHORT AppMisc.01300A2F 01300A29 CALL DWORD PTR DS:[<&AppUtil.?PluginSecu>; AppUtil.?PluginSecurityCheck@Misc@Util@@YAHXZ 01300A2F XOR EAX,EAX 01300A31 POP EBP 01300A32 RETN 4 不过360扣扣却把它变成了这个样子: 01300A20 55 PUSH EBP 01300A21 8BEC MOV EBP,ESP 01300A23 837D 08 64 CMP DWORD PTR SS:[EBP+8],64 01300A27 90 NOP 01300A28 90 NOP 01300A29 90 NOP 01300A2A 90 NOP 01300A2B 90 NOP 01300A2C 90 NOP 01300A2D 90 NOP 01300A2E 90 NOP 01300A2F 33C0 XOR EAX,EAX 01300A31 5D POP EBP 01300A32 C2 0400 RETN 4 这个做法,貌似有点暴力啊。但是从函数的名称上以及操作上,和安全(PluginSecurityCheck)似乎有点关,最让人无语的是好像你不做什么操作它也会这么做,所以才感觉暴力在此了。 之前一直以为,阻止扫描的关键是RemoveAD(或许是有点关系,搞不好是360注入用于反调试或者反侦察的)。不过后来,用OD单独看了次QQ加载模块才发现,QQ的安全扫描和模块TSEH.dat和TSEngine.dat等有关,也就是启动时候会加载的两个模块,还有就是提示安全检测的时候还会启动TSELoad.dat和TSEPB.dat。而LoadLibraryW的函数钩子正好悲剧了这个东西: int __stdcall inline_LoadLibraryW(const WCHAR *pszPath) { const wchar_t *v1; // esi@1 int result; // eax@3 WriteLog(L"[Mine_LoadLibraryW] Load %s", pszPath); v1 = PathFindFileNameW(pszPath); if ( IsQzone(v1) ) { WriteLog(L"[Mine_LoadLibraryW] Critical"); return g_Ori_LoadLibraryW(pszPath); } if ( !IsConfigFileSetScanOK() || _wcsicmp(v1, L"tseh.dat") && _wcsicmp(v1, L"tsengine.dat") && _wcsicmp(v1, L"tsvulengine.dat") && _wcsicmp(v1, L"tsvulmdw.dat") ) { if ( GetUserConfigFileSet(v1) ) { if ( !FindInBlackList(v1) ) return g_Ori_LoadLibraryW(pszPath); WriteLog(L"[Mine_LoadLibraryW]Block by processList %s", v1); result = 0; } else { WriteLog(L"[Mine_LoadLibraryW] Block %s", pszPath); result = 0; } } else { result = 0; } return result; } 这么说其实还没有搞清楚QQ安全检测到底干了些什么(主要还得看看那几个dat的模块到底干了什么),不过至少“扣扣”的操作基本拦截操作算是了解了,哎~~~漫长啊! PS:项目要交了,今天晚上还得搞点用于准备的“魔术”,真是的... 另外传说360和QQ要搞得鱼死网破啦?两者只能存在一个?寒了~~~~~最近两天为了看这个没有装360,真吓人啊,几天时间就...这样了?下次装回360看看QQ吧。难道360想这么快取代QQ,那也太夸张了吧?不过360内核主动防御和逆向的人才都很多,腾讯想干过他们可能真得下点这方面的功夫了。 不过再次证明了一个经典的理论啊:这个世界上本来是安全的,自从有了“信息安全”,就再也不安全了。
订阅后,新回复会通过你的通知中心匿名送达。
0 条回复
暂无回复 · 你可以订阅本帖等待新回复。