开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 7998|回复: 29
收起左侧

腾讯获取G_tk的算法

[复制链接]
发表于 2011-3-5 00:32:39 | 显示全部楼层 |阅读模式   天津市天津市
g_tk只是QQ空间对日志进行操作的时候,所采取的一套安全机制,如果g_tk字符串的值不对的话,请求是没有办法提交的,因此,很多刚刚涉及HTTP协议技术的人想对QQ空间这尊大佛动手脚的话,只能望而却步。下面我以VB为例,在这里详解一下g_tk的计算方法。
    其实g_tk校验是通过skey值来算出来的,弄过QQ登录的人可能都知道,在登录成功之后,cookies里都会返回skey值,通常是以@开头,并且带有一串看似无规则的大小写字母混合,总共10位。下面我们先来抓包看看,g_tk到底用在了哪里,我们以转载日志为例来抓包,

TT截图未命名.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. '二进制转UTF8
  2. Declare Function MultiByteToWideChar _
  3. Lib "kernel32" (ByVal CodePage As Long, _
  4. ByVal dwFlags As Long, _
  5. ByVal lpMultiByteStr As Long, _
  6. ByVal cchMultiByte As Long, _
  7. ByVal lpWideCharStr As Long, _
  8. ByVal cchWideChar As Long) As Long

  9. Public Enum CBoolean
  10. CFalse = 0
  11. CTrue = 1
  12. End Enum

  13. Private Const S_OK = 0
  14. Private Declare Function CreateStreamOnHGlobal _
  15. Lib "ole32" (ByVal hGlobal As Long, _
  16. ByVal fDeleteOnRelease As CBoolean, _
  17. ppstm As Any) As Long
  18. Private Declare Function OleLoadPicture _
  19. Lib "olepro32" (pStream As Any, _
  20. ByVal lSize As Long, _
  21. ByVal fRunmode As CBoolean, _
  22. riid As GUID, _
  23. ppvObj As Any) As Long

  24. Public Type GUID
  25. dwData1 As Long
  26. wData2 As Integer
  27. wData3 As Integer
  28. abData4(7) As Byte
  29. End Type

  30. Private Declare Function CLSIDFromString _
  31. Lib "ole32" (ByVal lpsz As Any, _
  32. pclsid As GUID) As Long
  33. Private Const sIID_IPicture = "{7BF80980-BF32-101A-8BBB-00AA00300CAB}"
  34. Private Const GMEM_MOVEABLE = &H2
  35. Private Declare Function GlobalAlloc _
  36. Lib "kernel32" (ByVal uFlags As Long, _
  37. ByVal dwBytes As Long) As Long
  38. Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
  39. Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
  40. Private Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
  41. Private Declare Sub MoveMemory _
  42. Lib "kernel32" _
  43. Alias "RtlMoveMemory" (pDest As Any, _
  44. pSource As Any, _
  45. ByVal dwLength As Long)

  46. Public Function PictureFromBits(abPic() As Byte) As IPicture
  47. Dim nLow As Long
  48. Dim cbMem As Long
  49. Dim hMem As Long
  50. Dim lpMem As Long
  51. Dim IID_IPicture As GUID
  52. Dim istm As stdole.IUnknown
  53. Dim ipic As IPicture
  54. On Error GoTo Out
  55. nLow = LBound(abPic)
  56. On Error GoTo 0
  57. cbMem = (UBound(abPic) - nLow) + 1
  58. hMem = GlobalAlloc(GMEM_MOVEABLE, cbMem) '分配可移动的内存

  59. If hMem Then
  60. lpMem = GlobalLock(hMem)

  61. If lpMem Then
  62. MoveMemory ByVal lpMem, abPic(nLow), cbMem
  63. Call GlobalUnlock(hMem)

  64. If (CreateStreamOnHGlobal(hMem, CTrue, istm) = S_OK) Then
  65. If (CLSIDFromString(StrPtr(sIID_IPicture), IID_IPicture) = S_OK) Then
  66. Call OleLoadPicture(ByVal ObjPtr(istm), cbMem, CFalse, IID_IPicture, PictureFromBits)
  67. End If
  68. End If
  69. End If
  70. End If

  71. Out:
  72. End Function

  73. Public Function UTF8_Decode(bUTF8() As Byte) As String '二进制解析为UTF8
  74. Dim lRet As Long
  75. Dim lLen As Long
  76. Dim lBufferSize As Long
  77. Dim sBuffer As String
  78. Dim bBuffer() As Byte
  79. lLen = UBound(bUTF8) + 1

  80. If lLen = 0 Then Exit Function
  81. lBufferSize = lLen * 2
  82. sBuffer = String$(lBufferSize, Chr(0))
  83. lRet = MultiByteToWideChar(65001, 0, VarPtr(bUTF8(0)), lLen, StrPtr(sBuffer), lBufferSize)

  84. If lRet <> 0 Then
  85. sBuffer = Mid(sBuffer, 1, lRet)
  86. End If

  87. UTF8_Decode = sBuffer
  88. End Function
复制代码

g_tk算法.zip

11.96 KB, 下载次数: 232, 下载积分: 精币 -2 枚

结帖率:63% (5/8)
发表于 2011-3-8 18:57:39 | 显示全部楼层   河南省濮阳市
此帖仅作者可见

使用道具 举报

结帖率:100% (2/2)

签到天数: 1 天

发表于 2011-3-10 08:03:57 | 显示全部楼层   宁夏回族自治区固原市
此帖仅作者可见

使用道具 举报

发表于 2011-3-11 00:12:09 | 显示全部楼层   山西省长治市
此帖仅作者可见

使用道具 举报

发表于 2011-3-11 00:19:45 | 显示全部楼层   山西省长治市
此帖仅作者可见

使用道具 举报

结帖率:100% (5/5)
发表于 2011-3-22 21:27:51 | 显示全部楼层   浙江省台州市
此帖仅作者可见

使用道具 举报

结帖率:100% (1/1)
发表于 2011-5-13 17:37:51 | 显示全部楼层   广东省东莞市
此帖仅作者可见

使用道具 举报

发表于 2011-6-8 12:08:02 | 显示全部楼层   四川省绵阳市
此帖仅作者可见

使用道具 举报

结帖率:100% (6/6)
发表于 2011-8-12 01:33:42 | 显示全部楼层   重庆市重庆市
此帖仅作者可见

使用道具 举报

结帖率:100% (2/2)
发表于 2011-8-18 19:20:49 | 显示全部楼层   广西壮族自治区桂林市
此帖仅作者可见

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表