C (x86_64), 11, 30, 34 hoặc 34 + 15 = 49 byte
main[]="/";
c=6;main(){((void(*)())&c)();}
main(){int c=6;((void(*)())&c)();}
Tôi đã gửi một vài giải pháp sử dụng các chức năng của thư viện để đưa ra SIGILL
các phương tiện khác nhau, nhưng có thể cho rằng đó là gian lận, trong đó chức năng thư viện giải quyết vấn đề. Đây là một loạt các giải pháp không sử dụng các chức năng thư viện và đưa ra các giả định khác nhau về nơi hệ điều hành sẵn sàng cho phép bạn thực thi mã không thể thực thi. (Các hằng số ở đây được chọn cho x86_64, nhưng bạn có thể thay đổi chúng để có giải pháp hoạt động cho hầu hết các bộ xử lý khác có hướng dẫn bất hợp pháp.)
06
là byte được đánh số thấp nhất của mã máy không tương ứng với một lệnh được xác định trên bộ xử lý x86_64. Vì vậy, tất cả chúng ta phải làm là thực hiện nó. (Ngoài ra, 2F
cũng không được xác định và tương ứng với một ký tự ASCII có thể in được.) Cả hai điều này đều được đảm bảo luôn luôn không được xác định, nhưng chúng không được định nghĩa cho đến ngày hôm nay.
Chương trình đầu tiên ở đây thực thi 2F
từ phân đoạn dữ liệu chỉ đọc. Hầu hết linkers không có khả năng tạo ra một bước nhảy làm việc kể từ .text
đến .rodata
(hoặc hệ điều hành của họ tương đương) vì nó không phải là cái gì đó bao giờ sẽ có ích trong một chương trình một cách chính xác phân đoạn; Tôi chưa tìm thấy một hệ điều hành nào mà nó hoạt động được. Bạn cũng phải cho phép thực tế là nhiều trình biên dịch muốn chuỗi được đề cập là một chuỗi rộng, điều này sẽ yêu cầu bổ sungL
; Tôi giả định rằng bất kỳ hệ điều hành nào mà hệ điều hành này hoạt động đều có một cái nhìn khá lỗi thời về mọi thứ, và do đó đang xây dựng cho một tiêu chuẩn trước C94 theo mặc định. Có thể không có chương trình này hoạt động ở đâu, nhưng cũng có thể có một nơi nào đó chương trình này hoạt động, và do đó tôi liệt kê nó trong bộ sưu tập các câu trả lời tiềm năng đáng ngờ hơn đến ít đáng ngờ hơn. (Sau khi tôi đăng câu trả lời này, Dennis cũng đề cập đến khả năng main[]={6}
trong trò chuyện, có cùng độ dài và không gặp vấn đề với độ rộng ký tự, và thậm chí còn ám chỉ tiềm năng main=6
; Tôi không thể yêu cầu các câu trả lời này một cách hợp lý của tôi, như tôi đã không nghĩ về họ.)
Chương trình thứ hai ở đây thực thi 06
từ phân đoạn dữ liệu đọc-ghi. Trên hầu hết các hệ điều hành, điều này sẽ gây ra lỗi phân đoạn, bởi vì các phân đoạn dữ liệu có thể ghi được coi là một lỗ hổng thiết kế xấu khiến cho việc khai thác có thể xảy ra. Tuy nhiên, điều này không phải luôn luôn như vậy, vì vậy nó có thể hoạt động trên một phiên bản Linux đủ cũ, nhưng tôi không thể dễ dàng kiểm tra nó.
Chương trình thứ ba thực hiện 06
từ ngăn xếp. Một lần nữa, điều này gây ra lỗi phân đoạn hiện nay, vì ngăn xếp thường được phân loại là không thể ghi được vì lý do bảo mật. Tài liệu liên kết mà tôi thấy rất nhiều ngụ ý rằng nó từng là hợp pháp để thực thi từ ngăn xếp (không giống như hai trường hợp trước, đôi khi làm như vậy rất hữu ích), vì vậy mặc dù tôi không thể kiểm tra nó, tôi khá chắc chắn có một số phiên bản Linux (và có lẽ các hệ điều hành khác) mà nó hoạt động.
Cuối cùng, nếu bạn đưa ra -Wl,-z,execstack
(hình phạt 15 byte) cho gcc
(nếu sử dụng GNU ld
như một phần của phụ trợ), nó sẽ tắt rõ ràng bảo vệ ngăn xếp thực thi, cho phép chương trình thứ ba hoạt động và đưa ra tín hiệu hoạt động bất hợp pháp như mong đợi. Tôi đã thử nghiệm và xác minh phiên bản 49 byte này để hoạt động. (Dennis đề cập trong trò chuyện rằng tùy chọn này rõ ràng hoạt động với main=6
, nó sẽ cho điểm 6 + 15. Tôi khá ngạc nhiên khi điều này hoạt động, với điều kiện là 6 không rõ ràng trên stack; tùy chọn liên kết rõ ràng không hơn tên của nó cho thấy.)
raise(SIGILL)
không?