首页 > 资料收集 > 腾讯QQ空间g_tk算法[附C#实现代码]

腾讯QQ空间g_tk算法[附C#实现代码]

今天张筱祥写一个QQ空间相关工具的时候,有个参数是g_tk,找了半天也没发现是在哪里生成的,百度了一下找到一个朋友写的解密技巧,转载到张筱祥博客记录下。

原文地址:http://www.codeages.com/forum.php?mod=viewthread&tid=43004&extra=page%3D1

原文详细内容:

在百度搜索g_tk,只得到几个可怜而且不完整的答案,易语言的也有人写了个模块,却一直不愿意公开算法,不知道出于什么目的,不过我顺便鄙视一下那些不愿意分享代码而且还把这些鸡肋的知识当宝的人。那我首次在源始时代公开一下QQ空间的g_tk算法。其实g_tk只是QQ空间对日志进行操作的时候,所采取的一套安全机制,如果g_tk字符串的值不对的话,请求是没有办法提交的,因此,很多刚刚涉及HTTP协议技术的人想对QQ空间这尊大佛动手脚的话,只能望而却步。下面我以VB为例,在这里详解一下g_tk的计算方法。
    其实g_tk校验是通过skey值来算出来的,弄过QQ登录的人可能都知道,在登录成功之后,cookies里都会返回skey值,通常是以@开头,并且带有一串看似无规则的大小写字母混合,总共10位。下面我们先来抓包看看,g_tk到底用在了哪里,我们以转载日志为例来抓包,上图:
zz.jpg

完整数据包内容如下:

  1. POST /cgi-bin/blognew/blog_quote HTTP/1.1
  2. Accept: */*
  3. Accept-Language: zh-cn
  4. Referer: http://b.qzone.qq.com/proxy.html
  5. If-Modified-Since: 0
  6. Content-Type: application/x-www-form-urlencoded
  7. Accept-Encoding: gzip, deflate
  8. User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Tablet PC 2.0)
  9. Host: b.qzone.qq.com
  10. Content-Length: 65
  11. Connection: Keep-Alive
  12. Cache-Control: no-cache
  13. Cookie: pt2gguin=o0138001655; ptcz=0b25a27219dd08bcfe38fc85365593dadb1a2a99cac9f1abfd5fb31a7052f89b; pvid=6724688319; flv=10.0; adid=138001655; adSP=GHTsOtSHTIJdDIr9+GXVoaFY59pet/LONpbU1rA0yPY=_837_326830_1290874683_; adVer=3121; ac=1,030,006; ptui_qstatus=2; uin=o0138001655; skey=@sZmfEEBdt; ptisp=ctc; ssid=s8226120880; login_time=B46BD5B3A93F9EC5226847DB4AE9A71589641475FCCEBBC9; __Q_w_s__appDataSeed=1; randomSeed=220115
  14. uin=138001655&fromuin=715746717&blogid=1286714133&g_tk=1423927145

 

    我们可以看到,数据包主体部分最后一个参数就是g_tk值,一般是一串数字。那这个值到底怎么算出来的呢?
    因为我们在网页登录QQ的时候,腾讯都会通过cookies里的skey值来计算,用js来算。既然在运算的时候执行了js脚本,那么我们就可以在抓包中获得。那g_tk是通过什么算法算出来的?其实很简单,当我们得到skey后,循环取单字符的二进制并取左值.累加之后就得到后面的g_tk值了,这听上去很复杂,不过算法不用我们自己写,我们只需要执行在腾讯网页登录的时候所执行的那个js脚本就可以了。当然,js不能直接调用,不过既然我写了这篇文章,就已经是有备而来的,js算法我已经整理并写了一个最简单的,代码如下:

  1. function getGTK(str){
  2.     var hash = 5381;
  3.     for(var i = 0, len = str.length; i < len; ++i){
  4.         hash += (hash << 5) + str.charAt(i).charCodeAt();
  5.     }
  6.     return hash & 0x7fffffff;
  7. }

复制代码

    那么我们现在还有两个问题没有解决:
    1.如何获取登录后的cookies?
    2.如何在VB中执行js代码并得到返回值?
    上面两个问题其实到了你们手里,我相信也不会是问题了,下面我再通过代码以及讲解,来剖析并解决这两个所谓的问题。对于HTTP数据包POST/GET,相信看这篇文章的人应该都懂得吧,否则你看了也没用,那么我们可以设计一个登录程序,并在登录之后获取cookies中的skey值,并计算出g_tk。下面设计个登录界面:
界面

  界面

主界面代码如下:(frmLogin.frm)

  1. ‘———————————————————————————————-
  2. ‘ – 腾讯QQ空间g_tk算法
  3. ‘ – 作者:泡面 (QQ138001655  email:admin@mafom.com)
  4. ‘ – 日期:2010/11/28
  5. ‘———————————————————————————————-
  6. ‘ – 本源码来自源始时代(http://www.codeages.com),转载时请保留此信息!
  7. ‘ – 本程序仅供学习、交流用,下载后请于24小时内删除,使用所带来的后果概不负责!
  8. ‘———————————————————————————————-
  9. Option Explicit
  10. ‘wininet提供的API函数,用于获取cookies
  11. Private Declare Function InternetGetCookie Lib "wininet.dll" Alias "InternetGetCookieA" (ByVal lpszUrlName As String, ByVal lpszCookieName As String, ByVal lpszCookieData As String, lpdwSize As Long) As Boolean
  12. Private Sub cmdCancel_Click()
  13.   End
  14. End Sub
  15. Private Sub cmdLogin_Click()
  16.   On Error GoTo hErr
  17.   If Len(txtQQNumber.Text) = 0 Then
  18.     MsgBox "请输入QQ号码!", vbInformation, "提示"
  19.     txtQQNumber.SetFocus
  20.     Exit Sub
  21.   End If
  22.   If Len(txtPassword.Text) = 0 Then
  23.     MsgBox "请输入QQ密码!", vbInformation, "提示"
  24.     txtPassword.SetFocus
  25.     Exit Sub
  26.   End If
  27.   If Len(txtVlCode.Text) = 0 Then
  28.     MsgBox "请输入验证码!", vbInformation, "提示"
  29.     txtVlCode.SetFocus
  30.     Exit Sub
  31.   End If
  32.   cmdLogin.Enabled = False
  33.   ScriptControl1.Language = "Jscript"
  34.   ScriptControl1.Timeout = -1
  35.   ScriptControl1.AddCode txtVarHexcase.Text
  36.   Dim QQPass    As String
  37.   Dim retString As String
  38.   ‘对QQ密码进行加密,否则服务器不会通过
  39.   QQPass = ScriptControl1.Run("md5", ScriptControl1.Run("md5_3", txtPassword.Text) + UCase(txtVlCode.Text))
  40.   ‘发送登录请求
  41.   Inet1.Execute "http://ptlogin2.qq.com/login", "POST", "u=" & txtQQNumber.Text & "&p=" & QQPass & "&verifycode=" & txtVlCode.Text & "&aid=15000101&u1=http%3A%2F%2Fimgcache.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&fp=loginerroralert&h=1&ptredirect=1&ptlang=0&from_ui=1&dumy=", "CONTENT-TYPE : application/x-www-form-urlencoded"
  42.   Do While Inet1.StillExecuting
  43.     DoEvents
  44.   Loop
  45.   ‘取得返回数据
  46.   Dim BinBuff() As Byte
  47.   BinBuff() = Inet1.GetChunk(0, icByteArray)
  48.   retString = UTF8_Decode(BinBuff())
  49.   ‘判断登录状态
  50.   If InStr(retString, "QQ社区登录") Then
  51.     MsgBox "登录成功!", vbInformation, "提示"
  52.     Dim nLen  As Long
  53.     Dim sBuff As String * 1024
  54.     nLen = 1024
  55.     ‘获取cookies
  56.     InternetGetCookie "http://ptlogin2.qq.com/login", vbNullString, sBuff, nLen
  57.     ‘获取skey值
  58.     Dim skey As String
  59.     Dim sPos As Long
  60.     sPos = InStr(sBuff, "skey=@")
  61.     If sPos <> 0 Then
  62.       skey = Mid(sBuff, sPos + 5, 10)
  63.       MsgBox "从cookies获取到的skey值:" & skey
  64.     End If
  65.     ‘执行js脚本,计算g_tk值
  66.     Dim js(6) As String
  67.     Dim g_tk  As String
  68.     js(0) = "function getGTK(str){" & vbCrLf
  69.     js(1) = "var hash = 5381;" & vbCrLf
  70.     js(2) = "for(var i = 0, len = str.length; i < len; ++i){" & vbCrLf
  71.     js(3) = "    hash += (hash << 5) + str.charAt(i).charCodeAt();" & vbCrLf
  72.     js(4) = "}" & vbCrLf
  73.     js(5) = " return hash & 0x7fffffff;" & vbCrLf
  74.     js(6) = "}"
  75.     ScriptControl1.AddCode js(0) & js(1) & js(2) & js(3) & js(4) & js(5) & js(6)
  76.     g_tk = ScriptControl1.Run("getGTK", skey)
  77.     MsgBox "计算出的g_tk值:" & g_tk
  78.   Else
  79.     If InStr(retString, "您输入的验证码有误,请重试。") <> 0 Then
  80.       MsgBox "您输入的验证码有误,请重试!", vbExclamation, "提示"
  81.     ElseIf InStr(retString, "您输入的密码有误,请重试。") <> 0 Then
  82.       MsgBox "您输入的密码有误,请重试!", vbExclamation, "提示"
  83.     ElseIf InStr(retString, "您的QQ号码存在安全隐患") <> 0 Then
  84.       MsgBox "您的QQ号码存在安全隐患!", vbExclamation, "提示"
  85.     Else
  86.       MsgBox "登录失败,请检查您的密码是否正确!", vbExclamation, "提示"
  87.     End If
  88.   End If
  89.   cmdLogin.Enabled = True
  90.   Exit Sub
  91. hErr:
  92.   MsgBox "错误:" & Err.Number & vbCrLf & vbCrLf & Err.Description, vbExclamation, "错误"
  93.   Exit Sub
  94. End Sub
  95. ‘获取验证码
  96. Sub GetCode()
  97.   On Error Resume Next
  98.   Dim Buff() As Byte
  99.   ‘腾讯最新登录接口,验证码已经升级为5位,请求验证码的时候必须要加上QQ号码
  100.   Inet1.URL = "http://captcha.qq.com/getimage?aid=46000101&r=0.03652396363445809&uin=" & txtQQNumber.Text & "&vc_type=063620256136860e997ba2ca06c3c10a43c1f346db8e9d98"
  101.   Buff() = Inet1.OpenURL(, icByteArray)
  102.   With picVlCode
  103.     .Picture = PictureFromBits(Buff())          ‘直接得到Picture对象
  104.     .PaintPicture .Picture, 0, 0, .Width, .Height, 0, 0, .ScaleWidth, .ScaleHeight
  105.   End With
  106. End Sub
  107. Private Sub Form_Load()
  108.   Me.Show
  109.   GetCode
  110.   txtQQNumber.SetFocus
  111. End Sub

 

模块代码:(mdlALG)

  1. ‘———————————————————————————————-
  2. ‘ – 腾讯QQ空间g_tk算法
  3. ‘ – 作者:泡面 (QQ138001655  email:admin@mafom.com)
  4. ‘ – 日期:2010/11/28
  5. ‘———————————————————————————————-
  6. ‘ – 本源码来自源始时代(http://www.codeages.com),转载时请保留此信息!
  7. ‘ – 本程序仅供学习、交流用,下载后请于24小时内删除,使用所带来的后果概不负责!
  8. ‘———————————————————————————————-
  9. ‘二进制转UTF8
  10. Declare Function MultiByteToWideChar _
  11.         Lib "kernel32" (ByVal CodePage As Long, _
  12.                         ByVal dwFlags As Long, _
  13.                         ByVal lpMultiByteStr As Long, _
  14.                         ByVal cchMultiByte As Long, _
  15.                         ByVal lpWideCharStr As Long, _
  16.                         ByVal cchWideChar As Long) As Long
  17. Public Enum CBoolean
  18.   CFalse = 0
  19.   CTrue = 1
  20. End Enum
  21. Private Const S_OK = 0
  22. Private Declare Function CreateStreamOnHGlobal _
  23.                 Lib "ole32" (ByVal hGlobal As Long, _
  24.                              ByVal fDeleteOnRelease As CBoolean, _
  25.                              ppstm As Any) As Long
  26. Private Declare Function OleLoadPicture _
  27.                 Lib "olepro32" (pStream As Any, _
  28.                                 ByVal lSize As Long, _
  29.                                 ByVal fRunmode As CBoolean, _
  30.                                 riid As GUID, _
  31.                                 ppvObj As Any) As Long
  32. Public Type GUID
  33.   dwData1 As Long
  34.   wData2 As Integer
  35.   wData3 As Integer
  36.   abData4(7) As Byte
  37. End Type
  38. Private Declare Function CLSIDFromString _
  39.                 Lib "ole32" (ByVal lpsz As Any, _
  40.                              pclsid As GUID) As Long
  41. Private Const sIID_IPicture = "{7BF80980-BF32-101A-8BBB-00AA00300CAB}"
  42. Private Const GMEM_MOVEABLE = &H2
  43. Private Declare Function GlobalAlloc _
  44.                 Lib "kernel32" (ByVal uFlags As Long, _
  45.                                 ByVal dwBytes As Long) As Long
  46. Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  47. Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  48. Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
  49. Private Declare Sub MoveMemory _
  50.                 Lib "kernel32" _
  51.                 Alias "RtlMoveMemory" (pDest As Any, _
  52.                                        pSource As Any, _
  53.                                        ByVal dwLength As Long)
  54. Public Function PictureFromBits(abPic() As Byte) As IPicture
  55.   Dim nLow         As Long
  56.   Dim cbMem        As Long
  57.   Dim hMem         As Long
  58.   Dim lpMem        As Long
  59.   Dim IID_IPicture As GUID
  60.   Dim istm         As stdole.IUnknown
  61.   Dim ipic         As IPicture
  62.   On Error GoTo Out
  63.   nLow = LBound(abPic)
  64.   On Error GoTo 0
  65.   cbMem = (UBound(abPic) – nLow) + 1
  66.   hMem = GlobalAlloc(GMEM_MOVEABLE, cbMem) ‘分配可移动的内存
  67.   If hMem Then
  68.     lpMem = GlobalLock(hMem)
  69.     If lpMem Then
  70.       MoveMemory ByVal lpMem, abPic(nLow), cbMem
  71.       Call GlobalUnlock(hMem)
  72.       If (CreateStreamOnHGlobal(hMem, CTrue, istm) = S_OK) Then
  73.         If (CLSIDFromString(StrPtr(sIID_IPicture), IID_IPicture) = S_OK) Then
  74.           Call OleLoadPicture(ByVal ObjPtr(istm), cbMem, CFalse, IID_IPicture, PictureFromBits)
  75.         End If
  76.       End If
  77.     End If
  78.   End If
  79. Out:
  80. End Function
  81. Public Function UTF8_Decode(bUTF8() As Byte) As String  ‘二进制解析为UTF8
  82.   Dim lRet        As Long
  83.   Dim lLen        As Long
  84.   Dim lBufferSize As Long
  85.   Dim sBuffer     As String
  86.   Dim bBuffer()   As Byte
  87.   lLen = UBound(bUTF8) + 1
  88.   If lLen = 0 Then Exit Function
  89.   lBufferSize = lLen * 2
  90.   sBuffer = String$(lBufferSize, Chr(0))
  91.   lRet = MultiByteToWideChar(65001, 0, VarPtr(bUTF8(0)), lLen, StrPtr(sBuffer), lBufferSize)
  92.   If lRet <> 0 Then
  93.     sBuffer = Mid(sBuffer, 1, lRet)
  94.   End If
  95.   UTF8_Decode = sBuffer
  96. End Function

以上代码是原作者用vb写的,因为张筱祥用的是C#,所以基本是学习其思路,看完上文可以说g_tk 的算法就很简单了,就是从登陆后的cookie中得到skey 然后执行一段js,加密得到g_tk的值。下面简单说下在C#中的实现过程。

1.  首先 引用COM组件  mscrosoft script control 1.0

2.  直接上张筱祥写好的方法。

string Getgtk(string skey)
{
     MSScriptControl.ScriptControlClass sc = new MSScriptControl.ScriptControlClass();
     sc.Language = "javascript";
     string[] js = new string[7];
     js[0] = "function getGTK(str){\r\n";
     js[1] = "var hash = 5381;\r\n";
     js[2] = "for(var i = 0, len = str.length; i < len; ++i){ \r\n";
     js[3] = "    hash += (hash << 5) + str.charAt(i).charCodeAt();\r\n";
     js[4] = "}\r\n";
     js[5] = " return hash & 0x7fffffff;\r\n";
     js[6] = "}\r\n";
     sc.AddCode(js[0] + js[1] + js[2] + js[3] + js[4] + js[5] + js[6]);
     object[] parm = new object[] { skey };
     string g_tk = sc.Run("getGTK", ref parm).ToString();
     return  g_tk;
}

以上计算g_tk 的方法在2011年2月25号测试有效。

Popularity: 18% [?]

你可能对下面的内容也感兴趣

    分类: 资料收集 标签: 阅读:1,420
    1. 本文目前尚无任何评论.
    1. 本文目前尚无任何 trackbacks 和 pingbacks.

    3718150474633154929112424204136344840324513627301092612313516391742725322194423144338215828