Kürzester Code, um SIGILL zu werfen


76

Hintergrund

Wir haben bereits eine Herausforderung beim Werfen von SIGSEGV . Warum also nicht eine Herausforderung beim Werfen von SIGILL?

Was ist SIGILL?

SIGILL ist das Signal für eine illegale Anweisung beim Prozessor, was sehr selten vorkommt. Die Standardaktion nach dem Empfang von SIGILL ist das Beenden des Programms und das Schreiben eines Core-Dumps. Die Signal-ID von SIGILL ist 4. Sie begegnen SIGILL sehr selten, und ich habe absolut keine Ahnung, wie Sie es in Ihrem Code generieren sollen, außer über sudo kill -s 4 <pid>.

Regeln

Sie haben root in Ihren Programmen, aber wenn Sie dies aus irgendwelchen Gründen nicht möchten, können Sie auch einen normalen Benutzer verwenden. Ich bin auf einem Linux-Computer mit deutschem Gebietsschema und kenne den englischen Text nicht, der angezeigt wird, nachdem ich SIGILL abgefangen habe, aber ich denke, es ist so etwas wie 'Illegale Anweisung'. Das kürzeste Programm, das SIGILL wirft, gewinnt.


6
Vielleicht möchten Sie klären, ob die Anweisung vom Kernel generiert werden muss oder nicht. Möchten Sie insbesondere zulassen, dass das Programm es nur direkt mit dem libc-Aufruf generiert raise(SIGILL)?

1
Es heißt wirklich Illegal instruction (core dumped).
Erik die Outgolfer

@ ais523 Alles ist erlaubt.
Mega Man

5
Für jede Hardware, die SIGILL auslösen kann, entspricht die Antwort der Anweisungslänge. Legen Sie einfach irgendwo eine illegale Anweisung ab und versuchen Sie, sie auszuführen. Das einzig interessante wird die komplizierte Toolchain sein.
OrangeDog

3
* Leute, die alte Programme
posten

Antworten:


112

PDP-11-Assembler (UNIX Sixth Edition), 1 Byte

9

Anweisung 9 ist keine gültige Anweisung auf dem PDP-11 (in oktaler Form 000011, die nicht in der Anweisungsliste (PDF) enthalten ist). Der mit UNIX Sixth Edition gelieferte PDP-11-Assembler gibt anscheinend alles, was er nicht versteht, direkt in die Datei ein. In diesem Fall ist 9 eine Zahl, sodass eine wörtliche Anweisung 9 generiert wird. Die Eigenschaft odd (in Assemblersprachen heutzutage ungewöhnlich), dass Dateien von Anfang an ausgeführt werden, ist ebenfalls vorhanden. Daher benötigen wir keine Deklarationen, um das Programm zu erstellen Arbeit.

Sie können das Programm mit diesem Emulator testen , obwohl Sie etwas damit kämpfen müssen, um das Programm einzugeben.

Die folgenden Dinge enden, sobald Sie herausgefunden haben, wie Sie das Dateisystem, den Editor, das Terminal und ähnliche Dinge verwenden, von denen Sie dachten, dass Sie bereits wussten, wie man sie verwendet:

% a.out
Illegal instruction -- Core dumped

Ich habe mit der Dokumentation bestätigt, dass dies ein echtes SIGILLSignal ist (und es hatte sogar die gleiche Signalnummer, 4, bis dahin!)


1
Es hatte die gleiche Signalnummer, da POSIX und UNIX und der SUS eng miteinander verwandt sind :)
Katze

4
Fast alle Signalnummern in V6 haben heute noch die gleiche Bedeutung; Die Mnemonik war tatsächlich weniger stabil als die Zahlen. Vergleichen Sie minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h mit github.com/freebsd/freebsd/blob/master/sys/sys/signal.h - identische Semantik für 1 bis 13, aber nur 1, 2 und 13 haben exakt dieselben Namen. (SIGALRM / 14 und SIGTERM / 15 wurden nur in V7 hinzugefügt.) (Die System V-Linie wurde um einige Änderungen erweitert, insbesondere um SIGBUS von 10 auf 7 (anstelle des nutzlosen SIGEMT) und SIGSYS über 15 zu verschieben, um Platz für SIGUSR1 und SIGUSR1 zu schaffen SIGUSR2.)
zwol

4
@cat POSIX und SUS spezifizieren nicht die Werte von Signalen - sie spezifizieren die Bedeutung einiger Zahlen, wenn sie als Argumente an den kill-Befehl übergeben werden, aber SIGILL ist nicht enthalten.
Random832

7
a.outenthält tatsächlich mehrere Bytes (die 9Anweisung wird zu zwei Bytes kompiliert, und der Assembler fügt auch einen Header und einen Footer hinzu, um das Programm ausführbar zu machen). Deshalb habe ich das Programm in Assembler geschrieben, nicht in Maschinencode. Das Assembler-Programm hat nur ein Byte und wird zu einem Programm mit mehr Byte kompiliert. Dies ist ein Code-Golf- Problem (minimieren Sie die Größe der Quelle), kein Größenkodierungsproblem (minimieren Sie die Größe der ausführbaren Datei), daher ist es die 1-Byte-Größe der Quelle, auf die es ankommt.

2
Sehr kluger Missbrauch eines alten, aber großartigen Systems.
Mast

81

C (x86_64, tcc ), 7 Bytes

main=6;

Inspiriert von dieser Antwort .

Probieren Sie es online!

Wie es funktioniert

Die generierte Assembly sieht folgendermaßen aus.

    .globl  main
main:
    .long 6

Beachten Sie, dass TCC findet nicht die definierte „Funktion“ in einem Datensegment.

Nach dem Kompilieren zeigt _start wie gewohnt auf main . Wenn das resultierende Programm ausgeführt wird, erwartet es Code in main und findet die Little-Endian (!) 32-Bit-Ganzzahl 6 , die als 0x06 0x00 0x00 0x00 codiert ist . Das erste Byte - 0x06 - ist ein ungültiger Opcode, daher wird das Programm mit SIGILL beendet .


C (x86_64, gcc ), 13 Bytes

const main=6;

Probieren Sie es online!

Wie es funktioniert

Ohne den const- Modifikator sieht die generierte Assembly folgendermaßen aus.

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

Der Linker von GCC behandelt die letzte Zeile als Hinweis darauf, dass das generierte Objekt keinen ausführbaren Stapel benötigt. Da Haupt explizit in einem platziert Datenabschnitt, ist der Opcode enthält es nicht ausführbar, so wird das Programm beendet SIGSEGV (Segmentierungsfehler).

Wenn Sie entweder die zweite oder die letzte Zeile entfernen, funktioniert die generierte ausführbare Datei wie beabsichtigt. Die letzte Zeile könnte mit dem Compiler-Flag ignoriert werden -zexecstack( online ausprobieren! ), Dies kostet jedoch 12 Byte .

Eine kürzere Alternative besteht darin, main mit dem Modifikator const zu deklarieren , was zu der folgenden Assembly führt.

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

Dies funktioniert ohne Compiler-Flags. Beachten Sie, dass main=6;die definierte "Funktion" in Daten geschrieben wird , aber der const- Modifikator bewirkt , dass GCC sie stattdessen in rodata schreibt , was (zumindest auf meiner Plattform) Code enthalten darf.


Lieben Sie es, überhaupt keine Funktion zu verwenden :) Wie funktioniert das in C-Begriffen? Sieht der Compiler, dass maines sich um eine 6 handelt, und versucht er, sie aufzurufen (was wahrscheinlich dazu führen würde, dass er aufgibt und die Anweisung versucht)?
Mia yun Ruse

11
@JackDobson ist ein undefiniertes Verhalten, daher funktioniert es in Bezug auf C nicht. Sie sind dem Compiler ausgeliefert. Clang hat aus irgendeinem Grund sogar eine Warnung dafür: "Die Variable 'main' mit externer Verknüpfung hat ein undefiniertes Verhalten".
Bobby Sacamano

2
GCC wird sich darüber beschweren, dass es sich mainnicht um eine Funktion handelt, sondern nur, wenn Sie die Warnungen einschalten (entweder -Walloder -pedanticwerden es tun).
20.

Ich denke, es ist ziemlich üblich, dass ausführbare Dateien für Unix-ähnliche Systeme Text / Daten / BSS- Segmente haben . Der Linker platziert den .rodata Abschnitt innerhalb des Textsegments der ausführbaren Datei, und ich gehe davon aus, dass dies auf so ziemlich jeder Plattform der Fall sein wird. (Der Programmlader des Kernels kümmert sich nur um Segmente, nicht um Abschnitte).
Peter Cordes

3
Beachten Sie auch, dass dies 06in x86-64 nur eine ungültige Anweisung ist. Im 32-Bit-Modus ist dies der Fall PUSH ES, daher funktioniert diese Antwort nur mit Compilern, die standardmäßig den Wert "" haben -m64. Siehe ref.x86asm.net/coder.html#x06 . Die einzige Byte - Sequenz , die als illegale Anweisung auf alle zukünftigen x86 - CPUs ist die 2 - Byte zu dekodieren garantiert wird UD2 : 0F 0B. Alles andere könnte ein zukünftiges Präfix oder eine Befehlskodierung sein. Trotzdem wurde es für eine coole Methode empfohlen, einen C-Compiler dazu zu bringen, ein mainLabel auf einige Bytes zu kleben !
Peter Cordes

39

Schnell, 5 Bytes

[][0]

Greifen Sie auf Index 0 eines leeren Arrays zu. Dieser ruft auf fatalError(), der eine Fehlermeldung ausgibt und mit einem SIGILL abstürzt. Sie können es hier ausprobieren .


Dies ist einer der schwierigeren;)
Mega Man

26
... warum um alles in der Welt stürzt es mit einem SIGILL ab? Wer hätte gedacht, dass dies ein angemessenes Signal ist? Blutige Hipster: D
Muzer

4
@Asu Nein; fatalError()stürzt absichtlich beim rennen ab ud2. Warum sie sich dafür entschieden haben, weiß ich nicht, aber vielleicht fanden sie die Fehlermeldung "Illegal instruction" sinnvoll, weil das Programm etwas Illegales tat.
NobodyNada

2
Brillant. Ich würde wetten, dass dies auch der kürzeste Swift-Code ist, der einen Absturz verursacht.
JAL

3
@ JAL Ja; Ich kann mir nichts kürzeres vorstellen. Ich habe es versucht nil!, aber der Compiler konnte nicht auf den Ergebnistyp schließen. (Auch Hallo JAL!)
NobodyNada

23

GNU C, 25 Bytes

main(){__builtin_trap();}

GNU C (ein spezifischer Dialekt von C mit Erweiterungen) enthält eine Anweisung, das Programm absichtlich zum Absturz zu bringen. Die genaue Implementierung variiert von Version zu Version, aber die Entwickler versuchen oft, den Absturz so billig wie möglich zu implementieren, was normalerweise die Verwendung einer illegalen Anweisung beinhaltet.

Die spezielle Version, die ich zum Testen verwendet habe, ist gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0; Dieses Programm verursacht jedoch ein SIGILL auf einem ziemlich breiten Bereich von Plattformen und ist daher ziemlich portabel. Darüber hinaus erfolgt dies durch die tatsächliche Ausführung einer unzulässigen Anweisung. Hier ist der Assembler-Code, den das oben Genannte mit den Standard-Optimierungseinstellungen kompiliert:

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

ud2 ist eine Anweisung, für die Intel garantiert, dass sie immer undefiniert bleibt.


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

Ich weiß auch nicht, wie wir die Bytes für 00 00 0f 0bdie ud2
unformatierte

5
@wchargin: das ist eine x86 + GNU C Antwort. Dieser ist auf alle GNU-Systeme portierbar. Beachten Sie auch, dass UD2 nur 2 Bytes umfasst . IDK, wo Sie diese 00Bytes haben; Sie sind nicht Teil des Maschinencodes für UD2. Übrigens, wie ich Dennis 'Antwort kommentiert habe , gibt es derzeit in x86-64 unzulässige 1-Byte-Anweisungen, aber das kann nicht garantiert werden.
Peter Cordes

@wchargin: Wir zählen Bytes für Maschinencode-Funktionen / -Programme, wie Sie es erwarten würden. Sehen Sie einige meiner Antworten, wie Adler32 in 32 Byte x86-64-Maschinencode oder GCD in 8 Byte x86-32-Maschinencode .
Peter Cordes

1
@ Ruslan: Sie sind nicht; 00 00decodiert dasselbe in x86-64 (als add [rax], al). 00 00 0f 0bwürde normalerweise SIGSEGV vor SIGILL sein, es sei denn, Sie haben zufällig einen beschreibbaren Zeiger in rax.
Peter Cordes

22

C (x86_64), 11, 30, 34 oder 34 + 15 = 49 Bytes

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

Ich habe ein paar Lösungen vorgelegt, die Bibliotheksfunktionen verwenden, um SIGILLmit verschiedenen Mitteln zu werfen , aber das ist wohl Betrug, da die Bibliotheksfunktion das Problem löst. Hier finden Sie eine Reihe von Lösungen, die keine Bibliotheksfunktionen verwenden und unterschiedliche Annahmen darüber treffen, wo das Betriebssystem bereit ist, Sie nicht ausführbaren Code ausführen zu lassen. (Die Konstanten hier sind für x86_64 ausgewählt, aber Sie können sie ändern, um funktionierende Lösungen für die meisten anderen Prozessoren mit ungültigen Anweisungen zu erhalten.)

06ist das niedrigstnumerierte Byte des Maschinencodes, das keinem definierten Befehl auf einem x86_64-Prozessor entspricht. Also müssen wir es nur ausführen. (Alternativ 2Fist auch undefiniert und entspricht einem einzelnen druckbaren ASCII-Zeichen.) Keines dieser Zeichen ist garantiert immer undefiniert, aber sie sind ab heute nicht definiert.

Das erste Programm hier wird 2Fvom Nur-Lese-Datensegment ausgeführt. Die meisten Linker sind nicht in der Lage, einen Sprung von .textzu .rodata(oder das Äquivalent zu ihrem Betriebssystem) zu erzeugen, da dies in einem korrekt segmentierten Programm niemals nützlich sein würde. Ich habe noch kein Betriebssystem gefunden, auf dem dies funktioniert. Sie müssten auch die Tatsache berücksichtigen, dass viele Compiler möchten, dass die fragliche Zeichenfolge eine breite Zeichenfolge ist, für die eine zusätzliche erforderlich wäreL; Ich gehe davon aus, dass jedes Betriebssystem, auf dem dies funktioniert, eine ziemlich veraltete Sicht der Dinge hat und daher standardmäßig auf einen Standard vor C94 aufbaut. Es ist möglich, dass dieses Programm nirgendwo funktioniert, aber es ist auch möglich, dass dieses Programm irgendwo funktioniert, und daher liste ich es in dieser Sammlung von zweifelhafteren bis weniger zweifelhaften möglichen Antworten auf. (Nachdem ich diese Antwort gepostet hatte, erwähnte Dennis auch die Möglichkeit main[]={6}im Chat, die die gleiche Länge hat und die keine Probleme mit der Zeichenbreite verursacht, und wies sogar auf das Potenzial für hin main=6. Ich kann diese Antworten nicht als vernünftig bezeichnen meins, da ich selbst nicht an sie gedacht habe.)

Das zweite Programm wird hier 06vom Lese- / Schreibdatensegment ausgeführt. Auf den meisten Betriebssystemen führt dies zu einem Segmentierungsfehler, da beschreibbare Datensegmente als schlechter Konstruktionsfehler angesehen werden, der Exploits wahrscheinlich macht. Dies war jedoch nicht immer der Fall, so dass es wahrscheinlich auf einer ausreichend alten Linux-Version funktioniert, aber ich kann es nicht einfach testen.

Das dritte Programm wird 06vom Stapel ausgeführt. Auch dies führt heutzutage zu einem Segmentierungsfehler, da der Stack aus Sicherheitsgründen normalerweise als nicht beschreibbar eingestuft wird. Die Linker-Dokumentation, die ich stark gesehen habe, impliziert, dass es früher legal war, vom Stapel auszuführen (im Gegensatz zu den beiden vorhergehenden Fällen ist dies gelegentlich nützlich). Obwohl ich es nicht testen kann, bin ich mir ziemlich sicher, dass es einige gibt Linux-Version (und wahrscheinlich auch andere Betriebssysteme), auf denen dies funktioniert.

Wenn Sie -Wl,-z,execstack( wenn Sie gccGNU ldals Teil des Backends verwenden) mit (15-Byte-Strafe) belegen, wird der Schutz für ausführbare Stapel explizit deaktiviert, sodass das dritte Programm wie erwartet funktionieren und ein ungültiges Betriebssignal ausgeben kann. Ich habe diese 49-Byte-Version getestet und verifiziert, damit sie funktioniert. (Dennis erwähnt im Chat, dass diese Option anscheinend funktioniert main=6, was eine Punktzahl von 6 + 15 ergeben würde. Ich bin ziemlich überrascht, dass dies funktioniert, da die 6 offensichtlich nicht auf dem Stack ist; die Link-Option macht anscheinend mehr als der Name weist darauf hin.)


Unter x86-64 / linux mit gcc6 im Standardmodus (lenient) const main=6;funktioniert dies ebenso wie verschiedene Variationen. Dieser Linker (was ich vermute auch , Ihre Linker ist) ist der Lage , einen Sprung von Erzeugung .textzu .rodata; Das Problem, das Sie hatten, ist, dass Sie ohne constin das beschreibbare Datensegment ( .data) springen , das auf moderner Hardware nicht ausführbar ist. Es hätte auf älteren x86-Versionen funktioniert, bei denen die Speicherschutzhardware Seiten nicht als lesbar, aber nicht ausführbar markieren konnte.
20.

Beachten Sie, dass auch in C89 maineine Funktion sein muss (§5.1.2.2.1) - Ich weiß nicht, warum gcc die Deklaration mainals Datenobjekt in Betracht zieht, um nur eine Warnung zu verdienen, und zwar nur -pedanticin der Befehlszeile. Jemand in den frühen neunziger Jahren dachte vielleicht, dass niemand das versehentlich tun würde, aber es ist nicht so, als wäre es eine nützliche Sache, die man absichtlich machen könnte, außer für diese Art von Spiel.
20.

1
... Beim erneuten main[]="/"Lesen wird erwartet, dass Sie in das schreibgeschützte Datensegment springen, da String-Literale in rodata geschrieben werden. Sie wurden vom Unterschied zwischen char *foo = "..."und überrascht char foo[] = "...". char *foo = "..."ist syntaktischer Zucker für const char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, daher geht das String-Literal in rodata und fooist eine separate , beschreibbare globale Variable, die darauf verweist. Mit char foo[] = "..."geht jedoch das gesamte Array in das beschreibbare Datensegment.
20.

19

GNU as (x86_64), 3 Bytes

ud2

$ xxd sigill.S

00000000: 7564 32                                  ud2

$ as --64 sigill.S -o sigill.o; ld-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

Es muss eine Möglichkeit geben, dies in einer Zwei-Byte- "Quelle"
auszudrücken

Oh, schlau. Ich habe mich gefragt, ob es eine Möglichkeit gibt, dies zu erstellen, bei der der Einstiegspunkt am Anfang der Datei steht (ohne Deklarationen) und bei der für eine ungewöhnliche Buildsystemkonfiguration keine Nachteile entstehen. Ich konnte keinen finden, aber es sieht so aus, als hättest du es getan.

@ ais523: Ja, mein gewöhnliches NASM / YASM-Build-Script ( asm-link) für Spielzeugprogramme mit einer einzelnen Datei würde eine ausführbare Datei aus dieser Quelle auf die gleiche Weise erstellen, da ldder Einstiegspunkt standardmäßig auf den Anfang des Textsegments oder so ähnlich festgelegt ist. Ich habe nur nicht daran gedacht, hier die Quellgröße zu wählen: P
Peter Cordes

18

Bash auf Raspbian auf QEMU, 4 (1?) Bytes

Nicht meine Arbeit. Ich berichte nur die Arbeit eines anderen. Ich bin nicht einmal in der Lage, die Behauptung zu testen. Da ein entscheidender Teil dieser Herausforderung darin zu bestehen scheint, eine Umgebung zu finden, in der dieses Signal ausgelöst und abgefangen wird, schließe ich die Größe von QEMU, Raspbian oder Bash nicht ein.

Am 27. Februar 2013, 20:49 Uhr, berichtete der Benutzer emlhalac in den Raspberry Pi-Foren , dass er " illegale Anweisungen erhalten" habe, wenn er versucht zu chrooten .

ping

produzieren

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

Ich stelle mir zum Beispiel vor, dass viel kürzere Befehle diese Ausgabe erzeugen tr.

BEARBEITEN: Auf der Grundlage des Kommentars von @ fluffy wurde die mutmaßliche Untergrenze für die Eingabelänge auf "1?"


5
Ich würde denken, das [Kommando würde gewinnen. :)
flauschige

17

x86-MS-DOS-COM-Datei, 2 Byte

BEARBEITEN: Wie in den Kommentaren erwähnt, wird DOS selbst die CPU-Ausnahme nicht abfangen und einfach hängen bleiben (nicht nur die App, das gesamte Betriebssystem). Die Ausführung auf einem 32-Bit-NT-basierten Betriebssystem wie Windows XP löst in der Tat ein ungültiges Anweisungssignal aus.

0F 0B

Aus der Dokumentation :

Erzeugt einen ungültigen Opcode. Diese Anweisung dient zum Testen der Software, um explizit einen ungültigen Opcode zu generieren.

Welches ist ziemlich selbsterklärend. Als .com-Datei speichern und in einem DOS-Emulator ausführen DOS-Emulatoren stürzen einfach ab. Laufen Sie unter Windows XP, Vista oder 7 32-Bit.

SIGILL unter Windows XP


1
Aus technischen Gründen generiert der Prozessor eine unzulässige Anweisungsausnahme. DOS verfügt jedoch nur über sehr eingeschränkte Speicherschutz- und Ausnahmebehandlungsfunktionen, und ich wäre nicht überrascht, wenn dies nur zu einem undefinierten Verhalten / Betriebssystemabsturz führen würde. Das OP hat nicht gesagt, dass der Kernel den Fehler abfangen und "Illegal Instruction" auf der Konsole ausgeben muss.
Diener

4
Ich habe über diese Lösung nachgedacht, aber ich glaube nicht, dass sie gültig ist. Die Frage erfordert ein illegale Anweisung Signal , nicht nur einen ungültigen Anweisung Prozessor Fall , so dass das Ziel , ein Betriebssystem zu finden war , die tatsächlich ein Signal als Reaktion auf die Erzeugung würde #UDstoppen. (Außerdem habe ich beschlossen, es tatsächlich zu testen, und es schien, als würde mein DOS-Emulator in eine Endlosschleife

2
Ich habe dies unter MS-DOS auf einem AMD K6-II getestet. Wenn Sie es ausführen, bleibt das System hängen, sowohl mit als auch ohne EMM386. (EMM386 Fallen einiger Fehler und stoppt das System mit einer Meldung, so war es wert zu testen , um zu sehen , ob es einen Unterschied gemacht.)
Mark

2
Ja, DOS-basierte Fenster sollten wirklich in der Lage sein, die Falle zu fangen und zumindest die App zum Absturz zu bringen.
Asu

2
@Asu Ich kann bestätigen, dass dies unter XP 32-Bit funktioniert und wahrscheinlich auch auf allen anderen 32-Bit-Windows-Systemen. Ich bin damit einverstanden, dass dies keine Lösung für DOS selbst ist, da es nur abstürzt.
Diener

13

C (32-Bit-Windows): 34 Byte

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

Dies funktioniert nur, wenn das Kompilieren nicht optimiert wurde (ansonsten ist der ungültige Code in der fFunktion "optimiert").

Die Demontage der mainFunktion sieht folgendermaßen aus:

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

Wir können sehen, dass es einen pushBefehl mit einem Literalwert verwendet 0b0f(Little-Endian, also werden seine Bytes ausgetauscht). Der callBefehl sendet eine Rücksprungadresse (des ...Befehls), die sich auf dem Stapel in der Nähe des Parameters der Funktion befindet. Bei Verwendung einer [-1]Verschiebung überschreibt die Funktion die Rücksprungadresse, sodass sie 9 Bytes früher zeigt, wo sich die Bytes 0f 0bbefinden.

Diese Bytes verursachen eine "undefinierte Anweisungs" -Ausnahme, wie vorgesehen.


12

Java, 50 43 24 Bytes

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

Dies ist eine java.util.function.Consumer<Runtime>1, deren Befehl aus Fluffys Antwort gestohlen wird . Es funktioniert, weil Sie es so nennen müssenwhateverNameYouGiveIt.accept(Runtime.getRuntime()) !

Beachten Sie, dass dadurch ein neuer Prozess erstellt und ein SIGILL ausgelöst wird, anstatt ein SIGILL selbst auszulösen.

1 - Technisch gesehen kann es sich auch um ein java.util.function.Function<Runtime, Process>because Runtime#exec(String)return a handeln java.lang.Process, mit dem Sie den Prozess steuern können, den Sie gerade durch Ausführen eines Shell-Befehls erstellt haben.


Um etwas Beeindruckenderes in solch einer wortreichen Sprache zu tun, gibt es hier einen Bonus von 72 60 48 Byte:

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

Dieses ist ein anderes Consumer<Runtime>, das ALLE Prozesse durchläuft (einschließlich sich selbst), wobei jeder von ihnen ein SIGILL wirft. Besser auf einen heftigen Sturz gefasst.


Und noch ein Bonus (a Consumer<ANYTHING_GOES>), der zumindest vorgibt , ein SIGILL in 20 Bytes zu werfen:

a->System.exit(132);

8

Perl, 9 Bytes

kill+4,$$

Ruft einfach die entsprechende Bibliotheksfunktion zur Signalisierung eines Prozesses auf und veranlasst das Programm, sich selbst zu signalisieren SIGILL. Hier handelt es sich nicht um rechtswidrige Anweisungen, sondern um das entsprechende Ergebnis. (Ich denke, das macht die Herausforderung ziemlich billig, aber wenn irgendetwas erlaubt ist, ist dies die Lücke, die Sie nutzen würden ...)


Kam hierher, um dasselbe zu posten, mit einem Leerzeichen anstelle des +. :)
simbabque

2
Wenn Leute Perl für Nicht-Golf-Programmierung lernen, lernen sie es mit a +. Nachdem sie eine Weile Golf gespielt haben +, zeigen sie sich gelegentlich. Schließlich haben sie genug Programme geschrieben, um Leerzeichen aus irgendeinem Grund zu vermeiden, der +zur Gewohnheit wird. (Es analysiert auch weniger mehrdeutig, da es den Sonderfall im Parser für Klammern

8

ARM Unified Assembler Language (UAL), 3 Byte

nop

Zum Beispiel:

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

Nach der Ausführung nopinterpretiert der Prozessor den .ARM.attributesAbschnitt als Code und trifft irgendwo dort auf eine unzulässige Anweisung:

$ 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

Getestet auf einem Raspberry Pi 3.


Irgendwie funktioniert das auf einem Pi 2 nicht.
Mega Man

7

Microsoft C (ab Visual Studio 2005), 16 Byte

main(){__ud2();}

Ich kann das nicht einfach testen, aber laut Dokumentation sollte es eine illegale Anweisung erzeugen, indem absichtlich versucht wird, eine Nur-Kernel-Anweisung von einem Benutzermodus-Programm auszuführen. (Beachten Sie, dass wir nicht versuchen müssen, zurückzukehren, da der illegale Befehl das Programm zum Absturz bringt. mainDies bedeutet, dass diese K & R- mainähnliche Funktion gültig ist. Visual Studio, das nie von C89 übergegangen ist, ist normalerweise eine schlechte Sache, aber sie ist eingegangen nützlich hier.)


Können Sie mit VS2015 für Linux kompilieren? Weil ich nicht denke, dass SIGILL in Windows definiert ist, oder?
Andrew Savinykh

7

Ruby, 13 Bytes

`kill -4 #$$`

Ich denke, es ist sicher anzunehmen, dass wir dies von einer * nix-Shell ausführen. Die Backtick-Literale führen den angegebenen Shell-Befehl aus. $$ist der laufende Ruby-Prozess und der #für die String-Interpolation.


Ohne die Shell direkt aufzurufen:

Ruby, 17 Bytes

Process.kill 4,$$

6

Beliebige Shell (sh, bash, csh usw.), beliebiges POSIX (10 Byte)

Triviale Antwort, aber ich hatte niemanden gesehen, der sie gepostet hat.

kill -4 $$

Sendet einfach SIGILL an den aktuellen Prozess. Beispielausgabe unter OSX:

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

Sie könnten tun, kill -4 1wenn die Frage nicht spezifisch ist, welches Programm SIGILL
Mark K Cowan

@ MarkKCowan Heh, guter Punkt, obwohl das Wurzel voraussetzt ...
flauschige

2
You will have root in your programs- Schlagen Sie ein Byte von Ihrer Antwort ab und werfen Sie gleichzeitig einen leichten Blick auf die Frage: D. BONUS: Du darfst töteninit
Mark K Cowan

2
@MarkKCowan: Unter (modernen Versionen von?) Linux initist es eigentlich immun gegen Signale, die es selbst mit root nicht speziell angefordert hat. Sie können dies möglicherweise umgehen, indem Sie ein anderes POSIX-Betriebssystem verwenden.

2
kill -4 2dann: D
Mark K Cowan

6

ELF + x86-Maschinencode, 45 Byte

Dies sollte das kleinste ausführbare Programm auf einem Unix-Rechner sein, das SIGILL auslöst (da Linux die ausführbare Datei nicht erkennt, wenn sie verkleinert wird).

Kompilieren Sie mit nasm -f bin -o a.out tiny_sigill.asm, getestet auf einer virtuellen x64-Maschine.

Tatsächliche 45 Bytes binär:

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

Montageliste (siehe Quelle unten):

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

Haftungsausschluss: Code aus dem folgenden Tutorial zum Schreiben des kleinsten Assembler-Programms, um eine Zahl zurückzugeben. Verwenden Sie jedoch opcode ud2 anstelle von mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html


2
Ich wollte eine modifizierte ausführbare Datei dieses genauen Tutorials veröffentlichen, aber Sie haben mich geschlagen. Das verdient zu gewinnen; Es ist ein wahrer Minimalist im Sinne der Systemressourcen (es erfordert nicht mehr als 45 Bytes sowohl in der Datei als auch im Speicher und ist in beiden exakt gleich) und kein aufgeblähter Interpreter wie die anderen Assembler-Lösungen. Es ist einfach was es ist.
Ich werde nicht existieren Idonotexist

5

AutoIt , 93 Bytes

Verwendung der Flatassembler-Inline-Montage:

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

Wenn es im interaktiven SciTE-Modus ausgeführt wird, stürzt es sofort ab. Der Windows-Debugger sollte für den Bruchteil einer Sekunde angezeigt werden. Die Konsolenausgabe sieht ungefähr so ​​aus:

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

Wo -1073741795wird der undefinierte Fehlercode von der WinAPI ausgegeben? Dies kann eine beliebige negative Zahl sein.

Ähnlich mit meinem eigenen Assembler LASM :

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

5

NASM, 25 Byte

Ich weiß nicht, wie das funktioniert, nur dass es auf meinem Computer funktioniert (Linux x86_64).

global start
start:
jmp 0

Kompilieren und ausführen wie:

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

Sie können es wahrscheinlich auf vier Bytes verkürzen, wieja 0
Mark K Cowan

1
oder drei alsud2
Mark K Cowan

1
Wahrscheinlich, weil es versucht, zu Daten zu springen?
Asu

5

TI-83 Hex Assembly, 2 Byte

PROGRAM:I
:AsmPrgmED77

Führen Sie so Asm(prgmI). Führt den ungültigen 0xed77-Opcode aus. Ich zähle jedes Paar hexadezimaler Ziffern als ein Byte.



3

x86.COM, 1 Byte

c

ARPLUrsachen #UDim 16-Bit-Modus


1

Linux-Shell, 9 Bytes

kill -4 0

Sendet SIGILLan den Prozess mit PID 0. Ich weiß nicht, welcher Prozess PID 0 hat, aber er existiert immer.

Probieren Sie es online!


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

1

GNU C, 24 19 18 Bytes

-4 dank Dennis
-1 dank ceilingcat

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

Probieren Sie es online! Dies setzt ASCII und x86_64 voraus. Es wird versucht, den Maschinencode auszuführen 27, der ... unzulässig ist.


shortC , 10 5 4 Bytes

AV"'

Entspricht dem obigen GNU C-Code. Probieren Sie es online!


L"\6"ist auch illegal, vorausgesetzt x86_64.
Dennis

@ Tennis Welche Anweisung ist 0x06? Auch das List nicht nötig.
MD XF

Es ist nicht zugewiesen.
Dennis

Es ist nicht zugewiesen; das macht es illegal. Außerdem 'ist 39 = 0x27 , nicht 0x39 .
Dennis

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.