description |
---|
Capítulo explicando os principais tópicos à respeito do Assembly e da arquitetura. |
Para que fique mais prático para todos, independentemente se estiverem usando Linux/Windows/MacOS/BSD/etc, usaremos a linguagem C como "ambiente" para escrever código e podermos ver o resultado. Certifique-se de ter o GCC/Mingw-w64 e o NASM instalados no seu sistema.
Caso você já programe em C e utilize outro compilador, mesmo assim recomendo que instale o GCC. O motivo disso é que irei ensinar o Inline Assembly deste compilador entre outras particularidades do mesmo. Também iremos analisar o código de saída do compilador, por isso é interessante que o código que você obter aí seja pelo menos parecido. Além disso também usaremos outras ferramentas do pacote GCC, como o gdb e o ld por exemplo.
O pacote GCC já tem o assembler GAS que é excelente mas prefiro usar aqui o NASM devido a vários fatores, dentre eles:
- O pré-processador do NASM é absurdamente incrível.
- O NASM tem uma sintaxe mais "legível" comparada a sintaxe do GAS.
- O NASM tem o ndisasm, vai ser útil na hora de estudar o código de máquina.
- Eu gosto do NASM.
Mais para frente no livro pretendo ensinar a usar o GAS também. Mas na base vamos usar só o NASM mesmo.
Primeiramente eu recomendaria o uso de alguma distribuição Linux de 64-bit ou qualquer sistema operacional Unix-Like (*BSD, MacOS etc). Isso porque mais para frente irei ensinar conteúdo que é exclusivo para sistemas operacionais compatíveis com o UNIX. Porém caso use o Windows não tem problema desde que instale o mingw-w64 como mencionei. O mais importante é ter um GCC que pode gerar código para 64-bit e 32-bit.
Vamos antes de mais nada preparar uma PoC em C para chamar uma função escrita em Assembly. Este seria nosso arquivo main.c:
{% code title="main.c" %}
#include <stdio.h>
int assembly(void);
int main(void)
{
printf("Resultado: %d\n", assembly());
return 0;
}
{% endcode %}
A ideia aqui é simplesmente chamar a função assembly()
que iremos usar para testar algumas instruções escritas diretamente em Assembly. Ainda não aprendemos nada de Assembly então apenas copie e cole o código abaixo. Este seria nosso arquivo assembly.asm:
{% code title="assembly.asm" %}
bits 64
global assembly
assembly:
mov eax, 777
ret
{% endcode %}
No GCC você pode especificar se quer compilar código de 32-bit ou 64-bit usando a opção -m no Terminal. Por padrão o GCC já compila para 64-bit em sistemas de 64-bit. A opção -c no GCC serve para especificar que o compilador apenas faça o processo de compilação do código, sem fazer a ligação do mesmo. Deste jeito o GCC irá produzir um arquivo objeto como saída.
No nasm é necessário usar a opção -f para especificar o formato do arquivo de saída, no meu Linux eu usei -f elf64 para especificar o formato de arquivo ELF. Caso use Windows então você deve especificar -f win64.
Por fim, para fazer a ligação dos dois arquivos objeto de saída podemos usar mais uma vez o GCC. Usar o ld diretamente exige incluir alguns arquivos objeto da libc, o que varia de sistema para sistema, portanto prefiro optar pelo GCC que irá por baixo dos panos rodar o ld incluindo os arquivos objetos apropriados. Para compilar e linkar os dois arquivos então fica da seguinte forma:
$ nasm assembly.asm -f elf64
$ gcc -c main.c -o main.o
$ gcc assembly.o main.o -o test -no-pie
$ ./test
Usamos a opção -o no GCC para especificar o nome do arquivo de saída. E -no-pie para garantir que um determinado recurso do GCC não seja habilitado. O comando final acima seria somente a execução do nosso executável test
em um sistema Linux. A execução do programa produziria o seguinte resultado no print abaixo, caso tudo tenha ocorrido bem.
{% hint style="info" %} Mantenha essa PoC guardada no seu computador para eventuais testes. Você não será capaz de entender como ela funciona agora, mas ela será útil para testar conceitos para poder vê-los na prática. Eventualmente tudo será explicado. {% endhint %}
Caso você tenha o make instalado a minha recomendação é que organize os arquivos em uma pasta específica e use o Makefile abaixo.
{% code title="Makefile" %}
all:
nasm *.asm -felf64
gcc -c *.c
gcc -no-pie *.o -o test
{% endcode %}
Isso é meio que gambiarra mas o importante agora é ter um ambiente funcionando.
Se você não conseguiu preparar nossa PoC aí no seu computador, acesse o fórum do Mente Binária para tirar sua dúvida.