使用AST进行JavaScript反混淆(2022年增值税发票查验js)

article/2025/8/15 21:06:26

背景

多年前学过龙书,一来当时本身也没看懂,二来时间也长也差不多都忘记了。直到最近有 deobfuscate 问题才看了下AST。

说实话,一旦稍微了解AST和熟悉了 Babel 接口,deobfuscate 实在不是啥难事。

反混淆总结放前面。

注意事项

最重要的就2条:

  1. 开源/简单的混淆方案,现有的基本上都能解决;如:https://deobfuscator.kuizuo.cn/ 和 https://github.com/Tsaiboss/decodeObfuscator
  2. 其它混淆方案,特别是商用的或者是变形后的 deobfuscate 需要注意以下几点:
    1. 务必要处理掉反逆向逻辑,如:死循环这类;
    2. 使用 astexplorer 务必分析好特征,一般来讲开源的处理不了基本上是因为特征变了,其核心是一样的。一旦你补上了对应的特征基本上使用前面的开源项目就达到目的了。
    3. 必要的动态调试(浏览器debug)少不了,因为可以非常方便进行对比验证;

JS混淆总的来讲是提升 deobfuscate 难度,和其它安全类产品类似。JS毕竟是运行在客户端,想要完全的避免是不可能的。甚至是Native APP VM加壳这种都不能完全避免。

实战

证书问题

官网(https://inv-veri.chinatax.gov.cn/)使用自签证书,如果没有安装跟证书会出现:证书错误
浏览器解决方案有下面几种:

  • 第一种是不管,直接点击继续访问。但是各省市的网站需要都点击一次。比较麻烦。
  • 第二种是安装跟证书,参考:https://inv-veri.chinatax.gov.cn/zdaz.html ,Windows平台建议选择自动安装。
  • 第三种浏览器里面设置忽略证书验证,设置浏览器启动参数 -ignore-certificate-errors ,参考:https://www.likecs.com/show-304407.html 忽略证书

接口分析

整个功能就2个接口,一个验证码接口一个发票查验接口,对应如下:

  1. yzmQuery:获取验证码。 eb23.js 文件。
  2. vatQuery:获取发票数据。被 eval 隐藏,请求在 90a1c.js 文件。

我们分别对这2个接口进行分析。

代码分析见后面的 源码整理。

验证码接口 yzmQuery

先在浏览器中抓个包,接口如下:

https://fpcy.guangdong.chinatax.gov.cn/NWebQuery/yzmQuery?callback=jQuery36108117432652732104_1665738094937&fpdm=224420000000&fphm=00234125&r=0.8586908933148021&v=2.0.11_060&nowtime=1665738219455&publickey=1665738219455&key9=6ed669ba8da29e71cd3f582907f3840a&_=1665738094939&flwq39=eoyleUZchlfg6YBgVcLURuRzQ3Z8GRI148s3JKhei5SSK%2BfibNFq7YxxZT6NO2aXSzrimz7GoKWos%2BVh2bdBiAT4tMlYqyQB%2BQY1%2BD5AmUv1nfu2stTeQCJVCHzhRcmHFoV2VPTq%2BBegLJwOatgO4yYY59uStSsc1nT6qvBcaf4%3D

具体参数如下:

callback: jQuery36108117432652732104_1665738094937
fpdm: 224420000000
fphm: 00234125
r: 0.8586908933148021
v: 2.0.11_060
nowtime: 1665738219455
publickey: 1665738219455
key9: 6ed669ba8da29e71cd3f582907f3840a
_: 1665738094939
flwq39: eoyleUZchlfg6YBgVcLURuRzQ3Z8GRI148s3JKhei5SSK+fibNFq7YxxZT6NO2aXSzrimz7GoKWos+Vh2bdBiAT4tMlYqyQB+QY1+D5AmUv1nfu2stTeQCJVCHzhRcmHFoV2VPTq+BegLJwOatgO4yYY59uStSsc1nT6qvBcaf4=

此接口返回内容下:

jQuery36108117432652732104_1665738094937({"key1": "xxx",  // 验证码的base64编码"key2": "2022-10-14 16:44:47",  // 时间,发票数据接口要使用"key3": "dda81561f442e25c978cb7d5b2139928", // key,发票数据接口要使用"key4": "01", // 颜色"key5": "2","key6": "8ae8f8fe838974270183d5bc260e5ae3" // key,发票数据接口要使用
})

验证码接口返回
我们对上面参数进行分类:

第一类是jsoup请求参数:callback_

callback_, 前面是随机字符串,可要可不要。不要的化服务器会直接返回json格式数据。_ 参数是当前时间(参考后面!)。不要callback参数

发票参数: fpdmfphm

fpdmfphm 发票代码和发票号码。注意新的电子发票是 20位发票号码,需要拆分。

获取当前时间参考

环境参数: nowtimer , v, publickey

这4个参数中只有 v是版本号的意思,在 validate.js 中,自己可以打开 https://inv-veri.chinatax.gov.cn/js/validate.js?0.3320348734641909 看。 r 参数是随机值,可以自己取。 nowtimepublickey 和 都是当前时间,参考前面的 showTime() 接口。

加密参数:key9flwq39

这重点。

参数 key9 是 算出来的,来源参考:key9参数
这个参数的三个参数分别是 发票代码、发票号码、时间。我们自己可以验证。
验证key9参数
跟踪$.nnyd.yzm 函数可以发现对应位置,方式如下:

  1. 控制台输入函数名称 $.nnyd.yzm
  2. 点击呈现的代码。
    输入函数,定位代码
    在新窗口中格式化代码并搜索关键字。
    搜索yzm关键字

flwq39参数:这个参数是放到 ajaxSetup中,如下所示:

    $.ajaxSetup({"beforeSend": function (_0xc6fbc4, _0x5a4363) {if (_0x5a4363.url.indexOf("127.0.0.1") == -1) {_0x5a4363.url += _0x5a4363.url.match(/\?/) ? "&" : "?";if (_0x5a4363.url.indexOf("yzmQuery") >= 0) {_0x5a4363.url += "flwq39=" + _0x3ed54a(_0x5a4363);dlqee = new Date().getTime() + 2000;}if (_0x5a4363.url.indexOf("vatQuery") >= 0) {var _0x61b5fc = new Date().getTime() < dlqee;_0x5a4363.url += "flwq39=" + _0x51824e(_0x5a4363, _0x61b5fc);}}}});

查验接口 vatQuery

如果你看前面的验证码接口,那么发现此接口和之前基本上是一样的。

看实际地址:

https://fpcy.guangdong.chinatax.gov.cn/NWebQuery/vatQuery?callback=jQuery36108117432652732104_1665738094937&key1=224420000000&key2=00234125&key3=20221013&key4=52200&fplx=09&yzm=zsj&yzmSj=2022-10-14%2016%3A45%3A04&index=e4c1e5acc4313342aa2e62cbb6dffdbd&key6=8ae8f8fe8389744a0183d5bc662d6b1e&publickey=2022-10-14%2016%3A45%3A04&key9=1065daa3d1a4b8a8b85e8ec531d13bac&_=1665738094940&flwq39=lYNyPq6FOGowj1WkJsBztPN8Gq%2FS4tfy9STQYrQoDbV7ac1KrlFeU8MopI9BGNo7Xf7VaCRDKeE6UNpps2UlMcC1IlYabqVzRog0VFh%2FNDrXPgylod3E4UjLDE3l6mk5A%2B57SMzNe%2BV7gSH7a9%2BhYTJ42B5wRTPT2ph2hNJoff4%3D

对应参数:

callback: jQuery36108117432652732104_1665738094937
key1: 224420000000
key2: 00234125
key3: 20221013
key4: 52200
fplx: 09
yzm: zsj
yzmSj: 2022-10-14 16:45:04
index: e4c1e5acc4313342aa2e62cbb6dffdbd
key6: 8ae8f8fe8389744a0183d5bc662d6b1e
publickey: 2022-10-14 16:45:04
key9: 1065daa3d1a4b8a8b85e8ec531d13bac
_: 1665738094940
flwq39: 
lYNyPq6FOGowj1WkJsBztPN8Gq/S4tfy9STQYrQoDbV7ac1KrlFeU8MopI9BGNo7Xf7VaCRDKeE6UNpps2UlMcC1IlYabqVzRog0VFh/NDrXPgylod3E4UjLDE3l6mk5A+57SMzNe+V7gSH7a9+hYTJ42B5wRTPT2ph2hNJoff4=

第一类是jsoup请求参数:callback_

见验证码接口

发票参数: key1key2key3key4

  • key1:发票代码
  • key2 发票号码。注意新的电子发票是 20位发票号码,需要拆分。
  • key3 开票日期
  • key4 发票金额,注意不同类型的发票这个值不一样,可能是校验码,也可能是 不含税进金额,也可能是含税金额。
  • yzm 验证码
  • fplx 发票类型,由 alxd 函数获取。如下所示:
    获取发票类型
    alxd 代码获取请参考前面的 $.nnyd.yzm

上下文参数: yzmSjindexpublickeykey6

  • yzmSj 验证码接口返回的
  • index 验证码接口返回的 key3
  • publickey 验证码接口返回的时间。
  • key6 验证码接口返回的key6

加密参数:key9flwq39

擦看前面的方式可以发现, key9$.nnyd.cy 接口返回的,如下所示。
查验接口参数
flwq39 参数见前面。

部分结果源码整理

// 获取发票的接口。
function getYzmXx() {$.pricode.clearA();show_yzm = "1";var _0x436381 = $("#fpdm").val().trim();if ("" === _0x436381) {_0x436381 = $("#fphm").val().trim();}var _0x58c97a = getSwjg(_0x436381, 0);if (!_0x58c97a[1]) {jAlert("<div id='popup_message'>请输入正确的代码号码!</div>", "提示");return;}var _0x3bab81 = _0x58c97a[1] + "/yzmQuery";var _0x469bdb = showTime().toString();var _0x4c4952 = $("#fpdm").val().trim();var _0x5699c9 = $("#fphm").val().trim();var _0x43c245 = $("#kjje").val().trim();var _0x4b069d = Math.random();var _0x1d0e71 = _0x58c97a[2];if (_0x5699c9.length === 20) {// 处理20位发票号码,前面12位分割成发票代码,后面8位分割位发票号码。_0x4c4952 = _0x5699c9.substring(0, 12);_0x5699c9 = _0x5699c9.substring(12);}var _0x28b87b = {"fpdm": _0x4c4952,"fphm": _0x5699c9,"r": _0x4b069d,"v": VVV,"nowtime": _0x469bdb,"area": _0x1d0e71,"publickey": _0x469bdb,"key9": $.nnyd.yzm(_0x4c4952, _0x5699c9, _0x469bdb)};$.ajaxSetup({"cache": false});yzmFlag = 1;$.ajax({"type": "post","url": _0x3bab81,"data": _0x28b87b,"dataType": "jsonp","jsonp": "callback","success": function (_0x165bcc) {// 省略....},"timeout": 5000,"error": function (_0x283219, _0x4d7b1f, _0xb6705a) {if (retrycount == 9) {jAlert("系统繁忙,请稍后重试!", "提示");} else {// 省略....}});function showTime() {const _0x2969c0 = new Date();return _0x2969c0.getTime();
}

发票查验接口所在代码:

            $("#checkfp").hide();$("#uncheckfp").show();var _0x2e8cad = 5;var _0x320d7e = $("#yzm").val().trim();_0x2e8cad = 6;var _0x53ae8a;var _0x2730af = '';_0x53ae8a = 8;var _0x23d188 = null;var _0x49fc66 = '';if (avai(fplx)) {if (fplx == '01' || fplx == '02' || fplx == '03' || fplx == '08' || fplx == '09' || fplx == '83' || fplx == '61') {var _0x472fbd;var _0x312fb7 = _0x57615f.indexOf('.');_0x472fbd = 11;if (_0x312fb7 > 0) {var _0x1d99cd = _0x57615f.split('.');if (_0x1d99cd[1] == '00' || _0x1d99cd[1] == '0') {_0x57615f = _0x1d99cd[0];} else {if (_0x1d99cd[1].charAt(1) == '0') {_0x57615f = _0x1d99cd[0] + '.' + _0x1d99cd[1].charAt(0);}}}}if (_0x277a13.length === 20) {_0x3e827f = _0x277a13.substring(0, 12);_0x277a13 = _0x277a13.substring(12);}var _0x181fe9;var _0x1220aa = _0x5f273a[1];_0x181fe9 = 11;_0x49fc66 = _0x1220aa + "/vatQuery";_0x23d188 = {'key1': _0x3e827f,'key2': _0x277a13,'key3': _0x57f456,'key4': _0x57615f,'fplx': fplx,'yzm': _0x320d7e,'yzmSj': yzmSj,'index': jmmy,'area': _0x3fb76c,'key6': key6,'publickey': yzmSj,'key9': $.nnyd.cy(_0x3e827f, _0x277a13, yzmSj)};if (oldweb == 1) {_0x49fc66 = _0x1220aa + "/invQuery";_0x23d188 = {'fpdm': _0x3e827f,'fphm': _0x277a13,'kprq': _0x57f456,'fpje': _0x57615f,'fplx': fplx,'yzm': _0x320d7e,'yzmSj': yzmSj,'index': jmmy,'area': _0x3fb76c,'key6': key6,'publickey': yzmSj,'key9': $.nnyd.cy(_0x3e827f, _0x277a13, yzmSj)};}delayMessage = "发票查验请求失败!";showTime();var _0x201fbe = 'N';$.ajax({'type': "post",'url': _0x49fc66,'dataType': "jsonp",'data': _0x23d188,'jsonp': "callback",// 省略....});

重点算法分析

涉及的接口 $.nnyd.yzm$.nnyd.cyflw39
涉及的算法有:md5、RSA、Base64。

流程大体如下:

  1. 对发票代码、发票号号码、当前时间分别组合进行 Base64 ;
  2. 分别组合算MD5;
  3. 对MD5进行RSA加密; 92da1b9c13d7432c8eae5aa66e641262.js 文件
  4. 对RSA结果进行URL编码;

除此之外还有其它的东西:

  1. 统计识别失败次数;
  2. 检查环境;常见爬虫的特征检查。

参考及工具

  • https://juejin.cn/post/7045604250126123015
  • https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#builders
  • https://astexplorer.net/
  • https://lzc6244.github.io/2021/07/27/Babel-AST%E5%85%A5%E9%97%A8.html
  • https://steakenthusiast.github.io/

http://chatgpt.dhexx.cn/article/o577I9lG.shtml

相关文章

html混淆压缩,JavaScript的压缩和混淆

JavaScript的压缩和混淆 我们都知道JavaScript是一种在客户端浏览器中执行的解释型语言。浏览器以纯文本的形式下载JavaScript&#xff0c;然后在需要的时候执行JavaScript代码。 通过使用浏览器的查看源代码功能&#xff0c;用户总是能够阅读JavaScript的源代码&#xff0c;该…

安卓混淆及反编译工具

目录 安卓混淆及反编译工具... 1 Eclipse编译混淆... 2 项目文件project.properties. 2 服务器编译混淆... 2 Android.mk. 2 混淆规则... 3 Java代码的混淆... 3 Proguard混淆规则汇总... 3 Native的混淆... 4 资源文件的混淆... 4 混淆的常见配置... 4 哪些不应该…

一款JavaScript 混淆(Obfuscator)工具(Tool)的研究(一)

1.研究使用的工具及网站 https://obfuscator.io 主要研究对象&#xff0c;主要是研究此网站的各种混淆方法及破解办法。 http://jsnice.org/ 用来格式化代码&#xff0c;方便调试。 notepad 编辑代码。 某浏览器 具有谷歌内…

stm32与sim900之GPRS通信(电脑串口与SIM900通信)

注意&#xff1a; 1 sim900在进行GPRS通信的时候最大电流可以到90MA.瞬间电流SIM900模块可能高达2A4V,即输入端电流瞬间值可能高达740mA12V,故给模块选择电源的时候&#xff0c;要能满足瞬间电流峰值。 以上这段话摘录自正点原子的SIM900用户手册&#xff0c;也就是说你在用SI…

GSM模块(SIM900)详解

GSM模块&#xff08;SIM900&#xff09; 0. GSM概述1. 常用的GSM模块2. SIM900系列3. STM32使用SIM900系列通信方法AT指令示例代码 0. GSM概述 GSM&#xff08;全球系统移动通信&#xff09;是一种数字移动通信技术&#xff0c;是世界上最常用的移动通信标准之一。它是由欧洲电…

常见的防火墙技术介绍

详见&#xff1a;http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt280 防火墙是一个系统或一组系统&#xff0c;它在内网与Internet间执行一定的安全策略。典型的防火墙应包含如下模块中的一个或多个&#xff1a;包过滤路由器、应用层网关&#xff08;或代理服务器…

linux平台下防火墙iptables原理

转载自:http://www.cnblogs.com/ggjucheng/archive/2012/08/19/2646466.html linux平台下防火墙iptables原理(转) iptables简介 netfilter/iptables&#xff08;简称为iptables&#xff09;组成Linux平台下的包过滤防火墙&#xff0c;与大多数的Linux软件一样&#xff0c;这个包…

简述防火墙

什么是防火墙&#xff1f; 在遭受入侵时&#xff0c;做内外网隔离的策略叫做防火墙。 防火墙分类 按物理特性划分&#xff1a;软件防火墙、硬件防火墙&#xff1b;按性能划分&#xff1a;百兆级防火墙、千兆级防火墙……按防火墙结构划分&#xff1a;单一主机防火墙、路由集…

【计算机基础】防火墙

工程师CCNAHCIA 资深工程师CCNPHCIP 技术专家CCIEHCIE IPS&#xff1a;入侵防御系统&#xff0c;发现攻击和入侵进行阻断IDS&#xff1a;入侵检测系统&#xff0c;检测有无攻击漏洞扫描&#xff1a;发现本地服务器/PC&#xff0c;存在哪些中高低危的风险&#xff0c;解决漏洞…

下一代防火墙概述

目录 1.防火墙概述 1.1定义 1.2防火墙分类 1.3防火墙功能 1.4防火墙的策略 2.防火墙发展史 2.1 包过滤防火墙&#xff1a;一个严格的规则表 2.2 应用代理防火墙&#xff1a;为每个应用添加代理 2.3 状态检测防火墙&#xff1a;建立会话表 2.4 入侵检测系统&#xff0…

上海交通大学考研复试模块小结——防火墙技术

既然上次开了这个系列&#xff0c;索性就把这个信息安全这一块的主流技术都介绍一遍好了。上篇博客讲了密码学&#xff0c;今天就来说说防火墙技术。 防火墙技术 防火墙技术是位于两个新人程度不同的网络之间的软件或者硬件设备的组合&#xff0c;实质上是一种控制隔离技术。…

防火墙入门实验

第一章 iptable的使用 一、实验原理 1.1 Iptables Iptables 是用来设置、维护和检查Linux内核的IP包过滤规则的。 可以定义不同的表&#xff0c;每个表都包含几个内部的链&#xff0c;也能包含用户定义的链。每个链都是一个规则列表&#xff0c;对对应的包进行匹配&#xf…

NAT和防火墙

网络地址翻译没文化的酒鬼 防火墙和NAT NAT路由器是安装了NAT软件的路由器&#xff0c;拥有至少一个全球通用的外部IP。 在计算机网络中&#xff0c;NAT最直接的作用是IP映射&#xff1a;将内网终端A的IP和端口号经过NAT映射后&#xff0c;转成公网服务器B的IP和新端口号&am…

快速了解防火墙

快速了解防火墙 防火墙是一种由计算机硬件和软件组成的系统&#xff0c;部署于网络边界&#xff0c;是连接内部网络和外部网络(或内部网络不同安全级别的部门)之间的桥梁&#xff0c;同时对进出网络边界的数据进行保护&#xff0c;防止恶意入侵、恶意代码的传播等&#xff0c;…

防火墙概述

AC是为了防御从内网到外网的攻击防火墙是为了防御从外网到内网的攻击 防火墙的定义 防火墙通常用于两个网络之间的隔离 主要用于保护一个网络区域免受来自另一个网络区域的网络攻击和网络入侵行为路由器与交换机的本质是转发&#xff0c;防火墙的本质是控制和防护 防火墙的工…

防火墙(firewall)

前言 计算机的安全性历来就是人们热衷的话题之一。而随着Internet的广泛应用&#xff0c;人们在扩展了获取和发布能力的同时也带来信息被污染和破坏的危险。这些安全问题主要是由网络的开放性、无边界性、自由性造成的&#xff0c;还包括以下一些因素。 1. 计算机操作系统本身…

华为防火墙的学习

防火墙 - 含义和定义 什么是防火墙&#xff1f; 防火墙的工作原理 防火墙的区域&#xff1a; 包过滤防火墙----访问控制列表技术---三层技术 代理防火墙----中间人技术---应用层 状态防火墙---会话追踪技术---三层、四层 UTM---深度包检查技术----应用层 下一代防火墙 防火墙的…

潘多拉 STM32L475 VE——开发板学习 (持续更新)

首先就是开发板的各个硬件的介绍&#xff1a; ◆ MCU &#xff1a; STM32L475VET6 &#xff0c; LQFP100 &#xff0c; SRAM &#xff1a; 128K &#xff0c; FLASH &#xff1a; 512K ◆ 外扩 SPI FLASH &#xff1a; W25Q128 &#xff0c; 16M 字节 ◆ 1 个电源指示灯…

WiFi 移植记录及心得 一

平台环境:IMX6-sabresd_6dq Android4.4.2 Linux3.0.35 WiFi模块:AP6181 (BCM43362) Linux3.0.35已经是支持博通的芯片,可以看到 kernel_imx/drivers/net/wireless 下面有几款博通芯片(bcm4329/bcm4330/bcmdhd)的驱动源码,AP6181WiFi模块用的bcm43362这款,所以这里选…