Mã ngắn nhất để ném SIGILL


76

Lý lịch

Chúng tôi đã có một thử thách về việc ném SIGSEGV , vậy tại sao không thử thách ném SIGILL?

SIGILL là gì?

SIGILL là tín hiệu cho một lệnh bất hợp pháp tại bộ xử lý, điều này rất hiếm khi xảy ra. Hành động mặc định sau khi nhận SIGILL là chấm dứt chương trình và viết kết xuất lõi. ID tín hiệu của SIGILL là 4. Bạn rất hiếm khi gặp SIGILL và tôi hoàn toàn không biết làm thế nào để tạo nó trong mã của bạn ngoại trừ thông qua sudo kill -s 4 <pid>.

Quy tắc

Bạn sẽ có quyền root trong các chương trình của mình, nhưng nếu bạn không muốn vì bất kỳ lý do gì, bạn cũng có thể sử dụng một người dùng bình thường. Tôi đang sử dụng máy tính Linux có ngôn ngữ tiếng Đức và tôi không biết văn bản tiếng Anh được hiển thị sau khi bắt SIGILL, nhưng tôi nghĩ đó là một thứ như 'Hướng dẫn bất hợp pháp'. Chương trình ngắn nhất ném SIGILL thắng.


6
Bạn có thể muốn làm rõ liệu lệnh có phải được tạo bởi kernel hay không. Cụ thể, bạn có muốn cho phép chương trình chỉ tạo trực tiếp bằng lệnh gọi libc raise(SIGILL)không?

1
Nó thực sự nói Illegal instruction (core dumped).
Erik the Outgolfer

@ ais523 Mọi thứ đều được phép.
Mega Man

5
Đối với bất kỳ phần cứng nào có thể tăng SIGILL, câu trả lời sẽ giống như độ dài hướng dẫn. Chỉ cần đặt một hướng dẫn bất hợp pháp ở đâu đó và cố gắng thực hiện nó. Điều thú vị duy nhất sẽ là chuỗi công cụ phức tạp có liên quan.
OrangeDog

3
* những người đăng các chương trình cũ mà họ đã không hoạt động *
RudolfJelin

Câu trả lời:


112

Trình biên dịch PDP-11 (Phiên bản thứ sáu UNIX), 1 byte

9

Hướng dẫn 9 không phải là hướng dẫn hợp lệ trên PDP-11 (theo bát phân, nó sẽ 000011không xuất hiện trong danh sách hướng dẫn (PDF)). Trình biên dịch PDP-11 đi kèm với UNIX Sixth Edition rõ ràng lặp lại mọi thứ mà nó không hiểu trực tiếp vào tệp; trong trường hợp này, 9 là một số, vì vậy nó tạo ra một lệnh bằng chữ 9. Nó cũng có một thuộc tính kỳ lạ (không bình thường trong ngôn ngữ lắp ráp) mà các tệp bắt đầu chạy từ đầu, vì vậy chúng tôi không cần bất kỳ khai báo nào để tạo chương trình công việc.

Bạn có thể kiểm tra chương trình bằng trình giả lập này , mặc dù bạn sẽ phải chiến đấu với nó để nhập chương trình.

Đây là cách mọi thứ kết thúc khi bạn tìm ra cách sử dụng hệ thống tập tin, trình soạn thảo, thiết bị đầu cuối và những thứ tương tự mà bạn nghĩ rằng bạn đã biết cách sử dụng:

% a.out
Illegal instruction -- Core dumped

Tôi đã xác nhận với tài liệu rằng đây là SIGILLtín hiệu chính hãng (và thậm chí nó có cùng số tín hiệu, 4, cho đến lúc đó!)


1
Nó có cùng số tín hiệu vì POSIX và UNIX và SUS có liên quan chặt chẽ với nhau :)
mèo

4
Hầu như tất cả các số tín hiệu trong động cơ V6 vẫn có cùng ý nghĩa ngày nay; các mnemonics thực sự đã không ổn định hơn các con số. So sánh minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h với github.com/freebsd/freebsd/blob/master/sys/sys/signal.h - ngữ nghĩa giống hệt nhau cho 1 đến 13, nhưng chỉ 1, 2 và 13 có cùng tên. (SIGALRM / 14 và SIGTERM / 15 chỉ được thêm vào V7.) (Dòng System V có một vài thay đổi, đáng chú ý là chuyển SIGBUS từ 10 sang 7 (thay thế SIGEMT vô dụng) và SIGSYS trên 15, để nhường chỗ cho SIGUSR1 và SIGUSR2.)
zwol

4
@cat POSIX và SUS không thực sự chỉ định các giá trị của tín hiệu - chúng thực sự chỉ định ý nghĩa của một số số khi được chuyển làm đối số cho lệnh kill, nhưng SIGILL không được bao gồm.
Random832

7
a.outThật vậy, có nhiều byte trong đó ( 9lệnh biên dịch thành hai byte và trình biên dịch cũng thêm một tiêu đề và chân trang để làm cho chương trình có thể thực hiện được). Đó là lý do tại sao tôi viết chương trình bằng ngôn ngữ lắp ráp, không phải bằng mã máy. Chương trình hợp ngữ chỉ có một byte trong và biên dịch thành chương trình có nhiều byte hơn; đây là một vấn đề về mã golf (tối thiểu hóa kích thước của nguồn), không phải là vấn đề mã hóa (giảm thiểu kích thước của tệp thực thi), do đó, kích thước 1 byte của nguồn là vấn đề.

2
Lạm dụng rất thông minh của một hệ thống cũ nhưng tuyệt vời.
Mast

81

C (x86_64, tcc ), 7 byte

main=6;

Lấy cảm hứng từ câu trả lời này .

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

Việc lắp ráp được tạo ra trông như thế này.

    .globl  main
main:
    .long 6

Lưu ý rằng TCC không đặt "hàm" đã xác định trong phân đoạn dữ liệu .

Sau khi biên dịch, _start sẽ trỏ đến main như bình thường. Khi chương trình kết quả được thực thi, nó hy vọng mã trong chính và tìm thấy ít về cuối nhỏ (!) 32-bit nguyên 6 , được mã hóa như 0x06 0x00 0x00 0x00 . Byte đầu tiên - 0x06 - là một opcode không hợp lệ, vì vậy chương trình kết thúc bằng SIGILL .


C (x86_64, gcc ), 13 byte

const main=6;

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

Không có công cụ sửa đổi const , lắp ráp được tạo ra trông như thế này.

    .globl  main
    .data
main:
    .long   6
    .section    .note.GNU-stack,"",@progbits

Trình liên kết của GCC coi dòng cuối cùng là một gợi ý rằng đối tượng được tạo không yêu cầu ngăn xếp thực thi. Vì chính được đặt rõ ràng trong một phần dữ liệu , opcode mà nó chứa không thể thực thi được, do đó chương trình chấm dứt sẽ SIGSEGV (lỗi phân đoạn).

Loại bỏ dòng thứ hai hoặc dòng cuối cùng sẽ làm cho công việc thực thi được tạo như dự định. Dòng cuối cùng có thể được bỏ qua với cờ trình biên dịch -zexecstack( Dùng thử trực tuyến! ), Nhưng chi phí này là 12 byte .

Một thay thế ngắn hơn là khai báo chính với bộ sửa đổi const , dẫn đến lắp ráp sau.

        .globl  main
        .section    .rodata
main:
        .long   6
        .section    .note.GNU-stack,"",@progbits

Điều này hoạt động mà không có bất kỳ cờ biên dịch. Lưu ý rằng main=6;sẽ ghi "hàm" được xác định trong dữ liệu , nhưng công cụ sửa đổi const làm cho GCC viết nó bằng Rodata , điều này (ít nhất là trên nền tảng của tôi) được phép chứa mã.


Tuy nhiên, yêu thích việc tránh hoàn toàn việc sử dụng một chức năng :) Làm thế nào để nó hoạt động theo thuật ngữ C? Trình biên dịch có thấy đó mainlà số 6 không và cố gắng gọi nó (mà tôi đoán sẽ khiến nó bỏ cuộc và thử hướng dẫn)?
Mia yun Ruse

11
@JackDobson đó là hành vi không xác định, vì vậy nó không hoạt động theo C; bạn đang thương xót nhà soạn nhạc. Clang thậm chí còn có một cảnh báo cho điều này vì một số lý do: "biến có tên 'chính' với liên kết bên ngoài có hành vi không xác định".
Bobby Sacamano

2
GCC sẽ phàn nàn về việc mainkhông phải là một chức năng mà chỉ khi bạn bật cảnh báo ( -Wallhoặc -pedanticsẽ làm điều đó).
zwol

Tôi nghĩ rằng nó khá chuẩn cho các tệp thực thi cho các hệ thống giống Unix có các phân đoạn văn bản / dữ liệu / bss . Trình liên kết đặt .rodata phần bên trong phân đoạn văn bản của tệp thực thi và tôi hy vọng đây sẽ là trường hợp trên hầu hết mọi nền tảng. (Trình tải chương trình của kernel chỉ quan tâm đến các phân đoạn chứ không phải các phần).
Peter Cordes

3
Cũng lưu ý rằng đó 06chỉ là một hướng dẫn không hợp lệ trong x86-64. Trong chế độ 32 bit PUSH ES, vì vậy, câu trả lời này chỉ hoạt động với các trình biên dịch mặc định -m64. Xem ref.x86asm.net/coder.html#x06 . Chuỗi byte duy nhất được đảm bảo để giải mã thành một lệnh bất hợp pháp trên tất cả các CPU x86 trong tương lai là UD2 2 byte : 0F 0B. Bất cứ điều gì khác có thể là một số tiền tố hoặc mã hóa hướng dẫn trong tương lai. Tuy nhiên, nâng cấp cho một cách tuyệt vời để có được trình biên dịch C để dán mainnhãn trên một số byte!
Peter Cordes

39

Swift, 5 byte

[][0]

Chỉ số truy cập 0 của một mảng trống. Cuộc gọi này fatalError(), in thông báo lỗi và gặp sự cố với SIGILL. Bạn có thể thử nó ở đây .


Đây là một trong những thứ khó hơn;)
Mega Man

26
... Tại sao nó lại sụp đổ với SIGILL? Ai nghĩ rằng đó là một tín hiệu thích hợp?
Hipster

4
@Asu Không; fatalError()cố ý gặp sự cố do chạy ud2. Tại sao họ chọn làm điều mà tôi không biết, nhưng có lẽ họ nghĩ thông báo lỗi "Hướng dẫn bất hợp pháp" có ý nghĩa vì chương trình đã làm điều gì đó bất hợp pháp.
NobodyNada

2
Xuất sắc. Tôi cá rằng đây cũng là mã Swift ngắn nhất để gây ra sự cố.
JAL

3
@JAL Vâng; Tôi không thể nghĩ bất cứ điều gì ngắn hơn. Tôi đã thử nil!, nhưng trình biên dịch không thể suy ra loại kết quả. (Ngoài ra, hi JAL!)
NobodyNada

23

GNU C, 25 byte

main(){__builtin_trap();}

GNU C (một phương ngữ cụ thể của C có phần mở rộng) chứa một lệnh cố tình làm hỏng chương trình. Việc triển khai chính xác thay đổi từ phiên bản này sang phiên bản khác, nhưng thường thì các nhà phát triển thực hiện một nỗ lực để thực hiện sự cố với giá rẻ nhất có thể, thường liên quan đến việc sử dụng một lệnh bất hợp pháp.

Phiên bản cụ thể tôi đã sử dụng để kiểm tra là gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0; tuy nhiên, chương trình này gây ra SIGILL trên một phạm vi khá rộng, và do đó khá dễ mang theo. Ngoài ra, nó thực hiện nó thông qua việc thực hiện một lệnh bất hợp pháp. Đây là mã lắp ráp mà phần trên biên dịch thành các cài đặt tối ưu hóa mặc định:

main:
    pushq %rbp
    movq %rsp, %rbp
    ud2

ud2 là một hướng dẫn mà Intel đảm bảo sẽ luôn không xác định.


11
6:main(){asm("ud2");}
wchargein

Ngoài ra, tôi không biết làm thế nào chúng tôi đếm byte để lắp ráp thô, nhưng 00 00 0f 0blà ngôn ngữ máy tính cho ud2...
wchargin

5
@wchargein: đó là câu trả lời x86 + GNU C. Cái này có thể mang theo cho tất cả các hệ thống GNU. Cũng lưu ý rằng UD2 chỉ có 2 byte . IDK nơi bạn có các 00byte đó; chúng không phải là một phần của mã máy cho UD2. BTW, như tôi đã nhận xét về câu trả lời của Dennis , hiện tại có các hướng dẫn bất hợp pháp một byte trong x86-64, nhưng chúng không được đảm bảo để duy trì như vậy.
Peter Cordes

@wchargein: Chúng tôi đếm byte cho các chương trình / chức năng mã máy như bạn mong đợi. Xem một số câu trả lời của tôi, như Adler32 trong 32 byte mã máy x86-64 hoặc GCD trong 8 byte mã máy x86-32 .
Peter Cordes

1
@Ruslan: Họ không; 00 00giải mã tương tự trong x86-64 (as add [rax], al). 00 00 0f 0bthường sẽ SIGSEGV trước SIGILL, trừ khi bạn tình cờ có một con trỏ có thể ghi trong rax.
Peter Cordes

22

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 SIGILLcá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.)

06là 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, 2Fcũ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 2Ftừ 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 06từ 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 06từ 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 ldnhư 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.)


Trên x86-64 / linux với gcc6 ở chế độ mặc định (lenient), const main=6;hoạt động, cũng như một số biến thể. Mối liên kết này (mà tôi nghi ngờ cũng là mối liên kết của bạn) khả năng tạo ra một bước nhảy từ .textđể .rodata; vấn đề bạn gặp phải là, nếu không const, bạn sẽ nhảy vào phân đoạn dữ liệu có thể ghi ( .data), không thể thực thi được trên phần cứng hiện đại. Nó sẽ hoạt động trên x86 cũ hơn, trong đó phần cứng bảo vệ bộ nhớ không thể đánh dấu các trang là có thể đọc được nhưng không thể thực thi được.
zwol

Lưu ý rằng ngay cả trong C89, mainbắt buộc phải là một hàm (§5.1.2.2.1) - Tôi không biết tại sao gcc coi việc khai báo mainlà một đối tượng dữ liệu chỉ đáng được cảnh báo và chỉ với -pedanticdòng lệnh. Một số người trở lại vào đầu những năm 1990 có lẽ đã nghĩ rằng không ai sẽ làm điều đó một cách tình cờ, nhưng nó không giống như đó là một điều hữu ích để làm mục đích ngoại trừ loại trò chơi này.
zwol

1
... Đọc lại một lần nữa, có vẻ như bạn dự kiến ​​sẽ main[]="/"nhảy sang phân đoạn dữ liệu chỉ đọc, bởi vì các chuỗi ký tự chuỗi đi trong Rodata. Bạn đã bị bắt gặp bởi sự khác biệt giữa char *foo = "..."char foo[] = "...". char *foo = "..."là đường cú pháp cho const char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, vì vậy, chuỗi ký tự thực hiện trong Rodata và foolà một biến toàn cục riêng biệt , có thể ghi được chỉ ra nó. Với char foo[] = "..."Tuy nhiên,, toàn bộ mảng đi trong phân đoạn dữ liệu ghi.
zwol

19

GNU dưới dạng (x86_64), 3 byte

ud2

$ xxd sigill.S

00000000: 7564 32                                  ud2

$ như --64 sigill.S -o sigill.o; ld -S sigill.o -o sigill

sigill.S: Assembler messages:
sigill.S: Warning: end of file not at end of a line; newline inserted
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078

$ ./sigill

Illegal instruction

$ objdump -d sigill

sigill:     file format elf64-x86-64

Disassembly of section .text:

0000000000400078 <__bss_start-0x200002>:>
  400078:       0f 0b                   ud2

Phải có một cách để diễn đạt điều đó trong một "nguồn" hai byte ...
OrangeDog

Ôi, thông minh. Tôi đã tự hỏi nếu có một cách để xây dựng cái này sẽ đặt điểm vào lúc bắt đầu tập tin (không có khai báo) và sẽ không bị phạt vì cấu hình hệ thống xây dựng bất thường. Tôi không thể tìm thấy một, nhưng có vẻ như bạn đã làm.

@ ais523: yeah, tập lệnh xây dựng NASM / YASM ( asm-link) thông thường của tôi cho các chương trình đồ chơi một tệp sẽ xây dựng một tệp thực thi từ nguồn này theo cách tương tự, vì ldmặc định điểm nhập vào đầu đoạn văn bản hoặc đại loại như thế. Tôi chỉ không nghĩ đến việc sử dụng kích thước nguồn asm trên cái này: P
Peter Cordes

18

Bash trên Raspbian trên QEMU, 4 (1?) Byte

Không phải công việc của tôi. Tôi chỉ báo cáo công việc của người khác. Tôi thậm chí không ở vị trí để kiểm tra yêu cầu bồi thường. Vì một phần quan trọng của thử thách này dường như là tìm ra một môi trường nơi tín hiệu này sẽ được phát ra và bắt được, tôi không bao gồm kích thước của QEMU, Raspbian hoặc bash.

Vào ngày 27 tháng 2 năm 2013 8:49 tối, người dùng emlhalac đã báo cáo " Nhận" hướng dẫn bất hợp pháp "khi cố gắng chroot " trên Raspberry Pi fora.

ping

sản xuất

qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal instruction (core dumped)

Tôi tưởng tượng các lệnh ngắn hơn nhiều sẽ tạo ra đầu ra này, ví dụ , tr.

EDIT: Dựa trên nhận xét của @ fluffy , đã giảm giới hạn dưới được phỏng đoán về độ dài đầu vào xuống "1?".


5
Tôi nghĩ rằng [lệnh sẽ thắng. :)
fluffy

17

Tệp COM x86 MS-DOS, 2 byte

EDIT: Như đã chỉ ra trong các bình luận, bản thân DOS sẽ không bẫy ngoại lệ CPU và sẽ đơn giản treo (không chỉ ứng dụng, toàn bộ HĐH). Chạy trên HĐH dựa trên NT 32 bit như Windows XP, thực sự, sẽ kích hoạt tín hiệu hướng dẫn bất hợp pháp.

0F 0B

Từ tài liệu :

Tạo một opcode không hợp lệ. Hướng dẫn này được cung cấp để kiểm tra phần mềm để tạo một opcode không hợp lệ.

Đó là khá tự giải thích. Lưu dưới dạng tệp .com và chạy trong mọi trình giả lập DOS Trình giả lập DOS sẽ bị sập. Chạy trên Windows XP, Vista hoặc 7 32 bit.

SIGILL trên Windows XP


1
Về mặt kỹ thuật, nó làm cho bộ xử lý tạo ra một ngoại lệ lệnh bất hợp pháp. Tuy nhiên, DOS có khả năng bảo vệ bộ nhớ và xử lý ngoại lệ rất hạn chế và tôi sẽ không ngạc nhiên nếu nó chỉ dẫn đến sự cố không xác định về hành vi / HĐH. OP không nói rằng kernel phải bắt lỗi và in "Hướng dẫn bất hợp pháp" lên bàn điều khiển.
masantant

4
Tôi đã nghĩ đến giải pháp này, nhưng tôi không tin nó hợp lệ. Câu hỏi yêu cầu tín hiệu chỉ dẫn bất hợp pháp , không chỉ là bẫy xử lý lệnh bất hợp pháp , vì vậy mục đích là tìm một hệ điều hành thực sự tạo ra tín hiệu để đáp ứng với #UDbẫy. (Ngoài ra, tôi đã quyết định thực sự thử nghiệm nó và nó dường như ném trình giả lập DOS của tôi vào một vòng lặp vô hạn.)

2
Tôi đã thử nghiệm điều này trên MS-DOS thực tế trên AMD K6-II. Chạy nó chỉ treo hệ thống, cả có và không có EMM386 chạy. (EMM386 bẫy một số lỗi và tạm dừng hệ thống bằng một thông báo, do đó, đáng để thử nghiệm để xem liệu nó có tạo ra sự khác biệt hay không.)
Đánh dấu

2
Có, các cửa sổ dựa trên DOS sẽ có thể thực sự bắt được bẫy và ít nhất là làm sập ứng dụng.
Asu

2
@Asu Tôi có thể xác nhận rằng tính năng này hoạt động trên XP 32 bit và có thể sẽ hoạt động trên tất cả các hệ thống Windows 32 bit khác. Tôi đồng ý rằng đây không phải là một giải pháp trên chính DOS, vì nó chỉ gặp sự cố.
maservant

13

C (Windows 32 bit), 34 byte

f(i){(&i)[-1]-=9;}main(){f(2831);}

Điều này chỉ hoạt động nếu biên dịch mà không tối ưu hóa (khác, mã bất hợp pháp trong fhàm là "tối ưu hóa").

Việc tháo gỡ các mainchức năng trông như thế này:

68 0f 0b 00 00    push 0b0f
e8 a1 d3 ff ff    call _f
...

Chúng ta có thể thấy rằng nó sử dụng một pushlệnh có giá trị bằng chữ 0b0f(little endian, do đó byte của nó được hoán đổi). Lệnh callđẩy một địa chỉ trả về (của ...lệnh), được đặt trên ngăn xếp gần tham số của hàm. Bằng cách sử dụng một [-1]sự dịch chuyển, hàm sẽ ghi đè địa chỉ trả về để nó trỏ 9 byte trước đó, trong đó các byte 0f 0blà.

Các byte này gây ra ngoại lệ "lệnh không xác định", như được thiết kế.


12

Java, 50 43 24 byte

a->a.exec("kill -4 $$");

Đây là java.util.function.Consumer<Runtime>1 có lệnh bị đánh cắp từ câu trả lời của fluffy . Nó hoạt động bởi vì bạn phải gọi nó là whateverNameYouGiveIt.accept(Runtime.getRuntime())!

Lưu ý rằng điều này sẽ tạo ra một quy trình mới và làm cho nó ném SIGILL thay vì ném SIGILL.

1 - Về mặt kỹ thuật, nó cũng có thể là java.util.function.Function<Runtime, Process>Runtime#exec(String)trả về một java.lang.Processcái có thể được sử dụng để kiểm soát quá trình bạn vừa tạo bằng cách thực hiện lệnh shell.


Để thực hiện điều gì đó ấn tượng hơn bằng ngôn ngữ dài dòng như vậy, đây là phần thưởng 72 60 48 byte:

a->for(int b=0;;b++)a.exec("sudo kill -s 4 "+b);

Đây là một Consumer<Runtime>quá trình khác trải qua TẤT CẢ các quy trình (bao gồm cả chính nó), làm cho mỗi trong số chúng ném SIGILL. Cú đúp tốt hơn cho một vụ tai nạn bạo lực.


Và một phần thưởng khác (a Consumer<ANYTHING_GOES>), ít nhất là giả vờ ném SIGILL trong 20 byte:

a->System.exit(132);

8

Perl, 9 byte

kill+4,$$

Chỉ cần gọi hàm thư viện thích hợp để báo hiệu một quá trình và để chương trình tự báo hiệu SIGILL. Không có hướng dẫn bất hợp pháp thực tế có liên quan ở đây, nhưng nó tạo ra kết quả thích hợp. (Tôi nghĩ rằng điều này làm cho thử thách khá rẻ, nhưng nếu bất cứ điều gì được cho phép, thì đây là kẽ hở mà bạn sử dụng.


Đến đây để đăng cùng, với một không gian thay vì +. :)
simbabque

2
Khi mọi người học Perl để lập trình không chơi gôn, họ học nó với a +. Sau khi chơi golf một lúc, họ +thỉnh thoảng thể hiện. Cuối cùng, họ đã viết đủ các chương trình mà họ cần để tránh khoảng trắng vì lý do nào đó hoặc lý do khác +trở thành thói quen. (Nó cũng phân tích cú pháp ít mơ hồ hơn, bởi vì nó hoạt động xung quanh việc kích hoạt trường hợp đặc biệt trong trình phân tích cú pháp cho dấu ngoặc đơn.)

8

Ngôn ngữ trình biên dịch hợp nhất ARM (UAL), 3 byte

nop

Ví dụ:

$ as ill.s -o ill.o
$ ld ill.o -o ill
ld: warning: cannot find entry symbol _start; defaulting to 00010054
$ ./ill 
Illegal instruction

Sau khi thực hiện nop, bộ xử lý diễn giải .ARM.attributesphần này dưới dạng mã và gặp một lệnh bất hợp pháp ở đâu đó:

$ objdump -D ill

ill:     file format elf32-littlearm


Disassembly of section .text:

00010054 <__bss_end__-0x10004>:
   10054:       e1a00000        nop                     ; (mov r0, r0)

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:   00001341        andeq   r1, r0, r1, asr #6
   4:   61656100        cmnvs   r5, r0, lsl #2
   8:   01006962        tsteq   r0, r2, ror #18
   c:   00000009        andeq   r0, r0, r9
  10:   01080106        tsteq   r8, r6, lsl #2

Đã thử nghiệm trên Raspberry Pi 3.


Bằng cách nào đó, điều này không hoạt động trên Pi 2.
Mega Man

7

Microsoft C (Visual Studio 2005 trở đi), 16 byte

main(){__ud2();}

Tôi không thể dễ dàng kiểm tra điều này, nhưng theo tài liệu, nó sẽ tạo ra một lệnh bất hợp pháp bằng cách cố ý thực hiện một lệnh chỉ kernel từ chương trình chế độ người dùng. (Lưu ý rằng vì hướng dẫn bất hợp pháp làm hỏng chương trình, chúng tôi không phải cố gắng quay lại main, nghĩa là mainchức năng kiểu K & R này là hợp lệ. Visual Studio không bao giờ được chuyển từ C89 thường là một điều xấu, nhưng nó đã xuất hiện hữu ích ở đây.)


Bạn có thể biên dịch cho linux với VS2015 không? Bởi vì tôi không nghĩ SIGILL được định nghĩa trong Windows, phải không?
Andrew Savinykh

7

Ruby, 13 byte

`kill -4 #$$`

Tôi đoán thật an toàn khi cho rằng chúng tôi đang chạy cái này từ vỏ * nix. Các chữ viết tắt backtick chạy lệnh shell đã cho. $$là quá trình Ruby đang chạy và #là để nội suy chuỗi.


Không cần gọi vỏ trực tiếp:

Ruby, 17 byte

Process.kill 4,$$

6

Bất kỳ shell (sh, bash, csh, v.v.), bất kỳ POSIX (10 byte)

Câu trả lời tầm thường nhưng tôi chưa thấy ai đăng nó.

kill -4 $$

Chỉ cần gửi SIGILL đến quy trình hiện tại. Ví dụ đầu ra trên OSX:

bash-3.2$ kill -4 $$
Illegal instruction: 4

Bạn có thể làm kill -4 1nếu câu hỏi là không cụ thể về chương trình ném SIGILL
Đánh K Cowan

@MarkKCowan Heh, điểm tốt, mặc dù điều đó giả định là root ...
fluffy

2
You will have root in your programs- gõ một byte khỏi câu trả lời của bạn và troll câu hỏi một chút cùng một lúc: D. THƯỞNG: Bạn có thể giếtinit
Mark K Cowan

2
@MarkKCowan: Trên (phiên bản hiện đại của?) Linux, initthực sự miễn dịch với các tín hiệu mà nó không được yêu cầu cụ thể để nhận, ngay cả với root. Bạn có lẽ có thể giải quyết vấn đề này bằng cách sử dụng HĐH POSIX khác.

2
kill -4 2sau đó: D
Mark K Cowan

6

Mã máy ELF + x86, 45 byte

Đây phải là chương trình thực thi nhỏ nhất trên máy Unix ném SIGILL (do Linux không nhận ra tệp thực thi nếu được thực hiện nhỏ hơn).

Biên dịch với nasm -f bin -o a.out tiny_sigill.asm, thử nghiệm trên máy ảo x64.

Thực tế nhị phân 45 byte:

0000000 457f 464c 0001 0000 0000 0000 0000 0001

0000020 0002 0003 0020 0001 0020 0001 0004 0000

0000040 0b0f c031 cd40 0080 0034 0020 0001

Danh sách hội (xem nguồn dưới đây):

;tiny_sigill.asm      
BITS 32


            org     0x00010000

            db      0x7F, "ELF"             ; e_ident
            dd      1                                       ; p_type
            dd      0                                       ; p_offset
            dd      $$                                      ; p_vaddr 
            dw      2                       ; e_type        ; p_paddr
            dw      3                       ; e_machine
            dd      _start                  ; e_version     ; p_filesz
            dd      _start                  ; e_entry       ; p_memsz
            dd      4                       ; e_phoff       ; p_flags


_start:
                ud2                             ; e_shoff       ; p_align
                xor     eax, eax
                inc     eax                     ; e_flags
                int     0x80
                db      0
                dw      0x34                    ; e_ehsize
                dw      0x20                    ; e_phentsize
                db      1                       ; e_phnum
                                                ; e_shentsize
                                                ; e_shnum
                                                ; e_shstrndx

  filesize      equ     $ - $$

Tuyên bố miễn trừ trách nhiệm: mã từ hướng dẫn sau đây về cách viết chương trình lắp ráp nhỏ nhất để trả về một số, nhưng sử dụng opcode ud2 thay vì Mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html


2
Tôi sẽ đăng một thực thi sửa đổi của hướng dẫn chính xác đó, nhưng bạn đã đánh bại tôi với nó. Điều này xứng đáng để giành chiến thắng; Đó là một sự tối giản thực sự theo nghĩa tài nguyên hệ thống (Nó yêu cầu không quá 45 byte cả trong tệp và trong bộ nhớ, và hoàn toàn giống nhau trong cả hai) và không có trình thông dịch cồng kềnh như các giải pháp trình biên dịch khác. Nó chỉ đơn giản là những gì nó là.
Idillotexist Idillotexist

5

Tự động , 93 byte

Sử dụng lắp ráp nội tuyến Flatassembler:

#include<AssembleIt.au3>
Func W()
_("use32")
_("ud2")
_("ret")
EndFunc
_AssembleIt("int","W")

Khi chạy ở chế độ tương tác SciTE, nó sẽ bị sập ngay lập tức. Trình gỡ lỗi Windows sẽ bật lên trong một phần của giây. Đầu ra giao diện điều khiển sẽ giống như thế này:

--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
0x0F0BC3
!>14:27:09 AutoIt3.exe ended.rc:-1073741795

Trong trường hợp -1073741795là mã lỗi không xác định ném ra bởi WinAPI. Đây có thể là bất kỳ số âm.

Tương tự bằng cách sử dụng trình biên dịch LASM của riêng tôi :

#include<LASM.au3>
$_=LASM_ASMToMemory("ud2"&@CRLF&"ret 16")
LASM_CallMemory($_,0,0,0,0)

5

NASM, 25 byte

Tôi không biết cách thức hoạt động của nó, chỉ là nó hoạt động trên máy tính của tôi (Linux x86_64).

global start
start:
jmp 0

Biên dịch và chạy như sau:

$ nasm -f elf64 ill.asm && ld ill.o && ./a.out
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
Illegal instruction

Bạn có thể rút ngắn nó xuống còn bốn byte, nhưja 0
Mark K Cowan

1
hoặc ba nhưud2
Mark K Cowan

1
Có lẽ bởi vì nó đang cố gắng nhảy vào một số dữ liệu?
Asu

5

TI-83 Hex hội, 2 byte

PROGRAM:I
:AsmPrgmED77

Chạy như Asm(prgmI). Thực thi opcode 0xed77 bất hợp pháp. Tôi đếm từng cặp chữ số hex là một byte.



3

x86 .COM, 1 byte

c

ARPLnguyên nhân #UDở chế độ 16 bit


1

Vỏ Linux, 9 byte

kill -4 0

Gửi SIGILLđến quy trình với PID 0. Tôi không biết quy trình nào có PID 0, nhưng nó luôn tồn tại.

Hãy thử trực tuyến!


Từ man kill:0 All processes in the current process group are signaled.
Dennis

1

GNU C, 24 19 18 byte

-4 nhờ Dennis
-1 nhờ trần

main(){goto*&"'";}

Hãy thử trực tuyến! Điều này giả định ASCII và x86_64. Nó cố chạy mã máy 27, mà ... là bất hợp pháp.


shortC , 10 5 4 byte

AV"'

Tương đương với mã GNU C ở trên. Hãy thử trực tuyến!


L"\6"cũng là bất hợp pháp, giả sử x86_64.
Dennis

@Dennis Hướng dẫn nào là 0x06? Ngoài ra, Lkhông cần thiết.
MD XF

Nó không được chỉ định.
Dennis

Nó không được chỉ định; đó là những gì làm cho nó bất hợp pháp. Ngoài ra, '39 = 0x27 , không phải 0x39 .
Dennis

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.