Descompilador

Um descompilador é um programa de computador que traduz um arquivo executável em código -fonte de alto nível . Ele faz, portanto, o oposto de um compilador típico , que traduz uma linguagem de alto nível para uma linguagem de baixo nível. Enquanto os desmontadores traduzem um executável para linguagem assembly , os descompiladores vão um passo além e traduzem o código para uma linguagem de nível superior como C ou Java , exigindo técnicas mais sofisticadas. Os descompiladores geralmente são incapazes de reconstruir perfeitamente o código-fonte original e, portanto, frequentemente produzem código ofuscado . No entanto, continuam a ser uma ferramenta importante na engenharia reversa de software de computador .

Introdução

O termo descompilador é mais comumente aplicado a um programa que traduz programas executáveis ​​(a saída de um compilador ) em código-fonte em uma linguagem de nível (relativamente) de alto nível que, quando compilada, produzirá um executável cujo comportamento é o mesmo do executável original. programa. Em comparação, um desmontador traduz um programa executável em linguagem assembly (e um montador pode ser usado para montá-lo novamente em um programa executável).

Descompilação é o ato de usar um descompilador, embora o termo também possa se referir à saída de um descompilador. Pode ser usado para a recuperação de código-fonte perdido, sendo também útil em alguns casos para segurança de computadores , interoperabilidade e correção de erros . [1] O sucesso da descompilação depende da quantidade de informações presentes no código que está sendo descompilado e da sofisticação da análise realizada nele. Os formatos de bytecode usados ​​por muitas máquinas virtuais (como a Java Virtual Machine ou o .NET Framework Common Language Runtime ) geralmente incluem metadados extensos e recursos de alto nível que tornam a descompilação bastante viável. A aplicação de dados de depuração , ou seja, símbolos de depuração, pode permitir reproduzir os nomes originais de variáveis ​​e estruturas e até mesmo os números de linha. A linguagem de máquina sem esses metadados ou dados de depuração é muito mais difícil de descompilar. [2]

Alguns compiladores e ferramentas de pós-compilação produzem código ofuscado (ou seja, tentam produzir uma saída que é muito difícil de descompilar ou que é descompilada para uma saída confusa). Isso é feito para dificultar a engenharia reversa do executável.

Embora os descompiladores sejam normalmente usados ​​para (re)criar código-fonte a partir de executáveis ​​binários, também existem descompiladores para transformar arquivos de dados binários específicos em fontes legíveis e editáveis. [3] [4]

Projeto

Os descompiladores podem ser considerados compostos por uma série de fases, cada uma das quais contribui com aspectos específicos do processo geral de descompilação.

Carregador

A primeira fase de descompilação carrega e analisa o código de máquina de entrada ou o formato de arquivo binário do programa de linguagem intermediária . Deve ser capaz de descobrir fatos básicos sobre o programa de entrada, como a arquitetura (Pentium, PowerPC, etc.) e o ponto de entrada. Em muitos casos, deve ser possível encontrar o equivalente à função de um programa C , que é o início do código escrito pelo usuário . Isso exclui o código de inicialização do tempo de execução, que não deve ser descompilado, se possível. Se disponíveis, as tabelas de símbolos e os dados de depuração também serão carregados. O front-end pode ser capaz de identificar as bibliotecas utilizadas mesmo que estejam vinculadas ao código, o que fornecerá interfaces de biblioteca. Se puder determinar o compilador ou compiladores usados, poderá fornecer informações úteis na identificação de idiomas de código. [5]main

Desmontagem

A próxima fase lógica é a desmontagem das instruções de código de máquina em uma representação intermediária independente de máquina (IR). Por exemplo, a instrução da máquina Pentium

mov eax , [ ebx + 0x04 ]     

pode ser traduzido para o IR

eax : = m [ ebx + 4 ] ;   

Expressões idiomáticas

Sequências idiomáticas de código de máquina são sequências de código cuja semântica combinada não é imediatamente aparente na semântica individual das instruções. Seja como parte da fase de desmontagem, ou como parte de análises posteriores, essas sequências idiomáticas precisam ser traduzidas em IR equivalente conhecido. Por exemplo, o código assembly x86 :

    cdq eax ; edx é definido como extensão de sinal≠edi,edi +(tex)push xor eax , edx sub eax , edx                 
         
         

poderia ser traduzido para

eax := abs(eax);

Algumas sequências idiomáticas são independentes da máquina; alguns envolvem apenas uma instrução. Por exemplo, limpa o registro (coloca-o em zero). Isto pode ser implementado com uma regra de simplificação independente da máquina, como . xor eax, eaxeaxa = 0

Em geral, é melhor adiar a detecção de sequências idiomáticas, se possível, para estágios posteriores que sejam menos afetados pela ordenação das instruções. Por exemplo, a fase de agendamento de instruções de um compilador pode inserir outras instruções em uma sequência idiomática ou alterar a ordem das instruções na sequência. Um processo de correspondência de padrões na fase de desmontagem provavelmente não reconheceria o padrão alterado. As fases posteriores agrupam expressões de instrução em expressões mais complexas e as modificam em uma forma canônica (padronizada), tornando mais provável que mesmo o idioma alterado corresponda a um padrão de nível superior posteriormente na descompilação.

É particularmente importante reconhecer os idiomas do compilador para chamadas de sub-rotinas , tratamento de exceções e instruções switch . Algumas linguagens também possuem amplo suporte para strings ou inteiros longos .

Análise do programa

Várias análises de programas podem ser aplicadas ao RI. Em particular, a propagação de expressões combina a semântica de diversas instruções em expressões mais complexas. Por exemplo,

    mov eax ,[ ebx + 0x04 ] adicionar eax ,[ ebx + 0x08 ] sub [ ebx + 0x0C ], eax   
       
       

poderia resultar no seguinte IR após a propagação da expressão:

m[ebx+12] := m[ebx+12] - (m[ebx+4] + m[ebx+8]);

A expressão resultante é mais parecida com uma linguagem de alto nível e também eliminou o uso do registro de máquina eax. Análises posteriores poderão eliminar o ebxregistro.

Análise de fluxo de dados

Os locais onde o conteúdo do registro é definido e utilizado devem ser rastreados por meio de análise de fluxo de dados . A mesma análise pode ser aplicada a locais usados ​​para dados temporários e locais. Um nome diferente pode então ser formado para cada conjunto conectado de definições e usos de valores. É possível que a mesma localização de variável local tenha sido usada para mais de uma variável em diferentes partes do programa original. Pior ainda, é possível que a análise do fluxo de dados identifique um caminho pelo qual um valor pode fluir entre dois desses usos, mesmo que isso nunca aconteça ou tenha importância na realidade. Em casos graves, isso pode levar à necessidade de definir um local como uma união de tipos. O descompilador pode permitir que o usuário quebre explicitamente essas dependências não naturais, o que levará a um código mais claro. É claro que isso significa que uma variável é potencialmente usada sem ser inicializada e, portanto, indica um problema no programa original. [ carece de fontes ]

Análise de tipo

Um bom descompilador de código de máquina realizará análise de tipo. Aqui, a forma como os registradores ou locais de memória são usados ​​resulta em restrições sobre o tipo possível de local. Por exemplo, uma andinstrução implica que o operando é um número inteiro; os programas não usam tal operação em valores de ponto flutuante (exceto em código de biblioteca especial) ou em ponteiros . Uma addinstrução resulta em três restrições, uma vez que os operandos podem ser ambos inteiros, ou um inteiro e um ponteiro (com resultados inteiros e de ponteiro respectivamente; a terceira restrição vem da ordenação dos dois operandos quando os tipos são diferentes). [6]

Podem ser reconhecidas várias expressões de alto nível que desencadeiam o reconhecimento de estruturas ou matrizes. No entanto, é difícil distinguir muitas das possibilidades, devido à liberdade que o código de máquina ou mesmo algumas linguagens de alto nível como C permitem com conversões e aritmética de ponteiros.

O exemplo da seção anterior poderia resultar no seguinte código de alto nível:

estrutura T1 * ebx ; estrutura T1 { int v0004 ; int v0008 ; int v000C ; }; ebx -> v000C -= ebx -> v0004 + ebx -> v0008 ;  
      
         
         
         
    
    

Estruturação

A penúltima fase de descompilação envolve a estruturação do IR em construções de nível superior, como whileloops e if/then/elseinstruções condicionais. Por exemplo, o código de máquina

    xor eax , eax l0002: ou ebx , ebx jge l0003 adicionar eax ,[ ebx ] mov ebx ,[ ebx + 0x4 ] jmp l0002 l0003: mov [ 0x10040000 ], eax  

       
     
     
     
     

     

poderia ser traduzido em:

eax = 0 ; enquanto ( ebx < 0 ) { eax += ebx -> v0000 ; ebx = ebx -> v0004 ; } v10040000 = eax ;  
    
      
      

  

O código não estruturado é mais difícil de traduzir em código estruturado do que o código já estruturado. As soluções incluem replicar algum código ou adicionar variáveis ​​booleanas. [7]

Geração de código

A fase final é a geração do código de alto nível no backend do descompilador. Assim como um compilador pode ter vários back-ends para gerar código de máquina para diferentes arquiteturas, um descompilador pode ter vários back-ends para gerar código de alto nível em diferentes linguagens de alto nível.

Pouco antes da geração do código, pode ser desejável permitir uma edição interativa do IR, talvez usando alguma forma de interface gráfica do usuário . Isso permitiria ao usuário inserir comentários e nomes de variáveis ​​e funções não genéricos. No entanto, estes são quase tão facilmente inseridos em uma edição pós-descompilação. O usuário pode querer alterar aspectos estruturais, como converter um whileloop em forloop. Eles são menos facilmente modificados com um editor de texto simples, embora ferramentas de refatoração de código- fonte possam ajudar nesse processo. O usuário pode precisar inserir informações que não foram identificadas durante a fase de análise de tipo, por exemplo, modificando uma expressão de memória para uma matriz ou expressão de estrutura. Finalmente, IR incorreto pode precisar ser corrigido ou alterações feitas para tornar o código de saída mais legível.

Outras técnicas

Descompiladores usando redes neurais foram desenvolvidos. Tal descompilador pode ser treinado por aprendizado de máquina para melhorar sua precisão ao longo do tempo. [8]

Legalidade

A maioria dos programas de computador é protegida por leis de direitos autorais . Embora o âmbito preciso do que é coberto pelos direitos de autor difere de região para região, a lei dos direitos de autor geralmente fornece ao autor (o(s) programador(es) ou empregador) um conjunto de direitos exclusivos sobre o programa. [9] Estes direitos incluem o direito de fazer cópias, incluindo cópias feitas na RAM do computador (a menos que a criação de tal cópia seja essencial para a utilização do programa). [10] Como o processo de descompilação envolve a realização de múltiplas cópias, geralmente é proibido sem a autorização do detentor dos direitos autorais. No entanto, como a descompilação é muitas vezes uma etapa necessária para alcançar a interoperabilidade do software , as leis de direitos autorais tanto nos Estados Unidos quanto na Europa permitem a descompilação até certo ponto.

Nos Estados Unidos, a defesa do uso justo dos direitos autorais foi invocada com sucesso em casos de descompilação. Por exemplo, no caso Sega v. Accolade , o tribunal considerou que Accolade poderia legalmente realizar a descompilação para contornar o mecanismo de bloqueio de software usado pelos consoles de jogos da Sega. [11] Além disso, a Lei de Direitos Autorais do Milênio Digital (LEI PÚBLICA 105–304 [12] ) tem isenções adequadas para testes e avaliações de segurança em §1201(i) e engenharia reversa em §1201(f). [13]

Na Europa, a Diretiva de Software de 1991 prevê explicitamente o direito de descompilar para alcançar a interoperabilidade. Resultado de um acalorado debate entre, por um lado, protecionistas de software e, por outro, académicos e criadores de software independentes, o artigo 6.º permite a descompilação apenas se forem satisfeitas uma série de condições:

  • Primeiro, uma pessoa ou entidade deve ter uma licença para utilizar o programa a ser descompilado.
  • Em segundo lugar, a descompilação deve ser necessária para alcançar a interoperabilidade com o programa alvo ou com outros programas. As informações sobre interoperabilidade não devem, portanto, estar prontamente disponíveis, como por exemplo através de manuais ou documentação API . Esta é uma limitação importante. A necessidade deve ser comprovada pelo descompilador. O objetivo desta importante limitação é principalmente fornecer um incentivo para que os desenvolvedores documentem e divulguem informações de interoperabilidade de seus produtos. [14]
  • Terceiro, o processo de descompilação deve, se possível, limitar-se às partes do programa-alvo relevantes para a interoperabilidade. Dado que um dos objectivos da descompilação é obter uma compreensão da estrutura do programa, esta terceira limitação pode ser difícil de cumprir. Novamente, o ônus da prova recai sobre o descompilador.

Além disso, o artigo 6.º prescreve que as informações obtidas através da descompilação não podem ser utilizadas para outros fins e não podem ser fornecidas a terceiros.

Globalmente, o direito de descompilação previsto no artigo 6.º codifica o que se afirma ser uma prática comum na indústria de software. Sabe-se que poucos processos judiciais europeus surgiram do direito de descompilação. Isso pode ser interpretado como significando uma de três coisas:

  1. ) o direito de descompilação não é utilizado com frequência e o direito de descompilação pode, portanto, ter sido desnecessário,
  2. ) o direito de descompilação funciona bem e proporciona segurança jurídica suficiente para não dar origem a litígios jurídicos ou
  3. ) a descompilação ilegal passa praticamente despercebida.

Num relatório de 2000 sobre a implementação da Diretiva de Software pelos estados membros europeus, a Comissão Europeia pareceu apoiar a segunda interpretação. [15]

Veja também

Descompiladores Java

Outros descompiladores

Referências

  1. ^ Van Emmerik, Mike (29/04/2005). "Por que descompilação". Programa-transformação.org. Arquivado do original em 22/09/2010 . Recuperado em 15/09/2010 .
  2. ^ Miecznikowski, Jerônimo; Hendren, Laurie (2002). "Descompilando Bytecode Java: Problemas, Armadilhas e Armadilhas" . Em Horspool, R. Nigel (ed.). Construção de compilador: 11ª Conferência Internacional, anais / CC 2002 . Springer-Verlag . páginas 111–127. ISBN 3-540-43369-4.
  3. ^ Paul, Matthias R. (10/06/2001) [1995]. "Descrição do formato dos arquivos DOS, OS/2 e Windows NT .CPI e Linux .CP" (arquivo CPI.LST) (1.30 ed.). Arquivado do original em 20/04/2016 . Recuperado em 20/08/2016 .
  4. ^ Paulo, Matthias R. (13/05/2002). "[fd-dev]mkeyb". freedos-dev . Arquivado do original em 10/09/2018 . Recuperado em 10/09/2018 . […] Analisador, validador e descompilador de arquivos de página de código .CPI e .CP […] Visão geral dos parâmetros /Style: […] Fonte ASM inclui arquivos […] Arquivos de origem ASM independentes […] Arquivos de origem ASM modulares […]
  5. ^ Cifuentes, Cristina; Gough, K. John (julho de 1995). "Descompilação de Programas Binários". Software: Prática e Experiência . 25 (7): 811–829. CiteSeerX 10.1.1.14.8073 . doi :10.1002/spe.4380250706. S2CID8229401  . 
  6. ^ Mycroft, Alan (1999). "Descompilação baseada em tipo". Em Swierstra, S. Doaitse (ed.). Linguagens e sistemas de programação: 8º Simpósio Europeu sobre Linguagens e Sistemas de Programação . Springer-Verlag . páginas 208–223. ISBN 3-540-65699-5.
  7. ^ Cifuentes, Cristina (1994). "Capítulo 6". Técnicas de compilação reversa (PDF) (tese de doutorado). Universidade de Tecnologia de Queensland . Arquivado (PDF) do original em 22/11/2016 . Recuperado em 21/12/2019 .)
  8. ^ Tian, ​​Yuandong; Fu, Cheng (2021-01-27). "Apresentando N-Bref: uma estrutura de descompilador baseada em neural" . Recuperado em 30/12/2022 .
  9. ^ Rowland, Diane (2005). Lei de tecnologia da informação (3 ed.). Cavendish. ISBN 1-85941-756-6.
  10. ^ "Escritório de Direitos Autorais dos EUA - Lei de Direitos Autorais: Capítulo 1" . Arquivado do original em 25/12/2017 . Recuperado em 10/04/2014 .
  11. ^ “A Legalidade da Descompilação” . Programa-transformação.org. 03/12/2004. Arquivado do original em 22/09/2010 . Recuperado em 15/09/2010 .
  12. ^ "Lei de Direitos Autorais do Milênio Digital" (PDF) . Congresso dos EUA . 28/10/1998. Arquivado (PDF) do original em 10/12/2013 . Recuperado em 15/11/2013 .
  13. ^ “Cadastro Federal :: Solicitar Acesso” . Arquivado do original em 25/01/2022 . Recuperado em 31/01/2021 .
  14. ^ Czarnota, Brígida; Hart, Robert J. (1991). Proteção legal de programas de computador na Europa: um guia para a diretiva CE . Londres: Butterworths Tolley . ISBN 0-40600542-7.
  15. ^ "Relatório da Comissão ao Conselho, ao Parlamento Europeu e ao Comité Económico e Social sobre a implementação e os efeitos da Directiva 91/250/CEE relativa à protecção jurídica dos programas de computador" . Arquivado do original em 04/12/2020 . Recuperado em 26/12/2020 .

links externos

  • Descompiladores e desmontadores em Curlie
Retrieved from "https://en.wikipedia.org/w/index.php?title=Decompiler&oldid=1204823766"