Uma pequena introdução ao Assembly para Linux

Paper publicado no zine Cogumelo Binário ( http://cogubin.leet.la/ ), sobre programação Assembly na sintaxe AT&T para Linux.

[ Hits: 37.264 ]

Por: Luiz Vieira em 19/12/2011 | Blog: http://hackproofing.blogspot.com/


Explicação e Segundo Programa



Explicação

Agora vamos à explicação das partes do programa.

Tudo o que possui uma '#' no início, é comentário. Acho que não há muito o que se dizer sobre isso. ;-)

Logo depois dos comentários, temos algumas seções específicas. E sempre que há algo que comece com '.section', não é uma instrução para que o computador execute, mas sim uma instrução diretamente inserida para o Assembler, como é o caso das seções abaixo, que quebra o programa em pedaços (seções) diferentes:
  • .section .data = esse comando cria a seção "data", onde listamos quaisquer containers de memória que precisaremos para os dados.
  • .section .text = é nessa seção onde inserimos as instruções a serem executadas.
  • .globl _start = '.globl' é uma instrução que diz que o símbolo '_start' não deve ser descartado após a compilação e linkedição do código. E '_start' é um símbolo que marca um determinado local da memória que servirá como referência para a execução de determinadas instruções, que vêm logo abaixo:
  • _start:  = é onde definimos o valor do label '_start', que terá vinculado à si, o conjunto de instruções que seguem logo abaixo. Podemos traçar um paralelo com as funções que utilizamos em C.
  • movl $1, %eax = aqui temos a instrução 'movl', seguido de dois operadores. Os operadores podem ser números, referência a locais da memória ou registradores. Nesse caso, inserimos o valor 1 no registrador EAX. Esse número é o valor de uma syscall específica (exit - para conhecer os valores das demais 'syscall', execute o comando "cat /usr/include/asm-i386/unistd.h" no terminal Linux).

Bem, com o comando acima, dizemos ao programa qual 'syscall' será executada pelo kernel ao ser chamado. No entanto, essa 'syscall' precisa de um parâmetro para dizer que está tudo ok e o programa poderá ser finalizado. Esse parâmetro será armazenado em outro registrador, com a próxima instrução:
  • movl $0, %ebx = aqui, inserimos o parâmetro através do valor "0" no registrador EBX. Isso é o que dirá para o kernel que está tudo ok para o 'exit' ser executado. Lembra um pouco o "return (0)" do C.

A próxima instrução é a que faz a sinalização para chamar o kernel e executar a 'syscall exit':
  • int $0x80 = 'int' é o mesmo que 'interrupt'. Uma interrupção corta o fluxo de funcionamento de um programa e passa o comando para o Linux, o que em nosso caso, fará com que o kernel execute a 'syscall 1 '(exit). E o valor '$0x80' é o número de interrupção utilizado para que essa passagem de controle para o Linux, aconteça. Não se preocupe ainda do porque ser esse valor, e não outro, porque isso não importa, apenas precisa lembrar-se que é a instrução de interrupção padrão utilizada pelo Assembly AT&T.

Segundo programa

Se você conseguiu entender a explicação do que foi feito até aqui, poderá esforçar-se mais um pouco e entenderá o próximo código. Esse novo programa tem como função ler algo digitado pelo usuário, armazená-lo e depois exibi-lo:

 #OBJETIVO: Ler uma string digitada pelo usuário
 #
 #ENTRADA: qualquer string que pode ser digitada
 #
 #OUTPUT: retorna o que foi digitado pelo usuário
 #
 #VARIÁVEIS:
 # string = armazena a string digitada
 # tam = armazena o tamanho da variável string
 #

 .section .data
 string: .string "Digite algo:\n"
 tam: .long . - string

 .section .text

 .globl _start

 _start:


 movl $4, %eax      # insere o valor 4, para a chamada da syscall write no EAX
 movl $1, %ebx      # passa o parâmetro da syscall 4 para que algo seja exibido
 leal string, %ecx   # carrega o endereço de memória do ECX e exibe o conteúdo de string
 movl tam, %edx      # armazena o valor de tam no EDX
 int $0x80      

 movl %esp, %ecx    # Salva o Stack Pointer em %ecx
 subl $10, %esp      # Reserva 10 bytes para o usuario digitar no stack
 movl $3, %eax       # insere o valor da syscall read (3) no EAX, o que for escrito tbm será armazenado em EAX
 movl $9, %edx       # Tamanho do que vai ser lido para EDX
 int $0x80

 movl %eax, %edx    # Move o que foi digitado para EDX.
 movl $4, %eax      # syscall write
 movl $1, %ebx
 int $0x80

 movl $0x1, %eax
 movl $0x0, %ebx
 int $0x80


Salve como 'leia.s'. Compile, linkedite e execute:

# as leia.s -o leia.o
# lf leia.o -o leia # ./leia
Página anterior     Próxima página

Páginas do artigo
   1. Introdução
   2. Os registradores
   3. Primeiro programa
   4. Explicação e Segundo Programa
   5. Mais dois programas e conclusão
Outros artigos deste autor

Boot Linux - o que acontece quando ligamos o computador

Bypass de firewall com tunelamento por DNS

Ferramentas de segurança - uma pequena compilação

ARP Poisoning: compreenda os princípios e defenda-se

Shellter Project - Ferramenta para bypass de AV

Leitura recomendada

Aulas particulares: Ganhando dinheiro com Linux

Transmissão de áudio e vídeo via Multicast

Experiência de migração para software livre

Uma pequena análise do Gentoo Linux

MenuetOS - O extraordinário mini-sistema operacional

  
Comentários
[1] Comentário enviado por JJSantos em 19/12/2011 - 22:12h

Muito bom, mesmo....

[2] Comentário enviado por dimasdaros em 20/12/2011 - 16:35h

Ossa, eu aprendi assembly para PIC há uns 5 anos atrás, quando cursei um técnico em Eletrônica, não me lembro de quase nada, mas era meio diferente ainda hehe

Ótimo artigo.
Uma pergunta, não tive como ler o artigo ao todo, pois estou em horário de trabalho, mas existe alguma linguaguem de programação de baixo nível para web? Que os navegadores podem interpretar? Fiquei com essa dúvida agora, que estou estudando web.

Mas de qualquer forma excelente conteúdo, como todos os que você posta.
Parabéns

Abraço
dimasdaros.

[3] Comentário enviado por sacioz em 21/12/2011 - 13:25h

Sempre acompanho os artigos desse Senhor com interesse , éle é de dar medo de tanto que sabe.

[4] Comentário enviado por Lisandro em 22/12/2011 - 07:57h

Excelente artigo. Meus parabéns!

[5] Comentário enviado por firebits em 22/12/2011 - 14:47h

Faaaaaaala, Luiz. Brother, você usou o NASM para compilar os fontes dos programas?

[6] Comentário enviado por taiar em 22/12/2011 - 14:55h

Estranho é dizer algo como "Assembly para Linux" sendo que uma linguagem de montagem é algo utilizado para se controlar processadores e não sistemas.

Qual a plataforma desse código Assembly? Intel 8086? Sparc?????? Sem saber isso, esse artigo não tem nada haver...

[7] Comentário enviado por renan16 em 22/12/2011 - 15:28h

Muito bom

[8] Comentário enviado por 9u31220 em 24/12/2011 - 14:20h

Parabéns Luiz Vieira, o artigo está bom.

Na página 4 no comando de linkedição do programa leia foi usado #lf... ao invés de #ld...

Eu testei os programas aqui e o último não funcionou, ele não cria nenhum arquivo arquivo.txt.

Você poderia citar as fontes no final, posso estar enganado mas acho que tudo o que foi dito sobre a sintaxe AT&T, o ciclo de execução de instrução do processador e os registradores pode ser encontrado em http://download.savannah.gnu.org/releases/pgubook/

[9] Comentário enviado por luizvieira em 28/12/2011 - 18:50h

Valeu pessoal!

Rafael, além do Programming From the Ground Up, que inclusive indiquei em minha palestra sobre Exploits no Hack'n Rio, utilizei o livro abaixo como fonte:

The Art of Assembly Language - http://www.amazon.com/Art-Assembly-Language-Randall-Hyde/dp/1886411972/ref=cm_lmf_tit_9

E com relação a sintaxe AT&T e o ciclo de execução, confesso que sempre tenho em mente as explicações do livro citado (Programming From the Ground Up), mas o conteúdo não foi retirado ipsis literis do referido livro, posto que não há muito o que acrescentar nessas informações. Logo, o conteúdo deve estar bem parecido :-)

Sobre o comando, ld, valeu pela correção, devo ter deixado o dedo escorregar hehehe, mas percebi que o erro consta apenas na linkedição do segundo código.

Quanto ao último programa, darei uma olhada no que pode ser... O mesmo foi testado em um Ubuntu 11.10, com proc. Core i7 e funcionou bem. Inclusive acabei de testar e verifiquei que o funcionamento está ok.

[ ]'s

[10] Comentário enviado por luizvieira em 28/12/2011 - 18:59h

firebits, meu brother, utilizei o GNU Assembler, que é o padrão do Linux.

taiar, realmente o artigo não deve ter nada "haver" :-)

Mas para informar, a arquitetura é x86, como explicado na resposta acima dado ao 9u31220. E com relação ao título de Assembly para Linux, é apenas para frisar que o foco é a sintaxe AT&T, já que deve ter ficado bem claro no artigo que há duas sintaxes: Intel (Windows) e AT&T (Unix like).

[ ]'s

[11] Comentário enviado por 9u31220 em 28/12/2011 - 21:44h

@liuzvieira

vlw pelas fontes

Deculpe a minha preguiça em não depurar o que aconteceu que o último programa não funcionou aqui, eu estou usando um crunch bang 10 com proc intel atom.
O arquivo arquivo.txt foi aberto com modo de arquivo "O_RDWR" que é uma string (não deveria ser um número?). Bastou substituir a linha 37:

movl $perm, %ecx # modo do arquivo
por
movl $03101, %ecx

que funcionou.

[ ]'s


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts