首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 模擬 QQ 登入獲取群列表與群成員:Cookie 處理、gtk 算法與 HTTP 請求實戰

     編輯:關於C#

前言

前兩篇已實現模擬 QQ 登入並取得 Cookie。本文進一步:獲取群列表、群成員 (含 QQ 郵箱),核心難點在於 g_tk 參數計算 (網上鮮見完整 C# 實作)。

抓包分析

1. 群列表介面

URL:https://qun.qzone.qq.com/cgi-bin/get_group_list?uin={uin}&random={rand}&g_tk={gtk}

回傳 JSON:{ "code":0, "data":{ "group":[{ "groupid":"12345", "groupname":"測試群", ... }] } }

2. 群成員介面

URL:https://qun.qzone.qq.com/cgi-bin/get_group_member?uin={uin}&groupid={gid}&random={rand}&g_tk={gtk}

回傳 JSON:{ "code":0, "data":{ "item":[{ "uin":"123456", "nick":"用戶", "iscreator":"0", ... }] } }

uin 即 QQ 號,郵箱為 {uin}@qq.com。

核心難點:g_tk 計算演算法

源自騰訊網頁 JS:hash = 5381; for(c in skey) hash += (hash << 5) + c.charCodeAt(); g_tk = hash & 0x7fffffff;


public static int GetGTK(CookieContainer cookies)
{
    foreach (Cookie cookie in GetAllCookies(cookies))
    {
        if (cookie.Name == "skey")
        {
            int hash = 5381;
            foreach (char c in cookie.Value)
                hash += (hash << 5) + c;
            return hash & 0x7fffffff;
        }
    }
    return 0;
}

public static List GetAllCookies(CookieContainer cc)
{
    var list = new List();
    var table = (Hashtable)cc.GetType().GetField("m_domainTable", 
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField).GetValue(cc);
    foreach (object pathList in table.Values)
    {
        var lst = (SortedList)pathList.GetType().GetField("m_list", 
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField).GetValue(pathList);
        foreach (CookieCollection coll in lst.Values)
            list.AddRange(coll.Cast());
    }
    return list;
}

JSON 反序列化模型


public class QQGroupJson { public int code; public QQGroupList data; }
public class QQGroupList { public List group; }
public class QQGroupInfo { public string groupid; public string groupname; public int count; }

public class QQMemberJson { public int code; public QQMemberData data; }
public class QQMemberData { public List item; }
public class QQMember { public string uin; public string nick; public string iscreator; public string ismanager; }

完整調用流程


var cookies = _cookieContainer; // 登入後取得的 CookieContainer
int gtk = GetGTK(cookies);
string uin = "你的QQ號";
string rand = new Random().NextDouble().ToString();

// 1. 獲取群列表
string groupUrl = $"https://qun.qzone.qq.com/cgi-bin/get_group_list?uin={uin}&random={rand}&g_tk={gtk}";
string json = HttpGet(groupUrl, cookies);
json = json.Substring(10, json.Length - 12); // 去除 _Callback() 包裹
var groups = JsonConvert.DeserializeObject(json).data.group;

// 2. 獲取指定群成員
string gid = groups[0].groupid; // 選擇第一個群
string memberUrl = $"https://qun.qzone.qq.com/cgi-bin/get_group_member?uin={uin}&groupid={gid}&random={rand}&g_tk={gtk}";
json = HttpGet(memberUrl, cookies);
json = json.Substring(10, json.Length - 12);
var members = JsonConvert.DeserializeObject(json).data.item;

foreach (var m in members)
    Console.WriteLine($"{m.nick} ({m.uin}) -> {m.uin}@qq.com");

HttpGet 輔助方法


public static string HttpGet(string url, CookieContainer cookies)
{
    var req = (HttpWebRequest)WebRequest.Create(url);
    req.CookieContainer = cookies;
    req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0";
    using (var resp = (HttpWebResponse)req.GetResponse())
    using (var stream = resp.GetResponseStream())
    using (var reader = new StreamReader(stream, Encoding.UTF8))
        return reader.ReadToEnd();
}

注意事項與風險

  • 介面非官方公開:騰訊隨時可能變更 URL、參數、回傳格式或加密。
  • 頻率限制:短時間大量請求會觸發驗證碼或封禁 IP。
  • 隱私合規:獲取群成員郵箱屬敏感個人資訊,請遵守《個人信息保護法》、平台服務條款,僅供個人學習研究。
  • 現代替代:騰訊開放平台提供 官方 API (OAuth 2.0),支援獲取群資訊、發送訊息等,建議生產環境使用官方途徑。

結語

從模擬登入到解析 g_tk 算法、調用內部介面獲取群成員,完整展示了逆向工程 Web 介面的典型流程。理解 Cookie 容器遍歷、JS 算法移植、JSONP 回調剝離等技巧,對爬蟲開發、API 測試、自動化測試均有參考價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved