2019-12-31 爬网页15-js逆向入门(Base64编码和解码应用)

本例引用自https://blog.csdn.net/Mr__lqy/article/details/88753324,只适用于初学者,只需要会打断点追踪就可以了。

目标从网站获取视频链接,然后下载。
我这里使用的浏览器是chrome。

先打开网页链接
在这里插入图片描述在开发者工具中找“Media”,这里可以看到一个请求地址

http://v3-default.ixigua.com/123236566489272e69198cde2756e341/5e0b075b/video/tos/hxsy/tos-hxsy-ve-0000/7507ec8b4de043ac94d23143c1c1162d/?a=2012&br=3446&bt=1723&cr=0&cs=0&dr=0&ds=3&er=&l=201912311530430100140640461E071D82&lr=motor&qs=0&rc=anJnM3B0N2x2aTMzO2gzM0ApNTk8aGU1ZmRlN2Y7Ozo6ZWdtXzVxX3FyNjNfLS0wLi9zcy0wYTU2XjVgNWI2L2I0X146Yw%3D%3D

它就是我们要找到目标地址。

按照原作者思路,先打开网页源码查看一下,是没有这个视频链接的。
注意,这里有段代码是有用的,就是下面的video_id 参数,回头会用到。

<script data-from="toutiao" crossorigin="anonymous">
    if (self != top) {
        top.location.href = self.location.href
    }

    //基础变量, 来自模板上下文
    var group_id = "6615388842591518733";
    var item_id = "6615388842591518733";
    var request_id = "56716001577773371709";
    var tag = "video_car";
    var site_id = "5000246";
    var weixinListPercent = 100;
    var custom_proportion1 = 0;
    var custom_proportion2 = 0;
    var is_app_video_downgrade = 0;
    var city = "上海";
    var country_code = "CN";
    var country = "中国";
    var province = "上海";
    var group_source = "20";
    var is_ugc_video = true;
    var content_type = "ugc_video";
    var creator_uid = "100118509879";
    var media_id = "1610842577106951";
    var video_id = "v0201e380000bf6s9iu4tqbmt08dbopg";
</script>

继续,在开发者工具中Elements,可以看到视频的src
在这里插入图片描述这说明这段video相关html代码是通过js动态创建的。
下面我们就需要跟踪html生成过程,最终找到链接地址的创建逻辑。

原作者是以html中的webkit-playsinline属性为突破口。
在开发者工具的Sources中搜索“webkit-playsinline”关键字
在这里插入图片描述
可以找到唯一相关代码,应该就是动态生成html的地方。
请注意9748行的videoList,从名称就应该感觉需要跟踪一下。
本文的第一个断点就是打在这里。

在9748行上用鼠标点一下,出现蓝色箭头,断点就已经打好了。
刷新页面,会自动停止在断点处。
在这里插入图片描述最右边是断点,打勾表示有效。
调试代码时候,可以在控制台(Console)直接输出变量,看一下值。
上图中可以看到,videoList中已经加载好了2个src链接(分别是极速和超清)。

下面就需要追踪videoList的来源
在这里插入图片描述把右边窗口滚动条网上移动,可以看到Call Stack,这里保留了代码运行过程的调用堆栈情况。
当前代码就是停留在最上面。

我们往下移动鼠标依次点击,可以逐步观察调用来自哪里。
移动2次后,可以到以下界面
在这里插入图片描述有没有发现,videoList中的src,type,label等等都是在这里push进去的。
src来自t.main_url,而且被Base64编码了(因为这里用了base64decode解码)。关于Base64编码,参见链接

我们继续往下移动堆栈2次,可以看到以下界面。
在这里插入图片描述这里出现了数据,其中就包含了mail_url,当然是编码过的(解码后就可以得到本文最初提到的,也就是我们需要的视频目标地址)。
注意,鼠标移动到文件名称上,会出现调用地址。你可以鼠标右键,选择copy link address,就能得到下面的地址。
它有r,s,logo_type和callback参数

https://i.snssdk.com/video/urls/v/1/toutiao/mp4/v0201e380000bf6s9iu4tqbmt08dbopg?r=37066702101798144&s=315584556&logo_type=motor&callback=tt_playerdppez

现在再理一下思路,只要我们找到上面的链接地址(入口地址),就能获得main_url,然后把main_url解码,那就能获得视频的src了。

原作者此时是利用链接中的logo_type=motor进行追踪。
在sources中搜索logo_type=motor,可以找到唯一一处,我们在9785行打断点跟踪
在这里插入图片描述此时,这里有一个crc32函数和2个参数r.config.remoteURL + r.config.videoID。
全局搜索remoteURL可以找到代码中定义的地方,它是一个定值。

remoteURL: "//i.snssdk.com/video/urls/v/1/toutiao/mp4/"

videoID其实已经出现过了,就是在本文最开始提到的页面源码中赋值。

var video_id = "v0201e380000bf6s9iu4tqbmt08dbopg"

打完断点后,刷新页面跟踪,可以进入crc32函数内部。

e.crc32 = function(e) {
                var t = document.createElement("a");
                t.href = e;
                var n = function() {
                    for (var e = 0, t = new Array(256), n = 0; 256 != n; ++n)
                        e = n,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        e = 1 & e ? -306674912 ^ e >>> 1 : e >>> 1,
                        t[n] = e;
                    return "undefined" != typeof Int32Array ? new Int32Array(t) : t
                }()
                  , r = function(e) {
                    for (var t, r, o = -1, i = 0, a = e.length; i < a; )
                        t = e.charCodeAt(i++),
                        t < 128 ? o = o >>> 8 ^ n[255 & (o ^ t)] : t < 2048 ? (o = o >>> 8 ^ n[255 & (o ^ (192 | t >> 6 & 31))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | 63 & t))]) : t >= 55296 && t < 57344 ? (t = (1023 & t) + 64,
                        r = 1023 & e.charCodeAt(i++),
                        o = o >>> 8 ^ n[255 & (o ^ (240 | t >> 8 & 7))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | t >> 2 & 63))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | r >> 6 & 15 | (3 & t) << 4))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | 63 & r))]) : (o = o >>> 8 ^ n[255 & (o ^ (224 | t >> 12 & 15))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | t >> 6 & 63))],
                        o = o >>> 8 ^ n[255 & (o ^ (128 | 63 & t))]);
                    return o ^ -1
                }
                  , o = t.pathname + "?r=" + Math.random().toString(10).substring(2);
                "/" != o[0] && (o = "/" + o);
                var i = r(o) >>> 0;
                return [t.protocol, t.hostname].join("//") + o + "&s=" + i
            }

这个函数就是用来生成部分目标链接地址的。
地址前面部分就不解释了,后面r参数和s参数都是在这里计算获得的。

而logo_type参数在9787行赋值,是写死的。

继续往下跟踪几步,进入9788行后,可以到达以下界面
在这里插入图片描述这里出现了一个函数,送入"tt_player",获得tt_player加一个随机字符串

 e.getName = function(e) {
                return e + Math.random().toString(36).replace(/[^a-z]+/g, "").substr(0, 5)
            }

最终callback参数在以下代码中拼接完成

var a = e.createScript(t + "&callback=" + i, o)

送入createScript中创建js。

至此,url地址逻辑已经全部得到。

总结一下:
我们需要的是remoteURL和video_id的值,crc32函数获得r和s的值,getName函数获得callback的值,把这些内容拼接起来得到请求地址。

通过请求地址可以获得tt_player开头的字符串。

在这个字符串中截取mai_url的值(有2个),经过Base64位解码,就能得到最终的目标地址了。

再用目标地址就可以直接下载感兴趣的视频。

完整代码参见链接

发布了122 篇原创文章 · 获赞 7 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_42555985/article/details/103783535