восстановление JS-кода
восстановление JS-кода

на основе Babel верно JS Веб-сайт, который запутывает и восстанавливает код JS Обфускация и восстановление кода (kuizuo.cn)

снижение Предисловие

AST Это всего лишь статический анализ, но вы можете заменить исходный код кодом с сайта, чтобы лучше динамически находить соответствующие точки. К слову, не весь код может с первого взгляда увидеть логику выполнения кода. Он не всемогущ, если у вас есть сильный. js Обратная возможность, иногда динамическая отладка даже лучше, чем AST Статический анализ дает удвоенный результат при вдвое меньших усилиях.

снижение Не самый оригинальныйкод

Идентификаторы могут быть определены по желанию. Пока переменные не конфликтуют, я могу определить их по своему желанию. Тогда было решено, что мы не можем восстановить имена переменных исходного кода, поэтому мы можем восстановить только некоторые причудливые инструкции. код выглядит лучше и облегчает отладку.

снижение Это не всемогущий

Есть много способов запутать,Есть много способов соответствовать верному снижению.,Сбивающее с толку снижение стоимости, приведенное выше, может относиться только к запутанному набору кодов «верно».,Если вы возьмете еще один запутанный код,Затем выполните эту программу,Программа, скорее всего, сообщит об ошибке. Так что всемогущего кодкода нет абсолютно,Все программы снижения цен,Нужны иглыверно Для выполнения используются различные методы обфускации.иметь дело с.

Я просто интегрировал методы обфускации, с которыми столкнулся, в набор кода, не все методы обфускации можно восстановить.

В то же время не стоит слишком усердствовать с восстановлением, поскольку восстановление может легко разрушить исходный код и привести к появлению неизвестных ошибок.

намекать

Если вам нужна настройка,Вы также можете связаться с нами. (Мне еще придется это сказать,Совершенно верно, не может удешевить самый оригинальный код)

пример

Далее основное внимание будет уделено некоторым распространённым методам путаницы (по крайней мере, тем, которые относительно хороши среди тех путаниц, с которыми я столкнулся), и для справки будет приложен верный код (источник кода не будет включен).

Далее я покажу, как восстановить запутанный код. Этот пример — мой первый контакт с обфускацией. Можно сказать, что это самое скользкое восстановление, которое я когда-либо делал. В любом случае, я бросал его 4 или 5 раз.

Вставьте код git адрес js-de-obfuscator/example/deobfuscator/cx

Примечание: js ФайлпроходитьинструментJavaScript Obfuscator Toolзапутыватьиметь дело с.

анализировать AST

Сначала вы должны разобрать запутанный код на AST древовидная структура,Это справедливо для любого запутанного звука. Прежде всего, взгляните на код,Найти такие не сложнокод Все в'\x6a\x4b\x71\x4b'Шестнадцатеричные символы, подобные этому,Можно использовать готовые инструменты,Форматирование ограничит результаты перед кодированием.,Но здесь мы используем ast-действия

проходить AST Проверять node узел,можно найтиvalueИменно те данные, которые нам нужны,Но то, что здесь показано,extra.raw,Фактически, вам нужно всего лишь перейти к соответствующему узлу,Затем extra Просто удалите атрибут, то же самое Unicode Кодировка также отображается, как указано выше.

Конкретный код обхода выглядит следующим образом

Язык кода:javascript
копировать
// Преобразование всех шестнадцатеричных кодировок и кодировок Unicode в обычные символы.
hexUnicodeToString() {
        traverse(this.ast, {
            StringLiteral(path) {
                var curNode = path.node;
                delete curNode.extra;
            },
            NumericLiteral(path) {
                var curNode = path.node;
                delete curNode.extra;
            }
        })
    }

Затем после обхода замените обработанный код на demo.js, чтобы облегчить последующий процесс восстановления. Однако после обработки остается еще большинство неизвестных строк, которые необходимо расшифровать, и, конечно, есть некоторые необработанные коды.

Найдите функцию расшифровки

Если вы попытались статически проанализировать код, вы обнаружите, что некоторые параметры имеют вид call_0x3028, вот так

Язык кода:javascript
копировать
_0x3028['nfkbEK']
_0x3028('0x0', 'jKqK')
_0x3028('0x1', ')bls')

А если серьезно Проверять Вы найдете выражения членов, такие какMemberExpressionзаявление_0x3028["nfkbEK"],носуществовать Статья 3заявление Но определите функцию_0x3028。На самом деле это js Функции, например, следующий код может добавить к функции настраиваемый атрибут.

Язык кода:javascript
копировать
let add = function (a, b) {
  add['abc'] = 123
  return a + b
}

console.log(add(1, 2))
console.log(add['abc'])

// 3
// 123

Но это не влияет,Просто упоминание здесь,Не совсемкодвопрос。ив_0x3028Это функция расшифровки,И траверс_0x3028выражение вызова,CallExpression с двумя параметрами.

Тогда следующий шаг — сосредоточиться на первых трех предложениях «Проверять», потому что эти три предложения являются ключом к этой путанице.

demo.js

Язык кода:javascript
копировать
var _0x34ba = ["JcOFw4ITY8KX", "EHrDoHNfwrDCosO6Rkw=",...]
(function(_0x2684bf, _0x5d23f1) {
    // Здесь мы просто определяем функцию, которая переупорядочивает массив, но вызов выполняется позже.
    var _0x20d0a1 = function(_0x17cf70) {
        while (--_0x17cf70) {
            _0x2684bf['push'](_0x2684bf['shift']());
        }
    };
    var _0x1b4e1d = function() {
        var _0x3dfe79 = {
            'data': {
                'key': 'cookie',
                'value': 'timeout'
            },
            "setCookie": function (_0x41fad3, _0x155a1e, _0x2003ae, _0x48bb02) {
                ...
            },
            "removeCookie": function () {
                return "dev";
            },
            "getCookie": function (_0x23cc41, _0x5ea286) {
                _0x23cc41 = _0x23cc41 || function (_0x20a5ee) {
                    return _0x20a5ee;
                };

                // Здесь определен вызов функции инструкции цветка для вызова
                var _0x267892 = function (_0x51e60d, _0x57f223) {
                    _0x51e60d(++_0x57f223);
                };
                // где фактически был сделан звонок
                _0x267892(_0x20d0a1, _0x5d23f1);

                return _0x1c1cc3 ? decodeURIComponent(_0x1c1cc3[1]) : undefined;
            }
      }
        };
    };
    _0x1b4e1d();
}(_0x34ba, 296));
var _0x3028 = function (_0x2308a4, _0x573528) {
  _0x2308a4 = _0x2308a4 - 0;
  var _0x29a1e7 = _0x34ba[_0x2308a4];

  // Опустить сто строк кода...

  return _0x29a1e7;
};

Нет необходимости внимательно читать опущенный код, поскольку в него будут записаны только эти три оператора. node В памяти (оценка),Затемпозвонить。Следующийанализироватькаждыйзаявление Для чего они все?。

большой массив

Базовый 99%путаницаПервый оператор представляет собой большой массив,Храните все зашифрованные строки,И что нам нужно сделать, это найти все зашифрованные строки,Сделайте это дешевле.

Массив не в порядке

ЗатемзатемВторой оператор обычно представляет собой самовызывающую функцию.,Принятие больших массивов и перетасованных величин массивов в качестве параметров,Функция в — перетасовать массив.,Это место, выделенное в коде выше.,Но здесь мы просто определяем функцию_0x20d0a1,игде фактически был сделан звонок _0x1b4e1d середина_0x3dfe79.getCookieсерединаназывается,В приведенном выше коде есть комментарии. Если вы идете нормально по шагам, то не обязательно, что анализировать получится.,Это запутанное отвратительное место.

Не путайте,Короче говоря, если вы знаете, что второй оператор используется для изменения порядка массива.,И как бы оно ни было запутано,,мы все можемпроходить eval Давайте вызовем его один раз, подробности см. в коде ниже.

Функция расшифровки

Третье утверждение — это функция шифрования,Фактически, это индекс большого массива, переданного в,Затем верните соответствующие члены массива верно,Просто инкапсулируйте это в функцию здесь,эквивалент оригинала _0x34ba[0] становиться_0x3028("0x0", "jKqK") form для получения исходной строки (это всего лишь пример, также задействован фактический второй параметр).

снижениенить

Сказав так много выше, на самом деле нет необходимости понимать конкретную логику путаницы. Нет необходимости понимать, что делает второй переданный параметр, потому что наша конечная цель — это сделать. _0x3028("0x0", "jKqK")конвертировать в оригиналнить,Затемзаменить текущийузелиз。Все, что вам нужно сделать, это перейти к_0x3028("0x0", "jKqK"),ЗатемВыполните функцию дешифрования один разПолучите расшифрованный результат,Тогда просто замените его. Поэтому ключевым моментом является то, как выполнить функцию дешифрования.

Воля Функция расшифровкидобавить вв памяти

Сначала запустите три оператора один раз, js В коде, который хочет запустить строку во время выполнения, вы можете использовать оценю, но eval Существует проблема с областью действия, eval Область выполняемого кода является локальной. Если он выходит за пределы текущей области, eval. Выполнение кода эквивалентно его недействительности.,Все доступноwindow.evalилиglobal.eval,Запишите это в глобальную область видимости,Поскольку это среда узла,Удобно использоватьglobal.eval

Перехватите первые три оператора и используйте eval, чтобы записать их в память.

Язык кода:javascript
копировать
// Получите узел, где находится функция дешифрования
let stringDecryptFuncAst = this.ast.program.body[2]
// Получить имя функции дешифрования Это _0x3028
let DecryptFuncName = stringDecryptFuncAst.declarations[0].id.name

let newAst = parser.parse('')
newAst.program.body.push(this.ast.program.body[0])
newAst.program.body.push(this.ast.program.body[1])
newAst.program.body.push(stringDecryptFuncAst)
// Преобразуйте эти три части кода в строки. Из-за обнаружения форматирования вам необходимо указать параметры сжатия кода.
let stringDecryptFunc = generator(newAst, { compact: true }).code
// Выполните строку кода формы, чтобы ее можно было nodejs Запустите функцию дешифрования в
global.eval(stringDecryptFunc)
вызов Функция расшифровки

В это время,ты можешь использовать_0x3028("0x0", "jKqK") вывести расшифрованный результат,Однако вводить каждый вручную все равно слишком хлопотно.,Это можно найти_0x3028везде называется,Затем определите, является ли это выражением вызова CallExpression.,Затемиспользоватьeval('_0x3028("0x0", "jKqK")') Получите результат расшифровки. Вот пример обхода.

Язык кода:javascript
копировать
traverse(this.ast, {
  VariableDeclarator(path) {
    // Когда имя переменной совпадает с именем функции дешифрования
    if (path.node.id.name == DecryptFuncName) {
      let binding = path.scope.getBinding(DecryptFuncName)
      // ИспользоватьreferencePaths может получить все места, на которые имеются ссылки.
      binding &&
        binding.referencePaths.map((p) => {
          // Определите, является ли родительский узел вызывающим выражением, а параметров — два.
          if (p.parentPath.isCallExpression()) {
            // Выходные параметры и расшифрованные результаты
            let args = p.parentPath.node.arguments.map((a) => a.value).join(' ')
            let str = eval(p.parentPath.toString())
            console.log(args, str)
            p.parentPath.replaceWith(t.stringLiteral(str))
          }
        })
    }
  },
})

Упомяните об этом, когда возникла привязка путаницы, которая может получить область действия текущей переменной.,иbinding.referencePathsВы можете получить все места для звонков,Тогда вам нужно только определить, является ли это выражением вызова,А когда параметров два,Затем etvval выполняет весь узел,То естьeval('_0x3028("0x0", "jKqK")'),Затемпроходить replaceWith,Просто замените узел. Передаваемые параметры и зашифрованные результаты примерно отображаются следующим образом:,Можно сделать это самомубегатьпроцедура одного проходасерединаdecStringArr()

Язык кода:javascript
копировать
0x0 jKqK PdAlB
0x1 )bls jtvLV
0x2 M10H SjQMk
0x3 2Q@E length
0x4 [YLR length
0x5 QvlS charCodeAt
0x6 YvHw IrwYd
0x7 iLkl ClOby
0x8 DSlT console
...
обакодверно Сравнивать

Сравнение (части) кодирования между исходным кодом и имеющимся кодом

Язык кода:javascript
копировать
var _0x505b30 = (function () {
  if (_0x3028('0x0', 'jKqK') !== _0x3028('0x1', ')bls')) {
    var _0x104ede = !![]

    return function (_0x3d32a2, _0x35fd15) {
      if ('bKNqX' === _0x3028('0x2', 'M10H')) {
        var _0x46992c,
          _0x1efd4e = 0,
          _0x5cae2b = d(f)

        if (0 === _0xb2c58f[_0x3028('0x3', '2Q@E')]) return _0x1efd4e

        for (_0x46992c = 0; _0x46992c < _0xb2c58f[_0x3028('0x4', '[YLR')]; _0x46992c++)
          (_0x1efd4e = (_0x1efd4e << (_0x5cae2b ? 5 : 16)) - _0x1efd4e + _0xb2c58f[_0x3028('0x5', 'QvlS')](_0x46992c)), (_0x1efd4e = _0x5cae2b ? _0x1efd4e : ~_0x1efd4e)

        return 2147483647 & _0x1efd4e
      } else {
        var _0x45a8ce = _0x104ede
          ? function () {
              if (_0x3028('0x6', 'YvHw') === _0x3028('0x7', 'iLkl')) {
                that[_0x3028('0x8', 'DSlT')]['log'] = func
                that[_0x3028('0x9', 'YW6h')][_0x3028('0xa', '&12i')] = func
                that[_0x3028('0xb', '1jb4')]['debug'] = func
                that[_0x3028('0xc', 'k9U[')][_0x3028('0xd', 'nUsA')] = func
                that[_0x3028('0xe', ')bls')][_0x3028('0xf', 'PZDB')] = func
                that['console'][_0x3028('0x10', 'r8Qx')] = func
                that[_0x3028('0x11', 'AIMj')][_0x3028('0x12', '[YLR')] = func
              } else {
                if (_0x35fd15) {
                  if (_0x3028('0x13', 'r8Qx') !== _0x3028('0x14', 'YLF%')) {
                    var _0x1fa1e3 = _0x35fd15[_0x3028('0x15', 'sLdn')](_0x3d32a2, arguments)

                    _0x35fd15 = null
                    return _0x1fa1e3
                  } else {
                    _0x142a1e()
                  }
                }
              }
            }
          : function () {}

        _0x104ede = ![]
        return _0x45a8ce
      }
    }
  } else {
    ;(function () {
      return ![]
    }
      [_0x3028('0x16', 'Yp5j')](_0x3028('0x17', ']R4I') + _0x3028('0x18', 'M10H'))
      [_0x3028('0x19', '%#u0')]('stateObject'))
  }
})()
Язык кода:javascript
копировать
var _0x505b30 = (function () {
  if ('PdAlB' !== 'jtvLV') {
    var _0x104ede = !![]

    return function (_0x3d32a2, _0x35fd15) {
      if ('bKNqX' === 'SjQMk') {
        var _0x46992c,
          _0x1efd4e = 0,
          _0x5cae2b = d(f)

        if (0 === _0xb2c58f['length']) return _0x1efd4e

        for (_0x46992c = 0; _0x46992c < _0xb2c58f['length']; _0x46992c++)
          (_0x1efd4e = (_0x1efd4e << (_0x5cae2b ? 5 : 16)) - _0x1efd4e + _0xb2c58f['charCodeAt'](_0x46992c)), (_0x1efd4e = _0x5cae2b ? _0x1efd4e : ~_0x1efd4e)

        return 2147483647 & _0x1efd4e
      } else {
        var _0x45a8ce = _0x104ede
          ? function () {
              if ('IrwYd' === 'ClOby') {
                that['console']['log'] = func
                that['console']['warn'] = func
                that['console']['debug'] = func
                that['console']['info'] = func
                that['console']['error'] = func
                that['console']['exception'] = func
                that['console']['trace'] = func
              } else {
                if (_0x35fd15) {
                  if ('WuEjf' !== 'qpuuN') {
                    var _0x1fa1e3 = _0x35fd15['apply'](_0x3d32a2, arguments)

                    _0x35fd15 = null
                    return _0x1fa1e3
                  } else {
                    _0x142a1e()
                  }
                }
              }
            }
          : function () {}

        _0x104ede = ![]
        return _0x45a8ce
      }
    }
  } else {
    ;(function () {
      return ![]
    }
      ['constructor']('debu' + 'gger')
      ['apply']('stateObject'))
  }
})()

Можно найти иметь дело с Прошедшийкод По крайней мере нет необходимости динамически вызывать расшифрованные результаты,и нравитсяif ("PdAlB" !== "jtvLV")Этот видзаявление С первого взгляда видно, что это должно быть true,Но после путаницыif (_0x3028("0x0", "jKqK") !== _0x3028("0x1", ")bls"))Но не могу видеть,Преимущества статического анализа Это AST

удалить Запутатьзаявление

После выполнения расшифровки строки,Фактически большие массивы и функции дешифрования больше не нужны.,Тогда вы можете пройти shift Удалите первые три утверждения.

Язык кода:javascript
копировать
// Удалить расшифрованный код из исходного кода
this.ast.program.body.shift()
this.ast.program.body.shift()
this.ast.program.body.shift()

Но в целомНе рекомендуется удалять,Потому что после загрузки нам может потребоваться заменить код на запутанный код на веб-сайте.,Затем выполните динамическую отладку и анализируйте,Но если эти три запутанных утверждения удалить,Это может вызвать ошибки выполнения кода. я раньше удалял,Но пока я не наткнулся на сайт. . .

Наконец все дело завершенокодв методе классаdecStringArr

Найдите функцию расшифровкиоптимизация

В приведенном выше коде есть такой фрагмент кода

Язык кода:javascript
копировать
    // Когда имя переменной совпадает с именем функции дешифрования
    if (path.node.id.name == DecryptFuncName) {
    // ...

Среди них здесь DecryptFuncName верно соответствует имени функции дешифрования function_0x3028.,это искусственное определение содержания,Первые три оператора загружаются одновременно.,В случае, если функция дешифрования находится в четвертом операторе,Или когда есть несколько функций дешифрования,Вам нужно изменить код

Язык кода:javascript
копировать
// Получите узел, где находится функция дешифрования
let stringDecryptFuncAst = this.ast.program.body[2]
// Получить имя функции дешифрования Это _0x3028
let DecryptFuncName = stringDecryptFuncAst.declarations[0].id.name

let newAst = parser.parse('')
newAst.program.body.push(this.ast.program.body[0])
newAst.program.body.push(this.ast.program.body[1])
newAst.program.body.push(stringDecryptFuncAst)
// Преобразуйте эти три части кода в строки. Из-за обнаружения форматирования вам необходимо указать параметры сжатия кода.
let stringDecryptFunc = generator(newAst, { compact: true }).code

Когда я случайно просмотрел код,Вспышка вдохновения,Функция дешифрования вызывается так часто,Я просто прохожу все функции,и обратитесь к нимreferencePathsСортировать от большего к меньшему,Разве вы не знаете, что это функция дешифрования?,Итак, естьfindDecFunctionArrметод

findDecFunctionArr

Вообще говоря,Функции дешифрования обычно определяются после больших массивов и перетасовки массивов.,в приведенном выше коде,Видно, что этопроходить Создайте нижний индекс для поиска Функция расшифровки this.ast.program.body[2];,Итак, пока вы можете перехватить этот код.

Язык кода:javascript
копировать
/**
   * Найдите функцию дешифрования по количеству вызовов функций.
   */
  findDecFunction() {
    let decFunctionArr = [];
    let index = 0; // Определите индекс оператора, в котором находится функция дешифрования.

    // Сначала просмотрите все функции (область действия в программе) и определите, является ли это функцией дешифрования на основе количества ссылок.
    traverse(this.ast, {
      Program(p) {
        p.traverse({
          'FunctionDeclaration|VariableDeclarator'(path) {
            if (!(t.isFunctionDeclaration(path.node) || t.isFunctionExpression(path.node.init))) {
              return;
            }

            let name = path.node.id.name;
            let binding = path.scope.getBinding(name);
            if (!binding) return;

            // Если она вызывается более 100 раз, вероятно, это функция дешифрования. О конкретной ситуации можно судить на основе фактической ситуации.
            if (binding.referencePaths.length > 100) {
              decFunctionArr.push(name);

              // По последним данным Функция расшифровки Приходить Определите индекс оператора, в котором находится функция дешифрования.
              let binding = p.scope.getBinding(name);
              if (!binding) return;

              let parent = binding.path.findParent((_p) => _p.isFunctionDeclaration() || _p.isVariableDeclaration());
              if (!parent) return;
              let body = p.scope.block.body;
              for (let i = 0; i < body.length; i++) {
                const node = body[i];
                if (node.start == parent.node.start) {
                  index = i + 1;
                  break;
                }
              }
              // После прохождения текущего узла он больше не будет пересекать дочерние узлы.
              path.skip();
            }
          },
        });
      },
    });

    let newAst = parser.parse('');
    // Вставьте несколько операторов перед функцией дешифрования.
    newAst.program.body = this.ast.program.body.slice(0, index);
    // Преобразуйте эту часть кода в строку. Поскольку возможно обнаружение форматирования, вам необходимо указать параметры сжатия кода.
    let code = generator(newAst, { compact: true }).code;
    // Выполните строку кода формы, чтобы ее можно было nodejs Запустите функцию дешифрования в
    global.eval(code);

    this.decFunctionArr = decFunctionArr;
  }

В то же время добавляется атрибут decFunctionArr для представления массива функции дешифрования для использования decStringArr, что устраняет необходимость определения функции дешифрования.

оптимизацияснижениепозжекод

Вот и все,Код Базовый после снижения может дать приблизительную схему статического анализа.,Следующим шагом будет тонкая оптимизация этого коднижения.

объект['свойства'] Изменить навернослон.свойство

Противоположность путанице, правда, свойства слона,Но это не обязательно,Просто это выглядит лучше, чем есть на самом деле.,Влияние не большое. Подробности следующие

Язык кода:javascript
копировать
changeObjectAccessMode() {
        traverse(this.ast, {
            MemberExpression(path) {
                if (t.isStringLiteral(path.node.property)) {
                    let name = path.node.property.value
                    path.node.property = t.identifier(name)
                    path.node.computed = false
                }
            }
        })
    }

Вернуться к Boolean

существоватьснижениепозжекод Все еще существуютсуществовать!![]и ![]или Тот, кто!0и!1,иэтотверноотвечать js середина То естьtrueиfalse,Таким образом, вы также можете пройти эту часть кода,Затем Воля其снижениестановиться Boolean, я не буду вдаваться в подробности подобных выражений (несколько похожих на jsfuck),ast Саму структуру анализировать. Подробности следующие

Язык кода:javascript
копировать
traverseUnaryExpression() {
        traverse(this.ast, {
            UnaryExpression(path) {
                if (path.node.operator !== '!') return // избегайте осуждения void

                // Определите, является ли второй символ!
                if (t.isUnaryExpression(path.node.argument)) {
                    if (t.isArrayExpression(path.node.argument.argument)) { // !![]
                        if (path.node.argument.argument.elements.length == 0) {
                            path.replaceWith(t.booleanLiteral(true))
                            path.skip()
                        }
                    }
                } else if (t.isArrayExpression(path.node.argument)) { // ![]
                    if (path.node.argument.elements.length == 0) {
                        path.replaceWith(t.booleanLiteral(false))
                        path.skip()
                    }
                } else if (t.isNumericLiteral(path.node.argument)) { // !0 or !1
                    if (path.node.argument.value === 0) {
                        path.replaceWith(t.booleanLiteral(true))
                    } else if (path.node.argument.value === 1) {
                        path.replaceWith(t.booleanLiteral(false))
                    }
                } else {
                }
            }
        })
    }

Вычислить биномиальный литерал

снижениепозжекодсередина Все еще существуютсуществовать["constructor"]("debu" + "gger")["call"]("action");этот样иззаявление,вdebugger Умышленно разделить на две части, и это тоже можно сделать ast Чтобы восстановить его до полной строки, это также аналогично 1 + 2 Этот буквальный Все можно объединить. Код программы восстановления следующий

Язык кода:javascript
копировать
    traverseLiteral() {
        traverse(this.ast, {
            BinaryExpression(path) {
                let { left, right } = path.node
                // Определите, являются ли левая и правая части литералами
                if (t.isLiteral(left) && t.isLiteral(right)) {
                    let { confident, value } = path.evaluate() // Вычислить значение бинома
                    confident && path.replaceWith(t.valueToNode(value))
                    path.skip()
                }
            }
        });
    }

Среди них уверенно указывает, является ли она вычисляемой, например, переменная + 1. Поскольку в данный момент программа не знает значения переменной, ее невозможно вычислить, а уверенно имеет значение false.

В то же время этот вычислительный биномиальный литерал можно спутать с некоторыми относительно простыми вещами, такими как числовая путаница XOR. 706526 ^ 706516Рассчитано как 10 Вы можете напрямую заменить исходный узел. Следовательно, этот шаг обхода необходимо выполнить раньше, чем другие обходы.

нитьнапрямую заменить числовыми константамиверноотвечатьиз变量引用地方

Некоторым переменным можно назначить один раз, а затем больше не изменять, как и константам, например, в следующем коде.

Язык кода:javascript
копировать
let a = 100
console.log(a)

Тогда его можно будет полностью заменитьстановитьсяconsole.log(100) , окончательный эффект на выходе тот же, но предпосылка a Он был назначен только один раз, что также можно сказать a Это должна быть переменная, иначе снижение может привести к сбою исходного результата выполнения и binding можно проверить переменную a история заданий.

Язык кода:javascript
копировать
traverseStrNumValue() {
        traverse(this.ast, {
            'AssignmentExpression|VariableDeclarator'(path) {
                let _name = null;
                let _initValue = null;
                if (path.isAssignmentExpression()) {
                    _name = path.node.left.name;
                    _initValue = path.node.right;
                } else {
                    _name = path.node.id.name;
                    _initValue = path.node.init;
                }
                if (t.isStringLiteral(_initValue) || t.isNumericLiteral(_initValue)) {
                    let binding = path.scope.getBinding(_name);
                    if (binding && binding.constant && binding.constantViolations.length == 0) {
                        for (let i = 0; i < binding.referencePaths.length; i++) {
                            binding.referencePaths[i].replaceWith(_initValue);
                        }
                    }
                }
            },
        });
    }

Удалите ненужные переменныеибесполезныйкодкусок

Как упоминалось выше, некоторые замены строк и числовых констант,Игла — это переменная, которая была назначена только один раз.,Но также могут быть случаи, когда переменные не используются.,столкнулся с такой ситуацией,мы можем судить constantViolations элемент пуст, затем удалите его.

Язык кода:javascript
копировать
    removeUnusedValue() {
        traverse(this.ast, {
            VariableDeclarator(path) {
                const { id, init } = path.node;
                if (!(t.isLiteral(init) || t.isObjectExpression(init))) return;
                const binding = path.scope.getBinding(id.name);
                if (!binding || binding.constantViolations.length > 0) return

                if (binding.referencePaths.length > 0) return
                path.remove();
            },
            FunctionDeclaration(path){
                const binding = path.scope.getBinding(path.node.id.name);
                if (!binding || binding.constantViolations.length > 0) return

                if (binding.referencePaths.length > 0) return
                path.remove();
            }
        });
    }

Есть также несколько бесполезных блоков кода, таких как

Язык кода:javascript
копировать
function test() {
  if (true) {
    return '123'
  } else {
    return Math.floor(10 * Math.random())
  }
}
test()

Второй оператор никогда не будет выполнен.,Тогда его можно будет удалить. Хотя редактор кода пометит его как темный,Указывает, что оно не будет выполнено,Но в этой путанице мне бы хотелось иметь меньше кода,Все еще необходимопроходить AST Выполнять операции.

Язык кода:javascript
копировать
    removeUnusedBlockStatement() {
        traverse(this.ast, {
            IfStatement(path) {
                if (t.isBooleanLiteral(path.node.test)) {
                    let testValue = path.node.test.value
                    if (testValue === true) {
                        path.replaceInline(path.node.consequent)
                    } else if (testValue === false) {
                        path.replaceInline(path.node.alternate)
                    }
                }
            },
        });
    }

Хотя говорят, что только такая игла if Условие Boolean,если Условиеif(1===1)Также возможна ситуация,Потому что в предыдущем вычислении снижения биномиального литерала,ужеif(1===1) заменен на if(true),Так что тут нам остаётся только судитьisBooleanLiteralВот и все。финальныйснижениепозже结果会Воля if Блоки кода удалены с сохранением BlockStatement, код следующий

Язык кода:javascript
копировать
function test() {
  {
    return "123";
  }
}

test();

Добавить комментарий

Некоторые коды клавиш будут скрыты в отладчике, setTimeout, setInterval и т. д. При отладке вам необходимо обратить особое внимание на наличие кодов клавиш, поэтому вы можете добавить комментарий в это время, чтобы добавить метку, например TOLOOK, для позиционирования. В частности, он позиционируется в соответствии с указанным идентификатором. Следующий код используется в качестве демонстрации, и в этих местах будут добавлены комментарии // TOLOOK.

Язык кода:javascript
копировать
addComments() {
        traverse(this.ast, {
            DebuggerStatement(path) {
                path.addComment('leading', ' TOLOOK', true);
            },
            CallExpression(path) {
                if (!['setTimeout', 'setInterval'].includes(path.node.callee.name)) return;
                path.addComment('leading', ' TOLOOK', true);
            },
            StringLiteral(path) {
                if (path.node.value === 'debugger') {
                    path.addComment('leading', ' TOLOOK', true);
                }
            }
        });
    }

шестнадцатеричный против. Unicode Преобразование кодировки в обычные символы

Этот метод был вызван в начале восстановления, но я должен сказать это здесь еще раз, потому что этот набор запутанных шестнадцатеричных чисел является окончательной обработкой, а это означает, что для нас не проблема использовать восстановление непосредственно в начале, но если он зашифрован. В строке присутствуют символы шестнадцатеричной кодировки, и если этот шаг выполнить до расшифровки строки, то некоторые строки все равно могут отображаться в шестнадцатеричном виде, поэтому этот метод намеренно помещен далее в статье, и этот метод. также можно назвать последним.

Язык кода:javascript
копировать
hexUnicodeToString() {
        traverse(this.ast, {
            StringLiteral(path) {
                var curNode = path.node;
                delete curNode.extra;
            },
            NumericLiteral(path) {
                var curNode = path.node;
                delete curNode.extra;
            },
        });
    }

идентификатороптимизация

Большинство запутанных идентификаторов похожи на _0x123456, но некоторые из них сильно отличаются, например, ОООО0о. По сравнению с предыдущими код легче увидеть и неправильно прочитать. Тогда вы сможете единожды переименовать все идентификаторы.

Язык кода:javascript
копировать
    renameIdentifier() {
        let code = this.code
        let newAst = parser.parse(code);
        traverse(newAst, {
            'Program|FunctionExpression|FunctionDeclaration'(path) {
                path.traverse({
                    Identifier(p) {
                        path.scope.rename(p.node.name, path.scope.generateUidIdentifier('_0xabc').name);
                    }
                })
            }
        });
        this.ast = newAst;
    }

Но узнать идентификатор исходного кода просто невозможно, поэтому невозможно понять код семантически.

Однако есть некоторые конкретные замены, например, для i

Язык кода:javascript
копировать
for (var _0x1e5665 = 0, _0x3620b9 = this['JIyEgF']['length']; _0x1e5665 < _0x3620b9; _0x1e5665++) {
  this['JIyEgF']['push'](Math['round'](Math['random']()))
  _0x3620b9 = this['JIyEgF']['length']
}

Нравится этот код,Это вполне возможно_0x1e5665заменятьстановитьсяi,Однако общий эффект чтения «верно» невелик.

другойснижениеозначает

Есть также некоторые методы восстановления, которые я не буду вдаваться в подробности (в примере здесь не используются), например

  • Измените формальные параметры на фактические параметры
  • Восстановить поток выполнения переключателя
  • иметь дело свернослонинструкции по цветку
  • Обработка кода оценки

Подождите, короче, оптимизировать можно все, что угодно, но восстановленный код может быть непонятен. По сравнению с расшифровкой строк, если вы не можете справиться с расшифровкой строк, то все это напрасно.

Конкретные примеры можно найти в руководстве Пример исходного кода середина Проверятьверно AST операция.

бегатьснижениепозжекод

финальныйвесьснижениепозжекод МожетсуществоватьnewCode.jsсередина Проверять,Но пока не проверялось, сможет ли код после снижения работать нормально.,Или замена узлов вызывает синтаксические ошибки,Все, что должно бытьснижениепозжекоди Запутать Прошедшийкодзаменятьбегатьэтот样才能测试из出Приходить。Я не буду здесь вдаваться в конкретный процесс выполнения.(因为真из懒得существоватьиметь дело это js файл. . . )

JS Запутатьиснижениевеб-сайт

Вышеупомянутая операция снижения для верно на самом деле недостаточно очевидна, поэтому я написал онлайн-верно. JS Обфускация и восстановление сайт кода (в основном для правильного снижения) – JS Обфускация и восстановление кода (kuizuo.cn)

Фактически, вышеупомянутый снижениекод упакован в инструмент для использования.

boy illustration
RasaGpt — платформа чат-ботов на основе Rasa и LLM.
boy illustration
Nomic Embed: воспроизводимая модель внедрения SOTA с открытым исходным кодом.
boy illustration
Улучшение YOLOv8: EMA основана на эффективном многомасштабном внимании, основанном на межпространственном обучении, и эффект лучше, чем у ECA, CBAM и CA. Малые цели имеют очевидные преимущества | ICASSP2023
boy illustration
Урок 1 серии Libtorch: Тензорная библиотека Silky C++
boy illustration
Руководство по локальному развертыванию Stable Diffusion: подробные шаги и анализ распространенных проблем
boy illustration
Полностью автоматический инструмент для работы с видео в один клик: VideoLingo
boy illustration
Улучшения оптимизации RT-DETR: облегченные улучшения магистрали | Support Paddle облегченный rtdetr-r18, rtdetr-r34, rtdetr-r50, rtdet
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | Деформируемое внимание с большим ядром (D-LKA Attention), большое ядро ​​​​свертки улучшает механизм внимания восприимчивых полей с различными функциями
boy illustration
Создано Datawhale: выпущено «Руководство по тонкой настройке развертывания большой модели GLM-4»!
boy illustration
7B превышает десятки миллиардов, aiXcoder-7B с открытым исходным кодом Пекинского университета — это самая мощная модель большого кода, лучший выбор для корпоративного развертывания.
boy illustration
Используйте модель Huggingface, чтобы заменить интерфейс внедрения OpenAI в китайской среде.
boy illustration
Оригинальные улучшения YOLOv8: несколько новых улучшений | Сохранение исходной информации — алгоритм отделяемой по глубине свертки (MDSConv) |
boy illustration
Второй пилот облачной разработки | Быстро поиграйте со средствами разработки на базе искусственного интеллекта
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция с нулевым кодированием и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
Решенная Ошибка | Загрузка PyTorch медленная: TimeoutError: [Errno 110] При загрузке факела истекло время ожидания — Cat Head Tiger
boy illustration
Brother OCR, библиотека с открытым исходным кодом для Python, которая распознает коды проверки.
boy illustration
Новейшее подробное руководство по загрузке и использованию последней демонстрационной версии набора данных COCO.
boy illustration
Выпущен отчет о крупной модели финансовой отрасли за 2023 год | Полный текст включен в загрузку |
boy illustration
Обычные компьютеры также могут работать с большими моделями, и вы можете получить личного помощника с искусственным интеллектом за три шага | Руководство для начинающих по локальному развертыванию LLaMA-3
boy illustration
Одной статьи достаточно для анализа фактора транскрипции SCENIC на Python (4)
boy illustration
Бросая вызов ограничениям производительности небольших видеокарт, он научит вас запускать большие модели глубокого обучения с ограниченными ресурсами, а также предоставит полное руководство по оценке и эффективному использованию памяти графического процессора!
boy illustration
Команда Fudan NLP опубликовала 80-страничный обзор крупномасштабных модельных агентов, в котором в одной статье представлен обзор текущего состояния и будущего агентов ИИ.
boy illustration
[Эксклюзив] Вы должны знать о новой функции JetBrains 2024.1 «Полнострочное завершение кода», чтобы решить вашу путаницу!
boy illustration
Краткое изложение базовых знаний о регистрации изображений 1.0
boy illustration
Новейшее подробное руководство по установке и использованию библиотеки cv2 (OpenCV, opencv-python) в Python.
boy illustration
Легко создайте локальную базу знаний для крупных моделей на основе Ollama+AnythingLLM.
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание решения. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Одна статья поможет вам понять RAG (Retrival Enhanced Generation) | Введение в концепцию и теорию + практику работы с кодом (включая исходный код).
boy illustration
Эволюция архитектуры шлюза облачной разработки
boy illustration
Docker и Kubernetes [Разработка контейнерных приложений с помощью Python]