Отладка/реверсинг JavaScript: мониторинг памяти и поиск значений в ней

Допустим, есть у меня простой код:

<html><body><script type=text/javascript>
゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚);
 (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚]
,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] 
=((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];
(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+
((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+
((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚)
['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3)
+'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o
-゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\';
(゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';
(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+
(゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚)+
(゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+
(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+
(゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ (c^_^o)+
(゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+
(゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) +
(゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+
(c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+
(゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+
(゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+
(o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+
((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+
((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚)
+ (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');

</script>

(это пример работы кодировщика с https://utf-8.jp/public/aaencode.html с примером по умолчанию)

Мне известно, что если этот код запустить, то где-то внутри соберется строка "Hello, JavaScript" и будет выведена на экран через alert();.

Если код засунуть в http://int3.github.io/metajs/, то можно увидеть, как в процессе пошаговой работы, внизу стека виднеется:

BinaryExpression
BinaryExpression → return"\141\154\145\162\164\50\42\110\145\

Где в качестве литерала, выступает закодированное представление

alert("He

Это - кусочек искомого значения, которое известно заранее (тут было закодировано alert("Hello, JavaScript"))

Внимание, вопросы:

  1. Как отловить фрагменты кода, ответственные за генерацию этой строки?
  2. Поставить брейкпоинт в тот момент, когда искомая строка уже сформирована, чтобы получить хотя бы бектрейс?
  3. Есть ли инструменты для преобразования этого в AST-деревья на манер https://esprima.org/demo/parse.html - но с возможностью редактирования и перекомпиляции обратно? Или таким образом ловить строчку бесполезно?

Ответы (1 шт):

Автор решения: UserTest013

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

  1. Открываем консоль браузера.
  2. Пишем в консоли ключевое слово debugger, ставим после него точку с запятой, вставляем нашу зашифрованную строку и нажимаем ентер.
  3. Если все сделали правильно оказываемся на вкладке с исходным кодом в режиме отладки. Для удобства нажимаем кнопочку pretty print {} чтобы видеть отформатированный код.

первый результат

  1. Посмотрев на код можно сделать вывод, что интересующая нас строка находится в самом конце. Потому что она самая длинная. Скорее всего все строки кроме последней - просто подготовительные операции. Так что ставим брекпоинт на последнюю строку и жмем Ф8.
  2. Находясь в последней строке ми можем увидеть что идет обращение к свойству "_" объекта (゚Д゚). Смотрим что там находится Function. Это позволяет нам сделать вывод, что наша строка будет передана первым аргументом в Function и полученная функция будет сразу вызвана (так как это последняя строчка в коде).

второй результат

  1. На основе информации из предыдущего шага мы понимаем, что надо просто взять последнюю строчку кода, убрать сначала строчки обращение Function и в конце убрать скобки.
  2. То что осталось от последней строчки надо выполнить в консоле.

введите сюда описание изображения

  1. Профит... Мы увидели исходный код.

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

→ Ссылка