当前位置: 首页 > 后端技术 > Python

【100ExamplesofJSReverseEngineering】Introductiontoanti-obfuscation,APengEducationJSobfuscationrestoration

时间:2023-03-26 18:47:56 Python

FollowWeChat公众号:BrotherKcrawler,continuetosharetechnicaldrygoodssuchascrawleradvancement,JS/Androidreverseengineering!Itisdeclaredthatallthecontentinthisarticleisforlearningandcommunicationonly.Thecapturedcontent,sensitiveURLs,anddatainterfaceshavebeendesensitized,andarestrictlyprohibitedfrombeingusedforcommercialorillegalpurposes.Otherwise,allconsequencesarisingtherefromhavenothingtodowiththeauthor.Infringement,pleasecontactmetodeleteimmediately!逆向目标目标:某鹏教育登录接口加密,含有简单的JS混淆主页:aHR0cHM6Ly9sZWFybi5vcGVuLmNvbS5jbi8=接口:aHR0cHM6Ly9sZWFybi5vcGVuLmNvbS5jbi9BY2NvdW50L1VuaXRMb2dpbg==逆向参数:FormData:black_box:eyJ2IjoiR01KM0VWWkVxMG0ydVh4WUd...逆向过程本次逆向的目标同样是一个登录接口,TheencryptedJSusessimpleobfuscation,whichcanbeusedasanentry-leveltutorialforobfuscationrestoration.Whenyoucometotheloginpage,enteryouraccountpasswordtologin.InthePOSTrequestforlogin,FormDatahasanencryptedparameterblack_box,whichisthistimeThereversegoal,packetcaptureisasfollows:directlysearchblack_box,youcaneasilyfindtheencryptedplaceinlogin.js,asshowninthefigurebelow:lookatthemethod_fmOpt.getinfo(),whichcallsOO0O0infm.js()method,seethatthisis0andO,itismostlyconfused,asshowninthefigurebelow:clickinandhavealook,thewholefm.jsisobfuscatedcode,weselectthecodesimilartoOQoOo[251],youcanseeItisactuallyastringobject,andyoucandirectlyoutputitintheConsoletoseeitsactualvalue.TheoOoo0[OQoOo[448]](JSON[OQoOo[35]](O0oOo[OQoOo[460]]returnedbythisOO0O0method)),whichisthevalueofblack_box,asshowninthefigurebelow:ifyouobservecarefully,youcanfindthatOQoOoshouldbesomethinglikeanarray,andyoucangetitsrealvalueinturnbypassinginthesubscriptoftheelement,andyoucansearchforavalueattheendofthecodeFindanarray,thisarrayisactuallyOQoOo,youcanpassinthesubscripttoverifyit,asshowninthefigurebelow:hereweactuallyknowthegeneralconfusionprinciple,wecantakedownthisJS,writeasmallscriptlocally,Replacethesevalues:#===================================#--*--coding:utf-8--*--#@Time:2021-11-09#@Author:WeChat公众号:K爬虫哥#@FileName:replace_js.py#@Software:Pycharm#@Describe:混淆还原小脚本#===========================#太多了,只列出几个)#以实际列表为准,与fm_old.js中的列表一致item=['referrer','absolute','replace',...]#ConfusedJSwithopen("fm_old.js","r",encoding="utf-8")asf:js_lines=f.readlines()js=""forjinjs_lines:js+=jforiinitem:#Qo00orequired根据你的fm_old.js具体替换stringstr_old="Qo00o[{}]".format(item.index(i))js=js.replace(str_old,'"'+i+'"')#恢复下面的JSwithopen("fm_new.js","w",encoding="utf-8")asf:f.write(js)使用这个脚本替换之后,你可能会发现JS会因为一些换行,斜杠解析错误,而报错重复使用双引号的问题,可以自己手动修改。fm.js后面有个后缀,类似t=454594,t=454570等,不同后缀得到的js内容也不同。各种函数的变量名和列表元素的顺序是不同的。其实调用方法都是一样的,所以影响不大。替换的时候只需要注意列表的内容,需要替换的字符串,下载的JS文件即可。可以是一致的。还原后的JS,我们可以用还原后的JS替换网站本身混淆后的JS。这里的替换方法有很多,比如使用Fiddler等抓包工具替换response,使用ReRes等插件替换,使用浏览器开发者工具自带的Overrides功能替换(一个功能只有Chrome64之后可用)等。这里我们使用Fiddler的Autoresponder功能来代替。实测fm.js的后缀短时间内是不会变的,所以可以直接复制它的完整地址来替换。如果想要更严谨一点,我们可以使用正则表达式来匹配这个t值,在Fiddler中选择AutoResponder,点击AddRule,添加替换规则,正则表达式的写法如下:regex:https:https:\/\/static\.tongdun\.net\/v3\/fm\.js\?t=\d+,注意regex前缀是必不可少的,选择Enablerules(应用规则),AcceptallCONNECTs(接受所有连接),Unmatchedrequestspassthrough(不匹配规则则按照之前的请求地址发送),EnableLatency是设置延迟生效时间,不要勾选,如下图:登录再次替换后,并设置断点。可以看到现在的JS清晰多了。查看此函数末尾的return语句。oQOQ0["blackBox"]中包含了它,os,t,v三个参数,使用JSON的stringify方法将其转化为字符串,然后调用QQo0方法进行加密,如下图:我们先来看oQOQ0["blackBox"]中的四个参数,其中,os,v,v三个参数在这个函数的开头就已经定义好了。v为Q0oQQ["version"],为固定值。可以发现这个值在一开始的大列表中,os是固定值,是固定值。两个时间戳相减的值,O000o这个方法是两个值相减,oQOQo这个时间戳可以搜索varoQOQo,是开始加载时生成的时间戳,JS开始加载,点击登录进入加密函数,大约是一分钟,所以这里我们可以直接生成一个五位数的随机数(一分钟左右的毫秒数相差五位数左右)。现在只剩下一个t参数了。往下看,t其实就是Q0oQQ["tokens"],中间经过一个if-else语句后,可以埋断点调试,发现实际上只执行了else语句,t被赋值了这个是唯一一句,所以在推导的时候其实可以把剩下的代码删掉。令牌经过多次测试,发现没有变化。尝试直接搜索token关键字,可以找到赋值的地方,按照|划分idsymbol,取第一个index值作为token,再看id的值,没有发现明显的生成逻辑,复制它的值查找,发现是通过一个接口返回的,可以直接写死,也可以先请求这个接口,取返回值,如下图:找到所有参数后,回到原来的返回位置,还有一个加密函数,即ooOoO["encode"](),直接跟进,就扣这个方法,弥补本地调试的缺失。使用的功能已经完成。完整代码GitHub关注K哥的爬虫,持续分享爬虫相关代码!欢迎加星!https://github.com/kgepachong/下面只是演示了部分关键代码,不能直接运行!完整代码仓库地址:https://github.com/kgepachong...JavaScript加密密钥代码结构}functionQo0oo(Q0o0,o0OQ){返回Q0o0|o0OQ;}functionOOO0Q(Q0o0,o0OQ){returnQ0o0<