2012-04-26 37 views
12

Tôi đang chạy Linux trên i386: x86_64.Tôi đã viết một đoạn mã c và tôi đã tháo rời nó cũng như đọc sổ đăng ký để hiểu cách chương trình hoạt động trong hội đồng. Dưới đây là chương trình c của tôi mà tôi đã viết.Tại sao địa chỉ bộ nhớ này có giá trị ngẫu nhiên?

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

Đoạn mã mà tôi đã kiểm tra là hàm kiểm tra. Khi tôi tháo rời đầu ra chức năng thử nghiệm của tôi, tôi nhận được ...

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 

Bây giờ sở thích của tôi nằm ở dòng < 12>. Từ sự hiểu biết của tôi rằng hướng dẫn là nói cho máy tính để lấy 28 bit đầu tiên của phân khúc đăng ký %fs và đặt nó vào %rax ắc quy của tôi. Điều gì làm phiền tôi là trước và sau khi dòng này được thực thi, tôi đọc thanh ghi %fs qua p/x $fs hiển thị giá trị bằng không (ngay cả trong suốt chương trình) và do đó %rax phải bằng 0. Tuy nhiên %rax không hiển thị số không sau khi lệnh đã được thực hiện. Trong thực tế, kết quả là một số ngẫu nhiên. Số ngẫu nhiên này sau đó được đặt 8 byte trước %rbp (vì nó là ít endian) và sau đó kiểm tra lại trong trường hợp có một bộ đệm trên dòng chảy đã ghi đè không gian đó.

Điều tôi muốn biết là những gì mov %fs:0x28,%rax thực sự đang thực hiện. Tôi đã hiểu nó phải không? Tại sao tôi đọc số không cho %fs khi ở trong p/x $fs và làm cách nào để đọc giá trị chính xác?

Trả lời

28

Trên x86_64, địa chỉ phân đoạn không còn được sử dụng, nhưng cả sổ đăng ký FSGS đều có thể được sử dụng làm địa chỉ con trỏ cơ sở để truy cập cấu trúc dữ liệu hệ điều hành đặc biệt. Vì vậy, những gì bạn đang thấy là một giá trị được nạp tại một giá trị bù trừ từ giá trị được giữ trong thanh ghi FS và không thao tác bit về nội dung của thanh ghi FS.

Cụ thể những gì đang diễn ra, là FS:0x28 trên Linux đang lưu trữ giá trị ngăn xếp ngăn xếp đặc biệt và mã đang thực hiện kiểm tra ngăn xếp ngăn xếp. Ví dụ, nếu bạn nhìn xa hơn trong mã của bạn, bạn sẽ thấy rằng giá trị tại FS:0x28 được lưu trữ trên ngăn xếp, và sau đó nội dung của ngăn xếp được thu hồi và XOR được thực hiện với giá trị ban đầu tại FS:0x28. Nếu hai giá trị bằng nhau, có nghĩa là bit zero đã được thiết lập vì XOR 'nhập hai giá trị giống nhau dẫn đến giá trị bằng không, sau đó chúng ta chuyển sang thói quen test, nếu không chúng ta sẽ chuyển sang một hàm đặc biệt cho biết rằng ngăn xếp bằng cách nào đó bị hỏng, và giá trị sentinel được lưu trữ trên ngăn xếp đã được thay đổi.

+0

Ok, điều đó có ý nghĩa. Làm thế nào tôi có thể đọc địa chỉ và giá trị này với gdb? –

+2

Cách đơn giản nhất là xem nội dung của thanh ghi RAX trực tiếp sau thao tác MOV. – Jason

1

Nhìn vào http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm, tôi nghĩ %fs:28 thực sự là khoản bù trừ 28 byte từ địa chỉ trong %fs. Vì vậy, tôi nghĩ rằng nó tải một kích thước đăng ký đầy đủ từ vị trí %fs + 28 vào% rax.

+3

Điều này không chính xác. 'fs' không phải là đăng ký" bình thường ". Nó là một thanh ghi phân đoạn. Trong chế độ được bảo vệ, 'fs' là bộ chọn * * vào GDT. Có các thanh ghi "cơ sở" và "giới hạn" ẩn được liên kết với nó, mà bạn không thể nhìn thấy. Vì vậy, 'fs: 0x28' thực sự là' [hidden_fs_base + 0x28] '. –

Các vấn đề liên quan