js обфускация и антиобфускация
js обфускация и антиобфускация

Зачем запутывать

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

Общие идеи об обфускации и антиобфускации JS

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

сжатие кода

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

обфускация кода

Здесь мы познакомим вас с некоторыми распространенными методами путаницы и поговорим о некоторых распространенных методах путаницы. На самом деле существует множество методов путаницы.

Javascript предоставляет возможность выполнять строки как код (оценивать). Строку можно передать в механизм js для анализа и выполнения через конструктор функций, eval, setTimeout и setInterval.

  • Методы доступа к переменным-членам

В js вы можете получить доступ к методу eval объекта Windows через window.eval() или использовать для доступа к нему window[’eval’].

  • Обфускация имен переменных (преобразование имен переменных в бессмысленные строки (шестнадцатеричные) снижает читаемость кода)
Язык кода:javascript
копировать
// let str = 'eval'
let _0xfg31e = 'eval'
  • Обфускация строк (шифрование или кодирование, цель: гарантировать, что исходную строку невозможно найти путем поиска в коде)
Язык кода:javascript
копировать
// let str = 'eval'
let str = 'e'+'v'+'a'+'l'//Сращивание
  • База/Кодировка
Язык кода:javascript
копировать
// let str = 'eval'
let str = '\u0065\u0076\u0061\u006c'//кодировка Юникода
let str = 14..toString(15) + 31..toString(32) + 0xf1.toString(22) //Используйте toString()
  • Разделить с помощью массивов
Язык кода:javascript
копировать
// console.log(new window.Date().getTime())  
var arr = ['log','Date','getTime']
console[arr[0]](new window[arr[1]]()[arr[2]]())
Язык кода:javascript
копировать
14..toString(15) + 31..toString(32) + 0xf1.toString(22)
  • Преобразование констант в арифметические выражения
Язык кода:javascript
копировать
// var num = 1234
var num = 602216 ^ 603322 
  • Арифметическое выражение изменено на выражение вызова функции
Язык кода:javascript
копировать
// var num = 602216 ^ 603322 
var a = function (s, h) {
    return s ^ h;
}(602216, 603322)

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

Анти-отладка

  • Запрещенный отладчик

Напишите бесконечный цикл таймера, чтобы отключить отладку.

Язык кода:javascript
копировать
function debug() {
    debugger;
    setTimeout(debug, 1);
}
debug();

Это может закомментировать ту часть, которая вызывает debug(). В конце концов, js может изменить что угодно во внешнем интерфейсе.

  • Очистить консоль
Язык кода:javascript
копировать
function clear() {
    console.clear();
    setTimeout(clear, 10);
}
clear();

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

  • Обнаружение изменений свойств функций и объектов

При отладке злоумышленники часто удаляют защитные функции или подделывают объекты данных обнаружения. Содержимое функции может быть обнаружено, а модификации прототипа запрещены.

Язык кода:javascript
копировать
// функция оценки
function eval() {
    [native code]
}

//Используйте eval.toString для сопоставления содержимого»[native код]" можно легко сэкономить
window.eval = function(str){
        /*[native code]*/
        //[native code]
        console.log("[native code]");
    };

//Полное совпадение с eval.toString, которое можно обойти, переписав toString
window.eval = function(str){
        //....
    };
    window.eval.toString = function(){
        return `function eval() {
            [native code]
        }`
    };

//Обнаружение прототипа eval.toString и eval
function hijacked(fun){
        return "prototype" in fun || fun.toString().replace(/\n|\s/g, "") != "function"+fun.name+"(){[nativecode]}";
    }

Некоторые методы борьбы с обфускацией

Самое главное — набраться терпения, прервать его по F12, а затем с помощью console.log и других методов просмотреть его шаг за шагом, ведь как бы вы его не запутывали, логику самого кода это не меняет, и большинство из них можно восстанавливать медленно.

Советы по F12

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

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

Общие инструменты обфускации/антиобфускации

Попробуйте антиобфускацию самостоятельно

HGAME 2023 Week1 Classic Childhood Game

Конечно, непосредственное выполнение mota() даст результат, но давайте попробуем деобфусцировать этот код посредством отладки, чтобы увидеть, в чем заключается логика.

https://www.json.cn/json/jshx.html Переименование переменной открытого метода Строковое шифрование Переставить строку Строка в кодировке Base64 Запутанный код, созданный escape-кодом Unicode.

Язык кода:javascript
копировать
function mota() {
  var a = ['\x59\x55\x64\x6b\x61\x47\x4a\x58\x56\x6a\x64\x61\x62\x46\x5a\x31\x59\x6d\x35\x73\x53\x31\x6c\x59\x57\x6d\x68\x6a\x4d\x6b\x35\x35\x59\x56\x68\x43\x4d\x45\x70\x72\x57\x6a\x46\x69\x62\x54\x55\x31\x56\x46\x52\x43\x4d\x46\x6c\x56\x59\x7a\x42\x69\x56\x31\x59\x35'];
  (function (b, e) {
    var f = function (g) {
      while (--g) {
        b['push'](b['shift']());
      }
    };
    f(++e);
  }(a, 0x198));
  var b = function (c, d) {
    c = c - 0x0;
    var e = a[c];
    if (b['CFrzVf'] === undefined) {
      (function () {
        var g;
        try {
          var i = Function('return\x20(function()\x20' + '{}.constructor(\x22return\x20this\x22)(\x20)' + ');');
          g = i();
        } catch (j) {
          g = window;
        }
        var h = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        g['atob'] || (g['atob'] = function (k) {
          var l = String(k)['replace'](/=+$/, '');
          var m = '';
          for (var n = 0x0, o, p, q = 0x0; p = l['charAt'](q++); ~p && (o = n % 0x4 ? o * 0x40 + p : p, n++ % 0x4) ? m += String['fromCharCode'](0xff & o >> (-0x2 * n & 0x6)) : 0x0) {
            p = h['indexOf'](p);
          }
          return m;
        });
      }());
      b['fqlkGn'] = function (g) {
        var h = atob(g);
        var j = [];
        for (var k = 0x0, l = h['length']; k < l; k++) {
          j += '%' + ('00' + h['charCodeAt'](k)['toString'](0x10))['slice'](-0x2);
        }
        return decodeURIComponent(j);
      };
      b['iBPtNo'] = {};
      b['CFrzVf'] = !![];
    }
    var f = b['iBPtNo'][c];
    if (f === undefined) {
      e = b['fqlkGn'](e);
      b['iBPtNo'][c] = e;
    } else {
      e = f;
    }
    return e;
  };
  alert(atob(b('\x30\x78\x30')));
}

Сначала определяется переменная a, а затем a — это часть содержимого в кодировке Base64, которая также закодирована в Unicode. Это содержимое можно увидеть в console.log, а также мы можем увидеть его во время динамической отладки.

Затем мы продолжаем двигаться дальше и видим, что на самом деле это процесс многократного декодирования base64.

здесьeЗначениеaGdhbWV7ZlVubnlKYXZhc2NyaXB0JkZ1bm55TTB0YUc0bWV9

Возвращаемое значение функции — e, а затем atob() base64 декодирует один слой, чтобы получить флаг.

Реверс интерфейса Baidu Translation

https://fanyi.baidu.com/

здесь Есть один, называетсяlangdetectиз接口来探测语言

然后有接口https://fanyi.baidu.com/v2transapi,Это запрос POST, и все данные находятся в форме.

здесьвоспользовалсяsignиtokenСделано несколько стратегий по предотвращению контроля рисков,Приходите и посмотритеsignиtokenКак он генерируется?。

Мы несколько раз пытались перевести,ОбнаружитьtokenВсегда то же самое,Тогда возьми это напрямуюtokenПоиск значения,Было обнаружено, что при запросе статических ресурсов,будет жестко запрограммировано.

signЗначение менялось в ходе нескольких переводов.,тогда мы Приходите и посмотритеjsКак он генерируется?signиз。

Выполните поиск по исходному коду по всему миру и обнаружите, что он присутствует в index.dc84f2b3.js, но не похож на него где-либо еще, поэтому присмотритесь к этому файлу и попытайтесь сломать точку, чтобы увидеть, можно ли его сломать.

Всего появилось 5 мест, я попробовал все брейк-пойнты и обнаружил, что могу пробить на линии 21909.

Итак, давайте посмотрим, что делает эта функция b(e),Наведите указатель мыши на функцию, чтобы увидеть, где на нее ссылаются.,мы можем Обнаружитьвходящийизпараметрeэто то, что мы хотим перевестиизсодержание,Кажется, это основано на переводеизсодержание动态生成了一个signраньше подписывал。

Давайте проследим за этим b(e) и посмотрим

Логика этой функциональной темы заключается в выполнении некоторых битовых операций на основе переданной нами строки.,Наконец-то получи одинsign

Найдя эту часть логики, мы можем сгенерироватьsignиз Часть кода скрыта отизизвлечено из функции

Язык кода:javascript
копировать
var e = 'Hello World'

function b(t) {
            var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
            if (null === i) {
                var a = t.length;
                a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
            } else {
                for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
                    "" !== s[c] && l.push.apply(l, function(t) {
                        if (Array.isArray(t))
                            return e(t)
                    }(o = s[c].split("")) || function(t) {
                        if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
                            return Array.from(t)
                    }(o) || function(t, n) {
                        if (t) {
                            if ("string" == typeof t)
                                return e(t, n);
                            var r = Object.prototype.toString.call(t).slice(8, -1);
                            return "Object" === r && t.constructor && (r = t.constructor.name),
                            "Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
                        }
                    }(o) || function() {
                        throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
                    }()),
                    c !== u - 1 && l.push(i[c]);
                var p = l.length;
                p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
            }
            for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
                var _ = t.charCodeAt(v);
                _ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
                g[y++] = _ >> 18 | 240,
                g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
                g[y++] = _ >> 6 & 63 | 128),
                g[y++] = 63 & _ | 128)
            }
            for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
                b = n(b += g[x], w);
            return b = n(b, k),
            (b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
            "".concat((b %= 1e6).toString(), ".").concat(b ^ f)
        }
console.log(b(e))

Запускать локально Обнаружить Недостатокr

Вернитесь на страницу и начните двигаться, чтобы увидеть, что такое r.

Вот доступ к атрибуту d объекта окна,Значение d — «gtk».,доступизоказаться320305.131321201,Таким образом, наша локальная среда узла не может получить доступ к окну [],Затем просто жестко закодируйте значение напрямую.

снова Обнаружитьnне существует,Тогда продолжим движение

Посмотрите шаг за шагом

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

Язык кода:javascript
копировать
var e = 'Hello World'

function b(t) {
    var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
    if (null === i) {
        var a = t.length;
        a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
    } else {
        for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
            "" !== s[c] && l.push.apply(l, function (t) {
                if (Array.isArray(t))
                    return e(t)
            }(o = s[c].split("")) || function (t) {
                if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
                    return Array.from(t)
            }(o) || function (t, n) {
                if (t) {
                    if ("string" == typeof t)
                        return e(t, n);
                    var r = Object.prototype.toString.call(t).slice(8, -1);
                    return "Object" === r && t.constructor && (r = t.constructor.name),
                        "Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
                }
            }(o) || function () {
                throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
            }()),
                c !== u - 1 && l.push(i[c]);
        var p = l.length;
        p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
    }
    for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (r = "320305.131321201").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
        var _ = t.charCodeAt(v);
        _ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
            g[y++] = _ >> 18 | 240,
            g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
            g[y++] = _ >> 6 & 63 | 128),
            g[y++] = 63 & _ | 128)
    }
    for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
        b = n(b += g[x], w);
    return b = n(b, k),
        (b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
        "".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}

function n(t, e) {
    for (var n = 0; n < e.length - 2; n += 3) {
        var r = e.charAt(n + 2);
        r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
            r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
            t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
    }
    return t
}
console.log(b(e))

Мы закончили здесь

Вопросы о соревнованиях Defcon 2021 Quals Threefactorooorx

Поскольку вложение, указанное в конкурсном вопросе (расширение браузера Chrome), больше не может работать на моем chrome109.,Я использовал управление пакетами Arch и выполнил поиск, но откатить версию Chrome не удалось.,Решение все равно должно быть, но мне не хочется тратить много времени, пытаясь это сделать.,взглянулп Ню, WPэта темаиз Суть в том, что пока вы можете отлаживатьи Антиобфускацияjs,Вы будете знать, что делаете, выполняя отладку шаг за шагом.

Суть вопроса в расширении Chrome под названием «3FA», которое используется для предотвращения фишинга. Js в плагине запутан. Вам необходимо установить это расширение, чтобы использовать функции сайта. Функция сайта заключается в том, что после загрузки HTML бот получит доступ к странице и отправит обратно скриншот посещения. Необходимо отладить этот запутанный js и обнаружить, что в этом js есть функция отправки сообщений. Перевернув логику, мы можем создать вредоносную HTML-страницу, которую представляет бот (эквивалент реального человека, который также установил плагин 3FA). in) может получить доступ. После этого на странице будет отображаться флаг бота, а затем в вопросе будет создана функция, позволяющая фотографировать результаты доступа бота и отображать их на нашей странице. Это эквивалентно тому, что мы завершаем атаку на посетителей. путем реверс-инжиниринга этого расширения Chrome.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose