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 SIGILL
mit 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.)
06
ist das niedrigstnumerierte Byte des Maschinencodes, das keinem definierten Befehl auf einem x86_64-Prozessor entspricht. Also müssen wir es nur ausführen. (Alternativ 2F
ist 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 2F
vom Nur-Lese-Datensegment ausgeführt. Die meisten Linker sind nicht in der Lage, einen Sprung von .text
zu .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 06
vom 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 06
vom 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 gcc
GNU ld
als 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.)
raise(SIGILL)
?