2012-04-26 19 views
12

I386 üzerinde linux çalıştırıyorum: x86_64.Ç bir parça kod yazdım ve programın nasıl çalıştığını anlamak için yazmaçları okuduğum kadar bunları da parçalarına ayırdım. Aşağıda yazdığım programım var.Bu bellek adresi neden rasgele bir değere sahip?

#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; 
} 

İncelemekte olduğum kodumun parçası test işlevidir. Ben olsun çıktı benim test fonksiyonunu ... sökerken

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 

Şimdi benim ilgi hattı < 12> yatıyor. Anladığım kadarıyla, bu talimatın, bilgisayara %fs bölümünün ilk 28 bitini almasını ve %rax akümülatörüme koymasını söylüyorum. Beni rahatsız eden şey, bu satırın uygulanmasından önce ve sonra, %fs kayıt numarasını p/x $fs üzerinden okuyarak sıfır değerini (program boyunca bile) gösterir ve böylece %rax sıfır olmalıdır. Ancak, talimat yürütüldükten sonra %rax sıfır göstermez. Aslında sonuç ne rasgele bir sayıdır. Bu rasgele sayı daha sonra %rbp'dan önce 8 byte yerleştirilir (küçük endian olduğu için) ve daha sonra bu alanın üzerine yazılan akış üzerinde bir tampon olması durumunda tekrar kontrol edilir.

Bilmek istediklerim, mov %fs:0x28,%rax'un gerçekten ne yaptığıdır. Bunu doğru mu anladım? p/x $fs numaralı telefondan %fs için neden sıfır okuyorum ve doğru değeri nasıl okuyacağım?

cevap

28

x86_64'de, bölümlendirilmiş adresleme artık kullanılmıyor, ancak FS ve GS kayıtlarının her ikisi de, özel işletim sistemi veri yapılarına erişmek için temel işaretçi adresleri olarak kullanılabilir. Gördüğünüz şey, FS kaydında tutulan değerden bir ofset yüklü bir değerdir ve FS kaydının içeriğinin bit manipülasyonu değildir.

Özellikle neler olup bittiği, Linux'taki FS:0x28 özel bir sentinel yığın koruma değerini saklaması ve kodun bir yığın koruma denetimi gerçekleştirmesidir. Örneğin, kodunuza daha fazla bakarsanız, FS:0x28'daki değerin yığında saklandığını görürsünüz ve yığının içeriği geri çağrılır ve XOR, FS:0x28 numaralı özgün değerle gerçekleştirilir. Eğer iki değer eşitse, yani sıfır bitin ayarlanmış olması, XOR'un aynı değerlerden ikisinin sıfır değeriyle sonuçlandığından, test rutinine atlıyoruz, aksi halde özel bir işleve atlıyoruz Yığın bir şekilde bozulmuş ve yığında saklanan sentinel değeri değiştirildi.

+0

Tamam, bu mantıklı. Bu adresi ve değeri gdb ile nasıl okuyabilirim? –

+2

En basit yol, MOV operasyonundan sonra RAX kaydının içeriğine doğrudan bakmaktır. – Jason

1

http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm'a baktığımda, %fs:28'un aslında %fs adresindeki 28 baytlık bir ofset olduğunu düşünüyorum. Bu yüzden, %fs + 28 konumundan% rax'a tam bir kayıt boyutu yüklediğini düşünüyorum.

+3

Bu doğru değil. fs, "normal" bir kayıt değildir. Bir bölüm kaydıdır. Korumalı modda, 'fs' GDT'ye * seçicidir *. Onunla ilişkili gizli "taban" ve "sınır" kayıtları vardır, göremezsiniz. Yani 'fs: 0x28' gerçekten' '[hidden_fs_base + 0x28]' dır. –

İlgili konular