- A rev.ng abriu o backend do decompilador revng-c, tornando open source o mecanismo de decompilação, e lançou junto uma beta fechada da UI, um novo site, o rev.ng Hub e a documentação
- Localmente, é possível configurar a CLI com um script de instalação e depois usar
revng artifact e revng ptml para verificar resultados de decompilação em forma de código C válido
- A UI interativa é baseada em VSCode, com objetivo de rodar no navegador e como aplicativo independente, e está disponível em uma beta fechada com convites para assinantes da newsletter em ordem FIFO
- Recuperação automática de estruturas de dados, reversing colaborativo, suporte a várias arquiteturas e extensibilidade são objetivos centrais, mas o QA atual está mais concentrado em binários Linux x86-64
- O framework e a CLI são open source, a UI em nuvem é gratuita para projetos públicos, e projetos privados e a UI offline independente ficam em um modelo pago
Transição para open source e beta fechada
- A rev.ng disponibilizou como open source o
revng-c, backend do seu decompilador
- Com isso, todo o mecanismo de decompilação passa a ser open source
- A documentação inicial também foi publicada
- A UI começará a enviar convites para a beta fechada a assinantes da newsletter
- Os convites serão enviados em ordem FIFO
- Para participar da beta, é preciso se cadastrar na newsletter
- Um novo site e o rev.ng Hub também foram lançados
- O rev.ng Hub é o ponto de entrada da versão em nuvem
- Usuários da beta podem criar projetos, executar a UI no navegador e colaborar com outros usuários
- Mesmo quem não estiver na beta fechada pode explorar projetos públicos
- A empresa também oferece demos privadas para quem quiser ver a rev.ng em ação diretamente
Testando a rev.ng pela CLI
- O
revng pode ser instalado em um único diretório sem permissões de root, e basta apagar esse diretório para removê-lo
curl -L -s https://rev.ng/downloads/revng-distributable/master/install.sh | bash
cd revng
source ./environment
- O exemplo
example.c é um programa simples que retorna argc * 3
int main(int argc, char *argv[]) {
return argc * 3;
}
- Depois de compilar com
gcc, executar revng artifact gera um resultado de decompilação em arquivo único
gcc example.c -o example -O2
revng artifact \
--analyze \
--progress \
decompile-to-single-file \
example \
| revng ptml --color \
| grep -A2 -B1 '[^_]main\b' \
> decompiled.c
Escopo da beta e alvos de teste
- Para usar a UI, é necessário se cadastrar na newsletter, e os convites serão enviados em pequenos lotes
- Esta versão foca em demonstrar a UI e os resultados de decompilação em alguns binários, além de receber feedback e relatos de bugs sobre trabalho com binários reais
- Os binários não triviais usados nos testes e seus tamanhos de
.text são os seguintes
- A rev.ng oferece suporte a vários ABIs e plataformas, mas o QA inicial nesta fase está concentrado em binários Linux x86-64
- Em caso de problemas, é possível buscar ajuda no Discourse
A experiência de decompilação que a rev.ng quer oferecer
- Os principais focos da rev.ng são recuperação automática de estruturas de dados, UX moderna, reversing colaborativo, amplo suporte a plataformas e extensibilidade
-
Recuperação automática de estruturas de dados
- Com a Data Layout Analysis, é possível recuperar automaticamente o layout de
struct por meio de análise interprocedural
- O exemplo de nó de lista encadeada usa uma estrutura com vetor
int64_t data[5] e um ponteiro para o próximo nó
- A saída da rev.ng gera automaticamente uma estrutura e código de função que detectam o tamanho 5 do vetor e o acesso ao ponteiro do próximo elemento
- A saída do decompilador é código C sintaticamente válido
- Esse recurso já está disponível
-
UI interativa baseada em VSCode
- Como a UI é baseada em VSCode, usuários do VSCode podem abordá-la de forma familiar
- Ela pode rodar tanto em uma aba do navegador quanto como aplicativo independente
- Os principais atalhos são os seguintes
Ctrl + Click: ir para a função ou definição de tipo sob o cursor
N: renomear
Y: editar tipo
X: mostrar referências
- A rev.ng é um decompilador interativo que recalcula apenas as partes afetadas quando há mudanças
- A UI está disponível atualmente para participantes da beta fechada
-
Reversing colaborativo
- A UI da rev.ng usa uma arquitetura cliente-servidor
- Vários usuários podem se conectar à mesma instância do daemon e trabalhar simultaneamente no mesmo projeto
- Na versão em nuvem, é possível usar o rev.ng Hub, um aplicativo semelhante ao GitHub para gerenciamento de projetos
- Os recursos colaborativos funcionam, mas ainda precisam de melhorias na experiência do usuário, acompanhadas no item #797 do roadmap
Arquitetura e forma de suporte a plataformas
- A rev.ng usa a parte inicial do pipeline do QEMU para elevar código executável a tiny code, convertê-lo em LLVM IR e então fazer a decompilação
- Essa estrutura permite oferecer suporte com relativa facilidade às arquiteturas suportadas pelo QEMU
- Assim como o suporte a arquiteturas, o suporte a plataformas — especialmente ABIs — também é importante
- A rev.ng usa um formato de descrição de ABI para descrever propriedades de ABI de forma declarativa
- Esse formato foi projetado para ser genérico o suficiente para facilitar a criação de suporte a novos ABIs
- O estado atual de suporte é o seguinte
- Arquiteturas: x86, x86-64, ARM, AArch64, MIPS e s390x, com diferentes níveis de maturidade
- Formatos binários: suporte a ELF, PE/COFF e Mach-O
- Importação: suporte a
.idb, informações de depuração DWARF e informações de depuração PDB
- A maior parte do QA foi feita em binários Linux x86-64, e o restante ainda precisa de QA adicional
- Mais QA para plataformas está sendo acompanhado no item #58 do roadmap
Extensibilidade e scripting
- A rev.ng pretende ser um framework para ferramentas de engenharia reversa, e todo o projeto fora a UI interativa é open source
- O model, arquivo de projeto, é um documento YAML, então é possível automatizar a rev.ng com qualquer ferramenta que consiga analisar JSON ou YAML
- O modelo inclui arquitetura do binário alvo, ABI padrão, segmentos, lista de funções, lista de tipos e outros dados
- É possível modificar o modelo com wrappers para Python e TypeScript
- Hoje já existem wrappers para manipulação do modelo, mas ainda não há uma forma simples de executar análises e buscar artefatos
- Um cliente Python completo está sendo acompanhado no item #17 do roadmap
- A representação interna usa bastante LLVM IR, permitindo aproveitar ferramentas do ecossistema LLVM
Separação entre CLI open source e UI paga
- O framework da rev.ng é totalmente open source, e é possível decompilar o que quiser pela CLI
- A oferta da UI se divide em três formas
- A UI em nuvem para projetos públicos pode ser usada gratuitamente
- A UI em nuvem para projetos privados exige assinatura
- A UI totalmente independente e totalmente offline será oferecida em modelo pago
- O uso da nuvem funciona da seguinte forma
- Cria-se um projeto no rev.ng Hub e convida-se colaboradores
- A UI roda no navegador
- O backend roda na nuvem da rev.ng
- Se você puder tornar público o arquivo do projeto, poderá usar gratuitamente a versão em nuvem da rev.ng com UI incluída
- Também é possível discutir a instalação de um serviço de nuvem privada on-premises com Kubernetes
Roadmap até a versão 1.0 e canais de contato
- O roadmap até a 1.0 está dividido em 4 níveis
- Tier 1: versão alfa, demos para conhecidos, concluído
- Tier 2: versão beta, acesso à versão em nuvem para assinantes da newsletter, iniciado agora
- Tier 3: beta aberta, prevista
- Tier 4: lançamento 1.0, previsto
- O andamento detalhado pode ser acompanhado na página de roadmap
- As novidades do projeto e canais de suporte são os seguintes
- X/Twitter: novidades de desenvolvimento e principais anúncios
- Discord: conversa em tempo real com a equipe de desenvolvimento
- Discourse: suporte a usuários e relatos de bugs
- GitHub: desenvolvimento open source e registro de issues
- Monthly newsletter: participação na beta fechada e novidades mensais
- E-mail: contato privado
1 comentários
Comentários no Hacker News
O modelo de preços parece ser que o framework rev.ng é totalmente open source, e no CLI dá para decompilar qualquer coisa
A UI será oferecida gratuitamente na nuvem para projetos públicos, com assinatura na nuvem para projetos privados, e como app totalmente independente e offline mediante pagamento
Em comparação, o Hopper custa US$ 100 com 1 ano de atualizações incluídas https://www.hopperapp.com/index.html, o Ghidra e o Radare2 são livres e open source, então são totalmente gratuitos, e o IDA Pro é muito caro
Pelo que usei, é bem parecido com o IDA, mas mais amigável ao usuário e com muitos recursos bem projetados que ajudam na produtividade
Não usei o Hopper, mas minha experiência com Ghidra e Radare2 não foi muito boa, e o código C gerado também não era muito legível. Dito isso, usei ambos há alguns anos
O Binja custa US$ 300, US$ 1500 para uso comercial, e também tem desconto para estudantes: https://binary.ninja/features
Ainda assim, sempre faltam bons decompiladores para C, então toda nova tentativa é bem-vinda
Só fico curioso sobre como isso é imposto sem tornar o app dependente de acesso à internet
Olhando a página da equipe https://rev.ng/about e as contribuições no código https://github.com/revng/revng/graphs/contributors, parece um pouco incomum que o CEO (aleclearmind) tenha muito mais commits do que o CTO (pfez)
Outros CEOs costumam dizer que quase não têm tempo para programar, e CTOs também geralmente acabam mais na gestão e menos no código em si
Ainda assim, se esse modelo funciona bem, imagino que deva ser bem divertido para a equipe. Edit: eu não tinha verificado a linha do tempo
A ideia é eventualmente unir os dois repositórios
E eu programo todos os dias, mas por algum motivo o GitHub não está associando corretamente meu usuário
Na prática, também é divertido
Na verdade, eu gostei de ver isso, e achei interessante justamente por ser diferente do que costumo ver em outros lugares
Será que recebeu downvote por não ser interessante nem incomum?
Parece uma empresa muito legal, inspirada por um dos melhores livros de teoria de linguagens de programação que existem: https://link.springer.com/book/10.1007/978-3-662-03811-6
“Ele também conheceu Pietro, que se tornaria seu cúmplice. De forma até romântica, ele o conheceu graças ao livro que viria a ser a base da empresa.”
https://rev.ng/about
Aí encontrei esse livro, denso mas aparentemente claro, e perguntei ao meu orientador se poderia comprá-lo, e ele disse: “primeiro veja na biblioteca da universidade”
Havia um exemplar na biblioteca, mas já estava emprestado, e como eu fazia parte do único grupo que pesquisava compiladores, pensei: “quem, fora do nosso grupo, ousaria mexer com compiladores?”
Fui à biblioteca e perguntei quem tinha pegado o livro, mas disseram que não podiam informar por privacidade; então perguntei só a terceira letra do sobrenome e a segunda do nome, e obtive Z e I
Encontrei a pessoa aqui: https://www.deib.polimi.it/ita/personale-lista-alfabetica
Com o tempo viramos amigos e abrimos uma empresa juntos
Foi preciso muito trabalho até o lançamento
Seria legal se ele atribuísse automaticamente nomes de variáveis e de membros de structs com base em como o código trata variáveis e membros de structs
Por exemplo, o ponteiro seguinte de uma lista encadeada deveria ser fácil de identificar como
nextParece possível baixar todo o GitHub, encontrar no código as variáveis com layout e interação mais parecidos e, se a confiança for alta o suficiente, usar esse nome
Por exemplo, ao detectar uma variável de indução, renomeá-la para
iMas hoje parece bastante claro que a forma certa de fazer isso é usar um LLM
Dito isso, neste estágio estamos mais focados em construir uma base robusta, e quando essa base estiver pronta, renomear ou adicionar comentários com modelos já existentes será relativamente fácil
O ponto central é que nós cuidamos da parte difícil da decompilação, que exige 100% de precisão, e podemos introduzir LLMs nas partes em que aproximações são aceitáveis, como nomes e comentários
De qualquer forma, é bem fácil escrever scripts para renomear, então é só ver a documentação: https://docs.rev.ng/user-manual/model-tutorial/
Artigo explicando o que o JSNice faz por dentro: https://files.sri.inf.ethz.ch/website/papers/jsnice15.pdf
Não funciona no meu arquivo ELF
Ao executar
./revng artifact --analyze --progress decompile-to-single-file ../maytag.ko, apareceOnly ELF executables and ELF dynamic libraries are supported, e o arquivo é identificado comoELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not strippedEle não suporta binários do FreeBSD?
Edit: eu deixei passar que módulos de kernel não são suportados, então parece que não é por ser FreeBSD, mas porque não é um executável comum
Não parece que seria tão difícil carregar isso
Espero que deem bastante atenção ao fluxo de trabalho colaborativo
Nunca usei algo como o IDA Teams, mas se for possível ter uma experiência de engenharia reversa sem atrito, como no Google Docs, seria incrível
Antigamente usávamos o QtCreator como base da UI, o que foi uma escolha horrível
Depois mudamos para o VSCode, que por acaso também roda no navegador
Então misturamos um pouco de Kubernetes e criamos um descompilador em nuvem com exatamente a mesma experiência de uso da versão totalmente standalone
A parte colaborativa ainda precisa de mais QA, mas basicamente funciona
É uma arquitetura bem simples: vários clientes para um único daemon
Acho que a inspiração veio de uma vez em que “colaboramos” num CTF com várias janelas do IDA e vários cursores sobre a sessão X do servidor. Era uma abordagem muito amaldiçoada, mas funcionava
Há planos para oferecer suporte a inferência de tipos?
No momento, parece que todas as variáveis aparecem como
generic64_t; seria ótimo detectar tipos automaticamente como o Ghidra faz, embora ele também erre às vezesItem do roadmap: https://rev.ng/roadmap#feature-798
Documento de design: https://pad.rev.ng/s/eDHi2PUoP#
Parece interessante
Quero experimentar a versão totalmente standalone
Já há alguma ideia de preço? Seria bom se até usuários hobby conseguissem pagar
É sempre bom ver mais ferramentas de hacking de binários
Como eu talvez quisesse testar pessoalmente, deixo algumas sugestões excessivamente minuciosas sobre o formato de empacotamento escolhido
source ./environmenté um mau sinal. Baixei o tar e ele de fato configurava várias variáveis de ambiente, incluindoPATH; felizmente não eraLD_LIBRARY_PATHA maioria usa o prefixo
HARD_, que provavelmente é único, masREVNGparece mais claro, e conflitar com variáveis de ambiente já existentes é ruimTambém define
AWS_EC2_METADATA_DISABLED="true"; eu não uso AWS, então não quebra nada para mim, mas no geral parece suspeitoRPATH_PLACEHOLDER,HARD_FLAGS_CXX_CLANG, umPATHlongo, strings como mingw32/gentoo/mips etc. parecem frágeisQuando as instruções de execução dizem “agora altere as variáveis de ambiente”, normalmente eu desisto; isso tem forte correlação com programas que não funcionam direito fora de sistemas Ubuntu
Vincular o fluxo de controle da aplicação ao ambiente de execução cria mais modos de falha do que parece à primeira vista, e é muito parecido com variáveis globais
O Clang pode incorporar valores padrão na build, como
-DCLANG_DEFAULT_CXX_STDLIB=libc++, eDEFAULT_SYSROOTtambém é útilMesmo usando
rpath, se o usuário executar comLD_LIBRARY_PATHdefinido, oDT_RUNPATHdo binário pode ser sobrescritoHoje em dia
-Wl,rpathna prática significa não rpath, mas orunpath, menos útil, e provavelmente a invocação desejada é-Wl,rpath -Wl,--disable-new-dtags, para que o loader ignoreLD_LIBRARY_PATHao procurar bibliotecasCombinar flags de build do Clang, linkagem estática e incorporação de binários dentro do binário provavelmente permitiria eliminar completamente a manipulação de variáveis de ambiente
O fato de o binário
clang-16ser ligado dinamicamente e procurar em tempo de execução coisas comolibLLVMAArch64CodeGen.so.16também aumenta os modos de falhaCom
LLVM_BUILD_STATIC=ON, dá para reduzir o problema de pegar a biblioteca errada em ambientes com toolchain de módulos HPC ativadoAs ferramentas estão ligadas a
libc++.so,libc++abi.soetc.; talvez valha considerar libc++ estática e, no mínimo, ligarlibc++abielibunwindestaticamente dentro da libc++Minha paciência para distribuir programas com linkagem dinâmica no Linux se esgotou completamente
Se o
source ourhackdo README ou variáveis de ambiente deixadas por um sistema de módulos trocarem as bibliotecas de runtime da minha aplicação, a experiência do usuário e o custo posterior com relatórios de bug ficam horríveisEm comparação, linkagem estática é realmente ótima
source environmentNa verdade, sugerimos isso apenas para fazer você usar o GCC que distribuímos para os binários de demonstração, e o modo de uso pretendido é o script
./revngNesse caso, a alteração de ambiente afeta apenas a invocação de
revngA documentação está aqui: https://docs.rev.ng/user-manual/working-environment/
Seria bom acrescentar um aviso sobre
source ./environmentPassamos muito tempo tentando evitar
LD_LIBRARY_PATHe montamos um conjunto totalmente autocontido de binários em que cada ELF referencia suas dependências por caminhos relativos.LD_LIBRARY_PATHé o malAs variáveis
HARD_são usadas só nos wrappers do compilador e eu diria que a chance real de conflito é quase zeroA discussão original sobre
AWS_EC2_METADATA_DISABLED="true"está em https://github.com/revng/revng/pull/309#discussion_r12805759...Poderíamos evitar isso aplicando um patch no AWS SDK, mas de qualquer forma isso só afeta quando o rev.ng roda na nuvem
RPATH_PLACEHOLDEReHARD_FLAGS_CXX_CLANGsão usados quando o revng faz o link de binários traduzidos e não importam se você não se interessa por tradução binária de ponta a pontaNós intencionalmente queremos
DT_RUNPATH.DT_RPATHestá sendo descontinuado, e pode haver casos de uso em que seja necessário substituir nossas bibliotecas viaLD_LIBRARY_PATHA crítica à “manipulação do ambiente” eu consideraria válida apenas no caso de variáveis de ambiente não privadas
RPATH_PLACEHOLDER,HARD_*,REVNG_*são variáveis privadas e todas existem para fins de tradução bináriaPodemos empurrá-las para dentro de wrappers de compilador com escopo menor, mas como distribuímos Python junto, não dá para eliminar totalmente o ambiente
Só incorporar algumas flags no Clang não basta. Essas flags também afetam o linker, e há partes da funcionalidade dos wrappers que não dá para simplesmente embutir
Ainda assim, dá para movê-las para um lugar mais privado
Você parece desconfiar de linkagem dinâmica, mas investimos esforço nisso e agora funciona bem, encontrando sempre o local correto
Não codificamos caminhos absolutos, nem existe uma etapa de instalação que “aplique patch” nos binários. O diretório descompactado pode ser movido para qualquer lugar
A solução que usamos não depende de
LD_LIBRARY_PATH; todos os binários referenciam uns aos outros de forma robusta via$ORIGINSe você executar
./root/bin/python ./root/bin/revng artifact --help, funcionaDe novo,
source environmenté quase só para demonstração; no uso real, basta executar./revnge o ambiente permanece intactoTambém distribuímos Python junto, mas você não é obrigado a usá-lo. Pode usar
./revngou interagir pela rede no modo daemonA abordagem é analisar e modificar o arquivo de projeto YAML com a ferramenta de script que você quiser e depois chamar
./revng artifact, ou interagir com o daemon: https://docs.rev.ng/user-manual/model-tutorial/No fim das contas, nós usamos uma versão moderna de Python, e o usuário pode usar a linguagem que quiser
Depois disso, planejam fornecer no PyPI um wrapper auxiliar compatível com várias versões do Python
Resumindo, em vez de fazer
source ./environment, basta usar./revngFico feliz que haja gente que se preocupa com esse tipo de detalhe
Na próxima grande iteração, talvez também seja possível simplificar muita coisa ao introduzir nix + mount namespace, permitindo usar
/nix/storesem privilégios de rootTalvez seja melhor discutir esse tipo de assunto no servidor do Discord, em vez de aqui
QEMU TCG: você se arrepende de ter delegado o lifting a ele, ou funcionou bem?
Primeiro, não fizemos rebase do fork do QEMU por alguns anos, e isso acabou nos colocando numa situação ruim
Mesmo assim, hoje mesmo um membro da equipe conseguiu fazer o lifting com o QEMU mais recente, e também conseguimos fazer o lifting do código Qualcomm Hexagon para o qual ajudamos a adicionar suporte ao QEMU
No fim, vamos acabar sendo o primeiro descompilador de Hexagon realmente decente
Segundo, por termos focado demais no QEMU, o frontend ficou fortemente acoplado ao QEMU
Agora vai exigir algum esforço dar suporte a frontends adicionais que não sejam baseados em QEMU, mas não é impossível
A ideia é fazer com que, ao adicionar suporte a uma nova arquitetura, o usuário só precise definir em C a estrutura de estado da CPU e algumas funções que operem sobre ela
Não será necessário aprender a representação interna
Em resumo, o QEMU foi uma excelente escolha e funcionou tão bem que acabamos deixando essa parte do codebase intocada por muito tempo, o que gerou dívida técnica, mas agora estamos resolvendo isso