Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introdução ao assembly x86-64

Introdução ao assembly x86-64

Será mostrado algumas diferenças entre sintaxe intel e AT&T, como o compilador GCC transcreve código da linguagem C para assembly, como chamadas de funções, recursão e gerenciamento da stack são tratados pelo GCC, convenção de chamadas de função e passagem de parâmetros mais especificamente "System V AMD64 ABI" e como o compilador gera código que identifica buffer overflow em tempo de execução.

Gravação: https://youtu.be/_wJUzWjpccU
Meetup: https://www.meetup.com/pt-BR/hackerspaceblumenau/events/264324307/

HackerSpace Blumenau

September 04, 2019
Tweet

More Decks by HackerSpace Blumenau

Other Decks in Technology

Transcript

  1. x86-64 Assembly Overview • Registradores • Sintaxe • Básico sobre

    instruções / Pilhas • Gerenciamento de pilhas • Chamadas de funções
  2. Registradores rsi - source index (normalmente usado em operações de

    transferência de dados na memória) rdi - destination index (normalmente usado em operações de transferência de dados na memória) rbp - base pointer (aponta para o início da stack) rsp - stack pointer (aponta para o topo da stack) rax, rbx, rcx, rdx, r8 to r15 - registradores genéricos sem uso bem pré-definido
  3. Sintaxe AT&T x Intel - Diferenciando valores imediatos de registradores

    Intel Não há símbolo para diferenciar valores e registradores AT&T Registradores são precedidos por % e números são precedidos por $ mov r9d, 6 movl $6, %r9d add eax, 3 add $3, %eax
  4. Sufixos em instruções Sufixo Tamanho em bytes Exemplo b (byte;

    8-bits) 1 addb $3, %ah w (word; 16-bits) 2 addw $3, %ax l (long; 32-bits integer; 64-bits float) 4 bytes integer; 8 bytes float addl $3, %eax s (single; 32-bits float) 4 q (quadword; 64-bits) 8 addq $3, %rax t (ten bytes; 80-bits float) 10
  5. Prefixos para notação de valores imediatos Formato Prefixo Exemplo binary

    0b add$0b0110, %eax octal 0 add$03, %eax decimal none add$3, %eax hexadecimal 0x add$0x123, %eax
  6. Formato de instruções Formato Exemplo mnemônico ret mnemônico op push

    $5 mnemônico op1, op2 addl %eax, %ebx mnemônico op1, op2, op3 shufps $0x1b, %xmm0, %xmm0
  7. Sintaxe AT&T x Intel - Posições dos Operandos Intel primeiro

    operando é o destino AT&T primeiro operando é a origem mov r9d, 6 movl $6, %r9d add eax, 3 add $3, %eax
  8. Intel AT&T mov al, BYTE PTR -16[rbp] mov -16(%rbp), %al

    movb al, BYTE PTR -16[rbp] movb -16(%rbp), %al mov ah, BYTE PTR -16[rbp] mov -16(%rbp), %ah movb ah, BYTE PTR -16[rbp] movb -16(%rbp), %ah mov ax, WORD PTR -16[rbp] mov -16(%rbp), %ax movw ax, WORD PTR -16[rbp] movw -16(%rbp), %ax mov eax, DWORD PTR -16[rbp] mov -16(%rbp), %eax movl eax, DWORD PTR -16[rbp] movl -16(%rbp), %eax mov rax, QWORD PTR -16[rbp] mov -16(%rbp), %rax movq rax, QWORD PTR -16[rbp] movq -16(%rbp), %rax Sintaxe AT&T x Intel - Tamanho dos Operandos
  9. Intel AT&T add al, 3 add $3, %al addb al,

    3 addb $3, %al add ah, 3 add $3, %ah addb ah, 3 addb $3, %ah add ax, 3 add $3, %ax addw ax, 3 addw $3, %ax add eax, 3 add $3, %eax addl eax, 3 addl $3, %eax add rax, 3 add $3, %rax addq rax, 3 addq $3, %rax Sintaxe AT&T x Intel - Tamanho dos Operandos
  10. Endereçamento de memória - Formatos Endereçamento de memória segue o

    seguinte formato: segment: displacement(base register, index register, scale factor) Este formato se traduz em um índice que pode ser calculado como: base register + (index register * scale factor) + displacement Em caso queira acessar uma posição de memória fixa que não requeira nenhum registrador existe o formato (índice imediato), exemplos: mov (45), %rax mov (0x45), %rax
  11. Endereçamento de memória - Regras segment: displacement(base register, index register,

    scale factor) • Displacement é opcional e para usá-lo deve ser fornecido no mínimo o base register ou então o index register. Displacement deve ser um valor de 32 bits sinalizado (que suporte números negativos). • Scale factor é opcional mas depende do index register, sem index register não há scale factor, o contŕario é possível, pode-se ter index register sem scale factor. Scale factor pode assumir os valores 1, 2, 4 e 8. • Base register e index register são opcionais mas pelo menos um deles deve ser fornecido. Base register pode ser qualquer um dos registradores de propósito geral, index register pode ser qualquer um dos registradores de propósito geral com exceção do sp (stack pointer). • Segment é opcional e pode ser qualquer um dos registradores de segmento: cs (code segment), ds (data segment), ss (stack segment), es (extra segment), fs (outro extra segment), gs (sim tem três extra segments).
  12. Endereçamento de memória - Exemplos Formatos Traduz para AT&T (base)

    base mov (%rbp), %eax displacement(base) base + displacement mov -16(%rbp), %eax (base, index) base + index mov (%rbp, %rsi), %eax displacement(base, index) base + index + displacement mov -16(%rbp, %rsi), %eax (base, index, scale) base + index * scale mov (%rbp, %rsi, 4), %eax displacement(base, index, scale) base + index * scale + displacement mov -16(%rbp, %rsi, 4), %eax (, index, scale) index * scale mov (, %rsi, 4), %eax displacement(, index, scale) index * scale + displacement mov -16(, %rsi, 4), %eax
  13. Endereçamento de memória - Exemplos Formatos Traduz para AT&T (base,

    index) base + index mov (12, %rsi), %eax displacement(base, index, scale) base + index * scale + displacement mov -16(%rbp, 29, 4), %eax (immediate) immediate mov (43), %eax (immediate) immediate mov (0x37), %eax
  14. Sintaxe AT&T x Intel - Endereçamento de Memória Intel AT&T

    mov eax, DWORD PTR -16[rbp] movl -16(%rbp), %eax mov eax, -16[rbp] mov -16(%rbp), %eax mov eax, gs:-16[rbp + rsi * 4] mov %gs:-16(%rbp, %rsi, 4), %eax
  15. Instruções mov • From register to register • From register

    to memory • From memory to register • From memory to memory Examples: • movl %eax, %ebx • movq %rbx, -8(%rbp) • movq -8(%rbp), %rbx • movq $23421, %r8
  16. Instruções push Coloca um valor no topo da pilha e

    decrementa o registrador stack pointer (esp/rsp). Decrementa porque a pilha cresce para baixo. Exemplos: • push %rcx • push -8(%rbp) • push $37
  17. Pilha Endereço Valor 0x00000040 8 0x00000038 3 0x00000030 7 0x00000028

    43 0x00000020 21 0x00000018 17 0x00000010 1 0x00000008 82 0x00000000 24 push $8 push $3 push $7 push $43 push $21 push $17 push $1 push $82 push $24
  18. Instruções pop Copia o valor do topo da pilha para

    o registrador/memória especificado e incrementa o registrador stack pointer (esp/rsp). Incrementa o stack pointer porque a pilha cresce para baixo e estamos removendo um elemento. Example: • popq %rbp • popq -12(%rbp)
  19. Pilha Endereço Valor 0x00000040 8 0x00000038 3 0x00000030 7 0x00000028

    ... 0x00000020 ... 0x00000018 ... 0x00000010 ... 0x00000008 ... 0x00000000 ... instruction esp/rsp push $8 0x0040 push $3 0x0038 push $7 0x0030
  20. Pilha Endereço Valor 0x00000040 8 0x00000038 3 0x00000030 7 0x00000028

    ... 0x00000020 ... 0x00000018 ... 0x00000010 ... 0x00000008 ... 0x00000000 ... instruction esp/rsp push $8 0x0040 push $3 0x0038 push $7 0x0030 pop %eax 0x0038 pop %ebx 0x0040 pop não remove o valor da memória, apenas altera o valor do stack pointer (esp/rsp).
  21. Instruções enter op1, op2 enter é usado no começo da

    função chamada para salvar o contexto/stack frame da função chamadora, se comporta como se as instruções abaixo fossem executadas na seguinte ordem. push %ebp #salva a base do stack frame da função chamadora na stack mov %esp, %ebp #faz com que o topo da função chamadora se torne a base do stack frame da função chamada sub $op1, %esp #reserva op1 bytes para variáveis locais se existirem obs: a maioria dos compiladores não usam a instrução enter mas sim as instruções descritas acima por ser mais performático.
  22. Instruções leave leave é usado no final da função chamada

    para restaurar o contexto/stack frame da função chamadora, se comporta como se as instruções abaixo fossem executadas na seguinte ordem. obs: Assim como a instrução enter não é comumente utilizada o mesmo acontece com leave que costuma ser substituído pela instrução acima. mov %ebp, %esp #o stack pointer da função chamadora é o base pointer da função chamada pop %ebp #o ebp da função chamadora havia sido salvo na pilha no começo da função chamada e por isso é executado o pop, para retirá-lo da pilha
  23. Convenção de chamadas de funções 8086 IA-32 x86-64 cdecl cdecl

    Microsoft x64 calling convention fastcall stdcall vectorcall pascal fastcall System V AMD64 ABI register thiscall vectorcall
  24. System V AMD64 ABI parâmetros salvo 1st edi/rdi 2nd esi/rsi

    3rd edx/rdx 4th ecx/rcx 5th r8d/r8 6th r9d/r9 7th ahead pilha da direita para esquerda
  25. System V AMD64 ABI int callee(int p1, int p2, int

    p3, int p4,int p5,int p6, int p7, int p8, int p9, int p10, int p11) { return p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11; } int caller() { return callee(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); } pushq $11 pushq $10 pushq $9 pushq $8 pushq $7 movl $6, %r9d movl $5, %r8d movl $4, %ecx movl $3, %edx movl $2, %esi movl $1, %edi movl $6, %r9d movl $5, %r8d movl $4, %ecx movl $3, %edx movl $2, %esi movl $1, %edi pushq $11 pushq $10 pushq $9 pushq $8 pushq $7 = p1 - p6 armazenados em registradores p7… armazenados na pilha
  26. Gerenciamento de pilha int f3(int p1, int p2) { int

    c = 13; int d = 17; return c + d + p1 + p2; } int f2(int p1, int p2) { return f3(p1, p2); } int f1() { int a = 3; int b = 11; return a + b + f2(13, 9); } gcc main.c -S -O0 f1: pushq %rbp movq %rsp, %rbp pushq %rbx subq $16, %rsp movl $3, -16(%rbp) movl $11, -12(%rbp) movl -16(%rbp), %edx movl -12(%rbp), %eax leal (%rdx,%rax), %ebx movl $9, %esi movl $13, %edi call f2 addl %ebx, %eax addq $16, %rsp popq %rbx popq %rbp ret f2: pushq %rbp movq %rsp, %rbp subq $8, %rsp movl %edi, -4(%rbp) movl %esi, -8(%rbp) movl -8(%rbp), %edx movl -4(%rbp), %eax movl %edx, %esi movl %eax, %edi call f3 leave ret f3: pushq %rbp movq %rsp, %rbp movl %edi, -20(%rbp) movl %esi, -24(%rbp) movl $13, -8(%rbp) movl $17, -4(%rbp) movl -8(%rbp), %edx movl -4(%rbp), %eax addl %eax, %edx movl -20(%rbp), %eax addl %eax, %edx movl -24(%rbp), %eax addl %edx, %eax popq %rbp ret
  27. Gerenciamento de pilha void f2() { } void f1() {

    } f1: pushq %rbp movq %rsp, %rbp nop popq %rbp ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret
  28. Gerenciamento de pilha void f2() { } void f1() {

    f2(); } f1: pushq %rbp movq %rsp, %rbp movl $0, %eax call f2 nop popq %rbp ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret
  29. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $16, %rsp movl $1, -4(%rbp) movl $0, %eax call f2 nop popq %rbp leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Endereço Valor 0x090 1 0x08C 0x088 0x084 0x080 0x07C 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  30. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $16, %rsp movl $1, -8(%rbp) movl $2, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 2 0x08C 1 0x088 0x084 0x080 0x07C 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  31. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $16, %rsp movl $1, -12(%rbp) movl $2, -8(%rbp) movl $3, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 3 0x08C 2 0x088 1 0x084 0x080 0x07C 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  32. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $16, %rsp movl $1, -16(%rbp) movl $2, -12(%rbp) movl $3, -8(%rbp) movl $4, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 4 0x08C 3 0x088 2 0x084 1 0x080 0x07C 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  33. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $16, %rsp subq $32, %rsp movl $1, -20(%rbp) movl $2, -16(%rbp) movl $3, -12(%rbp) movl $4, -8(%rbp) movl $5, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 5 0x08C 4 0x088 3 0x084 2 0x080 1 0x07C 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  34. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $32, %rsp movl $1, -24(%rbp) movl $2, -20(%rbp) movl $3, -16(%rbp) movl $4, -12(%rbp) movl $5, -8(%rbp) movl $6, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 6 0x08C 5 0x088 4 0x084 3 0x080 2 0x07C 1 0x078 0x074 0x070 0x06C 0x068 0x064 0x050
  35. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $32, %rsp movl $1, -28(%rbp) movl $2, -24(%rbp) movl $3, -20(%rbp) movl $4, -16(%rbp) movl $5, -12(%rbp) movl $6, -8(%rbp) movl $7, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 7 0x08C 6 0x088 5 0x084 4 0x080 3 0x07C 2 0x078 1 0x074 0x070 0x06C 0x068 0x064 0x050
  36. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $32, %rsp movl $1, -32(%rbp) movl $2, -28(%rbp) movl $3, -24(%rbp) movl $4, -20(%rbp) movl $5, -16(%rbp) movl $6, -12(%rbp) movl $7, -8(%rbp) movl $8, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 8 0x08C 7 0x088 6 0x084 5 0x080 4 0x07C 3 0x078 2 0x074 1 0x070 0x06C 0x068 0x064 0x050
  37. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $32, %rsp subq $48, %rsp movl $1, -36(%rbp) movl $2, -32(%rbp) movl $3, -28(%rbp) movl $4, -24(%rbp) movl $5, -20(%rbp) movl $6, -16(%rbp) movl $7, -12(%rbp) movl $8, -8(%rbp) movl $9, -4(%rbp) movl $0, %eax call f2 nop leave ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 9 0x08C 8 0x088 7 0x084 6 0x080 5 0x07C 4 0x078 3 0x074 2 0x070 1 0x06C 0x068 0x064 0x050
  38. Gerenciamento de pilha void f2() { } void f1() {

    int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); } f1: pushq %rbp movq %rsp, %rbp subq $48, %rsp movl $1, -36(%rbp) movl $2, -32(%rbp) movl $3, -28(%rbp) movl $4, -24(%rbp) movl $5, -20(%rbp) movl $6, -16(%rbp) movl $7, -12(%rbp) movl $8, -8(%rbp) movl $9, -4(%rbp) movl $0, %eax call f2 nop leave popq %rbp ret f2: pushq %rbp movq %rsp, %rbp nop popq %rbp ret Address Value 0x090 9 0x08C 8 0x088 7 0x084 6 0x080 5 0x07C 4 0x078 3 0x074 2 0x070 1 0x06C 0x068 0x064 0x050
  39. Gerenciamento de pilha #include <stdio.h> void f2() { int a

    = 17; int b = 62; } int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); printf("%d\n", a); printf("%d\n", b); printf("%d\n", c); printf("%d\n", d); printf("%d\n", e); printf("%d\n", f); printf("%d\n", g); printf("%d\n", h); printf("%d\n", i); } bruno@bruno-laptop:~/git/test$ gcc file.c -O0 -o main bruno@bruno-laptop:~/git/test$ ./main 1 2 3 4 5 6 7 8 9 bruno@bruno-laptop:~/git/test$
  40. Gerenciamento de pilha #include <stdio.h> void f2() { int a

    = 17; int b = 62; } int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); printf("%d\n", a); printf("%d\n", b); printf("%d\n", c); printf("%d\n", d); printf("%d\n", e); printf("%d\n", f); printf("%d\n", g); printf("%d\n", h); printf("%d\n", i); } main: pushq %rbp movq %rsp, %rbp subq $48, %rsp movl $1, -36(%rbp) movl $2, -32(%rbp) movl $3, -28(%rbp) movl $4, -24(%rbp) movl $5, -20(%rbp) movl $6, -16(%rbp) movl $7, -12(%rbp) movl $8, -8(%rbp) movl $9, -4(%rbp) movl $0, %eax call f2 f2: pushq %rbp movq %rsp, %rbp movl $17, -8(%rbp) movl $62, -4(%rbp) nop popq %rbp ret movl -36(%rbp), %eax movl %eax, %esi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT ... movl -4(%rbp), %eax movl %eax, %esi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax leave ret
  41. Gerenciamento de pilha #include <stdio.h> void f2() { int a

    = 17; int b = 62; } int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); printf("%d\n", a); printf("%d\n", b); printf("%d\n", c); printf("%d\n", d); printf("%d\n", e); printf("%d\n", f); printf("%d\n", g); printf("%d\n", h); printf("%d\n", i); } main: pushq %rbp movq %rsp, %rbp subq $48, %rsp movl $1, -36(%rbp) movl $2, -32(%rbp) movl $3, -28(%rbp) movl $4, -24(%rbp) movl $5, -20(%rbp) movl $6, -16(%rbp) movl $7, -12(%rbp) movl $8, -8(%rbp) movl $9, -4(%rbp) movl $0, %eax call f2 f2: pushq %rbp movq %rsp, %rbp movl $17, -8(%rbp) movl $62, -4(%rbp) nop popq %rbp ret movl -36(%rbp), %eax movl %eax, %esi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT ... movl -4(%rbp), %eax movl %eax, %esi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax leave ret
  42. Gerenciamento de pilha #include <stdio.h> void f2() { int a

    = 17; int b = 62; } int main() { int a = 1; int b = 2; int c = 3; int d = 4; int e = 5; int f = 6; int g = 7; int h = 8; int i = 9; f2(); printf("%d\n", a); printf("%d\n", b); printf("%d\n", c); printf("%d\n", d); printf("%d\n", e); printf("%d\n", f); printf("%d\n", g); printf("%d\n", h); printf("%d\n", i); } bruno@bruno-laptop:~/git/test$ gcc file.s -o main bruno@bruno-laptop:~/git/test$ ./main 1 2 3 17 62 1179108064 32767 1111847473 21990 bruno@bruno-laptop:~/git/test$
  43. Gerenciamento de pilha -fno-stack-protector .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset

    6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $16, %rsp movb $97, -1(%rbp) leaq -11(%rbp), %rax movq %rax, %rsi leaq .LC0(%rip), %rdi movl $0, %eax call __isoc99_scanf@PLT movsbl -1(%rbp), %eax movl %eax, %esi leaq .LC1(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc #include <stdio.h> int main() { char a[10]; char b = 'a'; scanf("%s", a); printf("b: %c\n", b); } gcc main.c -fno-stack-protector -o not_protected ./not_protected x b: a ./not_protected abcdefghijk b: k
  44. .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp,

    %rbp .cfi_def_cfa_register 6 subq $32, %rsp movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax movb $97, -19(%rbp) leaq -18(%rbp), %rax movq %rax, %rsi leaq .LC0(%rip), %rdi movl $0, %eax call __isoc99_scanf@PLT movsbl -19(%rbp), %eax movl %eax, %esi leaq .LC1(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax movq -8(%rbp), %rdx xorq %fs:40, %rdx je .L3 call __stack_chk_fail@PLT .L3: leave .cfi_def_cfa 7, 8 ret .cfi_endproc #include <stdio.h> int main() { char a[10]; char b = 'a'; scanf("%s", a); printf("b: %c\n", b); } gcc main.c -fstack-protector -o protected == gcc main.c -o protected ./protected x b: a ./protected abcdefghijk *** stack smashing detected ***: <unknown> terminated Aborted (core dumped) Gerenciamento de pilha -fstack-protector