Загрузка...

JavaScript deobfuscation with AST. Part 1.

Thread in Learning created by ElevenGate Sep 13, 2020. (bumped Sep 13, 2020) 2551 view

  1. ElevenGate
    ElevenGate Topic starter Sep 13, 2020 Banned 14 May 27, 2020
    Всем привет, я хочу рассказать вам о возможностях трансформации AST в контексте JS.

    Зачем это нужно? В основном, чтобы избавиться от рутины по трансформации кода.Помимо этого, такие манипуляции позволяют минимизировать количество допускаемых ошибок во время ручно манипуляции, а так же имеют свои преимущества по сравнению с регулярными выражениями.
    Это будет цикл статей, которые направлены на то, чтобы заинтересовать вас и показать что-то новое.
    Многие сайты обфусцируют свои файлы для того, чтобы вам было сложнее в них разобраться и понять как они работают.
    Обфускация так же проходит при помощи AST трансформации кода - открыв любой open source обфускатор вы можете в этом легко убедиться.
    Чем тебе не угодил beautifier.io, de4js, jsnice и прочие?
    Дело в том что они не поддерживают многие виды обфускаций, как, например, те, что используются на https://obfuscator.io

    Таким образом, я собираюсь показать вам некоторые примеры деобфускации при помощи AST трансформаций, на примере своего кода, пропущенного через obfuscator.io;
    В общем клин клином выбивается))
    Код в виде текста прикреплен в конце.
    В данной части будет продемонстрировано как из массива строк и функции, которая из него вытаскивает нужные строки, заменить вызовы функций на эквивалентные литералы.
    Код манипуляций будет простым, чтобы больше людей могли понять о чем речь.
    Code
    Бонусом я дам модуль для преобразования console['log'] в console.log.
    Мы будем делать из:
    [IMG]

    делать такой код:
    [IMG]
    Рассмотрев код, можно сделать вывод что функция, которая вытаскивает строки называется _0x3d28, массив строк под именем _0x4dfe,
    а за ним идет iife функция перемешивания.

    Разберем функцию _0x3d28 :
    [IMG]
    На вход подается 2 аргумента, второй из которых нигде не используется.
    Затем второй аргумент(индекс) преобразуется в число путем вычитания 0x0 что является нулем.
    После этого объявляется и возвращается переменная, которая равна индексу из массива строк(объявлен первой строкой).
    Чистый вариант:
    [IMG]

    Рассмотрим iife функцию:
    [IMG]
    Она вызывается сразу после объявления с аргументами - массив строк и число на которое нужно сдвинуть массив.
    Суть данной функции в том, что она сдвигает начальные элементы массива в конец, пока число, на которое нужно сдвинуть массив, не будет равно 0.
    Push и shift мутируют массив, так что не важно что она возвращает.

    Ее чистый вариант будет выглядеть примерно так:
    [IMG]

    И так инициализация массива происходит путем объявления переменной с массивом и аншафла строк. Данные из нее получаем путем выполнения функции, которая на вход получает индекс.

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

    Теперь напишем манипулятор.
    Я предлагаю использовать nodejs модули:
    meriyah для парсинга и преобразования кода в дерево, которая,
    astring для генерации текстового кода из AST,
    и astray для манипуляций с деревом.

    Установить их можно при помощи команды:
    npm i astray astring meriyah
    Перед этим прописав инициализацию(хороший тон):
    npm init
    Так же нам понадобится fs для чтения и записи файлов.
    Импортировать модули, а так же прочесть файл и сгенерировать для него дерево можно данным кодом:
    [IMG]

    Готовый манипулятор будет выглядеть как то так:
    [IMG]
    Многие траверсеры AST работают по паттерну visitor, поэтому каждый вызов функции(CallExpression) будет передаваться в нашу функцию.
    В самой функции мы проверяем вызов функции - что вызывается и с какими аргументами и если он удовлетворяем нашим хотелкам - возвращаем новую ноду в виде простой строки, вместо вызова функции.

    Мини пояснение:
    [IMG]

    Чтобы это работало нужно определить getValue - это просто переименованная _0x3d28, для нашего же удобства;

    Все! Мы изменили код))
    Осталось его сохранить - пишем в файл то, что вернет astring:
    Code
    writeFileSync("./output.js", generate(AST));
    В output будет уже измененный код. В нем уже можно удалить весь код который относится к инициализации массива и получению из него переменной, потому что он там более не используется.

    Для ренейминга переменных я предлагаю использовать модуль для vscode: https://marketplace.visualstudio.com/items?itemName=cmstead.jsrefactor
    Он переименовывает все идентификаторы указанной переменной, обращая внимание на scope.
    Финальная и чуть измененная(модульная) версия будет состоять из 2 файлов (cори за пастбин):
    index js: https://pastebin.com/VpgpWFay
    ASTmodules js: https://pastebin.com/QnwnUKEF
    Code
    Итог: в файл input.js помещаете ваш код, запускаете через node index скрипт, в output.js получаете изменненый.
    Понять почему именно такой код мы написали, вам так же поможет https://astexplorer.net. В него можно совать куски валидного кода, и он будет распаршивать их в AST, наглядно показывая результат.

    Так же могу порекомендовать великолепный плейграунд для js кода - quokka js. Желательно Pro версию, в ней больше возможностей.

    Для лучшего экспириенса во время деобфускации и в целом программирования можно пользоваться дебаггингом с брейкпоинтами в vscode. (Попробуйте нажать F5)

    Автор: https://t.me/elevengate
    Предложения по оформлению, что интересно по теме - пишите тут.
     
  2. petral2002
    petral2002 Nov 28, 2020 0 Nov 18, 2018
    нет кода ASTmodules js
     
  3. lonely_femboy
    lonely_femboy Mar 6, 2022 сыграй мне реквием 228 Feb 21, 2020
    +Rep, но [IMG]
     
Loading...
Top