抖音a_bogus爬虫逆向补环境

抖音a_bogus爬虫逆向补环境

接口及参数

  1. 打开网页版抖音,右键视频进入详情页。
  2. F12打开控制台筛选detail,然后刷新网页,找到请求。
  3. 可以发现我们本次的参数目标a_bogus。
    抖音详情接口

找到加密代码

  • 找到入口

    首先看一下接口的加载器,也就是发送请求的调用栈,挨个查看之后不难发现,加密的入口应该在这两处,由于栈中的调用顺序是从下往上,所以我们先看下面那个入口。

    调用栈定位

  • 查看参数

    首先我们查看入口参数,不难发现arguments[1]是请求的url,那么我们可以根据url包含detail去打一个断点,然后一步一步进行调试,看看发生了什么。

    入口参数

  • 断点调试

    单步步入之后,开始了加密参数的流程,我们发现这里的代码明显是混淆过的,上下翻动后,我们发现这是jsvmp文件。单步跳出后,直接到了请求流程,说明在这里面已经完成了a_bogus的加密,所以我们可以断定,加密参数是在调用栈中另一个地方调用的。所以我们再查看一下调用栈中的另一个入口。

    在这里插入图片描述

    可以看到,加密最后运行的函数是s.apply(b,u)并且赋值给了l,那么我们可以大胆猜测一下,这个l就是返回的加密结果,但是我们知道request中有很多加密参数,而且这个代码是jsvmp,所以我们可以认为,这里是调用了jsvmp的指令函数,这个指令函数加密了我们的a_bogus,但是也被其他的一些需求调用,所以说我们要定位到加密a_bogus的时机。

    加密入口
    我们可以知道a_bogus的长度为172,所以我们可以在这里打条件断点,当s.apply(b,u).length === 172时断住。然后进行观察。

    a_bogus
    断住之后,我们发现结果大概率是我们要的a_bogus,后面我们会验证一下,参数为uri以及UserAgent。那么我们之后调用的时候,可以直接调用这个函数,把相应的参数传进去就可以得到我们想要的结果。由于这个s.apply可能调用的函数有很多种,我们不知道它调用的具体函数是哪个,因此,我们需要找到函数调用入口也就是函数导出。至此我们先验证一下结果。

    断点
    断点结果
    我们发现,没错就是我们要的,所以加密就在这里进行。所以我们接下来的需要做的就是补环境和函数导出。

    请求参数

补环境

  1. 首先我们把整个bdms.js拿下来,本地运行,进行补环境。
  2. 然后运行后发现window is not defined,我们定义一个window=global补个window环境再试试看。
    window
  3. 我们发现这里莫名其妙报了个错,由于代码混淆加上各种循环,很难找到这个变量是什么,所以我们猜测,大概率是获取某些环境没有获取到,所以我们加代理看看他获取了什么没获取到导致的。我们添加下列代理来看看检测了哪些环境。
    function get_enviroment(proxy_array) {
        for (var i = 0; i < proxy_array.length; i++) {
            handler = '{\n' +
                '    get: function(target, property, receiver) {\n' +
                '        console.log("方法:", "get  ", "对象:", ' +
                '"' + proxy_array[i] + '" ,' +
                '"  属性:", property, ' +
                '"  属性类型:", ' + 'typeof property, ' +
                // '"  属性值:", ' + 'target[property], ' +
                '"  属性值类型:", typeof target[property]);\n' +
                '        return target[property];\n' +
                '    },\n' +
                '    set: function(target, property, value, receiver) {\n' +
                '        console.log("方法:", "set  ", "对象:", ' +
                '"' + proxy_array[i] + '" ,' +
                '"  属性:", property, ' +
                '"  属性类型:", ' + 'typeof property, ' +
                // '"  属性值:", ' + 'target[property], ' +
                '"  属性值类型:", typeof target[property]);\n' +
                '        return Reflect.set(...arguments);\n' +
                '    }\n' +
                '}'
            eval('try{\n' + proxy_array[i] + ';\n'
                + proxy_array[i] + '=new Proxy(' + proxy_array[i] + ', ' + handler + ')}catch (e) {\n' + proxy_array[i] + '={};\n'
                + proxy_array[i] + '=new Proxy(' + proxy_array[i] + ', ' + handler + ')}')
        }
    }
    proxy_array = ['window', 'document', 'location', 'navigator', 'history', 'screen', 'aaa', 'target']
    get_enviroment(proxy_array)
    
  4. 我们发现,检测的还不少。加上代理之后我们发现,在访问wondow.requestAnimationFrame时没访问到,然后紧接着报错了,那么说明,对window.requestAnimationFrame进行了校验,因此我们可以补一下 ,这个是一个函数,我们补一个空函数试试。
    补环境
  5. 补完后发现又有报错。我们发现访问window._sdkGlueVersionMap时XMLHttpRequest报错,那我们都补一下。我们可以到浏览器的控制台获取window._sdkGlueVersionMap的值。补环境
    补环境
  6. 全部补完之后我们发现终于没报错了,说明正常运行了,下一步我们需要找到加密函数的入口,然后进行最后的加密操作。(其中检测环境时还创建了一个span标签,这个不是强制的,因此有兴趣的同学可以补一下。)
    完成补环境

函数入口

我们可以发现,首次调用的函数是这里,也就是说这里导出给外面的文件使用,所以,我们可以认定这里是导出的加密入口。分析代码可以发现实际加密是调用的是u._u,所以我们可以将window.sign导出然后进行调用即可。
入口

结果

结果
其中我们发现,调用sign之后又多检测了很多环境变量,为了环境更加真实和防止被检测的风险,尽量补全环境是最好的,即使会降低运行速度,如果追求运行速度我们可以尝试难度更高的纯算逆向。

项目参考

https://github.com/ShilongLee/Crawler

相关推荐

  1. 爬虫案列 --视频批量爬取

    2024-06-14 22:30:03       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-14 22:30:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-14 22:30:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-14 22:30:03       82 阅读
  4. Python语言-面向对象

    2024-06-14 22:30:03       91 阅读

热门阅读

  1. 深入解析JVM的GC过程

    2024-06-14 22:30:03       30 阅读
  2. cocos入门11:生命周期

    2024-06-14 22:30:03       28 阅读
  3. Docker相关命令

    2024-06-14 22:30:03       27 阅读
  4. Linux下安装MySQL

    2024-06-14 22:30:03       21 阅读