#инструмент дня
Несколько часов превратились в пару дней. Новый год, а что вы хотели.Итак, мы остановились на том что конкуренты писали свой проект на React Native, с говорящим за себя файлом
main.jsbundle.
И тут начинается самое интересное: этот бандл может оказаться как просто минифицированным JS-кодом, так и... байт-кодом Hermes!
Немного истории: React Native начинался с движка JSC aka JavaScriptCore. Но в Facebook решили, что производительности его JIT для замены нативных приложений явно недостаточно, и с 2019 года
предложили альтернативу: виртуальную машину Hermes, в код которой и собирается ваш JavaScript.
Это ускоряет запуск приложений, особенно больших. В статье по
ссылке много интересных подробностей.
Первым делом убеждаемся, что это именно Hermes:
$ file main.jsbundle
main.jsbundle: Hermes JavaScript bytecode, version 96
Поиск по строкам внутри бинарника, прямо в mc, даёт нам искомое sendGetInstalledApps. Пришло время для дизассемблирования!
Идём в гугл, наверняка кто-то уже озадачился вопросом. И таки да! Встречайте:
hermes-dec. Буквально, описание: «A reverse engineering tool for decompiling and disassembling the React Native Hermes bytecode». Звучит как нечто, нужное нам.
Забираем, пробуем установить:
$ git clone git@github.com:P1sec/hermes-dec.git
$ cd hermes-dec/
$ python3 setup.py install
...и получаем отлуп по
python-installtools. Впрочем, это быстро решается через
brew. Едем дальше, дизассемблируем:
$ python3 hbc_disassembler.py ../../main.jsbundle bundle.hasm
И вот, красиво оформленный вывод ассемблера HASM, в котором все строковые данные и названия функций разнесены по блокам и расшифрованы!
И что же мы (внимание на иллюстрацию к посту) можем увидеть из такого вывода, даже не зная ассемблера?
Ну, достаточно много. Например, что тут формируется JSON для отправки телевизору, в котором присутствует метод
ms.channel.emit и передаются данные:
{'data': '', 'event': 'ed.installedApp.get', 'to': 'host'}.
Не то, чтоб я об этом не знал! Но все эти API достаются обходными путями. Например, из SDK Tizen или из официальных приложений от Samsung и вендоров. Зачастую, очень важен формат: где-то
data должна быть
null, где-то — пустой объект или строка. Поиски нужных комбинаций откровенно раздражают.
Что же дальше? А дальше я обратил внимание на метод
sendGetAppIcon, который тоже виден на скриншоте. И до меня дошло: они реально отправляют запрос на список всех приложений, а потом — бомбят телевизор запросами об иконках. Не самый оптимальный способ получения информации, но другого нет.
Впрочем, всегда можно просто бандлить иконки с собой.Но давайте попробуем воспользоваться ещё одной возможностью hermes-dec: декомпиляцией. Ага, получаем JS-код обратно:
$ python3 hbc_decompiler.py ../../main.jsbundle main.jsНу и на самом деле что-то получили, вот только, выглядит оно как-то так:
r4 = function() { // Original name: sendGetInstalledApps, environment: r3
r0 = global;
r2 = r0.JSON;
r1 = r2.stringify;
r0 = {};
r3 = 'ms.channel.emit';
r0['method'] = r3;
r3 = {'data': '', 'event': 'ed.installedApp.get', 'to': 'host'};
r0['params'] = r3;
r2 = r1.bind(r2)(r0);
r1 = _closure1_slot4;
r0 = r1.send;
r0 = r0.bind(r1)(r2);
r0 = undefined;
return r0;
};
Не сильно больше информации, чем в дизассемблированной версии :( Всё дело в том, что утилита пока не продвинулась дальше «плоских» вызовов и не разворачивает не то, что замыкания, но даже циклы. Впрочем, не мне жаловаться!
Итак, выводы: у разработчиков неофициальных клиентов под телевизоры не больше информации чем у меня или любого из вас, потому любое начинание — стоит того. Как минимум, это интересно! Иногда брутфорс реально рабочий метод, и его применение не должно вас смущать так, как смутило когда-то меня настолько, что я решил использовать захардкоженный список приложений.
Дерзайте, котаны! С Новым годом :)