Conceptos básicos de AST + demostración paso a paso de la reducción de JS ofuscado

parte basica

AST: Árbol de sintaxis abstracta (árbol de sintaxis abstracta) es una representación abstracta de la estructura gramatical del código fuente. Representa la estructura gramatical de un lenguaje de programación en forma de árbol, y cada nodo del árbol representa una estructura en el código fuente.

Sé que después de leer la definición, probablemente estés confundido: ¿Cuál es la representación abstracta de la estructura gramatical del código fuente? No tengas miedo, simplemente usaré una frase como ejemplo para ayudarte a entender:

¿Has bebido agua hoy?

Todo el mundo sabe que esta frase significa preguntar si bebiste agua hoy, pero ¿sabes en qué ingredientes consta esta frase?
Insertar descripción de la imagen aquí
Debo haber aprendido en clases de idioma chino cuando estaba en la escuela. Hay sujetos, predicados, objetos, atributos, etc. en una oración. Las palabras en la oración se dividen en sustantivos, verbos, preposiciones... varias palabras. Cuando estas palabras se combinan de acuerdo con ciertas reglas. Después de eso, se formó la oración anterior,

Y usted, que está leyendo el artículo ahora, definitivamente sabe y comprende el significado de la oración anterior, pero no necesariamente conoce la parte gramatical de cada palabra en esta oración y no sabe cuál es el sujeto y cuál es. el predicado. Esto es lo mismo que saber JavaScript. , pero no entiendo que AST es lo mismo.

entonces:

No conocer AST en sí no tendrá ningún impacto en su aprendizaje para usar JavaScript, pero si comprende y domina AST, entonces JavaScript puede verse un poco diferente ante sus ojos. Hasta cierto punto, comprender y dominar AST puede ayudarlo a comprender verdaderamente su esencia. del lenguaje JavaScript.

En este caso, ¿cómo podemos entender rápidamente AST?

La respuesta es muy simple: escriba una oración JS, llévela a AST para su análisis y luego mírela. Creo que la comprenderá pronto si es inteligente.

Sitio web de análisis de estructura gramatical AST en línea: https://asexplorer.net/

Echemos un vistazo al JS más simple.

var a=1;

La estructura de árbol de sintaxis de AST correspondiente al código:
Insertar descripción de la imagen aquí
Mirando de arriba a abajo, hay Programa, declaraciones, Declarador de Variable, Identificador y Literal. Todos estos son tipos estructurales de AST. Además de estos, hay muchos más. La lista es como sigue: ¿De qué sirve conocerlos
Insertar descripción de la imagen aquí
? Además de la capacidad mencionada anteriormente para profundizar la comprensión de JS, el mayor uso es ofuscar y restaurar el código JavaScript.

Los amigos que conocen JavaScript deben saber que JS tiene mucho azúcar sintáctico, y la ofuscación de cifrado de JS en realidad hace un uso completo de estos azúcares sintácticos. Cuando no solo domina JavaScript, sino que también comprende y domina AST, puede restaurar el código JS ofuscado hasta cierto punto desde la perspectiva de la estructura del árbol de sintaxis de AST, que es algo similar a la reducción de dimensionalidad, porque la ofuscación del cifrado JS se realiza en la expresión externa del código JS Manos y pies, mientras que la perspectiva de AST es más hacia el fondo.

Demostración de restauración de JS ofuscado

PD: Resuelva los problemas ambientales usted mismo en Baidu.
Código de prueba:

function MyFun(a,b){
    
    
        var c=a+b;
        var d=a*b+c;
        return c+d;
}
console.log(MyFun(10,20))

Código cifrado ofuscado:

var _0x305a = ['B8OBMcKcUQ==', 'w4Y2wrrCl8OT', 'wpHCpMKLRsOu', 'wpgfwo7DgMO4', 'wpVywozCqwHCucKV', 'HMK1VsOS', 'wrfCiSgfw7c0NGHCoAXCuH7CnyzDlMOdfXxHLDorfsOCwrzCnFNPw6I+cwQ=', 'SsO0PUdW', 'PcKRVQ==', 'UHbDj3xcw7ZY', 'UsO6OA==', 'wrjChmcfw70=', 'W8OnLURB', 'w6/CrATDncKcw6lF', 'IcOxw4DDiMOx', 'wr3Dp07DtUUfwrI=', 'N8KOesOsw58=', 'FR7DgS0p', 'AgPDjj0jcUI=', 'AsOYGMKFdg==', 'bcK0wrHCiMOt', 'w7HClAPDo8KVSsKe', 'wrbDhGR1', 'ABzDkCI1', 'Fg1fRsOE', 'w4XCocOJBGg=', 'w60AwpHCv8OJ', 'NcKLwpBPHW01', 'w4QGIWLDiw==', 'wqXCmmAT', 'FT9dMg==', 'LF7Du2sqwrrCqsKDRw==', 'wr/DsknDs3s=', 'wrXDhHR3BQ==', 'P8KKwphT', 'RHjDk2E=', 'w7FCY21yw7BV', 'w7tDa3E=', 'w77ClAo=', 'AcOWJMKKRsOCwpbDsRLDlHkTw5g/wqfCgDzCusOC', 'w6fDpAHDiRlpWQ==', 'wpgGwo3Dtg==', 'w4c+wqHDh2E=', 'fXjDpUspw5kAH1jDvcOGAMKhfiHCiFvCkcOLGMOqw5HDtsKTw5jDom7DmMOaYMKdwrs=', 'QhFqYQg=', 'wqHCsm3Ds0DCpsKB', 'w4cdwo4=', 'w75Cag==', 'w4YiEcO9wq1aIw==', 'w48XwovCvcOY', 'e1vDnHbCg8Kkdkp5', 'cEHDtUhR', 'asKwwonCjMOw', 'TsOaw4QMGsKswp4=', 'wqrDqULDqk8=', 'w7DCjHcsw4A=', 'w4N6worDksOo', 'WMKywpDDonI=', 'wo0GwqkKwrA=', 'DjRPKMKlwpROa8OCV8KxY8KYWGEuwobDgcO2', 'CcOZw5jDlcOO', 'bsK4wpLClsOT', 'w6YJw5APwoo=', 'w4EoHcO7wqU=', 'w4lHTTnCpcKkw6jCgUc=', 'wpNlwoHCvR7CocKZwoMe', 'w6XCt8O1I1A=', 'w7dff3Fv', 'FMKrQMORw6M=', 'w7fCgw7DtcKKUsKSLyA=', 'DMOyw6vDucO6', 'L1/Dt1nDuMOlwpQ=', 'w5MbLnLDgcKlwps=', 'wrXCvHHDrg==', 'w5EsHcOiwqc=', 'N8KUwo5QCw==', 'w6sdwo3Co8OUw7xB', 'VABoYw==', 'wrF7LhFwwo5O', 'Rj9O']; (function(_0x1f4b85, _0x305a4c) {
    
    
    var _0x796962 = function(_0x4b72d1) {
    
    
        while (--_0x4b72d1) {
    
    
            _0x1f4b85['push'](_0x1f4b85['shift']());
        }
    };
    _0x796962(++_0x305a4c);
} (_0x305a, 0xe7));
var _0x7969 = function(_0x1f4b85, _0x305a4c) {
    
    
    _0x1f4b85 = _0x1f4b85 - 0x0;
    var _0x796962 = _0x305a[_0x1f4b85];
    if (_0x7969['UkyMFX'] === undefined) {
    
     (function() {
    
    
            var _0x344906;
            try {
    
    
                var _0x1d345f = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
                _0x344906 = _0x1d345f();
            } catch(_0x1d3b2a) {
    
    
                _0x344906 = window;
            }
            var _0x14f0f1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
            _0x344906['atob'] || (_0x344906['atob'] = function(_0x3128ab) {
    
    
                var _0x23f475 = String(_0x3128ab)['replace'](/=+$/, '');
                var _0x32bdd4 = '';
                for (var _0x3da026 = 0x0,
                _0x372bba, _0x104d49, _0x5eb7a8 = 0x0; _0x104d49 = _0x23f475['charAt'](_0x5eb7a8++);~_0x104d49 && (_0x372bba = _0x3da026 % 0x4 ? _0x372bba * 0x40 + _0x104d49: _0x104d49, _0x3da026++%0x4) ? _0x32bdd4 += String['fromCharCode'](0xff & _0x372bba >> ( - 0x2 * _0x3da026 & 0x6)) : 0x0) {
    
    
                    _0x104d49 = _0x14f0f1['indexOf'](_0x104d49);
                }
                return _0x32bdd4;
            });
        } ());
        var _0x570ba5 = function(_0x257551, _0x1f613d) {
    
    
            var _0x3e9282 = [],
            _0x434903 = 0x0,
            _0x33fc11,
            _0x249601 = '',
            _0x2f07c3 = '';
            _0x257551 = atob(_0x257551);
            for (var _0x464f7e = 0x0,
            _0x4b3e63 = _0x257551['length']; _0x464f7e < _0x4b3e63; _0x464f7e++) {
    
    
                _0x2f07c3 += '%' + ('00' + _0x257551['charCodeAt'](_0x464f7e)['toString'](0x10))['slice']( - 0x2);
            }
            _0x257551 = decodeURIComponent(_0x2f07c3);
            var _0x94001b;
            for (_0x94001b = 0x0; _0x94001b < 0x100; _0x94001b++) {
    
    
                _0x3e9282[_0x94001b] = _0x94001b;
            }
            for (_0x94001b = 0x0; _0x94001b < 0x100; _0x94001b++) {
    
    
                _0x434903 = (_0x434903 + _0x3e9282[_0x94001b] + _0x1f613d['charCodeAt'](_0x94001b % _0x1f613d['length'])) % 0x100;
                _0x33fc11 = _0x3e9282[_0x94001b];
                _0x3e9282[_0x94001b] = _0x3e9282[_0x434903];
                _0x3e9282[_0x434903] = _0x33fc11;
            }
            _0x94001b = 0x0;
            _0x434903 = 0x0;
            for (var _0x27a73e = 0x0; _0x27a73e < _0x257551['length']; _0x27a73e++) {
    
    
                _0x94001b = (_0x94001b + 0x1) % 0x100;
                _0x434903 = (_0x434903 + _0x3e9282[_0x94001b]) % 0x100;
                _0x33fc11 = _0x3e9282[_0x94001b];
                _0x3e9282[_0x94001b] = _0x3e9282[_0x434903];
                _0x3e9282[_0x434903] = _0x33fc11;
                _0x249601 += String['fromCharCode'](_0x257551['charCodeAt'](_0x27a73e) ^ _0x3e9282[(_0x3e9282[_0x94001b] + _0x3e9282[_0x434903]) % 0x100]);
            }
            return _0x249601;
        };
        _0x7969['tMJLOX'] = _0x570ba5;
        _0x7969['vDRtQv'] = {
    
    };
        _0x7969['UkyMFX'] = !![];
    }
    var _0x4b72d1 = _0x7969['vDRtQv'][_0x1f4b85];
    if (_0x4b72d1 === undefined) {
    
    
        if (_0x7969['SqRviR'] === undefined) {
    
    
            _0x7969['SqRviR'] = !![];
        }
        _0x796962 = _0x7969['tMJLOX'](_0x796962, _0x305a4c);
        _0x7969['vDRtQv'][_0x1f4b85] = _0x796962;
    } else {
    
    
        _0x796962 = _0x4b72d1;
    }
    return _0x796962;
};
function _0x556652(_0x4a2332, _0x2634dc) {
    
    
    var _0x94d946 = function() {
    
    
        if (_0x7969('0xb', 'X*5E') !== _0x7969('0xc', 'WhTf')) {
    
    
            if (fn) {
    
    
                var _0x33221e = fn[_0x7969('0x35', 'hsTm')](context, arguments);
                fn = null;
                return _0x33221e;
            }
        } else {
    
    
            var _0x43616c = !![];
            return function(_0x550c05, _0x13d9c2) {
    
    
                if (_0x7969('0xa', '9uv1') !== _0x7969('0x1d', 'wdO$')) {
    
    
                    var _0x296878 = _0x43616c ?
                    function() {
    
    
                        if (_0x7969('0x22', 'NGkH') !== _0x7969('0x40', 't$pJ')) {
    
    
                            if (_0x13d9c2) {
    
    
                                if (_0x7969('0x21', '9kDW') === _0x7969('0x17', 'k(YQ')) {
    
    
                                    that[_0x7969('0x16', 'r8p)')] = function(_0x1c2524) {
    
    
                                        var _0x2972cc = {
    
    };
                                        _0x2972cc[_0x7969('0x11', 'k3XH')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x1f', 'Cu4J')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x3a', 'R*hj')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x26', 'V6wH')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x41', 'Bt5v')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x4e', 'kamb')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x10', 'a4uQ')] = _0x1c2524;
                                        _0x2972cc[_0x7969('0x9', 'uP&h')] = _0x1c2524;
                                        return _0x2972cc;
                                    } (func);
                                } else {
    
    
                                    var _0x34a69a = _0x13d9c2[_0x7969('0x20', 'sT$v')](_0x550c05, arguments);
                                    _0x13d9c2 = null;
                                    return _0x34a69a;
                                }
                            }
                        } else {
    
    
                            that = window;
                        }
                    }: function() {
    
    };
                    _0x43616c = ![];
                    return _0x296878;
                } else {
    
    
                    var _0x2c3174 = {
    
    };
                    _0x2c3174[_0x7969('0x8', 'pE[N')] = func;
                    _0x2c3174[_0x7969('0x32', 'WhTf')] = func;
                    _0x2c3174[_0x7969('0x47', 'sDkG')] = func;
                    _0x2c3174[_0x7969('0x27', 'YgD$')] = func;
                    _0x2c3174[_0x7969('0x23', '9uv1')] = func;
                    _0x2c3174[_0x7969('0x4a', '(^8)')] = func;
                    _0x2c3174[_0x7969('0x2a', 'Cu4J')] = func;
                    _0x2c3174[_0x7969('0x25', 'AWI1')] = func;
                    return _0x2c3174;
                }
            };
        }
    } ();
    var _0x23c1f6 = _0x94d946(this,
    function() {
    
    
        var _0x6e83c1 = function() {
    
    };
        var _0x3f3777;
        try {
    
    
            if (_0x7969('0x33', 'JKNM') !== _0x7969('0x45', 'k(YQ')) {
    
    
                var _0x584a01 = Function(_0x7969('0x30', 'uP&h') + _0x7969('0xf', 'V6wH') + ');');
                _0x3f3777 = _0x584a01();
            } else {
    
    
                var _0x30c130 = Function(_0x7969('0x44', 'YgD$') + _0x7969('0x34', 'Jler') + ');');
                _0x3f3777 = _0x30c130();
            }
        } catch(_0x5365b4) {
    
    
            if (_0x7969('0x19', 'D3T3') !== _0x7969('0x1c', 'uP&h')) {
    
    
                _0x3f3777 = window;
            } else {
    
    
                _0x3f3777[_0x7969('0x1', 'AWI1')][_0x7969('0x38', 'sJv5')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x12', 'O(f6')][_0x7969('0x2c', 'O(f6')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x1e', 'kamb')][_0x7969('0x48', 'aCn%')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x3e', ']zyO')][_0x7969('0xe', 'D3T3')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x31', 'jA(H')][_0x7969('0x4c', 'sJv5')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x24', '*20m')][_0x7969('0x3b', 'G1i2')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x7', '1MEH')][_0x7969('0x2a', 'Cu4J')] = _0x6e83c1;
                _0x3f3777[_0x7969('0x0', 'QGrn')][_0x7969('0x14', 'V6wH')] = _0x6e83c1;
            }
        }
        if (!_0x3f3777[_0x7969('0x39', 'aCn%')]) {
    
    
            if (_0x7969('0x4b', 'NGkH') !== _0x7969('0x3c', 'O(f6')) {
    
    
                _0x3f3777[_0x7969('0x36', 'WU*x')] = function(_0x4bdab5) {
    
    
                    if (_0x7969('0x29', 'zEsY') === _0x7969('0x46', 'wdO$')) {
    
    
                        var _0x5f33bc = {
    
    };
                        _0x5f33bc[_0x7969('0x37', 'R*hj')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x6', 'hsTm')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x43', 'JQ7t')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x2e', 'sJv5')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x3d', 'wdO$')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x49', 'U(TC')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x3f', 'zEsY')] = _0x4bdab5;
                        _0x5f33bc[_0x7969('0x1a', 'sT$v')] = _0x4bdab5;
                        return _0x5f33bc;
                    } else {
    
    
                        var _0x1b640b = firstCall ?
                        function() {
    
    
                            if (fn) {
    
    
                                var _0x3dd5c2 = fn[_0x7969('0x4d', 'D3T3')](context, arguments);
                                fn = null;
                                return _0x3dd5c2;
                            }
                        }: function() {
    
    };
                        firstCall = ![];
                        return _0x1b640b;
                    }
                } (_0x6e83c1);
            } else {
    
    
                var _0x345d2c = fn[_0x7969('0x4', '*20m')](context, arguments);
                fn = null;
                return _0x345d2c;
            }
        } else {
    
    
            _0x3f3777[_0x7969('0x36', 'WU*x')][_0x7969('0x2f', 'kamb')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x5', '9uv1')][_0x7969('0x2', 'WU*x')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x12', 'O(f6')][_0x7969('0x42', 'vJ8P')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x2d', 'sJv5')][_0x7969('0x2b', '*20m')] = _0x6e83c1;
            _0x3f3777[_0x7969('0xd', '(^8)')][_0x7969('0x15', 'a4uQ')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x1b', 'sT$v')][_0x7969('0x28', 'ijQK')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x1b', 'sT$v')][_0x7969('0x3', 'aCn%')] = _0x6e83c1;
            _0x3f3777[_0x7969('0x18', 'zEsY')][_0x7969('0x4f', 'k(YQ')] = _0x6e83c1;
        }
    });
    _0x23c1f6();
    var _0x245e10 = _0x4a2332 + _0x2634dc;
    var _0x5d196d = _0x4a2332 * _0x2634dc + _0x245e10;
    return _0x245e10 + _0x5d196d;
}
console[_0x7969('0x13', 'a4uQ')](_0x556652(0xa, 0x14));

Compruebe si el código ofuscado se puede ejecutar normalmente:
Insertar descripción de la imagen aquí
el código ofuscado se puede ejecutar normalmente,

Análisis preliminar del código ofuscado. La función _0x7969 aparece en grandes cantidades en todo el JS ofuscado, y todas aparecen en la forma de _0x7969['xxx'] o _0x7969('xxx','xxx'), donde xxx son todas cadenas desordenadas. , de donde podemos sacar la conclusión:

La función _0x7969 es la función de descifrado que ofusca la cadena cifrada JS.

Utilice un editor de texto que admita el formato JS para reducir el código ofuscado, de la siguiente manera:
Insertar descripción de la imagen aquí
Marqué la función de descifrado y la función de ejecución (o la función original, no importa cómo se llamen, solo comprenda el significado)

Ahora que conocemos la estructura general de JS ofuscado, el primer paso es descifrar la cadena cifrada utilizada para ejecutar la función.

Primero copiamos la función de descifrado en Chaos JS y la guardamos en de.js, copiamos la parte de la función de ejecución y la guardamos como en.js, y luego creamos un nuevo obTest.js para escribir el código de restauración AST
Insertar descripción de la imagen aquí
de.js. agregue una línea y expórtela. El nombre de la función es _0x7969 arriba, de la siguiente manera:
_0x796962

Abra obTest.js y comience a ingresar al proceso de movimiento de ladrillos AST

const fs = require("fs");
const esprima = require('esprima'); //ECMAScript(JavaScript) 解析架构,主要用于多用途分析。
const estraverse = require('estraverse'); //语法树遍历辅助库(提供了两个静态方法,estraverse.traverse 和 estraverse.replace。前者单纯遍历 AST 的节点,通过返回值控制是否继续遍历到叶子节点;而 replace 方法则可以在遍历的过程中直接修改 AST,实现代码重构功能。)
const escodegen = require('escodegen');//AST的 ECMAScript (也称为JavaScript)代码生成器
const iconv = require("iconv-lite");
const de = require("./de");   
 
//读取加密混淆的执行函数Js
var content = fs.readFileSync('./en.js',{
    
    encoding:'binary'});  
var buf = new Buffer.from(content,'binary');
var code = iconv.decode(buf,'utf-8');
 
//将混淆后的执行函数Js转换为AST
var ast = esprima.parse(code);
//字符串解密
var ast = esprima.parse(code);
ast = estraverse.replace(ast, {
    
    
    enter: function (node) {
    
    
        if (node.type == 'CallExpression' &&  //标注1
            node.callee.type == 'Identifier' && //标注2
            node.callee.name == "_0x7969" &&  //解密函数名
            node.arguments.length == 2 &&  
            node.arguments[0].type == 'Literal' && //标注3
            node.arguments[1].type == 'Literal')  //标注4
        {
    
    
            var val = de._0x7969(node.arguments[0].value,node.arguments[1].value);  //标注5
            return {
    
    
                type: esprima.Syntax.Literal,
                value: val,
                raw: val
            }
        }
    }
});
 
code = escodegen.generate(ast)  //将AST转换为JS
console.log(code)

¿No puedes entender el código anterior? No importa. El
Insertar descripción de la imagen aquí
lado izquierdo de la imagen es el código ofuscado y el lado derecho es la estructura del árbol de sintaxis AST. Como dijimos anteriormente, todas las cadenas cifradas aparecen en una estructura como _0x7969('xxx','xxx' ), entonces, necesitamos filtrar y juzgar la estructura y encontrar todos los nodos de este tipo.

El if... && ...&& en el código anterior se utiliza para hacer esto. Tome una línea como ejemplo:

if (node.type == 'CallExpression' && // Marque 1
para determinar si node.type (tipo de nodo actual) es CallExpression (correspondiente a la imagen de arriba), quedará claro de inmediato.

Ejecute el código para ver el efecto (después de descifrar la cadena cifrada)

function _0x556652(_0x4a2332, _0x2634dc) {
    
    
    var _0x94d946 = function () {
    
    
        if ('wxqXe' !== 'wxqXe') {
    
    
            if (fn) {
    
    
                var _0x33221e = fn['apply'](context, arguments);
                fn = null;
                return _0x33221e;
            }
        } else {
    
    
            var _0x43616c = !![];
            return function (_0x550c05, _0x13d9c2) {
    
    
                if ('NDYGh' !== 'bvJko') {
    
    
                    var _0x296878 = _0x43616c ? function () {
    
       
                        if ('RzWPN' !== 'fJYYY') {
    
    
                            if (_0x13d9c2) {
    
    
                                if ('CONdw' === 'YqJRn') {
    
          
                                    that['console'] = function (_0x1c2524) {
    
    
                                        var _0x2972cc = {
    
    };
                                        _0x2972cc['log'] = _0x1c2524;
                                        _0x2972cc['warn'] = _0x1c2524;
                                        _0x2972cc['debug'] = _0x1c2524;
                                        _0x2972cc['info'] = _0x1c2524;
                                        _0x2972cc['error'] = _0x1c2524;
                                        _0x2972cc['exception'] = _0x1c2524;
                                        _0x2972cc['table'] = _0x1c2524;
                                        _0x2972cc['trace'] = _0x1c2524;
                                        return _0x2972cc;
                                    }(func);
                                } else {
    
    
                                    var _0x34a69a = _0x13d9c2['apply'](_0x550c05, arguments);
                                    _0x13d9c2 = null;
                                    return _0x34a69a;
                                }
                            }
                        } else {
    
    
                            that = window;
                        }
                    } : function () {
    
    
                    };
                    _0x43616c = ![];
                    return _0x296878;
                } else {
    
    
                    var _0x2c3174 = {
    
    };
                    _0x2c3174['log'] = func;
                    _0x2c3174['warn'] = func;
                    _0x2c3174['debug'] = func;
                    _0x2c3174['info'] = func;
                    _0x2c3174['error'] = func;
                    _0x2c3174['exception'] = func;
                    _0x2c3174['table'] = func;
                    _0x2c3174['trace'] = func;
                    return _0x2c3174;
                }
            };
        }
    }();
    var _0x23c1f6 = _0x94d946(this, function () {
    
    
        var _0x6e83c1 = function () {
    
    
        };
        var _0x3f3777;
        try {
    
    
            if ('LbvcK' !== 'qYROQ') {
    
    
                var _0x584a01 = Function('return (function() ' + '{}.constructor("return this")( )' + ');');
                _0x3f3777 = _0x584a01();
            } else {
    
    
                var _0x30c130 = Function('return (function() ' + '{}.constructor("return this")( )' + ');');
                _0x3f3777 = _0x30c130();
            }
        } catch (_0x5365b4) {
    
    
            if ('BUJQE' !== 'qkHzB') {
    
    
                _0x3f3777 = window;
            } else {
    
    
                _0x3f3777['console']['log'] = _0x6e83c1;
                _0x3f3777['console']['warn'] = _0x6e83c1;
                _0x3f3777['console']['debug'] = _0x6e83c1;
                _0x3f3777['console']['info'] = _0x6e83c1;
                _0x3f3777['console']['error'] = _0x6e83c1;
                _0x3f3777['console']['exception'] = _0x6e83c1;
                _0x3f3777['console']['table'] = _0x6e83c1;
                _0x3f3777['console']['trace'] = _0x6e83c1;
            }
        }
        if (!_0x3f3777['console']) {
    
    
            if ('rlkwv' !== 'CXTGb') {
    
    
                _0x3f3777['console'] = function (_0x4bdab5) {
    
    
                    if ('aziuQ' === 'aziuQ') {
    
    
                        var _0x5f33bc = {
    
    };
                        _0x5f33bc['log'] = _0x4bdab5;
                        _0x5f33bc['warn'] = _0x4bdab5;
                        _0x5f33bc['debug'] = _0x4bdab5;
                        _0x5f33bc['info'] = _0x4bdab5;
                        _0x5f33bc['error'] = _0x4bdab5;
                        _0x5f33bc['exception'] = _0x4bdab5;
                        _0x5f33bc['table'] = _0x4bdab5;
                        _0x5f33bc['trace'] = _0x4bdab5;
                        return _0x5f33bc;
                    } else {
    
    
                        var _0x1b640b = firstCall ? function () {
    
    
                            if (fn) {
    
    
                                var _0x3dd5c2 = fn['apply'](context, arguments);
                                fn = null;
                                return _0x3dd5c2;
                            }
                        } : function () {
    
    
                        };
                        firstCall = ![];
                        return _0x1b640b;
                    }
                }(_0x6e83c1);
            } else {
    
    
                var _0x345d2c = fn['apply'](context, arguments);
                fn = null;
                return _0x345d2c;
            }
        } else {
    
    
            _0x3f3777['console']['log'] = _0x6e83c1;
            _0x3f3777['console']['warn'] = _0x6e83c1;
            _0x3f3777['console']['debug'] = _0x6e83c1;
            _0x3f3777['console']['info'] = _0x6e83c1;
            _0x3f3777['console']['error'] = _0x6e83c1;
            _0x3f3777['console']['exception'] = _0x6e83c1;
            _0x3f3777['console']['table'] = _0x6e83c1;
            _0x3f3777['console']['trace'] = _0x6e83c1;
        }
    });
    _0x23c1f6();
    var _0x245e10 = _0x4a2332 + _0x2634dc;
    var _0x5d196d = _0x4a2332 * _0x2634dc + _0x245e10;
    return _0x245e10 + _0x5d196d;
}
console['log'](_0x556652(10, 20));


Como puede ver, la cadena ofuscada y cifrada ha sido descifrada. En circunstancias normales, este nivel de código ya se puede depurar y analizar, pero nuestra búsqueda puede ser mayor. Los estudiantes pueden pasar al frente para echar un vistazo y probar el cifrado. ofuscación. El JS original tiene solo unas pocas líneas de largo. Aunque la cadena cifrada ahora está descifrada, todavía hay muchas instrucciones basura en el código. Entonces, ¿a qué estás esperando? Continuar.

Analice el código después del primer paso de descifrar la cadena, como se muestra a continuación
Insertar descripción de la imagen aquí

Hay muchos if ('xxx'= en el código'xxx') 、si ('xxx'!'xxx') 、 si ('xxx' === 'aaa') 、 si ('xxx' !== 'aaa)

Cualquiera que sepa cómo hacer clic en js puede darse cuenta de un vistazo que se trata de un código basura. También tiene una rama de juicio, por lo que al manejar todos estos if, la cantidad de código se puede reducir a la mitad.

// 处理if('xx'==='xx')
ast = estraverse.replace(ast, {
    
    
    enter: function (node,parent) {
    
    
        if (node.type == 'IfStatement' &&
            node.test.type == 'BinaryExpression')
        {
    
    
            if(node.test.left.value == node.test.right.value) {
    
     //if('aaa'==='aaa'){}
                switch (node.test.operator) {
    
    
                    case '!==' :  //if('aaa'!=='aaa'){}
                        for (var idx = 0; idx < node.consequent.body.length; idx++) {
    
    
                            parent.body.splice(parent.body.indexOf(node), 0, node.consequent.body[idx]);
                        }
                        parent.body.splice(parent.body.indexOf(node), 1);
                        break
 
                    case '===' : //if('aaa'==='aaa'){}
                        for (var idx = 0; idx < node.alternate.body.length; idx++) {
    
    
                            parent.body.splice(parent.body.indexOf(node), 0, node.alternate.body[idx]);
                        }
                        parent.body.splice(parent.body.indexOf(node), 1);
                        break
 
                }
            } else {
    
      //if('aaa'==='bbb'){}
                switch (node.test.operator) {
    
    
                    case '!==' : //if('aaa'!=='bbb'){}
                        for (var idx = 0; idx < node.consequent.body.length; idx++) {
    
    
                            parent.body.splice(parent.body.indexOf(node), 0, node.consequent.body[idx]);
                        }
                        parent.body.splice(parent.body.indexOf(node), 1);
                        break
 
                    case '===' : //if('aaa'==='bbb'){}
                        for (var idx = 0; idx < node.alternate.body.length; idx++) {
    
    
                            parent.body.splice(parent.body.indexOf(node), 0, node.alternate.body[idx]);
                        }
                        parent.body.splice(parent.body.indexOf(node), 1);
                        break
 
                }
            }
        }
    }
});

En comparación con el código de descifrado de cadenas en el primer paso, la diferencia no es muy grande. También hay muchos juicios de tipo en el frente para garantizar que el nodo atravesado sea el nodo basura if... que necesitamos encontrar. Después de encontrar el nodo basura, se bifurcará normalmente. El contenido se inserta en el nodo principal y luego se elimina el nodo actual. ¿Por qué se realiza esta operación? La misma imagen muestra que el lado izquierdo es el nodo if... que necesitamos
Insertar descripción de la imagen aquí
. a encontrar. La parte verde representa la parte que se ejecutará, y la parte negra representa la parte que no se ejecutará. Lo que debemos hacer
Insertar descripción de la imagen aquí
es insertar el consecuente nodo del código que se ejecutará en la parte verde en su nodo padre, que es el nodo TryStatement, y luego elimine todo el nodo IfStatement, completando así el procesamiento de este tipo de basura si... declaración trata con

Eche un vistazo al efecto (procesamiento de basura si resulta la declaración)

function _0x556652(_0x4a2332, _0x2634dc) {
    
    
    var _0x94d946 = function () {
    
    
        if (fn) {
    
    
            var _0x33221e = fn['apply'](context, arguments);
            fn = null;
            return _0x33221e;
        }
    }();
    var _0x23c1f6 = _0x94d946(this, function () {
    
    
        var _0x6e83c1 = function () {
    
    
        };
        var _0x3f3777;
        try {
    
    
            var _0x584a01 = Function('return (function() ' + '{}.constructor("return this")( )' + ');');
            _0x3f3777 = _0x584a01();
        } catch (_0x5365b4) {
    
    
            _0x3f3777 = window;
        }
        if (!_0x3f3777['console']) {
    
    
            _0x3f3777['console'] = function (_0x4bdab5) {
    
    
                var _0x1b640b = firstCall ? function () {
    
    
                    if (fn) {
    
    
                        var _0x3dd5c2 = fn['apply'](context, arguments);
                        fn = null;
                        return _0x3dd5c2;
                    }
                } : function () {
    
    
                };
                firstCall = ![];
                return _0x1b640b;
            }(_0x6e83c1);
        } else {
    
    
            _0x3f3777['console']['log'] = _0x6e83c1;
            _0x3f3777['console']['warn'] = _0x6e83c1;
            _0x3f3777['console']['debug'] = _0x6e83c1;
            _0x3f3777['console']['info'] = _0x6e83c1;
            _0x3f3777['console']['error'] = _0x6e83c1;
            _0x3f3777['console']['exception'] = _0x6e83c1;
            _0x3f3777['console']['table'] = _0x6e83c1;
            _0x3f3777['console']['trace'] = _0x6e83c1;
        }
    });
    _0x23c1f6();
    var _0x245e10 = _0x4a2332 + _0x2634dc;
    var _0x5d196d = _0x4a2332 * _0x2634dc + _0x245e10;
    return _0x245e10 + _0x5d196d;
}
console['log'](_0x556652(10, 20));

¿Es mucho más refrescante? Por supuesto, todavía hay espacio para la optimización. No es más que formular reglas para agregar. Te dejaré esto como tarea después de clase.

Finalmente, adjunte el resultado final de este JS ofuscado restaurado a través de AST:

function _0x556652(_0x4a2332, _0x2634dc) {
    
    
    var _0x245e10 = _0x4a2332 + _0x2634dc;
    var _0x5d196d = _0x4a2332 * _0x2634dc + _0x245e10;
    return _0x245e10 + _0x5d196d;
}
console['log'](_0x556652(10, 20));

Compare el código fuente de cifrado de prueba:

function MyFun(a,b){
    
    
        var c=a+b;
        var d=a*b+c;
        return c+d;
}
console.log(MyFun(10,20))

Artículo de referencia: https://www.52pojie.cn/thread-1473162-1-1.html
Vídeo de demostración: https://www.bilibili.com/video/BV1E64y147Q6/

Supongo que te gusta

Origin blog.csdn.net/LI4836/article/details/130000206
Recomendado
Clasificación