seerozha (seerozha) wrote,
seerozha
seerozha

Category:

ИТ: О незаметном JavaScript

Визуально непривлекательный JavaScript, так скажем )) Для поклонников JSfuck.

"

«Исчезатор» кода


Задача написать код, которого… как бы нет. Еще он должен уметь что-то делать. Очевидно, что какие-либо манипуляции нужно сопроводить некоей функцией, которая бы могла интерпретировать эти манипуляции, а поэтому скрыть код вообще, увы, не выйдет, но сократить последний до пары-тройки строчек — запросто.

Многие знают или слышали, что в компьютерной типографике существуют непечатные символы, т.е. фактически невидимые. Причем это не какой-то баг или фишка, а вполне нормальное поведение — быть невидимыми. В настоящий момент одной из общепринятых и стандартизированных кодировок текста является UTF-8, она используется практически на любом современном сайте. В ней ценно и то, что там присутствует целая куча невидимых символов! Например, один из них — Zero Width Space (U+200B). Вот он: "​". Видите? Нет? А он есть.

Метод Дэвида Блейна


Для желающих потрогать руками привожу ссылку на пример годичной давности: рабочее демо смотреть бесплатно онлайн. Уже потом, спустя несколько месяцев после заметки в песочнице Хабра, я случайно набрел на пост, где просматривалась эта идея (способ номер три), но без изюминки.

В моей версии кодирование производилось наипримитивнейшим образом. Минус — сильно возрастает объем файла, плюс — нужно всего два символа для кодирования. Выглядело примерно так:
var code = '1101101111110111111111111111110101101101111101111';




Спустя довольно длительное время, я вернулся к этой теме в рамках одного проекта, которым занимаюсь. Была предпринята попытка пойти дальше и начал с того, что теперь каждый символ кодируется не единицами и нулями, а четырьмя символами:
"f".charCodeAt(0).toString(16);
// "66"

//Таким образом код символа "f" - 0x0066
String.fromCharCode("0x0066");
// "f"




В итоге, имея набор из 16 символов, можно сократить избыток лишнего кода:
var Symbols = ["й","ц","у","к","е","н","г","ш","щ","з","х","ъ","ф","ы","в","а"];

//Теперь можно закодировать символ "f":
var bar = invisibleJS("f");
// bar = "ййгг";




Увеличение объема, занимаемого кодом в данном примере снизилось до (4 символа, чтобы закодировать один), но по идее, если не нужен русский язык и/или какие-то другие не латинские символы, то можно добиться и .

Примеры в студию


Пускай будет такой код:
alert("Hello world!");




После скармливания кода обфускатору (приводить и разбирать код не буду, в нем нет ничего интересного), на выходе получается что-то вроде:
var helloworld = "⁡⁡‫‌⁡⁡‫⁡⁡‫‪⁡⁡‬‍⁡⁡‬‏⁡⁡‍‭⁡⁡‍‍⁡⁡‏‭⁡⁡‫‪⁡⁡‫⁡⁡‫⁡⁡‫⁡⁡‍⁡⁡⁡‬‬⁡⁡‫⁡⁡‬‍⁡⁡‫⁡⁡‫‏⁡⁡‍‌⁡⁡‍‍⁡⁡‍‮";




Обратите внимание на то, что точка с запятой находится внутри кавычек, хотя на самом деле это не так (можно проверить почти в любом текстовом редакторе, например Sublime). С одной стороны, это добавляет +5 к обфускации, вводит в заблуждение и грозит легким brain-fuck'ом, с другой — «правильный» редактор не будет применять символы влияющие на направление текста (слева-направо, справа-налево).

Вот так выглядит в результате функция декодирования:
var revealJS = function(s){return s.match(/(.{4})/g).map(function(b){return b.split('').map(function(i){return Array.apply(null,{length:10}).map(Number.call,Number).concat('abcdef'.split(''))['⁡‌‍‎‏‪‫‬‭‮'.split('').indexOf(i)]})}).map(function(c){return String.fromCharCode(0+"x"+c.join(''))}).join('')}




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

Теперь можно «проявлять» невидимый код:
var helloworld = "⁡⁡‫‌⁡⁡‫⁡⁡‫‪⁡⁡‬‍⁡⁡‬‏⁡⁡‍‭⁡⁡‍‍⁡⁡‏‭⁡⁡‫‪⁡⁡‫⁡⁡‫⁡⁡‫⁡⁡‍⁡⁡⁡‬‬⁡⁡‫⁡⁡‬‍⁡⁡‫⁡⁡‫‏⁡⁡‍‌⁡⁡‍‍⁡⁡‍‮";

revealJS(helloworld);
// "alert("Hello world!")"

eval(revealJS(helloworld));
// Оп!




Можно прямо отсюда скопировать в консоль или посмотреть здесь.

(Приведенный в качестве примера код «проявлятора» заточен конкретно под определенные символы, использующиеся в функции «исчезатора». Меняя эти символы местами и/или используя другие, кол-во вариантов «кодовой таблицы» взлетают далеко в бесконечность.)

У всего этого есть один большой минус: можно подглядеть выполненный с помощью eval() код. Более того, консоль даже укажет файл/строчку откуда этот код запущен:


Можно исправить это недоразумение. Если использовать все четыре символа для кодирования (о чем я говорил выше), то появляется возможность обфускации внутри обфускации. Xzibit в восторге:
// Брюки превращаются...
alert("Hello world!");
// Превращаются...
window["alert"]("Hello world!");
// Брюки...
window[revealJS("⁡⁡‫‌⁡⁡‫⁡⁡‫‪⁡⁡‬‍⁡⁡‬‏")](revealJS("⁡⁡‏‭⁡⁡‫‪⁡⁡‫⁡⁡‫⁡⁡‫⁡⁡‍⁡⁡⁡‬‬⁡⁡‫⁡⁡‬‍⁡⁡‫⁡⁡‫‏⁡⁡‍‌"))
// ...превращаются в невидимый код:
"⁡⁡‬‬⁡⁡‫‮⁡⁡‫⁡⁡‫‏⁡⁡‫⁡⁡‬‬⁡⁡‪⁡⁡‫‌⁡⁡‬‎⁡⁡‫⁡⁡‍‭⁡⁡‍‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡⁡⁡‍‍⁡⁡‍‮⁡⁡‪⁡⁡‍‭⁡⁡‫‌⁡⁡‬‎⁡⁡‫⁡⁡‍‭⁡⁡‍‍‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡⁡⁡⁡‍‍⁡⁡‍‮⁡⁡‍‮"




Смотреть можно здесь. Кстати, никто не мешает обфусцировать код хоть трижды, хоть четырежды.

Теперь результирующий код выглядит так:


Уже лучше, но можно сделать еще кое-что. Вначале статьи я обозначил задачу скрыть код так, будто его нет. Сейчас же, можно просто открыть консоль и все сразу видно, что нехорошо. Устранить этот нюанс оказалось довольно просто: вместо eval() надо использовать<script></script>:
var script = document.createElement("script");
script.innerHTML = revealJS("⁡⁡‬‬⁡⁡‫‮⁡⁡‫⁡⁡‫‏⁡⁡‫⁡⁡‬‬⁡⁡‪⁡⁡‬‍⁡⁡‫‪⁡⁡‬‫⁡⁡‫‪⁡⁡‫‌⁡⁡‫⁡⁡‏⁡⁡‪‎⁡⁡‍‭⁡⁡‍‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡⁡⁡‍‍⁡⁡‍‮⁡⁡‪⁡⁡‍‭⁡⁡‬‍⁡⁡‫‪⁡⁡‬‫⁡⁡‫‪⁡⁡‫‌⁡⁡‫⁡⁡‏⁡⁡‪‎⁡⁡‍‭⁡⁡‍‍‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‍‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡‫‍⁡‫‌‍⁡‫‌‍⁡‍‍⁡⁡‍⁡‫‌‍⁡‫‌‍⁡⁡‍⁡⁡⁡⁡‍‍⁡⁡‍‮⁡⁡‍‮");
document.getElementsByTagName('body')[0].appendChild(script);
// А потом сразу же удаляем тэг, чтобы не маячил перед глазами
document.getElementsByTagName('body')[0].removeChild(script);




К сожалению, при выполнении этого кода на jsFiddle код все равно проявляется. Есть подозрение, что это каким-то образом связано с тем, что код в окне JavaScript так же оборачивается в eval() или тот же <script></script>. При тестах на локальном проекте, где нет «чудес», все работает как надо, выполняемая функция себя не проявляет:
image

Области применения


1. For fun.
2. Средство обфускации кода.
3. Использование совместно с другими способами минификации/обфускации кода. Например Google Closure Compiler или UglifyJS.
4. Возможность скрытного общения на открытых площадках.
5. «Спящие» скрипты, «закладки» в статьях, сообщениях на форумах, досках объявлений, в контекстной рекламе, да вообще где угодно, где дают что-нибудь написать и это потом попадает в браузеры пользователей.

С последними двумя пунктами не все так однозначно, но не мог их не упомянуть. Немного раскрою мысль. При беглом просмотре, было обнаружено, что, например, Gmail и Яндекс.Почта не удаляют такие символы. Некоторые трансформируются в вид &zwj; &#8234; &lrm;, но часть остается таки невидимой. Думаю, что в почтовых клиентах ситуация аналогичная (я проверил Thunderbird) — ничего не видно. Значит в письме можно послать скрытое сообщение, которое при «визуальном осмотре» не выдаст себя никак и при всем при этом даже в случае обнаружения непонятных скрытых символов расшифровать это сообщение сможет только тот, у кого есть алгоритм дешифрации (который, в общем-то, можно хранить в голове и написать код прямо в консоли браузера):
Привет, как дела⁡⁡‍⁡⁡‍⁡⁡‏‏‌⁡‏‎‪⁡‏‎‎⁡‏‎⁡‏‎‏⁡‏‎⁡‏‏⁡⁡‍⁡⁡‏‎‍⁡⁡‍⁡⁡‏‎⁡‏‏⁡‏‏‍⁡‏‏⁡⁡‍⁡⁡‍⁡⁡‏‎⁡‏‏⁡⁡‏‎‭⁡‏‏‪⁡‏‎⁡‏‎‏⁡‏‎‭⁡⁡‍⁡⁡‏‎⁡‏‎‏⁡‏‎‭⁡‏‎?




А на самом деле (надо применить ф-цию revealJS() к той части, что находится между буквой «а» и знаком вопроса):
Привет как дела/*, сегодня в пять, приходи один*/?




image

Таким образом есть возможность скрытного общения на открытых площадках. При этом никто ничего и не заподозрит. (Разве что целенаправлено будут искать, но это другой разговор). В общем, одно из главных преимуществ (а может и единственное) заключается в том, что содержание проходит «визуальный контроль» (но и тут не все так гладко: можно сменить кодировку и все обнажится). Это как человек-невидимка и система видеонаблюдения. Кто знает, может быть весь интернет уже давно напичкан такими сообщениями? :)

Что касается спрятанных скриптов, то тут все очевидно: если в ваш браузер каким-либо образом попадет вредоносный js-код, содержащий «проявлятор» и «запускатор» (например, многие подгружают библиотеки извне, взять тот же самый jQuery, который не так давно взламывали, или какой-нибудь распространенный плагин, например AdBlock), то спрятанный на странице код с определенной степенью вероятности будет запущен. То есть в данном случае схема такая: множество разных «векторов», каждый из которых направлен по-своему и один единый «активатор», который совсем крохотный.

Спасибо за внимание.

П.С. Маленький «ништячок»: если в скрипте вначале строки поставить символ U+202E (Right-To-Left Override) в кавычках, то будет веселье. Работоспособность кода при этом сохраняется:

"‮";var revealJS = function(s){return s.match(/(.{4})/g).map(function(b){return b.split('').map(function(i){return Array.apply(null,{length:10}).map(Number.call,Number).concat('abcdef'.split(''))['⁡‌‍‎‏‪

‫‬‭‮'.split('').indexOf(i)]})}).map(function(c){return String.fromCharCode(0+"x"+c.join(''))}).join('')}





Источник
Tags: javascript, web, ИТ, безопасность
Subscribe
  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments