这个元旦假期过的比较奇怪,为了向远方的GF表示忠诚。除了1号和同学吃了个大锅饭之外,尽量做到了大门不出二门不迈,躲在闺房守岁:)。
在家闲着也不能干闲着,总得做点事情,想起前段时间一个师兄交代给我的任务:把若干个qq群串在一起。X国的政策一向比较Bt,你说开个群还要限制人数。H大在深圳有几千校友,一个群怎么可能放的下那么多人。好多在tx工作的师兄,明确告诉:我买通tx的人是不大可能了,搞一个传话筒才是解决之道。
事情虽小,但也着实麻烦。你说要去分析QQ具体数据包,万一哪天tx一高兴把数据给改了,或者接口开放了,也够我郁闷一壶的了。那就找个最简单的办法吧,左一顿baidu,又一顿google. “QQ接口”搜出来的结果绝大多数是关于tx qq的http接口,既然大家那么推崇,那我就从Http接口下手,于是把我以前写的AJAX给拆了,在把所谓的qq接口研究成果给鼓捣在一起,然后去webqq( http://webqq.qq.com)上大抢一遍,那家伙,天昏地暗,相当的&(&(。
代码我是用script写的:
异步AJAX会话类
1
//异步AJAX会话类
2
if(typeof(AjaxSession) == 'undefined')
3
var AjaxSession = function()
{
4
5
//创建会话
6
this.CreateSession = function()
7
{
8
if (window.ActiveXObject)
{ // IE
9
try
{
10
return new ActiveXObject('Microsoft.XMLHTTP');
11
}catch(e)
{}
12
13
try
{
14
return new ActiveXObject('Msxml2.XMLHTTP');
15
}catch(ee)
{}
16
}else
{ //Mozilla, Safari
17
var s = new XMLHttpRequest();
18
if (s.readyState == null)
{
19
s.readyState = 1;
20
s.addEventListener("load", function ()
{
21
s.readyState = 4;
22
if (typeof(s.onreadystatechange) == "function")
23
s.onreadystatechange();
24
}, false);
25
}
26
27
return s;
28
}
29
30
return null;
31
}
32
33
//进行请求
34
this.Request = function(url, params, callback)
35
{
36
37
var s = this.CreateSession();
38
if(null == s)
39
alert("对不起,您的浏览器不支持某些特性。");
40
else
41
s.abort();
42
43
var isAsync = typeof(callback) == 'function';
44
var method = !params ? "GET" : "POST";
45
46
if(isAsync) s.onreadystatechange = function()
47
{
48
try
{
49
alert(s.status);
50
if ((4 == s.readyState) && (200 == s.status || 304 == s.status))
51
callback(this.Response(s));
52
else
53
alert("请求错误,错误原因:" + s.statusText);
54
}catch(e)
{}
55
}
56
57
s.open(method, url, isAsync);
58
s.setRequestHeader("Connection","Keep-Alive");
59
s.setRequestHeader("Content-Type","text/html; charset=gb2312");
60
//s.setRequestHeader("Content-Type","text/plain; charset=UTF-8");
61
62
if(method == "POST")
63
{
64
s.setRequestHeader("Content-Length",params.length)
65
s.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
66
67
}
68
69
alert(params);
70
s.send(params);
71
72
73
if(!isAsync)
74
return this.Response(s);
75
}
76
77
//返回应答信息
78
this.Response = function(s)
79
{
80
if(s.status == 200 || 304 == s.status)
81
{
82
if(s.responseXML != null && s.responseXML.xml != null && s.responseXML.xml != '')
83
return s.responseXML;
84
else
85
return s.responseText;
86
}
87
}
88
89
//对字符串进行编码
90
this.UncCoding = function(s)
91
{
92
var output = '';
93
for(var i = 0 ;i< s.length;i++)
{
94
output = output + '%' + s.charCodeAt(i);
95
}
96
97
return output;
98
}
99
100
//获取xml结构
101
this.GetDom = function(s)
{
102
var doc = new ActiveXObject('Microsoft.XMLDOM');
103
doc.async = false;
104
doc.loadXML(s) ;
105
return doc;
106
}
107
108
return this;
109
}
//QQ会话类
1
//会话类
2
if(typeof(QQSession) == 'undefined')
3
var QQSession = function()
{
4
this.UIN = 0;
5
this.Md5PasswordStr = "";
6
this.WebQQUrl = "http://tqq.tencent.com:8000/";
7
this.qs = null;
8
this.isLogin = false;
9
this.SeqIndex = null;
10
11
//用户登陆
12
this.Login = function(uin,passwd,vcode,qs)
{
13
var m5 = new MD5();
14
this.UIN = uin;
15
this.Md5PasswordStr = m5.calcMD5(passwd);
16
var CmdStr = "VER=1.0&CMD=1&SEQ=" + this.GetNewSEQ() + "&UIN=" + uin + "&PS=" + this.Md5PasswordStr + "&STATUS=10&VCODE=" + vcode + "&QQSESSION=" + qs ;
17
18
//if(!this.qs)
19
// this.qs = new AjaxSession();
20
window.frames["proxy"].request(this.WebQQUrl,CmdStr);
21
//this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
22
23
//document.getElementById("ssl_login").callback = this.ShowMsg;
24
//document.getElementById("ssl_login").src = "https://webqq-proxy.qq.com/webqq/l?"+ CmdStr;
25
}
26
27
//用户信息
28
this.GetInfo = function()
{
29
var CmdStr = "VER=1.0&CMD=10&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&FUIN=" + this.UIN;
30
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
31
//window.frames["proxy"].request(this.WebQQUrl,CmdStr);
32
}
33
34
//获取好友列表
35
this.GetList = function()
{
36
var CmdStr = "VER=1.0&CMD=2&SEQ=" + this.GetNewSEQ() + "&UIN=" + this.UIN + "&NPOS=0";
37
this.qs.Request(this.WebQQUrl,CmdStr,this.ShowMsg);
38
}
39
40
//获得新的SEQ
41
this.GetNewSEQ = function()
{
42
if(!this.SeqIndex)
{
43
var d = new Date();
44
this.SeqIndex = d.getTime()
45
}
46
47
this.SeqIndex ++;
48
return this.SeqIndex;
49
}
50
51
this.ShowMsg = function(s)
{
52
alert(s);
53
}
54
55
return this;
56
}
我在那用天真的眼神,盼望着能从这个地方掏出点东西来。可偏偏我这个比较倒霉的孩子,碰到了极其复杂的网络问题(家穷人丑,只好用手机上网,速度回到上世纪90年代),掏了半天啥也没弄到,返回的尽是12152错误。
去翻MSDN时,遇到几个头疼的单词(鄙人英语着实差劲,单词量屈指可数),很习惯的就去开金山词霸。等等,金山词霸能把别的窗口的信息给拽出来,为什么我就不能。于是我就抛弃了前面的工作,从QQ对话窗口下手。nndx,偶就不信了,偶还灭不了你。
说干就干,那就先勾吧,.net好象是干不了这事,但是winapi还是能干这活的。win32编程嘛,不就几个消息循环(—(—……*(—
WinApi调用
1
using System;
2
using System.Drawing;
3
using System.Runtime.InteropServices;
4
5
namespace TQQ
6

{
7
/**//// <summary>
8
/// WinApi调用
9
/// </summary>
10
public class WinApi
11
{
12
/**//// <summary>
13
/// 根据鼠标位置获取窗体
14
/// </summary>
15
/// <param name="lpPoint"></param>
16
/// <returns></returns>
17
[DllImport("user32.dll")]
18
public static extern IntPtr WindowFromPoint(Point lpPoint);
19
20
/**//// <summary>
21
/// 获取鼠标位置
22
/// </summary>
23
/// <param name="lpPoint"></param>
24
/// <returns></returns>
25
[DllImport("user32.dll")]
26
public static extern int GetCursorPos(out Point lpPoint);
27
28
/**//// <summary>
29
/// 获取鼠标位置下的窗体
30
/// </summary>
31
/// <returns></returns>
32
public static IntPtr GetLocalWindow()
33
{
34
Point point;
35
GetCursorPos(out point);
36
return WindowFromPoint(point);
37
}
38
39
/**//// <summary>
40
/// 申请内存空间
41
/// </summary>
42
/// <param name="hProcess"></param>
43
/// <param name="lpAddress"></param>
44
/// <param name="dwSize"></param>
45
/// <param name="flAllocationType"></param>
46
/// <param name="flProtect"></param>
47
/// <returns></returns>
48
[ DllImport( "Kernel32.dll" )]
49
public static extern Int32 VirtualAllocEx(IntPtr hProcess,Int32 lpAddress,Int32 dwSize,Int16 flAllocationType,Int16 flProtect);
50
51
/**//// <summary>
52
/// 读取内存空间
53
/// </summary>
54
/// <param name="hProcess"></param>
55
/// <param name="lpBaseAddress"></param>
56
/// <param name="lpBuffer"></param>
57
/// <param name="nSize"></param>
58
/// <param name="lpNumberOfBytesWritten"></param>
59
/// <returns></returns>
60
[ DllImport( "Kernel32.dll" )]
61
public static extern int ReadProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
62
63
/**//// <summary>
64
/// 写内存空间
65
/// </summary>
66
/// <param name="hProcess"></param>
67
/// <param name="lpBaseAddress"></param>
68
/// <param name="lpBuffer"></param>
69
/// <param name="nSize"></param>
70
/// <param name="lpNumberOfBytesWritten"></param>
71
/// <returns></returns>
72
[ DllImport( "Kernel32.dll" )]
73
public static extern int WriteProcessMemory(IntPtr hProcess, Int32 lpBaseAddress,byte[] lpBuffer,long nSize,long lpNumberOfBytesWritten);
74
75
/**//// <summary>
76
/// 根据类/标题查找窗口
77
/// </summary>
78
/// <param name="lpClassName"></param>
79
/// <param name="lpWindowName"></param>
80
/// <returns></returns>
81
[DllImport("User32.dll",EntryPoint="FindWindow")]
82
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
83
84
/**//// <summary>
85
/// 获取窗口子对象
86
/// </summary>
87
/// <param name="hwndParent"></param>
88
/// <param name="hwndChildAfter"></param>
89
/// <param name="lpszClass"></param>
90
/// <param name="lpszWindow"></param>
91
/// <returns></returns>
92
[DllImport("user32.dll",EntryPoint="FindWindowEx")]
93
public static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
94
95
/**//// <summary>
96
/// 发送windows消息
97
/// </summary>
98
/// <param name="hWnd"></param>
99
/// <param name="Msg"></param>
100
/// <param name="wParam"></param>
101
/// <param name="lParam"></param>
102
/// <returns></returns>
103
[DllImport("User32.dll")]
104
public static extern IntPtr SendMessage(IntPtr hWnd,int Msg,IntPtr wParam,IntPtr lParam);
105
106
/**//// <summary>
107
/// 发送windows消息
108
/// </summary>
109
/// <param name="hWnd"></param>
110
/// <param name="Msg"></param>
111
/// <param name="wParam"></param>
112
/// <param name="lParam"></param>
113
/// <returns></returns>
114
[DllImport("User32.dll",EntryPoint="SendMessage")]
115
public static extern int SendMessage(IntPtr hWnd,int Msg, IntPtr wParam, string lParam);
116
117
/**//// <summary>
118
/// 发送windows消息
119
/// </summary>
120
/// <param name="hwnd"></param>
121
/// <param name="wMsg"></param>
122
/// <param name="wParam"></param>
123
/// <param name="lParam"></param>
124
/// <returns></returns>
125
[DllImport("user32.dll", CharSet = CharSet.Auto)]
126
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,string lParam);
127
128
/**//// <summary>
129
/// 发送windows消息
130
/// </summary>
131
/// <param name="hwnd"></param>
132
/// <param name="wMsg"></param>
133
/// <param name="wParam"></param>
134
/// <param name="lParam"></param>
135
/// <returns></returns>
136
[DllImport("user32.dll", CharSet = CharSet.Auto)]
137
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,int lParam);
138
139
/**//// <summary>
140
/// 发送windows消息
141
/// </summary>
142
/// <param name="hwnd"></param>
143
/// <param name="wMsg"></param>
144
/// <param name="wParam"></param>
145
/// <param name="lParam"></param>
146
/// <returns></returns>
147
[DllImport("user32.dll", CharSet = CharSet.Auto)]
148
public static extern int SendMessage( IntPtr hwnd, int wMsg, int wParam,System.Text.StringBuilder lParam);
149
150
public const int WM_GETTEXT = 0x000D;
151
public const int WM_GETTEXTLENGTH = 0x000E;
152
public const int WM_SETTEXT = 0x000C;
153
public const int WM_CLICK = 0x00F5;
154
public const int WM_CHAR = 0x0102;
155
public const int EM_SETSEL = 0x00B1;
156
public const int EM_REPLACESEL = 0x00C2;
157
158
}
159
}
QQ钩子
1
/**//// <summary>
2
/// QQ钩子
3
/// </summary>
4
public class QQHooks
5
{
6
/**//// <summary>
7
/// 发送消息
8
/// </summary>
9
/// <param name="windowName">窗口标题</param>
10
/// <param name="strMsg">消息内容</param>
11
public static void SendMsg(string windowName,string strMsg)
12
{
13
string lpszParentClass = "#32770"; //整个窗口的类名
14
string lpszParentWindow = windowName; //窗口标题
15
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
16
IntPtr EdithParentWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
17
IntPtr EdithWnd = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),"AfxWnd42","");
18
19
string lpszClass_Text = "RICHEDIT"; //消息输入窗口
20
string lpszName_Text = ""; //消息输入窗口
21
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
22
23
StringBuilder sb = new StringBuilder(strMsg);
24
WinApi.SendMessage(THandle,WinApi.EM_SETSEL,-1,-1);//
25
WinApi.SendMessage(THandle,WinApi.EM_REPLACESEL,0,sb);
26
27
string lpszClass_Submit = "Button"; //需要查找的Button的类名
28
string lpszName_Submit = "发送(&S)"; //需要查找的Button的标题
29
IntPtr TButtonHandle = WinApi.FindWindowEx(EdithParentWnd,new IntPtr(0),lpszClass_Submit,lpszName_Submit);
30
WinApi.SendMessage(TButtonHandle,WinApi.WM_CLICK,new IntPtr(0),"");//发送消息到目标控件使它执行click事件
31
}
32
33
/**//// <summary>
34
/// 获取消息
35
/// </summary>
36
/// <param name="windowName">窗口标题</param>
37
/// <returns></returns>
38
public static string GetMsg(string windowName)
39
{
40
string lpszParentClass = "#32770"; //整个窗口的类名
41
string lpszParentWindow = windowName; //窗口标题
42
IntPtr ip = WinApi.FindWindow(lpszParentClass,lpszParentWindow);
43
IntPtr EdithWnd = WinApi.FindWindowEx(ip,new IntPtr(0),"#32770","");
44
45
string lpszClass_Text = "RichEdit20A"; //查找历史记录类
46
string lpszName_Text = ""; //查找历史记录类的标题
47
IntPtr THandle = WinApi.FindWindowEx(EdithWnd,new IntPtr(0),lpszClass_Text,lpszName_Text);
48
49
StringBuilder sb = new StringBuilder(300000);
50
WinApi.SendMessage(THandle,WinApi.WM_GETTEXT,255,sb);//发送消息到目标控件
51
WinApi.SendMessage(THandle,WinApi.WM_SETTEXT,0,"");
52
return sb.ToString();
53
}
54
}
东西到手了,传话筒的工作基本上算是完成了,接下来就让它显示出来:
在家闲着也不能干闲着,总得做点事情,想起前段时间一个师兄交代给我的任务:把若干个qq群串在一起。X国的政策一向比较Bt,你说开个群还要限制人数。H大在深圳有几千校友,一个群怎么可能放的下那么多人。好多在tx工作的师兄,明确告诉:我买通tx的人是不大可能了,搞一个传话筒才是解决之道。
事情虽小,但也着实麻烦。你说要去分析QQ具体数据包,万一哪天tx一高兴把数据给改了,或者接口开放了,也够我郁闷一壶的了。那就找个最简单的办法吧,左一顿baidu,又一顿google. “QQ接口”搜出来的结果绝大多数是关于tx qq的http接口,既然大家那么推崇,那我就从Http接口下手,于是把我以前写的AJAX给拆了,在把所谓的qq接口研究成果给鼓捣在一起,然后去webqq( http://webqq.qq.com)上大抢一遍,那家伙,天昏地暗,相当的&(&(。
代码我是用script写的:


1

2

3



4

5

6

7



8



9



10

11



12

13



14

15



16



17

18



19

20



21

22

23

24

25

26

27

28

29

30

31

32

33

34

35



36

37

38

39

40

41

42

43

44

45

46

47



48



49

50

51

52

53

54



55

56

57

58

59

60

61

62

63



64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79



80

81



82

83

84

85

86

87

88

89

90

91



92

93



94

95

96

97

98

99

100

101



102

103

104

105

106

107

108

109



1

2

3



4

5

6

7

8

9

10

11

12



13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28



29

30

31

32

33

34

35



36

37

38

39

40

41



42



43

44

45

46

47

48

49

50

51



52

53

54

55

56

我在那用天真的眼神,盼望着能从这个地方掏出点东西来。可偏偏我这个比较倒霉的孩子,碰到了极其复杂的网络问题(家穷人丑,只好用手机上网,速度回到上世纪90年代),掏了半天啥也没弄到,返回的尽是12152错误。
去翻MSDN时,遇到几个头疼的单词(鄙人英语着实差劲,单词量屈指可数),很习惯的就去开金山词霸。等等,金山词霸能把别的窗口的信息给拽出来,为什么我就不能。于是我就抛弃了前面的工作,从QQ对话窗口下手。nndx,偶就不信了,偶还灭不了你。
说干就干,那就先勾吧,.net好象是干不了这事,但是winapi还是能干这活的。win32编程嘛,不就几个消息循环(—(—……*(—


1

2

3

4

5

6



7


8

9

10

11



12


13

14

15

16

17

18

19

20


21

22

23

24

25

26

27

28


29

30

31

32

33



34

35

36

37

38

39


40

41

42

43

44

45

46

47

48

49

50

51


52

53

54

55

56

57

58

59

60

61

62

63


64

65

66

67

68

69

70

71

72

73

74

75


76

77

78

79

80

81

82

83

84


85

86

87

88

89

90

91

92

93

94

95


96

97

98

99

100

101

102

103

104

105

106


107

108

109

110

111

112

113

114

115

116

117


118

119

120

121

122

123

124

125

126

127

128


129

130

131

132

133

134

135

136

137

138

139


140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159



1


2

3

4

5



6


7

8

9

10

11

12



13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33


34

35

36

37

38

39



40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

东西到手了,传话筒的工作基本上算是完成了,接下来就让它显示出来:
1
/**/
/// <summary>
2
/// 时钟事件
3
/// </summary>
4
/// <param name="sender"></param>
5
/// <param name="e"></param>
6
private
void
tmGetMsg_Tick(
object
sender, System.EventArgs e)
7
{
8
//群1里的消息
9
string strMsg = QQHooks.GetMsg(txtGroupWinName1.Text);
10
string str = "";
11
12
if(!string.Empty.Equals(strMsg))
13
{
14
ArrayList msgList = ParseMsg.Parse(strMsg);
15
16
foreach(QQMsg msg in msgList)
17
{
18
if("253822559" == msg.Number.ToString())continue;
19
20
if(string.Empty.Equals(msg.Msg.Trim()))
21
str = string.Format("{0}在群1里做了个表情/r/n",msg.Name,msg.Msg);
22
else
23
str = string.Format("{0}在群1里说:/r/n{1}/r/n",msg.Name,msg.Msg);
24
25
lbGroupMsgList1.Items.Add(str);
26
//save msg
27
28
//发送消息
29
QQHooks.SendMsg(txtGroupWinName2.Text,str);
30
QQHooks.SendMsg(txtGroupWinName3.Text,str);
31
32
}
33
}
34
}


2

3

4

5

6

7



8

9

10

11

12

13



14

15

16

17



18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

这里的txtGroupWinName1是让输入qq窗口标题。以前用asm32做程序的时候就觉的微软够BT的,要是每个窗口编译的时候就给限制个GUID多好—()—*)((—
至此大功算是告成了,完美交差。拿着这东东,改天狠狠的宰我师兄几顿.
(07-01-04)续:
要的人太多了,我还是主动把东西传上来吧,要不然有骗 email地址之嫌
源代码和相关资料下载:/Files/sukyboor/Q.rar