engenharia reversa aplicada a segurança de executáveis

35
ANHANGUERA EDUCACIONAL S.A. Faculdade Anhanguera de Rondonópolis Curso de Sistemas de Informação 1158386326 Filipe de Souza Carvalho Engenharia Reversa Aplicada a Segurança de Executáveis Rondonópolis 2015

Upload: filipe-carvalho

Post on 22-Jan-2018

396 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Engenharia Reversa Aplicada a Segurança de Executáveis

ANHANGUERA EDUCACIONAL S.A.

Faculdade Anhanguera de Rondonópolis

Curso de Sistemas de Informação

1158386326 – Filipe de Souza Carvalho

Engenharia Reversa Aplicada a Segurança de Executáveis

Rondonópolis

2015

Page 2: Engenharia Reversa Aplicada a Segurança de Executáveis

1158386326 – Filipe de Souza Carvalho

Engenharia Reversa Aplicada a Segurança de Executáveis

Monografia apresentada, como exigência parcial para a obtenção do grau de Bacharel em Sistemas de Informação, na Faculdade Anhanguera Rondonópolis, sob a orientação do Humberto Roque Kuhn.

Rondonópolis

2015

Page 3: Engenharia Reversa Aplicada a Segurança de Executáveis

1158386326 – Filipe de Souza Carvalho

Engenharia Reversa Aplicada a Segurança de Executáveis

Trabalho de Conclusão de Curso apresentado como exigência parcial para a obtenção do grau de Bacharel em Sistemas de Informação da Faculdade Anhanguera Rondonópolis.

Monografia aprovada em ____/____/_______.

________________________________

Orientador Prof. Esp. Humberto Roque Kuhn

Faculdade Anhanguera de Rondonópolis

Orientador

________________________________

Prof. Esp.

Faculdade Anhanguera de Rondonópolis

Avaliador

________________________________

Prof. Esp. Pierre Inácio

Faculdade Anhanguera de Rondonópolis

Coordenador do Curso de Sistemas de Informação

Rondonópolis

2015

Page 4: Engenharia Reversa Aplicada a Segurança de Executáveis

RESUMO

Com a popularidade e importância da informática na atualidade, grandes transformações ocorrem frequentemente nos processos de criação de software, com intuito de se aumentar produtividade, reduzir custos de manutenção, se diferenciar da concorrência, etc. Com isto em mente, o antigo conceito de engenharia reversa, que pode ser descrito objetivamente como “desmontar algo para entender seu funcionamento”, foi adaptado à indústria de software para facilitar este processo, muitas vezes de forma controversa, considerada por alguns como algo ilegal. Serão utilizados exemplos práticos utilizando ferramentas específicas com linguagens de baixo nível para reforçar os conceitos de engenharia reversa. Palavras-Chave: segurança, engenharia reversa, software, usuários

Page 5: Engenharia Reversa Aplicada a Segurança de Executáveis

ABSTRACT

With the current popularity and importance of computing, big changes occur frequently in the software creation process, with the intent of increasing productivity, reducing maintenance costs, differentiation of the competition, etc. With this in mind, the old concept of reverse engineering, that can be objectively described as “disassemble something to understand its behavior”, was adapted to the software industry to make this process easier, often controversial, and considered by many as something illegal. Practical examples will be used utilizing specific tools with low level languages to reinforce the concepts of reverse engineering. Keywords: security, reverse engineering, software, users

Page 6: Engenharia Reversa Aplicada a Segurança de Executáveis

LISTA DE ILUSTRAÇÕES

Figura 1 – Interface da ferramenta OllyDbg

Figura 2 - Código fonte em linguagem Delphi

Figura 3 - Tela console com o resultado do exemplo em Delphi

Figura 4 - Código em linguagem Assembly equivalente ao Código Fonte em Delphi

Figura 5 - Código em linguagem Assembly com alteração da operação aritmética em

debugger

Figura 6 - Tela console com o resultado do exemplo em Delphi depois de ser

alterado no debugger OllyDbg

Figura 7 - Código Fonte em linguagem C#

Figura 8 - Tela console com o resultado do exemplo em C# original

Figura 9 - Exemplo em C# descompilado na ferramenta ILSpy

Figura 10 - Código do Exemplo em C# descompilado na linguagem CIL pelo plugin

Reflexil

Figura 11 - Tela console com o resultado do exemplo em C# depois de ser alterado

na ferramenta ILSpy

Figura 12 – Código JavaScript sem ofuscação

Figura 13 – Código JavaScript depois de sua ofuscação

Page 7: Engenharia Reversa Aplicada a Segurança de Executáveis

LISTA DE SIGLAS

API – Application Programming Interface

DLL – Dynamic-link Library

JVM – Java Virtual Machine

CIL – Common Intermediate Language

MSIL – Microsoft Intermediate Language

IDE – Integrated Development Environment

Page 8: Engenharia Reversa Aplicada a Segurança de Executáveis

SUMÁRIO

1 - INTRODUÇÂO .................................................................................................... 8

2 – ASPECTOS JURIDICOS ................................................................................. 10

3 –DEFINIÇÕES E CONCEITOS........................................................................... 12

3.1 Difusão .......................................................................................................... 12

3.2 Debugging .................................................................................................... 12

3.3 Domínios hierárquicos de proteção .............................................................. 13

4 – ESTUDO DE CASO: ENGENHARIA REVERSA NA PRÁTICA ....................... 15

4.1. Ferramentas................................................................................................. 15

4.1.1 OllyDbg ................................................................................................... 15

4.1.2 ILSpy ...................................................................................................... 16

4.1.3 Reflexil .................................................................................................... 17

4.2. Exemplo 1: Linguagem Delphi ..................................................................... 17

4.3 Exemplo 2: Linguagem C# ............................................................................ 22

4.3: Complementação ......................................................................................... 28

5 – SEGURANÇA .................................................................................................. 29

5.1: Ofuscação .................................................................................................... 29

5.2: Compressão ................................................................................................ 30

6 – CONSIDERAÇÕES FINAIS ............................................................................. 32

REFERÊNCIAS ...................................................................................................... 34

Page 9: Engenharia Reversa Aplicada a Segurança de Executáveis

8

1 - INTRODUÇÂO

Programas de computador são comumente distribuídos para seus usuários

finais somente em forma de binários, enquanto seus desenvolvedores mantém sua

versão entendível por humanos (ou código fonte) como um “segredo comercial”. Na

versão binária, é virtualmente impossível para um usuário “lê-la” enquanto se

mantém nesta forma. Já desenvolvedores desejando estudar sua estrutura, ou até

alterá-la, seria necessário obter acesso à este programa na forma de código fonte.

Por esta razão, desenvolvedores que não possuem este acesso utilizam a

prática chamada “engenharia reversa”, que emula as etapas originalmente

envolvidas em criar o programa em questão.

A engenharia reversa é o processo de analisar um sistema, identificar seus

componentes e suas inter-relações, representando-os de outra forma ou nível maior

de abstração. O conceito surgiu décadas antes da era da computação, apenas foi

adaptada de indústrias como a automobilística, onde as fabricantes compravam

veículos de suas concorrentes para desmontá-los, analisar seus componentes e

assim melhorar seus próprios veículos.

Segundo Saleh e Boujarwah (1996), o mercado de software todo o dia cresce

mais e mais, e com ele o uso de técnicas de programação, muitas vezes informais.

Como resultado, a manutenção destes produtos se torna problemática, uma vez que

a documentação associada aos mesmos, na maioria das vezes, não estão de

acordo com o código implementado.

Diariamente ao utilizar o computador, executamos uma variedade de

softwares sem saber realmente quais operações são realizadas. O desenvolvimento

de software atualmente é um processo tão complexo e interconectado que o

desenvolvedor comumente não tem conhecimento de todas as repercussões e

recursos dos projetos que ele mesmo mantém.

Além disso, as constantes modificações e adições de novas características ao

produto acarretam efeitos colaterais inesperados que não estão presentes na

documentação. Dessa forma, quando diante da manutenção do produto, o

desenvolvedor encontra uma documentação informal e incompleta, que não reflete o

software existente, tornando impossível o gerenciamento do processo de

Page 10: Engenharia Reversa Aplicada a Segurança de Executáveis

9

manutenção, segundo Saleh e Boujarwah (1996). Neste contexto, a engenharia

reversa tem o objetivo de recuperar informações de projeto perdidas durante a fase

de programação, de documentar o estado real do software e poder auxiliar o

processo de gerenciamento da manutenção.

Page 11: Engenharia Reversa Aplicada a Segurança de Executáveis

10

2 – ASPECTOS JURIDICOS

Na indústria de software, a engenharia reversa tem um papel controverso,

onde sempre serão discutidos seus limites entre legalidade e ilegalidade. Sua prática

contribui para a evolução tecnológica, ajuda a criação de conceitos mais eficazes em

relação a segurança, reduz o custo de desenvolvimento dos produtos através do

aproveitamento de ideias, assim economizando tempo. Porém, ao evitar “reinventar

a roda”, em certos casos esta economia é obtida infringindo leis que protegem a

propriedade intelectual.

Existem duas legalidades relacionadas à engenharia reversa: proteção de

copyright (protege a forma e aparência do software) e proteção de patente (protege

a ideia por trás da funcionalidade do software).

Uma patente é uma espécie de alerta para desencorajar competidores.

Quando há mérito em uma ideia, um competidor fará o seguinte: negociar uma

licença para utilizar esta ideia, fazer uma alteração sutil e declarar que a ideia

alterada não é protegida por uma patente ou declarar que a ideia não é

revolucionaria e que é uma evolução óbvia em um determinado campo.

Na investigação de quebra de copyright, instituições também utilizam

engenharia reversa para analisar se certas funcionalidades de um sistema foram

desenvolvidas através de uma cópia de código-fonte. Esta prática não é efetiva

quando o desenvolvimento da funcionalidade copiada e a engenharia reversa do

software original são realizados por equipes diferentes, onde a segunda faz a

análise e definições, assim disponibilizando para a primeira.

A cópia de funcionalidades também é sujeita a quebra de copyright, quando

empresas registram suas ideias em forma de patentes. Empresas como Apple e

Samsung frequentemente se encontram nos tribunais quando seus smartphones e

tablets são lançados com funcionalidades similares a de seus concorrentes.

Em 2015 a empresa Oracle publicou um texto, reclamando que alguns de

seus clientes estão contratando consultores de segurança para realizar engenharia

reversa em suas ferramentas na tentativa de achar falhas de segurança, assim

infringindo seus termos de licença.

Page 12: Engenharia Reversa Aplicada a Segurança de Executáveis

11

Uma das empresas que a Oracle direcionou com a publicação respondeu que

os softwares que utilizam as ferramentas mencionadas são de extrema importância,

envolvidos em assuntos como saúde, segurança pessoal e bem-estar. Desencorajar

seus clientes de procurar vulnerabilidades em seus produtos é uma tentativa de

regredir os progressos feitos para melhorar a segurança do software em geral.

Praticar engenharia reversa em um programa que foi legitimamente comprado

é perfeitamente legal, pelo menos na União Europeia, contando que seja para uso

pessoal ou educacional.

Por mais que a engenharia reversa é uma prática legal contando que não haja

cópias explicitas de outro produto, este debate ético não tem previsão de terminar.

Um argumento para sua legalidade pode ser resumido à analogia dita por Jennifer

Granick, diretora dos departamentos de lei e tecnologia da Universidade de

Stanford, “Você possui um carro, mas não tem permissão de abrir o capô”.

Page 13: Engenharia Reversa Aplicada a Segurança de Executáveis

12

3 –DEFINIÇÕES E CONCEITOS

3.1 Difusão

Atualmente há centenas de empresas espalhadas pelo mundo com vagas de

emprego que esperam de seus candidatos conhecimento avançado em linguagens

como Assembly e C++, ferramentas de Debugging de binários, exclusivamente para

a procura de vulnerabilidades de softwares. Entre essas empresas, estão:

Empresas de segurança privada sob contratação, que atendem outras

empresas desenvolvedoras de software de Finanças, Educação, Saúde,

Governo, etc., respeitando diversos regulamentos internacionais de

privacidade, com a intenção de proteger seus produtos de vazamento de

informações confidenciais.

Empresas desenvolvedoras de software antivírus, que realizam análises

em executáveis maliciosos, assim entendendo seu padrão de

funcionamento interno e adicionando tais regras, chamadas “heurísticas”,

nos algoritmos de detecção de ameaças.

3.2 Debugging

Debugging é a prática de testar e analisar aplicações com o intuito de se

achar erros ou comportamentos indesejados. A maioria das IDEs para

desenvolvimento atualmente possuem um recurso embutido para a pratica de

Debugging.

Seu funcionamento consiste em executar o código uma linha de cada vez,

assim permitindo o desenvolvedor analisar as alterações dos valores de variáveis ou

comportamento do algoritmo em geral, sendo necessário conhecimento do

funcionamento de memória, processador e endereços de variáveis.

Debuggers possuem um recurso chamado breakpoint, que é uma forma de

notificar a IDE que a execução necessita ser pausada no momento que sua posição

chegar à uma determinada linha ou instrução. Outros recursos são oferecidos, como

Page 14: Engenharia Reversa Aplicada a Segurança de Executáveis

13

ferramentas de análise de consumo de memória e processamento da CPU. Mesmo

com tantos recursos e tecnologias das linguagens e IDEs atuais, grande parte do

tempo de um desenvolvedor é gasto em debugging.

Para a engenharia reversa de binários nativos, gerados na linguagem

Assembly, a utilização de um debugger é primordial. Comandos nesta linguagem,

otimizados para entendimento do processador, e sem possibilidade de se obter o

código fonte a partir de tal binário, tornam a análise dos mesmos uma tarefa quase

impossível sem um debugger. Com a sua capacidade de executar linha por linha,

analisando o valor dos registradores e endereços de memória, grande facilidade é

obtida para achar o lugar certo de realizar uma edição em seu código.

3.3 Domínios hierárquicos de proteção

Os domínios hierárquicos de proteção, comumente chamados de anéis de

proteção, são mecanismos para proteger dados e funcionalidades de falhas de

código e atividades maliciosas. Estes anéis são ordenados em uma hierarquia de

mais confiável (menor nível, geralmente de número zero) à menos confiável

(geralmente com o maior número). Na maioria dos sistemas operacionais, o anel 0 é

o ambiente com mais privilégios e interage diretamente com o hardware, tornando

possível a interação com o usuário.

O sistema operacional Windows possui somente dois anéis, 0 (kernel) e 3

(modo de usuário). Este sistema de segurança funciona de uma forma em que

softwares normais (que utilizam o anel 3, sendo separados por processos), como os

utilizados em comunicação virtual, não terão permissão de utilizar um periférico

como Webcam sem o consentimento do usuário.

No ambiente kernel (anel 0) são executadas aplicações independentes de

processos (chamadas drivers), onde qualquer falha de programação imediatamente

interrompe a execução do sistema operacional, tornando o desenvolvimento das

mesmas muito mais difícil. Este ambiente onde todo código nele contido é executado

com permissão máxima, também é utilizado por softwares antivírus para monitorar a

atividade dos códigos executados no anel 3, tráfego de rede, utilização de arquivos

no disco, etc. Outro exemplo de utilização deste ambiente são malwares avançados,

Page 15: Engenharia Reversa Aplicada a Segurança de Executáveis

14

chamados Rootkits, que podem alterar funções primordiais do sistema operacional,

dificultando sua detecção por softwares antivírus.

Geralmente a prática de engenharia reversa em executáveis se limita ao anel

3 pela disponibilidade das ferramentas necessárias. Em drivers de modo kernel,

sendo binários nativos, seus comandos são muito complexos e seria necessário um

debugger para melhor entendimento. Tipicamente, para utilizar um debugger em um

driver em modo de desenvolvimento dois computadores são requeridos, assim sua

comunicação sendo efetuada via rede local. Sem a posse de código fonte, não há

conhecimento de ferramentas que realizem tais requerimentos.

Page 16: Engenharia Reversa Aplicada a Segurança de Executáveis

15

4 – ESTUDO DE CASO: ENGENHARIA REVERSA NA PRÁTICA

Neste capítulo serão demonstrados exemplos simples de códigos, onde seus

executáveis serão analisados e alterados por ferramentas que facilitam a prática de

engenharia reversa. Os exemplos realizam uma operação aritmética e o objetivo é

alterar o resultado da mesma.

4.1. Ferramentas

4.1.1 OllyDbg

Figura 1 – Interface da ferramenta OllyDbg

Page 17: Engenharia Reversa Aplicada a Segurança de Executáveis

16

A ferramenta OllyDbg é um debugger 32 bits de análise em nível Assembly

para o sistema operacional Windows. É conhecido pela sua praticidade em análise

de código binário tornando a tarefa fácil quando não há posse de código fonte. Sua

licença é Shareware, necessitando registro para uso comercial, caso contrário pode

ser utilizado gratuitamente.

É muito rico em recursos, como carregamento direto e Debugging de DLLs,

localização de rotinas em objetos e bibliotecas, suporte ao desenvolvimento de

plugins, suporte à aplicações com várias threads, breakpoints de hardware, etc.

No fim de 2001, quando as primeiras versões da ferramenta apareceram,

havia outro software chamado SoftICE, que estava em declínio, e a ferramenta IDA

(que hoje é a mais popular) ainda não era muito conhecida. Nesta época OllyDbg se

tornou a ferramenta de referência para a prática de engenharia reversa em todo o

planeta.

Atualmente a ferramenta sofre uma queda de popularidade, porque não há

suporte completo à executáveis com instruções 64 bits, sem receber uma versão

desde 2013.

4.1.2 ILSpy

A ferramenta ILSpy é um descompilador e navegador open-source de binários

gerados para a plataforma .NET. Seu desenvolvimento foi iniciado depois que a

empresa desenvolvedora da ferramenta Reflector anunciou que sua versão gratuita

deixaria de existir no final de fevereiro de 2011.

Seu funcionamento é baseado na famosa biblioteca para .NET Mono.Cecil,

desenvolvida desde 2004 e que tem como função analisar e modificar binários .NET

em nível arquivo, sem necessidade de carrega-los em memória.

Atualmente a ferramenta ILSpy é uma das mais populares entre as capazes

de realizar engenharia reversa em binários .NET, possuindo recursos importantes

como o suporte de plugins, escolha de linguagem para descompilação (C# ou

VB.NET), navegação prática via links, etc.

Seu desenvolvimento continua ativo, com vários recursos já planejados, como

suporte à edição de binários.

Page 18: Engenharia Reversa Aplicada a Segurança de Executáveis

17

4.1.3 Reflexil

A ferramenta Reflexil é um editor de binários .NET open-source distribuído na

forma de plugin para as ferramentas Reflector, ILSpy e JustDecompile. Como a

ferramenta ILSpy, Reflexil também é baseado na biblioteca Mono.Cecil.

Como atualmente as ferramentas que se destina somente suportam a

descompilação de binários .NET, Reflexil é um complemento importante,

adicionando a funcionalidade de edição e injeção de código aos binários sendo

analisados.

Possui recursos que suportam a alteração quase completa dos elementos de

um binário .NET, como suas referências, instruções, assinaturas digitais, etc.

4.2. Exemplo 1: Linguagem Delphi

A linguagem Delphi, anteriormente chamada de Object Pascal, é uma

linguagem muito utilizada no desenvolvimento de sistemas empresariais, devido a

sua facilidade e velocidade.

Figura 2 - Código fonte em linguagem Delphi

Page 19: Engenharia Reversa Aplicada a Segurança de Executáveis

18

O exemplo exibirá um texto simulando a operação aritmética, utilizando os

valores das variáveis n1, n2 e n3.

Figura 3 - Tela console com o resultado do exemplo em Delphi

Seu binário é gerado no formato nativo do sistema operacional Windows,

onde todas as suas instruções são convertidas para a linguagem Assembly, que

opera diretamente com os registradores do processador, assim otimizando sua

velocidade de execução.

O executável compilado a partir do código fonte exibido na Figura 2, aberto

para análise na ferramenta OllyDbg, pode ser visto na Figura 4.

Page 20: Engenharia Reversa Aplicada a Segurança de Executáveis

19

Figura 4 - Código em linguagem Assembly equivalente ao Código Fonte em

Delphi

Em uma linguagem otimizada para entendimento do processador, com

operações de baixo nível e com registradores limitados, a prática de engenharia

reversa se torna bastante demorada e crítica. É necessário conhecimento dos

comandos e parâmetros chamados mnemônicos, números hexadecimais, etc.

No processo de compilação, todos os nomes de funções e variáveis são

perdidos, e uma linha em código Delphi é convertida em várias linhas na linguagem

Assembly, onde qualquer alteração incorreta completamente invalida a execução do

bloco de código.

Comumente compiladores possuem um parâmetro para a ativação da

geração de um arquivo chamado map, que possui uma lista com todas as funções e

seus respectivos endereços de memória, também chamados de offsets, para ajudar

ferramentas de análise a localizar pontos de execução.

Page 21: Engenharia Reversa Aplicada a Segurança de Executáveis

20

Normalmente um executável possui milhares de linhas de código Assembly, e

sua análise sem um arquivo map seria quase impossível sem algumas técnicas

como as seguintes:

- Busca de texto: Os blocos de texto originais, chamados Strings, não

são perdidos no processo de compilação, assim facilitando a localização dos

códigos que utilizam os mesmos. No exemplo exibido na Figura 4, os textos “ + “ e “

= “, que são usados para exibir o resultado da operação aritmética para o usuário,

ajudam a localizar o bloco de código Assembly correto, equivalente ao código fonte

Delphi exibido na Figura 2.

- Chamadas de APIs: Por mais que os nomes de funções são perdidos

no processo de compilação, chamadas às APIs do Windows são completamente

mantidas. APIs como a MessageBoxA, que está declarada na DLL user32.dll, são

comumente usadas para localizar blocos Assembly onde exibem uma caixa de

diálogo ao usuário.

Brechas de segurança podem ser ilusórias e difíceis de se definir. O fato é que mesmo com posse do código-fonte as vezes pode ser difícil para se distinguir código seguro de perigosas vulnerabilidades de segurança. Ainda, quando você sabe que tipo de problemas está procurando e com consciência de certas áreas de alto risco, é definitivamente possível de estimar se uma função é segura ou não praticando engenharia reversa na mesma. Só é necessário o entendimento do sistema e o que torna um código seguro ou inseguro. (EILAM, 2005, p. 271).

Para realizar a alteração da operação de adição do exemplo para uma

subtração, é necessário fazer uma análise das linhas de Assembly equivalentes à

operação em Delphi:

● Linha 0040828C: Preenche o espaço de memória de endereço 40A798

(equivalente a variável n1) com o valor 0A (equivalente a 10, depois da conversão

hexadecimal -> decimal).

● Linha 00408296: Preenche o espaço de memória de endereço 40A79C

(equivalente a variável n2) com o valor 2.

● Linha 004082A0: Preenche o registrador EAX com o valor 10, que está

armazenado no endereço de memória 40A798 (equivalente a variável n1).

● Linha 004082A5: Adiciona no registrador EAX (que atualmente possui

o valor 10) o valor 2, que está armazenado no endereço de memória 40A79C

(equivalente a variável n2). Nesta linha ocorre a operação aritmética que será

alterada.

Page 22: Engenharia Reversa Aplicada a Segurança de Executáveis

21

Figura 5 - Código em linguagem Assembly com alteração da operação

aritmética em debugger

Alterando o comando ADD pelo comando SUB, a operação de adição entre o

registrador EAX e o endereço de memória 40A79C se torna uma operação de

subtração.

Como a alteração foi realizada somente no momento de produzir o valor da

variável n3, que é equivalente ao resultado da operação no texto do console, o

mesmo continuará sendo exibido como se a operação fosse uma adição, como é

mostrado na figura 6:

Page 23: Engenharia Reversa Aplicada a Segurança de Executáveis

22

Figura 6 - Tela console com o resultado do exemplo em Delphi depois de ser

alterado no debugger OllyDbg

Em aplicações reais de engenharia reversa, dependendo de sua

complexidade para chegar no resultado final, são necessárias alterações simples

como a utilizada neste exemplo, alterações que envolvem várias linhas de código

Assembly, ou até injeções de código, onde o ponto de execução atual é

redirecionado para outro endereço de memória, localizado no próprio executável ou

em bibliotecas DLL carregadas dinamicamente, para depois voltar ao seu ponto de

execução original.

4.3 Exemplo 2: Linguagem C#

A linguagem C# também é uma linguagem compilada, porém seu executável

não é gerado com instruções Assembly, e sim com instruções IL.

A linguagem CIL (Common Intermediate Language, também conhecida como

Microsoft Intermediate Language - MSIL) é o resultado da compilação de todas as

linguagens que fazem parte do .NET Framework. Este nível de abstração é utilizado

para executar um mesmo binário em várias plataformas ou arquiteturas diferentes,

pois quem interpreta o código CIL é a máquina virtual do .NET Framework, e não o

sistema operacional em si. Este conceito também é utilizado na linguagem Java,

onde sua máquina virtual JVM pode ser instalada em diversos tipos de plataformas e

assim permitindo a execução de um mesmo binário.

Page 24: Engenharia Reversa Aplicada a Segurança de Executáveis

23

Figura 7 - Código Fonte em linguagem C#

Para comparação, o código C# do exemplo é equivalente ao exemplo na

linguagem Delphi, porém com a operação aritmética padrão sendo a subtração ao

invés de adição.

Figura 8 - Tela console com o resultado do exemplo em C# original

Assim como Assembly, a linguagem CIL também é uma linguagem de

programação, ou seja, é possível escrever algoritmos diretamente utilizando-as. É

muito importante possuir o conhecimento de ambas sintaxes para além de realizar

alterações em códigos existentes via engenharia reversa, poder criar algoritmos de

qualquer tamanho sem posse do código fonte.

Em linguagens de compilação nativa como Delphi, o binário já é gerado para

entendimento do processador pois no momento de sua geração é necessário

informar ao compilador a plataforma desejada. Ou seja, em compilação para estas

linguagens, é formado um binário diferente para cada plataforma ou arquitetura,

Page 25: Engenharia Reversa Aplicada a Segurança de Executáveis

24

como x86, x64, ARM, Windows, Linux, etc., assim delegando a tarefa de fornecer

compatibilidade para o sistema operacional.

Por exemplo, em Windows, a maioria de binários gerados para a arquitetura

x86 podem ser executados em instalações x64, porém em um sistema operacional

x86 não é possível executar um binário compilado com instruções x64.

Já em linguagens que dependem de uma máquina virtual, seus binários são

compilados com instruções “universais” entendíveis por humanos que são

convertidas para linguagem de máquina em sua primeira execução. Esta conversão

é realizada somente neste momento pois a máquina virtual utilizará a arquitetura

atual de execução para gerar o código de máquina otimizado para posteriores

execuções.

Esta falta de otimização, que mantém informações de nomes de objetos,

funções, namespaces, etc., são completamente mantidos. Por mais que a

velocidade de execução é reduzida, há benefícios como a possibilidade de

desenvolver soluções utilizando várias linguagens de programação (como VB.NET e

C#, no caso do .NET Framework), recursos de linguagem para criação de código em

tempo de execução, ferramentas de produtividade embutidas na IDE como

ReSharper para Visual Studio, etc.

Desta forma, para a engenharia reversa estes binários não otimizados podem

ser analisados e revertidos quase que identicamente à sua sintaxe original. Em

binários CIL, é possível até escolher qual linguagem será utilizada no processo de

reversão.

Atualmente existem dezenas de ferramentas que conseguem “descompilar”

binários CIL, fornecendo recursos de navegação de namespaces, classes, métodos

e suas chamadas, entre outros. Neste exemplo será utilizada a ferramenta ILSpy,

pois além de realizar reversão, é permitido o desenvolvimento de plugins. O plugin

Reflexil, que suporta ser embutido em várias ferramentas, incluindo o ILSpy, permite

a alteração de instruções, posteriormente salvando um binário novo.

Page 26: Engenharia Reversa Aplicada a Segurança de Executáveis

25

Figura 9 - Exemplo em C# descompilado na ferramenta ILSpy

Como exibido na figura 9, binários CIL contém toda a informação necessária

para uma análise profunda de seu comportamento, diferente de binários nativos. É

possível ver suas dependências — na forma de referências —, classes e métodos,

todos de uma forma estruturada.

Na parte de código, por mais que os nomes de variáveis não foram

identicamente mantidos, e recursos de facilidade foram abstraídos (concatenação

direta do texto foi substituída por uma chamada de função Concat do objeto String,

para melhor entendimento da máquina virtual), a lógica do programa se mantém

completamente entendível por humanos depois da ferramenta ILSpy analisar o

código CIL armazenado no binário e realizar a reversão.

Para a edição da operação aritmética, será utilizado o plugin Reflexil,

embutido na ferramenta ILSpy. Em modo de edição, o código é exibido na

linguagem CIL, da mesma forma que está armazenado no binário como exibido na

figura 10.

Page 27: Engenharia Reversa Aplicada a Segurança de Executáveis

26

Figura 10 - Código do Exemplo em C# descompilado na linguagem CIL pelo

plugin Reflexil

Page 28: Engenharia Reversa Aplicada a Segurança de Executáveis

27

A figura 10 exibe exatamente como o código CIL é armazenado no binário,

antes de sua reversão e formatação na ferramenta ILSpy. Seu modelo de instruções

é bem similar à linguagem Assembly, utilizando mnemônicos de forma linear para

construir os algoritmos, porém com uma quantidade de informações bem maior.

Segue a análise de seus comandos, equivalente ao código em C#:

Linha 01: Adiciona o valor 10 no topo da pilha.

Linha 02: Preenche a variável de índice 0 da função atual com o valor

armazenado no topo da pilha (equivalente a 10), removendo-o da mesma.

Linha 03: Adiciona o valor 2 no topo da pilha.

Linha 04: Preenche a variável de índice 1 da função atual com o valor

armazenado no topo da pilha (equivalente a 2), removendo-o da mesma.

Linha 05: Adiciona o valor da variável de índice 0 da função atual

(equivalente a variável n1, possuindo o valor 10) no topo da pilha.

Linha 06: Adiciona o valor da variável de índice 1 da função atual

(equivalente a variável n2, possuindo o valor 2) no topo da pilha.

Linha 07: Subtrai os dois valores que estão no topo da pilha em ordem

inversa (10 e 2 após a inversão), adicionando o resultado no topo da pilha.

Linha 08: Preenche a variável de índice 2 da função atual com o valor

armazenado no topo da pilha (equivalente a 8), removendo-o da mesma.

Como no exemplo em Delphi, de forma inversa, alteraremos o comando SUB

armazenado na linha 07 para ADD, alterando a forma que o algoritmo produz o valor

da variável n3, assim enganando o programa a exibir um texto de uma operação

aritmética com um valor errado.

Figura 11 - Tela console com o resultado do exemplo em C# depois de ser

alterado na ferramenta ILSpy

Page 29: Engenharia Reversa Aplicada a Segurança de Executáveis

28

4.3: Complementação

Por mais que a prática de engenharia reversa é muito mais fácil e flexível

quando praticada em binários utilizados por máquinas virtuais, como exibido no

exemplo 2, sua prática em binários nativos é muito mais popular, pois a maioria de

produtos direcionados ao usuário final utilizando o modelo Desktop focados pela

pirataria são desenvolvidos em linguagens como C, C++ ou Delphi, tendo

performance como principal motivo.

Produtos focados pela pirataria através da engenharia reversa

frequentemente alteram seus métodos de proteção, como a troca de algoritmos de

criptografia, análise de códigos serial, compactação, etc., porém eventualmente

estes métodos se tornam obsoletos, assim tornando este problema um ciclo que

sempre fará parte da manutenção do produto.

Page 30: Engenharia Reversa Aplicada a Segurança de Executáveis

29

5 – SEGURANÇA

A prática de engenharia reversa em executáveis é o principal método que

crackers utilizam para disponibilizar aplicativos pagos de forma gratuita ou extrair

informações confidenciais.

Por mais que não seja possível prevenir tal prática, foram desenvolvidos

vários métodos para aumentar o tempo necessário para sua conclusão, assim

necessitando maior conhecimento do invasor.

5.1: Ofuscação

Esta técnica, bastante utilizada em binários que dependem de máquinas

virtuais como .NET, Java e até páginas web como JavaScript, consiste em renomear

elementos de sua estrutura, como métodos, propriedades, eventos, variáveis, etc.,

tornando a análise da lógica de seus algoritmos um processo bem mais demorado.

Sua prática em códigos JavaScript é amplamente utilizada, pois como a

linguagem é executada pelo navegador, qualquer usuário tem acesso completo ao

código fonte. Desta forma, sua análise se torna mais complicada com a remoção de

comentários, espaços utilizados na indentação e na troca de nomes de variáveis e

funções por combinações de uma ou duas letras, assim diminuindo a largura de

banda necessária para o usuário realizar o download dos arquivos. Também é

comum utilizar esta técnica em linguagens de marcação como HTML e CSS, porém

o ganho é obtido somente com performance de largura de banda.

Exemplo:

Page 31: Engenharia Reversa Aplicada a Segurança de Executáveis

30

Figura 12 – Código JavaScript sem ofuscação

Figura 13 – Código JavaScript depois de sua ofuscação

5.2: Compressão

Esta técnica é utilizada quase que exclusivamente em executáveis nativos,

que possuem Assembly como sua linguagem final. Se tornou popular quando

computadores tinham espaço em disco limitado, compatíveis com a capacidade de

disquetes, onde eram lentos e de baixa capacidade. Assim permitindo o

armazenamento de uma maior quantidade de softwares em uma determinada

quantidade de espaço, sem a inconveniência de precisar extrair os mesmos toda vez

que o usuário precisar executá-los.

Esta compressão é realizada de uma forma onde o executável original é

compactado e armazenado em um executável novo — chamado Stub — que possui

um algoritmo de descompactação.

Quando este Stub é executado, ele descompacta o binário original em

memória e o executa de uma forma transparente, onde o usuário não percebe tal

operação.

Há perda de performance ao utilizar esta técnica, pois para realizar a

descompactação é necessário que o computador possua mais memória, porque nela

Page 32: Engenharia Reversa Aplicada a Segurança de Executáveis

31

será armazenado o algoritmo de descompactação, os dados compactados e o

código descompactado, além de processamento adicional para gerar o mesmo.

Suas vantagens incluem menor espaço em disco para armazenamento de

binários, menos tempo requerido para upload ou download via internet, invalida a

prática de engenharia reversa em binários diretamente, assim sendo só possível

através de um debugger em tempo de execução, onde a descompactação já foi

executada e o código original já está disponível na memória.

Algumas ferramentas de compressão que tem seu principal foco dificultar a

prática de engenharia reversa, possuem recursos de descompactação onde o local

em memória que o código original será armazenado é aleatoriamente gerado a cada

execução, assim não sendo possível o desenvolvimento de patchers para a

alteração de instruções na memória em tempo de execução.

É comum sua utilização em softwares maliciosos, para confundir softwares

antivírus e passar despercebidos em suas análises.

Programas maliciosos podem ser traiçoeiros e complicados. Eles farão o necessário para se manter invisíveis e parecerem inocentes. Educar usuários finais em como estes programas funcionam e no que prestar atenção é uma tarefa importante, porém não suficiente. Desenvolvedores de aplicações e sistemas operacionais precisam melhorar constantemente a forma que seus produtos tratam código inseguro e convincentemente transmitir para seus usuários o fato de que eles simplesmente não deveriam deixar um programa desconhecido ser executado em seu sistema a não ser que exista uma razão excelente para isso. (EILAM, 2005, p. 306).

Alguns softwares antivírus simplesmente detectam qualquer executável

gerado com certas ferramentas de compressão como vírus porque o algoritmo de

descompactação armazenado no Stub compartilham algumas características que

ferramentas maliciosas possuem.

Page 33: Engenharia Reversa Aplicada a Segurança de Executáveis

32

6 – CONSIDERAÇÕES FINAIS

A engenharia reversa está fundamentalmente direcionada à descoberta e

aprendizado. Desenvolvedores não se profissionalizam somente lendo artigos, indo

à conferências ou mantendo produtos de suas empresas, mas também analisando

produtos dos outros. Aprendendo com o que já foi feito anteriormente por outros

frequentemente é convertido à novos produtos e avanços de conhecimento.

Segundo EILAM (2005), qualquer barreira baseada em software pode ser

quebrada simplesmente modificando-o. Atualmente é impossível prevenir a prática

da técnica de engenharia reversa em executáveis quando há posse dos mesmos,

independentemente de linguagem. Existem várias técnicas que dificultam sua

prática, como ofuscação, compressão, detecção de debuggers, vínculos com chaves

de hardware, etc.

O dilema de investir em proteger de engenharia reversa os binários de uma

aplicação é que quanto mais se gasta nisso, menos do custo do projeto está sendo

investido em adicionar reais funcionalidades para o usuário final, porém uma

aplicação sem prevenção nenhuma torna mais fácil para empresas concorrentes

obterem informações sigilosas da mesma.

Não é coincidência que recentemente a maioria das propostas para restringir

a engenharia reversa venha do contexto de produtos baseados em informática,

como software ou semicondutores. Estes tipos de produtos carregam consigo uma

grande quantidade de propriedade intelectual, que custaram muitas pesquisas,

tempo e dinheiro, assim tornando-os mais vulneráveis que outros tipos de produtos

manufaturados. Isto é especialmente verdade quando a informação está em forma

digital. Copiar e distribuir software é essencialmente instantâneo e sem nenhum

custo em um ambiente como a internet, utilizando ferramentas como o protocolo

torrent.

Todos os dias a engenharia reversa causa milhares de dólares em prejuízos

às desenvolvedoras de software, pois ela torna possível a criação de cracks e

keygens, assim tornando seus produtos pagos vítimas da pirataria. Exemplos:

Windows, Office, Photoshop, AutoCAD. Porém sem essa técnica não existiriam

softwares antivírus, tornando os prejuízos imensuráveis para os usuários e

Page 34: Engenharia Reversa Aplicada a Segurança de Executáveis

33

empresas do mundo inteiro com a proliferação sem controle de softwares

maliciosos.

É possível proteger certas regras e lógicas da prática de engenharia reversa

disponibilizando seu uso pelo executável através de um serviço hospedado em um

ambiente web controlado. Esta técnica está limitada à aplicações com acesso à

internet obrigatório ou aplicações empresariais multiusuário conectadas à um

servidor.

A forma mais segura de se desenvolver uma aplicação sem se preocupar com

engenharia reversa é possuindo uma interface Web, pois assim os usuários não

terão posse dos binários, se limitando somente a ataques como SQL Injection e

XSS.

Page 35: Engenharia Reversa Aplicada a Segurança de Executáveis

34

REFERÊNCIAS

EILAM, Eldad. Reversing: Secrets of Reverse Engineering, Indianapolis: Wiley

Publishing, 2005.

SECUNIA – Jobs. Disponível em: <http://secunia.com/company/jobs/reverse-

engineer/>. Acesso em: 24 set. 2015.

Núcleo (Software). Disponível em: <https://pt.wikipedia.org/wiki/Núcleo_(software).>.

Acesso em: 24 set. 2015.

SALEH, K.; BOUJARWAH, A. Communications Software Reverse Engineering: A

Semi-Automatic approach. Information and Software Technology, Oxford, n.38,

p.370-395, 1996.

Engenharia Reversa. Disponível em:

<http://www.ebah.com.br/content/ABAAAf2CEAJ/50-apostilas-hacker-engenharia-

reversa>. Acesso em: 24 set. 2015.

Aplicativo OllyDbg. Disponível em: <http://www.ollydbg.de/>. Acesso em: 24 set.

2015.

Sistema Operativo. Disponível em: <https://pt.wikipedia.org/wiki/Sistema_operativo>.

Acesso em: 24 set. 2015.

Aplicativo ILSpy. Disponível em: <http://ilspy.net/>. Acesso em: 24 set. 2015.

Plugin Reflexil para o aplicativo ILSpy. Disponível em: <http://reflexil.net>. Acesso

em: 24 set. 2015.