11
Introdução ao Assembly Caríssimos leitores, o presente artigo pretende expor um pouco dos segredos desta linguagem de baixo nível, aquela mais próxima do código máquina. Como fator de motivação, é sabido que quando existe a necessidade de perceber o funcionamento de um executável, por exemplo um jogo de computador, a solução passa pela análise do assembly . A partir dele, é possível alterar e personalizar seus processos e procedimentos, mas existe a necessidade de compreensão do código. Este artigo não tem objetivo de aprofundar a matéria, apenas oferecer uma introdução de modo a facilitar a compreensão dos artigos de engeharia reversa do presente blog. Assembler ou Assembly? Antes de mais convém esclarecer os conceitos de assembler e de assembly . Um erro muito comum nos indíviduos experts em informática, é falarem de assembler referindo-se à linguagem de programação, mas não, assembler é o nome dado ao programa de computador que gera o ficheiro binário apartir do código assembly . De uma forma ainda mais simplificada, assembler : "Programa para desenvolver e compilar assembly", assembly : "é o nome dado à linguagem de programação". Ferramentas de Trabalho para o Artigo -Emu 80x86: Um assembler para criação do código-fonte. Possuí uma excelente interface e diversos módulos para debbuging. Tópico 1: Registos De uma forma geral, pode dizer-se que o assembly usa variáveis globais. Estas variáveis são úteis para a chamada de vários processos, como por exemplo: - "Verificar se o utilizador digitou algo no buffer do teclado." - "Informar o sistema que é pretendido escrever no buffer de saída para o monitor." Estes são os dois casos mais simples e fáceis de perceber, na verdade, isto é um tudo mais complicado. Os registos mais importantes e comuns são os listados em seguida. 1. AX - O acumulador. Compreende AH e AL, os bytes alto e baixo de AX. 2. BX – A base. Compreende BH e BL, são usados como apontadores registos.

Introdução ao Assembly.pdf

Embed Size (px)

DESCRIPTION

Reverse Engineering.http://infptavares.blogspot.pt

Citation preview

Page 1: Introdução ao Assembly.pdf

Introdução ao Assembly

Caríssimos leitores, o presente artigo pretende expor um pouco dos segredos desta linguagem debaixo nível, aquela mais próxima do código máquina. Como fator de motivação, é sabido quequando existe a necessidade de perceber o funcionamento de um executável, por exemplo um jogode computador, a solução passa pela análise do assembly. A partir dele, é possível alterar epersonalizar seus processos e procedimentos, mas existe a necessidade de compreensão do código.

Este artigo não tem objetivo de aprofundar a matéria, apenas oferecer uma introdução de modo afacilitar a compreensão dos artigos de engeharia reversa do presente blog.

Assembler ou Assembly?

Antes de mais convém esclarecer os conceitos de assembler e de assembly. Um erro muito comumnos indíviduos experts em informática, é falarem de assembler referindo-se à linguagem deprogramação, mas não, assembler é o nome dado ao programa de computador que gera o ficheirobinário apartir do código assembly.De uma forma ainda mais simplificada, assembler : "Programa para desenvolver e compilarassembly", assembly : "é o nome dado à linguagem de programação".

Ferramentas de Trabalho para o Artigo

-Emu 80x86: Um assembler para criação do código-fonte. Possuí uma excelente interface ediversos módulos para debbuging.

Tópico 1: Registos

De uma forma geral, pode dizer-se que o assembly usa variáveis globais. Estas variáveis são úteispara a chamada de vários processos, como por exemplo:

- "Verificar se o utilizador digitou algo no buffer do teclado."- "Informar o sistema que é pretendido escrever no buffer de saída para o monitor."

Estes são os dois casos mais simples e fáceis de perceber, na verdade, isto é um tudo maiscomplicado.Os registos mais importantes e comuns são os listados em seguida.

1. AX - O acumulador. Compreende AH e AL, os bytes alto e baixo de AX.2. BX – A base. Compreende BH e BL, são usados como apontadores registos.

Page 2: Introdução ao Assembly.pdf

3. CX – O contador. Compreende CH e CL, é usado genéricamente em ciclos iterativos (loops).4. DX – O deslocamento, este é similar aos registos base (BX). Compreende DH e DL.

Estes registos são definidos como gerais, pois permitem armazenar informação. Convém salientarque são todos registos de 16 bits, portanto, significa que apenas é possível guardar um inteiropositivo de 0 a 65535, ou um inteiro com sinal de -32768 até 32768.

Como mencioando, estes são registos de 16 bits. Em seguida uma imagem representativa.

Acima foi dito que AH e AL são os bytes alto e baixo, isto é, mais e menos significativos de AX.Na verdade, olhando para a imagem fica fácil perceber o porquê.Sendo estes registos de 16 bits, por vezes são necessários registos de 32 bits e até 64 bits, conformeas necessidades. O principio passa maioritariamente pelo mesmo conceito.Em seguida é apresentada a evolução dos registos de 16 bits para 32 bits.

1. AX - EAX2. BX - EBX3. CX - ECX4. DX - EDX

Apenas existe a mudança de E, refere-se a extended, isto é, registo extendido. O conceito é quase omesmo do anterior. É possivel observar uma imagem que representa essa mudança em seguida.

Mais uma vez parece intuitivo, isto funciona de igual forma para os outros registos. Voltando aoregisto AX, que foi o escolhido antecipadamente, é proposto um desafio. Se for pretendidoarmazenar 0A4Ch em AX como ficará armazenada a informação?

Nota.: No assemby a notação usada é a hexadecimal, daí o uso do valor 0A4C(hexadecimal).

Solução: AH receberá 0A e AL receberá 4C (AH=0A e AL=4C).

Page 3: Introdução ao Assembly.pdf

Dito isto, se verificar a imagem referente ao registo AX é intuitivo que tanto AH como AL contêm8 bits de espaço reservado disponíveis na memória. Portanto, a junção dos dois (AX + AH) permiteobter o registo AX de 16 bits.De uma forma bastante simplista é possivel afirmar que cada "valor" do número: 0A4C vale 4 bits,um nibble. (Definição de nibble em http://en.wikipedia.org/wiki/Nibble.)

0 – 4 bits.A – 4 bits.4 – 4 bits.C – 4 bits.

Visualizando novamente a imagem referente ao AX e voltando a olhar para a solução do problemaproposto, ficou claro esta subdivisão do registo na memória e o porquê de 0A ficar armazenado emAH. Na verdade, 0A são 8 bites, o tamanho total de AH.

Caso ainda presistam dúvidas, reparar no próximo caso.

AH= 03h (00000011)AL= 10h (00010000)

Qual é o valor de AX? Basta combinar os valores de AH e AL.

AH + AL = 03h + 10h = 0310hAX= 0310h

Para mais informação ver a tabela em: (http://pt.wikipedia.org/wiki/Inteiro_(ciência_da_computação)

Os restantes registos funcionam mais ou menos dentro desta lógica. Em seguida são apresentados osregistos mais importantes.

5. CS – O segmento de código. O bloco de memória onde o código é armazenado.6. DS – O segmento de dados. A área na memória onde os dados são armazenados.7. ES - O segmento extra. Apenas outro segmento de dados.8. SS – O segmento de pilha. Aqui o CPU (Central Processing Unit) armazena os endereçosremotos das subrotinas.10. SI- O índice de fonte. Frequentemente usado para movimentações de blocos de instruções. Esteé um apontador que, com um segmento, geralmente DS, é usado pela CPU para leitura.11. DI – O índice de destino. Novamente um apontador, que com um segmento, geralmente ES, éusado para escrita pela CPU.12. SP – O apontador da pilha. Comumente usado com o segmento da pilha.

Estes e muitos outros são registos do assembly. Não existe a necessidade saber todos eles, visto quenão é suposto programar em assembly, apenas perceber blocos de assembly, nomeadamente nospróximos artigos de engenharia reversa. Contudo, é suposto solidificar esta base de conhecimento,tão importante no contexto da engenharia reversa.

Tópico 2: Tipos de Dados

Aproveitando a ideia, é imporante referir que no assembly, como noutra qualquer linguagem deprogramação, existem diferentes tipos de dados. Os mais usuais são os seguintes.

Page 4: Introdução ao Assembly.pdf

1. Byte : Conjunto de 8 bits.2. Word: Conjunto de 16 bits.3. Dword: Conjunto de 32 bits.4. Qword: Conjunto de 64 bits.

É possivel perceber que é sempre a dobrar o tipo de dados (bits) do anterior.

Tópico 3: As Instruções e a Pilha

Neste ponto é sabido que existem registos e diferentes tipos de dados no assembly. Uma possívelanalogia é comparar registos como prateleiras do supermercado, cada uma apenas possuí um certotipo de produtos, mas dentro dessa produto existem diversas gamas.

Para o uso dos registos são necessárias instruções. Em seguida segue uma listagem das maiscomuns. Convém referir, que estas poderão variar entre diferentes tipos de CPU.

1. MOV <destino> , <valor> - MOVE. Esta instrução permite mover um valor para umadeterminada posição da memória.

Ex: MOV AX, 13h. Desta forma, 13h (10 em decimal) é movido para o registo AX. Antes da instrução, AX continha ovalor zero, neste momento possuí 13h. É evidente que todas aquelas operações feitas no "Tópico1"relacionadas com o AX, nomeadamente: "apenas foi usado o byte mais significativo de AX paraarmazenar o valor 13h (8 bits)", se tornam agora mais percetíveis.

2. INT <número> - Interrupção. Esta instrução gera uma interrupção no sistema.

Ex: INT 10h.

Neste caso era gerada uma interrupção 10h (16 em decimal). A interrupção lançada depende doconteúdo do registo AH, entre outras coisas. Por exemplo, se AX=13h e a interrupção 10h fossegerada, o vídeo (modo gráfico) seria colocado no modo 320x200x256.

Mais precisamente:

AH seria igual a 00 – seleciona a subfunção do modo, e AL seria igual a 13h – modo gráfico230x200x256.

Contudo, se AH=2h, e a interrupção 16h fosse gerada, isso instruiria a CPU para checkar se algumatecla pressionada estava no buffer do teclado.

Se AH=2h, e BH = 0h e a interrupção 10h fosse gerada, então a CPU movia o cursor para a posiçãoX em DL e posição Y em DH.

Como é possível perceber neste momento, os registos quase que são os ingredientes para fazer umbolo.

Page 5: Introdução ao Assembly.pdf

3. ADD <destino> , <valor> -Adiciona. Esta instrução soma um número ao valor armazenado emdestino.

Ex: MOV AX, 0h; AX agora é igual a 0h.ADD AX, 5h ; AX agora é igual a 5h.ADD AX, 10h; AX agora é igual a 15h.

4. SUB <destino>, <valor> - Subtrai. Esta instrução faz o inverso da adição.

Ex: MOV AX, 13h; AX agora é igual a 13h (19 decimal). SUB AX, 5h ; AX agora é igual a 0Eh (14 decimal).

5. DEC <registo> -Decrementa. Esta instrução tem a função de decrementar, por exemplo, umregisto.

Ex: MOV AX, 13h; AX agora é igual a 13h.DEC AX; AX agora é igual a 12h.

6. INC <registo> - Incrementa. É o inverso da operação anterior.

7. CALL <procedimento> - Chama uma subfunção.

Era possível passar umas boas horas a listar e descrever as instruções do assembly, mas tal não iráacontecer. Quando existe a necessidade de perceber um programa em assembly é necessário oanalista usar a ferramenta Internet e procurar/perceber o que cada uma das instruções faz. Estasinstruções, como já mencionado no presente artigo, variam de CPU para CPU, mas fazem mais oumenos as mesmas operações.

-Pilhas

Duas das instruções que normalmente são usadas e que aparecem com regularidade em códigoassembly são as seguintes.

1. PUSH <registo> - Push, coloca algo na pilha.2. POP <registo> - Pop, retira algo da pilha.

O conceito de pilha é bastante simples. Para não entrar em demasiados detalhes é apresentada aseguinte imagem, ilustrando uma pilha.

Quando é colocado um byte na pilha ele fica armazenado na base da pilha. O próximo registo ficariana posição acima a SP. O último byte a entrar é sempre o primeiro a sair. Este é o conceito geral depilha e é assim que funciona através das instruções push e pop.

Page 6: Introdução ao Assembly.pdf

Na prática funciona como na listagem apresentada em seguida, com todos os passos efetuadosdevidamente comentados.

Tópico 4: Instruções e Flags

No tópico anterior foram vistas algumas das instruções mais usuais no assembly, mas de formapropositada, foram deixadas duas das mais importantes, a fim de serem discutidas no presentetópico. A razão pela qual estas instruções foram descartadas do tópico anterior, foi porque estasfazem uso de flags. Sem mais demora, estas instruções são o CMP (comparação de dois valores) eos JUMPS (saltar para determinado endereço de memória (offset)). Esta instrução tem imensasinstruções JUMP associadas.

1. CMP AX , BX – Comparação. Compara o registo AX com o registo BX e reflete o valor dacomparação (maior, menor ou igual) nas flags. É possível imaginar as flags como uma tabela, serávisto mais adiante. Como se percebe, após uma instrução de CMP é normal que apareça um JUMP,e a lógica associada é muito simples. Se o valor da comparação for superior, então o salto (JUMP)é efetuado para determinada posição, se o valor for menor para outra posição e por aí em diante. Ovalor desta comparação é então armazenado na tabela de flags, daí a sua real importância.

2. Comparações sem sinal.

Em seguida segue uma tabela com todas as comparações sem sinal e o valor de cada flag.

Não será exemplificado o uso destas instruções. Este será um tema a abordar no primeiro artigo deengenharia reversa. Como já referido, este artigo apenas serve como suporte à linguagem e de certaforma, ajudar o leitor a perceber o funcionamento ("por baixo") de qualquer ficheiro executável.(Ver mais informação no blog: http://infptavares.blogspot.pt/2013/12/os-segredos-de-um-exe-pe-file-portable.html .)

Page 7: Introdução ao Assembly.pdf

3. Comparações com sinal.

Em seguida segue uma tabela com todas as comparações com sinal e o valor de cada flag.

4. Comparações menos comuns

Abaixo segue uma listagem de algumas comparações menos comuns e o valor de cada flag.

Para despoletar cada uma das instruções acima mencionadas, a CPU analisa de forma individual asflags da tabela, e verifica o bit que elas armazenam. Consoante o seu valor é disparado o respetivosalto (jump). Em seguida é apresentada a tabela de flags do assembly.

5. Flags

Legenda:SF – Flag de Sinal.ZF – Flag de Zero.AF – Flag Auxiliar.PF – Flag de Paridade.CF – Flag de Carry.

Convém lembrar que existem muitas mais, mas estas são as usuais.

Page 8: Introdução ao Assembly.pdf

Tópico 5: Instruções Lógicas

Completando a família das instruções do assembly, existe um tipo de instruções que ainda nãoforam discutidas no artigo, as instruções lógicas. Elas são bastante usadas. Em seguida segue umatabela com as seguintes intruções.

Este tipo de instruções são vistas com frequência antes das instruções de comparação (CMP). Porvezes, existe a necessidade de as efetuar. Das instruções listadas, a mais frequênte costuma ser oXOR.

Tópico 6: Implementação de um programa e sua análise

O presente tópico apresenta a implementação de um pequeno exercício exemplo na linguagemassembly. Antes de avançar com problemas concretos de engenharia reversa, convém lidar e praticarexercícios deste tipo, de forma a calcificar o conhecimento adquirido até este ponto. Neste sentido,foi proposto o famoso exercício Hello World, onde cada passo é devidamente comentado. Para a suaimplementação é usado o software referido no início do artigo.

1. Criar um novo projeto no Emu80x86.

Para a criação de um novo projeto neste ambiente de desenvolvimento e emulador, apenas énecessário aceder ao menu file > new e selecionar a opção exe template. Podia ser escolhido umcom template, mas como os próximos tutoriais de engenharia reversa são perante ficheirosexecutáveis (.exe), foi optado o seu uso neste mini tutorial. Segue uma imagem abaixo ademonstrar esse processo.

Page 9: Introdução ao Assembly.pdf

2. Código gerado por defeito.

Consequentemente à criação do ficheiro, o IDE (Integrated development environment) gera algum código por defeito, nomeadamente as secções do assembly. Este foi um assunto que não foi mencionado no artigo, visto não haver grande necessidade em fazê-lo. Será discutido sem grande detalhe abaixo. Em seguida é apresentada a janela de código gerada pelo IDE.

Como é fácil de perceber, o IDE comentou o local onde será escrito o código. Antes de mais, foi feito um comentário às linhas geradas, por forma a perceber todas as instruções. Segue a imagem em seguida.

Page 10: Introdução ao Assembly.pdf

O presente ficheiro segue então a configuração padrão de qualquer ficheiro vulgar escrito emassembly. Segue abaixo um protótipo ainda mais base.

Observando-o é fácil criar uma relação com o projecto gerado pelo IDE. Para os mais curiosossegue em seguida uma listagem a descrever cada uma das secções.

a) DOSSEG : Diz a CPU como organizar o segmento.b) MODEL : Declara o modelo a usar. (Poderá explorar mais sobre este ponto se achar necessário.)c) STACK : Qual o tamanho de pilha a alocar.d) DATA : O que vai conter o segmento de dados.e) CODE : O que vai conter o segmento de código.f) START: Início do código.g) END START: Fim do código.

Posto isto, estão lançados os ingredientes para fazer o bolo, neste caso, escrever o código exemplo.

Foi criada uma subfunção _proc: com o código acima. Penso não ser necessário estar a referir cada uma das linhas, pois elas estão comentadas.

Page 11: Introdução ao Assembly.pdf

Por fim, de maneira a organizar o documento foi chamada a subfunção através da instrução CALL, como já tinha sito estudado uns tópicos acima.Antes de terminar, convém referir que este artigo é de caracter importantissímo para os próximos artigos sobre engenharia reversa.

Em anexo é disponibilizado o projecto .asm para download.

Boa continuação!Visite: infptavares.blogspot.pt