# Syscall 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.

{% hint style="info" %}
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.
{% endhint %}

### 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:

{% tabs %}
{% tab title="assembly.asm" %}

```nasm
bits 64

section .text

global assembly
assembly:
  mov rax, 60
  mov rdi, 0
  syscall
  ret
```

{% endtab %}

{% tab title="main.c" %}

```c
#include <stdio.h>

int assembly(void);

int main(void)
{
  assembly();
  puts("Hello World!");
  return 0;
}
```

{% endtab %}
{% endtabs %}

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:

```
$ ./test
$ echo $?
```

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:

* [Linux System Call Table for x86 64](https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/)

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](https://pt.wikipedia.org/wiki/Wrapper) em C da syscall afim de entender mais detalhadamente o que cada uma delas faz. Por exemplo:

```
$ man 2 exit
```

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:

```bash
function syscall() {
	if [ -z "$1" ]; then
		echo "Developed by Luiz Felipe <felipe.silva337@yahoo.com>"
		echo "See (Portuguese): https://mentebinaria.gitbook.io/assembly-x86"
		echo
		echo "Usage: syscall name [32|64]"
		return 0
	fi

	name="$1"
	bits="${2-64}"
	number=$(grep -m1 "__NR_$name" \
			 "/usr/include/x86_64-linux-gnu/asm/unistd_$bits.h" \
			 | cut -d' ' -f3)

	[ -z "$number" ] && return 1

	if [ "$bits" == "64" ]; then
		sysnumRegister="RAX"
		arguments="RDI, RSI, RDX, R10, R8, R9"
	else
		sysnumRegister="EAX"
		arguments="EBX, ECX, EDX, ESI, EDI, EBP"
	fi

	echo "Syscall number ($sysnumRegister): $number"
	echo "Arguments: $arguments"
	echo
	echo "Synopsis:"

	awkCode='
		/SYNOPSIS/,/DESCRIPTION/{
			if ($1 != "SYNOPSIS" && $1 != "DESCRIPTION") {
				print $0
			}
		}
	'

	man 2 "$name" | awk "$awkCode"

	return 0
}
```

Exemplo de uso:

![](/files/-MfDYG-I0LwS_c2kv20B)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mentebinaria.gitbook.io/assembly/a-base/syscall-no-linux.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
