A partir deste post é mostrado que FS:[0x28]
é um stack-canary. Estou gerando esse mesmo código usando o GCC nesta função,
void foo () {
char a[500] = {};
printf("%s", a);
}
Especificamente, estou recebendo esta montagem ..
0x000006b5 64488b042528. mov rax, qword fs:[0x28] ; [0x28:8]=0x1978 ; '(' ; "x\x19"
0x000006be 488945f8 mov qword [local_8h], rax
...stuff...
0x00000700 488b45f8 mov rax, qword [local_8h]
0x00000704 644833042528. xor rax, qword fs:[0x28]
0x0000070d 7405 je 0x714
0x0000070f e85cfeffff call sym.imp.__stack_chk_fail ; void __stack_chk_fail(void)
; CODE XREF from 0x0000070d (sym.foo)
0x00000714 c9 leave
0x00000715 c3 ret
O que está configurando o valor de fs:[0x28]
? O kernel, ou o GCC está lançando o código? Você pode mostrar o código no kernel ou compilado no binário que define fs:[0x28]
? O canário é regenerado - na inicialização ou no processo de geração? Onde isso está documentado?
É fácil rastrear essa inicialização, pois (quase) todos os processos
strace
mostram uma syscall muito suspeita durante o início da execução do processo:É o que
man 2 arch_prctl
diz:Eba, parece que é disso que precisamos. Para encontrar quem chama
arch_prctl
, vamos procurar um backtrace:Assim, a base do segmento FS é definida pelo
ld-linux
, que faz parte deglibc
, durante o carregamento do programa (se o programa estiver vinculado estaticamente, esse código será incorporado ao binário). É aqui que tudo acontece.Durante a inicialização, o carregador inicializa o TLS . Isso inclui alocação de memória e configuração do valor base do FS para apontar para o início do TLS. Isso é feito via
arch_prctl
syscall .security_init
Depois que a função de inicialização TLS é chamada, o que gera o valor do protetor de pilha e o grava no local da memória, quefs:[0x28]
aponta para:E
0x28
é o deslocamento dostack_guard
campo na estrutura que está localizado no início do TLS.O que você está vendo é chamado (no GCC) de Stack Smashing Protector (SSP) , que é uma forma de proteção contra estouro de buffer gerada pelo compilador. O valor é um número aleatório gerado pelo programa na inicialização e como o artigo da Wikipedia menciona, é colocado em Thread Local Storage (TLS) . Outros compiladores podem usar estratégias diferentes para implementar esse tipo de proteção.
Por que armazenar o valor em TLS? Como o valor está localizado lá, seu endereço não é acessível pelos registradores CS, DS e SS, tornando muito difícil adivinhar o valor armazenado se você estiver tentando alterar a pilha de código malicioso.