
Inspeciona, descompila e aplica patches estruturais ao bytecode Hermes (HBC) de aplicações React Native, com um REPL estilo GDB, CFG, descompilador e patcher de re-serialização.
Hermes Reverse Engineering & Manipulation Interactive Toolkit.
hermit inspeciona, descompila e aplica patches estruturais ao bytecode do Hermes (HBC), o formato no qual os aplicativos React Native distribuem seu JavaScript. Abra um arquivo .hbc, navegue por suas funções, leia o JavaScript descompilado, edite instruções, strings e literais em um editor interativo e grave de volta um arquivo que a VM do Hermes ainda carrega e executa.
Diferente de ferramentas que apenas analisam bytecode, ou que o patcham no local sem alterar tamanhos, o hermit re-serializa o arquivo inteiro. Ele pode inserir e excluir instruções, realocar saltos e tratadores de exceção, reconstruir as tabelas de strings e literais, adicionar novas funções e recalcular o rodapé SHA-1. Um arquivo não modificado faz round-trip byte a byte.
.hbc| Versão | Papel |
|---|---|
| 96 | Alvo principal. O que os aplicativos React Native em produção usam: RN 0.73 a 0.83, e RN 0.84+ com Hermes V1 desabilitado. |
| 94, 95 | Validados. O formato é idêntico ao 96, apenas as tabelas de opcodes diferem. |
Aplicativos compilados com Hermes V1 (o padrão a partir do RN 0.84) emitem HBC 98, que ainda não é suportado. Notas sobre o formato estão em doc/hbc-format/.
Cada release tem arquivos para macOS e Linux, em arm64 e x86_64. Não é necessário Python nem compilador:
| Arquivo | Conteúdo |
|---|---|
hermit-<version>-<platform>.tar.gz | O REPL interativo: ./hermit file.hbc. |
hermit-tools-<version>-<platform>.tar.gz | As ferramentas de linha de comando hbc_* autônomas. |
SHA256SUMS | Checksums: shasum -a 256 -c SHA256SUMS. |
tar -xzf hermit-0.1.0-macos-arm64.tar.gz
./hermit-0.1.0-macos-arm64/hermit --version
Os binários para macOS não são assinados. Após o download, remova a flag de quarentena uma vez: xattr -dr com.apple.quarantine hermit-0.1.0-macos-arm64. As compilações para Linux precisam de glibc 2.35 ou mais recente. O comando cfg ainda precisa do graph-easy instalado.
Os releases são produzidos por .github/workflows/release.yml quando uma tag v* é enviada, usando packaging/build-release.sh, que você também pode executar localmente.
FetchContent do CMake, a menos que já estejam instalados.graph-easy para o comando cfg (cpanm Graph::Easy), less como seu paginador.Execute tudo a partir deste diretório (o que contém o CMakeLists.txt):
cmake -B build
cmake --build build -j
Isso compila a biblioteca estática libhbc, o módulo Python _libhbc (em build/bindings/), as ferramentas de linha de comando (em build/tools/) e os testes unitários. O REPL só precisa do módulo Python:
cmake --build build --target _libhbc
As ferramentas e os testes podem ser deixados de fora de uma compilação, por exemplo para um release:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DHERMIT_BUILD_TOOLS=OFF -DHERMIT_BUILD_TESTS=OFF
Recompile com o mesmo comando após cada alteração em core/ ou bindings/.
macOS: se a linkagem falhar com um erro sobre um SDK malformado, aponte a compilação para um SDK completo, por exemplo
SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX26.5.sdk cmake --build build.
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
O módulo _libhbc não é instalado no virtualenv. Adicione seu diretório de compilação ao PYTHONPATH sempre que executar o hermit:
export PYTHONPATH=$PWD/build/bindings:$PYTHONPATH
.hbcUm aplicativo React Native distribui seu bundle como um arquivo simples:
| Plataforma | Localização dentro do pacote |
|---|---|
Android (.apk, um zip) | assets/index.android.bundle |
iOS (.ipa, um zip) | Payload/<App>.app/main.jsbundle |
Se o arquivo começar com os bytes C6 1F BC 03 C1 03 19 1F, é bytecode do Hermes. O REPL só abre arquivos com a extensão .hbc, então renomeie-o:
unzip -p app.apk assets/index.android.bundle > app.hbc
xxd app.hbc | head -1 # c61f bc03 c103 191f ...
Analise apenas aplicativos que você tem permissão para estudar, por exemplo os seus próprios, ou aplicativos de código aberto para pesquisa.
Para obter entradas pequenas e controladas, compile JavaScript ou TypeScript com um compilador Hermes que emita HBC 96 (por exemplo, hermesc do react-native 0.73 a 0.83, em node_modules/react-native/sdks/hermesc/):
hermes -emit-binary -g0 -out hello.hbc hello.js # -g0: sem informações de depuração
O pacote seeder/ automatiza isso para os programas de exemplo em seeder/samples/ e grava os resultados em seeder/corpus/:
.venv/bin/python -m seeder.compile # todos os exemplos
.venv/bin/python -m seeder.compile --g0 seeder/samples/loop_sum.js
.venv/bin/python -m seeder.compile --debug seeder/samples/greeting.js
--g0 grava <name>_g0.hbc sem informações de depuração, --debug grava <name>_g.hbc com informações de depuração completas. Exemplos .ts precisam do tsc no seu PATH; o compilador é obtido de --hermes (padrão hermes). seeder/build-real-bundle.sh compila um aplicativo React Native de código aberto real em um .hbc.
export PYTHONPATH=$PWD/build/bindings:$PYTHONPATH
.venv/bin/python -m cli.main app.hbc
Sem um argumento de arquivo, o REPL inicia vazio; use open <file.hbc>. O prompt mostra a versão do HBC e o nome do arquivo, com um + quando há alterações não salvas: [hbc v96 | app+] >. O histórico é mantido em ~/.hermit_history e os comandos têm autocompletar com Tab.
> info
> strings --identifiers filter:fetch
> functions
> disasm func:12
> decompile func:isPremium
> xrefs string:"api.example.com"
> edit func:isPremium
> patch patched.hbc
As funções são endereçadas por índice ou nome (func:12, func:isPremium), as strings por índice ou valor (string:42, string:"hello"), os locais de literais por índice (array:7).