Tài liệu Hợp ngữ và tràn bộ đệm

  • Số trang: 37 |
  • Loại file: PDF |
  • Lượt xem: 459 |
  • Lượt tải: 0

Mô tả:

Hợp ngữ ● Gán 2 vào EAX ● ● MOV EBX, 3 Tính ECX = EAX + EBX ● ● ● EAX, 2 Gán 3 vào EBX ● ● MOV MOV ADD ECX, EAX ECX, EBX Hoặc LEA ECX, [EAX+EBX] Tính EDX = EAX * EBX ● ... Hợp ngữ ● Cho EAX=1, dùng một lệnh luận lý để gán EAX=-1 ● ● ● NEG EAX Cho EAX=FFFFFFFF, dùng một lệnh số học để gán EAX=0 ● ADD EAX, 1 ● Hoặc SUB EAX, FFFFFFFF Cho EAX=0, dùng một lệnh số học để gán EAX=FFFFFFFF ● SUB EAX, 1 ● Hoặc ADD EAX, FFFFFFFF Hợp ngữ ● ● Cho EAX là một số bất kỳ, dùng một lệnh khác MOV để gán EAX=0 ● SUB EAX, EAX ● Hoặc XOR EAX, EAX ● Hoặc AND EAX, 0 ● Hoặc LEA EAX, [0] Cho EAX là một số bất kỳ, dùng một lệnh khác MOV để gán EAX=FFFFFFFF ● OR EAX, FFFFFFFF Hợp ngữ ● Gán giá trị ở đỉnh ngăn xếp vào EAX ● ● POP EBX Gán giá trị của phần tử thứ hai trên ngăn xếp vào ECX ● ● EAX, [ESP] Lấy ra giá trị ở đỉnh ngăn xếp vào EBX ● ● MOV MOV ECX, [ESP + 4] Lấy ra giá trị của phần tử thứ hai trên ngăn xếp vào EDX (vẫn giữ giá trị của đỉnh ngăn xếp) ● ... Hợp ngữ ● Gán giá trị của EIP vào EAX ● ● Gán giá trị của EAX vào EIP ● ● … Dùng một lệnh để thực hiện phép chia lấy dư của EAX cho 16 ● ● ... AND EAX, 0x0F Kiểm tra nếu EAX chia hết cho 4 ● AND EAX, 0x03 Hợp ngữ ● Xét hàm ● int func(int a, int b) { int c; char d[7]; short e; return 0; } ● 2 đối số là a và b ● 3 biến nội bộ là c, d và e ● Biến a dài 4 byte, b 4, c 4, d 7 và e 2. Hợp ngữ ● ● Một hàm sẽ có các phần dẫn nhập, thân hàm, và kết thúc Dẫn nhập: ● ● ● ● PUSH MOV SUB EBP EBP, ESP ESP, 0x20 Biến nội bộ được cấp trên ngăn xếp Các biến nội bộ được cấp vùng nhớ theo thứ tự khai báo Biến được cấp vùng nhớ là bội số của 4 Hợp ngữ Hợp ngữ ● Thân hàm ● XOR EAX, EAX ● Kết quả trả về của hàm được lưu trong EAX ● Trong thân hàm, EBP không thay đổi ● Kết thúc: ● MOV POP RET ESP, EBP EBP Hợp ngữ Hợp ngữ ● Gọi hàm ● ● ● ● ● PUSH PUSH CALL b a func Đối số được “push” từ phải qua trái Vùng từ đối số đến biến nội bộ gọi là vùng nhớ (khung nhớ) ngăn xếp (stack frame) Vùng nhớ ngăn xếp thể hiện một hàm chưa thực thi xong EBP luôn chỉ đến ô “EBP cũ” trong vùng nhớ. Xác định được 1 ô → xác định các ô còn lại Hợp ngữ Hợp ngữ Hợp ngữ Tràn bộ đệm ● ● Dữ liệu nhập dài quá giới hạn bộ nhớ chứa nó Dữ liệu dư ra này có thể đè lên dữ liệu quan trọng dẫn đến cơ hội tận dụng Tràn bộ đệm ● Dữ liệu quan trọng phải nằm sau bộ đệm ● Phải tràn tới được dữ liệu quan trọng ● Dữ liệu bị ghi đè phải được sử dụng Tràn bộ đệm ● Ghi đè giá trị biến nội bộ ● Biến nội bộ nằm trong ngăn xếp ● Tràn ngăn xếp có thể đè lên biến nội bộ ● Ít bị phát hiện ● Có thể có ảnh hưởng lớn đến kết quả chương trình Tràn bộ đệm ● Xét ví dụ ● int main() { int cookie; char buf[16]; gets(buf); if (cookie==0x41424344) { puts(“You win!”); } } Tràn bộ đệm ● 2 biến nội bộ ● cookie kiểu int, 4 byte ● buf kiểu mảng char, 16 byte ● ● ● cookie nằm phía sau buf → tràn buf có thể làm thay đổi cookie Nhập 16 ký tự bất kỳ sẽ làm đầy buf, ký tự thứ 17 sẽ đè lên cookie → trở thành byte thấp của cookie Nhập 20 ký tự sẽ kiểm soát toàn bộ cookie Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm ● Ghi đè địa chỉ trở về ● Địa chỉ trở về nằm trong ngăn xếp ● Ghi đè địa chỉ trở về làm thay đổi luồng thực thi ● Bị phát hiện trong các trình biên dịch hiện đại Tràn bộ đệm ● Xét ví dụ ● int main() { int cookie; char buf[16]; gets(buf); if (cookie==0x000D0A00) { puts(“You win!”); } } Tràn bộ đệm ● ● Gần giống ví dụ trước Hàm gets() ngắt tại 0x0A → không thể kiểm soát trọn vẹn giá trị cookie ● Nhưng vẫn kiểm soát được địa chỉ trở về ● → gán địa chỉ nhánh “==” vào ô ngăn xếp đó Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm Tràn bộ đệm ● ● 0804849d: 080484a4: 080484a6: 080484a9: 080484ae: 080484b3: 080484b6: cmp jne add push call add … [ebp-4], 0x0d0a00 0x080484b6 esp, 0xfffffff4 0x080485e7 printf esp, 0x10 Có thể dùng 080484a6 hoặc 080484a9 Tràn bộ đệm Tràn bộ đệm ● ● ● Một số hàm không an toàn là gets(), strcpy(), strcat(), sprintf(). int main(int argc, char **argv) { char name[128]; strcpy(name, argv[1]); strcat(name, “ = “); strcat(name, argv[2]); return 0; } Cả ba lệnh đều có thể gây tràn biến name Tràn bộ đệm ● ● ● int main(int argc, char **argv) { char name[128]; sprintf(name, “%s”, argv[1]); return 0; } Hàm sprintf() có thể gây tràn biến name nếu argv[1] là chuỗi dài hơn 128 ký tự. Cách khắc phục thay bằng các hàm “an toàn” hơn như fgets(), strncpy(), snprintf(). Tràn bộ đệm ● Xét ví dụ ● int main(void) { char a[16]; char b[16]; char c[32]; strncpy(a, "0123456789abcdef", sizeof(a)); strncpy(b, "0123456789abcdef", sizeof(b)); strncpy(c, a, sizeof(c)); } Tràn bộ đệm ● ● ● ● Tất cả 3 hàm đều là hàm “an toàn” strncpy() không tự động chèn ký tự NUL vào chuỗi → chuỗi a, và b không được ngắt (nhìn lên bảng) Khắc phục bằng cách đảm bảo chuỗi phải được ngắt bằng ký tự NUL ● Ví dụ a[15] = b[15] = '\x00'; Tràn bộ đệm ● Bảo đảm bộ đệm có thể chứa đủ ● ● char *b = malloc(strlen(argv[1]) + 1); if (b != NULL) { strcpy(b, argv[1]); printf("argv[1] = %s.\n", b); } Dùng các hàm “an toàn” hơn nữa như strlcpy(), strlcat(), strcpy_s(), strcat_s(), strncpy_s(), strncat_s()... ● Compiler hiện đại với chức năng StackGuard ● Luôn nghĩ về khả năng bị tràn
- Xem thêm -