一天两天三天
https://www.cnblogs.com/santian/p/4420877.html
随笔 - 51,  文章 - 0,  评论 - 65,  阅读 - 20万

大家可以先看下这篇文章,将微博或者qq空间的说说同步至博客园 wcf+js(ajax)跨域请求(1),在该文里面,对使用javascript调用wcf到我本机取数据作了介绍。不过吐槽一下,该文发布没多久,就被博客园移除首页了,博主可是花了五个小时调试代码,部署环境。最后太晚了,所以文章写得仓促了点。文章写得不咋滴。大概是博客园管理认为我没写完,所以移除了首页。博主可真是冤枉。最后这一系列文章写完,博主会重新详细写一下如何通过javascript调用wcf。废话不多说。我们今天来看一下,如何在本地去qq空间的数据。

刚开始博主的思路是写一个Chrome扩展,然后每次当我打开空间的时候自动记录数据到本地。后来感觉javascript操作数据很不方便,便决定还是使用C#来取数据。

另外先透漏一下,从qq空间取数据到博客园后博主的思路。博主打算使用Knockout组件的形式在博客园渲染页面。所以现在把qq空间同步至博客园这个工程大概有以下三步。一是本地服务端取数据存储到数据库。二是通过javascript调用wcf将数据传输到博客园,最后是使用KnockOut将数据渲染至页面。

另:博主本打算模拟qq空间登录的方式来取数据。不过qq空间登录的模块是使用插件的形式登录的。了解其机制代价太大。所以决定通过下面这种方式取数据。

另:现在页面上还看不到效果。最后一步使用KnockOut将数据渲染至页面博主还没开始准备。现在我们开始到qq空间取数据。

确定qq空间异步无刷新填充数据的报文必要参数

我们仔细观察下qq空间首页,会发现qq空间全部动态那儿有个刷新的按钮

点击此处会异步去qq服务器取数据。如下图

我们将该链接访问以下。

http://user.qzone.qq.com/p/ic2.s51/cgi-bin/feeds/feeds3_html_more?uin=11******88&scope=0&view=1&daylist=&uinlist=&gid=&flag=1&filter=all&applist=all&refresh=0&aisortEndTime=0&aisortOffset=0&getAisort=0&aisortBeginTime=0&pagenum=2&externparam=basetime%3D1428817036%26pagenum%3D2%26dayvalue%3D0&firstGetGroup=0&icServerTime=0&mixnocache=0&scene=0&begintime=1428817036&count=10&dayspac=0&sidomain=cm.qzonestyle.gtimg.cn&useutf8=1&outputhtmlfeed=1&rd=0.1990418911445886&g_tk=1385204724

如上所示,可以通过这样取到我们需要的json数据。

那么问题来了。我们如果要使用System.Net该类库提供的服务来模拟http请求报文,都需要什么条件么。毫无疑问,在这儿需要的是,一个是get请求的url,包括该get请求传递过去的参数。以及报文发送时随报文发送的cookie.

需求已经明了。我们需要得到get参数,以及发送的cookie.

破解g_tk=1385204724参数的秘密

观察上面我发布get链接。首先最想说的是,这参数也太**多了。不过没问题。我们多对比几次就会发现,上面的大部分参数都是不怎么变化的。其中一个begintime参数,博主试了下并没有多大的影响。几经确认,发现该get请求最重要的参数只有一个,那就是g_tk参数。该参数和cookie几乎决定了我们请求数据的成败。那么该参数到底是在哪儿来的呢。

要想知道该参数怎么来的,我们就要知道当我们点击刷新的时候,javascript函数到底做了什么。怎样生成的ajax请求呢。那么我们就需要知道当我们点击该刷新按钮的时候执行的是什么函数,也就是该按钮到底和哪个javascript函数绑定。那么问题来了----如何找到dom元素绑定的函数呢。我们首先在chrome浏览器下f12调试。

如下图

 

博主在这儿找了半天,也没找到有用的信息,不过幸好博主找到了一个神器

该插件可以提供让我们看dom元素绑定函数的功能,虽说有些限制,不过在这儿确实发挥了作用。

既然找到了该函数调用的函数,那么顺藤摸瓜。博主找到了下面这个函数。

1
2
3
4
  pingCgi: function () {
            var a =
            "http://" + g_R_Domain + "/cgi-bin/user/qzone_cgi_msg_getcnt2"; setInterval(function () { QZFL.pingSender(a + "?uin=" + g_iLoginUin + "&bm=" + g_LoginBitmap + "&v=" + c.getCGISeed("_QZN_TodoMsgCnt") + "&g_tk=" + QZONE.FrontPage.getACSRFToken() + "&g=" + Math.random(), 0) }, 6E5)
}

显然g_tk是通过QZONE.FrontPage.getACSRFToken()这个函数生成的。我们继续找到该函数。

1
2
3
4
5
6
7
8
9
10
QZONE.FrontPage.getACSRFToken = function (a) {
    a = QZFL.util.URI(a);
    var b;
    a && (a.host && 0 < a.host.indexOf("qzone.qq.com") ? b = QZFL.cookie.get("p_skey") : a.host && 0 < a.host.indexOf("qq.com") && (b = QZFL.cookie.get("skey")));
    b || (b = QZFL.cookie.get("skey") || QZFL.cookie.get("rv2"));
    a = 5381;
    for (var c = 0, d = b.length; c < d; ++c)
        a += (a << 5) + b.charAt(c).charCodeAt();
    return a & 2147483647
};

找到了个函数那么问题就清楚了。该函数调用了cookie里面的P_skey参数来生成了该g_tk. 我们可以使用C#来重写该javascript函数。

1
2
3
4
5
6
7
8
public string getg_tk(string str)
{
    var b = str;
    var a = 5381;
    for (int c = 0, d = b.Length; c < d; ++c)<br>      //这儿是javascript代码的c#实现。b[c]取到字符串在c索引处的字符。强转为int既是将char转为Unicode
     a += (a << 5) + (int)b[c];
    return (a & 2147483647).ToString();
}

之后我们传入cookie里面的p_skey=rK6xJHZPMWUxBj6ehdS5CoILGC8aMt7EPEgNYVRBbRU_;会发现生成的g_tk和我们用来调用的g_tk=1385204724相等。如下图。

 

现在解决了get参数的问题,我们再来解决我们的cookie问题。

使用sqllite数据库获取chrome cookie数据表

我们找到chrome cookie所在的文件夹。

使用notepad打开,会发现是乱码。这是因为chrome后来版本的cookie都是通过加密后存储到了sqlite数据库里面。

为我们的项目添加如下引用。同时在我们项目的bin问价夹下添加SQLite.Interop.dll类库。

我们添加一个sqllitehelper帮助类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//添加一个静态帮助类 <br>public static class SqlLiteHelper
    {
        public static DataTable ExecuteSql(System.Data.IDbConnection connection, string sql)
        {
            var cmd = connection.CreateCommand();
            cmd.CommandText = sql;
 
            using (var reader = cmd.ExecuteReader())
            {
                var dataTable = new DataTable();
                dataTable.Load(reader);
                return dataTable;
            }
        }
    }
1
2
3
4
5
6
//这是sqllite数据库的连接字符串  <br> string connectionString = @"Data Source=C:\Documents and Settings\wfm\Local Settings\Application Data\Google\Chrome\User Data\Default\Cookies";<br>  //使用using用来释放非托管资源,垃圾回收。
   using (var conn = new System.Data.SQLite.SQLiteConnection(connectionString))
   {
         conn.Open();
         DataTable db = SqlLiteHelper.ExecuteSql(conn, "select host_key,name,value,encrypted_value from cookies;");
   }

使用上面的代码我们就可取到sqllite数据库的数据。

 

使用crypt32.dll下的CryptUnprotectData函数解密chrome cookie

如上图取到cookie的数据后我们会发现取到的value值是空的,同时有一个encrypted_value的byte数组.随便google一下我们就知道这是chrome新版本里面存储的cookie数据。不过被chrome加密了。那么现在我们就需要解密cookie.如何解密,博主其实一点也不会。不过幸好有大神会。搜索相关资源,我们知道需要用到

crypt32.dll下的CryptUnprotectData函数来解密。我们寻找资源会发现相关的资料都是使用Python实现的。并没有c#下面的代码可以拿来直接用。相关连接如下

Chrome 33+浏览器 Cookies encrypted_value解密脚本(python实现),还有一些其它类似的资料。这里就不列出了。

我们新建一个类DPAPI相关代码如下。

我们可以通过如下调用解密cookie:

1
Encrypted_value = DPAPI.Decrypt(Convert.ToBase64String(cookieContent))

现在关于模拟http报文请求的条件已经都准备好了。

使用System.net类库模拟http请求报文

1
2
3
4
5
6
7
HttpResponseParameter responseParameter1 = httpProvider.Excute(new HttpRequestParameter
           {
               Url = "http://user.qzone.qq.com/p/ic2.s51/cgi-bin/feeds/feeds3_html_more?uin=11******88&scope=0&view=1&daylist=&uinlist=&gid=&flag=1&filter=all&applist=all&refresh=0&aisortEndTime=0&aisortOffset=0&getAisort=0&aisortBeginTime=0&pagenum=2&externparam=basetime%3D1428810895%26pagenum%3D2%26dayvalue%3D0&firstGetGroup=0&icServerTime=0&mixnocache=0&scene=0&begintime=1428810895&count=10&dayspac=0&sidomain=cm.qzonestyle.gtimg.cn&useutf8=1&outputhtmlfeed=1&rd=0.9383603150490671&g_tk=" + getg_tk(GetCookieStr("p_skey").Split('=')[1].Replace(";", "")),
               IsPost = false,
               Encoding = Encoding.UTF8,
               Cookie = new HttpCookieType() { CookieCollection = addCookieToContainer(cookieSend) }
           });

注意上面我使用了一个类库,也是园子里的一位大神写的,大家可以自己去下载。

.Net(c#)模拟Http请求之HttpWebRequest封装

  

现在,所有的难点我们都一一解决了。现在我们运行代码

OK,我们需要的数据都取到了。但是注意一个问题,取数据的时候只有我们登陆qq空间也就是qq空间的cookie有效的时候才可以取到数据。

 现在我们可以将数据存储到数据。等待javascript调用wcf来读取数据

本文地址:http://www.cnblogs.com/santian/p/4420877.html

博客地址:http://www.cnblogs.com/santian/

转载请以超链接形式标明文章原始出处。
posted on   一天两天三天  阅读(2376)  评论(3编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?

< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5
点击右上角即可分享
微信分享提示