瑞数6代jsvmp简单分析(天津电子税x局)

发布于:2025-05-29 ⋅ 阅读:(23) ⋅ 点赞:(0)

国际惯例 今天帮朋友看一个gov网站的瑞数加密(天津电子税x局)

传送门(登陆入口界面)

瑞数6特征

1.服务器会发两次包,第一次响应状态码为412,第二次响应状态码为200。

2.有三重debugger,其中有一重debugger要拦截和修改使用 Function 构造函数创建的新函数(即Hook)。
3.返回第一个cookie_S其中cookie_S的值的第一个值为6代表瑞数6代(由服务器生成);然后js混淆生成了第二个cookie_T,只有携带有效的cookie_T才能正确请求页面状态码才是200。(也有些是O/P结尾的)
4.加载VM的1万多行代码入口特性用正则匹配是:ret=\S{4}.call(\S{4},(\S{4}));其中第一个参数为eval,第二个是要用eval执行生成的VM文件。


在这里插入图片描述

这里简单提一句怎么区分瑞数3/4/5/6/jsvmp版本的

如图中后端返回的第一个LmqtOhuon8XES键值对,里面的首个字符串是6,就代表了当前为6代,同理也有3/4/5开头的,至于jsvmp版本,则可以通过响应源码里面有如下内容$_ts.nsd 或者 打开f12直接在跳出的js里面搜索<= 63 ,也可以判断出来它是最新版本的瑞数jsvmp。

在这里插入图片描述


废话不多说直接开干吧 我们首先分析下整个流程

index文件
在这里插入图片描述

外链JS文件(自执行方法)

在这里插入图片描述

在这里插入图片描述

分析1.其中meta标签,其content内容很长且(每次请求都是动态变化的)。

分析2.外链js文件,一般同一页面中其内容是固定的,里面是个自执行方法,虚拟文件入口也在这里,主要是解密ts内容。

分析3.ts内容(每次请求首页都会动态变化)

执行流程图
在这里插入图片描述


接下来进入喜闻乐见的nodejs补环境环节

ps:瑞数6在扣代码到本地环境的时候,千万不要格式化代码,因为瑞数6有to string检测,会检测代码的长度、内容或者一些方法的环境。不然逆向会送你一个“Bug大礼包”Invalid array length 程序一直执行。(不仅是瑞数,其它的都是一样的,只要是js文件,在扣js代码的内容,最好是碗就碗是碟就碟,千万不要格式化)。

这里推荐几个大佬的开源代码

在这里插入图片描述

在这里插入图片描述

这里贴部分补环境的代码

    window = new Proxy(window, {
        get: function (x, y) {
            if (typeof x[y] === "function") {
                x[y].toString = function () {
                    return 'function ' + y + '() { [native code] }'
                }
            }
            return x[y]
        },
        set: function (target, p, value, receiver) {
            if (p.indexOf('jsonp_') > -1) {
                callbackJsonpCustom.push(p)
            }
            Object.defineProperty(target, p, {value: value, writable: true, configurable: true});
            // Object.defineProperty(global, p, {value: value, writable: true, configurable: true});
            return true
        }
    });
    window.location = new Proxy(window.location, {
        get: function (x, y) {
            if (typeof x[y] === "function") {
                x[y].toString = function () {
                    return 'function ' + y + '() { [native code] }'
                }
            }
            if (y === "port") {
                return "443"
            }
            return x[y]
        },
        set: function (target, p, value, receiver) {
            if (p.indexOf('jsonp_') > -1) {
                callbackJsonpCustom.push(p)
            }
            Object.defineProperty(target, p, {value: value, writable: true, configurable: true});
            return true
        }
    });
    let txt = fs.readFileSync('./JsBase64.txt').toString('utf8')
    let ts_data = new Buffer.from(txt, 'base64').toString('utf8')
    window['$_ts'] = {};
    let execScript = window.eval;
    window.eval.toString = function () {
        return 'function eval() { [native code] }'
    }

    window.eval = function (data) {
        window.eval = execScript;
        window.eval.toString = function () {
            return 'function eval() { [native code] }'
        }

这里需要注意一个东西(必须加上)

delete __dirname;
delete __filename;

另外再提几句比较坑的地方,有时候补环境生成的长度比较短,然后拿去跑代码,会发现后端返回http状态码400,这个时候就得注意下是否环境没补全,看看document.all 的检测 / webdriver 属性检测 / navigator 相关属性检测 等 能从浏览器自吐的就全部cv过去。


ok 到了喜闻乐见的成品运行图。(目前可以通杀所有省份的税务局瑞数6代jsvmp)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


Ending

Github传送门

持续更新ing (欢迎各种star与fork)

如有权益问题可以发私信联系我删除


网站公告

今日签到

点亮在社区的每一天
去签到