По причинам проектирования доступ к внешнему js-коду можно получить в браузере, поэтому нам необходимо запутать js-код, поскольку необходимо предотвратить анализ и копирование кода, что вызовет больше проблем с безопасностью.
Поняв процесс выполнения js-кода, давайте посмотрим, как его запутать. Вы можете подумать, что нам следует делать, если мы хотим реализовать js-обфускатор. Либо использовать обычную замену, либо генерировать запутанный код на этапе AST. Использование обычной замены легко реализовать, но эффект в настоящее время относительно невелик. Это делается для того, чтобы сгенерировать запутанный код без изменения AST, гарантируя, что функция кода останется неизменной и цель обфускации может быть достигнута.
Излишне говорить, что сжатие js-кода означает удаление пробелов, новых строк и т. д., в результате чего код становится куском или даже строкой.
Здесь мы познакомим вас с некоторыми распространенными методами путаницы и поговорим о некоторых распространенных методах путаницы. На самом деле существует множество методов путаницы.
Javascript предоставляет возможность выполнять строки как код (оценивать). Строку можно передать в механизм js для анализа и выполнения через конструктор функций, eval, setTimeout и setInterval.
В js вы можете получить доступ к методу eval объекта Windows через window.eval() или использовать для доступа к нему window[’eval’].
// let str = 'eval'
let _0xfg31e = 'eval'
// let str = 'eval'
let str = 'e'+'v'+'a'+'l'//Сращивание
// let str = 'eval'
let str = '\u0065\u0076\u0061\u006c'//кодировка Юникода
let str = 14..toString(15) + 31..toString(32) + 0xf1.toString(22) //Используйте toString()
// console.log(new window.Date().getTime())
var arr = ['log','Date','getTime']
console[arr[0]](new window[arr[1]]()[arr[2]]())
14..toString(15) + 31..toString(32) + 0xf1.toString(22)
// var num = 1234
var num = 602216 ^ 603322
// var num = 602216 ^ 603322
var a = function (s, h) {
return s ^ h;
}(602216, 603322)
В JS существует множество способов конвертации, которые полны возможностей. Использование всего лишь нескольких сделает код совершенно непонятным.
Анти-отладка
Напишите бесконечный цикл таймера, чтобы отключить отладку.
function debug() {
debugger;
setTimeout(debug, 1);
}
debug();
Это может закомментировать ту часть, которая вызывает debug(). В конце концов, js может изменить что угодно во внешнем интерфейсе.
function clear() {
console.clear();
setTimeout(clear, 10);
}
clear();
Это бесполезно. Вы можете проверять переменные непосредственно во время отладки или использовать описанный выше метод, чтобы обойти это.
При отладке злоумышленники часто удаляют защитные функции или подделывают объекты данных обнаружения. Содержимое функции может быть обнаружено, а модификации прототипа запрещены.
// функция оценки
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 и других методов просмотреть его шаг за шагом, ведь как бы вы его не запутывали, логику самого кода это не меняет, и большинство из них можно восстанавливать медленно.
Во-первых, существует функция поиска, которая может глобально искать статические файлы, что полезно при поиске некоторых конкретных функциональных блоков.
Вторая — функция замены. После включения локальной замены вы можете напрямую редактировать содержимое исходного кода и сохранять его. Файл будет сохранен в файле замены, и вы сможете по своему желанию внести некоторые изменения во внешний интерфейс.
Конечно, непосредственное выполнение mota() даст результат, но давайте попробуем деобфусцировать этот код посредством отладки, чтобы увидеть, в чем заключается логика.
https://www.json.cn/json/jshx.html Переименование переменной открытого метода Строковое шифрование Переставить строку Строка в кодировке Base64 Запутанный код, созданный escape-кодом Unicode.
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 декодирует один слой, чтобы получить флаг.
здесь Есть один, называется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
из Часть кода скрыта отизизвлечено из функции
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
。
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))
Мы закончили здесь
Поскольку вложение, указанное в конкурсном вопросе (расширение браузера Chrome), больше не может работать на моем chrome109.,Я использовал управление пакетами Arch и выполнил поиск, но откатить версию Chrome не удалось.,Решение все равно должно быть, но мне не хочется тратить много времени, пытаясь это сделать.,взглянулп Ню, WPэта темаиз Суть в том, что пока вы можете отлаживатьи Антиобфускацияjs,Вы будете знать, что делаете, выполняя отладку шаг за шагом.
Суть вопроса в расширении Chrome под названием «3FA», которое используется для предотвращения фишинга. Js в плагине запутан. Вам необходимо установить это расширение, чтобы использовать функции сайта. Функция сайта заключается в том, что после загрузки HTML бот получит доступ к странице и отправит обратно скриншот посещения. Необходимо отладить этот запутанный js и обнаружить, что в этом js есть функция отправки сообщений. Перевернув логику, мы можем создать вредоносную HTML-страницу, которую представляет бот (эквивалент реального человека, который также установил плагин 3FA). in) может получить доступ. После этого на странице будет отображаться флаг бота, а затем в вопросе будет создана функция, позволяющая фотографировать результаты доступа бота и отображать их на нашей странице. Это эквивалентно тому, что мы завершаем атаку на посетителей. путем реверс-инжиниринга этого расширения Chrome.