Le code le plus court pour lancer SIGILL


76

Contexte

Nous avons déjà un défi à propos de lancer SIGSEGV , alors pourquoi pas un défi à lancer SIGILL?

Qu'est-ce que SIGILL?

SIGILL est le signal d'une instruction illégale du processeur, ce qui arrive très rarement. L'action par défaut après réception de SIGILL est la fermeture du programme et l'écriture d'un vidage mémoire. Le signal ID de SIGILL est 4. Vous rencontrez très rarement SIGILL, et je ne sais absolument pas comment le générer dans votre code, sauf via sudo kill -s 4 <pid>.

Règles

Vous aurez la racine dans vos programmes, mais si vous ne le souhaitez pas, vous pouvez également utiliser un utilisateur normal. Je suis sur un ordinateur Linux avec des paramètres régionaux allemands et je ne connais pas le texte anglais qui s’affiche après la capture de SIGILL, mais je pense que c’est quelque chose qui ressemble à «Instruction illégale». Le programme le plus court qui lance SIGILL gagne.


6
Vous voudrez peut-être préciser si l'instruction doit être générée par le noyau ou non. Voulez-vous en particulier permettre au programme de le générer directement en utilisant l'appel de la libc raise(SIGILL)?

1
C'est vraiment dit Illegal instruction (core dumped).
Erik the Outgolfer

@ ais523 Tout est permis.
Mega Man

5
Pour tout matériel pouvant augmenter SIGILL, la réponse sera la même que la longueur de l'instruction. Il suffit de placer une instruction illégale quelque part et d'essayer de l'exécuter. La seule chose intéressante sera la chaîne d'outils compliquée impliquée.
Cessez de nuire à Monica

3
* les gens postant leurs anciens programmes qui ne fonctionnaient pas *
RudolfJelin

Réponses:


112

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

9

L'instruction 9 n'est pas une instruction valide sur le PDP-11 (ce serait en octal, ce 000011qui ne figure pas dans la liste d'instructions (PDF)). L'assembleur PDP-11 fourni avec UNIX Sixth Edition reproduit apparemment tout ce qu'il ne comprend pas directement dans le fichier; dans ce cas, 9 est un nombre, il génère donc une instruction littérale 9. Il a également la propriété impaire (inhabituelle dans les langages d'assemblage de nos jours) que les fichiers commencent à s'exécuter depuis le début, nous n'avons donc pas besoin de déclarations pour rendre le programme travail.

Vous pouvez tester le programme à l'aide de cet émulateur , bien que vous deviez vous battre un peu pour le saisir.

Voici comment les choses se terminent une fois que vous avez compris comment utiliser le système de fichiers, l'éditeur, le terminal et des objets similaires que vous pensiez déjà savoir utiliser:

% a.out
Illegal instruction -- Core dumped

J'ai confirmé avec la documentation qu'il SIGILLs'agissait d' un signal authentique (et il avait même le même numéro de signal, 4, tout à fait à l'époque!)


1
Il avait le même numéro de signal parce que POSIX, UNIX et le SUS sont étroitement liés :)
Cat

4
Presque tous les numéros de signal dans V6 ont toujours la même signification aujourd'hui; les mnémoniques ont été moins stables que les nombres. Comparez minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h avec github.com/freebsd/freebsd/blob/master/sys/sys/signal.h - sémantique identique à 1 à 13, mais seuls 1, 2 et 13 portent exactement le même nom. (SIGALRM / 14 et SIGTERM / 15 n’ont été ajoutés qu’en V7.) (La lignée des systèmes V a subi quelques modifications, notamment en faisant passer SIGBUS de 10 à 7 (en remplacement de l’inutile SIGEMT) et SIGSYS au-delà de 15 ans, afin de laisser de la place à SIGUSR1. SIGUSR2.)
lundi

4
@cat POSIX et SUS ne spécifient pas réellement les valeurs des signaux - ils spécifient la signification de certains nombres lorsqu'ils sont transmis en tant qu'arguments à la commande kill, mais SIGILL n'est pas inclus.
Random832

7
a.outplusieurs octets, en effet (l’ 9instruction est compilée sur deux octets et l’assembleur ajoute également un en-tête et un pied de page pour rendre le programme exécutable). C'est pourquoi j'ai écrit le programme en langage assembleur, pas en code machine. Le programme en langage assembleur a un seul octet dans et compile dans un programme avec plus d'octets dans; c'est un problème de code-golf (minimiser la taille de la source), pas un problème de taille (minimiser la taille de l'exécutable), c'est donc la taille de la source sur 1 octet qui compte.

2
Abus très intelligent d'un système ancien mais génial.
Mât

81

C (x86_64, tcc ), 7 octets

main=6;

Inspiré par cette réponse .

Essayez-le en ligne!

Comment ça fonctionne

L'assemblage généré ressemble à ceci.

    .globl  main
main:
    .long 6

Notez que TCC ne place pas la "fonction" définie dans un segment de données .

Après la compilation, _start indiquera main comme d'habitude. Lorsque le programme résultant est exécuté, il attend du code dans main et recherche le nombre entier 6 de little-endian (!) 6 , codé sous la forme 0x06 0x00 0x00 0x00 . Le premier octet - 0x06 - est un code opération non valide. Le programme se termine donc avec SIGILL .


C (x86_64, gcc ), 13 octets

const main=6;

Essayez-le en ligne!

Comment ça fonctionne

Sans le modificateur const , l'assemblage généré ressemble à ceci.

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

L'éditeur de liens de GCC considère la dernière ligne comme un indice que l'objet généré ne nécessite pas de pile exécutable. Puisque main est explicitement placé dans une section de données , le code opération qu’il contient n’est pas exécutable. Le programme se termine donc par SIGSEGV (erreur de segmentation).

En supprimant la deuxième ou la dernière ligne, l'exécutable généré fonctionnera comme prévu. La dernière ligne peut être ignorée avec l'indicateur de compilation -zexecstack( Essayez-le en ligne! ), Mais cela coûte 12 octets .

Une alternative plus courte consiste à déclarer main avec le modificateur const , ce qui entraîne l'assemblage suivant.

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

Cela fonctionne sans les indicateurs du compilateur. Notez que main=6;cela écrirait la "fonction" définie dans les données , mais le modificateur const obligera GCC à l'écrire dans rodata , qui (du moins sur ma plate-forme) est autorisé à contenir du code.


J'adore éviter même d'utiliser une fonction :) Comment cela fonctionne-t-il en langage C? Est-ce que le compilateur voit qu'il mains'agit d'un 6 et essaye de l'appeler (ce qui, je suppose, le ferait abandonner et essayer l'instruction)?
Mia yun Ruse

11
@JackDobson c'est un comportement indéfini, donc ça ne marche pas en termes de C; vous êtes à la merci du compilateur. Clang a même un avertissement à ce sujet pour une raison quelconque: "La variable nommée 'main' avec une liaison externe a un comportement indéfini".
Bobby Sacamano

2
GCC se plaindra de mainne pas être une fonction, mais seulement si vous activez les avertissements ( -Wallou -pedanticle ferez).
dimanche

Je pense que c'est assez standard pour les exécutables pour les systèmes de type Unix d'avoir des segments text / data / bss . L'éditeur de liens place la .rodata section à l'intérieur du segment de texte de l'exécutable, et je m'attends à ce que ce soit le cas sur à peu près n'importe quelle plate-forme. (Le chargeur de programme du noyau ne se soucie que des segments, pas des sections).
Peter Cordes

3
Notez également qu'il 06ne s'agit que d'une instruction invalide dans x86-64. En mode 32 bits, PUSH EScette réponse ne fonctionne donc qu'avec les compilateurs dont le comportement par défaut est -m64. Voir ref.x86asm.net/coder.html#x06 . La seule séquence d'octets dont le décodage est garanti en tant qu'instruction non autorisée sur tous les futurs processeurs x86 est le UD2 : 2 octets 0F 0B. Tout le reste pourrait être un préfixe futur ou un codage d’instruction. Néanmoins, une voix pour un moyen génial d’obtenir un compilateur C pour coller une mainétiquette sur certains octets!
Peter Cordes

39

Rapide, 5 octets

[][0]

Access index 0 d'un tableau vide. Cet appel appelle fatalError()un message d'erreur et se bloque avec un SIGILL. Vous pouvez l'essayer ici .


C'est l'un des plus délicats;)
Mega Man

26
... pourquoi est-ce que ça plante avec un SIGILL? Qui a pensé que c'était un signal approprié? Sanglier hipsters: D
Muzer

4
@Asu No; fatalError()se bloque intentionnellement en courant ud2. Je ne sais pas pourquoi ils ont choisi de le faire, mais ils pensaient peut-être que le message d'erreur "Instruction illégale" était logique, car le programme avait un comportement illégal.
NobodyNada

2
Brillant. Je parierais que c'est aussi le code Swift le plus court pour provoquer un crash.
JAL

3
@ JAL Ouais; Je ne peux pas penser à quelque chose de plus court. J'ai essayé nil!, mais le compilateur ne pouvait pas déduire le type de résultat. (Salut aussi JAL!)
NobodyNada

23

GNU C, 25 octets

main(){__builtin_trap();}

GNU C (un dialecte spécifique de C avec extensions) contient une instruction pour planter le programme intentionnellement. L’implémentation exacte varie d’une version à l’autre, mais les développeurs essaient souvent d’implémenter le crash le moins cher possible, ce qui implique normalement l’utilisation d’une instruction illégale.

La version spécifique que j'avais l'habitude de tester est gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0; Cependant, ce programme génère un SIGILL sur un assez grand nombre de plates-formes et est donc assez portable. De plus, il le fait via l'exécution d'une instruction illégale. Voici le code d'assemblage dans lequel ce qui précède est compilé avec les paramètres d'optimisation par défaut:

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

ud2 est une instruction pour laquelle Intel garantit qu’il restera toujours indéfini.


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

De plus, je ne sais pas comment nous comptons les octets pour l'assemblage brut, mais 00 00 0f 0bc'est le langage machine pour ud2
wchargin

5
@wchargin: c'est une réponse x86 + GNU C. Celui-ci est portable sur tous les systèmes GNU. Notez également que UD2 n’est que de 2 octets . IDK où vous avez ces 00octets; ils ne font pas partie du code machine pour UD2. BTW, comme je l'ai commenté sur la réponse de Dennis , il existe pour le moment des instructions illégales à un octet dans x86-64, mais elles ne sont pas garanties pour rester.
Peter Cordes

@wchargin: nous comptons les octets pour les fonctions / programmes en code machine comme vous le souhaitiez. Voir certaines de mes réponses, comme Adler32 dans 32 octets de code machine x86-64 ou GCD dans 8 octets de code machine x86-32 .
Peter Cordes

1
@Ruslan: Ils ne sont pas; 00 00décode la même chose en x86-64 (en tant que add [rax], al). 00 00 0f 0bgénéralement SIGSEGV avant SIGILL, à moins que vous ne disposiez d’un pointeur inscriptible rax.
Peter Cordes

22

C (x86_64), 11, 30, 34 ou 34 + 15 = 49 octets

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

J'ai présenté quelques solutions qui utilisent des fonctions de bibliothèque pour lancer, SIGILLpar divers moyens, mais on peut dire que c'est de la triche, car la fonction de bibliothèque résout le problème. Voici une gamme de solutions qui n'utilisent pas de fonctions de bibliothèque et émettent des hypothèses variables sur l'endroit où le système d'exploitation est prêt à vous permettre d'exécuter du code non exécutable. (Les constantes ici sont choisies pour x86_64, mais vous pouvez les changer pour obtenir des solutions qui fonctionnent pour la plupart des autres processeurs qui ont des instructions illégales.)

06est l'octet du plus petit numéro du code machine qui ne correspond pas à une instruction définie sur un processeur x86_64. Donc, tout ce que nous avons à faire est de l'exécuter. (Alternativement, 2Fest également non défini et correspond à un seul caractère ASCII imprimable.) Ni l'un ni l'autre n'est garanti d'être toujours non défini, mais ils ne sont pas définis à ce jour.

Le premier programme s'exécute ici à 2Fpartir du segment de données en lecture seule. La plupart des linkers ne sont pas capables de produire un saut de travail de .textvers .rodata(ou leur équivalent de système d'exploitation) car ce n'est pas quelque chose qui serait utile dans un programme correctement segmenté; Je n'ai pas encore trouvé de système d'exploitation sur lequel cela fonctionne. Vous devez également tenir compte du fait que de nombreux compilateurs souhaitent que la chaîne en question soit une chaîne large, ce qui nécessiterait un complément.L; Je suppose que tout système d'exploitation sur lequel cela fonctionne a une vue assez dépassée des choses et qu'il est donc construit par défaut pour une norme antérieure à C94. Il est possible que ce programme ne fonctionne nulle part, mais il est également possible que quelque part ce programme fonctionne. Je le répertorie donc dans cette collection de réponses potentielles plus douteuses à moins douteuses. (Après avoir posté cette réponse, Dennis a également mentionné la possibilité main[]={6}dans le chat, qui est de la même longueur et qui ne pose pas de problèmes de largeur de caractère, et a même laissé entendre que le potentiel existe main=6. Je ne peux pas raisonnablement prétendre que ces réponses le mien, comme je n'y pensais pas moi-même)

Le deuxième programme s'exécute ici à 06partir du segment de données en lecture-écriture. Sur la plupart des systèmes d’exploitation, cela entraînera une erreur de segmentation, car les segments de données en écriture sont considérés comme un défaut de conception qui rend les exploitations probables. Cela n’a pas toujours été le cas, donc cela fonctionne probablement sur une version suffisamment ancienne de Linux, mais je ne peux pas le tester facilement.

Le troisième programme s'exécute à 06partir de la pile. Encore une fois, cela provoque une erreur de segmentation de nos jours, car la pile est normalement classée comme non inscriptible pour des raisons de sécurité. La documentation de l'éditeur de liens que j'ai beaucoup vue implique qu'il était légal d'exécuter à partir de la pile (contrairement aux deux cas précédents, il est parfois utile de le faire), donc bien que je ne puisse pas le tester, je suis assez sûr qu'il y a version de Linux (et probablement d’autres systèmes d’exploitation) sur laquelle cela fonctionne.

Enfin, si vous donnez -Wl,-z,execstack(pénalité de 15 octets) à gcc(si vous utilisez GNU lddans le backend), il désactivera explicitement la protection de pile exécutable, permettant ainsi au troisième programme de fonctionner et donnant un signal d’opération non conforme comme prévu. Je l' ai testé et vérifié cette version 49 octets au travail. (Dennis mentionne dans le chat que cette option fonctionne apparemment main=6, ce qui donnerait un score de 6 + 15. Je suis assez surpris que cela fonctionne, étant donné que le 6 n'est pas flagrant; l'option de lien fait apparemment plus que son nom suggère.)


Sur x86-64 / linux avec gcc6 dans son mode par défaut (indulgent), const main=6;fonctionne, ainsi que plusieurs variations. Cet éditeur de liens (qui, je suppose, est également votre éditeur de liens) est capable de générer un saut de .textà .rodata; le problème que vous aviez est que, sans cela const, vous sautez dans le segment de données en écriture ( .data), qui n’est pas exécutable sur du matériel moderne. Cela aurait fonctionné sur les anciens x86, où le matériel de protection de la mémoire ne pouvait pas marquer les pages comme lisibles, mais non exécutables.
dimanche

Notez que même dans C89, il mainest nécessaire d’être une fonction (§5.1.2.2.1) - Je ne sais pas pourquoi gcc considère que la déclaration en maintant qu’objet de données mérite uniquement un avertissement, et uniquement avec -pedanticla ligne de commande. Au début des années 90, quelqu'un a peut-être pensé que personne ne le ferait par accident, mais ce n'est pas comme si c'était utile de le faire exprès, sauf pour ce type de jeu.
dimanche

1
... Relisant à nouveau, il semble que vous vous main[]="/"attendiez à passer au segment de données en lecture seule, car les littéraux de chaîne vont en rodata. Vous avez été surpris par la différence entre char *foo = "..."et char foo[] = "...". char *foo = "..."est un sucre syntaxique pour const char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, donc le littéral chaîne va dans rodata, et fooest une variable globale distincte et inscriptible qui pointe vers elle. Avec char foo[] = "...", cependant, tout le tableau va dans le segment de données en écriture.
dimanche

19

GNU en tant que (x86_64), 3 octets

ud2

$ xxd sigill.S

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

Il doit y avoir un moyen de l'exprimer dans une "source" à deux octets ...
Stop Harming Monica

Oh, intelligent. Je me demandais s'il y avait un moyen de le construire qui placerait le point d'entrée au début du fichier (sans déclaration) et qui n'entraînerait pas de pénalité pour une configuration de système de construction inhabituelle. Je ne pouvais pas en trouver un, mais il semblerait que ce soit le cas.

@ ais523: Ouais, mon script de construction NASM / YASM habituel ( asm-link) pour les programmes de jouets mono-fichier construirait un exécutable à partir de cette source de la même manière, car, par lddéfaut, le point d'entrée est situé au début du segment de texte ou quelque chose comme ça. Je ne pensais tout simplement pas à choisir la taille source asm pour celui-ci: P
Peter Cordes

18

Bash sur Raspbian sur QEMU, 4 (1?) Octets

Pas mon travail. Je rapporte simplement le travail d'un autre. Je ne suis même pas en mesure de tester l'allégation. Puisqu'une partie cruciale de ce défi semble être de trouver un environnement dans lequel ce signal sera émis et capté, je n'inclus pas la taille de QEMU, Raspbian ou bash.

Le 27 février 2013 à 20 h 49, l'utilisateur emlhalac a signalé qu'il avait reçu " des instructions illégales lorsqu'il tentait de chrooter " sur le forum Raspberry Pi.

ping

produisant

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

J'imagine que des commandes beaucoup plus courtes produiront cette sortie, par exemple tr.

EDIT: D'après le commentaire de @ fluffy's , la limite inférieure conjecturée de la longueur d'entrée a été réduite à "1?".


5
Je penserais que la [commande gagnerait. :)
moelleux

17

Fichier COM MS-DOS x86, 2 octets

EDIT: Comme indiqué dans les commentaires, le DOS lui-même ne piège pas l'exception du processeur et se bloque simplement (pas seulement l'application, mais tout le système d'exploitation). L'exécution d'un système d'exploitation basé sur NT 32 bits, tel que Windows XP, déclenchera en effet un signal d'instruction illégal.

0F 0B

De la documentation :

Génère un opcode invalide. Cette instruction est fournie pour les tests logiciels afin de générer explicitement un code opération non valide.

Ce qui est assez explicite. Enregistrer sous un fichier .com et s’exécuter dans n’importe quel émulateur DOS Les émulateurs DOS vont juste planter. Exécuter sous Windows XP, Vista ou 7 32 bits.

SIGILL sur Windows XP


1
Techniquement, le processeur génère une exception d'instruction illégale. Cependant, DOS dispose de capacités de protection de la mémoire et de gestion des exceptions très limitées, et je ne serais pas surpris que cela conduise simplement à un plantage du comportement non défini / du système d'exploitation. L'OP n'a pas dit que le noyau devait attraper l'erreur et afficher "Instruction illégale" sur la console.
Maservant

4
J'ai pensé à cette solution, mais je ne crois pas qu'elle soit valide. La question nécessitant un signal d’ instruction illégal , pas seulement un piège de processeur d’ instruction illégal , l’objectif était de trouver un système d’exploitation capable de générer un signal en réponse au #UDpiège. (En outre, j'ai décidé de le tester, et il est apparu que mon émulateur DOS était projeté dans une boucle infinie.)

2
J'ai testé cela sur MS-DOS sur un AMD K6-II. L'exécuter ne fait que suspendre le système, avec ou sans EMM386 en cours d'exécution. (EMM386 intercepte certaines erreurs et arrête le système avec un message. Il était donc intéressant de tester pour voir si cela ferait une différence.)
Mark

2
Oui, les fenêtres basées sur DOS devraient pouvoir vraiment attraper le piège et au moins planter l’application.
Asu

2
@Asu Je peux confirmer que cela fonctionne sur XP 32 bits et probablement sur tous les autres systèmes Windows 32 bits. Je conviens que ce n’est pas une solution sous DOS, car il se bloque.
Maservant

13

C (Windows 32 bits), 34 octets

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

Cela ne fonctionne que si vous compilez sans optimisation (sinon, le code illégal de la ffonction est "optimisé").

Le désassemblage de la mainfonction ressemble à ceci:

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

Nous pouvons voir qu'il utilise une pushinstruction avec une valeur littérale 0b0f(little-endian, donc ses octets sont permutés). L' callinstruction pousse une adresse de retour (de l' ...instruction) située sur la pile près du paramètre de la fonction. En utilisant un [-1]déplacement, la fonction remplace l'adresse de retour afin qu'elle pointe 9 octets plus tôt, où se trouvent les octets 0f 0b.

Ces octets provoquent une exception "instruction non définie", telle que conçue.


12

Java, 50 43 24 octets

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

Ceci est un java.util.function.Consumer<Runtime>1 dont la commande est volée de la réponse de Fluffy . Cela fonctionne parce que vous devez l' appeler comme whateverNameYouGiveIt.accept(Runtime.getRuntime())!

Notez que cela va créer un nouveau processus et le faire lancer un SIGILL plutôt que de lancer un SIGILL lui-même.

1 - Techniquement, cela peut aussi être un java.util.function.Function<Runtime, Process>parce que Runtime#exec(String)renvoie un java.lang.Processqui peut être utilisé pour contrôler le processus que vous venez de créer en exécutant une commande shell.


Afin de faire quelque chose de plus impressionnant dans un langage aussi prolixe, voici un bonus de 72 60 à 48 octets:

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

Celui-ci en est un autre Consumer<Runtime>qui passe par TOUS les processus (y compris lui-même), faisant que chacun d'eux jette un SIGILL. Mieux vaut se préparer à un accident violent.


Et un autre bonus (a Consumer<ANYTHING_GOES>), qui prétend au moins lancer un SIGILL sur 20 octets:

a->System.exit(132);

8

Perl, 9 octets

kill+4,$$

Appelle simplement la fonction de bibliothèque appropriée pour signaler un processus et oblige le programme à se signaler lui-même SIGILL. Aucune instruction illégale réelle n'est impliquée ici, mais le résultat approprié est obtenu. (Je pense que cela rend le défi assez bon marché, mais si quelque chose est permis, c'est l'échappatoire que vous utiliseriez…)


Est venu ici pour poster le même, avec un espace au lieu de +. :)
simbabque

2
Lorsque les gens apprennent Perl pour des programmes autres que le golf, ils l’apprennent avec a +. Après avoir joué au golf pendant un certain temps, ils font +parfois des démonstrations. Finalement, ils ont écrit suffisamment de programmes où ils avaient besoin d'éviter les espaces pour une raison ou une autre, ce qui en +fait une habitude. (Il analyse également de manière moins ambiguë, car il permet de déclencher le cas particulier de l’analyseur des parenthèses.)

8

Langage d'assemblage unifié (UAL) ARM, 3 octets

nop

Par exemple:

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

Après exécution nop, le processeur interprète la .ARM.attributessection en tant que code et rencontre une instruction illégale quelque part à cet endroit:

$ 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

Testé sur un Raspberry Pi 3.


En quelque sorte, cela ne fonctionne pas sur un Pi 2.
Mega Man

7

Microsoft C (Visual Studio 2005 et versions ultérieures), 16 octets

main(){__ud2();}

Je ne peux pas facilement tester cela, mais selon la documentation, il devrait produire une instruction illégale en essayant intentionnellement d'exécuter une instruction réservée au noyau à partir d'un programme en mode utilisateur. (Notez que, du fait que l'instruction illégale bloque le programme, nous n'avons pas à essayer de revenir main, ce qui signifie que cette mainfonction de style K & R est valide. Visual Studio ne jamais être passé de C89 est normalement une mauvaise chose, mais il est entré utile ici.)


Pouvez-vous compiler pour Linux avec VS2015? Parce que je ne pense pas que SIGILL soit défini dans Windows, est-ce?
Andrew Savinykh

7

Ruby, 13 octets

`kill -4 #$$`

Je suppose qu'il est prudent de supposer que nous exécutons ceci à partir d'un shell * nix. Les littéraux backtick exécutent la commande shell donnée. $$est le processus en cours d'exécution Ruby, et le #est pour l'interpolation de chaîne.


Sans appeler directement le shell:

Ruby, 17 octets

Process.kill 4,$$

6

N'importe quel shell (sh, bash, csh, etc.), n'importe quel POSIX (10 octets)

Réponse banale mais je n'avais vu personne le poster.

kill -4 $$

Envoie simplement SIGILL au processus en cours. Exemple de sortie sur OSX:

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

Vous pourriez le faire kill -4 1si la question n'est pas précise sur le programme qui lance le SIGILL
Mark K Cowan

@MarkKCowan Heh, bon point, bien que cela suppose racine ...
moelleux

2
You will have root in your programs- supprimez un octet de votre réponse et posez légèrement la question en même temps: D. BONUS: Vous devez tuerinit
Mark K Cowan

2
@MarkKCowan: Sur (les versions modernes de?) Linux, il initest en réalité à l'abri des signaux qu'il n'a pas spécifiquement demandé de recevoir, même avec root. Vous pourriez peut-être contourner ce problème en utilisant un système d'exploitation POSIX différent, cependant.

2
kill -4 2alors: D
Mark K Cowan

6

ELF + code machine x86, 45 octets

Ce devrait être le plus petit programme exécutable sur une machine Unix qui lance SIGILL (car Linux ne reconnaît pas l'exécutable s'il est réduit).

Compiler avec nasm -f bin -o a.out tiny_sigill.asm, testé sur une machine virtuelle x64.

Binaire réel de 45 octets:

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

Liste de montage (voir source ci-dessous):

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

Disclaimer: code du tutoriel suivant sur l'écriture du plus petit programme d'assemblage pour renvoyer un nombre, mais en utilisant l'opcode ud2 au lieu de mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html


2
J'allais poster un exécutable modifié de ce tutoriel exact, mais vous m'avez battu. Cela mérite de gagner; C'est un véritable minimaliste au sens des ressources système (il ne nécessite pas plus de 45 octets à la fois dans le fichier et en mémoire, et est exactement le même dans les deux), et aucun interpréteur gonflé comme les autres solutions d'assembleur. C'est simplement ce que c'est.
Iwillnotexist Idonotexist

5

AutoIt , 93 octets

Utilisation de l’assemblage en ligne de flatassembler:

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

Lorsqu'il est exécuté en mode interactif SciTE, il se bloque immédiatement. Le débogueur Windows devrait apparaître pendant une fraction de seconde. La sortie de la console ressemblera à ceci:

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

-1073741795est le code d'erreur indéfini émis par WinAPI. Cela peut être n'importe quel nombre négatif.

Similaire avec mon propre assembleur LASM :

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

5

NASM, 25 octets

Je ne sais pas comment cela fonctionne, mais seulement sur mon ordinateur (Linux x86_64).

global start
start:
jmp 0

Compiler et exécuter comme:

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

Vous pouvez probablement le raccourcir à quatre octets, commeja 0
Mark K Cowan

1
ou trois commeud2
Mark K Cowan

1
Probablement parce qu'il essaie de passer à certaines données?
Asu

5

TI-83 Hex Assembly, 2 octets

PROGRAM:I
:AsmPrgmED77

Courir en tant que Asm(prgmI). Exécute l'opcode 0xed77 non conforme. Je compte chaque paire de chiffres hexadécimaux comme un octet.



3

x86 .COM, 1 octet

c

ARPLprovoque #UDen mode 16 bits


1

Shell Linux, 9 octets

kill -4 0

Envoie SIGILLau processus avec le PID 0. Je ne sais pas quel processus a le PID 0, mais il existe toujours.

Essayez-le en ligne!


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

1

GNU C, 24 19 18 octets

-4 grâce à Dennis
-1 grâce à ceilingcat

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

Essayez-le en ligne! Cela suppose ASCII et x86_64. Il tente d'exécuter le code machine 27, ce qui ... est illégal.


shortC , 10 5 4 octets

AV"'

Équivalent au code GNU C ci-dessus. Essayez-le en ligne!


L"\6"est également illégal, en supposant que x86_64.
Dennis

@Dennis Quelle instruction est 0x06? En outre, le Ln'est pas nécessaire.
MD XF

C'est non assigné.
Dennis

C'est non assigné; c'est ce qui le rend illégal. En outre, 'est 39 = 0x27 , pas 0x39 .
Dennis

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.