当前位置: 首页 > 后端技术 > Node.js

JS逆向补偿环境详解Ruishu

时间:2023-04-03 20:12:58 Node.js

JS逆向补偿环境OverRuishu详解“Ruishu”是逆向路上的一座大山,是很多JS逆向者无法避开的一堵墙,也是一份跳槽简历一个亮点,下次跳槽前一定要克服!!好在网上有很多讲解睿数的文章,一步步教我们分析睿数的过程,如何推演睿数逻辑,试图教给我们(手动狗头)。但是,很少有文章详细说明如何通过纯补环境来过睿树。今天,它来了!为了让大家彻底搞定睿书大哥,本文将从以下四个部分进行讲述:简单探讨rs的流程逻辑。坐好开始吧!*注:本文内容取材于一个对新手友好的rs4网站:以在线房产为例;*1:我们在逆向rs的流程逻辑的时候,首先要分析哪些加密参数需要逆向,然后去Invert这些参数。当然,瑞书也是如此。所以我们第一步明确反向目标:现象:rs上的网站会请求page_url两次,第二次请求page_url才能获取到正确的页面内容;分析:分析请求体,发现第二次请求page_url时带上了cookie_s和cookie_t,cookies_s来自于第一次请求page_url时设置的响应头;结论:那么我们的目标就确定了——破解cookie_t的生成逻辑;现在,我们知道我们需要反向加密的参数是cookie_t,那么cookie_t从何而来呢?我们先来分析网站的请求。睿数网站请求流程分析:第一次请求:请求page_url,响应状态码202,响应头中设置cookie_s;响应主体是HTML源代码从上到下可以分为四个部分:让我先破坏它们的功能。一个meta标签,内容很长,而且是动态的(随着每次请求而变化),会在执行第二层JS的eval代码中用到;一个外链js文件,一般它的内容固定在同一个页面,下面的自执行函数会解密文件内容,生成eval执行所需的JS源代码,也就是第二层vm代码;一个大的自执行函数执行函数(每次请求都会动态改变首页),主要是对外部链接的JS内容进行解密,给window添加一些属性比如$_ts,在里面会用到虚拟机;最后两个脚本标签中的函数调用将更新cookie,使其更长。我们可以在这里忽略它。第二个请求:请求外链js,一般内容固定;第三次请求:请求page_url,返回200,并携带cookie_s、cookie_T进行正常请求;那么我们在浏览器中访问网站时发生了什么?什么值得我们关注?让我们手动模拟浏览器加载page_url源代码时发生的情况:浏览器加载meta;浏览器请求外部链接js并执行js内容;执行page_url源码自执行函数,内部将外部链接js解密成eval需要的所有行js字符串,并在window.$_ts中添加大量属性,然后调用eval函数进入VM执行解密js,生成cookie,执行完eval后,继续执行自执行函数;最后执行script标签中的代码,这些代码会更新cookie_t(可以忽略),执行setTimeout和eventlistener回调函数(可以忽略)。Ruishu的执行流程图如下:这里需要注意eval调用的位置(也就是VM的入口)和cookie生成的位置。注意:浏览器v8调用eval执行代码时,会开启一个虚拟机(VM+号)执行JS代码。我们可以直接hookeval或者搜索.call来定位调用eval的位置_$Ln是解密后的js代码串;进入vm是一个自执行函数,里面有生成cookie的逻辑,定位cookie可以直接hook或者在Search(5)vm代码中hookcookie代码://hook指定cookie赋值(function(){'usestrict';Object.defineProperty(document,'cookie',{set:function(cookie){if(cookie.indexOf("FSSBBIl1UgzbN7N80T")!=-1){debugger;}returncookie;}});})();好了,以上就是睿数的整体流程逻辑,那么我们如何通过推码生成cookie_t多少呢?2.说说扣码通过睿数。由于瑞书page_url的源码每次都是请求的,VM代码也是动态变化的,所以我们需要保存一个静态代码,方便调试;直接如图,修复page_urlresponse没错,这样请求的时候,page_url中的外部链接JS是固定的,自执行函数是固定的,VM中的代码也是固定的,所以是这个固定码每次生成的cookie_t也是固定的?答:不是,因为cookie_t的生成使用了随机数和时间戳,我们hook了这两个变量,最终生成的cookie_t是固定的。至此,我们就可以开始推导这段静态代码了。如果节点生成的cookie_t与浏览器执行静态代码生成的cookie_t一致,则表示推演成功。扣除代码需要扣除两部分,page_url源代码部分和VM中生成的cookie_t部分。根据我们之前的分析,VM中的代码会使用到window.$_ts,所以首先要保证从page_url源码中推导出来的代码在执行到eval时能够正常生成window.$_ts。我们先扣除page_url的自执行函数和外链的JS内容,先扣除meta内容,然后根据执行报错简单补充一下环境,这样扣除的代码执行到eval的时候,它的window.$_ts和解密后的VMJS代码和本地静态代码生成的是一样的。也就是说我们已经扣掉了page_url源码部分,接下来可以扣掉VM中生成cookie_t的部分。上面我们分析了cookie的定位,可以知道二级cookie_t是在函数_$bO中生成的,那么这就是我们推演代码的起点,推演这个函数到文件末尾,执行直接,然后补上缺的。在使用BOM和DOMapi的代码时,我们可以将其替换成等价的逻辑。比如这里原来的逻辑是获取meta标签中的content内容,然后删除meta标签。我们可以直接用returnmeta_content等价替换。如图:如果node生成的cookie_t在扣完最后和本地静态代码生成的不一致,说明我们扣的部分代码没有通过环境检测。我们可以根据node和浏览器执行的不同来定位。比如当node执行到某个地方的值和浏览器执行静态代码得到的值不一样,说明前面的逻辑有区别。继续往前走,重复这个过程,找到所有缺失的环境检测,完成VM部分的推演。至此,我们已经完成了静态rs代码的推演并成功了,但是rs网站的代码是动态的。每次发出请求时,window.$_ts和VMjs都会发生变化。我们必须扣除每份吗??不,事实上,我们现在离真正的成功只有一步之遥。VM的几万行js代码虽然每次都会变,但只有变量名变了,其他都不变。映射是将动态window.$_ts中的属性名与我们一一扣除的VM中JS使用的window.$_ts中的固定属性名进行匹配。所以在推导的过程中,我们需要注意在VM中哪里使用了外部变量(即函数中的哪个变量来自其他作用域,即使是外部变量),我们需要注意这些外部变量是从哪里来的,如果是VM自执行函数中定义的,那就不用管了。如果是来自window.$_ts,需要记录一下,也就是需要映射的地方。这里的计算逻辑使用了window.$_ts._$IK,所以我们做映射的时候需要传入这个值;window.$_ts={_$IK:对应的动态属性名}求解映射,成功推导代码通过rs。好了,推演代码就到此为止,接下来才是我们本文的重点。3.补偿环境Passrs详解不知道补充环境原理的同志可以参考我之前的文章:JS逆向中浏览器补充环境详解;其实纯辅环境通睿数的原理很简单。我们观察瑞书的执行流程图。根据浏览器环境执行这些动态的JS,可以生成可用的cookie_t。所以只要我们补充的浏览器环境足够完善,使得在这些动态JS的视图中,我们补充的环境===浏览器环境,那么我们补充的环境执行这些动态JS,也可以生成可用的cookie_t,然后我们通过document.cookie提取cookie_t就更好了。在伪代码中,它是://Supplementedenvironmentheaderwindow=this;...省略大量的环境头//模拟元标签及其contentdocument.createElement('meta');Meta$content="{qYnKTJPAw84QfF5jm0I2_1IqhgTvRw8Y0yCBPxIVn6od8AeJE6CBz8ZSU6U...Omitted";//固定外部链接js$_ts=window['$_ts'];if(!$_ts)$_ts={};$_ts.scj=[];$_ts['dfe1675']='tt+...omit';//page_url动态自执行函数(function(){var_$CK=0,_$WI=[[9,3,6,0,4,1;...ret=_$su.call(_$fr,_$WR);很长...省略}}}}}}}})();//获取cookiefunctionget_cookie(){returndocument.cookie;}//获取MmEwMD参数函数get_mme(){{XMLHttpRequest.prototype.open("GET","http://desensitization/",true);returnXMLHttpRequest.prototype.uri;}}这个就是我们要在最后添加的生成的文件貌似Meta$content和page_url动态自执行函数是动态变化的,所以每次请求page_url的时候都需要使用正则表达式将这两个字符串提取出来,然后拼接到文件中,然后pythonpyexecjs调用get_cookie就可以得到可用的cookie_t;上面推导代码中提到,由于生成cookie_t操作涉及到随机数和时间戳,所以改变了同样静态JS代码生成的cookie_t。我们可以通过hooks让时间戳和随机数是固定的,这样同一个静态JS生成的cookie_t也是固定的。//固定随机数和时间戳Date.prototype.getTime=function(){return1672931693};Math.random=function(){return0.5};我们也可以通过最终生成的cookie_t来判断,我们自己搭建的环境是不是===浏览器环境。原理很简单,接下来就是如何实践了。我们需要补一个完善的环境头,让这个静态JS执行得到的cookie_t和浏览器得到的保持一致。由于环境打补丁是一项系统性的工作,有一定的套路,所以我们可以使用上一篇文章中提到的打补丁环境框架来系统地打补丁。我们需要做的是根据日志输出和出现的问题不断完善框架。如图,启动框架,上面是我们添加的环境头,下面是我们扣除的代码,继续调试,当我们的Proxy拦截器拦截到BOM和DOMapi的使用,就会debugger,我们可以根据调用栈去查看哪一行代码使用了浏览器环境,然后看框架中的模拟结果是否与浏览器一致。如果没有,你需要弥补这个环境。如此往复补充环境,直到最后可以生成cookie_t,判断是否与浏览器生成的本地一致,如果不一致,则使用二分法定位,看哪个浏览器环境没有被修正,直到最后得到正确的cookie_t,贴在这里看一下最后的执行效果图:这是最后打印的部分环境检测点:这是最后取出的cookie_t:同理,MmEwMD参数的补环境也是同样的逻辑,在环境头完善的情况下,在python中执行final结果文件,可以得到如下结果:4.补充环境和推演代码总结:对于js逆向,这是两种常规实用的方法,各有千秋的优点和缺点;无论使用哪种方式,我们都会先从网站中扣除加密后的JS代码,然后选择是否继续扣除代码,逻辑上更换使用的浏览器环境api;或者使用辅助环境,让加密后的JS代码看起来运行在浏览器环境中。推演代码和补环境都看JS的熟练程度,推演代码更侧重于js语法和代码逻辑,补环境更侧重于原型链和BOM、DOM对象的模拟。代码推演熟练度靠逆向经验,补充环境几乎只靠JS熟练度。推演代码需要调试跟踪很多逻辑。对于rs,如果你不混淆它,你的屁股就会长痔疮;推演代码需要替换环境检测逻辑,所以你也需要知道浏览器环境在哪里使用;辅助环境框架只能用于监控浏览器环境的使用,可以作为代码推导的辅助工具。由于瑞书是动态的,推演代码只能推演一个静态的,所以需要找到vm中使用的所有动态属性进行映射。补环境是通用的,补的越多,能杀的网站就越多。推导代码比补充环境更有效。毕竟补充环境的代码数量远大于推演代码,可以通过剔除不需要的环境来缩小差距;人工扣码耗时远高于辅助环境。总而言之,代码推演重在js语法和代码逻辑,熟练程度靠逆向经验。不同网站的扣法不同,难以通用,劳动效率低,但程序执行效率高。补充环境侧重于原型链和浏览器环境模拟,熟练程度几乎只依赖于对JS原理的掌握。对不同网站补充的越多,能杀的网站就越多。人工效率极高,但程序执行效率不高。5、弯道超车段超瑞树几乎是每个新手逆势的小目标,也是面试官常问的问题。通过这篇文章,我们了解了睿数的流程和破解思路。接下来,我们可以尝试从头实现一个完整的补充环境框架,去纯环境黑盒传睿书,但这需要很长时间才能完成。开发,有很多重复性的工作很无聊(复制粘贴比较等)。走快车道:本文这一版的补充环境框架是在上一篇框架的基础上系统改进的。目前可以说是比较完善了,补充了很多环境。如果想节省时间,大大提高效率,弯道直接超车,可以微信联系我:dengshengfeng666付费源码参考;春节优惠价199(节后恢复统一定价233),付款后直接发框架项目源码(附最新图片文字readme小白可直接使用),如有以后有问题可以直接问我。或者直接在CSDN私信我。本版本与上一版本的改进:优化Proxy13个拦截器,实现Proxy的极限,并启用递归代理,支持a.b.c.d.e...级别深度检测;完善最终结果file.js的调用机制,使其无需改动,可直接用于V8和node调用;添加一些BOM和DOM对象,如:XMLHttpRequest、XMLHttpRequestEventTarget等;完成rs使用的所有浏览器环境方法,使其可以在黑盒中传递rs;优化调试方式,想断点就断点,不想断点就跳过检测;添加py直接调用结果文件case,可以用python用v8和node调用;优化readme,图文介绍环境配置和使用。弯道超车,从我做起,这个版本的框架目录: