国家税务总局全国增值税发票查验平台网站js逆向分析及全逆向算法还原

2023-10-31

本文教程针对的是2021年7月2日时国税查验平台的js分析,其中版本号为V2.0.06_009。主要分析内容为key9和flwq39以及fplx这3个参数的算法,其中key9分为获取验证码阶段和查验阶段,算法有所区别,flwq39同理。

教程开始:

一、官方网址

国家税务总局全国增值税发票查验平台

二、请求分析

国税查验平台请求共分为2个,第一个请求获取验证码,第二个请求为输入验证码后查验数据并返回发票详细信息。

第一步:安装证书

基础:谷歌浏览器

首先需要安装证书,建议选择自动安装,在某些教程中可能选择手动安装,以便于使用ast工具挂代理找内存数据,但是这里我们采用一种新的方法来解决js逆向问题,因此那种方便用那种。

第二步:抓包

基础:谷歌浏览器+开发者工具+js基础知识

我们使用开发者工具或按F12打开谷歌浏览器的开发者工具,请注意尽量在网页加载完成后打开开发者工具,界面如下:

官方很给力,直接debug了,至于如何去掉断点,可以参考百度上的其他教程,这里给出一个办法,上图中点击数据1所处位置,使其颜色为蓝色,点击2或者点击上方的debug恢复按钮。此时,我们成功绕过了debug,但是特别注意尽量关闭其他无用软件或者网页,因为在后面的操作中,会感到特别卡顿。

我们在发票代码输入框和发票号码中输入合法的数据,并在开发者工具模块,观察所发送的请求包:

https://fpcy.anhui.chinatax.gov.cn/NWebQuery/yzmQuery?callback=jQuery11020854931324645166_1625223145135&fpdm=034012000211&fphm=12345678&r=0.28901229909781767&v=V2.0.06_009&nowtime=1625223446708&publickey=1625223446708&key9=ec213f1e1aa579511f5d58f09a01a5a2&_=1625223145136&flwq39=LdjaQwXUtzKjxpXQ%2FmD7KCBtBMP7lqfc7uBJNuxAumYpT9mjp90BloLfM4V6KKuD4GWdYCxRLLjJX9a1YrNy7Bs95NmSWQmpc1VAibkeG3HydXc0r9xsRc%2BkIsPWeHrFk3PYAP6k8tAcTJzoIdlhctD8wOUVXOUwczcMJW6WiF0%3D

在这个请求中,分为url的网址前缀部分和尾部参数,其中尾部参数如下:

callback=固定值
fpdm=发票代码
fphm=发票号码
r=随机数
V=版本号
nowtime=当前时间减去1分钟
publickey=当前时间减去1分钟
key9=加密参数
_=可为固定值
flwq39=加密参数

如果你观察过会发现,不同地区的发票,请求的地址不同,如这里是anhui。该请求的前缀部分在一个js文件中,如图:

但是,很不幸,当你打开这个文件时,你会发现混淆了,不过很容易发现是sojson的样子,这并不影响我们逆向,我们使用http://tool.yuanrenxue.com/decode_obfuscator这个网站可以解密这些js代码,尽管解密的代码看着很头疼,但是已经比原始的好太多了。

解密后可以得到各个地区的ip和网址以及对应的地区代码:

0: {code: "1100", sfmc: "北京", Ip: "https://fpcy.beijing.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.beijing.chinatax.gov.cn:443"}
1: {code: "1200", sfmc: "天津", Ip: "https://fpcy.tjsat.gov.cn:443/NWebQuery", address: "https://fpcy.tjsat.gov.cn:443"}
2: {code: "1300", sfmc: "河北", Ip: "https://fpcy.hebei.chinatax.gov.cn/NWebQuery", address: "https://fpcy.hebei.chinatax.gov.cn"}
3: {code: "1400", sfmc: "山西", Ip: "https://fpcy.shanxi.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.shanxi.chinatax.gov.cn:443"}
4: {code: "1500", sfmc: "内蒙古", Ip: "https://fpcy.neimenggu.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.neimenggu.chinatax.gov.cn:443"}
5: {code: "2100", sfmc: "辽宁", Ip: "https://fpcy.liaoning.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.liaoning.chinatax.gov.cn:443"}
6: {code: "2102", sfmc: "大连", Ip: "https://sbf.dalian.chinatax.gov.cn:8402/NWebQuery", address: "https://sbf.dalian.chinatax.gov.cn:8402"}
7: {code: "2200", sfmc: "吉林", Ip: "https://fpcy.jilin.chinatax.gov.cn:4432/NWebQuery", address: "https://fpcy.jilin.chinatax.gov.cn:4432"}
8: {code: "2300", sfmc: "黑龙江", Ip: "https://fpcy.heilongjiang.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.heilongjiang.chinatax.gov.cn:443"}
9: {code: "3100", sfmc: "上海", Ip: "https://fpcy.shanghai.chinatax.gov.cn:1001/NWebQuery", address: "https://fpcy.shanghai.chinatax.gov.cn:1001"}
10: {code: "3200", sfmc: "江苏", Ip: "https://fpcy.jiangsu.chinatax.gov.cn:80/NWebQuery", address: "https://fpcy.jiangsu.chinatax.gov.cn:80"}
11: {code: "3300", sfmc: "浙江", Ip: "https://fpcy.zhejiang.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.zhejiang.chinatax.gov.cn:443"}
12: {code: "3302", sfmc: "宁波", Ip: "https://fpcy.ningbo.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.ningbo.chinatax.gov.cn:443"}
13: {code: "3400", sfmc: "安徽", Ip: "https://fpcy.anhui.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.anhui.chinatax.gov	.cn:443"}
14: {code: "3500", sfmc: "福建", Ip: "https://fpcy.fujian.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.fujian.chinatax.gov.cn:443"}
15: {code: "3502", sfmc: "厦门", Ip: "https://fpcy.xiamen.chinatax.gov.cn/NWebQuery", address: "https://fpcy.xiamen.chinatax.gov.cn"}
16: {code: "3600", sfmc: "江西", Ip: "https://fpcy.jiangxi.chinatax.gov.cn:82/NWebQuery", address: "https://fpcy.jiangxi.chinatax.gov.cn:82"}
17: {code: "3700", sfmc: "山东", Ip: "https://fpcy.shandong.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.shandong.chinatax.gov.cn:443"}
18: {code: "3702", sfmc: "青岛", Ip: "https://fpcy.qingdao.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.qingdao.chinatax.gov.cn:443"}
19: {code: "4100", sfmc: "河南", Ip: "https://fpcy.henan.chinatax.gov.cn/NWebQuery", address: "https://fpcy.henan.chinatax.gov.cn"}
20: {code: "4200", sfmc: "湖北", Ip: "https://fpcy.hubei.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.hubei.chinatax.gov.cn:443"}
21: {code: "4300", sfmc: "湖南", Ip: "https://fpcy.hunan.chinatax.gov.cn:8083/NWebQuery", address: "https://fpcy.hunan.chinatax.gov.cn:8083"}
22: {code: "4400", sfmc: "广东", Ip: "https://fpcy.guangdong.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.guangdong.chinatax.gov.cn:443"}
23: {code: "4403", sfmc: "深圳", Ip: "https://fpcy.shenzhen.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.shenzhen.chinatax.gov.cn:443"}
24: {code: "4500", sfmc: "广西", Ip: "https://fpcy.guangxi.chinatax.gov.cn:8200/NWebQuery", address: "https://fpcy.guangxi.chinatax.gov.cn:8200"}
25: {code: "4600", sfmc: "海南", Ip: "https://fpcy.hainan.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.hainan.chinatax.gov.cn:443"}
26: {code: "5000", sfmc: "重庆", Ip: "https://fpcy.chongqing.chinatax.gov.cn:80/NWebQuery", address: "https://fpcy.chongqing.chinatax.gov.cn:80"}
27: {code: "5100", sfmc: "四川", Ip: "https://fpcy.sichuan.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.sichuan.chinatax.gov.cn:443"}
28: {code: "5200", sfmc: "贵州", Ip: "https://fpcy.guizhou.chinatax.gov.cn:80/NWebQuery", address: "https://fpcy.guizhou.chinatax.gov.cn:80"}
29: {code: "5300", sfmc: "云南", Ip: "https://fpcy.yunnan.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.yunnan.chinatax.gov.cn:443"}
30: {code: "5400", sfmc: "西藏", Ip: "https://fpcy.xztax.gov.cn:81/NWebQuery", address: "https://fpcy.xztax.gov.cn:81"}
31: {code: "6100", sfmc: "陕西", Ip: "https://fpcy.shaanxi.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.shaanxi.chinatax.gov.cn:443"}
32: {code: "6200", sfmc: "甘肃", Ip: "https://fpcy.gansu.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.gansu.chinatax.gov.cn:443"}
33: {code: "6300", sfmc: "青海", Ip: "https://fpcy.qinghai.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.qinghai.chinatax.gov.cn:443"}
34: {code: "6400", sfmc: "宁夏", Ip: "https://fpcy.ningxia.chinatax.gov.cn:443/NWebQuery", address: "https://fpcy.ningxia.chinatax.gov.cn:443"}
35: {code: "6500", sfmc: "新疆", Ip: "https://fpcy.xj-n-tax.gov.cn:443/NWebQuery", address: "https://fpcy.xj-n-tax.gov.cn:443"}

回到抓包中,我们观察到这时发送了一个获取验证码的请求:

注意到通过分析这个url,我们发现请求来自如下图,我们注意到getyzmxx这个函数,来自eab23.js这个文件里,我们提取这个文件使用ob解密。

ob解密后的数据如下:

var _0x14658c = function () {
  var _0x2253f1 = true;
  return function (_0x41c5d5, _0x508a27) {
    var _0x47fbda = _0x2253f1 ? function () {
      if (_0x508a27) {
        var _0x6b4e27 = _0x508a27["apply"](_0x41c5d5, arguments);

        _0x508a27 = null;
        return _0x6b4e27;
      }
    } : function () {};

    _0x2253f1 = false;
    return _0x47fbda;
  };
}();

var _0x59e564 = _0x14658c(this, function () {
  var _0x595419 = function () {
    return "dev";
  },
      _0x4c5231 = function () {
    return "window";
  };

  var _0x1842a8 = function () {
    var _0x21d015 = new RegExp("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}");

    return !_0x21d015["test"](_0x595419["toString"]());
  };

  var _0x113bb3 = function () {
    var _0x326224 = new RegExp("(\\\\[x|u](\\w){2,4})+");

    return _0x326224["test"](_0x4c5231["toString"]());
  };

  var _0x185d70 = function (_0x4ac461) {
    var _0x557ade = 0;

    if (_0x4ac461["indexOf"](false)) {
      _0x3cbd92(_0x4ac461);
    }
  };

  var _0x3cbd92 = function (_0x2bb9d8) {
    var _0x5f4806 = 3;

    if (_0x2bb9d8["indexOf"]("true"[3]) !== _0x5f4806) {
      _0x185d70(_0x2bb9d8);
    }
  };

  if (!_0x1842a8()) {
    if (!_0x113bb3()) {
      _0x185d70("ind\u0435xOf");
    } else {
      _0x185d70("indexOf");
    }
  } else {
    _0x185d70("ind\u0435xOf");
  }
});

_0x59e564();

var yzmWait = 2;
var retrycount = 0;
$(document)["ready"](function () {
  $("#fpdm")["blur"](function () {
    retrycount = 0;
  });
});

function yzmTime(_0x5c47fb) {
  if (yzmWait == 0) {
    $("#yzm_unuse_img")["hide"]();
    $("#yzm_img")["show"]();
    yzmWait = 60;
  } else {
    if (yzmWait == 2) {
      $("#yzm_unuse_img")["show"]();
      $("#yzm_img")["hide"]();
    }

    yzmWait--;
    setTimeout(function () {
      yzmTime(_0x5c47fb);
    }, 1000);
  }
}

function getYzmXx() {
  $["pricode"]["clearA"]();
  show_yzm = "1";

  var _0x31767b = $("#fpdm")["val"]()["trim"]();

  var _0x4dfb9 = getSwjg(_0x31767b, 0);

  var _0x3297c1 = _0x4dfb9[1] + "/yzmQuery";

  var _0x41afd2 = showTime()["toString"]();

  var _0x1912a2 = $("#fpdm")["val"]()["trim"]();

  var _0x478041 = $("#fphm")["val"]()["trim"]();

  var _0x1a5014 = $("#kjje")["val"]()["trim"]();

  var _0x70138f = Math["random"]();

  var _0x1d5629 = _0x4dfb9[2];
  var _0x18c20a = {
    "fpdm": _0x1912a2,
    "fphm": _0x478041,
    "r": _0x70138f,
    "v": VVV,
    "nowtime": _0x41afd2,
    "area": _0x1d5629,
    "publickey": _0x41afd2,
    "key9": $["nnyd"]["yzm"](_0x1912a2, _0x478041, _0x41afd2)
  };
  $["ajaxSetup"]({
    "cache": false
  });
  yzmFlag = 1;
  $["ajax"]({
    "type": "post",
    "url": _0x3297c1,
    "data": _0x18c20a,
    "dataType": "jsonp",
    "jsonp": "callback",
    "success": function (_0x135eb2) {
      if (_0x135eb2["hasOwnProperty"]("data")) {
        _0x135eb2 = _0x135eb2["data"];
        _0x135eb2 = replaceStr(_0x135eb2, _0x41afd2);
        _0x135eb2 = Base64["decode"](_0x135eb2);
        _0x135eb2 = eval("(" + _0x135eb2 + ")");
      }

      delayFlag = "1";
      var _0x2651d3 = _0x135eb2["key1"];
      var _0x1a96a9 = _0x135eb2["key2"];
      var _0x2b0c56 = _0x135eb2["key3"];
      var _0x1769c2 = _0x135eb2["key4"];
      var _0x483079 = _0x135eb2["key5"];
      var _0x2e8ee0 = _0x135eb2["key6"];

      if (_0x483079 == "2") {
        oldweb = 2;
      } else {
        if (_0x483079 == "1") {
          oldweb = 1;
        }
      }

      if (_0x2651d3 == "003") {
        jAlert("\u9A8C\u8BC1\u7801\u8BF7\u6C42\u6B21\u6570\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF71\u5206\u949F\u540E\u518D\u8BD5\uFF01", "\u8B66\u544A");
        $("#yzm_img")["hide"]();
      } else {
        if (_0x2651d3 == "005") {
          jAlert("\u975E\u6CD5\u8BF7\u6C42!", "\u8B66\u544A");
        } else {
          if (_0x2651d3 == "010") {
            jAlert("\u7F51\u7EDC\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5\uFF01(01)", "\u8B66\u544A");
          } else {
            if (_0x2651d3 == "fpdmerr") {
              jAlert("\u8BF7\u8F93\u5165\u5408\u6CD5\u53D1\u7968\u4EE3\u7801!", "\u8B66\u544A");
            } else {
              if (_0x2651d3 == "024") {
                jAlert("24\u5C0F\u65F6\u5185\u9A8C\u8BC1\u7801\u8BF7\u6C42\u592A\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF01", "\u8B66\u544A");
                $("#yzm_img")["hide"]();
              } else {
                if (_0x2651d3 == "016") {
                  jAlert("\u670D\u52A1\u5668\u63A5\u6536\u7684\u8BF7\u6C42\u592A\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF01", "\u8B66\u544A");
                  $("#yzm_img")["hide"]();
                } else {
                  if (_0x2651d3 == "020") {
                    jAlert("\u7531\u4E8E\u67E5\u9A8C\u884C\u4E3A\u5F02\u5E38\uFF0C\u6D89\u5ACC\u8FDD\u89C4\uFF0C\u5F53\u524D\u65E0\u6CD5\u4F7F\u7528\u67E5\u9A8C\u670D\u52A1\uFF01", "\u63D0\u793A");
                  } else {
                    if (_0x2651d3 == "errv") {
                      jAlert("\u5F53\u524D\u9875\u9762\u7248\u672C\u8F83\u4F4E\uFF0C\u8BF7\u6309CTRL-F5\u5237\u65B0\u9875\u9762\uFF01", "\u63D0\u793A");
                    } else {
                      if (_0x2651d3 != "") {
                        setTimeout(function () {
                          $("#yzm_img")["attr"]("src", "data:image/png;base64," + _0x2651d3);
                          $("#yzm_unuse_img")["attr"]("src", "data:image/png;base64," + _0x2651d3);

                          if (_0x1769c2 == "00") {
                            $("#yzminfo")["text"]("\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801\u6587\u5B57");
                          } else {
                            if (_0x1769c2 == "01") {
                              $("#yzminfo")["html"]("\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801\u56FE\u7247\u4E2D<font color=\"red\" size=\"4\" style=\"background:#C0C0C0\">\u7EA2\u8272</font>\u6587\u5B57");
                            } else {
                              if (_0x1769c2 == "02") {
                                $("#yzminfo")["html"]("\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801\u56FE\u7247\u4E2D<font color=\"yellow\" size=\"4\" style=\"background:#C0C0C0\">\u9EC4\u8272</font>\u6587\u5B57");
                              } else {
                                if (_0x1769c2 == "03") {
                                  $("#yzminfo")["html"]("\u8BF7\u8F93\u5165\u9A8C\u8BC1\u7801\u56FE\u7247\u4E2D<font color=\"blue\" size=\"4\" style=\"background:#C0C0C0\">\u84DD\u8272</font>\u6587\u5B57");
                                }
                              }
                            }
                          }

                          yzmSj = _0x1a96a9;
                          jmmy = _0x2b0c56;
                          key6 = _0x2e8ee0;
                        }, 500);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "timeout": 5000,
    "error": function (_0x11ade1, _0x2c42b8, _0x3a7f30) {
      if (retrycount == 9) {
        jAlert("\u7CFB\u7EDF\u7E41\u5FD9\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5!", "\u63D0\u793A");
      } else {
        retrycount = retrycount + 1;
        getYzmXx();
      }
    }
  });
  yzmWait = 2;
  yzmTime($("#yzm_img"));
}

function showTime() {
  var _0x229b47 = new Date();

  var _0x2be691 = _0x229b47["getTime"]();

  return _0x2be691;
}

我们注意到key9值的位置,

$["nnyd"]["yzm"](_0x1912a2, _0x478041, _0x41afd2)

这里需要知道$["nnyd"]["yzm"]的具体函数,分析后如下:


  _0x4abed0["prototype"]["yzm"] = function (_0x4a04f9, _0x1fcc0a, _0x4473d7) {
    var _0x3a01ad = new Array(3);

    _0x3a01ad[0] = _0x4a04f9 + _0x1fcc0a;
    _0x3a01ad[1] = _0x4a04f9 + _0x1fcc0a + _0x1fcc0a + _0x4a04f9;
    _0x3a01ad[2] = _0x4a04f9 + _0x4a04f9 + _0x1fcc0a + _0x4a04f9 + _0x1fcc0a + _0x4a04f9;

    var _0x155fec = _0x3a01ad[0]["substring"](0, 8);

    var _0x32d768 = _0x3a01ad[0]["substring"](8);

    var _0x559889 = _0x1e3a12(_0x155fec);

    var _0x5a173e = _0x559889["length"];

    for (var _0x2e3884 = 0; _0x2e3884 < _0x5a173e; _0x2e3884++) {
      for (var _0x39a07a = _0x2e3884 + 1; _0x39a07a < _0x5a173e; _0x39a07a++) {
        if (_0x559889[_0x2e3884] > _0x559889[_0x39a07a]) {
          _0x3f015b(_0x559889, _0x2e3884, _0x39a07a);
        }
      }
    }

    _0x155fec = _0x328421(_0x559889);

    var _0x3cf5d7 = _0x1e3a12(_0x32d768);

    var _0x5a173e = _0x3cf5d7["length"];
    var _0x38743f = 0;

    for (var _0x2e3884 = 0; _0x2e3884 < _0x5a173e; _0x2e3884++) {
      _0x38743f = _0x2e3884;

      for (var _0x39a07a = _0x2e3884 + 1; _0x39a07a < _0x5a173e; _0x39a07a++) {
        if (_0x3cf5d7[_0x38743f] > _0x3cf5d7[_0x39a07a]) {
          _0x38743f = _0x39a07a;
        }
      }

      _0x3f015b(_0x3cf5d7, _0x2e3884, _0x38743f);
    }

    _0x32d768 = _0x328421(_0x3cf5d7);

    var _0x8300db = _0x205ff1["encrypt"](_0x155fec) + _0x32d768;

    var _0x15339a = _0x3a01ad[1]["substring"](0, 9);

    var _0x3c7f1d = _0x3a01ad[1]["substring"](9, 17);

    var _0x1dd08a = _0x3a01ad[1]["substring"](17);

    var _0x591ade = _0x1e3a12(_0x15339a);

    var _0x5a173e = _0x591ade["length"];
    var _0x41c5e3 = 0;

    for (var _0x2e3884 = 0; _0x2e3884 < _0x5a173e; _0x2e3884++) {
      _0x41c5e3 = _0x2e3884;

      for (var _0x39a07a = _0x2e3884 + 1; _0x39a07a < _0x5a173e; _0x39a07a++) {
        if (_0x591ade[_0x41c5e3] > _0x591ade[_0x39a07a]) {
          _0x41c5e3 = _0x39a07a;
        }
      }

      _0x3f015b(_0x591ade, _0x2e3884, _0x41c5e3);
    }

    _0x15339a = _0x328421(_0x591ade);

    var _0x185cf9 = _0x1e3a12(_0x3c7f1d);

    var _0x2fa209 = _0x185cf9["length"];

    _0x3ad848["yzmdelay"](_0x4a04f9, _0x1fcc0a, _0x4473d7);

    console["log"]("\u9A8C\u8BC1\u7801\u9ED8\u8BA4\u5EF6\u65F6:312");

    for (var _0x2e3884 = 0; _0x2e3884 < _0x2fa209; _0x2e3884++) {
      for (var _0x39a07a = _0x2e3884 + 1; _0x39a07a < _0x2fa209; _0x39a07a++) {
        if (_0x185cf9[_0x2e3884] > _0x185cf9[_0x39a07a]) {
          _0x3f015b(_0x185cf9, _0x2e3884, _0x39a07a);
        }
      }
    }

    _0x3c7f1d = _0x328421(_0x185cf9);

    var _0x30d382 = _0x1e3a12(_0x1dd08a);

    var _0x3a8185 = _0x30d382["length"];

    for (var _0x2e3884 = 1; _0x2e3884 < _0x3a8185; _0x2e3884++) {
      for (var _0x39a07a = _0x2e3884; _0x39a07a > 0; _0x39a07a--) {
        if (_0x30d382[_0x39a07a] < _0x30d382[_0x39a07a - 1]) {
          _0x3f015b(_0x30d382, _0x39a07a, _0x39a07a - 1);
        } else {
          break;
        }
      }
    }

    _

这里只展示了部分数据,同时注意到一个参数,后面用得到:

0x5ecc18["setPublicKey"]("MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCjrcnzPya+QS6i5QND2EsIcrsP3/NRwgcYoaNyowpuIzQGDIySfhifm/+j41vJqwKd0D5Otjn6lF5mpUz0zvgMlVco5YytXIbBR8n7WfJ/1W4kTWYr9PM/sT3P23fS3xt13NHln7XgEjP7juv6z52OQOKxYKL/LFxoLkhQpUydWQIBEQ==");

如果有经验,你会知道可能和RSA加密相关,事实也是如此,上面已经对key9的算法位置分析清楚了,下面对flwq39进行分析,实际上,flwq39也是在这个文件中,我使用vscode对解密后的js代码进行了格式化,并查找了flwq39这个关键字,发现如图:

因此,我们继续分析会发现该参数是在请求前拼接完成的,并且关键字本身被替换了:

 反向找到调用的函数就会发现最终是调用了RSA加密算法,其中PublicKey就是

MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCjrcnzPya+QS6i5QND2EsIcrsP3/NRwgcYoaNyowpuIzQGDIySfhifm/+j41vJqwKd0D5Otjn6lF5mpUz0zvgMlVco5YytXIbBR8n7WfJ/1W4kTWYr9PM/sT3P23fS3xt13NHln7XgEjP7juv6z52OQOKxYKL/LFxoLkhQpUydWQIBEQ==

在验证码获取后返回包如下:

jQuery11020854931324645166_1625223145135({"key1":"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","key2":"2021-07-02 18:34:48","key3":"43017c78ec891a4b9406501694f0b479","key4":"01","key5":"2","key6":"402887f17a53027c017a66d4d62d72d0"})

 其中key1是经过base64编码的图片数据,key2是验证码的时间,另外注意到key3和key4及key6。

其中key4分为4种情况分别为输入全部、黄色、红色、蓝色,对应00,01,02,03。余下的参数在验证阶段用到。

同理,在查验阶段,请求如下:

https://fpcy.anhui.chinatax.gov.cn/NWebQuery/vatQuery?callback=jQuery11020854931324645166_1625223145135&key1=034012000211&key2=12345678&key3=20210702&key4=123456&fplx=10&yzm=MK&yzmSj=2021-07-02+18%3A34%3A48&index=43017c78ec891a4b9406501694f0b479&key6=402887f17a53027c017a66d4d62d72d0&publickey=2021-07-02+18%3A34%3A48&key9=ac558f9ae05a94c21dc504f5d8882b9d&_=1625223145137&flwq39=Ky8pYUqln7zaEZcxF9XZw3fAsiOM%2F92RmTxy%2BNAtDo4f1h3c1yHQJZNESl5Nz9Xq5Mu7bEeBkFlPgerOBnR1pnLviLn4WLkMTtzsLy%2BMe2wPu%2B%2FFaiszckIGS%2F1Z5YZ4zusosj68YLZ0hRk53UWbrWz9xg%2BC3XRGwEWyqbzg0XE%3D

这里注意到

key1=发票代码
key2=发票号码
key3=发票日期
key4=校验码或者不含税的金额
fplx=发票类型,一个函数
yzm=验证码
yzmsj=获取验证码请求的返回包里的key2
index=获取验证码请求的返回包里的Key3
key6=获取验证码请求的返回包里的Key6
publickey=验证码时间
key9=加密参数
flwq39=加密参数

这里的key9和flwq39在

$["nnyd"]["cy"]

这个对应的函数中,key9和flwq39算法和上面的类似。

此外注意到fplx这种参数,也在这几个js文件中,这里给出具体的函数名:

var code=["144031539110", "131001570151", "133011501118", "111001571071"];
    function alxd(a) {
    var b;
    var c = "99";
    if (a.length == 12) {
        b = a.substring(7, 8);
        for (var i = 0; i < code.length; i++) {
            if (a == code[i]) {
                c = "10";
                break
            }
        }
        if (c == "99") {
            if (a.charAt(0) == '0' && a.substring(10, 12) == '11') {
                c = "10"
            }
            if (a.charAt(0) == '0' && (a.substring(10, 12) == '04' || a.substring(10, 12) == '05')) {
                c = "04"
            }
            if (a.charAt(0) == '0' && (a.substring(10, 12) == '06' || a.substring(10, 12) == '07')) {
                c = "11"
            }
            if (a.charAt(0) == '0' && a.substring(10, 12) == '12') {
                c = "14"
            }
        }
        if (c == "99") {
            if (a.substring(10, 12) == '17' && a.charAt(0) == '0') {
                c = "15"
            }
            if (c == "99" && b == 2 && a.charAt(0) != '0') {
                c = "03"
            }
        }
    } else if (a.length == 10) {
        b = a.substring(7, 8);
        if (b == 1 || b == 5) {
            c = "01"
        } else if (b == 6 || b == 3) {
            c = "04"
        } else if (b == 7 || b == 2) {
            c = "02"
        }
    }
    return c
}

通过使用php的v8js拓展,我们可以实现接口编写:

二者结果一致。

至此,全部参数已经解密部分完毕。

第三步,算法的完全还原,脱离js环境,这里我使用C#实现算法还原和脱离

首先,我们需要知道的是在核心的算法中,源代码使用了ob进行了混淆,我们使用第三方软件进行初次还原时,也只能还原一部分,核心的内容基本会被还原,但是生成的代码还是无法完全被理解阅读,基于此,需要二次还原,这里注意到Ob混淆的核心思想,是一个大数组和若干个解密函数,后续的代码里不断的调用解密函数进行解密。

设计如下:通过分析可以注意到解密函数的前缀是_开头的,后续是)]或其他的组合,因此,我们需要使用提取函数名,在调用时,才能知道那些函数可以还原,同时在提取时也随同获取调用的参数,如果参数中包含变量,则直接忽略,并在调用成功后进行替换。

 string[] ret = getBValueT(djm, "_", "\\)");
            if (ret != null && ret.Count() > 0)
            {
                foreach (string s in ret)
                {
                    if (s.IndexOf("=") == -1 && s.IndexOf(":") == -1 && s.IndexOf(",") != -1)
                    {
                        listBox1.Items.Add("_" + s + ")");
                        listBox1.Items.Add("_" + s + "))");
                        File.AppendAllText("function.txt", "_0x" + s + ")" + ";\r\n");
                    }
                }
              
            }
            //第二种情况
            ret = getBValueT(djm, "_", "\\]");
            if (ret != null && ret.Count() > 0)
            {
                foreach (string s in ret)
                {
                    if (s.IndexOf(",") != -1)
                    {
                        listBox1.Items.Add("_" + s + "]");
                        listBox1.Items.Add("_" + s + "");
                        File.AppendAllText("function.txt", "_" + s + ")" + ";\r\n");
                    }
                }
              
            }
            //第三种情况
            ret = getBValueT(djm, "\\[_", "\\]");
            if (ret != null && ret.Count() > 0)
            {
                foreach (string s in ret)
                {
                    if (s.IndexOf(",") != -1)
                    {
                        listBox1.Items.Add("[_" + s + "]");
                        listBox1.Items.Add("_" + s + "");
                        File.AppendAllText("function.txt", "_" + s + ")" + ";\r\n");
                    }
                }
               
            }
            //第四种情况
            ret = getBValueT(djm, "\\(_", "\\)");
            if (ret != null && ret.Count() > 0)
            {
                foreach (string s in ret)
                {
                    if (s.IndexOf(",") != -1)
                    {
                        listBox1.Items.Add("(_" + s + ")");
                        listBox1.Items.Add("(_" + s + "))");
                        File.AppendAllText("function.txt", "_" + s + ")" + ";\r\n");
                    }
                }
              //  label3.Text = "匹配到" + listBox1.Items.Count + "个函数";
            }
 try
            {
                List<string> ret = new List<string>();
                Regex regex = new Regex("(?<=(" + sStr + "))0x[0-9a-z]{4,6}[\\[|\\(][.\\s\\S]*?(?=(" + eStr + "))", RegexOptions.Singleline|RegexOptions.Multiline);

                MatchCollection mc = regex.Matches(str);
                for (int i = 0; i < mc.Count; i++)
                {
                    ret.Add(mc[i].Value);
                }
                return ret.ToArray();
            }
            catch
            {
                return new string[] { };
            }

 通过上述操作,我们就能最大程度还原出原始的代码段。

接着,彻底逆向还原使用其他语言改写,如果你看过本文,并对相关js有分析,你大概会知道,核心部分就是涉及几个加密算法,如md5和移位的一些操作。但其核心的算法如下:

第一个是Gen函数

第二个是key9

 其他的类似。部分代码如下图:


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

国家税务总局全国增值税发票查验平台网站js逆向分析及全逆向算法还原 的相关文章

  • Java笔试题

    精选30道Java笔试题解答 都是一些非常非常基础的题 是我最近参加各大IT公司笔试后靠记忆记下来的 经过整理献给与我一样参加各大IT校园招聘的同学们 纯考Java基础功底 老手们就不用进来了 免得笑话我们这些未出校门的孩纸们 但是IT公司
  • EasyExcel——多sheet、有合并单元格的excel导入

    EasyExcel 读Excel官方文档链接 maven依赖
  • 系统运维-Linux Mariadb数据库基本命令教程

    Mariadb 是MySQL数据库的一个分支 它与MySQL比较有更优的存储引擎 运行速度快等优势 实验环境 Rocky 9 0 本地yum 安装Mariadb yum install mariadb y 开启服务并设置一下自启动 syst
  • mysql常用命令

    1 显示所有数据库 show database 2 显示所有表 show tables 3 显示表结构 desc 表名 4 查询所有表 select from 表名 参考 1 MYSQL常用SQL命令 http hi baidu com g
  • 限制input输入符合规则的浮点数

    给指定的dom添加事件 col sm 2 min goods amount keydown function e return formatInput e 限制input输入符合规则的浮点数 param type e 键盘事件 param
  • sizeof,strlen-----关于两者的一些小题解

    思维导图 目录 做题先知 第一波题目 一维数组 第一波题目解答 第二波题目 2 1字符数组为 char arr a b c d e f 详细题解 第三波题目 字符数组 char arr abcdef 详细题解 第四波题目 char p ab

随机推荐

  • 用Typora+PicGo搞定多个平台发文和微信公众号排版

    文章目录 如何开启公众号写作新思路 1 本文概述 1 1 适用人群 1 2 阅读完本文你可以获得什么 1 3 你需要什么 1 4 原理 2 安装npm 3 注册码云Gitee 3 1 新建仓库 3 2 创建私人令牌 4 安装PicGo 4
  • 【数据挖掘】期末复习:ID3、DBSCAN、关联分析、离群点挖掘等

    文章目录 小题 一些要背 计算 大题 分类 ID3 C4 5 CART Gini系数 K近邻 ID3 C4 5 K近邻优缺点 分类评价 朴素贝叶斯 聚类 K means DBSCAN 一趟聚类算法 层次聚类 关联分析 离群点挖掘 OF1 O
  • VMware Workstation 不可恢复错误: (vcpu-0),Exception 0xc0000005 (access violation) has occurred.

    在使用VMware虚拟机的时候可能会出现VMware Workstation 不可恢复错误 vcpu 0 Exception 0xc0000005 access violation has occurred 的报错情况 经常出现在启动 挂起
  • 【游戏音效】Unity集成Wwise并进行开发的全流程教程(一)准备工作

    集成教程 游戏音效 Unity集成Wwise并进行开发的全流程教程 二 Wwise项目 游戏音效 Unity集成Wwise并进行开发的全流程教程 三 脚本接入Unity 前言 Unity有自己的原生音乐功能 AduioSound 但是这个功
  • C++ 泛型算法 std::find() ,用于在数组或标准库容器中查找指定元素

    find 函数是一个 泛型算法 可以用于操作所有STL容器 它用于在数组或标准库容器 如vector map 中查找指定元素 查找成功则返回一个指向指定元素的迭代器 查找失败则返回end迭代器 注意不是返回 true or false 代码
  • java科学计数法转换为普通数字_Java BigDecimal toString() 的转换和输出

    BigDecimal 的 toString 方法将会把 BigDecimal 通过字符串的方式输出 这个方法将会在必要的时候使用指数进行输出 具体的转换步骤是按照下面的步骤进行转换的 BigDecimal的非标度值的绝对值用字符 0 到 9
  • linxu/torch/pytorch会自动安装 cuda

    如下图所示
  • Android 是否可支持 exFAT 格式 U 盘?如何使 Android 设备支持 exFAT

    Android 是否可支持 exFAT 格式 U 盘 如何使 Android 设备支持 exFAT exFAT 文件系统是一种适用于移动设备和嵌入式系统的文件系统 它具有更好的兼容性和更高的性能 然而 并非所有的 Android 设备都原生
  • 华为OD机试真题-完美走位/滑动窗口【2023Q1】

    输入一个长度为4的倍数的字符串 字符串中仅包含WASD四个字母 将这个字符串中的连续子串用同等长度的仅包含WASD的字符串替换 如果替换后整个字符串中WASD四个字母出现的频数相同 那么我们称替换后的字符串是 完美走位 求子串的最小长度 如
  • 2023华为OD机试真题【严格递增字符串】【2023.Q2】

    题目描述 定义字符串完全由 A 和 B 组成 当然也可以全是A 或全是 B 如果字符串从前往后都是以字典序排列的 那么我们称之为严格递增字符串 给出一个字符串s 允许修改字符串中的任意字符 即可以将任何的 A 修改成 B 也可以将任何的 B
  • dll signing issue

    1 Verify if a dll has been signed sn exe v module dll Scenario sometimes for security reasons a Net program requires all
  • 命令行_第二篇 Anaconda Prompt 命令提示符

    Anaconda 安装外接库过程 1 打开Anaconda Prompt 输入conda list 就会显示已经安装好的库 2 如果已安装库中没有所需的库 则需要手动进行安装 3 pip install 外接库 更新所需要的外接库 Anac
  • 用 h2 替换 hsql

    开发时用hsql做数据库 没什么问题 部署的时候 碰到数据量比较大的情况 就有点感觉慢了 这个时候 想替换方案时 考虑了几个可能的替代 一个是mysql 肯定没问题 但是部署麻烦 被否定了 其他的java数据库 可选的包括 mocki 这个
  • C语言学习

    为了更好的理解数据结构 开始重温C语言 以前学习过C语言 所以此笔记可能有些天马行空 不系统 挂个学习链接 C语言实例说明 解剖C语言 C语言教程 C语言网 dotcpp com 1B 1byte 字节 8bit 一字节存两位16进制数 以
  • 数据科学猫:强化学习的定义

    进击的橘子猫正式改名上线啦 我的CSDN主页 https blog csdn net Orange Spotty Cat 也欢迎大家搜索微信公众号 进击的橘子猫 我也会定期分享数据科学 Python 大数据 项目管理与PPT的相关知识 让我
  • DUT处理延迟 对Monitor采数和验证环境结束机制的影响分析

    1 问题背景 一句话描述 验证环境中 当激励完成发送时 由于DUT存在处理延迟 monitor在延迟一段时间后才能采集到DUT完整的输出 如何设计验证环境的结束机制 此处的验证环境结束机制 可以认为是main phase的结束控制 但并不单
  • 21. Merge Two Sorted Lists

    题目描述 将两个升序链表合并为一个新的 升序 链表并返回 新链表是通过拼接给定的两个链表的所有节点组成的 示例 1 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img 0VfjZ6Ct 1686493063120 i
  • STM32CubeMX工程配置说明

    一 STM32CubeMX配置 1 1 设置时钟 单片机的时钟 相当于人的心跳 只要单片机工作 必须要开启时钟 STM32单片机共有4个时钟来源 名称 缩写 频率 外部连接 功能 用途 特性 外部高速晶体振荡器 HSE 4 16MHz 4
  • Android手把手实战APP首页 下拉刷新 自动加载

    一 概述 作为一名三年Android开发经验的程序员 今天和大家一起实战一款APP的首页功能 这个首页在我们平时接触中还是很常见的 虽然页面简单 但是里面涉及的功能点还是挺多的 代码如有不足的还望各路同仁指点一二 页面中使用的开发库 整个首
  • 国家税务总局全国增值税发票查验平台网站js逆向分析及全逆向算法还原

    本文教程针对的是2021年7月2日时国税查验平台的js分析 其中版本号为V2 0 06 009 主要分析内容为key9和flwq39以及fplx这3个参数的算法 其中key9分为获取验证码阶段和查验阶段 算法有所区别 flwq39同理 教程