Почему этот адрес памяти% fs: 0x28 (fs [0x28]) имеет случайное значение?
Я написал фрагмент кода на C и разобрал его, а также прочитал регистры, чтобы понять, как программа работает в ассемблере.
int test(char *this){
char sum_buf[6];
strncpy(sum_buf,this,32);
return 0;
}
Часть моего кода, которую я изучал, является тестовой функцией. Когда я разбираю вывод своей тестовой функции, я получаю...
0x00000000004005c0 <+12>: mov %fs:0x28,%rax
=> 0x00000000004005c9 <+21>: mov %rax,-0x8(%rbp)
... stuff ..
0x00000000004005f0 <+60>: xor %fs:0x28,%rdx
0x00000000004005f9 <+69>: je 0x400600 <test+76>
0x00000000004005fb <+71>: callq 0x4004a0 <[email protected]>
0x0000000000400600 <+76>: leaveq
0x0000000000400601 <+77>: retq
Я хотел бы знать, что действительно делает mov %fs:0x28,%rax
?
Ответы
Ответ 1
На x86_64 сегментированная адресация больше не используется, но регистры FS
и GS
могут использоваться в качестве адресов базовых указателей для доступа к специальным структурам данных операционной системы. Итак, вы видите значение, загруженное со смещением от значения, хранящегося в регистре FS
, а не битовые манипуляции с содержимым регистра FS
.
В частности, происходит то, что FS:0x28
в Linux хранит специальное значение сторожевого стража, а код выполняет проверку защитного стека. Например, если вы посмотрите дальше в своем коде, вы увидите, что значение в FS:0x28
сохраняется в стеке, а затем FS:0x28
содержимое стека и выполняется XOR
с исходным значением в FS:0x28
, Если эти два значения равны, что означает, что нулевой бит был установлен, потому что XOR
, если два одинаковых значения приводят к нулевому значению, мы переходим к процедуре test
, в противном случае мы переходим к специальной функции, которая указывает что стек был каким-то образом поврежден, и значение часового, хранящееся в стеке, было изменено.
При использовании GCC это можно отключить с помощью
-fno-stack-protector
Ответ 2
glibc:
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
THREAD_SET_STACK_GUARD (stack_chk_guard);
the _dl_random from kernel.
Ответ 3
Глядя на http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm, я думаю, что %fs:28
на самом деле является смещением 28 байтов от адреса в %fs
. Поэтому я думаю, что он загружает полный размер регистра из местоположения %fs + 28
в% rax.