3 pontos por GN⁺ 2024-03-31 | 1 comentários | Compartilhar no WhatsApp
  • 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

 
GN⁺ 2024-03-31
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

    • O Binary Ninja também é uma boa opção
      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
    • A decompilação costuma ser a parte menos importante e menos confiável no IDA/Ghidra, então comparar os dois só por isso é injusto
      Ainda assim, sempre faltam bons decompiladores para C, então toda nova tentativa é bem-vinda
    • Eu gosto muito do modelo de licença de pagamento único com período fixo de atualizações
      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

    • O CTO trabalha principalmente no backend de decompilação revng-c que acabou de ser lançado: https://github.com/revng/revng-c/commits/develop/
      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
    • O CTO tem mais commits recentes, e os commits do aleclearmind caem para 0 depois de 2020, então parece que ele também passou a ter mais dificuldade para arrumar tempo para programar
    • Eu não estava tentando criticar de forma alguma, então fiquei um pouco curioso sobre por que recebi downvotes
      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 história completa por trás desse livro é a seguinte. Eu tinha começado a estudar compiladores, mas a teoria era difícil demais, e até os livros famosos não estavam funcionando para mim, então eu estava bem desanimado
      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 next
    Parece 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

    • Antigamente eu tentava fazer esse tipo de coisa manualmente
      Por exemplo, ao detectar uma variável de indução, renomeá-la para i
      Mas 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/
    • Isso parece muito legal, meio na linha do http://jsnice.org/
      Artigo explicando o que o JSNice faz por dentro: https://files.sri.inf.ethz.ch/website/papers/jsnice15.pdf
    • Parece parecido com o sidekick do Binary Ninja
    • Seria tipo um GitHub Copilot para reverse engineering?
  • Não funciona no meu arquivo ELF
    Ao executar ./revng artifact --analyze --progress decompile-to-single-file ../maytag.ko, aparece Only ELF executables and ELF dynamic libraries are supported, e o arquivo é identificado como ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped
    Ele 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

    • Você pode abrir uma issue no GitHub e anexar o binário?
      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

    • Esse é o nosso objetivo
      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 vezes

  • 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, incluindo PATH; felizmente não era LD_LIBRARY_PATH
    A maioria usa o prefixo HARD_, que provavelmente é único, mas REVNG parece mais claro, e conflitar com variáveis de ambiente já existentes é ruim
    Também define AWS_EC2_METADATA_DISABLED="true"; eu não uso AWS, então não quebra nada para mim, mas no geral parece suspeito
    RPATH_PLACEHOLDER, HARD_FLAGS_CXX_CLANG, um PATH longo, strings como mingw32/gentoo/mips etc. parecem frágeis
    Quando 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++, e DEFAULT_SYSROOT também é útil
    Mesmo usando rpath, se o usuário executar com LD_LIBRARY_PATH definido, o DT_RUNPATH do binário pode ser sobrescrito
    Hoje em dia -Wl,rpath na prática significa não rpath, mas o runpath, menos útil, e provavelmente a invocação desejada é -Wl,rpath -Wl,--disable-new-dtags, para que o loader ignore LD_LIBRARY_PATH ao procurar bibliotecas
    Combinar 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-16 ser ligado dinamicamente e procurar em tempo de execução coisas como libLLVMAArch64CodeGen.so.16 também aumenta os modos de falha
    Com LLVM_BUILD_STATIC=ON, dá para reduzir o problema de pegar a biblioteca errada em ambientes com toolchain de módulos HPC ativado
    As ferramentas estão ligadas a libc++.so, libc++abi.so etc.; talvez valha considerar libc++ estática e, no mínimo, ligar libc++abi e libunwind estaticamente dentro da libc++
    Minha paciência para distribuir programas com linkagem dinâmica no Linux se esgotou completamente
    Se o source ourhack do 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íveis
    Em comparação, linkagem estática é realmente ótima

    • A maior parte das preocupações sobre mexer no ambiente só faz sentido assumindo que a pessoa realmente execute source environment
      Na 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 ./revng
      Nesse caso, a alteração de ambiente afeta apenas a invocação de revng
      A documentação está aqui: https://docs.rev.ng/user-manual/working-environment/
      Seria bom acrescentar um aviso sobre source ./environment
      Passamos muito tempo tentando evitar LD_LIBRARY_PATH e montamos um conjunto totalmente autocontido de binários em que cada ELF referencia suas dependências por caminhos relativos. LD_LIBRARY_PATH é o mal
      As variáveis HARD_ são usadas só nos wrappers do compilador e eu diria que a chance real de conflito é quase zero
      A 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_PLACEHOLDER e HARD_FLAGS_CXX_CLANG sã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 ponta
      Nós intencionalmente queremos DT_RUNPATH. DT_RPATH está sendo descontinuado, e pode haver casos de uso em que seja necessário substituir nossas bibliotecas via LD_LIBRARY_PATH
      A 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ária
      Podemos 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 $ORIGIN
      Se você executar ./root/bin/python ./root/bin/revng artifact --help, funciona
      De novo, source environment é quase só para demonstração; no uso real, basta executar ./revng e o ambiente permanece intacto
      Também distribuímos Python junto, mas você não é obrigado a usá-lo. Pode usar ./revng ou interagir pela rede no modo daemon
      A 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 ./revng
Fico 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/store sem privilégios de root
Talvez seja melhor discutir esse tipo de assunto no servidor do Discord, em vez de aqui

  • Parabéns
    QEMU TCG: você se arrepende de ter delegado o lifting a ele, ou funcionou bem?
    • Funcionou muito bem. Tenho dois arrependimentos
      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