Najkrótszy kod do rzucenia SIGILL


76

tło

Mamy już wyzwanie rzucenia SIGSEGV , więc dlaczego nie wyzwanie rzucenia SIGILL?

Co to jest SIGILL?

SIGILL to sygnał nielegalnej instrukcji procesora, co zdarza się bardzo rzadko. Domyślną akcją po otrzymaniu SIGILL jest zakończenie programu i zapisanie zrzutu podstawowego. Identyfikator sygnału SIGILL to 4. SIGILL występuje bardzo rzadko i nie mam absolutnie żadnego pojęcia, jak go wygenerować w kodzie, z wyjątkiem via sudo kill -s 4 <pid>.

Zasady

Będziesz mieć root w swoich programach, ale jeśli nie chcesz z żadnych powodów, możesz również użyć zwykłego użytkownika. Jestem na komputerze z systemem Linux z niemieckimi ustawieniami regionalnymi i nie znam angielskiego tekstu wyświetlanego po złapaniu SIGILL, ale myślę, że to coś w rodzaju „Nielegalnej instrukcji”. Najkrótszy program, który rzuca SIGILL wygrywa.


6
Możesz wyjaśnić, czy instrukcja musi zostać wygenerowana przez jądro, czy nie. W szczególności, czy chcesz pozwolić programowi na generowanie go bezpośrednio za pomocą wywołania libc raise(SIGILL)?

1
To naprawdę mówi Illegal instruction (core dumped).
Erik the Outgolfer,

@ ais523 Wszystko jest dozwolone.
Mega Man,

5
Dla każdego sprzętu, który może podnieść SIGILL, odpowiedź będzie taka sama jak długość instrukcji. Po prostu umieść gdzieś nielegalną instrukcję i spróbuj ją wykonać. Jedyną interesującą rzeczą będzie zaangażowany zawiły łańcuch narzędzi.
OrangeDog,

3
* osoby wysyłające stare programy, które miały, ale nie działały *
RudolfJelin,

Odpowiedzi:


112

PDP-11 Asembler (UNIX Sixth Edition), 1 bajt

9

Instrukcja 9 nie jest prawidłową instrukcją na PDP-11 (byłoby to ósemkowe 000011, które nie pojawia się na liście instrukcji (PDF)). Asembler PDP-11, który jest dostarczany z UNIX Sixth Edition, najwyraźniej odzwierciedla wszystko, czego nie rozumie bezpośrednio w pliku; w tym przypadku 9 jest liczbą, więc generuje literalną instrukcję 9. Ma także właściwość nieparzystą (obecnie w językach asemblera), że pliki zaczynają działać od początku, więc nie potrzebujemy żadnych deklaracji, aby stworzyć program praca.

Możesz przetestować program za pomocą tego emulatora , chociaż będziesz musiał nieco z nim walczyć, aby wprowadzić program.

Oto jak to się skończy, gdy nauczysz się korzystać z systemu plików, edytora, terminala i podobnych rzeczy, o których myślałeś, że wiesz, jak z nich korzystać:

% a.out
Illegal instruction -- Core dumped

Potwierdziłem za pomocą dokumentacji, że jest to prawdziwy SIGILLsygnał (a nawet wtedy miał ten sam numer sygnału, 4!)


1
Miał ten sam numer sygnału, ponieważ POSIX, UNIX i SUS są ściśle powiązane :)
cat

4
Prawie wszystkie liczby sygnałów w V6 mają dziś takie samo znaczenie; mnemoniki były mniej stabilne niż liczby. Porównaj minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h z github.com/freebsd/freebsd/blob/master/sys/sys/signal.h - identyczna semantyka dla 1 do 13, ale tylko 1, 2 i 13 mają dokładnie takie same nazwy. (SIGALRM / 14 i SIGTERM / 15 zostały dodane tylko w wersji 7.) (Linia Systemu V ma kilka zmian, w szczególności przesunięcie SIGBUS z 10 na 7 (zastępując bezużyteczny SIGEMT) i SIGSYS powyżej 15, aby zrobić miejsce dla SIGUSR1 i SIGUSR2.)
zwolnij

4
@cat POSIX i SUS tak naprawdę nie określają wartości sygnałów - określają znaczenie niektórych liczb, gdy są przekazywane jako argumenty do polecenia kill, ale SIGILL nie jest uwzględniony.
Random832,

7
a.outzawiera wiele bajtów ( 9instrukcja kompiluje się do dwóch bajtów, a asembler dodaje również nagłówek i stopkę, aby program był wykonywalny). Dlatego napisałem program w języku asemblera, a nie w kodzie maszynowym. Program języka asemblera ma tylko jeden bajt wejściowy i kompiluje się do programu z większą liczbą bajtów; jest to problem związany z kodowaniem golfa (minimalizacja rozmiaru źródła), a nie problem z rozmiarem kodu (minimalizacja rozmiaru pliku wykonywalnego), więc liczy się wielkość 1-bajtowego źródła.

2
Bardzo sprytne nadużycie starego, ale niesamowitego systemu.
Maszt

81

C (x86_64, tcc ), 7 bajtów

main=6;

Zainspirowany tą odpowiedzią .

Wypróbuj online!

Jak to działa

Wygenerowany zespół wygląda następująco.

    .globl  main
main:
    .long 6

Zauważ, że TCC nie umieszcza zdefiniowanej „funkcji” w segmencie danych .

Po kompilacji, _start jak zwykle wskaże na main . Kiedy program wynikowy jest wykonywany, oczekuje kodu w main i znajduje 32-bitową liczbę całkowitą little-endian (!) 6 , która jest zakodowana jako 0x06 0x00 0x00 0x00 . Pierwszy bajt - 0x06 - jest niepoprawnym kodem operacji, więc program kończy się na SIGILL .


C (x86_64, gcc ), 13 bajtów

const main=6;

Wypróbuj online!

Jak to działa

Bez modyfikatora const wygenerowany zestaw wygląda tak.

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

Linker GCC traktuje ostatni wiersz jako wskazówkę, że wygenerowany obiekt nie wymaga stosu wykonywalnego. Ponieważ main jest wyraźnie umieszczony w sekcji danych , kod operacji, który zawiera, nie jest wykonywalny, więc program kończy SIGSEGV (błąd segmentacji).

Usunięcie drugiego lub ostatniego wiersza spowoduje, że wygenerowany plik wykonywalny będzie działał zgodnie z przeznaczeniem. Ostatni wiersz można zignorować przy użyciu flagi kompilatora -zexecstack( Wypróbuj online! ), Ale kosztuje to 12 bajtów .

Krótszą alternatywą jest zadeklarowanie głównego za pomocą modyfikatora const , co daje następujący zestaw.

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

Działa to bez żadnych flag kompilatora. Zauważ, że zapisałbymain=6; zdefiniowaną „funkcję” w danych , ale modyfikator const powoduje, że GCC zapisuje ją w rodata , która (przynajmniej na mojej platformie) może zawierać kod.


Uwielbiam całkowite unikanie nawet korzystania z funkcji :) Jak to działa w kategoriach C? Czy kompilator widzi, że mainjest to 6 i próbuje ją nazwać (co, jak sądzę, sprawiłoby, że zrezygnowałby i wypróbowałby instrukcję)?
Mia yun Ruse,

11
@JackDobson to niezdefiniowane zachowanie, więc nie działa w kategoriach C; jesteś na łasce kompilatora. Clang ma nawet z tego powodu ostrzeżenie: „zmienna o nazwie„ main ”z zewnętrznym powiązaniem ma niezdefiniowane zachowanie”.
Bobby Sacamano,

2
GCC będą narzekać mainnie jest funkcją, ale tylko jeśli włączysz ostrzeżeń (albo -Wallczy -pedanticto zrobi).
zwolnienie

Myślę, że jest dość standardem w plikach wykonywalnych systemów uniksowych, takich jak segmenty tekst / dane / bss . Linker umieszcza .rodata sekcję wewnątrz segmentu tekstowego pliku wykonywalnego i spodziewam się, że tak będzie na prawie każdej platformie. (Program ładujący jądro dba tylko o segmenty, a nie sekcje).
Peter Cordes,

3
Zauważ też, że 06jest to tylko niepoprawna instrukcja w x86-64. Jest to tryb 32-bitowy PUSH ES, więc ta odpowiedź działa tylko z domyślnymi kompilatorami -m64. Zobacz ref.x86asm.net/coder.html#x06 . Jedynym sekwencja bajtów, która jest zagwarantowana rozszyfrować jako nielegalne nauczania na wszystkich przyszłych procesorów x86 jest 2 bajt UD2 : 0F 0B. Wszystko inne może być jakimś przyszłym prefiksem lub kodowaniem instrukcji. Nadal głosowaliśmy za świetnym sposobem, aby kompilator C nakleił mainetykietę na niektórych bajtach!
Peter Cordes,

39

Szybki, 5 bajtów

[][0]

Uzyskaj dostęp do indeksu 0 pustej tablicy. Nazywa to fatalError(), co wypisuje komunikat o błędzie i wywala z SIGILL. Możesz spróbować tutaj .


To jeden z trudniejszych;)
Mega Man

26
... dlaczego, u licha, rozbija się o SIGILL? Kto uważał, że to odpowiedni sygnał?
Cholerni

4
@Asu No; fatalError()celowo ulega awarii podczas uruchamiania ud2. Dlaczego zdecydowali się to zrobić, nie wiem, ale może uznali, że komunikat o błędzie „Niedozwolona instrukcja” ma sens, ponieważ program zrobił coś nielegalnego.
NobodyNada

2
Znakomity. Założę się, że jest to również najkrótszy kod Swift, który powoduje awarię.
JAL

3
@JAL Tak; Nie mogę wymyślić nic krótszego. Próbowałem nil!, ale kompilator nie mógł wywnioskować typu wyniku. (Cześć, JAL!)
NobodyNada

23

GNU C, 25 bajtów

main(){__builtin_trap();}

GNU C (specyficzny dialekt języka C z rozszerzeniami) zawiera instrukcję celowej awarii programu. Dokładna implementacja różni się w zależności od wersji, ale często programiści próbują wdrożyć awarię tak tanio, jak to możliwe, co zwykle wiąże się z użyciem nielegalnej instrukcji.

Konkretna wersja, której użyłem do testowania, to gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0; jednak program ten powoduje SIGILL na dość szerokiej gamie platform, a zatem jest dość przenośny. Dodatkowo robi to poprzez faktyczne wykonanie nielegalnej instrukcji. Oto kod zestawu, do którego powyższe kompiluje się z domyślnymi ustawieniami optymalizacji:

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

ud2 to instrukcja, którą gwarancje Intel zawsze pozostaną niezdefiniowane.


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

Nie wiem też, jak liczymy bajty dla surowego zestawu, ale 00 00 0f 0bjest to język maszynowy dla ud2
wchargin

5
@wchargin: to odpowiedź x86 + GNU C. Ten jest przenośny dla wszystkich systemów GNU. Zauważ też, że UD2 ma tylko 2 bajty . IDK, gdzie masz te 00bajty; nie są częścią kodu maszynowego dla UD2. BTW, jak skomentowałem odpowiedź Dennisa , na razie istnieją x-bajtowe instrukcje niezgodne z x86-64, ale nie ma gwarancji, że tak pozostanie.
Peter Cordes,

@wchargin: Liczymy bajty dla funkcji / programów kodu maszynowego, jak można się spodziewać. Zobacz niektóre z moich odpowiedzi, np. Adler32 w 32 bajtach kodu maszynowego x86-64 lub GCD w 8 bajtach kodu maszynowego x86-32 .
Peter Cordes

1
@Ruslan: Nie są; 00 00dekoduje to samo w x86-64 (as add [rax], al). 00 00 0f 0bzwykle SIGSEGV przed SIGILL, chyba że zdarzy ci się mieć zapisywalny wskaźnik rax.
Peter Cordes

22

C (x86_64), 11, 30, 34 lub 34 + 15 = 49 bajtów

main[]="/";
c=6;main(){((void(*)())&c)();}
main(){int c=6;((void(*)())&c)();}

Przedstawiłem kilka rozwiązań, które używają funkcji bibliotecznych do rzucania SIGILLna różne sposoby, ale prawdopodobnie to oszustwo, ponieważ funkcja biblioteczna rozwiązuje problem. Oto szereg rozwiązań, które nie wykorzystują funkcji bibliotecznych i przyjmują różne założenia dotyczące tego, gdzie system operacyjny jest skłonny pozwolić na wykonanie kodu niewykonywalnego. (Stałe tutaj są wybrane dla x86_64, ale możesz je zmienić, aby uzyskać działające rozwiązania dla większości innych procesorów, które mają nielegalne instrukcje).

06jest bajtem kodu maszynowego o najniższym numerze, który nie odpowiada zdefiniowanej instrukcji procesora x86_64. Więc wszystko, co musimy zrobić, to go wykonać. (Alternatywnie 2Fjest również niezdefiniowany i odpowiada jednemu drukowanemu znakowi ASCII.) Żadnemu z nich nie gwarantuje się, że zawsze będzie niezdefiniowany, ale na dzień dzisiejszy nie jest zdefiniowany.

Pierwszy program tutaj wykonuje się 2Fz segmentu danych tylko do odczytu. Większość łączniki nie są zdolne do wytwarzania skok roboczy od .textdo .rodata(lub równoważny ich systemów operacyjnych), jak to nie jest coś, co nigdy nie będzie przydatna w prawidłowej segmentacji programu; Nie znalazłem jeszcze systemu operacyjnego, na którym to działa. Trzeba też dopuścić fakt, że wiele kompilatorów chce, aby dany ciąg był szerokim ciągiem, co wymagałoby dodatkowegoL; Zakładam, że każdy system operacyjny, na którym działa, ma dość przestarzały obraz rzeczy, dlatego domyślnie buduje się na standard wcześniejszy niż C94. Możliwe, że nigdzie ten program nie działa, ale jest też możliwe, że gdzieś ten program działa, dlatego wymienię go w tej kolekcji bardziej wątpliwych do mniej wątpliwych potencjalnych odpowiedzi. (Po opublikowaniu tej odpowiedzi Dennis wspomniał również o możliwości main[]={6}na czacie, która jest tej samej długości i która nie ma problemów z szerokością postaci, a nawet zasygnalizowała potencjał main=6; Nie mogę racjonalnie twierdzić, że te odpowiedzi są mój, bo sam o nich nie myślałem.)

Drugi program tutaj wykonuje się 06z segmentu danych do odczytu i zapisu. W większości systemów operacyjnych spowoduje to błąd segmentacji, ponieważ zapisywalne segmenty danych są uważane za wadę projektową, która sprawia, że ​​exploity są prawdopodobne. Jednak nie zawsze tak było, więc prawdopodobnie działa na wystarczająco starej wersji Linuksa, ale nie mogę tego łatwo przetestować.

Trzeci program wykonuje się 06ze stosu. Ponownie powoduje to obecnie błąd segmentacji, ponieważ ze względów bezpieczeństwa stos jest zwykle klasyfikowany jako niepisujący. Dokumentacja konsolidatora, którą widziałem, wyraźnie sugeruje, że wykonywanie ze stosu było legalne (w przeciwieństwie do poprzednich dwóch przypadków, czasami jest to przydatne), więc chociaż nie mogę tego przetestować, jestem pewien, że jest trochę wersja systemu Linux (i prawdopodobnie inne systemy operacyjne), na których to działa.

Wreszcie, jeśli podasz -Wl,-z,execstack(kara 15 bajtów) dla gcc(jeśli używasz GNU ldjako części backendu), to jawnie wyłączy ochronę wykonywalnego stosu, pozwalając na działanie trzeciego programu i podając nieprawidłowy sygnał operacji zgodnie z oczekiwaniami. I zostały przetestowane i zweryfikowane tej wersji 49-bajtowy do pracy. (Dennis wspomina na czacie, że ta opcja najwyraźniej działa main=6, co dałoby wynik 6 + 15. Jestem dość zaskoczony, że to działa, biorąc pod uwagę, że 6 rażąco nie jest na stosie; opcja link najwyraźniej działa więcej niż jego nazwa sugeruje.)


Na x86-64 / linux z gcc6 w domyślnym (łagodnym) trybie const main=6;działa, podobnie jak kilka odmian. Ten linker (który, jak podejrzewam, jest również twoim linkerem) jest w stanie wygenerować skok od .textdo .rodata; Problemem jest to, że bez tego constprzeskakujesz do zapisywalnego segmentu danych ( .data), który nie jest wykonywalny na nowoczesnym sprzęcie. Działałoby to na starszych wersjach x86, w których sprzęt do ochrony pamięci nie mógł oznaczać stron jako możliwych do odczytu, ale nie do wykonania.
zwolnienie

Zauważ, że nawet w C89 mainwymagana jest funkcja (§5.1.2.2.1) - Nie wiem, dlaczego gcc uważa, że ​​deklarowanie mainjako obiektu danych zasługuje tylko na ostrzeżenie i tylko -pedanticw wierszu poleceń. Ktoś na początku lat 90. może myślał, że nikt nie zrobiłby tego przez przypadek, ale to nie jest tak, że jest to przydatne celowo, z wyjątkiem tego rodzaju gier.
zwolnij

1
... Ponownie odczytując, wydaje się, że spodziewałeś main[]="/"się przeskoczyć do segmentu danych tylko do odczytu, ponieważ literały łańcuchowe idą w rodata. Zostałeś złapany przez różnicę między char *foo = "..."i char foo[] = "...". char *foo = "..."jest cukrem syntaktycznym const char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, więc literał łańcuchowy idzie w rodata i foojest osobną , zapisywalną zmienną globalną, która na to wskazuje. Dzięki char foo[] = "..."jednak cała tablica idzie w segmencie danych do zapisu.
zwolnij

19

GNU as (x86_64), 3 bajty

ud2

$ xxd sigill

00000000: 7564 32                                  ud2

$ as --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

Musi istnieć sposób na wyrażenie tego w dwubajtowym „źródle” ...
OrangeDog,

Och, sprytnie. Zastanawiałem się, czy istnieje sposób na zbudowanie tego, który umieściłby punkt wejścia na początku pliku (bez deklaracji) i który nie wiązałby się z karami za nietypową konfigurację systemu kompilacji. Nie mogłem znaleźć, ale wygląda na to, że tak.

@ ais523: tak, mój zwykły build-skrypt NASM / YASM ( asm-link) dla zabawkowych programów z jednym plikiem budowałby plik wykonywalny z tego źródła w ten sam sposób, ponieważ lddomyślnie punkt wejścia jest na początku segmentu tekstowego lub coś w tym rodzaju. Po prostu nie pomyślałem o wyborze źródła asm na ten: P
Peter Cordes

18

Bash na Raspbian na QEMU, 4 (1?) Bajtów

Nie moja praca. Po prostu informuję o pracy innej. Nie jestem nawet w stanie przetestować roszczenia. Ponieważ kluczową częścią tego wyzwania wydaje się być znalezienie środowiska, w którym ten sygnał zostanie podniesiony i złapany, nie uwzględniam wielkości QEMU, Raspbian ani bash.

27 lutego 2013 20:49 użytkownik emlhalac poinformował na forum Raspberry Pi o „ uzyskiwaniu„ nielegalnych instrukcji ”podczas próby chrootowania ” .

ping

produkować

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

Wyobrażam sobie na przykład, że znacznie krótsze polecenia spowodują takie wyjście tr.

EDYCJA: Na podstawie komentarza @ fluffy zmniejszono przypuszczalną dolną granicę długości wejściowej do „1?”.


5
Myślałem, że [polecenie wygra. :)
puszysty

17

Plik COM x86 MS-DOS, 2 bajty

EDYCJA: Jak wskazano w komentarzach, sam DOS nie wyłapie wyjątku procesora i po prostu zawiesi się (nie tylko aplikacja, cały system operacyjny). Uruchamianie w 32-bitowym systemie operacyjnym opartym na NT, takim jak Windows XP, rzeczywiście wyzwoli nielegalny sygnał instrukcji.

0F 0B

Z dokumentacji :

Generuje nieprawidłowy kod operacji. Niniejsza instrukcja dotyczy testowania oprogramowania w celu jawnego wygenerowania nieprawidłowego kodu operacji.

Co jest dość oczywiste. Zapisz jako plik .com i uruchom w dowolnym emulatorze DOS. Emulatory DOS ulegną awarii. Uruchom w systemie Windows XP, Vista lub 7 32-bit.

SIGILL w systemie Windows XP


1
Z technicznego punktu widzenia procesor generuje wyjątek niezgodny z instrukcją. DOS ma jednak bardzo ograniczone możliwości ochrony pamięci i obsługi wyjątków i nie zdziwiłbym się, gdyby po prostu doprowadził do nieokreślonego zachowania / awarii systemu operacyjnego. OP nie powiedział, że jądro musi wychwycić błąd i wydrukować „Nielegalne instrukcje” na konsoli.
maservant

4
Myślałem o tym rozwiązaniu, ale nie sądzę, aby było ważne. Pytanie wymaga nielegalnego sygnału instrukcji , a nie tylko nielegalnej pułapki procesora instrukcji , więc celem było znalezienie systemu operacyjnego, który faktycznie generowałby sygnał w odpowiedzi na #UDpułapkę. (Poza tym zdecydowałem się go przetestować i wyglądało na to, że rzucił mój emulator DOS w nieskończoną pętlę.)

2
Przetestowałem to na rzeczywistym MS-DOS na AMD K6-II. Uruchomienie go po prostu zawiesza system, zarówno z uruchomionym EMM386, jak i bez niego. (EMM386 wychwytuje niektóre błędy i zatrzymuje system z komunikatem, więc warto było sprawdzić, czy to coś zmieniło.)
Mark

2
Tak, okna oparte na systemie DOS powinny być w stanie naprawdę złapać pułapkę i przynajmniej zawiesić aplikację.
Asu

2
@Asu Mogę potwierdzić, że działa to na 32-bitowym systemie XP i prawdopodobnie będzie działać na wszystkich innych 32-bitowych systemach Windows. Zgadzam się, że nie jest to rozwiązanie w samym systemie DOS, ponieważ po prostu ulega awarii.
maservant

13

C (32-bitowy system Windows), 34 bajty

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

Działa to tylko wtedy, gdy kompiluje się bez optymalizacji (w przeciwnym razie niedozwolony kod w ffunkcji jest „zoptymalizowany”).

Demontaż mainfunkcji wygląda następująco:

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

Widzimy, że używa pushinstrukcji o wartości dosłownej 0b0f(little-endian, więc jej bajty są zamieniane). callInstrukcja popycha adres zwrotny (z ...instrukcją), który znajduje się na stosie w pobliżu parametr funkcji. Korzystając z [-1]przesunięcia, funkcja zastępuje adres zwrotny, więc wskazuje 9 bajtów wcześniej, tam gdzie 0f 0bsą bajty .

Bajty te powodują wyjątek „niezdefiniowana instrukcja”, zgodnie z przeznaczeniem.


12

Java, 50 43 24 bajty

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

To java.util.function.Consumer<Runtime>1, którego rozkaz skradziono z odpowiedzi puszystego . To działa, bo trzeba nazwać to jak whateverNameYouGiveIt.accept(Runtime.getRuntime())!

Zauważ, że stworzy to nowy proces i sprawi, że rzuci SIGILL, a nie sam SIGILL.

1 - Technicznie rzecz biorąc, może to być również java.util.function.Function<Runtime, Process>ponieważ Runtime#exec(String)zwraca, java.lang.Processktórego można użyć do kontrolowania właśnie utworzonego procesu przez wykonanie polecenia powłoki.


Aby zrobić coś bardziej imponującego w tak pełnym słów języku, oto 72 60 48-bajtowy bonus:

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

Ten jest kolejnym, Consumer<Runtime>który przechodzi WSZYSTKIE procesy (w tym siebie), przez co każdy z nich rzuca SIGILL. Lepsze przygotowanie do gwałtownego wypadku.


I kolejna premia (a Consumer<ANYTHING_GOES>), która przynajmniej udaje, że rzuca SIGILL w 20 bajtów:

a->System.exit(132);

8

Perl, 9 bajtów

kill+4,$$

Po prostu wywołuje odpowiednią funkcję biblioteczną do sygnalizowania procesu i powoduje, że program sam się sygnalizuje SIGILL. Nie dotyczy to żadnych niezgodnych z prawem instrukcji, ale daje odpowiedni wynik. (Myślę, że to sprawia, że ​​wyzwanie jest dość tanie, ale jeśli cokolwiek jest dozwolone, jest to luka, z której skorzystasz…)


Przybyłem tutaj, aby opublikować to samo, ze spacją zamiast +. :)
simbabque

2
Kiedy ludzie uczą się Perla w programowaniu nie golfowym, uczą się tego za pomocą +. Po pewnym czasie gry w golfa +okazjonalnie się popisują. W końcu napisali wystarczającą liczbę programów, w których musieli unikać białych znaków z tego czy innego powodu, że +stają się nawykiem. (Analizuje również mniej jednoznacznie, ponieważ działa w taki sposób, że wyzwala specjalny przypadek w analizatorze składni dla nawiasów.)

8

ARM Unified Assembler Language (UAL), 3 bajty

nop

Na przykład:

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

Po wykonaniu nopprocesor interpretuje .ARM.attributessekcję jako kod i napotyka gdzieś tam niedozwoloną instrukcję:

$ 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

Testowane na Raspberry Pi 3.


Jakoś to nie działa na Pi 2.
Mega Man

7

Microsoft C (Visual Studio 2005 i nowsze), 16 bajtów

main(){__ud2();}

Nie mogę tego łatwo przetestować, ale zgodnie z dokumentacją powinien on wygenerować niedozwoloną instrukcję, celowo próbując wykonać instrukcję tylko do jądra z programu trybu użytkownika. (Należy pamiętać, że ponieważ niedozwolona instrukcja powoduje awarię programu, nie musimy próbować wracać main, co oznacza, że ​​ta mainfunkcja w stylu K & R jest poprawna. Visual Studio nigdy nie przechodząc z C89 jest zwykle złą rzeczą, ale pojawiła się przydatne tutaj.)


Czy potrafisz skompilować dla systemu Linux z VS2015? Ponieważ nie uważam, że SIGILL jest zdefiniowany w systemie Windows, prawda?
Andrew Savinykh,

7

Rubinowy, 13 bajtów

`kill -4 #$$`

Sądzę, że można bezpiecznie założyć, że uruchamiamy to z powłoki * nix. Literały wsteczne uruchamiają podane polecenie powłoki. $$jest działającym procesem Rubiego i #służy do interpolacji ciągów.


Bez bezpośredniego wywoływania powłoki:

Rubinowy, 17 bajtów

Process.kill 4,$$

6

Dowolna powłoka (sh, bash, csh itp.), Dowolny POSIX (10 bajtów)

Trywialna odpowiedź, ale nie widziałem, żeby ktoś ją opublikował.

kill -4 $$

Po prostu wysyła SIGILL do bieżącego procesu. Przykładowe dane wyjściowe w OSX:

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

Możesz zrobić, kill -4 1jeśli pytanie nie jest szczegółowe na temat tego, który program rzuca SIGILL
Mark K Cowan

@ MarkKCowan Heh, dobra uwaga, chociaż zakłada to rootowanie
puszysty

2
You will have root in your programs- znokautuj bajt odpowiedzi i lekko trolluj pytanie jednocześnie: D. BONUS: Zabijeszinit
Mark K Cowan

2
@MarkKCowan: Na (współczesnych wersjach?) Linuksa initjest właściwie odporny na sygnały, których nie zażądał, nawet z rootem. Być może możesz to obejść, używając innego systemu operacyjnego POSIX.

2
kill -4 2następnie: D
Mark K Cowan

6

Kod maszynowy ELF + x86, 45 bajtów

Powinien to być najmniejszy program wykonywalny na komputerze z systemem Unix, który wyrzuca SIGILL (ponieważ Linux nie rozpoznaje pliku wykonywalnego, jeśli zostanie zmniejszony).

Kompiluj z nasm -f bin -o a.out tiny_sigill.asm, przetestowany na maszynie wirtualnej x64.

Rzeczywiste 45 bajtów binarnych:

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

Lista zestawień (patrz źródło poniżej):

;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     $ - $$

Uwaga: kod z poniższego samouczka na temat pisania najmniejszego programu asemblującego, aby zwrócić liczbę, ale używając opcode ud2 zamiast mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html


2
Zamierzałem opublikować zmodyfikowany plik wykonywalny tego dokładnego samouczka, ale pobiłeś mnie. To zasługuje na zwycięstwo; To prawdziwy minimalista w sensie zasobów systemowych (wymaga nie więcej niż 45 bajtów zarówno w pliku, jak i w pamięci, i jest dokładnie taki sam w obu), i nie ma rozlanego interpretera, jak inne rozwiązania asemblera. Jest po prostu tym, czym jest.
Nie będę istniał Idonotexist

5

AutoIt , 93 bajty

Korzystanie z wbudowanego zestawu flatassembler:

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

Po uruchomieniu w interaktywnym trybie SciTE natychmiast się zawiesi. Debuger systemu Windows powinien wyskakować przez ułamek sekundy. Dane wyjściowe konsoli będą wyglądać mniej więcej tak:

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

Gdzie -1073741795jest niezdefiniowany kod błędu generowany przez WinAPI. Może to być dowolna liczba ujemna.

Podobne przy użyciu mojego własnego asemblera LASM :

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

5

NASM, 25 bajtów

Nie wiem, jak to działa, tylko że działa na moim komputerze (Linux x86_64).

global start
start:
jmp 0

Skompiluj i uruchom jak:

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

Prawdopodobnie można go skrócić do czterech bajtów, ponieważja 0
Mark K Cowan

1
lub trzy jakoud2
Mark K Cowan

1
Prawdopodobnie dlatego, że próbuje przejść do niektórych danych?
Asu

5

Zestaw sześciokątny TI-83, 2 bajty

PROGRAM:I
:AsmPrgmED77

Uruchom jako Asm(prgmI). Wykonuje niedozwolony kod operacji 0xed77. Liczę każdą parę cyfr szesnastkowych jako jeden bajt.



3

x86 .COM, 1 bajt

c

ARPLpowoduje #UDw trybie 16-bitowym


1

Powłoka Linux, 9 bajtów

kill -4 0

Wysyła SIGILLdo procesu z PID 0. Nie wiem, jaki proces ma PID 0, ale zawsze istnieje.

Wypróbuj online!


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

1

GNU C, 24 19 18 bajtów

-4 dzięki Dennis
-1 dzięki pułapkowi cat

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

Wypróbuj online! To zakłada ASCII i x86_64. Próbuje uruchomić kod maszynowy 27, co ... jest nielegalne.


shortC , 10 5 4 bajtów

AV"'

Odpowiednik powyższego kodu GNU C. Wypróbuj online!


L"\6"jest również nielegalne, zakładając, że x86_64.
Dennis

@Dennis Jaka instrukcja to 0x06? Nie Ljest to również konieczne.
MD XF

To jest nieprzypisane.
Dennis

Jest nieprzypisany; to sprawia, że ​​jest to nielegalne. Ponadto 'wynosi 39 = 0x27 , a nie 0x39 .
Dennis

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.