o uso da engenharia reversa no desenvolvimento de software ... · software seguro, por meio de...
TRANSCRIPT
1
ESCOLA SUPERIOR ABERTA DO BRASIL – ESAB
CURSO LATO SENSU EM ENGENHARIA DE SISTEMAS
RONILDO CESAR DE MOURA
O USO DA ENGENHARIA REVERSA NO
DESENVOLVIMENTO DE SOFTWARE SEGURO
VITÓRIA
2008
2
RONILDO CESAR DE MOURA
O USO DA ENGENHARIA REVERSA NO
DESENVOLVIMENTO DE SOFTWARE SEGURO
Monografia apresentada à ESAB – Escola Superior Aberta do Brasil, sob orientação do (a) Prof. (a) Beatriz Christo Gobbi.
VITÓRIA
2008
3
RONILDO CESAR DE MOURA
O USO DA ENGENHARIA REVERSA NO
DESENVOLVIMENTO DE SOFTWARE SEGURO
Aprovada em ____ de __________ de 2008.
_____________________________________
_____________________________________
_____________________________________
VITÓRIA
2008
4
Este trabalho é dedicado aos meus pais e à
minha esposa, pois só eles conhecem todo o
esforço que fizemos para chegar até aqui.
5
RESUMO
O estudo teve por objetivo apresentar meios que contribuam no desenvolvimento de software seguro, por meio de utilização de engenharia reversa de software. A engenharia reversa de software tem o propósito de recuperar as informações de projeto perdidas durante a fase de desenvolvimento, de documentar o real estado do software e poder auxiliar o processo de gerenciamento da manutenção. Dessa forma, a engenharia reversa pode ser aplicada em qualquer etapa do ciclo de vida, seja para recuperar níveis de abstração ou para fornecer uma nova visão em um grau de abstração mais alto. O objetivo da engenharia reversa é a produção de informações que possam aumentar o conhecimento geral de sistemas de software. Essas informações podem ser utilizadas em atividades como manutenção, reuso, teste e controle de qualidade de software. Existe um debate legal ao redor de engenharia reversa que acontece há vários anos. Isto normalmente revolve ao redor da pergunta de qual o impacto social e econômico a engenharia reversa está causando na sociedade como um todo. Todavia, para calcular este tipo de impacto, em grande parte, depende de como a engenharia reversa é usada. Em alguns países a prática de engenharia reversa é considerada ilegal por ter praticantes interessados em obter acesso não autorizado a recursos de software não oferecidos gratuitamente pelos fabricantes que vendem o produto. Por outro lado, demonstra a utilização da própria engenharia reversa como ferramenta de proteção contra a sua prática ilegal. A partir de técnicas aplicadas nesta área é possível modelar melhores proteções para o software como anti-descompiladores, códigos mutantes e armadilhas.
6
LISTA DE FIGURAS
Figura 1 – Comparação dos níveis de abstração e das visões ................................. 14
Figura 2 – Relação entre a engenharia progressiva e a engenharia reversa ............ 15
Figura 3 – Software IDA Pro...................................................................................... 53
Figura 4 – Sofware VB Decompiler ........................................................................... 54
Figura 5 – Software Understand for Delphi ............................................................... 56
Figura 6 – Visão geral do método FUSION-RE/I ....................................................... 57
Figura 7 – Síntese do método FUSION-RE/I............................................................. 58
7
SUMÁRIO
1 INTRODUÇÃO ...................................................................................................... 9
1.1 CONTEXTO ................................................................................................... 9
1.2 PROBLEMA ................................................................................................. 10
1.3 JUSTIFICATIVA ........................................................................................... 10
1.4 OBJETIVOS ................................................................................................. 10
1.5 METODOLOGIA .......................................................................................... 11
2 CONCEITOS E DEFINIÇÕES ............................................................................ 12
3 ENGENHARIA REVERSA DE SISTEMA ........................................................... 17
3.1 SOFTWARE DE BAIXO NÍVEL .................................................................... 17
3.2 LINGUAGEM ASSEMBLY ........................................................................... 18
3.3 COMPILADORES ........................................................................................ 19
3.4 MÁQUINAS VIRTUAIS E BYTECODES ...................................................... 20
3.5 SISTEMAS OPERACIONAIS ....................................................................... 21
3.6 DISASSEMBLERS ....................................................................................... 21
3.7 DEPURADORES.......................................................................................... 21
3.8 DECOMPILADOR ........................................................................................ 22
4 ASPECTOS LEGAIS .......................................................................................... 23
4.1 COMPATIBILIDADE ..................................................................................... 23
4.2 SÃO PONTOS FUNDAMENTAIS DA LEI DE SOFTWARE: ........................ 26
4.3 FALHAS DE SEGURANÇA .......................................................................... 27
4.3.1 Um pouco de história ............................................................................. 27
4.3.2 Alguns conceitos importantes ................................................................ 28
4.3.3 Chaves públicas e privadas ................................................................... 31
4.3.4 Exemplos de falhas ............................................................................... 32
5 TÉCNICAS DE ENGENHARIA REVERSA ......................................................... 37
8
5.1 TÉCNICAS DE ENGENHARIA REVERSA SEM O CÓDIGO-FONTE ......... 37
5.2 TÉCNICAS DE ENGENHARIA REVERSA COM O CÓDIGO-FONTE ........ 38
5.2.1 Extração das Informações ..................................................................... 38
5.2.2 Tratamento das informações ................................................................. 40
5.3 TÉCNICAS COMPLEXAS DE ENGENHARIA REVERSA ........................... 43
5.3.1 Análise de propagação .......................................................................... 43
5.3.2 Objetização ............................................................................................ 43
5.3.3 Reengenharia de interfaces ................................................................... 44
5.4 ENGENHARIA REVERSA PARA SEGURANÇA ......................................... 44
5.4.1 Software malicioso ................................................................................. 44
5.4.2 Métodos de proteção ............................................................................. 45
5.4.3 Técnicas Anti-reversão .......................................................................... 49
6 FERRAMENTAS DE ENGENHARIA REVERSA ................................................ 53
6.1 IDA Pro ......................................................................................................... 53
6.2 VB Decompiler ............................................................................................. 54
6.3 Understand for Delphi .................................................................................. 56
6.4 MÉTODO FUSION-RE/I ............................................................................... 57
7 CONCLUSÃO ..................................................................................................... 59
8 REFERENCIAS BIBLIOGRAFICAS ................................................................... 61
9
1 INTRODUÇÃO
Engenharia Reversa, Engenharia de Software, Segurança.
1.1 CONTEXTO
O estudo procura demonstrar como o desenvolvimento de software pode se
beneficiar com a utilização da engenharia reversa. O processo de desenvolvimento
possui diversos requisitos, entre eles a segurança. Todavia, nem sempre os
programadores, analistas e gestores dão a devida atenção que o tema requer.
Com a disseminação da internet, de novas tecnologias e de ferramentas cada vez
mais poderosas, a informação tornou-se artigo valioso. Contudo, é preciso torná-la
protegida da ação de pessoas não autorizadas. Para tal, a elaboração de programas
de computador com um nível maior de proteção requer a utilização de ferramentas
específicas. Nesse contexto, surgem técnicas que podem reduzir esse risco, entre
elas o emprego da engenharia reversa como meio de proteger o código dos
sistemas.
A necessidade do uso da engenharia reversa tem vários motivos, dentre eles: os
sistemas terem sido desenvolvidos há muito tempo; possuírem pouca ou nenhuma
documentação atualizada; os desenvolvedores do produto já não trabalharem mais
na empresa; o sistema ter sido criado com métodos diferentes, nem sempre
padronizados.
Outras necessidades devem-se a adaptação às novas tecnologias de hardware e
software (novas linguagens e métodos); adaptação às novas economias (moeda,
legislação, impostos); adaptação de novas funcionalidades, acessibilidade, correção
de erros, etc.
10
1.2 PROBLEMA
Devido à quantidade de vulnerabilidades que os sistemas atuais têm enfrentado,
aumentar a segurança no desenvolvimento de software tornou- se tão necessário
quanto o uso dos computadores nas empresas e nas residências. Uma das soluções
é tornar os programas imunes aos vários tipos de ataques que podem sofrer, para
isso ressurge a engenharia reversa como alternativa na elaboração de códigos mais
seguros.
1.3 JUSTIFICATIVA
Um dos principais motivos do estudo é descrever a engenharia reversa como algo
imprescindível na engenharia de software. Rever os conceitos que colaboram para o
uso perverso de suas técnicas na pirataria e a violação dos direitos autorais. A partir
desse conhecimento, propor alternativas que impeçam ou diminuam o acesso a
dados confidenciais, a reprodução de cópias ilegais e a invasão de sistemas.
1.4 OBJETIVOS
Para tal, este trabalho procura identificar alguns métodos que podem colaborar na
redução dos riscos. Apresentar a engenharia reversa como ferramenta de segurança
no desenvolvimento de software confiável. Identificar seus conceitos, assim como
seus aspectos legais; Examinar as falhas de segurança de software e suas
conseqüências; Levantar as técnicas de engenharia reversa e apresentar métodos
de proteção.
11
1.5 METODOLOGIA
Para alcançar o objetivo proposto, a metodologia adotada procura identificar na
literatura as falhas dos sistemas, apresentando os conceitos de engenharia reversa,
os métodos empregados na proteção de código dos programas, as técnicas e os
procedimentos empregados na engenharia de software que visam diminuir as
vulnerabilidades e aprimorar a segurança de software. Utiliza-se de livros, revistas,
manuais, dissertações e textos de internet sobre o assunto e suas co-relações, além
de citar alguns dos softwares e ferramentas disponíveis no mercado.
12
2 CONCEITOS E DEFINIÇÕES
Segundo Saleh e Boujarwah (1996), o mercado de software vem crescendo a cada
dia e com ele o uso de técnicas de desenvolvimento, muitas vezes informais. Como
resultado, a manutenção de tais softwares torna-se problemática, uma vez que a
documentação associada ao software, na maioria das vezes, não está de acordo
com o código implementado. Além disso, as constantes modificações e adições de
novas características ao software acarretam efeitos colaterais inesperados que não
estão presentes na documentação.
Dessa forma, quando diante da manutenção do produto, o engenheiro de software
encontra uma documentação informal e incompleta, que não reflete o software
existente, tornando impossível o gerenciamento do processo de manutenção
segundo Saleh e Boujarwah (1996). Neste contexto, a engenharia reversa de
software, tem o propósito de recuperar as informações de projeto perdidas durante a
fase de desenvolvimento, de documentar o real estado do software e poder auxiliar o
processo de gerenciamento da manutenção.
Rugaber (1992) afirma que a maior parte do esforço de desenvolvimento de software
é gasto na manutenção de sistemas existentes e não no desenvolvimento de
sistemas novos, e que grande parte do processo de manutenção é dirigido ao
entendimento do sistema em manutenção. Sendo assim, se queremos melhorar o
desenvolvimento de software, é necessário facilitar o processo de compreensão de
sistemas existentes. A engenharia reversa ataca diretamente o problema de
compreender o software.
Segundo Chikofsky e Cross II (1990) o termo engenharia reversa teve sua origem na
análise de hardware, onde a prática de decifrar o projeto de produtos prontos é
comum. O mesmo conceito pode ser aplicado a software, com uma diferença:
enquanto a engenharia reversa de hardware tem por objetivo reproduzir o sistema, a
de software se destina a criar visões do sistema em diferentes níveis de abstração,
facilitando seu entendimento com o principal objetivo de ajudar na manutenção do
sistema.
13
Uma definição de abstração é dada como a habilidade de se ignorar os aspectos de
assuntos não relevantes para o propósito em questão, tornando possível uma
concentração maior nos assuntos principais (Oxford, 1986).
Segundo Feltrim, V. D. (1999), o ciclo de vida do software expressa bem a diferença
entre níveis de abstração. Vale ainda ressaltar a existência de dois conceitos
relativos a abstração: nível e grau. Diferentes níveis de abstração ocorrem entre
diferentes etapas do desenvolvimento (as informações na etapa de projeto são
outras além das informações da etapa de análise), enquanto diferenças no grau de
abstração ocorrem dentro de uma mesma etapa (pode-se representar as
informações de uma mesma etapa do desenvolvimento de forma geral ou de forma
mais detalhada).
Segundo Harandi e Ning (HARANDI e NING, 1990), um sistema pode ser
visualizado a partir de diferentes níveis de entendimento. Baseado nos níveis de
abstração, as visões são classificadas em quatro categorias:
• Visão em nível implementacional: abstrai características da linguagem de
programação e, especificamente, da implementação. Exemplos de visões em
nível implementacional são informações a respeito da sintaxe e da semântica
da linguagem, e informações de implementação;
• Visão em nível estrutural: abstrai detalhes da implementação para revelar sua
estrutura a partir de diferentes perspectivas. O resultado é uma representação
explicita das dependências entre os componentes do sistema;
• Visão em nível funcional: abstrai a função de um componente do sistema de
modo a identificar o que o componente faz. Relaciona partes do programa à
suas funções a fim de revelar as relações lógicas entre elas;
• Visão em nível de domínio: abstrai o contexto em que o sistema está
operando, ou seja, relato o porquê do sistema ter sido desenvolvido.
Dessa forma, a engenharia reversa pode ser aplicada em qualquer etapa do ciclo de
vida, seja para recuperar níveis de abstração ou para fornecer uma nova visão em
14
um grau de abstração mais alto (é consenso de que quanto mais alto o grau de
abstração, menos detalhes são fornecidos.)
A engenharia reversa segue o sentido oposto ao da engenharia progressiva. A
engenharia progressiva segue a seqüência que vai desde os requisitos, passa pelo
projeto até a implementação. Na engenharia progressiva o sistema é o resultado do
processo de desenvolvimento. Na engenharia reversa, o sistema geralmente é o
ponto inicial do processo, conforme Chikofsky e Cross II (1990). A figura 1
representa esquematicamente, uma forma comparativa das direções inversas por
quais se orientam as etapas envolvidas em cada uma das engenharias. O processo
de engenharia reversa caracteriza-se pelas atividades retroativas do ciclo de vida,
que partem de um baixo nível de abstração para um alto nível de abstração.
Fig. 1 – Comparação dos níveis de abstração e das visões.
Existem várias definições de engenharia reversa. A definição de Pressman (1995,
p.546) diz que é o “processo de análise num esforço de criar uma representação do
programa em um nível de abstração mais alto que o código fonte”. Assim sendo,
pode-se dizer que o objetivo da engenharia reversa é a produção de informações
que possam aumentar o conhecimento geral de sistemas de software. Essas
informações podem ser utilizadas em atividades como manutenção, reuso, teste e
controle de qualidade de software.
15
A figura 2 ilustra a relação entre a engenharia progressiva e a engenharia reversa de
acordo com as fases do ciclo de vida do software, sendo que essas fases podem ser
agrupadas em três atividades fundamentais:
• Sistema (engenharia de sistemas): envolve o contexto em que o sistema está
operando, ou seja, o porquê do sistema ser desenvolvido;
• Requisitos (análise): são estabelecidos os serviços a serem fornecidos pelo
sistema e as restrições sob as quais ele deve operar, ou seja, o que o sistema
deve fazer e sob quais circunstâncias;
• Desenvolvimento (projeto, codificação e testes): cria-se um planejamento da
solução, ou seja, como o sistema cumprirá o que foi estabelecido na atividade
de requisitos e a implementação dessa solução, incluindo a codificação, os
testes, a depuração e a entrega do sistema. A fase de manutenção é vista
como reiteração das atividades prévias.
Fig. 2 – Relação entre a engenharia progressiva e a engenharia reversa.
Em Costa (1997) encontramos a definição de engenharia reversa como “o processo
de exame e compreensão do sistema existente, para recapturar ou recriar os
requisitos atualmente implementados pelo sistema, apresentando-os em um grau ou
16
nível mais alto de abstração. Não envolve mudanças no sistema ou criação de um
novo sistema”. Segundo Chikofsky e Cross II (1990), engenharia reversa de
software é um processo de investigação, não um processo de mudança ou
reprodução. Rugaber (1992) identifica o propósito da engenharia reversa como
sendo entender um sistema de software com o objetivo de facilitar atividades como:
expansão, correção, documentação, re-projeto ou reprogramação em outra
linguagem de programação.
Chikofsky e Cross II (1990) também identificam duas importantes categorias da
engenharia reversa: a redocumentação (visualização de código) e a recuperação de
projeto (entendimento de programa). A categoria redocumentação compreende a
criação ou revisão de uma representação semanticamente equivalente dentro de um
mesmo nível de abstração. Esse processo visa criar novas visões do sistema
através da análise do código fonte, com o objetivo de melhorar a compreensão do
sistema.
A criação dessas visões adicionais do código, geralmente gráficas, tem como
objetivo recriar a documentação que já existiu ou que deveria ter existido sobre o
sistema, conforme Costa (1997). No entanto, as informações recuperadas com esse
tipo de análise fornecem apenas visões estruturais, de forma que informações como
a função e os propósitos do sistema exigem um maior esforço de entendimento.
A engenharia reversa categorizada como recuperação de projeto é um subconjunto
da engenharia reversa no qual o domínio de conhecimento, informação externa e
dedução são adicionados às observações sobre o sistema para identificar
abstrações de mais alto nível que sejam significativas, além daquelas obtidas
diretamente pelo exame do sistema em si, segundo Biggerstaff (1989). Esse tipo de
processo de entendimento visa recuperar todas as informações necessárias para se
compreender melhor o que o sistema faz, como faz e porque o faz.
Recuperação de projeto é a forma mais critica de engenharia reversa porque tenta
recuperar não só a funcionalidade do sistema, mas o processo no qual ele foi
desenvolvido, conforme Costa (1997). Esse tipo de análise recupera mais do que
visões estruturais, obtendo visões funcionais e até mesmo de domínio.
17
3 ENGENHARIA REVERSA DE SISTEMA
Engenharia reversa de sistema envolve várias ferramentas e utiliza o sistema
operacional para obter informação, inspecionando programas executáveis. Pois toda
interação que um programa tem com o mundo externo tem que ir pelo sistema
operacional. Esta é a razão da necessidade em entender a operação do sistema.
Segundo Eilam, E. (2005), a Engenharia reversa de Código é uma arte. Conceitos
de extração de algoritmos de um programa binário é um processo complexo que
requer um domínio de várias técnicas acrescidas de um entendimento sólido de
desenvolvimento de software, da CPU, e do sistema operacional. O software pode
ser altamente complexo, até mesmo com acesso a programas bem escritos e
corretamente documentados, o código fonte é freqüentemente difícil de ser
compreendido.
Para isso observa-se o código de baixo nível, procurando detalhes de como o
software opera. Muitos destes detalhes são gerados automaticamente pelo
compilador e não manualmente pelo desenvolvedor de software.
3.1 SOFTWARE DE BAIXO NÍVEL
Segundo Eilam, E. (2005), o software de baixo nível (também conhecido como
software de sistema) é um nome genérico para a infra-estrutura do mundo de
software. Algumas ferramentas de desenvolvimento como compiladores, linkers, e
depuradores são software de infra-estrutura para operar sistemas e linguagens de
programação de baixo nível como a linguagem assembly. Esta é a camada que
separa o desenvolvedor de software e aplicação do hardware físico. As ferramentas
de desenvolvimento separam o desenvolvedor de software de arquiteturas de
processador e da linguagem assembly, enquanto sistemas operacionais separam o
desenvolvedor de software de dispositivos de hardware específicos e simplifica a
interação com o usuário final, administrando a exibição, o mouse, o teclado, e assim
por diante.
18
Antigamente, os programadores sempre tiveram que trabalhar no baixo nível porque
era o único modo possível para escrever software de infra-estrutura de baixo nível.
Hoje em dia, sistemas operacionais modernos e ferramentas de desenvolvimento
ocultam os detalhes do mundo do baixo nível. Isto simplifica profundamente o
processo de desenvolvimento de software, porém à custa da redução do poder e
controle geral do sistema.
Para se tornar um engenheiro reverso pleno, é preciso desenvolver um sólido
conhecimento de software de baixo nível e programação de baixo nível. Isso porque
os aspectos de baixo nível de um programa freqüentemente permitem o domínio dos
detalhes de engenharia reversa de alto nível.
A maioria dos desenvolvedores de software usa a linguagem de alto-nível que é de
fácil compreensão. Por exemplo, comandos que criam uma janela, carregam uma
página de Web, ou exibem um quadro é inacreditavelmente simples, enquanto o
significado disso é traduzido em milhares ou até mesmo milhões de comandos nas
mais baixas camadas. Engenharia reversa requer um entendimento sólido destas
mais baixas camadas. Para tanto, tem que estar literalmente atento a qualquer coisa
que se coloca entre a fonte de programa e a CPU.
3.2 LINGUAGEM ASSEMBLY
Segundo Eilam, E. (2005), a linguagem assembly é o mais baixo nível na cadeia de
software possibilitando inacreditavelmente satisfazer a engenharia reversa. Se o
software executa uma operação, deve ser visível no código de linguagem assembly.
Esta é a linguagem da engenharia reversa, seu domínio requer do desenvolvedor
um entendimento sólido da linguagem assembly na plataforma escolhida.
Outro conceito importante do código de máquina (freqüentemente chamado de
código binário ou código de objeto). As pessoas às vezes cometem o erro de
pensar que o código de máquina é "mais rápido" na linguagem assembly. Isso é um
19
engano, código de máquina e linguagem assembly são duas representações
diferentes da mesma coisa. ACPU lê código de máquina, que nada mais é que uma
sucessão de pedaços que contêm uma lista de instruções para a CPU executar.
Em vez de números de hexadecimal secretos nós podemos ver em instrução textual
nomes como MOV (Mova), XCHG (Troca), e assim por diante. Cada comando de
linguagem assembly é representado por um número, chamando o código de
operação, ou opcode. Código de objeto é essencialmente uma sucessão de opcodes
e outros números estão relacionados a opcodes para executar operações.
CPU’s constantemente lêem código de objeto de memória, decodifica-o, e agem
baseados em instruções embutidas. Quando o desenvolvedor escreve código em
linguagem assembly (uma ocorrência bastante rara estes dias), eles usam um
programa de montador para traduzir o código de linguagem assembly textual em
código binário que pode ser decodificado por uma CPU. Na outra direção, um
disassembler faz o oposto exato. Lê código de objeto e gera o textual traçando cada
instrução nela. Esta é uma operação relativamente simples para executar porque a
linguagem assembly textual simplesmente é uma representação diferente do código
de objeto. Disassembler é uma ferramenta fundamental para a engenharia reversa.
3.3 COMPILADORES
Segundo Eilam, E. (2005), um arquivo de texto que contém instruções que
descrevem o programa em um alto-nível de linguagem é produzido pelo compilador.
O compilador é um programa que lê um arquivo fonte e gera um arquivo de código
de máquina correspondente. Dependendo do alto-nível da linguagem, este código
de máquina pode ser um objeto de plataforma específica que é decodificado
diretamente pela CPU ou pode ser codificado em uma plataforma especial
independente chamado bytecode.
Compiladores tradicionais usam linguagens de programação como C e C++
diretamente para gerar código objeto de máquina legível a partir do código fonte
20
textual. O que isto significa é que o código de objeto resultante, quando traduzido
pela linguagem assembly por um disassembler, é essencialmente um programa de
máquina gerado. Claro que, não é completamente nenhum código de máquina,
porque o desenvolvedor de software descreveu ao compilador o que precisada ser
feito na linguagem de alto-nível.
A barreira maior em decifrar código gerado pelo compilador é a otimização aplicada
pela maioria dos compiladores modernos. Compiladores empregam uma variedade
de técnicas, isso minimiza o tamanho de código e melhora o desempenho da
execução. O problema é que o código aperfeiçoado é freqüentemente difícil de ler.
Por exemplo, ao aperfeiçoar os compiladores substituem instruções com operações
matemáticas equivalentes cujo propósito pode estar longe do óbvio à primeira vista.
3.4 MÁQUINAS VIRTUAIS E BYTECODES
Segundo Eilam, E. (2005), compiladores para linguagem de alto-nível como Java
geram um bytecode em vez de um código de objeto. Bytecodes são semelhantes a
códigos, a não ser que eles sejam decodificados por um programa, em vez de uma
CPU. A idéia é ter um compilador que gere o bytecode, e usar um programa
chamando a máquina virtual para então decodificar o bytecode e executar as
operações descritas nele. Claro que, a máquina virtual terá que converter em algum
ponto o bytecode em código de objeto, que é compatível com a CPU subjacente.
Há vários benefícios em usar a linguagem baseada em bytecode. Uma vantagem
significativa é a independência de plataforma. A máquina virtual pode ser instalada
em plataformas diferentes que habilitam o mesmo programa binário em qualquer
CPU, contanto que tenha uma máquina virtual compatível. Claro que,
indiferentemente da plataforma na qual a máquina virtual está executando
atualmente, o bytecode formado fica o mesmo. Isto significa teoricamente que o
desenvolvedor de software não precisa se preocupar sobre a compatibilidade de
plataforma. Tudo que eles têm que fazer são prover os clientes com uma versão de
bytecode do programa deles.
21
3.5 SISTEMAS OPERACIONAIS
Segundo Eilam, E. (2005), um sistema operacional é um programa que administra o
computador, incluindo o hardware e aplicações de software. Um sistema operacional
tem o controle de muitas tarefas diferentes e pode ser visto como um tipo de
coordenador entre diferentes elementos em um computador. Sistemas operacionais
são fundamentais em um computador, tanto que a engenharia reversa necessita do
conhecimento profundo do que eles fazem e como eles trabalham.
3.6 DISASSEMBLERS
Segundo Eilam, E. (2005), disassemblers são programas que transformam um
programa executável em arquivos textuais que contêm código de linguagem
assembly de um programa inteiro ou partes dele. Isto é um processo relativamente
simples considerando que código de linguagem assembly é a cartografia textual do
código de objeto. Um disassembler de alta qualidade é um componente fundamental
no kit de ferramentas da engenharia reversa, contudo alguns preferem usar
disassemblers embutidos em certos depuradores de baixo nível.
3.7 DEPURADORES
O depurador é um programa que permite ao desenvolvedor de software observar o
programa enquanto está funcionando. As características básicas do depurador são a
habilidade para fixar pontos de ruptura e a habilidade para localizar por código.
Pontos de ruptura permitem os usuários selecionar certa função ou linha de código
em qualquer lugar dentro do programa e instrui o depurador para interromper a
execução do programa uma vez que esta linha é alcançada. Quando o programa
alcança o ponto de ruptura, o depurador pára e exibe o estado atual do programa.
Neste ponto, é possível iniciar o depurador e o programa continuará executando ou
começar a traçar o programa.
22
Depuradores permitem aos usuários localizar por um programa enquanto estiver
executando. O programa executa uma linha de código e então gerada, permite o
usuário observar ou até mesmo alterar o estado do programa. O usuário pode
executar a próxima linha então e pode repetir o processo. Isto permite ao
desenvolvedor ver o fluxo exato de um programa.
Instalando pontos de ruptura e localizando por programas, o desenvolvedor pode
assistir a um programa de perto, como executa uma seção problemática de código e
tentar determinar fontes do problema. Os depuradores apresentam o programa em
código fonte, e permitem ao desenvolvedor fixar pontos de ruptura e localizar por
linhas, embora o depurador esteja trabalhando de fato com o código de máquina,
segundo Eilam, E. (2005).
3.8 DECOMPILADOR
O decompilador está a um passo acima do disassembler. Um decompilador
transforma um arquivo binário executável em linguagem de alto nível. A idéia é
tentar reverter o processo de compilação, obter o arquivo de fonte original ou algo
semelhante. Na maioria das plataformas, a recuperação atual do código fonte
original não é realmente possível. Existem elementos significantes na maioria das
linguagens de alto-nível, porém são omitidos no processo de compilação e é
impossível recuperar. Decompiladores são ferramentas poderosas que em algumas
situações e ambientes podem reconstruir um código fonte altamente legível de um
programa binário, segundo Eilam, E. (2005).
23
4 ASPECTOS LEGAIS
A engenharia reversa pode também gerar problemas de legalidade, como uma
empresa querendo criar uma cópia de um produto que vende bem. No entanto, a
questão legal depende das leis de cada país. E, mesmo assim, ainda existem países
que não possuem leis específicas sobre o assunto.
O debate legal ao redor de engenharia reversa acontece há vários anos. Isto
normalmente revolve ao redor da pergunta de qual o impacto social e econômico a
engenharia reversa está causando na sociedade como um todo. Claro que, para
calcular este tipo de impacto, em grande parte, depende de como a engenharia
reversa é usada. As seguintes seções discutem os aspectos legais dessas
aplicações, com uma ênfase nos Estados Unidos , segundo Eilam, E. (2005). Porém
nota-se a dificuldade em afirmar quando tal procedimento é legal ou não, pois
depende de muitos fatores.
4.1 COMPATIBILIDADE
Em tecnologia, especialmente em informática (independentemente de plataforma), é
dito de um produto que este possui compatibilidade reversa (ou compatibilidade
descendente) quando é capaz de assumir o lugar de um produto mais antigo,
interagindo com outros produtos que foram desenhados para funcionar com a
versão anterior.
Segundo Eilam, E. (2005), a engenharia reversa utilizada para tal finalidade produz
vários benefícios, simplificando o processo de desenvolvimento e melhorando as
tecnologias existentes. Todavia, quando usada como ferramenta de competição de
produtos, a situação torna-se mais complexa. Por exemplo, o roubo de segmentos
de códigos dos concorrentes e sua reprodução integral demonstram claramente a
violação dos direitos autorais. Entretanto, quando se utiliza de métodos de
24
descompilação de programas e recompilação com funcionalidades idênticas mas
com códigos diferentes, torna-se mais difícil sua comprovação.
Uma das leis mais conhecidas é o “Digital Millenium Copyright Act, (DMCA)” dos
Estados Unidos, aprovado em 1998 que, entre várias medidas para proteger direitos
autorais na informática, também faz restrições em relação à engenharia reversa. O
DMCA considera proibido:
• Burlar sistemas protegidos por direitos autorais: Isto significa que uma pessoa
não pode burlar a tecnologia do Digital Rights Management (DRM), até
mesmo para uso pessoal.
• O desenvolvimento de tecnologias de alteração: Isto significa que uma pessoa
não pode desenvolver ou possa disponibilizar qualquer produto ou tecnologia
que iluda uma tecnologia de DRM. Exemplo, um programa de keygen. Na
realidade, uma pessoa que desenvolve um keygen viola esta seção, e uma
pessoa que usa um keygen viola o item anterior.
Um keygen é um programa que gera um número de série rapidamente para
programas que pedem números consecutivos durante a instalação. Keygens estão
(ilegalmente) disponíveis on-line para praticamente qualquer programa que requer
um número de série.
Afortunadamente, o DMCA faz várias exceções nas quais a engenharia reversa é
permitida. São isenções providas pelo DMCA:
• Compatibilidade: inverter e evitar tecnologias de DRM podem ser permitidas
em circunstâncias onde tal trabalho é necessário para a compatibilidade com
o produto de software em questão. Por exemplo, se um programa foi
codificado com a finalidade de proteção de cópia, um desenvolvedor de
software pode decifrar o programa em questão se o único objetivo for a
compatibilidade com o mesmo.
• Investigação de encriptação: está é uma cláusula altamente restringida no
DMCA, que permite os investigadores de tecnologias de encriptação para
evitar tecnologias de proteção de direitos autorais em produtos de
25
encriptação. A reversão só é permitida se as tecnologias de proteção
interferem com a avaliação da tecnologia de encriptação.
• Teste de segurança: Uma pessoa pode inverter e pode evitar proteção de
direitos autorais de software com a finalidade de avaliar ou melhorar a
segurança de um sistema de computador.
• Instituições educacionais e bibliotecas públicas: Estas instituições podem
evitar uma tecnologia de proteção de direitos autorais para avaliar o trabalho
registrado antes de comprá-lo.
• Investigação de governo: Não surpreendentemente, as agências de
investigações do governo não são afetadas pelo DMCA.
• Regulamento: Podem ser evitadas Tecnologias de DRM com o propósito de
regular os materiais acessados por menores na Internet. Assim, um produto
teórico que não permite monitoração dos acessos e navegação na Internet,
pode ser burlado com a finalidade de controlar seu uso por menores.
• Proteção de privacidade: Produtos que armazenam ou transmitem informação
pessoal pode ser revertido e qualquer tecnologia de proteção que eles
incluem pode ser alterada.
Na União Européia, o “Eu Copyright Directive”, de 2001, é similar ao “Digital
Millenium Copyright Act”, porém não é tão restritivo. Só são feitas restrições caso o
objetivo final da engenharia reversa seja a cópia de algum programa ou quebra de
patente com objetivo de lucro. Caso seja para fins acadêmicos ou de
compatibilidade, à princípio não existem restrições. Entretanto, alguns países partem
do princípio de que o software comprado é propriedade particular e, portanto, pode
ser alterado como qualquer outra manufatura.
Na Suíça, a lei a respeito do assunto é bastante curiosa e, de certo modo, polêmica.
A lei Suíça de Concorrência Desleal de 1986 exige dos competidores a realização
de investimentos em engenharia reversa mesmo quando a tecnologia não seja
secreta. Os tribunais suíços, porém, têm rejeitado ou limitado severamente a
aplicação de tal norma, pela inexistência de prazo e limites.
26
No Japão, a Lei Japonesa de Concorrência Desleal de 1993 proíbe a imitação servil,
mesmo no caso de produtos não patenteados, nem protegidos por direitos autorais.
A lei japonesa impõe limites claros à aplicação da norma de apropriação ilícita: o
“lead time” vigora apenas por três anos; não se protegem as idéias e os conceitos
técnicos; e ressalva-se o caso de modificações ou aperfeiçoamento técnico efetuado
pelo competidor com base no item copiado; a necessidade de padronização e
compatibilização de produtos e o uso de elementos de caráter estritamente
funcional. Ou seja, a proibição de imitação não impede o progresso técnico, ressalva
o domínio das patentes para proteger idéias e conceitos, e o interesse social na
padronização e compatibilização industrial.
No Brasil não existe uma lei específica sobre Engenharia Reversa. Apesar disso,
quando ocorre costuma-se proceder de duas maneiras: caso a engenharia reversa
não tenha como objetivo a pirataria ou infração de algum direito autoral, não é
considerado crime; porém caso contrário, a Lei N. 9.609, de 19 de fevereiro de 1998
(Lei de Software) e também a Lei N. 9.610 de Direitos Autorais de 1998 protege
seus autores.
4.2 SÃO PONTOS FUNDAMENTAIS DA LEI DE SOFTWARE:
Segundo Júnior, J. B. (2006), a definição de “programa de computador” está no
artigo primeiro da lei; O regime de proteção dos direitos de autores de programas de
computador, conforme o artigo 2º da lei, é o mesmo das obras literárias; Não há
discussão sobre danos morais quanto ao uso irregular de softwares, ressalvado ao
proprietário o direito de fazer cessar as alterações que seu software tenha sofrido ou
venha sofrendo; A tutela dos direitos autorais sobre software é por 50 anos, a partir
de 1º de janeiro do ano subseqüente à publicação ou criação do software; A
proteção aos direitos independe de registro do software;
Há reciprocidade de reconhecimento de direitos aos estrangeiros domiciliados no
exterior, desde que seu país também reconheça os mesmos direitos em relação aos
brasileiros e estrangeiros domiciliados no Brasil; Ao autor também cabe o direito
27
exclusivo de autorizar ou proibir o aluguel comercial de seu software (aplicável
somente aos softwares cujo objeto do contrato não seja a locação em si); Os
programas de computador poderão ser registrados em órgãos competentes; As
informações para registro do programa de computador deverão ser capazes de
identificá-lo, e são de caráter sigiloso, sendo reveladas apenas em razão de
interesse do proprietário dos direitos ou por ordem judicial; segundo Júnior, J. B.
(2006).
A cópia de um só exemplar para salvaguarda não é considerada ofensa a direitos
autorais. Portanto, se em nossa empresa possuímos 10 licenças legalmente
adquiridas de Windows, podemos ter também 10 cópias (uma de cada licença), e
isso não será considerado ilegal. Atenção: essas cópias de salvaguarda não
poderão estar instaladas, sob pena de violação de direitos autorais;
Em resumo, podemos dizer que a lei de direitos autorais – no tocante à área de
informática – veio delimitar a ação criminosa e trazer as sanções civis aplicáveis ao
contrafator (nome técnico do “pirata”). O processo de verificação de violação de
diretos autorais usará sempre a lei de software como base, eis que o objeto
perseguido é a proteção de direitos de autor de programa de computador. Segundo
Júnior, J. B. (2006), ele será, também, baseado na lei de direitos autorais, eis que
esta define o que é o ato de contrafação (artigo 5º), assim como a multa civil
aplicável ao contrafator em favor do autor lesado.
4.3 FALHAS DE SEGURANÇA
4.3.1 Um pouco de história
Anos atrás, os operadores de um computador ENIAC se depararam com uma coisa
curiosa. Um inseto havia ficado preso dentro da máquina e estava atrapalhando o
funcionamento da mesma. Daí surgiu o termo bug (inseto) que virou sinônimo de
28
falha. Hoje quando se descobre um erro em algum programa, se diz: “novo bug
descoberto”. De lá pra cá, as coisas evoluíram muito, mas os bugs continuam a
existir. Muitos deles são frutos da história do próprio programa ou sistema. O
Windows por exemplo. O Windows NT foi construído a partir do zero, mas o
Windows ME não. Desde o início da criação de sua primeira interface gráfica, a
Microsoft vêm tendo problemas com erros graves em seu sistema operacional. Já o
sistema Unix, foi criado pelos desenvolvedores da linguagem C, para ser um sistema
versátil e poderoso.
Para Assunção, M. F. A. (2001), a Internet também têm seus problemas ligadas à
história de sua origem. Desde que se chamava Arpanet e foi criada pelo exército
americano para resistir à guerra fria, a rede evoluiu muito e foram criados novos
serviços como E-mail, World Wide Web, Gopher, Wais e outros. Milhões de
computadores se juntaram a ela e seus recursos são cada vez mais sofisticados.
Mas alguns problemas bem antigos ainda são perturbadores hoje. Uma falha na
implementação do TCP/IP (conjunto de protocolos em que a Internet se baseia), por
exemplo, possibilita que o ataque de Spoof aconteça.
4.3.2 Alguns conceitos importantes
Hackers: Alguém que estuda sistemas ou qualquer tipo de conhecimento humano
pelo simples desafio de dominá-los. No sentido original da palavra, o Hacker é
alguém que usa seus conhecimentos para ajudar outros, direta ou indiretamente.
Hackers foram os principais responsáveis pelo desenvolvimento da Internet, criaram
o Linux, o MP3 e a filosofia do software livre. Atualmente o termo vem sendo muito
usado em relação aos Crackers, segundo Morimoto, C.E. (2005).
Crackers: O cracker é um vândalo virtual, alguém que usa seus conhecimentos para
invadir sistemas, quebrar travas e senhas, roubar dados, etc. Alguns tentam ganhar
dinheiro vendendo as informações roubadas, outros buscam apenas fama ou
divertimento. Na hierarquia Hacker, o Cracker está acima do Lamer (que sabe muito
pouco), mas abaixo do Hacker, que é alguém de mais maturidade, que ao invés de
29
usar seu conhecimento para destruir tudo que vê pela frente, o utiliza para construir
coisas, desenvolver novos sistemas (principalmente de código aberto), etc.
Para Morimoto, C.E. (2005), outra definição, mais branda, é alguém que quebra
travas de segurança de programas e algoritmos de encriptação, seja para rodar
jogos sem o CD-ROM, ou gerar uma chave de registro falsa para um determinado
programa, quebrar as travas anti-cópias usadas em alguns softwares ou quebrar o
sistema de encriptação do DVD (este último realmente importante, pois permitiu que
os usuários do Linux e outros sistemas não Windows pudessem assistir DVDs). Ou
seja, nesta definição o Cracker é alguém na margem da lei, cujas ações ainda são
ilegais, embora muitas vezes eticamente justificáveis (os usuários têm direito a fazer
cópias de CDs legalmente comprados, tem direito de assistir DVDs no Linux e assim
por diante).
Trojans: O nome trojan é uma alusão à história do antigo cavalo de tróia, em que o
governante da cidade de Tróia na antiga Grécia foi presenteado com um cavalo de
madeira “recheado” de soldados inimigos, segundo Assunção, M. F. A. (2001).
Possui muitas características similares aos vírus, tais como: perda de arquivos,
falhas na memória, erros em periféricos, etc. A grande diferença é que o trojan pode
ser considerado um vírus inteligente, pois é controlado à distância pela pessoa que o
instalou. Esse indivíduo então consegue “enxergar” o seu computador, podendo
realizar desde as mais simples tarefas como mexer o mouse à utilização do seu IP
como ponte para outros ataques. Conseguem ficar escondidos em arquivos de
inicialização do sistema operacional e se iniciam toda vez que a máquina é ligada.
Sniffers: Os sniffers ou farejadores são os tipos de programas mais usados para
conseguir senhas em uma rede. Eles ficam residentes na memória como um cavalo
de tróia, analisando todo o tráfego que ali passa. Qualquer entrada ou saída de
dados é capturada, seja em um servidor FTP, uma página de chat ou um e-mail
digitado. O sniffer captura os pacotes recebidos em seu estado bruto e os
transforma em texto puro para serem lidos. Sempre foram mais usados em sistemas
Unix, mas ultimamente todos os outros sistemas contam com poderosos sniffers,
segundo Assunção, M. F. A. (2001).
30
Syn-flood: O tipo de ataque usado para gerar o ip spoof. A autenticação por Syn é
feita em três vias. Para Assunção, M. F. A. (2001), o ataque consiste em não
completar essas três vias. Mais ou menos assim. No caso do ping, ele é em duas
vias, apenas envia o pacote e recebe a resposta. Para o Syn-flood, primeiro é
enviado o pacote Syn e logo depois teria que ser enviado o Ack para a conexão se
estabelecer, mas ele não é enviado, fazendo com que a máquina alvo consuma
seus recursos ao receber muitos Syns e esperar muitos Acks. O ataque por ping é
parecido, é enviado vários pings com grandes pacotes fazendo com que um sistema
trave. Mas é mais difícil de ocorrer o travamento do que o ataque por syn.
OOB: Ataque Out-of-Band ou popularmente conhecido como WinNuke. Consiste em
mandar pacotes malformados para uma porta Netbios do Windows. Geralmente
usado nas portas 135, 137 e 139, essa última sendo a mais usada. O sistema não
consegue lidar com os pacotes, trava e mostra a famosa tela azul de erro. No
Windows 95 esse ataque era mais eficaz, agora está se tornando obsoleto.
Smurf: Enviam pacotes ICMP (protocolo que informa condições de erro) spoofados
para centenas, talvez milhares de sites. Enviam-se os pacotes com o endereço IP da
vítima, assim fazendo com que ela receba muitos pacotes ping de resposta ao
mesmo tempo, causando um travamento total. Ainda não existe uma proteção eficaz
contra esse tipo de ataque. Um programa bom (para Windows) que realiza o smurf é
o WinSmurf, conforme Assunção, M. F. A. (2001).
Scanners: São programas que analisam um sistema ou rede em busca de falhas de
qualquer tipo. Existem dezenas de scanners diferentes, cada um com suas
vantagens. Aprendendo melhor sobre eles, poderá se proteger melhor e evitar que
algum invasor malicioso dê um passo à sua frente.
Senhas: Serve para autenticar o usuário, ou seja, é utilizada no processo de
verificação da identidade do usuário, assegurando que este é realmente quem diz
ser.
Engenharia social: Método de ataque, onde alguém faz uso da persuasão, muitas
vezes abusando da ingenuidade ou confiança do usuário, para obter informações
31
que podem ser utilizadas para ter acesso não autorizado a computadores ou
informações, segundo Vale e Ulbrich, (2004).
Vulnerabilidades: É uma falha no projeto ou implementação de um software ou
sistema operacional, que quando explorada por um atacante resulta na violação da
segurança de um computador, para Eilam, E. (2005).
Criptografia é a arte da escrita oculta usada desde a antiguidade, por exemplo:
pelos egípcios na sua antiga escrita. Ela é muito importante hoje em dia na internet.
Mandar um e-mail confidencial da maneira convencional é muito inseguro, ele pode
ser interceptado no meio da transmissão ou posteriormente, por isto a necessidade
do uso de programas eficientes, como o PGP. Esses programas possibilitam uma
espécie de “código especial” entre você e o receptor da mensagem, fazendo com
que mesmo que alguém consiga obtê-la no meio do caminho, ela será impossível de
se ler, segundo Assunção, M. F. A. (2001).
4.3.3 Chaves públicas e privadas
Em Assunção, M. F. A. (2.001), na década de 1970 o padrão na criptografia era a
criptografia simétrica onde existia uma única chave (senha) para encriptar e
desencriptar, tanto para o emissor quanto para o destinatário. O grande problema
desse método era como transmitir com segurança esta senha.
No final da década de 70 foi desenvolvido o método da criptografia assimétrica e a
tecnologia das chaves pública e privada. Você encriptava com a chave pública do
destinatário e somente ele poderia desencriptar utilizando a sua chave privada e
também haveria como saber com certeza absoluta se a pessoa que mandou a
mensagem era realmente quem dizia ser, segundo Soares et al. (1995).
Um sistema computacional é dito seguro se este atende a três requisitos básicos
relacionados aos recursos que o compõem: confidencialidade, integridade e
disponibilidade.
32
A confidencialidade diz que a informação só está disponível para aqueles que
devidamente autorizados; a integridade diz que a informação não é destruída ou
corrompida e o sistema tem um desempenho correto, e a disponibilidade diz que o
serviços/recursos do sistema estão disponíveis sempre que forem necessários.
Todos os sistemas têm falhas, segundo Assunção, M. F. A. (2001). Elas consistem
em pequenos erros na criação dos programas, possibilitando que crackers os
utilizem para tomar o controle de alguma máquina. Existem em absolutamente todo
tipo de software, desde um simples tocador de mp3, um aparentemente inofensivo
editor de texto, um jogo de computador e até mesmo o próprio sistema operacional.
Essas falhas por mais insignificantes que pareçam, podem comprometer a
segurança de uma rede inteira. E a maior de todas as falhas é o desinteresse dos
muitos administradores de hoje que acham que o termo bug é algum desenho do
Walt Disney.
O bug, ou falha, surge a partir do momento que o programador comete um erro. Ou
seja, indiretamente é um erro humano que gera a falha nos programas. Por serem
pequenos erros e não aqueles cabeludos que fazem o compilador até rir do
programador, muitas vezes passam despercebidos e só são descobertos por algum
hacker ou analista de segurança. Os erros do Windows, por exemplo. A grande
maioria das falhas descobertas são os próprios usuários que descobrem. Os
criadores que têm o código fonte e conhecem o programa como a palma da mão
raríssimas vezes percebem algum erro. Para ser mais seguro, um programa têm que
ser testado de todas as maneiras possíveis. Algo que nem sempre é feito.
4.3.4 Exemplos de falhas
Algumas falhas são tão bobas que é difícil de acreditar. Geralmente, no sistema
Windows, que de longe é o que possui mais falhas. O Windows 98 possui muitos
erros, mas três são interessantes. O primeiro é que não consegue executar nem
abrir nenhum link com a url c:\con\con. Se você tentar ir em iniciar e executar, o
33
sistema travará e mostrará a famosa tela azul. Os outros dois são do netbios. O
primeiro possibilita que você acesse o diretório system do Windows por um
compartilhamento de impressora. É só mapear o compartilhamento padrão printer$.
O último possibilita que se descubra a senha do netbios sabendo apenas o primeiro
caractere. Por exemplo: coloca-se no disco C compartilhado a senha herodes. Se
alguém tentar o primeiro h já consegue acesso à rede. O Windows 2000 também
possui algumas falhas, como deixar o netbios ativo em sua instalação. Saindo um
pouco dos sistemas operacionais, alguns programas também possuem falhas
graves, segundo Assunção, M. F. A. (2001).
Erros de Active X possibilitam que ao visitar um site, o Internet Explorer instale um
programa no seu computador e o execute sem ser percebido. Outro erro está no
anexo de e-mail. Erros no Outlook fazem com que só de receber os e-mails, os
anexos sejam executados automaticamente. O Internet Information Server, servidor
de homepages da Microsoft, possui erros graves. Unicode, RDS, existem muitos. O
mais recente é uma falha no printer .isapi , fazendo com que se consiga acesso ao
Windows 2000 pelo IIS 5.0 . O sistema Unix possui muitas falhas também, como no
sendmail e no Apache.
4.3.4.1 Buffer overflows
O buffer overflow é um ataque usado há muito tempo e que ainda será muito usado.
Compreende em lotar os buffers (memória disponível para aplicativos) de um
servidor e incluir na sua lista de processos algum programa tal como um keylogger
ou um trojan. Todos os sistemas são vulneráveis a buffer overflows e a solução é a
mesma, procurar se já existem correções existentes. Novos erros desse tipo surgem
todo dia, até o XP já têm alguns. A atualização do software deve ser contínua.
Segundo Assunção, M. F. A. (2001), um dos usos famosos do buffer overflow é o
telnet reverso. Ele consiste em fazer a máquina alvo conectar-se a um servidor no
computador do cracker, fornecendo-lhe um shell (prompt) de comando. O netcat,
chamado de “canivete suíço do TCP/IP”, é uma espécie de “super-telnet”, pois
34
realiza conexões por UDP, serve como servidor, entre outras tarefas. Ele é o mais
utilizado para a realização do telnet reverso, e pode ser usado tanto na arquitetura
NT quanto no Unix. A versão para Windows está disponível em ftp.technotronic.com
.
A exploração de código vulnerável a buffer overflow exige alguma habilidade.
Entretanto, o conhecimento necessário para tal tarefa pode ser facilmente adquirido
pelo material difundido na rede e experimentação exaustiva. A tarefa de codificar
software seguro é difícil, mas deve ser tomada com máxima seriedade.
Principalmente quando se está desenvolvendo software de segurança ou projetado
para ser executado com privilégios de super-usuário ou usuário especial do sistema.
Chega a impressionar o número de vulnerabilidades a buffer overflow encontradas
em software de utilização ampla, dada a simplicidade das técnicas em evitá-las.
4.3.4.2 Race condition
O Race condition ou condição de corrida é mais comum no Unix e no Linux.
Consiste em fazer algum programa que rode como root (super-usuário) executar
alguma falha que possa lhe enviar para o shell do sistema. O programa que mais
teve problemas de race condition até hoje é o sendmail , serviço de e-mail padrão do
Unix. É possível encontrar falhas até em versões mais recentes.
4.3.4.3 Descobrindo se algum sistema tem falhas
Segundo Assunção, M. F. A. (2001), para o programador experiente é mais fácil
verificar se um sistema tem falhas, utilizando de recursos de debug que checam por
erros de buffer overflow e outros. Para o usuário é bem mais difícil descobrir algo,
principalmente o usuário comum. O interessante seria visitar páginas especializadas
no assunto, que a cada dia publicam novos tipos de erros descobertos.
35
Scanners de vulnerabilidade (ou falhas).
• Typhon (Só funciona em Windows NT/2000/XP): esse scanner é excelente
pois é rápido e dá algumas informações muito boas sobre possíveis falhas e
desconfigurações do sistema alvo. Não é muito completo, mas é o ideal para
se usar antes do Stealth, que como veremos, é inigualável.
• Stealth: um dos melhores scanner de vulnerabilidades. É um programa de
uma empresa brasileira, já ganhou destaque internacional pois consegue
identificar cerca de 15.000 falhas em sistemas. Poucos conseguem escapar
ilesos a essa potente arma.
4.3.4.4 Utilizando exploits
Exploits são programas criados para explorar falhas. O exemplo do printer .isapi do
IIS 5.0 mencionado anteriormente, possui um exploit chamado iishack2000. Ele
possibilita que somente digitando o IP de algum computador, seja possível conseguir
acesso direto ao interpretador de comandos (ou shell). Permitindo fazer o que
quiser com o sistema. Existe também o iishack (sem o 2000), que utiliza um erro de
buffer overflow do IIS 4.0 para fazer com que o servidor execute qualquer tarefa
(como um trojan). Cada exploit corresponde a uma falha, por isso geralmente os
grandes sites de segurança publicam os dois juntos. Geralmente vêm em código-
fonte C, Perl e alguns poucos em executáveis comuns, segundo Assunção, M. F. A.
(2001).
4.3.4.5 Instalando patches
Os patches são atualizações de programas geradas pelos fabricantes. Toda vez que
um erro for descoberto, deve-se visitar a página do fabricante do programa e baixar
a correção. Conforme Assunção, M. F. A. (2001), isso não pode ser feito de mês em
mês, e sim no máximo de três em três dias. Os erros aparecem muito rapidamente,
e um sistema é composto de muitos softwares. Todos devem ser checados. É
36
interessante também assinar uma lista de discussão sobre segurança, assim toda
vez que uma falha for descoberta, serão enviados e-mail’s para alertar. A Microsoft
(www.microsoft.com), a Securenet (www.securenet.com.br) e Security-focus
(www.securityfocus.com) possuem algumas. O fato é que até mesmo com o código
fonte às vezes pode ser difícil de distinguir código seguro inofensivo de
vulnerabilidades de segurança perigosas.
37
5 TÉCNICAS DE ENGENHARIA REVERSA
5.1 TÉCNICAS DE ENGENHARIA REVERSA SEM O CÓDIGO-FONTE
Segundo Anquetil, N. (2002), a engenharia reversa de software pode ser efetuada
por vários métodos.Três grupos principais da engenharia de software são:
• Análise de fluxo de dados: Análise através da observação da troca de
informações que envolvem “analisadores de bus” e “pacotes de sniffers”, por
exemplo, para "ouvir" dentro do bus de um computador ou uma conexão de
rede, revelando o tráfico de dados "escondidos".
O comportamento dos dados no bus ou na rede podem então ser analisados
para produzir uma nova implementação do software que imita o mesmo
comportamento. Isto é especialmente utilizado na engenharia reversa de
drivers de dispositivos.
• Desassemblar: Usando um desassembler, conseguimos obter a linguagem de
máquina diretamente do programa. Este código é lido e entendido nos seus
próprios termos, apenas com a ajuda de “mnemonics” da linguagem de
máquina. Isto funciona em qualquer programa de computador, mas pode levar
um bom tempo, especialmente para alguém que não esteja acostumado ao
código de máquina.
• Decompilação: Neste método utiliza-se um decompilador, um programa que
tenta recriar o código-fonte em uma linguagem de alto nível, tendo disponível
apenas o código de máquina.
38
5.2 TÉCNICAS DE ENGENHARIA REVERSA COM O CÓDIGO-FONTE
5.2.1 Extração das Informações
O primeiro trabalho que se deve fazer é coletar informações sobre o sistema a ser
estudado. As atividades da engenharia reversa se fazem sobre essas informações
extraídas, mais do que sobre o próprio sistema.
As informações podem ser extraídas de várias fontes: o código fonte, a execução, os
dados (por exemplo, em banco de dados), a “documentação”, ou outras fontes.
5.2.1.1 Código (análise estática)
A primeira fonte, o código, é a mais usada. A análise do código é chamada também
de análise estática (por oposição à análise dinâmica que é a execução do sistema).
Ela permite extrair as informações mais básicas do sistema:
• Quais são os componentes básicos do sistema: arquivos, rotinas, tipos,
variáveis, classes, etc.;
• Relações de definição conectam um componente com seu conteúdo (onde ele
se encontra);
• Relações de referência conectam um componente com aqueles que o usam
(se uma rotina A chamar uma outra rotina B. A depende de B porque uma
modificação na definição de B pode ter conseqüências sobre a execução de
A).
Essas relações podem ser memorizadas como as relações de definição/referência.
Na extração das informações, gravam-se apenas as informações que vem
diretamente do código, mas depois outras podem ser deduzidas a partir dessas.
39
Ferramentas para fazer essa análise são chamadas de “parser”. O “parsing” é a
primeira etapa da compilação do código fonte. Para fazer isso, é preciso conhecer a
sintaxe da linguagem de programação usada.
Dependendo das necessidades, pode-se usar parsers específicos que vão procurar
só um tipo particular de informação. Por exemplo, num programa Pascal, pode-se
extrair o nome de todas as funções definidas com um parser muito simples.
5.2.1.2 Trace de execução (análise dinâmica)
A análise estática pode extrair muitas informações de um programa, mas nem todas.
Por exemplo, qual parte de uma instrução IF é realmente usada pode depender dos
dados com que o programa foi chamado. Para descobrir esse tipo de informação,
precisamos da análise dinâmica, que consiste em executar o programa e monitorar
os valores das variáveis, quais funções são chamadas, etc.
5.2.1.3 Dados
Os bancos de dados podem ser usados como fonte de informação para ajudar na
engenharia reversa de um sistema. Mas a engenharia reversa de dados é também
um trabalho específico que pode ser feito independentemente de qualquer sistema
que possa manipular esses dados. Por exemplo, querer converter um velho banco
de dados de um “mainframe” para um banco de dados relacional e distribuído sobre
vários PCs.
Podem ser extraídos de um banco de dados: a estrutura, os dados, os
relacionamentos e até os relatórios e as interfaces com o usuário.
40
5.2.1.4 Documentação
Chama-se de documentação tudo o que não está usado pelo computador para fazer
funcionar o sistema, mas se destina aos engenheiros que usam o código: relatórios,
comentários no código, diagramas da análise ou do projeto, etc.
Como ela se destina aos seres humanos, é difícil de ser analisada automaticamente.
A abordagem mais usada é usar as palavras da documentação. Isso pode permitir
extrair os conceitos importantes do domínio de aplicação do sistema. Esta
abordagem está baseada sobre a suposição que os conceitos importantes aparecem
com mais freqüência na documentação.
5.2.1.5 Outras fontes de informação
Finalmente, é possível usar outras fontes de informação. Por exemplo, para definir
sub-sistemas, poderíamos procurar quem escreveu cada porção do código. É
razoável pensar que se duas partes do código foram desenvolvidas pela mesma
pessoa elas tem maior probabilidade de pertencer ao mesmo sub-sistema. Outras
informações seriam: quais programas são chamados, em que linguagem são
escritos, tipo de máquina que roda os programas.
5.2.2 Tratamento das informações
Essas são algumas das principais atividades envolvidas na engenharia reversa.
Essas atividades usam as informações que foram extraídas do sistema. Podemos
resumir o objetivo geral dessas atividades da seguinte forma: elas tentam abstrair
informações de mais alto nível de abstração das informações do sistema. O que
quer dizer que elas vão eliminar os inumeráveis detalhes. O problema é decidir
nessa massa de informações o que é importante ou não, segundo Anquetil, N.
(2002).
41
5.2.2.1 Anomalias no código
Num software legado, o código pode conter várias anomalias, como partes do
programa que nunca podem ser executadas (código morto) e trechos de código que
foram copiados e levemente modificados, denominados clones. Essas anomalias
complicam o código inutilmente, fazendo ele mais longo do que deveria ser e
multiplicando as coisas que um programador tem que estudar e entender.
Para resolver esse problema pode-se apagar o código morto, e no caso dos clones é
possível modificar o código para suprimi-los ou então fazer comentários no código
sobre a existência de clones.
5.2.2.2 Encapsulamento
O encapsulamento é uma técnica de re-engenharia mais do que de engenharia
reversa. Em vez de reestruturar um sistema, ela propõe esconder o velho código
dentro de uma nova camada.
5.2.2.3 “Slicing”
“Slicing” (fatiar) é uma técnica de decomposição do código de acordo com a
utilização das variáveis. O slicing de uma parte do código consiste em extrair dela
todas as instruções que têm uma influência sobre o valor de uma variável definida a
um ponto definido do código. Ajuda na descoberta da origem dos bugs, limitando a
pesquisa nas únicas instruções realmente necessárias.
5.2.2.4 (Re-)Modularização
42
A (re-)modularização é a decomposição de um conjunto de componentes de
software em sub-partes (os módulos). Em engenharia de software, normalmente, se
espera que os módulos tenham uma forte coesão interna e um pequeno
acoplamento com o exterior.
Essa atividade de agrupar arquivos em sub-sistema não é trivial. Um sistema legado
pode ser composto de milhares de arquivos, em várias linguagens de programação
(por exemplo: uma linguagem procedural, assembly, dados e alguns “scripts” para
compilações e execuções).
Para agrupar os componentes são utilizados algoritmos que “medem as distâncias”
entre os componentes com base em informações extraídas do sistema. Existem
muitos algoritmos de agrupamento (clustering) diferentes. Os mais típicos são:
• Algoritmo por construção: são os mais rápidos porque trabalham num passe
único. Os componentes são introduzidos um depois do outro. Agrupando um
novo componente com um módulo existente.
• Algoritmos por otimização: começam com uma partição do conjunto de
componentes e tentam melhorar esta partição usando heurísticas para medir
a qualidade desta.
• Algoritmos hierárquicos: constroem uma hierarquia de módulos e não
necessitam de informações do usuário.
Segundo Anquetil, N. (2002), os algoritmos apresentam dois problemas principais:
• O resultado pode ser difícil de entender;
• Eles agrupam todos os componentes segundo algumas restrições. Se as
restrições forem erradas, o resultado também será.
• O resultado desta técnica é globalmente bom. Mas sempre há detalhes
errados em alguns módulos. Esses algoritmos são bons quando existem
muitos componentes para tratar e como uma primeira abordagem para
desbravar o sistema.
43
5.2.2.5 Reconhecimento de Clichés
Um “clichê” ou plano é um padrão que descreve uma maneira geral de implementar
um conceito de programação. A atividade de reconhecimento de clichês trabalha
com um banco de clichês e procura esses clichês no código. A idéia é que um clichê
é implementado com várias linhas de código. Reconhecer um clichê pode simplificar
o código porque isso vai substituir um só conceito a essas linhas.
O reconhecimento de clichê sofre de várias dificuldades:
• Construção do banco de clichês;
• Dualidade, precisão e cobertura (a descrição do clichê deve ser geral, porém
corre-se o risco de ocorrerem falso-positivos);
• Tempo de execução;
• Clichês deslocalizados ou interligados (podem existir outras instruções entre
as que implementam o clichê ou dois clichês cujas instruções estão
misturadas).
5.3 TÉCNICAS COMPLEXAS DE ENGENHARIA REVERSA
5.3.1 Análise de propagação
Utilizada em manutenção de software, consiste no estudo do código para descobrir
as conseqüências de uma modificação.
5.3.2 Objetização
44
Consiste na extração da representação orientada a objetos de um código
procedural. Baseia-se:
• nas funcionalidades: isolar uma funcionalidade do código e construir um
objeto para encapsulá-la;
• nos dados: procurar tipos estruturados que representem conceitos da
aplicação. Agrupam-nos com as rotinas para formar classes.
• e os objetos: fazer uma análise orientada a objetos do domínio do software
para descobrir os objetos pertencentes.
5.3.3 Reengenharia de interfaces
Seu objetivo é disponibilizar uma nova interface ou reorganizar a existente para
facilitar a utilização de funcionalidades já existentes. Possui duas atividades:
identificação das informações envolvidas na execução de uma tarefa e a
identificação da sequência de mensagens necessária para cumpri-la.
5.4 ENGENHARIA REVERSA PARA SEGURANÇA
Para algumas pessoas a conexão entre segurança e engenharia reversa pode não
ser tão clara. A engenharia reversa está relacionada a vários aspectos diferentes na
segurança de computador. Por exemplo, engenharia reversa foi empregada em
pesquisa de encriptação, o investigador inverte um produto encriptado e avalia o
nível de segurança deste. Também é usada com relação a software malicioso, em
ambos os casos: pelo desenvolvedor de malware e os que desenvolvem seus
antídotos.
5.4.1 Software malicioso
Segundo Eilam, E. (2005), a Internet mudou completamente a indústria de
computador e o aspectos de segurança de informação em particular. Software
45
malicioso, tal como vírus e worms, espalham mais rápido em um mundo onde
milhões de usuários estão conectados diariamente à Internet. Há 10 anos, um vírus
normalmente teria que se copiar a um disquete e ser carregado em outro
computador para que o vírus se espalhasse. O processo de infecção era bastante
lento e a defesa era muito mais simples porque os canais de infecção eram poucos
e exigia a intervenção humana para espalhar. Isso é história antiga, a Internet criou
uma conexão virtual em quase todos os computadores da terra. Hoje em dia, vírus
modernos podem se espalhar automaticamente a milhões de computadores sem
qualquer intervenção humana.
A engenharia reversa é extensivamente usada em ambos os fins da cadeia de
software maliciosa. O desenvolvedor de software malicioso usa freqüentemente a
reversão para localizar vulnerabilidades em sistemas operacionais e outros
softwares. Tais vulnerabilidades podem ser usadas para penetrar a defesa do
sistema, estendendo a infecção, normalmente através da Internet. Além da infecção,
às vezes eles empregam técnicas de engenharia reversa para localizar
vulnerabilidades de software que permitem que um programa malicioso ganhe
acesso à informação sensível ou até mesmo tome o controle total do sistema.
O outro lado da cadeia diz respeito ao desenvolvedor de software antivírus, pois
permite a análise de todo programa malicioso que se tem contato. Eles usam
técnicas reversas para localizar os passos que o programa leva e avalia o dano que
possa causar ou a taxa esperada de infecção, como poderia ser removido de
sistemas infetados e se a infecção pode ser evitada completamente.
5.4.2 Métodos de proteção
Alguns cuidados precisam ser levados em consideração para garantir a segurança
de um sistema. As boas práticas de programação, mesmo sem se considerar a
segurança em si, garantem um código mais robusto, confiável e, conseqüentemente,
seguro, segundo Albuquerque (2002). Código seguro não significa necessariamente
segurança em código ou código que implemente alguma função para segurança,
46
mas código que é escrito para suportar os atacantes maliciosos. O código seguro é
também código robusto, Howard (2002).
Albuquerque et al. (2002) considera que o código seguro muita vezes implica em
certa perda de desempenho. Entretanto, ressalva que a perda de performance pode
ser compensada por um hardware mais rápido, o contrário, porém, não é verdadeiro.
A perda de performance pode ser compreendida por sugestões como as de Viega et
al. (2003): “assuma que toda entrada de dados é culpada até que se prove o
contrário” ou “quanto mais você compreende o dado, mais facilmente você o filtrará”.
Torres (2003) também é cauteloso ao tratar as entradas de dados, especialmente
em uma arquitetura cliente-servidor e, sobretudo, nas solicitações provenientes de
ambientes inseguros – ou pouco controlado – como é o caso da Internet.
Existem três fatos a serem considerados no desenvolvimento de software mais
seguro: processo repetível, educação e métrica, segundo Lipner (2004). Segundo
Lipner et al., é importante que se tenha na organização um grupo responsável pelo
desenvolvimento e evolução das melhores práticas de segurança; melhorias no
processo, que sirva de fonte de conhecimento para a organização de uma forma
geral e que faça a Revisão Final de Segurança (em inglês FSR – Final Security
Review) antes da liberação da release.
Enquanto muitas organizações preferem ter uma equipe central de segurança,
outras optam por contratar terceiros, a experiência demonstrou – na visão de Lipner
et al. – que a existência de um grupo interno de segurança é um fator vital para o
sucesso na implementação de um ciclo de vida de desenvolvimento.
A experiência com segurança de software tem demonstrado que um conjunto de
princípios de alto nível para desenvolver software mais seguro precisam ser
estabelecidos. A Microsoft refere-se a esses princípios como SD3+C – Seguro por
Design, Seguro por Default, Seguro na Distribuição e Comunicação. Uma descrição
sucinta desses princípios seria:
• Seguro por Design: Uma arquitetura pode ser desenhada para utilizar
criptografia 3DES (triplo DES) para dados sensíveis antes de serem
armazenados no banco de dados e o uso do protocolo SSL para transportar o
47
dado através da Internet. Todo código é bastante verificado em busca de
vulnerabilidades comuns usando ferramentas manuais e automáticas. A
modelagem de ameaças é criada durante o processo de design do software.
• Seguro por Default: O software é empacotado com medidas de segurança e
os componentes potencialmente vulneráveis são desativados.
• Seguro na Distribuição: Atualizações de segurança são fáceis de serem
localizadas e instaladas – eventualmente são instaladas automaticamente – e
ferramentas são disponibilizadas para o levantamento e gerenciamento dos
riscos de segurança em toda a organização.
• Comunicação – os desenvolvedores precisam estar preparados para
descobrir vulnerabilidades nos produtos e comunicar aberta e
responsavelmente os usuários finais e/ou administradores para ajudá-los a
tomarem as ações preventivas necessárias.
5.4.2.1 Criptografia
Soares et al. (1995) comenta que "a criptografia surgiu da necessidade de se enviar
informações sensíveis através de meios de comunicação não confiáveis, ou seja, em
meios onde não é possível garantir que um intruso não irá interceptar o fluxo de
dados para leitura (intruso passivo) ou para modificá-lo (intruso ativo). A forma de
contornar esse problema é utilizar um método que modifique o texto original da
mensagem a ser transmitida (texto normal), gerando texto criptografado na origem,
através de um processo de codificação definido por um método de criptografia. O
texto (ou a mensagem) criptografado é então transmitido e, no destino, o processo
inverso ocorre, isto é, o método de criptografia é aplicado agora para decodificar o
texto criptografado transformando-o no texto normal original".
"Existem basicamente dois tipos de criptografia: a simétrica e a assimétrica"
Albuquerque (2002). Júlio César empregava um método de criptografia que consistia
em substituir as letras de uma mensagem pela terceira letra após sua posição no
alfabeto (sendo a sucessor de z) Tanenbaum (1989). Esse é um exemplo de
criptografia simétrica ou baseada em chave secreta, pois a mesma chave será
48
usada para cifrar e decifrar a mensagem. O problema clássico dessa solução é a
dificuldade de entregar a chave de forma segura a quem vai decifrar a mensagem,
segundo Rufino (2002). Existem diversos algoritmos conhecidos de criptografia
simétrica, como DES, IDEA, TRIPLE-DES e BlowFish, conforme Albuquerque
(2002). O algoritmo DES codifica blocos de 64 bits de texto normal gerando 64 bits
de texto criptografado, diz Tanenbaum (1989).
O conceito de chaves assimétricas é baseado na idéia que o momento de maior
vulnerabilidade da chave é quando ela está em trânsito, Rufino (2002), Disnei
(2002). Em 1976, Diffie e Hellman (1976) propuseram um método que revolucionou
os sistemas de criptografia. Baseado na utilização de chaves distintas: uma para
codificação (E) e outra para decodificação (D), tal que a derivação de D a partir de E
fosse, em termos práticos, senão impossível, pelo menos muito difícil de ser
realizada. Portanto, o que uma cifrasse somente a outra poderia revelar. Dessa
maneira, uma poderia ser tornada pública e trafegar sem necessidade de canais
seguros, desde que a outra, privada, permanecesse em local seguro, conforme
Rufino (2002) e Soares (1995). Entre os algoritmos de criptografia assimétrica ou de
chave pública de uso prático, os mais comuns são o RSA e as Curvas Elípticas. O
RSA, cujo nome deriva das inicias dos autores Rivest, Shamir e Adleman (1978),
baseia-se na dificuldade de fatorar números muito grandes. Acreditava-se em 1977
que uma mensagem criptografada pelo RSA-129 levaria milhões de anos para ser
quebrada Gardner (1977). Foi quebrada em 1994 usando computação distribuída
Leutwyler (1994), Lima (2002).
5.4.2.2 Privacidade
Albuquerque et al. (2002) explica que:
[...] privacidade é a capacidade de um usuário realizar ações em um sistema sem que seja identificado. É completamente diferente de confidencialidade, que define que apenas usuários autorizados podem ter acesso à determinada informação.
49
Um exemplo de sistema que emprega privacidade como atributo essencial é o usado
pelo processo eleitoral brasileiro, no qual não pode haver forma de ligação entre o
eleitor e seu voto.
O Common Criteria for Information Technology Security Evaluation (Critério Comum
para Avaliação de Segurança da Tecnologia da Informação) é o nome do padrão
que originou a norma ISO/IEC 15408, muitas vezes chamada apenas de Common
Criteria, conforme ISO JTC 1/SC (1999). A norma objetiva fornecer um conjunto de
critérios fixos que permitem especificar a segurança de uma aplicação de forma não
ambígua a partir de características do ambiente da aplicação e definir formas de
garantir a segurança da aplicação para o cliente final.
As formas de privacidades destacadas pelo Common Criteria são:
• Anonimato - garante que um usuário possa usar um recurso ou serviço sem
ter sua identidade revelada.
• Pseudônimo - garante que um usuário possa usar um recurso ou serviço sem
ter sua identidade revelada, porém suas ações são rastreadas e reveladas,
geralmente, em situações especiais. Portanto, permite a responsabilização e
privacidade ao mesmo tempo. Se usado com não-rastreamento, para cada
ato deve ser usado um pseudônimo diferente.
• Não-rastreamento - garante que um usuário possa fazer uso de vários
recursos e serviços sem que outros possam ligá-lo a esses usos.
• Invisibilidade - garante que um usuário possa usar um recurso ou serviço sem
que outros, principalmente terceiros, possam saber que o recurso ou serviços
está sendo usado.
5.4.3 Técnicas Anti-reversão
Algumas aplicações têm uma necessidade especial por medidas de anti-reversão.
Um excelente exemplo é a tecnologia de proteção de cópia e a administração de
tecnologia de propriedade digital. Prevenir ou obstruir a “quebra” de tecnologias de
proteção é um passo crucial de criar meios efetivos de proteção.
50
Segundo Eilam, E. (2005), algumas plataformas de desenvolvimento de software
realmente necessitam de medidas anti-reversão, porque caso contrário o programa
pode ser mesmo facilmente convertido numa representação próxima do código
fonte. Isto é verdade para a maioria das plataformas baseadas em bytecode como a
Java e .NET, e é a razão de possuírem tantas obstruções de código para tais
plataformas (entretanto também é possível programas de obstrução que foram
compilados num processador de idioma nativo da máquina). Um bloqueador é uma
ferramenta automatizada que reduz a legibilidade de um programa modificando ou
eliminando certa informação.
Existem várias formas de evitar a engenharia de software, cada uma com sua
vantagem e desvantagem. Pode-se utilizar uma ou várias formas combinadas.
5.4.3.1 Eliminação de Informação Simbólica
O primeiro passo e mais óbvio em impedir a reversão é eliminar qualquer informação
textual óbvia do programa. Em um programa compilado baseado em bytecode
regular, isto simplesmente tira toda a informação simbólica do programa executável.
Segundo Eilam, E. (2005), em programas baseados em bytecode, os executáveis
contêm freqüentemente grandes quantias de informação simbólica interna como
nomes de classe, nomes de objetos globais, etc. Isto é comum em linguagens como
Java e plataformas como .NET. Esta informação pode ser extremamente útil na
engenharia reversa, por isto deve ser eliminada de programas onde a reversão é
uma preocupação. Outra característica fundamental de quase todo ofuscador de
bytecode é renomear todos os símbolos em sucessões sem sentido de caracteres.
5.4.3.2 Encriptação de código de programa
51
É um método comum para prevenir a análise estática. É realizado codificando o
programa em algum ponto depois da compilação (antes de ser entregue ao cliente) e
embutindo algum tipo de desencriptação codificada dentro do executável.
Infelizmente, esta alternativa normalmente cria nada mais que uma inconveniência
para o analista hábil, porque na maioria dos casos tudo que o desencriptador requer
está no arquivo executável.
5.4.3.3 Ofuscação de Programa
É um nome genérico para várias técnicas que são apontadas em reduzir a
vulnerabilidade do programa a qualquer tipo de análise estática como o processo de
engenharia reversa manual. Isto é realizado modificando o plano do programa,
lógica, dados e organização, de certo modo isso mantém a funcionalidade idêntica,
porém menos legível. Há muitas formas diferentes de obstrução, segundo Eilam, E.
(2005).
5.4.3.4 Transformação de dados
É uma técnica de ofuscação que focaliza a estrutura de dados do programa. Pois
entender a estrutura de dados permite conhecer como ele trabalha.
5.4.3.5 Embutir código antidebugger
É outra técnica comum de impedir a análise por programas de depuração para
determinar detalhes. A idéia é intencionalmente executar operações que
danificariam de alguma maneira ou incapacitariam um depurador de obter
informações sobre o sistema. Algumas destas ações simplesmente envolvem a
descoberta do depurador presente e encerrar o programa, enquanto outros
envolvem meios mais sofisticados de interferir com depuradores no caso de um
52
usuário presente. Existem vários programas anti-depuração e muitos deles são
específicos para cada plataforma.
5.4.3.6 Mudança no fluxo de controle
São transformações que alteram a ordem e o fluxo de um programa com a finalidade
de reduzir a legibilidade humana. O controle nas transformações de fluxo são
categorizadas como transformações de computação, transformações de agregação,
e ordenação.
As transformações de computação são as que reduzem a legibilidade do código,
modificando a estrutura de fluxo de controle original do programa, de modo que
traga um programa funcionalmente equivalente, porém mais difícil de traduzir em
linguagem de alto-nível. Isto pode ser feito removendo o controle da informação do
fluxo do programa ou somando ao fluxo de controle novas declarações que
complicam o programa e não podem ser traduzidas facilmente em linguagem de
alto-nível.
Transformações de agregação destroem a estrutura de alto-nível do programa
quebrando as abstrações de alto-nível criadas pelo programador enquanto o
programa estava sendo escrito. A idéia básica é quebrar tais abstrações assim que a
organização de alto-nível do código ficar ilegível.
Transformações de ordenação são transformações menos poderosas, pois
reordenam a ordem das operações em um programa de forma que sua legibilidade
seja reduzida.
53
6 FERRAMENTAS DE ENGENHARIA REVERSA
6.1 IDA Pro
Fig. 3 – Software IDA Pro.
IDA Pro (Interactive Disassembler) é um software avançado que tem como
características: análise de código hostil, de vulnerabilidades, pesquisa e engenharia
reversa. Possui multiprocessador, disassembler e depurador, funciona tanto em
Windows quanto Linux.
Suporta uma variedade de formatos de executáveis para diferentes processadores e
sistemas operacionais. Ele também pode ser usado como um depurador PE para
Windows, Mac OS X Mach-O, e Linux Executáveis ELF.
Embora IDA desempenhe um elevado grau automático de análise de código, em
certa medida, alavancando referências cruzadas entre código seções, o
conhecimento dos parâmetros das chamadas API, e outras informações, é centrada
no uso interativo. Um usuário terá início com uma lista gerada automaticamente da
desmontagem e, em seguida, renomea, anota, ou adiciona informações à lista, até
que se torne claro seu funcionamento, criando um modelo de engenharia reversa.
Criado como uma aplicação shareware por Ilfak Guilfanov, foi mais tarde
transformado em um produto comercial por DataRescue, uma empresa belga.
54
6.2 VB Decompiler
Fig. 4 – Sofware VB Decompiler.
VB Decompiler - é um descompilador de programas (executáveis, DLL ou OCX)
criados em Visual Basic 6.0. Os programas criados pelo Visual Basic 6.0 podem ser
compilados nas opções P-Code ou Codigo Nativo.
Como a opção P-Code monta comandos de alto nível, existe a real possibilidade de
descompilar um executável até chegar ao código fonte (mas como regra, nome de
variáveis, funções, etc. não serão descompilados). VB Decompiler restaura muitas
instruções em P-Code e fornece a opção de inseri-las em um projeto do Visual
Basic, criado automaticamente. O descompilador irá simplificar o problema do
aprendizado da análise algorítmica e parcialmente resgatar o código fonte original.
Se um programa foi compilado em Código Nativo, a restauração das instruções de
máquina iniciais não pode ser garantida. Mas nesse caso, VB-Decompiler pode
também ajudar na análise do programa. Ele contém um poderoso "Disassembler"
55
que suporta comandos no Pentium Pro incluindo MMX e SSE e permite desmontar
qualquer função. O software VB-Decompiler possui também um analisador de
código que procura todas as chamadas de função API. Outro recurso disponível é a
"Referência de Strings", uma lista com todos os textos contidos no executável (após
a descompilação).
Em geral, VB-Decompiler pode ser bastante útil na análise de programa e
especialmente recomendado para os casos de perda do código fonte ou restauração
parcial do projeto.
Para iniciar a descompilação você precisa selecionar um programa (executável EXE,
DLL ou OCX) clicando em Open VB program no menu File. Selecione a pasta que
contém o arquivo executável e abra-o. O software confirmará a descompilação.
Pressione SIM (YES) para iniciar a descompilação ou NAO (NO) para fazê-lo mais
tarde. Se for selecionado <<NAO>>, o nome do arquivo será adicionado na caixa de
texto FileName e quando for preciso descompilá-lo basta clicar no botão Decompile
(Descompilar).
Se for necessário gerar o projeto para Visual Basic 6.0 para facilitar a análise, será
preciso selecionar o menu File, "Save decompiled project" e selecionar a pasta que
conterá o novo projeto (incluindo funções e módulos), exceto arquivos forms frx que
salvam os ícones de programas, objetos de formulários, gráficos e outros dados
binários que serão gerados automaticamente.
Para os programadores em Visual Basic, é possível proteger o seu código da
descompilação. Para isso, VB-Descompiler contém um "obfuscator" que pode
deletar o nome de todas as funções, forms, módulos e objetos, incluindo diferentes
tipos de assinaturas no arquivo executável (EXE). Isso fará com que a análise de
descompilação seja muito complicada. Outros descompiladores não conseguirão
descompilar. Para adicionar esta proteção a seus programas, abra o seu programa
com o VB-Descompiler e em seguida clique em Tools -> Obfuscate. Este
procedimento é rápido e seguro, sendo extremamente recomendado como medida
preventiva de segurança.
56
6.3 Understand for Delphi
Fig. 5 – Software Understand for Delphi.
Understand for Delphi é uma ferramenta que suporta todas as versões da linguagem
Delphi e de Turbo Pascal da Borland. Também suporta a ISO 7185: 1990 (também
conhecida como Unextended Pascal) com as extensões DEC Pascal. Também pode
habilitar suporte para Ingres embedded SQL statements.
O projeto do banco de dados é armazenado num formato binário proprietário. Este
formato de arquivo utiliza o formato rede/objeto para otimizar seu desempenho.
Understand for Delphi analisa seu software e cria um banco de dados que contém
informação sobre as entidades e suas relações. O banco de dados permite várias
janelas para facilitar sua utilização. Estas são divididas em quatro tipos:
57
• Informação: mostra tudo sobre uma determinada entidade.
• Hierarquia: mostra o relacionamento entre as entidades. Cada janela
demonstra um relacionamento (por exemplo, "chamadas") da entidade entre
pais e filhos.
• Estrutura: mostra a estrutura de qualquer entidade que é adicionada à
estrutura do software (por exemplo, um pacote, função, procedimento, tarefa)
• Espetáculo: mostra a origem de um determinado link. Possibilitando descobrir
como a informação no código de fonte está relacionada ou ligada a outra
informação.
6.4 MÉTODO FUSION-RE/I
Fig. 6 – Visão geral do método FUSION-RE/I. Masiero, P. C. (1995).
58
O método de engenharia reversa Fusion-RE/1 (Fusion-Reverse Engineering /
Interface) desenvolvido no ICMC-USP, baseia-se nos conceitos e idéias de
engenharia reversa orientada a objetos, e fornece mecanismos para abstrair visões
funcionais (modelos de análise de sistemas de acordo com o método Fusion de
Coleman e outros (1996)) e visões estruturais partindo, inicialmente, dos aspectos
operacionais e de dados disponíveis na interface usuário-computador.
O método FUSION-RE/I é constituído de duas etapas:
1ª. Etapa – recuperar visões funcionais: parte-se de considerações “lógicas”, obtidas
por meio de aspectos operacionais e visões de dados disponíveis via interface,
para a recuperação de visões funcionais do sistema, ou seja, a abstração da
funcionalidade do sistema, representada por meio dos modelos de ciclo de vida,
de operações e de objetos do sistema.
2ª. Etapa – recuperar visões estruturais: parte-se de considerações “físicas”, obtidas
por meio do código-fonte, e das visões funcionais, para a recuperação de visões
estruturais do sistema, ou seja, a identificação dos procedimentos que
implementam as operações da interface do sistema, representados através dos
quadros de chamadas de procedimentos e de operações-procedimentos de
implementação.
Fig. 7 - Síntese do método de Engenharia Reversa FUSION-RE/I.
59
7 CONCLUSÃO
A pesquisa teve por objetivo geral propor a utilização da engenharia reversa como
ferramenta de proteção no desenvolvimento de software. A partir dos conceitos
presentes, conclui-se que as técnicas adotadas atualmente, ao esquecerem o uso
da segurança, permitem que os sistemas estejam acessíveis a todo tipo de
contaminação. Para tal, através da revisão de literatura, demonstra que são fatores
preponderantes, o uso de procedimentos que tornem o software confiável, seguro,
disponível.
Dentro desse escopo, quanto aos objetivos específicos, pode-se destacar a
identificação dos conceitos de engenharia reversa e seus aspectos legais. O exame
das falhas de segurança de software e suas conseqüências, entre outras. Bem como
a apresentação das principais técnicas de engenharia reversa e de métodos de
proteção utilizados segundo a bibliografia estudada.
Porém, foram identificadas algumas dificuldades durante a elaboração desta
pesquisa. Entre elas, citam-se a complexidade do assunto em relação às
implicações legais do uso da engenharia reversa devido a sua interpretação e
critérios de cada país; bem como da quantidade de ferramentas disponíveis para
avaliação, nem sempre confiáveis ou de caráter acadêmico; além do grande volume
de informações sobre o tema, às vezes conflitantes entre si.
Portanto, o presente trabalho não tem a pretensão de esgotar o assunto, pois existe
muito material pouco explorado, abordando um conjunto de processos específicos.
Todavia, a generalização dos resultados não fica comprometida, devido às
peculiaridades da pesquisa.
Quanto às limitações da pesquisa, um aspecto a ser considerado diz respeito à
metodologia utilizada, de revisão bibliográfica e testes de softwares, Para trabalhos
posteriores, sugere-se a implementação do tema proposto, aplicando-o dentro dos
outros contextos organizacionais e da utilização de metodologias de pesquisa
complementares, entre elas a quantitativa. Sugerem-se pesquisas que identifiquem
60
as funções desempenhadas pouco estruturadas em uma organização e os fluxos de
informação nem sempre claros e perceptíveis.
Espera-se que, à medida que os desenvolvedores de software utilizem a engenharia
reversa intensamente, investigações futuras possam analisar estes pontos, bem
como estabelecer um referencial para a criação de legislação específica do assunto,
além de determinar o impacto econômico do uso ilegal da engenharia reversa.
61
8 REFERENCIAS BIBLIOGRAFICAS
ALBUQUERQUE, R; RIBEIRO, B. Segurança no Desenvolvimento de Software, Editora Campus, 2002. ANQUETIL, N., Engenharia Reversa, COOPE, UFRJ, Rio de Janeiro, 2002. ASSUNÇÃO, M.F.A., O guia do hacker brasileiro, 2001. BIGGERSTAFF, T. Design Recovery for Maintenance and Reuse. IEEE Computer, v.22, n.7, p-36-49, 1989. CHIKOFSKY, E.J.; CROSS II, J.H. Reverse Engineering and Design Recovery: A Taxonomy. IEEE Software, v.7, n.1, p.13-17, 1990. COLEMAN, D, et al. Desenvolvimento Orientado a Objetos: O Método Fusion. Ed. Campos, Rio de Janeiro, 1996. COSTA, R.M. Um método de engenharia reversa para auxiliar a manutenção de software. Dissertação (mestrado). ICMC-USP, São Carlos, 1997. DIFFIE, W.; HELLMAN, M. E. New Directions in Cryptography, IEEE Trans. on Inform. Theory, Vol IT-22, Novembro, 1976. DISNEI, Aplicações de Curvas Elípticas em Criptografia, III Seminário de Informática - Segurança da Informação, Instituto Metodista Bennett e Instituto Militar de Engenharia, 2002. EILAM, E., Reversing: Secrets of Reverse Engineering. Wiley Publishing, Inc., 2005. FELTRIM, V. D., Apoio à Documentação de Engenharia Reversa de Software por meio de Hipertextos, São Carlos, 1999. Dissertação (Mestrado em Ciências de Computação e Matemática Computacional) – Instituto de Ciências Matemáticas e de Computação – USP São Carlos. GARDNER, M. Mathematical Games: A New Kind of Cipher that Would Take Millions of Years to Break, Scientific American 237, Agosto, 1977. HARANDI, M.T.; NING, J.Q. Knowledge-base program analysis. IEEE Software, 7: p.74-81, 1990. HOWARD, M.; LEBLANC, D. Writing Secure Code, Microsoft Press, 2002. ISO JTC 1/SC 27 Commitee ISO/IEC 15408-1:1999 Information Technology – Security Techniques - Evaluation Criteria for IT Security - Part 1: Introduction @ General Model, ISO Online Catalogue, 1999.
62
JÚNIOR, J. B., Legislação aplicada à Informática: livro didático. Palhoça: UnisulVirtual, 2006. LEUTWYLER, K. Superhack: Forty Quadrillion Years Early, a 129-Digit Code is Broken, Scientific American 271, 1994. LIMA, A. P. Algoritmos de Chave Pública: Estado da Arte, III Seminário de Informática - Segurança da Informação, Instituto Metodista Bennett e Instituto Militar de Engenharia, 2002. LIPNER, S.; HOWARD, M. The Trustworthy Computing Security Development Lifecycle, IEEE Annual Computer Security Applications Conference, 2004. MASIERO, P. C.; Análise Orientada a Objetos: Uma Introdução ao Método Fusion. In: IX Simpósio Brasileiro de Engenharia de Software. Documento preparado como apoio ao tutorial homônimo, Recife, 1995. MORIMOTO, C.E., Dicionário Técnico de Informática, 3a. ed., 2005. (http://www.guiadohardware.net) OXFORD, Dictionary of Computing Oxford, University Press, 1986. PRESSMAN, R.S. Engenharia de Software. 3a. ed., Makron Books, 1995. RIVEST, R. L., SHAMIR, A.; ADLEMAN, L. On a Method for Obtaining Digital Signature and Public Key Cryptosystems, Commun, ACM, Vol 21, Fevereiro, 1978. RUFINO, N. M. O. Segurança Nacional - Técnicas e Ferramentas de Ataque e Defesa de Redes de Computadores, Novatec Editora, 2002. RUGABER, S. Program Comprehension for Reverse Engineering. In: AAAI Workshop on AI and Automated Program Understanding, San Jose, California, p.106-110. July 1992. (http://www.cc.gatech.edu/reverse/papers.html) SALEH, K.; BOUJARWAH, A. Communications Software Reverse Engineering: A Semi-Automatic approach. Information and Software Technology, Oxford, n.38, p.379-390, 1996. SOARES, L. F. G.; LEMOS, G.; COLCHER, S. Redes de Computadores - Das Lans, Mans e Wans às Redes ATM, Editora Campus, 1995. TANENBAUM, A. S. Computer Networks, Prentice Hall, 2a. Edição, 1989. TORRES, D. Segurança Máxima de Software, Brasport, 2003. VIEGA, J.; MESSIER, M. Secure Programming Cookbook for C and C++, O'Reilly, 2003.
63
VALE, J.; ULBRICH, H. C. Universidade H4CK3R, Digerati Books, 4a. Edição, 2004.