李恒道 发表于 2023-10-10 18:30

关于GF某脚本动态加载分析问题

作者声明
原作者青龙,代为发布


分析
样本https://greasyfork.org/zh-CN/scripts/463858
其中存在大量功能,但是代码明显跟功能不符
在首部下debugger断点发现没有任何运行
说明实际运行文件存在于Require文件中
二分法取消发现实际功能隐藏在
https://cdn.jsdelivr.net/gh/photocpea/Typr.js@e3e85e3cb33e5ec657f818d890757191163a06da/angular-ui.js

经典ob加密
直接提crpChar函数
var _0x7065 = ["yM9K", "lJaG", "DJ1Q", "thzS", "EfnL", "q21l", "o2zU", "CM9Y", "z3jL", "ugfY", "DKvz", "DfnJ", "nJy0", "C3vI", "venq", "DgeS", "BwvU", "BMrb", "runc", "mdSG", "EeXV", "ugTJ", "Buv2", "q2HY", "zwnO", "ywmY", "BY5J", "CgfY", "q3vo", "Bw9K", "Dc9Q", "vgLT", "BuTz", "zw5J", "Aw5K", "BNrm", "Bgvx", "zxj2", "CxvL", "CNLW", "tefh", "ysK7", "DgHL", "Ee5l", "BwfP", "kfDP", "Bg9J", "DgfY", "DwrH", "ywjV", "Axb0", "y29K", "l2fW", "Dgv4", "z25v", "Ct0W", "BI9L", "uLvZ", "icOV", "5yQG6l295BYc", "zgi2", "BgvU", "ywPH", "v3zT", "yNvI", "lY9U", "BwvZ", "nJmU", "DgeU", "EvrH", "y2Hf", "vw9l", "B3rL", "BfrV", "BgnM", "ChjV", "s0Ho", "lcbH", "khnF", "zw5L", "CMvH", "Df9S", "tcWG", "lJaU", "ngiZ", "AhvP", "r0vu", "zM9A", "qwj5", "DwvZ", "zgf0", "B0ns", "yxj0", "C2nY", "yxbW", "5AsN6lwM5AsP", "ihG2", "sNjf", "C29T", "B3bL", "t0HP", "z05H", "EwPb", "Bg9H", "vxrM", "BIHZ", "Ag9K", "q2fU", "zhLt", "uuzN", "v2LU", "we1m", "zwfH", "p3nL", "DfDP", "Dge7", "ntm3", "n2mW", "rfzQ", "y3jL", "C2uX", "DenV", "ys81", "zM4P", "B3ru", "yxzH", "nJq7", "DMvU", "EefI", "B3j0", "AgfU", "y21H", "ChqS", "C2vY", "CNvZ", "lMnV", "zM9Y", "ihnF", "Aw5N", "Awvs", "Ee9W", "yxrL", "Buj5", "uLDl", "DgTP", "y2TV", "tgD6", "sw50", "zwnA", "DeHL", "yxrH", "zhn0", "B3jN", "Dhnc", "y2f0", "EfrP", "BvfL", "zwnR", "wNDH", "y29U", "u2nY", "ndq5", "ncKG", "C3rY", "A01h", "Cgf0", "ywr5", "DxrV", "CMvT", "BwvV", "EMHP", "Aw5P", "mge2", "ywrK", "C2fN", "Axn0", "6isA5PYS5BYc", "BYKG", "sgv4", "DeHx", "y2fS", "lNLV", "kJSG", "q3vZ", "o3nL", "As9U", "rfDS", "Chm6", "BI9Q", "B3vY", "Bhnx", "BMrV", "DgvU", "rwXL", "Dg9W", "C2HV", "s0Ts", "nwm0", "Ahr0", "DMfY", "B3zL", "zNjV", "zgvJ", "DKLW", "yvLX", "vxbK", "DgLV", "B2DY", "yLjm", "rMf0", "revt", "z2v0", "mcbt", "lMLJ", "De1L", "ywrt", "y2y5", "wLf4", "zMyZ", "ywrf", "AwnH", "AxqV", "rNPJ", "y2vS", "ExbL", "zhLZ", "B21L", "DMvY", "DKz5", "BgXg", "C3nH", "CfjL", "EwTb", "x2rH", "Dg9T", "Dgf0", "v1P5", "ywzH", "lJaX", "ndy4", "wMP6", "zxjY", "Dxro", "CgfK", "v2Xz", "yM5t", "ngvJ", "yxPK", "zxHp", "o2XV", "DsGP", "C19Z", "vuDo", "sfn3", "r01f", "Cg9U", "lwvJ", "lJm2", "AwzY", "Eg1b", "B3jP", "yM90", "ywjS", "Ag9Z", "B3HP", "mc4W", "C2vU", "zw91", "D3mG", "ExDZ", "Dg9t", "rwfJ", "uurl", "ywrL", "Bwv0", "zxnZ", "EfjL", "D3D3", "Cg9Z", "vMvY", "icHl", "uMvX", "Eg1F", "C3rH", "zsbh", "u3rH", "lZeX", "zgv0", "CM5P", "y1nq", "v0zm", "ChbS", "CIbM", "EK5A", "zgLZ", "yt1K", "nMrI", "rxzL", "AwXS", "y2LW", "EMH1", "B20V", "EevY", "zgvU", "yMXL", "zNjH", "qxbW", "yxn5", "zw50", "y2fU", "mtaU", "BgLR", "zgrH", "shr0", "yw1L", "AgvY", "C2v0", "y2HL", "CMvZ", "C2LV", "CMLW", "ywrF", "ChvZ", "DhjP", "ywLS", "CMvX", "ztKY", "Dgvd", "yxrP", "sezi", "y3jP", "sfrn"];
function _0x211c(_0x6a88bb, _0x7065c1) {
    return _0x211c = function (_0x211c56, _0x4e8cad) {
      _0x211c56 = _0x211c56 - 102;
      var _0x2874c9 = _0x7065;
      if (_0x211c["rWTdWT"] === undefined) {
            var _0x3963c6 = function (_0x54f47c) {
                var _0x46f442 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=";
                var _0x422a4b = "",
                  _0x37f5bd = "";
                for (var _0x54a79a = 0,
                  _0x402494, _0x11b22a, _0x1cfd15 = 0; _0x11b22a = _0x54f47c["charAt"](_0x1cfd15++); ~_0x11b22a && (_0x402494 = _0x54a79a % 4 ? _0x402494 * 64 + _0x11b22a : _0x11b22a, _0x54a79a++ % 4) ? _0x422a4b += String["fromCharCode"](255 & _0x402494 >> (- 2 * _0x54a79a & 6)) : 0) {
                  _0x11b22a = _0x46f442["indexOf"](_0x11b22a)
                }
                for (var _0x516f49 = 0,
                  _0x3bbb37 = _0x422a4b["length"]; _0x516f49 < _0x3bbb37; _0x516f49++) {
                  _0x37f5bd += "%" + ("00" + _0x422a4b["charCodeAt"](_0x516f49)["toString"](16))["slice"](- 2)
                }
                return decodeURIComponent(_0x37f5bd)
            };
            _0x211c["fNncXc"] = _0x3963c6,
                _0x6a88bb = arguments,
                _0x211c["rWTdWT"] = !![]
      }
      var _0x422c8f = _0x7065,
            _0x329e67 = _0x211c56 + _0x422c8f,
            _0xb05c11 = _0x6a88bb;
      return !_0xb05c11 ? (_0x2874c9 = _0x211c["fNncXc"](_0x2874c9), _0x6a88bb = _0x2874c9) : _0x2874c9 = _0xb05c11,
            _0x2874c9
    },
      _0x211c(_0x6a88bb, _0x7065c1)
};
跑一下函数解密
function crpChar(path, func_name) {
    let bind = path.scope.getBinding(func_name);
    let refer_list = bind.referencePaths;
    refer_list.forEach((item) => {
      let parent_path = item.parentPath;
      if (parent_path.node.type === "CallExpression") {
            let loc = parent_path.node.arguments.value;
            let str_node = types.stringLiteral(_0x211c(loc));
            parent_path.replaceInline(str_node);
      } else {
            if (parent_path.node.type === "VariableDeclarator") {
                crpChar(parent_path, parent_path.node.id.name);
            }
      }
    });
    path.remove()
}
let ast = parser.parse(originData);
const handleObfs = {
    VariableDeclarator(path) {
      let func_name = path.node.id.name;
      let init_name = path.node.init?.name;
      if (init_name === "_0x211c") {
            crpChar(path, func_name);
      }
    },
}
然后合并字符串
const handleString = {
    BinaryExpression(path) {
      const node = path.node
      if (node.right.type === 'StringLiteral' && node.left.type === 'StringLiteral') {
            path.replaceInline(types.stringLiteral(node.left.value + node.right.value));
      }
    }
}
得到了一个比较干净的样本

比较有意思的是偷了道哥的代码


我们主要目的是分析功能动态引入,所以不管了
根据Gm的特征找到了引入文件

其中https://note.youdao.com/yws/api/ ... 80a6ff331fb9?sev=j1是动态执行代码,已经被加密了


解密代码字符串是
_0x3c974e = decryptByDES(_0x3c974e["substring"](0, _0x3c974e["length"] - 16), _0x3c974e["substring"](_0x3c974e["length"] - 16, _0x3c974e["length"]))

密钥2e88a859b74e2b0c
解密代码
    function decryptByDES(_0x52ef6e, _0xb384d0) {
      var _0x1d45c7 = CryptoJS["enc"]["Utf8"]["parse"](_0xb384d0),
            _0x86a59a = CryptoJS["DES"]["decrypt"]({
                "ciphertext": CryptoJS["enc"]["Hex"]["parse"](_0x52ef6e)
            },
                _0x1d45c7, {
                "mode": CryptoJS["mode"]["ECB"],
                "padding": CryptoJS["pad"]["Pkcs7"]
            }),
            _0x37607d = _0x86a59a["toString"](CryptoJS["enc"]["Utf8"]);
      return _0x37607d
    }
标准的CryptoJS
直接解密

做了动态执行

从而实现动态配置






初音MIKU公主 发表于 2023-10-12 09:16

感谢大佬分享{:1_921:}

猫携 发表于 2023-10-12 11:34

谢谢分享,很实用~

daniel7785 发表于 2023-10-14 09:40

感谢分享,做个参考

ztqddj007 发表于 2023-10-16 07:57

感觉好牛逼 谢谢

xiaolei1314555 发表于 2023-10-16 08:15

很实用,感谢分享。

luoweili666 发表于 2023-10-16 14:57

感谢分享!
页: [1]
查看完整版本: 关于GF某脚本动态加载分析问题