js逆向案例-猿人学比赛题(中等及以下难度的)

目录

        • 1、注意
        • 1、js混淆-源码乱码尝试hook window属性
        • 2、js混淆-动态cookie
        • 3、请求头顺序与请求规律检测
        • 4、css样式style偏移干扰
        • 5、js混淆-用hook定位与埋坑
        • 6、js混淆回溯
        • 7、woff动态字体编码
        • 12、入门级js
        • 13、入门级cookie
        • 15、了解wasm
        • 16、了解webpack打包js与window埋坑
        • 17、了解http2.0协议
        • 19、了解tls指纹

1、注意

  • 暂时只做了中等及以下难度的题目,困难及以上以及app的等后面有时间继续研究(8、9、10、11、14、18)
  • js逆向是一个极其考验细心与耐心的活:因为马虎常常因为一个小细节导致流程错误
    • 比如js扣的没有考虑到运算符优先级未加括号导致运算错误(其它网站)
    • 2题超大的混淆,要么ast,要么慢慢扣
    • 5题警惕try catch,以及全局变量,尤其window的全局变量,我们会发现有些值写死是不可以的,所以要仔细研究下
    • 6题url请求参数采用拼接的方式会出错,get请求参与用params传或者用urlencode请求参数也可以;另外此题用node调服务请求js可以,但是用其它包执行js就不行,是因为一个全局变量与页码绑定的原因,我没找到
    • 13题url链接http少加了s,导致后两页爬取失败
    • 16题扣js由于全局函数放置位置与局部变量冲突影响,导致生成的加密参数错误(webpack一个模块一个作用域的对应扣)
  • 第2题、第5题可以用来练一练ast解混淆,由于ast还不熟,所以硬扣了

1、js混淆-源码乱码尝试hook window属性

  • ① 反爬点:请求参数m加密
    js逆向案例-猿人学比赛题(中等及以下难度的)_第1张图片
  • ② 定位加密:调用栈回溯法
    js逆向案例-猿人学比赛题(中等及以下难度的)_第2张图片js逆向案例-猿人学比赛题(中等及以下难度的)_第3张图片
  • _0x57feae是m加密关键参数之一,分两部分,其中第一部分返回时空串,所以只需要看第二部分window[“f”]是什么
    在这里插入图片描述
    js逆向案例-猿人学比赛题(中等及以下难度的)_第4张图片
  • hook的window的属性f,如在console界面输入如下,hook后看堆栈往前回溯直接找到源码window.f,把代码全部扣下来即可
    Object.defineProperty(window, 'f', {
            set: function(val) {
                console.log('Setting window.属性', val);
                debugger ;
                pre = val;
            }
        })
    
    js逆向案例-猿人学比赛题(中等及以下难度的)_第5张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第6张图片
  • ③ 解决方案如下:
    js逆向案例-猿人学比赛题(中等及以下难度的)_第7张图片

2、js混淆-动态cookie

  • ① 反爬点:cookie里面的m参数加密
    js逆向案例-猿人学比赛题(中等及以下难度的)_第8张图片
  • ② 定位加密:用油猴脚本hook cookie,然后堆栈回溯扣代码
    js逆向案例-猿人学比赛题(中等及以下难度的)_第9张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第10张图片
  • 扣代码方式采用手动翻译(不会ast的话,或者搞ast本身也需要很长时间)
    js逆向案例-猿人学比赛题(中等及以下难度的)_第11张图片
  • 然后主函数扣代码如下,接下来就找_0x313b78函数,按缺啥补啥的方式扣,挺费时间的,慢慢来
    js逆向案例-猿人学比赛题(中等及以下难度的)_第12张图片

3、请求头顺序与请求规律检测

  • ① 反爬点:请求头顺序问题,以及必须请求一次jssm后再请求另一个请求
    js逆向案例-猿人学比赛题(中等及以下难度的)_第13张图片
    在这里插入图片描述
  • ② 解决方案:如下请求头顺序,采用session.headers=headers的方式保留请求头顺序
    js逆向案例-猿人学比赛题(中等及以下难度的)_第14张图片

4、css样式style偏移干扰

  • ① 反爬点:css样式偏移,-11.5/11.5=-1代表当前标签需向左偏移1位,34.5/11.5=3代表当前标签需向右偏移3位
    js逆向案例-猿人学比赛题(中等及以下难度的)_第15张图片

  • ② 定位加密:堆栈回溯法找到需要删除的display干扰图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第16张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第17张图片

  • ②解决方案:代码如下
    js逆向案例-猿人学比赛题(中等及以下难度的)_第18张图片

5、js混淆-用hook定位与埋坑

  • ① 反爬点:cookie加密RM4hZBv0dDon443M ,如果不懂hook,可以先看这篇文章关于hook的一些介绍
    js逆向案例-猿人学比赛题(中等及以下难度的)_第19张图片

  • hook脚本注意事项:再未生成之前下hook,由于本案例代码逻辑都在vm里生成,所以我们通过堆栈找到一个vm入口处的位置,然后再进入vm自执行的第一行里下hook即可正确hook

  • 本案例如何正确hook,先在eval($_ow);处打断点,然后刷新网页停在了eval处,然后进入连点两次F11进入vm的第二行,然后下hook,然后放运行,即可hook住打印结果,下面看正式解密逻辑
    js逆向案例-猿人学比赛题(中等及以下难度的)_第20张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第21张图片

  • ② 解决方案:打开控制台,一直打印console.log,我们可以先置空下 js逆向案例-猿人学比赛题(中等及以下难度的)_第22张图片

  • hook cookie,打开油猴脚本hook cookie(也可按我开始讲的方案下hook),如下定位到
    js逆向案例-猿人学比赛题(中等及以下难度的)_第23张图片

  • hook到cookie后调用栈回溯,发现其实是_0x4e96b4[’_KaTeX parse error: Expected group after '_' at position 20: …(控制台打印下是window._̲ss)
    js逆向案例-猿人学比赛题(中等及以下难度的)_第24张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第25张图片

  • hook之window属性_$ss
    js逆向案例-猿人学比赛题(中等及以下难度的)_第26张图片

  • hook的window后调用栈回溯,我们发现是_0x29dd83['toString']()生成
    js逆向案例-猿人学比赛题(中等及以下难度的)_第27张图片

  • 复制到本地手动翻译上面混淆的js逻辑如下,,通过这段可以发现是aes的ecb模式加密,key是取得时间戳的前16位, 加密的明文是pr.toString()而得,我们先把这部分逻辑写好,接下来找_0x4e96b4['_$pr']就行了、 _0x4e96b4['_$qF']
    js逆向案例-猿人学比赛题(中等及以下难度的)_第28张图片

    'R' + 'M' + '4' + 'h' + 'Z' + 'B' + 'v' + '0' + 'd' + 'D' + 'o' + 'n' + '4' + '4' + '3' + 'M=' + _0x4e96b4['_$ss'] + ';\x20path=/'
    _0x29dd83[_$UH[0x1f]]()
     _0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8'][_$UH[0xff]](_0x4e96b4['btoa'](_0x4e96b4['_$is'])['slice'](0x0, 0x10));
    _0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8']['parse'](_0x4e96b4['btoa']('1637767804235')['slice'](0x0, 0x10));  
    _$Ww = _$Tk['enc']['Utf8']['parse'](pr['toString']()),                           _
    _0x29dd83 = _$Tk['AES']['encrypt'](_$Ww, _0x4e96b4['_$qF'], {
        'mode': _$Tk['mode']['ECB'],
        'padding': _$Tk['pad']['Pkcs7']
    })
    _0x29dd83['toString']()
    
  • 搜索下_0x4e96b4['_$qF']找到了,即取得是时间戳的前16位,这个即aes的ecb的key,也是url请求参数的m时间戳
    js逆向案例-猿人学比赛题(中等及以下难度的)_第29张图片

  • 然后我们先简单写下现有的js逻辑,接下来只要找到明文pr生成逻辑就行了
    js逆向案例-猿人学比赛题(中等及以下难度的)_第30张图片

  • 而明文pr其实在前面我们hook,cookie打印的时候就会发现,pr就是前面连续hook的cookie组成的
    js逆向案例-猿人学比赛题(中等及以下难度的)_第31张图片

  • 刷新重新hook cookie ,找pr里面的元素生成逻辑,接下来只要扣 _0x474032这个函数即可生成pr,注意pr有5个值,前四个值生成逻辑是在这里_0x474032(_$Wa) ,第五个值的生成逻辑在_0x474032(_$yw)这里,第5个值的时间戳不仅是pr的元素,也是url请求的参数m,同时还是aes加密的key参数
    js逆向案例-猿人学比赛题(中等及以下难度的)_第32张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第33张图片

  • 剩下的扣_0x474032函数,该函数按缺啥补啥的直接扣就行,其中有一个函数需要注意改下_0x11a7a2(_0x193f00, _0x1cfe89),跟着浏览器调试发现走的是固定的流程,所以我们直接注释掉一些代码,并写死某些值,_0x4e96b4是window变量,所以我们还定义一下它_0x4e96b4= window = {}
    js逆向案例-猿人学比赛题(中等及以下难度的)_第34张图片

  • 除上面写死的一些值之外,_0x11a7a2(_0x193f00, _0x1cfe89)该函数还用到3个关于window的变量(如_0x4e96b4['_$Jy']),pr的5个时间戳每次加密时,我们都需要关注下这3个变量,看是否一致,由于本次js只校验了pr参数的最后一个加密值,所以我们直接复制第5次加密值生成的这三个参数写死即可_0x4e96b4['_$Jy']
    js逆向案例-猿人学比赛题(中等及以下难度的)_第35张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第36张图片

  • hook之 _0x474032 函数观察一下_$Jy,_$tT,_$6_,确实每次加密都有所变化,但是由于只检测了最后一个,所以js里面这3个参数写死即可

    (function hook_0x474032() {
        var n_0x474032 = _0x474032;
        _0x474032 = function (e) {
            var ret = n_0x474032(e);
            console.log('>>>>>_$Jy',_$Jy,'_$tT',_$tT,'_$6_',_$6_,"加密前:", e, "加密后:", ret);
            return ret;
        }
    })();
    

    js逆向案例-猿人学比赛题(中等及以下难度的)_第37张图片

  • 最终代js码如下
    js逆向案例-猿人学比赛题(中等及以下难度的)_第38张图片

6、js混淆回溯

  • ① 反爬点:请求参数的m和q
    js逆向案例-猿人学比赛题(中等及以下难度的)_第39张图片
  • ② 定位加密:堆栈回溯,本来以为是简单的rsa,但是找到公钥试了之后并不行,所以还是扣js了
    js逆向案例-猿人学比赛题(中等及以下难度的)_第40张图片js逆向案例-猿人学比赛题(中等及以下难度的)_第41张图片
  • 进入r函数后,把delect.js全部复制下来,注释掉location.reload()代码,直接运行报错window.o = 1(其实是颜文字那一部分,由于没有用直接注释掉)
    js逆向案例-猿人学比赛题(中等及以下难度的)_第42张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第43张图片
  • delect.js这个文件里面最前面加了颜文字js混淆,解决方案,颜文字混淆本身是一个自执行函数或者是eval函数,该案例自执行找到表示括号的颜文字删除,在console界面可直接打印出结果,由于这行代码在全文中并没有调用,所以直接注释
    js逆向案例-猿人学比赛题(中等及以下难度的)_第44张图片
  • 继续运行,报错ASN1.prototype.getHexStringValue,浏览器中调试ASN1是有结果的,但是本地未定义,原因看下面
    js逆向案例-猿人学比赛题(中等及以下难度的)_第45张图片
  • 在js的最开始,网站埋坑,首先了解一些js基础知识点:① JavaScript中, var声明的变量默认绑定到window对象上 (全局对象),window的属性变量可直接作为全局变量使用, ② 在Node中全局变量则为global,类似于浏览器的window对象,但要注意在使用时要谨慎处理,如果滥用则很可能引起变量污染
  • 所以当埋坑直接把window={}置空,在浏览器这行代码并不能强制把window置空,所以浏览器window作为全局变量一直存在;但是到本地时window={}就生效了,所以我们这里直接修改window = global;解决
    js逆向案例-猿人学比赛题(中等及以下难度的)_第46张图片
  • 继续运行报错Message too long for RSA,按上面找问题的思路同样的方法调试会发现是,浏览器上直接打印发现返回是false,所以我们这里也直接改掉,之后就运行正常了
    在这里插入图片描述
    js逆向案例-猿人学比赛题(中等及以下难度的)_第47张图片
  • 继续,我们用execjs调用的时候会报些编码错误,所以介绍一个python新的调用js的库pip install node_vm2,js当中这样写就行module.exports = {get_m:r},pyhon如下调用即可
    from node_vm2 import NodeVM
    
    
    def get_m(temp_time, page):
        with open("./match_6.js", "r", encoding='utf-8') as f:
            f_js = f.read()
            ctx = NodeVM.code(f_js)
            m = ctx.call_member("get_m", temp_time, page)
            return m
    
    js逆向案例-猿人学比赛题(中等及以下难度的)_第48张图片
  • 但是按上述方式只能跑一页的数据,后来我换成了node服务的调用方式就没问题了,但是只能跑5页的数据,每次需要重启node服务才能继续跑
  • 原因是js当中有一个全局变量,与页数是绑定的;你可以理解为全局变量为1时,一定是第一页的加密逻辑,全局变量为2时一定是第二页的加密逻辑。 如果单次调用,全局变量永远是1,所以用上面的方式调用第2页就会出错。所以用node服务,同理当node服务不重启时,全局变量已经大于5,由于传过来的页数是1,所以此时没办法走全局变量是1的加密逻辑,自然而然就错了。这个全局变量我没找到
  • 总销售额等于value*24
    js逆向案例-猿人学比赛题(中等及以下难度的)_第49张图片
  • 最终解决方案:用node启用服务的方式进行调用
    js逆向案例-猿人学比赛题(中等及以下难度的)_第50张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第51张图片

7、woff动态字体编码

  • ① 反爬点:字体采用woff文件字体加密,动态字体加密即动态文件,动态编码,动态的有规律的偏移坐标、固定字体,woff文件动态变化,字符编码动态变化,为中级的字体反爬
    js逆向案例-猿人学比赛题(中等及以下难度的)_第52张图片
  • ② 解决方案:可以通过这篇文章先了解下woff是什么以及如何处理,本案例先pip install fontTools ,然后下载2份woff文件用FontStore打开,并分别保存为xml,打开两个xml拿数字2做对比,我们发现虽然2的编码不一样,但是字体on坐标信息(0表示弧形/1表示矩形)是一致的
    # -*- coding:utf-8 -*-
    from fontTools.ttLib import TTFont
    font_data_after_decode = base64.b64decode(text)
    with open('./match7.ttf', 'wb') as f:
        f.write(font_data_after_decode)
    font = TTFont('./match7.ttf')
    font.saveXML('./match7.xml')
    
    js逆向案例-猿人学比赛题(中等及以下难度的)_第53张图片
  • 所以我们只需要保存一份字体on坐标信息与数字的映射关系,后面进行代码判断即可正常解析
    js逆向案例-猿人学比赛题(中等及以下难度的)_第54张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第55张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第56张图片

12、入门级js

  • ① 反爬点:请求参数m加密,使用base64,采用猜一猜方法
    js逆向案例-猿人学比赛题(中等及以下难度的)_第57张图片
  • ② 解决方案:猜一猜,所以base64直接加密
    在这里插入图片描述

13、入门级cookie

  • ① 反爬点:cookie反爬,响应由js生成
    js逆向案例-猿人学比赛题(中等及以下难度的)_第58张图片
  • ② 解决方案:直接执行响应的js生成cookie
    js逆向案例-猿人学比赛题(中等及以下难度的)_第59张图片

15、了解wasm

  • ① 反爬点:请求参数m加密,是用wasm(WebAssembly:体积小且加载快的二进制格式)加密的
    js逆向案例-猿人学比赛题(中等及以下难度的)_第60张图片
  • ② 定位加密:采用堆栈回溯法
    js逆向案例-猿人学比赛题(中等及以下难度的)_第61张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第62张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第63张图片
  • ③ 解决方案:pip install pywasm,将.wasm文件保存到本地,然后用python包调用,模拟js上面的调用方式进行对应
    js逆向案例-猿人学比赛题(中等及以下难度的)_第64张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第65张图片

16、了解webpack打包js与window埋坑

  • ① 反爬点:请求参数m加密,使用webpack打包的js
    js逆向案例-猿人学比赛题(中等及以下难度的)_第66张图片

  • ② 定位加密:堆栈回溯法
    js逆向案例-猿人学比赛题(中等及以下难度的)_第67张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第68张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第69张图片

  • ③ 解决方案:扣webpackjs如下,我们发现上面的加密是在732这个模块下,所以直接将主函数扣下来window[u(208)]改成btoa,运行缺啥补啥将主函数依赖的其它函数一起扣下来,如d函数、l函数
    js逆向案例-猿人学比赛题(中等及以下难度的)_第70张图片

  • ③ 解决方案:直接btoa函数调用,报错发现缺少md5函数,继续从webpack里面直接扣
    js逆向案例-猿人学比赛题(中等及以下难度的)_第71张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第72张图片

  • ③ 解决方案: 主函数btoa函数内埋坑:如果上面扣md5函数的时候,将127模块的n函数放到全局中,则代码能正常运行,但是实际会校验失败,这是因为n函数被732模块的n误用了,732的n对象指向了123模块的n函数;
    在这里插入图片描述
    在这里插入图片描述

  • ③ 解决方案:排坑:"WhHMm" === i[t(198)] || n.g && c[t(246)](,这里的n.g指的是window,当复制下来我们并没有自定义window,且n对象误用了n函数,导致js代码误以为成功。所以为和浏览器保持一致,需通过本地js逐步调试与浏览器逐步调试对比,发现流程错误而后修正
    js逆向案例-猿人学比赛题(中等及以下难度的)_第73张图片
    ③ 解决方案:完整js代码如下
    js逆向案例-猿人学比赛题(中等及以下难度的)_第74张图片

17、了解http2.0协议

  • ① 反爬点:http2协议,requests只限于http1.0协议
    在这里插入图片描述
  • ②解决如下:pip install hyperlpr -i https://pypi.tuna.tsinghua.edu.cn/simple
    js逆向案例-猿人学比赛题(中等及以下难度的)_第75张图片

19、了解tls指纹

  • ① 反爬点:检测了tls指纹,requests请求无法通过,需修改套接字
  • ② 解决方案:首先要抓包看tls,如果fiddler不正确就用wireshark抓包看
  • fiddler抓包流程如下,可以看到Ciphers为tls指纹的key
    js逆向案例-猿人学比赛题(中等及以下难度的)_第76张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第77张图片
    js逆向案例-猿人学比赛题(中等及以下难度的)_第78张图片
  • 复制每个TLS分别去该网找对应的value,将找到的value用冒号拼接起来,然后赋值给requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS即可,接着就是正常的请求了
    js逆向案例-猿人学比赛题(中等及以下难度的)_第79张图片
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA'

js逆向案例-猿人学比赛题(中等及以下难度的)_第80张图片

你可能感兴趣的:(SpiderCrawl,python,javascript,http)