[JS逆向] 知乎x-zse-96参数分析详解

目录

声明

目标 

运行结果

x-zse-96参数分析

补环境

总结


声明

        本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
        本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!

目标 


        目标:某乎的文章评论
        网址:aHR0cHM6Ly93d3cuemhpaHUuY29tL3NlYXJjaD90eXBlPWNvbnRlbnQmcT0lRTglOEIlQjklRTYlOUUlOUM=

运行结果

知乎的x-zse-9还是三年前搞过

现在有空重新梳理一下流程,前面几部都大差不差,关键是后面函数的补环境.

x-zse-96参数分析

 1、在加载包那边搜索评论,就可以看到加载评论的包啦,还是和以前一样,是x-zse-96加密在里面,其他的可以固定

2、很好奇不需要x-zse-81参数加密,但是影响也不大在里面,x-zse-81也是固定的

3、先全局搜索x-zse-96,不行的话可以hook头部或者下xhr

4、可以看到有两处有搜索到x-zse-96 ,全部打上断点后往下滑,断住后把另一个取消掉

5、发现就是t0这个结果,此时只需要分析,可以往上找

6、参数就需要注意,其他的参数没什么重要的

te:是请求的链接

tS:是cookie的d_c0

7、跟ed函数里面就可以看到

ta、tu、tc、tf、td、tp就不再过多的分析了

 8、看看t8函数加密的,跟栈进去

        发现调用挺简单的,可以合并在一起

t8 = function(t, e) {
    return void 0 === e && (e = 4096),
    !!t && function(t) {
        return new Blob([t]).size
    }(t) <= e
}

9、重点还是研究 下面的signature参数是怎么样加密的

   可以看的出ty是一个很标准的md5加密的库(加密后的数据是32位的话,可以怀疑他是不是md5加密)

10、继续跟栈tJ(ti).encrypt这个加密函数

        可以看到__g._encrypt(encodeURIComponent(tt)) 实现了加密在里面

可以看到上面有很长的字符串,这个就是VMP加密在里面

VMP就是把你的JS代码转换成一长串的字符串,然后再通过switch....case进行还原一系列操作,今天的课题是属于一个简单的

10、往上找,很容易就会发现是一个webpack加密在里面

// webpack加载器
var fff;
!function (e){
    var h = {};
    function f(n){
    if(h[n])
        return h[n].exports;
    console.log('-->',n);
    var u=h[n]={
        i:n,
        l:!1,
        exports:{}
    };
    return e[n].call(u.exports,u,u.exports,f),
        u.l=!0,
        u.exports
    }
    fff =f;
}({
    //函数

})

11 、在另外的一个页面里面创建脚本

        这个错误是告诉你缺少模块,把需要的模块补上去即可

12、浏览器运行的已经出来了结构 

13、在nodejs环境中运行结构,就会发现是报错的 TypeError: __g._encrypt is not a function

        其实是缺少了浏览器环境导致js走错了

        这里我用的是jsdom补环境,需要安装jsdom这个库,直接调用npm命令就行了

npm install jsdom

14、再补上以下环境,需要自己把地址换了 

const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`,{url:"aHR0cHM6Ly93d3cuemhpaHUuY29tDQo="});
window = dom.window
location = window.location
navigator = window.navigator
document = window.document;
history = window.history;
screen = window.screen;

15、补完发现可以生成结果,但是带上这个参数的请求是拿不了数据的,还缺了环境 

16、回到浏览器里,可以发现多次加密同一组数据竟然结果不同,可能是时间戳,也可能是随机数,试着hook了一下随机数,发现结果不变了,证明是随机数的问题,可以在node里hook随机数再调试,直到出现和浏览器一样的结果

        会发现nodejs里面和浏览器加密出来的参数是不一样的

补环境

17、直接运行结果不一样,也没有任何提示,可以加上proxy代理再调试

proxy_ = function(func){
    return new Proxy(func,{
        set(target,property,value){
            console.table([{"类型":"set","调用者":target,"调用属性":property,"设置值":value}]);
            return Reflect.set(...arguments)
        },
        get(target,property,receiver){
            console.table([{"类型":"get","调用者":target,"调用属性":property,"获取值":target[property]}]);
            return target[property]
        },
    })
}

window = proxy_(window)
location = proxy_(location)
navigator = proxy_(navigator)
document = proxy_(document)
history = proxy_(history)
screen = proxy_(screen)

18、观察代理会发现Document的Symbol 浏览器里返回的是'[object HTMLDocument]',node里返回的是[object Object]

       浏览器

        

        node的

        

19 、可以在原型里修改这个方法

let ObjectToString = Object.prototype.toString
Object.prototype.toString = function () {
  if (this.constructor.name === 'Document') {
    return '[object HTMLDocument]'
  }
  return ObjectToString.call(this, arguments)
}

        在原型里面判断name是Document的话就返回[object HTMLDocument],其他的不变

20、可以发现补完document,但结果还是不对

21、安装canvas这个包

npm install canvas

22、 在刚才定义原型的方法里面添加

let ObjectToString = Object.prototype.toString
Object.prototype.toString = function () {
  if (this.constructor.name === 'Document') {
    return '[object HTMLDocument]'
  }
  else if(this.constructor.name === 'CanvasRenderingContext2D') {
      return '[object CanvasRenderingContext2D]'
}
  return ObjectToString.call(this, arguments)
}

23、再次运行会告诉你 _resourceLoader,浏览器里是undefined,把这个补上后再次运行

24、刚才那处已经过了,_sessionHistory,浏览器也是undefined,接着补上

25、global这里报错,node的全局变量是global,浏览器里面没有global,补一个alert = window.alert

26、__proto__还在出错,这里其实是再次对tostring进行了了检测,打印一下发现是大Window的问题

        补一个判断window的

let FunctionToString = Function.prototype.toString
Function.prototype.toString = function () {
if(this.name === 'Window') {
  return 'function Window() { [native code] }'
}
return FunctionToString.call(this, arguments)
}

27、运行一下就可以看见结构和浏览器一样啦 -->看16步操作

28、最后就可以记得把代码的hook随机数的删除

总结

        1、出于安全考虑,本章未提供完整流程,调试环节省略较多,只提供大致思路,具体细节要你自己还原,相信你也能调试出来.

        2、本人写作水平有限,如有讲解不到位或者讲解错误的地方,还请各位大佬在评论区多多指教,共同进步

        3、如果这篇文章对你有帮助,就点赞、关注、收藏、三连击一下

        4、本篇分享到这里就结束了,欢迎大家关注下期,我们不见不散☀️☀️😊

评论 45
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值