2012-04-26 1 views
12

Я бегу linux на i386: x86_64.Я написал кусок кода c, и я разобрал его, а также прочитал регистры, чтобы понять, как программа работает в сборке. Ниже приведена моя программа c, которую я написал.Почему этот адрес памяти имеет случайное значение?

#include <unistd.h> 
#include <string.h> 
#include <stdio.h> 

char *string_in = "Did not work"; 

int test(char *this){ 
    char sum_buf[6]; 
    strncpy(sum_buf,this,32); 
    return 0; 
} 

int hello(){ 
    printf("hello man"); 
    string_in = "If this triggered, it means our shell code is working\n"; 
    while(1){ 
     printf("Worked!"); 
    } 
    return 0; 
} 

int main(int argc, void **argv){ 
    test("\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x28\x06\x06\x40\x00\x00\x00\x00\x00");//6f 73 
    printf("My string is %s",string_in); 
    return 0; 
} 

Кусок моего кода, который я рассматривал, является тестовой функцией. Когда я разобрать выходной свою функцию тестирования я получаю ...

0x00000000004005b4 <+0>:   push %rbp 
    0x00000000004005b5 <+1>:   mov %rsp,%rbp 
    0x00000000004005b8 <+4>:   sub $0x20,%rsp 
    0x00000000004005bc <+8>:   mov %rdi,-0x18(%rbp) 
    0x00000000004005c0 <+12>:  mov %fs:0x28,%rax 
=> 0x00000000004005c9 <+21>:  mov %rax,-0x8(%rbp) 
    0x00000000004005cd <+25>:  xor %eax,%eax 
    0x00000000004005cf <+27>:  mov -0x18(%rbp),%rcx 
    0x00000000004005d3 <+31>:  lea -0x10(%rbp),%rax 
    0x00000000004005d7 <+35>:  mov $0x20,%edx 
    0x00000000004005dc <+40>:  mov %rcx,%rsi 
    0x00000000004005df <+43>:  mov %rax,%rdi 
    0x00000000004005e2 <+46>:  callq 0x400490 <[email protected]> 
    0x00000000004005e7 <+51>:  mov $0x0,%eax 
    0x00000000004005ec <+56>:  mov -0x8(%rbp),%rdx 
    0x00000000004005f0 <+60>:  xor %fs:0x28,%rdx 
    0x00000000004005f9 <+69>:  je  0x400600 <test+76> 
    0x00000000004005fb <+71>:  callq 0x4004a0 <[email protected]> 
    0x0000000000400600 <+76>:  leaveq 
    0x0000000000400601 <+77>:  retq 

Теперь мой интерес лежит в строке < 12>. Из моего понимания, что инструкция говорит компьютеру взять первые 28 бит регистра сегмента %fs и поместить его в %rax мой аккумулятор. Меня беспокоит, что до и после этой строки я читаю регистр %fs через p/x $fs, который показывает значение нуля (даже во всей программе), и поэтому %rax должен быть равен нулю. Однако %rax не показывает нуль после выполнения команды. Фактически, что приводит к случайному числу. Затем это случайное число помещается в 8 байтов до %rbp (так как оно немного условно), а затем снова проверяется в случае, если есть буфер над потоком, который переписал это пространство.

Что я хотел бы знать, это то, что mov %fs:0x28,%rax действительно делает. Правильно ли я это понял? Почему я читаю ноль для %fs, когда в p/x $fs и как я могу прочитать правильное значение?

ответ

28

На x86_64 сегментированная адресация больше не используется, но как регистры FS, так и GS могут использоваться в качестве адресов базового указателя для доступа к специальным структурам данных операционной системы. Итак, что вы видите, это значение, загруженное со смещением от значения, хранящегося в регистре FS, а не бит-манипулирование содержимым регистра FS.

В частности, то, что происходит, заключается в том, что FS:0x28 в Linux хранит специальное значение стоп-кода, и код выполняет проверку безопасности стека. Например, если вы посмотрите дальше в своем коде, вы увидите, что значение в FS:0x28 хранится в стеке, а затем содержимое стека вызывается и выполняется XOR с исходным значением в FS:0x28. Если два значения равны, это означает, что нулевой бит был установлен, потому что XOR 'с двумя одинаковыми значениями приводит к нулевому значению, затем мы переходим к подпрограмме test, иначе мы переходим к специальной функции, которая указывает что стек был каким-то образом поврежден, а значение часового, хранящееся в стеке, было изменено.

+0

Хорошо, это имеет смысл. Как я мог прочитать этот адрес и значение с помощью gdb? –

+2

Самый простой способ - посмотреть содержимое регистра RAX непосредственно после операции MOV. – Jason

1

Глядя на http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm, я думаю, %fs:28 фактически является смещением 28 байт от адреса в %fs. Поэтому я думаю, что он загружает полный размер регистра из местоположения %fs + 28 в% rax.

+3

Это неверно. 'fs' не является« нормальным »регистром. Это регистр сегментов. В защищенном режиме 'fs' является * селектором * в GDT. С ним связаны скрытые «базовые» и «предельные» регистры, которые вы не видите. Поэтому 'fs: 0x28' действительно' [hidden_fs_base + 0x28] '. –

 Смежные вопросы

  • Нет связанных вопросов^_^