赞
踩
JS逆向的主要思路一般有这几种
1,利用AST反混淆,因为用的就是AST混淆的,所以理论上应该都能用AST再返回去。但是实际操作好像不容易。
2,跟值,一步一步找到加密方法和密钥。现在很多混淆方法,把一句代码变成了1万句(这个没夸张,我遇到好几个,虽然不知道原来的代码量是多少,反正实际运行了几十万行,浏览器竟然也很流畅),再利用一些平坦流的写法,让你无法跟值。
3,完全就不用去逆向,直接搞个浏览器(为了提高效率,可以用无头浏览器),真实的去运行就行了,最后用一些手段得到加密的结果。
为了防御方案3,又有2种方法:1)浏览器指纹;2)判断环境是什么
获取到方案3的浏览器环境指纹,如果这个指纹提交了过多的数据,那么这些数据就都是异常的。
知道方案3用的是什么环境,比如python的selenium,只要是这个,那就都判定为异常。
针对方法1,可以用指纹浏览器,每次都是不同的指纹。
针对方法2,只要知道对方是根据什么判断出是selenium,相应的属性干掉或者补充就行了。
但问题是,指纹的获取和selenium的判断,你怎么知道是什么。
指纹的获取和selenium的判断,本质就是一组js代码,但是这组js代码是什么,是没法确定的,通常只能是百度搜一下,把搜到的都做相应的处理,但是别人可能还根据什么做了判断,就无法得知了。
比如PC端的B站注册,用了fingerprint获取指纹,不管你通过什么方式,实现了fingerprint获取到的指纹每次都不同,但是你会发现,注册的B站账号,还是异常,说明B站检测到了你这个注册途径不正常(每次注册IP肯定会换的,已经排除掉了这个检测的可能)。
这时候,就需要补环境框架了。
js代码简单的说是3部分组成,V8(js最核心的代码,可以简单的理解为js官方发布的),BOM(浏览器实现的js代码,比如alert,比如xmlHttpRequest),DOM(页面节点,节点对应的js方法,也是浏览器自己实现的)。不管是指纹或者判断selenium的代码,基本都在BOM和DOM中。
很多语言都有运行js代码的功能,本质就是调用V8。所以就产生了一种思路,如果我把混淆的js代码放在V8里跑,因为没有BOM和DOM的方法,如果有用到了相关函数,那就会报错,一旦报错了,不就知道这个js代码判断了什么东西了。
以判断selenium的方法window.navigator.webdriver为例,说下js补环境框架下如何知道对方是怎么检测的。
首先,V8环境是没有navigator的,所以需要我们先自己定义,然后挂上代理,此时运行“window.navigator.webdriver”,就能监听到代码有在获取navigator的webdriver属性。
- //*******************这部分是框架代码***************************
- var navigator={};
-
- window.navigator=new Proxy(window.navigator, {
- set(target, property, value) {
- console.log("proxy set", target, property, value);
- return Reflect.set(...arguments);
- },
- get(target, property, receiver) {
- console.log('proxy get:',target,property);
- return target[property];
- }
- });
- //*******************这部分是框架代码***************************
-
-
- //***这是混淆的js代码(当然为了说明问题自然就没混淆)**********
- console.log(window.navigator.webdriver);
- //***这是混淆的js代码(当然为了说明问题自然就没混淆)**********

补环境的基本思路就是这样,看着很简单,但问题是,你既然能想到这么做,人家也能想到,那么人家可以用一些方法,去检测你是不是补环境框架。
比如,我们刚才定义的navigator,就是个普通的对象,但是真实的navigator,是有原型为Navigator的对象。你在控制台里测试这句代码,会得到这么个结果,这个在我们自己的代码里可没有。
- console.log(navigator.__proto__[Symbol.toStringTag])
- "Navigator"
所以相对完善一点的定义navigator代码,应该是这样。
- var Navigator = function Navigator() {
- throw new TypeError("Illegal constructor");
- };
-
- Object.defineProperties(Navigator.prototype, {
- [Symbol.toStringTag]: {
- value: "Navigator",
- configurable: true
- }
- });
-
- Navigator.prototype.userAgent="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36";
-
- navigator = {};
- navigator.__proto__ = Navigator.prototype;
-
- for (var property_ in Navigator.prototype) {
- navigator[property_] = Navigator.prototype[property_];
- Navigator.prototype.__defineGetter__(property_, function () {
- throw new TypeError("Illegal constructor");
- });
- }

首先,先定义一个Navigator,这个是不能被new的。
然后,定义Navigator原型上的Symbol.toStringTag
然后,把Navigator的属性否赋值给navigator,此时还有个点需要注意,不能直接从Navigator上获取属性。
再比如navigator.plugins,这是指纹用到的检测浏览器插件,这个东西你在控制台里看的话,在内部无限循环。如果你模拟出来的不是这样的,就很容易被检测出来。
最近跑一个混淆的js代码,第一次开始研究这个东西,自认为有几个点比较难(大佬应该觉得是浮云),在此记录一下
1,事件的监听与触发,也可以说是Event的重写
2,webrtc的重写,要自己实现这个,还得解决promise
3,XMLHttpRequest的重写
4,plugins里无限嵌套
5,toString的检测,在控制台里对原生函数执行toString,得到是这么个结果“function alert() { [native code] }”,如果alert是我们自己定义的,就不是这个结构了。有一次偶然,对toString进行监听,发现有个混淆的js代码,输出了这样的字符串"function get cancelBubble() { [native code] }",直接蒙了,完全不知道怎么能得到这样的结果。研究了4,5天吧,每天下班回家搞2小时,最后终于发现了端倪。
最后再说一下,有了补环境框架,基本上也就实现了指纹重写,因为都知道了检测的是什么了,只需要把对应的js代码拿出来,在selenium跑一下就行了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。