Syscall no Linux

Chamada de sistema no Linux

Uma chamada de sistema, ou syscall (abreviação para system call), é algo muito parecido com uma call mas com a diferença nada sutil de que é o kernel do sistema operacional quem irá executar o código.

O kernel é a parte principal de um sistema operacional encarregada de gerenciar todo o sistema, desde o hardware até mesmo a execução do software (processos/tarefas). Ele é a base de todo o restante do sistema que roda sob controle do kernel. O Linux na verdade é um kernel, um "sistema operacional Linux" na verdade é um sistema operacional que usa o kernel Linux.

Em x86-64 existe uma instrução que foi feita especificamente para fazer chamadas de sistema e o nome dela é, intuitivamente, syscall. Ela não recebe nenhum operando e a especificação de qual código ela irá executar e com quais argumentos é definido por uma convenção de chamada assim como no caso das funções.

Convenção de syscall x86-64

A convenção para efetuar uma chamada de sistema em Linux x86-64 é bem simples, basta definir RAX para o número da syscall que você quer executar e outros 6 registradores são usados para passar argumentos. Veja a tabela:

Registrador

Uso

RAX

Número da syscall / Valor de retorno

RDI

1° argumento

RSI

2° argumento

RDX

3° argumento

R10

4° argumento

R8

5° argumento

R9

6° argumento

O retorno da syscall também fica em RAX assim como na convenção de chamada da linguagem C.

Em syscalls que recebem menos do que 6 argumentos não é necessário definir o valor dos registradores restantes porque não serão utilizados.

exit

Nome

RAX

RDI

exit

60

int status_de_saída

Vou ensinar aqui a usar a syscall mais simples que é a exit, ela basicamente finaliza a execução do programa. Ela recebe um só argumento que é o status de saída do programa. Esse número nada mais é do que um valor definido para o sistema operacional que indica as condições da finalização do programa.

Por convenção geralmente o número zero indica que o programa finalizou sem problemas, e qualquer valor diferente deste indica que houve algum erro. Um exemplo na nossa PoC:

A instrução ret na linha 10 nunca será executada porque a syscall disparada pela instrução syscall na linha 9 não retorna. No momento em que for chamada o programa será finalizado com o valor de RDI como status de saída.

No Linux se quiser ver o status de saída de um programa a variável especial $? expande para o status de saída do último programa executado. Então você pode executar nossa PoC da seguinte forma:

O echo teoricamente iria imprimir 0 que é o status de saída que nós definimos. Experimente mudar o valor de RDI e ver se reflete na mudança do valor de $? corretamente.

Outras syscalls

Se quiser ver uma lista completa de syscalls x86-64 do Linux pode ver no link abaixo:

Você também pode consultar o conteúdo do arquivo cabeçalho /usr/include/x86_64-linux-gnu/asm/unistd_64.h para ver uma lista completa da definição dos números de syscall.

Além disso também sugiro consultar a man page do wrapper em C da syscall afim de entender mais detalhadamente o que cada uma delas faz. Por exemplo:

E para simplificar a consulta de syscalls no meu Linux eu implementei e uso a seguinte função em Bash. Fique à vontade para usá-la:

Exemplo de uso:

Last updated

Was this helpful?