Questão:
Código de byte Java equivalente a assinaturas de função IDA
Dr Deo
2016-04-15 14:30:38 UTC
view on stackexchange narkive permalink

Lembro-me de que o IDA (Interactive Disassembler) tem um recurso realmente interessante de assinaturas de função em que você não precisa fazer engenharia reversa do código encontrado nas bibliotecas padrão.
Existe um recurso semelhante para o código de bytes Java, especialmente para código ofuscado ?

O recurso IDA está usando assinaturas binárias reais. Essa abordagem não funcionará para código ofuscado, pois não haverá uma assinatura binária.
[JEB Decompiler] (https://www.pnfsoftware.com/blog/jeb-1-3-how-to-sign-and-match-third-party-library-code/) possui recurso de assinatura para bytecode java.
@ExtremeCoders, mas não acho que isso funcionará para funções ofuscadas.
@LucaD'Amico Ofcourse. As assinaturas não funcionam para funções ofuscadas.
Dois respostas:
Guntram Blohm supports Monica
2016-04-18 23:19:47 UTC
view on stackexchange narkive permalink

Não há recurso semelhante para o código de bytes Java.

Quando você compila um programa C e o vincula estaticamente a uma biblioteca padrão, o código da biblioteca estará presente, mais ou menos sem modificações, dentro do binário (exceto para endereços que serão alterados), mas não haverá qualquer indício de que uma função específica tinha um nome específico antes de ser compilada (a menos que a depuração seja habilitada durante a compilação / vinculação). Mas, qualquer função tem um padrão mais ou menos fixo de bytes e, reconhecendo esses bytes, o IDA pode atribuir o nome original à função.

No bytecode Java, não há necessidade de fazer isso. Nomes de funções, nomes de variáveis ​​e informações semelhantes estão presentes no bytecode compilado de qualquer maneira. A "biblioteca padrão", rt.jar , também não está embutida no bytecode, então se uma classe usa um ArrayList , a classe terá uma referência a java.util.ArrayList mesmo após o processo de ofuscação. Portanto, nada a fazer aqui para um analisador de assinatura.

Se o aplicativo optar por ofuscar a biblioteca padrão também, ele precisará incluir essa biblioteca ofuscada em seus próprios arquivos jar. Isso provavelmente levantará alguns problemas de licenciamento, mas, além disso, como o obfuscator renomeará métodos e campos, o código de byte dessa biblioteca ofuscada será muito diferente do código de byte original para ser reconhecido por um recurso como o FLIRT do IDA. Além disso, você não pode simplesmente renomear o método no IDA, porque você também teria que modificar todas as referências.

No entanto, há pelo menos um projeto de código aberto que tem um problema semelhante ao seu, e eles parecem ter resolvido muito bem. Minecraft é um jogo popular que inclui um servidor escrito em Java (e ofuscado); o projeto Spigot descompila este servidor, muda algumas coisas, adiciona uma API e distribui o resultado. Especificamente, para evitar problemas de licenciamento, eles distribuem um sistema de compilação que baixa, descompila, corrige e recompila o servidor Minecraft na máquina do usuário.

Eles usam o descompilador fernflower, que tem a opção de renomear símbolos durante a descompilação e inclui um extenso mapa de nomes de símbolos ofuscados para legíveis. Exemplo:

  AttributeInstance a () LIAttribute; getAttributeAttributeInstance a (D) V setValueAttributeInstance e () D getValueAttributeMapServer b () Ljava / util / Set; getAttributesAxisAlignedBB b (DDD) LAxisAlignedBB; grow  

O código-fonte, que é gerado usando esses mapas, é obviamente muito mais legível do que o original. E, pelo menos para o projeto spigot, recompilar esta fonte (depois de adicionar alguns patches para criar uma API) produz um servidor Minecraft funcional.

Então, talvez, esta possa ser uma maneira de você continuar - use fernflower para descompilar suas classes, carregue-as em um editor para encontrar algum código útil e atribua nomes de classe legíveis, escreva um arquivo de mapeamento e repita isso algumas vezes. Então, quando você quiser fazer alguma análise dinâmica, recompile o código Java descompilado e carregue-o no IDA.

Claro, esta abordagem ainda tem alguns problemas:

  • você ainda terá que identificar cada função manualmente - mas como eu disse, você provavelmente não encontrará nenhuma função de biblioteca padrão em seu código. E, não há bibliotecas de assinatura existentes para qualquer método que você use, então provavelmente não há maneira de contornar isso.
  • o código descompilado / recompilado pode não funcionar, por causa de bugs / falhas no próprio descompilador Java
  • o código descompilado / recompilado pode não funcionar por causa do ofuscador; por exemplo, o obfuscator pode substituir todas as constantes de string por algo como Obfuscator :: decode ("some_crypted_stuff") , onde a função decode usa o nome da classe de chamada como seu chave de descriptografia, o que significa que a descriptografia falha quando a classe é renomeada
  • o obfuscator pode trazer seu próprio carregador de classe, que altera o nome da classe antes de carregá-la; por exemplo, ele pode saber transformar uma classe com.obfuscate.SOME_BASE_64_STRING em uma string base64 decodificada, então com.obfuscate.amF2YS51dGlsLkFycmF5TGlzdAo.something () chamaria java.util.ArrayList.something () . Isso quebra a conexão visível entre o chamador e o receptor (mas o mapeamento de nome pode resolver esse problema muito bem e você pode automatizar muito)

Mesmo se você não puder obter um descompilado, recompilável, versão do seu binário, você provavelmente pode escrever algum código que funcione no código-fonte descompilado para identificar funções por seu comportamento, usando alguma heurística. Em seguida, faça com que seu código escreva uma tabela de mapeamento e escreva um plugin Python para importar essa tabela de mapeamento para o seu código como comentários.

É questionável se essas abordagens superam a engenharia reversa manual dentro do IDA, mas como o IDA não tem esse recurso e como não há bibliotecas de assinatura genéricas (e elas não funcionariam de qualquer maneira, veja acima), é o melhor que tenho a oferecer.

Editar 2016-04-17

Acontece que tenho um pequeno projeto onde poderia usar algum mapeamento de desofuscação sozinho e verifiquei no processo de desofuscação da etapa de descompilação do Minecraft um pouco mais.

Acontece que eles nem usam flores de samambaia r recurso de emapping. Em vez disso, eles têm seu próprio conjunto de ferramentas. Esses são lamentavelmente subdocumentados, mas parece haver um Repositório GitHub.

O primeiro, SpecialSource.jar, compara um jar ofuscado com uma versão não ofuscada e gera uma tabela de mapeamento. Isso parece permitir construir novas tabelas rapidamente quando uma nova versão do original ofuscado for lançada. No entanto, não há documentação sobre o que exatamente está sendo comparado.

O segundo, SpecialSource-2.jar, remapeia referências e nomes de classes e métodos diretamente no arquivo jar , sem uma etapa de descompilação / compilação, para evitar todos os problemas que vêm com isso. Assim, depois de ter um arquivo de mapeamento, você pode aplicá-lo ao jar para obter um jar de saída, que você pode alimentar no IDA ou em um descompilador de sua escolha. O uso é

  java - jar /path/to/SpecialSource-2.jar map -m mapping.csrg \ -i obfuscated.jar -o readable.jar  

com o arquivo de mapeamentos parecido com este

  # Isso renomeia uma classe, dado o nome ofuscado e onecom / example / ab / a legível MyNiceClassName # Isso renomeia um método, dado a classe, método, assinatura e nome legível.MyNiceClassName a (D) I doubleToInt  
douggard
2016-04-19 23:01:19 UTC
view on stackexchange narkive permalink

Se o gráfico de fluxo de controle não foi ofuscado, você pode usá-los para combinar os métodos. O maior obstáculo para isso é construir o banco de dados de assinaturas da biblioteca.

Os gráficos de fluxo de controle são a estrutura que os blocos básicos fazem quando vistos como um gráfico direcionado. [1] Estes representam os caminhos possíveis de execução em um método. Eles são relativamente fáceis de analisar e recuperar de um aplicativo compilado. A maior parte da ofuscação Android e Java concentra-se nos nomes dos métodos e não no fluxo de controle. Além disso, o bytecode Java / Dalvik pode mudar entre as compilações se os métodos forem modificados ou movidos. É aí que a comparação da estrutura se torna útil, a menos que mudanças sérias sejam feitas, o fluxo de controle provavelmente permanecerá o mesmo.

Fiz alguns trabalhos com correspondência de gráfico de fluxo de controle em aplicativos Android. [2] [3] A verdadeira força do projeto acabou sendo o clustering de tipos de malware. Ele corresponderia a métodos de estrutura semelhante e você poderia ver que certos aplicativos compartilhavam métodos com outros aplicativos e como as tensões evoluíram.

Se você está procurando criar uma assinatura de função Java, uma combinação entre estrutural e a correspondência de base de bytes seria muito poderosa.

  1. https://en.wikipedia.org/wiki/Control_flow_graph
  2. https: //github.com/douggard/CFGScanDroid
  3. http://www.irongeek.com/i.php?page=videos/derbycon4/t420-control-flow-graph -based-virus-scanning-douglas-goddard
Pelos 3 minutos que passei olhando o repo, isso parece muito interessante, especialmente com o propósito de "atualizar" um mapa ofuscado para legível para uma versão mais recente do binário ofuscado. Seu projeto funcionará com arquivos .jar também ou apenas com arquivos dex?
Apenas arquivos dex, muito do código poderia ser reutilizado, porém, seria apenas uma questão de obter o bytecode dos arquivos de classe e analisar os métodos. Tenho certeza de que existe uma biblioteca Java feita para isso. A extração CFG pode ser um pouco diferente indo de Dalvik para Java, mas provavelmente nada muito grande.


Estas perguntas e respostas foram traduzidas automaticamente do idioma inglês.O conteúdo original está disponível em stackexchange, que agradecemos pela licença cc by-sa 3.0 sob a qual é distribuído.
Loading...