本文主要是介绍QQ机器人(转贴),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这个元旦假期过的比较奇怪,为了向远方的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 }
东西到手了,传话筒的工作基本上算是完成了,接下来就让它显示出来:
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 }
这里的txtGroupWinName1是让输入qq窗口标题。以前用asm32做程序的时候就觉的微软够BT的,要是每个窗口编译的时候就给限制个GUID多好—()—*)((— 至此大功算是告成了,完美交差。拿着这东东,改天狠狠的宰我师兄几顿. (07-01-04)续: 要的人太多了,我还是主动把东西传上来吧,要不然有骗 email地址之嫌 源代码和相关资料下载:/Files/sukyboor/Q.rar
附,说明: 先介绍一下http方法: 1,qq接口.txt 是我在网络上找的一篇“C#编写QQ接口软件--QQ协议篇” 里面有QQhttp协议访问的详细的介绍,协议标准是v1.1。但是经过我是没调通,好象是 http://tqq.tencent.com:8000 被封了,你有没有好的运气我就不知道了。tx的webqq用的端口是 http://webqq-proxy.qq.com:8080/ 这个就是慢点,用还是能用的。 2,Maxthon_Appin 文件夹下面有2个文件QQTest.txt ,GetQQSession.txt。maxthon有个简易收集面板你可以动态的去调试脚本.用maxthon打开 http://webqq.qq.com 后装入qqtest.txt你会发现访问过程的一举一动都在你的监视之中。Log.txt就是这么来的。GetQQSession.txt操作同上,用于获取一个新的sessionid 3,log.txt是监视 http://webqq.qq.com 的访问过程后得来的.你可以参考qq接口.txt看。不过tx的webqq用的是v1.0的接口,但大体上是相似的,相信聪明的你是可以看懂的。 4,webqq文件夹下放着 http://webqq.qq.com 被我下到本地的页面。有兴趣的可以去看看里面的脚本,尤其是js/web_cmd.js虽然写的比我还烂,但还是值得一看。 5,WQQ文件夹下放着我写的测试页面。不过我家的破电脑调不通。如果你运气好的话,在这个基础上继续干吧。不过别忘记了,到时候把做好的东西发给我一份(sukyboor·163.com)。 好了,下面说说钩子方法 项目在TQQ文件夹下面,注释写的挺详细的,自己看吧。 就提醒4点, 1 是app.config里面的qqnum一定要配置成你的qq号,否则你就等着别人骂你sx吧。 2 主窗口上的几个输入框一定要配置成群聊窗口的标题,否则它啥也干不了 3 别告诉我你还用qq2005 4 消息被转发以后在窗口里是看不到的,得点聊天记录按纽以后才能看的见 license.txt 里面堆的是一堆套话,有空就瞅2眼.
这篇关于QQ机器人(转贴)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!