Broadm 发表于 2023-2-14 21:46

解码 Javascript 文件之 C# 正则替换

在Web前端逆向时,经常会遇到混肴加密的JS,比如下面的原始JS

var _0x1056b1=_0x195f;(function(_0x5d4e30,_0x48c9c6){var _0xc2c325=_0x195f,_0x50f292=_0x5d4e30();while(!![]){try{var _0x461dae=parseInt(_0xc2c325(0x1e7))/0x1+-parseInt(_0xc2c325(0x1d4))/0x2+-parseInt(_0xc2c325(0x1d6))/0x3+parseInt(_0xc2c325(0x1d7))/0x4+parseInt(_0xc2c325(0x1f3))/0x5*(parseInt(_0xc2c325(0x1f8))/0x6)+parseInt(_0xc2c325(0x1e8))/0x7+-parseInt(_0xc2c325(0x1df))/0x8;if(_0x461dae===_0x48c9c6)break;else _0x50f292['push'](_0x50f292['shift']());}catch(_0x436e53){_0x50f292['push'](_0x50f292['shift']());}}}(_0x4309,0x920ef),$(document)(function(){var _0x11c06f=_0x1056b1,_0x284d4d=window;$(_0x11c06f(0x1f7))['filter'](function(){var _0x214f26=_0x11c06f;return this==_0x284d4d;})(_0x11c06f(0x1f2)),$(_0x11c06f(0x1f7))(function(){var _0x1c5b20=_0x11c06f;return this+'#'==_0x284d4d;})['addClass']('active');}));function _0x195f(_0x2630a3,_0x13a8ed){var _0x430959=_0x4309();return _0x195f=function(_0x195fba,_0x490f64){_0x195fba=_0x195fba-0x1d4;var _0x56a5ba=_0x430959;return _0x56a5ba;},_0x195f(_0x2630a3,_0x13a8ed);}function switch_proj(_0x22df2b){var _0x52381c=_0x1056b1;$({'url':_0x52381c(0x1ed),'type':'POST','data':{'project_id':_0x22df2b['id']},'dataType':'json','success':function(_0x5f5891){var _0x5cbb93=_0x52381c;response=_0x5f5891,_0x5f5891=_0x5f5891;if(response=='success'){active_project=document(_0x5cbb93(0x1e5));var _0x5e20bf=document['getElementById'](_0x22df2b['id']);active_project=_0x5e20bf,active_project=document['getElementById']('current_active_project2'),active_project['innerText']=_0x5e20bf;}else alert(_0x5f5891);}});}function _0x4309(){var _0x5cbed7=['6101864rlJFPI','data','textContent','hide','ajax','getElementById','current_active_project','reload','453406xKGppO','2619750tfYSkd','href','#projectcreation_error','ready','#projecttext','/switch-project','project_name','innerText','response','POST','active','35IfdNdC','#projectcreation_success','projectcreation_success','create','ul.nav\x20a','435684KAJSHB','498572KPcLCy','location','1257909VYUmQG','2774492jOaOCZ','#createProjectSpinner','/project-handling','addClass','content','show','projectcreation_error','filter'];_0x4309=function(){return _0x5cbed7;};return _0x4309();}function create_project(){var _0x447cef=_0x1056b1;$(_0x447cef(0x1ec))(),$(_0x447cef(0x1d8))(),project_name=document(_0x447cef(0x1ee))['value'],$({'url':_0x447cef(0x1d9),'type':_0x447cef(0x1f1),'data':{'action':_0x447cef(0x1f6),'project_name':project_name},'success':function(_0x1fcfdb){var _0x3c6a45=_0x447cef;$(_0x3c6a45(0x1ec))(),$('#createProjectSpinner')['hide']();var _0x25fdf8=_0x1fcfdb,_0x190897=_0x1fcfdb;_0x25fdf8=='success'?($(_0x3c6a45(0x1f4))(),document(_0x3c6a45(0x1f5))['textContent']=_0x190897,location()):($(_0x3c6a45(0x1ea))(),document(_0x3c6a45(0x1dd))=_0x190897);}});}

上面的JS文件几乎无法阅读,这时候我们先要格式化它,比如拿到VSCode中使用格式化插件处理一下,然后再人工处理,把不容易理解的混肴变量重命名一下,之后可以得到如下的JS代码:

function __getArray() {
    var array = [
      "6101864rlJFPI",
      "data",
      "textContent",
      "hide",
      "ajax",
      "getElementById",
      "current_active_project",
      "reload",
      "453406xKGppO",
      "2619750tfYSkd",
      "href",
      "#projectcreation_error",
      "ready",
      "#projecttext",
      "/switch-project",
      "project_name",
      "innerText",
      "response",
      "POST",
      "active",
      "35IfdNdC",
      "#projectcreation_success",
      "projectcreation_success",
      "create",
      "ul.nav a",
      "435684KAJSHB",
      "498572KPcLCy",
      "location",
      "1257909VYUmQG",
      "2774492jOaOCZ",
      "#createProjectSpinner",
      "/project-handling",
      "addClass",
      "content",
      "show",
      "projectcreation_error",
      "filter",
    ];
    return array;
}

function _getName(index) {
    var array = __getArray();
    var _index = _index - 0x1d4;
    var name = array;
    return name;
}

(function (_getArray, _break_val) {
    var array = _getArray();
    while (true) {
      try {
            var result =
                parseInt(_getName(0x1e7)) / 0x1 +
                -parseInt(_getName(0x1d4)) / 0x2 +
                -parseInt(_getName(0x1d6)) / 0x3 +
                parseInt(_getName(0x1d7)) / 0x4 +
                (parseInt(_getName(0x1f3)) / 0x5) *
                (parseInt(_getName(0x1f8)) / 0x6) +
                parseInt(_getName(0x1e8)) / 0x7 +
                -parseInt(_getName(0x1df)) / 0x8;
            if (result === _break_val) break;
            else array["push"](array["shift"]());
      } catch (_0x436e53) {
            array["push"](array["shift"]());
      }
    }
})(__getArray, __break_val);

$(document)(function () {
    var value = window;
    $(_getName(0x1f7))
    ["filter"](function () {
      return this == value;
    })
    (_getName(0x1f2));
    $(_getName(0x1f7))
    (function () {
      return this + "#" == value;
    })
    ["addClass"]("active");
});

function switch_proj(model) {
    $({
      url: _getName(0x1ed),
      type: "POST",
      data: { project_id: model["id"] },
      dataType: "json",
      success: function (data) {
            response = data;
            data = data;
            if (response == "success") {
                active_project = document(_getName(0x1e5));
                var attr = document["getElementById"](model["id"]);
                active_project = attr;
                active_project = document["getElementById"]("current_active_project2");
                active_project["innerText"] = attr;
            } else alert(data);
      },
    });
}

function create_project() {
    $(_getName(0x1ec))();
    $(_getName(0x1d8))();
    project_name = document(_getName(0x1ee))["value"];
    $({
      url: _getName(0x1d9),
      type: _getName(0x1f1),
      data: { action: _getName(0x1f6), project_name: project_name },
      success: function (data) {
            $(_getName(0x1ec))();
            $("#createProjectSpinner")["hide"]();
            var value1 = data;
            var value2 = data;

            if (value1 == "success") {
                $(_getName(0x1f4))();
                document(_getName(0x1f5))["textContent"] = value2;
                location();
            } else {
                $(_getName(0x1ea))();
                document(_getName(0x1dd)) = value2;
            }
      },
    });
}


我们可以看到,上面的代码已经很容易阅读了,但是还是有问题,很明显代码使用了一个数组,把部分参数混肴加密了,这时候我们需要替换掉这些地方 , 比如_getName(0x1e7)
由于本人比较收悉C#语言, 下面我使用C#编写的正则替换的代码, 把解码后的JS输出到一个新的文件


using System;
using System.Text.RegularExpressions;


var array = new string[]{
    "6101864rlJFPI",
    "data",
    "textContent",
    "hide",
    "ajax",
    "getElementById",
    "current_active_project",
    "reload",
    "453406xKGppO",
    "2619750tfYSkd",
    "href",
    "#projectcreation_error",
    "ready",
    "#projecttext",
    "/switch-project",
    "project_name",
    "innerText",
    "response",
    "POST",
    "active",
    "35IfdNdC",
    "#projectcreation_success",
    "projectcreation_success",
    "create",
    "ul.nav 20a",
    "435684KAJSHB",
    "498572KPcLCy",
    "location",
    "1257909VYUmQG",
    "2774492jOaOCZ",
    "#createProjectSpinner",
    "/project-handling",
    "addClass",
    "content",
    "show",
    "projectcreation_error",
    "filter"
};


string? _getName(int index)
{
    var _index = index - 0x1d4;
    string? funcName = array;
    return funcName;
}

var originJSFileName = "1.js";
var decodeJSFileName = "1.decode.js";

using FileStream fs = new(decodeJSFileName, FileMode.Create, FileAccess.Write);
using StreamWriter writer = new(fs);

//正则,用来匹配每行的 _getName(0x111)
var regex = new Regex("_getName\\((.+?)\\)");

//读取原始加密的js文件的所有行
var lines = File.ReadAllLines(originJSFileName);

//遍历处理每一行
foreach (var line in lines)
{
    //处理每行匹配正则的所有字符串
    var decodeLine = regex.Replace(line, new MatchEvaluator(match =>
    {
      var numberString = match.Groups.Value;
      if (numberString == "index")
      {
            return match.Value;
      }

      //提取函数中的数字索引参数
      int number;
      if (numberString.StartsWith("0x"))
      {
            number = Convert.ToInt32(numberString, 16);
      }
      else
      {
            _ = int.TryParse(numberString, out number);
      }

      //获取实际的解密参数并返回
      return $"\"{_getName(number)}\"";
    }));
    global::System.Console.WriteLine(decodeLine);

    //写入解码后的每一行到新的文件中
    writer.WriteLine(decodeLine);
}


Console.WriteLine("完成解码");



最终我得到的解码后的JS代码如下:
function __getArray() {
    var array = [
      "6101864rlJFPI",
      "data",
      "textContent",
      "hide",
      "ajax",
      "getElementById",
      "current_active_project",
      "reload",
      "453406xKGppO",
      "2619750tfYSkd",
      "href",
      "#projectcreation_error",
      "ready",
      "#projecttext",
      "/switch-project",
      "project_name",
      "innerText",
      "response",
      "POST",
      "active",
      "35IfdNdC",
      "#projectcreation_success",
      "projectcreation_success",
      "create",
      "ul.nav a",
      "435684KAJSHB",
      "498572KPcLCy",
      "location",
      "1257909VYUmQG",
      "2774492jOaOCZ",
      "#createProjectSpinner",
      "/project-handling",
      "addClass",
      "content",
      "show",
      "projectcreation_error",
      "filter",
    ];
    return array;
}

function _getName(index) {
    var array = __getArray();
    var _index = _index - 0x1d4;
    var name = array;
    return name;
}

(function (_getArray, _break_val) {
    var array = _getArray();
    while (true) {
      try {
            var result =
                parseInt("active") / 0x1 +
                -parseInt("6101864rlJFPI") / 0x2 +
                -parseInt("textContent") / 0x3 +
                parseInt("hide") / 0x4 +
                (parseInt("/project-handling") / 0x5) *
                (parseInt("filter") / 0x6) +
                parseInt("35IfdNdC") / 0x7 +
                -parseInt("#projectcreation_error") / 0x8;
            if (result === _break_val) break;
            else array["push"](array["shift"]());
      } catch (_0x436e53) {
            array["push"](array["shift"]());
      }
    }
})(__getArray, __break_val);

$(document)["create"](function () {
    var value = window["data"]["#projectcreation_success"];
    $("projectcreation_error")
    ["filter"](function () {
      return this["#projectcreation_success"] == value;
    })
    ["current_active_project"]("#createProjectSpinner");
    $("projectcreation_error")
    ["href"](function () {
      return this["#projectcreation_success"] + "#" == value;
    })
    ["addClass"]("active");
});

function switch_proj(model) {
    $["project_name"]({
      url: "435684KAJSHB",
      type: "POST",
      data: { project_id: model["id"] },
      dataType: "json",
      success: function (data) {
            response = data["1257909VYUmQG"];
            data = data["ready"];
            if (response == "success") {
                active_project = document["innerText"]("response");
                var attr = document["getElementById"](model["id"])["location"];
                active_project["location"] = attr;
                active_project = document["getElementById"]("current_active_project2");
                active_project["innerText"] = attr;
            } else alert(data);
      },
    });
}

function create_project() {
    $("ul.nav 20a")["/switch-project"]();
    $("ajax")["453406xKGppO"]();
    project_name = document["innerText"]("498572KPcLCy")["value"];
    $["project_name"]({
      url: "getElementById",
      type: "2774492jOaOCZ",
      data: { action: "show", project_name: project_name },
      success: function (data) {
            $("ul.nav 20a")["453406xKGppO"]();
            $("#createProjectSpinner")["hide"]();
            var value1 = data["1257909VYUmQG"];
            var value2 = data["reload"];

            if (value1 == "success") {
                $("addClass")["453406xKGppO"]();
                document["innerText"]("content")["textContent"] = value2;
                location["POST"]();
            } else {
                $("projectcreation_success")["453406xKGppO"]();
                document["innerText"]("2619750tfYSkd")["#projecttext"] = value2;
            }
      },
    });
}

流水 发表于 2023-2-15 09:48

Broadm 发表于 2023-2-15 09:04
https://www.babeljs.cn/
Babel 是一个 JavaScript 编译器。
我没看到Babel能解决我所描述的问题, 请给 ...

这个是菜老板,用他的https://github.com/Tsaiboss/decodeObfuscator
可以直接还原cd decodeObfuscator
node main.js a.js b.js

然后出来的结果
$(document)["ready"](function () {
var _0x284d4d = window["location"]["href"];
$("ul.nav a")['filter'](function () {
    return this["href"] == _0x284d4d;
})["addClass"]("active");
$("ul.nav a")["filter"](function () {
    return this["href"] + '#' == _0x284d4d;
})['addClass']('active');
});

function switch_proj(_0x22df2b) {
$["ajax"]({
    'url': "/switch-project",
    'type': 'POST',
    'data': {
      'project_id': _0x22df2b['id']
    },
    'dataType': 'json',
    'success': function (_0x5f5891) {
      response = _0x5f5891["response"];
      _0x5f5891 = _0x5f5891["data"];

      if (response == 'success') {
      active_project = document["getElementById"]("current_active_project");
      var _0x5e20bf = document['getElementById'](_0x22df2b['id'])["innerText"];
      active_project["innerText"] = _0x5e20bf;
      active_project = document['getElementById']('current_active_project2');
      active_project['innerText'] = _0x5e20bf;
      } else {
      alert(_0x5f5891);
      }
    }
});
}

function create_project() {
$("#projecttext")["hide"]();
$("#createProjectSpinner")["show"]();
project_name = document["getElementById"]("project_name")['value'];
$["ajax"]({
    'url': "/project-handling",
    'type': "POST",
    'data': {
      'action': "create",
      'project_name': project_name
    },
    'success': function (_0x1fcfdb) {
      $("#projecttext")["show"]();
      $('#createProjectSpinner')['hide']();
      var _0x25fdf8 = _0x1fcfdb["response"];
      var _0x190897 = _0x1fcfdb["content"];
      _0x25fdf8 == 'success' ? ($("#projectcreation_success")["show"](), document["getElementById"]("projectcreation_success")['textContent'] = _0x190897, location["reload"]()) : ($("#projectcreation_error")["show"](), document["getElementById"]("projectcreation_error")["textContent"] = _0x190897);
    }
});
}

Broadm 发表于 2023-2-15 09:47

代码的思路没有问题, 其中有个循环修改数组的代码,被我遗漏了, 执行一下就能得到真实的数组了,然后就没有问题了
循环的代码如下
(function (_getArray, _break_value) {
var array = _getArray();
while (true) {
    try {
      var value =
      parseInt(getName(0x1e7)) / 0x1 +
      -parseInt(getName(0x1d4)) / 0x2 +
      -parseInt(getName(0x1d6)) / 0x3 +
      parseInt(getName(0x1d7)) / 0x4 +
      (parseInt(getName(0x1f3)) / 0x5) * (parseInt(getName(0x1f8)) / 0x6) +
      parseInt(getName(0x1e8)) / 0x7 +
      -parseInt(getName(0x1df)) / 0x8;
      if (value === _break_value) break;
      else array["push"](array["shift"]());
    } catch (_0x436e53) {
      array["push"](array["shift"]());
    }
}
})(getArray, 0x920ef);

执行一下这个代码就能得到真实的数组了, 然后最终的解码后的JS是

$(document)["ready"](function () {
    var value = window["location"]["href"];
    $("ul.nav a")
    ["filter"](function () {
      return this["href"] == value;
    })
    ["addClass"]("active");
    $("ul.nav a")
    ["filter"](function () {
      return this["href"] + "#" == value;
    })
    ["addClass"]("active");
});

function switch_proj(model) {
    $["ajax"]({
      url: "/switch-project",
      type: "POST",
      data: { project_id: model["id"] },
      dataType: "json",
      success: function (data) {
            response = data["response"];
            data = data["data"];
            if (response == "success") {
                active_project = document["getElementById"]("current_active_project");
                var attr = document["getElementById"](model["id"])["innerText"];
                active_project["innerText"] = attr;
                active_project = document["getElementById"]("current_active_project2");
                active_project["innerText"] = attr;
            } else alert(data);
      },
    });
}

function create_project() {
    $("#projecttext")["hide"]();
    $("#createProjectSpinner")["show"]();
    project_name = document["getElementById"]("project_name")["value"];
    $["ajax"]({
      url: "/project-handling",
      type: "POST",
      data: { action: "create", project_name: project_name },
      success: function (data) {
            $("#projecttext")["show"]();
            $("#createProjectSpinner")["hide"]();
            var value1 = data["response"];
            var value2 = data["content"];

            if (value1 == "success") {
                $("#projectcreation_success")["show"]();
                document["getElementById"]("projectcreation_success")["textContent"] = value2;
                location["reload"]();
            } else {
                $("#projectcreation_error")["show"]();
                document["getElementById"]("projectcreation_error")["textContent"] = value2;
            }
      },
    });
}


再次感谢大家的支持, 谢谢 :lol

夜泉 发表于 2023-2-14 22:05

最终的代码是这个:

$(document).ready(function () {
var _0x284d4d = window.location.href;
$("ul.nav a").filter(function () {
    return this.href == _0x284d4d;
}).addClass("active");
$("ul.nav a").filter(function () {
    return this.href + "#" == _0x284d4d;
}).addClass("active");
});

function switch_proj(_0x22df2b) {
$.ajax({
    "url": "/switch-project",
    "type": "POST",
    "data": {
      "project_id": _0x22df2b.id
    },
    "dataType": "json",
    "success": function (_0x5f5891) {
      response = _0x5f5891.response;
      _0x5f5891 = _0x5f5891.data;

      if (response == "success") {
      active_project = document.getElementById("current_active_project");
      var _0x5e20bf = document.getElementById(_0x22df2b.id).innerText;
      active_project.innerText = _0x5e20bf;
      active_project = document.getElementById("current_active_project2");
      active_project.innerText = _0x5e20bf;
      } else alert(_0x5f5891);
    }
});
}

function create_project() {
$("#projecttext").hide();
$("#createProjectSpinner").show();
project_name = document.getElementById("project_name").value;
$.ajax({
    "url": "/project-handling",
    "type": "POST",
    "data": {
      "action": "create",
      "project_name": project_name
    },
    "success": function (_0x1fcfdb) {
      $("#projecttext").show();
      $("#createProjectSpinner").hide();
      var _0x25fdf8 = _0x1fcfdb.response;
      var _0x190897 = _0x1fcfdb.content;

      if (_0x25fdf8 == "success") {
      $("#projectcreation_success").show();
      document.getElementById("projectcreation_success").textContent = _0x190897;
      location.reload();
      } else {
      $("#projectcreation_error").show();
      document.getElementById("projectcreation_error").textContent = _0x190897;
      }
    }
});
}

awa2004 发表于 2023-2-15 00:33

平常看到浑浊的js代码就头晕,谢谢楼主分享

zjh889 发表于 2023-2-15 00:34

太复杂了,虽然看不懂,顶楼主一个!

Pwaerm 发表于 2023-2-15 03:09

厉害厉害支持楼主

libvkv58iwb 发表于 2023-2-15 06:45

楼主是大善人。

aa2923821a 发表于 2023-2-15 08:37

感谢楼主 刚好用上

悦来客栈的老板 发表于 2023-2-15 08:47

了解一下babel库吧,js的代码,由js库来解决更好。

Broadm 发表于 2023-2-15 09:04

悦来客栈的老板 发表于 2023-2-15 08:47
了解一下babel库吧,js的代码,由js库来解决更好。

https://www.babeljs.cn/
Babel 是一个 JavaScript 编译器。
我没看到Babel能解决我所描述的问题, 请给出示范谢谢

Broadm 发表于 2023-2-15 09:07

夜泉 发表于 2023-2-14 22:05
最终的代码是这个:

$(document).ready(function () {


好的,学习了,我也是初学,主要是分享下解析过程,应该哪步出错了,可以帮助指出那个代码写错了吗?
页: [1] 2 3
查看完整版本: 解码 Javascript 文件之 C# 正则替换