看完Pornhub的视频接口JS混淆后,我顺手写了个下载插件

看完Pornhub的视频接口JS混淆后,我顺手写了个下载插件

看过我博客的朋友,应该都知道我以前经常写爬虫的,但是现在基本上不玩了。以前写过一篇关于pornhub视频接口抓取的文章,当时写那个完全是兴趣使然。不过没想到很多朋友在谷歌上都看到了那篇文章,然后加了我好友一起探讨。

pornhub视频地址接口抓取分析&&爬虫源码分享

之所以写这篇文章呢,是因为前几天有一位朋友,看了我上面这篇文章,加了我好友并咨询了我一些问题。

应该是最近Pornhub(下面全部简称P站)好像修改了前端的代码,将视频的接口信息全部隐藏起来了。不过我很久都没有看过P站了,也不太了解情况。第二天打开看了一下,发现确实不像以前那样能直接在网页源码中找到视频链接了。

这是以前的P站。

现在的P站。

这两段都是JS代码,但是以前的一看就很清晰明了,而现在的都是些什么鬼玩意儿,怎么还有一大堆的垃圾注释在里面。

不用说,肯定是做了JS混淆。恰好最近在研究JS逆向,本来想着可能比较复杂。应该要下断点,然后查看堆栈调用什么的。因为代码是被压缩过的,所以在chrome开发者工具里直接代码格式化。

在network面板中将代码格式化之后可以看的很清楚,看上面定义的那一堆变量感觉就是我们要的url,而下面就是将变量拼接的最后的视频链接。

我在想P站的程序猿不会真的这么傻吧,难道就这样拼接一堆字符串??所以我就去前面找到定义的那个变量。

然后在控制台输出这个变量的值。

我整个人都傻了,P站的程序猿这么直接的吗?那还混淆个**的代码。以前写个P站的爬虫还得每个URL正则匹配才能提取出来。现在更省事了,都不用爬了,直接把这个变量的值取出来就什么信息都有了。

我严重怀疑P站的前端程序猿是不是写代码的时候看片去了!

所以接下来要想提取出视频的url就很容易了,我本来还是打算用Python来写个脚本直接拿到url的。直接用ExecJS这个库来执行这段被混淆过的JS代码就ok了。但是想了想这样也太简单了吧,没什么意思。要不我写一个Chrome的插件来完成这件事,因为本身视频加载之前JS肯定会执行。那么用插件的方式也更加方便。于是思索了一晚上,第二天一大早就起床撸插件。

插件开发的过程,最关键的问题就是如何将包含所有视频接口信息的变量给提取出来。

一开始我是想到是直接在浏览器的全局变量window中拿到那个变量,这是最简单的办法。我发现通过注入JS代码用console.log(window)输出的全局变量中还是没有包含flashvars_*****这个变量,不清楚为什么。我一开始认为可能是页面onload的时候还没有执行JS所以没有变量信息。后面我想了想要不执行settimeout来实现延迟执行代码,但是还是不行。

 

于是我决定用另外一个办法,将字符串作为代码执行。也就是写木马最常用到的eval函数。在页面加载时,通过xpath得到混淆JS代码的位置,将它作为一段字符串当成代码执行,这样同样拿到了接口信息。

给大家看一下插件最核心的两段代码content-script.js,也就是注入页面的JS代码。

function Func() {
   return new Promise((resolve, reject) => {
      var a = document.querySelector("#player >script:nth-child(1)").innerHTML
      a = a.split('loadScriptUniqueId')[0]
      var c = a.match("flashvars_[0-9]{1,}")[0] 
      eval(a) 
      var d = eval(c) 
      resolve(d)
   })
}
window.onload = () => {
   Func().then(res => {
      var videoType = []
      Object.keys(res).forEach((item) => {
         if (item.startsWith('quality_')) {
            var obj={
               key:item,
               val:res[item]
            }
            videoType.push(obj)
         }
      })
   for(var i = 0, len = videoType.length; i < len; i++){
   console.log(videoType[i].key,videoType[i].val)
}   
   chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
      if(request.cmd == 'test') 
      sendResponse(videoType);
      });
   })
}

和popup.js也就是插件在浏览器右上角的那个页面的JS。

function sendMessageToContentScript(message, callback)
{
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs)
    {
        chrome.tabs.sendMessage(tabs[0].id, message, function(response)
        {
            if(callback) callback(response);
        });
    });
}
sendMessageToContentScript({cmd:'test', value:'test'}, function(videoType)
{
    console.log(videoType);
   for(var i = 0, len = videoType.length; i < len; i++){
      console.log(videoType[i].key,videoType[i].val)
}
    var boxEl = document.getElementsByTagName('ul')[0]
    //var videoType = [{ key: 'qeqw', val: 'adasda' }, { key: 'qeqw', val: 'adasda' }, { key: 'qeqw', val: 'adasda' }]
    var videoStr = ''
    videoType.forEach(item => {
        videoStr += "<li>" + "<label>清晰度:" + "<span>" + item.key + "</span>" + "</label>" + "<a href=" + item.val + " target='_blank'>下载</a>" + "</li>"
    });
    boxEl.innerHTML = videoStr
});

popup.js的作用主要就是和content-script.js通信,相互传值。然后在插件中渲染生成页面,JS间传值主要用到了Chrome的API。

插件开发的过程中还涉及到很多细节问题,比如ico的制作,这些就不提了。最后插件的样子大致如下。

当页面加载完成,点击下载就能下载到到原视频了。最后插件写完,顺便上传到了Google商店里,毕竟是自己写的第一个Chrome插件,还是蛮激动的。感兴趣的小伙伴可以下载来试试。

插件链接:https://chrome.google.com/webstore/detail/pornhub%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD%E6%8F%92%E4%BB%B6/ilkaomdecidpjhckgicihkekblbfjklc?hl=zh-CN&gl=CN

插件源码压缩包:

Pornhub视频下载插件

如果不能从谷歌商店安装的话,可以直接解压导入。

总结:

由于之前一直都是用Python写脚本,对JS不是太熟悉,虽然我只知道怎么去实现,但是我却不能熟练地用JS写出来,这期间向很多问题都是我的同学勾大佬请教的,很感谢大佬的帮忙。不过令我很惊奇的是做开发的同学他们普遍都没用过eval函数,甚至不知道。他们告诉我正常的开发中没有这样用的。但是我感觉搞安全的,基本人人都知道eval,毕竟一开始学习一句话木马的时候就没少接触过。也许做开发和搞安全区别真的挺大的吧。

10月13日更新:

谈一下谷歌插件发布的一些经验。由于写插件之前我根本不知道看P站的人竟然有这么多。大概过去半个多月,就有700多用户了,Amazing!

 

所以我在前两天就修复了一些插件的bug,并且添加了一些插件的英文翻译。

好像是触发了Chrome插件商店的自动化审查,结果第二天我收到了谷歌给我发来的邮件。

所以赶紧删掉了插件介绍的英文翻译,然后重新发布了插件,然后通过了审查。恰好有朋友发邮件咨询我。

大概就是这样吧,不过我还是想声明一下,真的没有搞黄色[\捂脸]

插件1.2版本更新:

1.取消onload事件,优化插件运行速度,不必等待页面加载完成再获取视频链接信息
2.增加对pornhub会员账号的视频链接提取
3.增加用户提示

赞赏

微信赞赏支付宝赞赏