因为自己的QQ号码有好几个,每次重启机子的时候一个一个的登录超级麻烦,而且腾讯老是在偶尔的时候,再把以前已经记住密码的QQ密码给置空,还要重新输入,太麻烦,因此尝试着自己搞一个批量自动登录的程序
以TM2009为例,查看了一下,未登录之前一个窗体,上边两个控件,登录以后,窗体捕获到一个控件,根据这个,首先找到QQ的登录框,输入用户名,密码的位置,获取窗体句柄的具体代码如下:
这里先定义了一个record类型,
1
TQQWnd
=
record
2
QQWnd,QStatusWnd: HWND;
//
QQ的窗口句柄,QQ的弹出登录状态句柄
3
QQNumWnd, QQPassWnd: HWND;
//
QQ号码输入句柄,QQ密码输入句柄
4
end
;
5
1
function
GetQQLoginHwd(
var
AQQWnd: TQQWnd): Boolean;
2
var
3
WinTitle:
array
[
0
..
254
]
of
Char;
4
WinClass:
array
[
0
..
254
]
of
Char;
5
begin
6
Result:
=
False;
7
AQQWnd.QQWnd:
=
0
;
8
AQQWnd.QQNumWnd:
=
0
;
9
AQQWnd.QQPassWnd:
=
0
;
10
AQQWnd.QQWnd:
=
FindWindow(
nil
,
'
TM2009
'
);
11
while
AQQWnd.QQWnd
<>
0
do
begin
12
AQQWnd.QQNumWnd:
=
FindWindowEx(AQQWnd.QQWnd,
0
,
'
ATL:30A4D1D8
'
,
nil
);
13
AQQWnd.QQPassWnd:
=
FindWindowEx(AQQWnd.QQWnd,
0
,
'
Edit
'
,
nil
);
14
if
(AQQWnd.QQNumWnd
<>
0
)
and
(AQQWnd.QQPassWnd
<>
0
)
then
begin
15
Result:
=
True;
16
FOpened:
=
True;
17
Exit;
18
end
else
begin
19
AQQWnd.QQWnd:
=
GetWindow(AQQWnd.QQWnd, GW_HWNDNEXT);
20
if
AQQWnd.QQWnd
=
0
then
Continue;
21
GetWindowText(AQQWnd.QQWnd, @WinTitle, SizeOf(WinTitle));
22
if
WinTitle
<>
'
TM2009
'
then
Continue;
23
end
;
24
end
;
25
end
;
26
因为腾讯的密码输入框,采用的是低级钩子,然后定时的释放,建立钩子这种方式来防止木马程序去捕获,我尝试了下,直接的用Sendmessage去发送密码信息,没反应,因此这里我采用了SendInput的方式去输入密码,而用户框因为没有做任何的保护措施,所以可以直接的通过发送消息,将QQ账户信息给赋值过去,具体代码为
1
SetForegroundWindow(QQWnds.QQWnd);
//
QQ窗体设置为活动窗体
2
//
设置QQ号码
3
SendMessage(QQWnds.QQNumWnd,WM_SETFOCUS,
0
,
0
);
//
聚焦至QQ号码输入框
4
Sleep(
20
);
5
SendMessage(QQWnds.QQNumWnd,WM_SETTEXT,
0
,LPARAM(FQQNum));
//
设置QQ号码
6
7
SendMessage(QQWnds.QQPassWnd,WM_SETFOCUS,
0
,
0
);
//
聚焦密码输入框
8
Sleep(
20
);
9
//
设置QQ密码
10
SIKeyInput(FQQPass,
10
);
//
QQ密码采取SENDINPUT方式
11
12
13
解下来要操作的,就是设置登录方式了,譬如说“我在线上”,“隐身”等状态,由于腾讯的登录窗体是采用的GUI,所以是捕获不到句柄的,只能通过坐标来捕获,我之前的时候,是用的固定坐标,然后有的电脑可以用,有的不能用,后来才发现,是由于腾讯的界面可以拉动,只要一拉动,他的坐标位置就变了,因此我这里采取相对坐标,根据QQ密码框的坐标,来设置点击的坐标。腾讯的状态是在窗体上点击以后,弹出一个跟登录框平级的窗口,因此点击以后,需要检测是否弹出选择状态窗口,找到那个窗口句柄以后,再发送相应的点击命令,这样就完成整个的流程了
1
const
2
QQStatusYArray:
array
[
0
..
5
]
of
Integer
=
(
19
,
38
,
62
,
86
,
105
,
131
);
3
4
5
ClickTimes:
=
0
;
//
为防止有的时候点击过程中出现其他不可预料的错误,这里可以重复点击三次
6
QQWnds.QStatusWnd:
=
0
;
//
设置QQ状态初始句柄为0
7
//
鼠标点击
8
while
ClickTimes
<
3
do
begin
9
PostMessage(QQWnds.QQWnd,$
201
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQNumRec.Bottom
-
QQRect.Top
+
21
,
4
)
+
IntToHex(QQNumRec.Left
-
QQRect.Left
+
25
,
4
)));
//
发送点击消息,这里如果采用SendMessage,会死线程,因此我采用了PostMessage
10
PostMessage(QQWnds.QQWnd,$
202
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQNumRec.Bottom
-
QQRect.Top
+
21
,
4
)
+
IntToHex(QQNumRec.Left
-
QQRect.Left
+
25
,
4
)));
11
Sleep(
200
);
12
QQWnds.QStatusWnd:
=
FindWindow(
'
TXGuiFoundation
'
,
'
TXMenuWindow
'
);
//
检测是否存在QQ设置状态窗体
13
if
QQWnds.QStatusWnd
<>
0
then
begin
14
try
15
PostMessage(QQWnds.QStatusWnd,$
201
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQStatusYArray[FQQStatus],
4
)
+
IntToHex(
27
,
4
)));
//
如果存在窗体,直接的发送点击信息
16
PostMessage(QQWnds.QStatusWnd,$
202
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQStatusYArray[FQQStatus],
4
)
+
IntToHex(
27
,
4
)));
17
except
18
end
;
19
Break;
20
end
;
21
ClickTimes:
=
ClickTimes
+
1
;
22
end
;
23
if
QQWnds.QStatusWnd
=
0
then
begin
//
如果一直没有捕获到设置状态窗体,程序则自动退出
24
Task.Comm.Send(MSG_QQ_ERR, IntToStr(QQRect.Left)
+
'
:
'
+
IntToStr(QQRect.Top)
+
'
:
'
+
IntToStr(QQRect.Right)
+
'
:
'
+
IntToStr(QQRect.Bottom)
25
+
'
,
'
+
IntToStr(QQNumRec.Left)
+
'
:
'
+
IntToStr(QQNumRec.Top)
+
'
:
'
+
IntToStr(QQNumRec.Right)
+
'
:
'
+
IntToStr(QQNumRec.Bottom)
26
+
IntToStr(QQNumRec.Bottom
-
QQRect.Top
+
21
)
+
'
设置状态失败
'
);
27
//
Task.Comm.Send(MSG_QQ_ERR, IntToStr(QQNumRec.Left
-
QQRect.Left
+
25
)
+
'
:
'
+
IntToStr(QQNumRec.Bottom
-
QQRect.Top
+
21
)
+
'
设置状态失败
'
);
28
Exit;
29
end
;
30
最后,直接的点击登录按钮就可以了,这个地方,也是要计算相对于密码输入框的坐标
1
//
点击登录按钮
2
try
3
PostMessage(QQWnds.QQWnd,$
201
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQNumRec.Bottom
-
QQRect.Top
+
114
,
4
)
+
IntToHex(QQNumRec.Left
-
QQRect.Left
+
64
,
4
)));
4
PostMessage(QQWnds.QQWnd,$
202
,MK_LBUTTON,StrToInt(#
36
+
IntToHex(QQNumRec.Bottom
-
QQRect.Top
+
114
,
4
)
+
IntToHex(QQNumRec.Left
-
QQRect.Left
+
64
,
4
)));
5
except
6
end
;
7
至此,整个的流程完毕了,最后,还可以增加上检测该QQ号码是否已经登录
以下是最后出来的界面,我直接的将QQ信息保存在数据库当中,密码采用了AES加密,所以也不用担心密码信息被泄
可以点击这里下载QQ批量下载
本文出自 “痛苦的转变” 博客,转载请与作者联系!