Trang 1 trên tổng số 2 12 Cuối cùngCuối cùng
Từ 1 tới 10 trên tổng số 11 kết quả

Đề tài: Có ai giải thích giùm không?

  1. #1
    Ngày gia nhập
    07 2014
    Bài viết
    8

    Mặc định Có ai giải thích giùm không?

    Mình có 1 chương trình kiểm tra password:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int check_authentication(char *password){
    	int auth_flag = 0;
    	char password_buffer[16];
    	strcpy(password_buffer, password);
    	if(strcmp(password_buffer, "password1") == 0){
    		auth_flag = 1;
    	}
    	return auth_flag;
    }
    
    int main(int argc, char *argv[]){
    	if(check_authentication(argv[1])){
    		printf("Access granted!");
    	}
    	else{
    		printf("Access denied!");
    	}
    }
    và khi chạy:
    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		checkpass.jpg
Lần xem:	17
Size:		429.7 KB
ID:		27389
    The problem is not the problem. the problem is your attitude about the problem

  2. #2
    Ngày gia nhập
    01 2013
    Bài viết
    1,479

    Buffer overflow kìa
    Đã được chỉnh sửa lần cuối bởi prog10 : 06-03-2015 lúc 11:24 PM.

  3. #3
    Ngày gia nhập
    07 2011
    Bài viết
    474

    do password_buffer[16] chỉ chứa được tối đa 15 chữ nên input nhiều hơn 15 chữ sẽ bị chép đè...

    EDIT: "password1" ko nằm trên stack

    Code:
    password_buffer      ???????????     auth_flag
    [0][1][2]...[14][15] [16][17]...[27] [28][29][30][31]
    password_buffer chiếm 16 bytes từ 0-15
    ??????? chiếm 12 bytes từ 16-27
    auth_flag chiếm 4 bytes từ 28-31

    chuỗi có 29 ký tự sẽ chép đè lên cả vị trí của "password1" và auth_flag, làm auth_flag mang giá trị khác 0 (do có ký tự '9'). Còn chuỗi 28 ký tự tuy cũng có thể chép đè lên auth_flag, nhưng nó chép ký tự '\0' nên auth_flag vẫn mang giá trị 0.

    vì sao "password1" 9 ký tự chiếm 12 bytes chứ ko phải 10 bytes thì là do data alignment. Data alignment nôm na là máy tính đọc thường đọc 4 bytes 1 lúc, ko đọc từng byte. Ở đây nếu "password1" chiếm 10 byte thì để máy tính đọc auth_flag, máy tính sẽ phải đọc 2 lần: lần 1 là 2 bytes cuối của "password1" và 2 bytes đầu của auth_flag. Lần 2 là 2 bytes cuối của auth_flag và 2 byte rác phía sau. Sau đó phải ghép 2 bytes đầu và 2 bytes cuối của auth_flag lại với nhau để được auth_flag. Vì đọc khó khăn vậy nên password1" chiếm luôn 12 bytes, việc đọc auth_flag sẽ dễ hơn, chỉ cần đọc 1 lần và chả phải ghép gì.
    Đã được chỉnh sửa lần cuối bởi INTP : 07-03-2015 lúc 01:19 AM.

  4. #4
    Ngày gia nhập
    01 2013
    Bài viết
    1,479

    @thớt: vậy tại sao dữ liệu lại có thứ tự như vậy

  5. #5
    Ngày gia nhập
    07 2011
    Bài viết
    474

    ta cũng nghĩ là ko nằm ở đó được, nhưng chạy cái test trên thì thấy đúng 29 ký tự thì nó cho access granted, 28 ký tự thì denied, tức là auth_flag phải nằm ở đúng byte thứ 28-31. Như vậy khoảng cách giữa auth_flag và password_buffer phải là 12 bytes, vừa khớp cho chuỗi "password1" kia. Như vậy chắc là trình duyệt tạo thêm 1 biến tạm thời chứa giá trị "password1" nên nó bị đẩy lên stack luôn :-?

    nếu ko có thì xâu 28 hay 17 ký tự là chép hư auth_flag rồi @_@

  6. #6
    Ngày gia nhập
    07 2014
    Bài viết
    8

    Mặc định Có ai giải thích giùm không?

    ở ví dụ trên nếu chuyển độ dài password_buffer nhỏ hơn ví dụ password_buffer[10] thì cái giải thích của INTP có vẻ không đúng thì phải?
    The problem is not the problem. the problem is your attitude about the problem

  7. #7
    Ngày gia nhập
    01 2013
    Bài viết
    1,479

    Trích dẫn Nguyên bản được gửi bởi tdracuda Xem bài viết
    ở ví dụ trên nếu chuyển độ dài password_buffer nhỏ hơn ví dụ password_buffer[10] thì cái giải thích của INTP có vẻ không đúng thì phải?
    Bạn có các cặp input/output ko

  8. #8
    Ngày gia nhập
    07 2014
    Bài viết
    8

    Trích dẫn Nguyên bản được gửi bởi INTP Xem bài viết
    do password_buffer[16] chỉ chứa được tối đa 15 chữ nên input nhiều hơn 15 chữ sẽ bị chép đè...

    Code:
    password_buffer      "password1"     auth_flag
    [0][1][2]...[14][15] [16][17]...[27] [28][29][30][31]
    password_buffer chiếm 16 bytes từ 0-15
    "password1" chiếm 12 bytes từ 16-27
    auth_flag chiếm 4 bytes từ 28-31

    chuỗi có 29 ký tự sẽ chép đè lên cả vị trí của "password1" và auth_flag, làm auth_flag mang giá trị khác 0 (do có ký tự '9'). Còn chuỗi 28 ký tự tuy cũng có thể chép đè lên auth_flag, nhưng nó chép ký tự '\0' nên auth_flag vẫn mang giá trị 0.

    vì sao "password1" 9 ký tự chiếm 12 bytes chứ ko phải 10 bytes thì là do data alignment. Data alignment nôm na là máy tính đọc thường đọc 4 bytes 1 lúc, ko đọc từng byte. Ở đây nếu "password1" chiếm 10 byte thì để máy tính đọc auth_flag, máy tính sẽ phải đọc 2 lần: lần 1 là 2 bytes cuối của "password1" và 2 bytes đầu của auth_flag. Lần 2 là 2 bytes cuối của auth_flag và 2 byte rác phía sau. Sau đó phải ghép 2 bytes đầu và 2 bytes cuối của auth_flag lại với nhau để được auth_flag. Vì đọc khó khăn vậy nên password1" chiếm luôn 12 bytes, việc đọc auth_flag sẽ dễ hơn, chỉ cần đọc 1 lần và chả phải ghép gì.
    Làm vài ví dụ thì thấy, nếu password_buffer nhỏ hơn 12 bytes thì ô nhớ kế dùng để lưu biến auth_flag
    còn nếu password_buffer lớn hơn 12 bytes thì ô nhớ kế đó dùng để lưu "password1"

    Không biết có phải không!

    - - - Nội dung đã được cập nhật ngày 06-03-2015 lúc 11:55 PM - - -

    Trích dẫn Nguyên bản được gửi bởi prog10 Xem bài viết
    @thớt: vậy tại sao dữ liệu lại có thứ tự như vậy
    mình nhập thôi mà... nhập thế cho dễ đếm thôi !!!
    The problem is not the problem. the problem is your attitude about the problem

  9. #9
    Ngày gia nhập
    07 2011
    Bài viết
    474

    ta chạy thử thấy nó denied hết mà @_@ Hơn nữa in địa chỉ từng biến ra thì thấy auth_flag được để nằm trước password_buffer và "password1" thì nằm trong vùng .data chứ ko phải stack. Ko hiểu sao lần chạy kia 29 ký tự lại granted =)

    compile có phải ở chế độ debug ko? có optimize gì ko?


    ồ ta ko xài -O2 thì nó ra lỗi granted như trên =)



    "password1" KHÔNG nằm trên stack. Cách giải thích của ta sai rồi. Nhưng sửa buffer lại thành [12] thì chuỗi 13 14 ký tự nó đều cho granted trong khi 16 lại ko cho =)

    [12] thì buffer ở cách 0x23fe00 16 byte
    23fe10
    23fe1c
    => buffer cách auth_flag 12 ký tự, input >= 13 ký tự sẽ làm auth_flag mang giá trị khác 0

    [16] thì buffer ở ngay 0x23fe00
    23fe00
    23fe1c
    => buffer cách auth_flag 28 ký tự, input >= 29 ký tự sẽ làm auth_flag mang giá trị khác 0

    vậy là tùy thằng biên dịch lúc chưa optimize nó sắp xếp dữ liệu như thế nào.


    nếu có flag -O2
    [16] hay [12] thì đều ra
    23fe00
    23fdfc
    tức là auth_flag nằm trước buffer 4 bytes => ko bị chép đè, bảo đảm ko bị lỗi granted.

    (nhưng bao giờ cũng gặp lỗi buffer overflow)
    Đã được chỉnh sửa lần cuối bởi INTP : 07-03-2015 lúc 01:23 AM.

  10. #10
    Ngày gia nhập
    01 2013
    Bài viết
    1,479

    "password1" là literal string mà, nằm ở .data chứ
    Mà nếu vọc sao đó để sinh mã assembly sẽ dễ thấy hơn.

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn