Найкоротший код для кидання SIGILL


76

Фон

У нас вже є завдання щодо кидання SIGSEGV , так чому б не виклик кидання SIGILL?

Що таке SIGILL?

SIGILL - це сигнал про незаконну інструкцію процесору, що трапляється дуже рідко. Дія за замовчуванням після отримання SIGILL - це припинення програми та запис основного дампа. Ідентифікатор сигналу SIGILL становить 4. Ви зустрічаєтесь із SIGILL дуже рідко, і я абсолютно не маю уявлення, як генерувати його у своєму коді, крім via sudo kill -s 4 <pid>.

Правила

Ви матимете корінь у своїх програмах, але якщо з будь-яких причин цього не хочете, ви також можете використовувати звичайного користувача. Я на комп'ютері Linux з німецькою мовою, і я не знаю англійського тексту, який відображається після вилучення SIGILL, але я думаю, що це щось на кшталт "Незаконна інструкція". Виграє найкоротша програма, яка кидає SIGILL.


6
Ви можете уточнити, чи повинна інструкція генеруватися ядром чи ні. Зокрема, ви хочете дозволити програмі просто генерувати її безпосередньо за допомогою виклику libc raise(SIGILL)?

1
Це дійсно говорить Illegal instruction (core dumped).
Ерік Атголфер

@ ais523 Дозволено все.
Мега-людина

5
Для будь-якого обладнання, яке може підняти SIGILL, відповідь буде такою ж, як і довжина інструкції. Просто покладіть десь незаконну інструкцію і спробуйте її виконати. Єдиним цікавим буде заплутаний ланцюжок інструментів.
OrangeDog

3
* люди публікували старі програми, які у них не працювали *
RudolfJelin

Відповіді:


112

PDP-11 Асемблер (UNIX шосте видання), 1 байт

9

Інструкція 9 не є дійсною інструкцією для PDP-11 (у восьмеричній частині, це було б 000011, що не відображається у списку інструкцій (PDF)). Асемблер PDP-11, що постачається з UNIX шостою редакцією, очевидно, повторює все те, що він не розуміє, безпосередньо у файл; у цьому випадку 9 - це число, тож воно генерує буквальну інструкцію 9. У нього також є дивна властивість (незвична в мовах складання нині), що файли починають працювати з самого початку, тому нам не потрібні декларації для створення програми робота.

Ви можете протестувати програму за допомогою цього емулятора , хоча вам доведеться дещо боротися з нею, щоб ввести програму.

Ось як все закінчується, коли ви зрозуміли, як користуватися файловою системою, редактором, терміналом та подібними речами, які ви думали, що вже знаєте, як користуватися:

% a.out
Illegal instruction -- Core dumped

Я підтвердив документацією, що це справжній SIGILLсигнал (і навіть у нього був той самий номер сигналу, 4, весь час назад!)


1
Він мав однаковий номер сигналу, тому що POSIX і UNIX та SUS тісно пов'язані :)
кіт

4
Майже всі сигнальні номери V6 досі мають однакові значення; Мнемоніка насправді була менш стабільною, ніж числа. Порівняйте minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h з github.com/freebsd/freebsd/blob/master/sys/sys/signal.h - однакова семантика для 1 - 13, але лише 1, 2 і 13 мають абсолютно однакові назви. (SIGALRM / 14 і SIGTERM / 15 були додані лише у V7.) (Рядок System V має декілька змін, зокрема переміщення SIGBUS з 10 на 7 (замінюючи непотрібний SIGEMT) та SIGSYS вище 15, щоб звільнити місце для SIGUSR1 і SIGUSR2.)
zwol

4
@cat POSIX і SUS насправді не вказують значення сигналів - вони вказують значення деяких чисел, коли передаються як аргументи команді kill, але SIGILL не включається.
Випадково832

7
a.outНасправді в ньому є кілька байтів ( 9інструкція збирається в два байти, а асемблер також додає заголовок і колонтитул, щоб зробити програму виконуваною). Тому я написав програму мовою складання, а не машинним кодом. Програма мови складання містить лише один байт і компілює до програми з більшою кількістю байтів; це проблема коду-гольфу (мінімізуйте розмір джерела), а не проблема кодування розмірів (мінімізуйте розмір виконуваного файлу), тому значення має 1-байтовий розмір джерела.

2
Дуже розумне зловживання старою, але приголомшливою системою.
щогла

81

C (x86_64, tcc ), 7 байт

main=6;

Натхненний цією відповіддю .

Спробуйте в Інтернеті!

Як це працює

Створена збірка виглядає приблизно так.

    .globl  main
main:
    .long 6

Зауважте, що TCC не розміщує визначену "функцію" в сегменті даних .

Після компіляції _start вкаже на main як завжди. Коли виконувана програма виконується, вона очікує код в основному і знаходить малого ендіанського (!) 32-бітного цілого числа 6 , кодованого як 0x06 0x00 0x00 0x00 . Перший байт - 0x06 - є недійсним опкодом , тому програма закінчується SIGILL .


C (x86_64, gcc ), 13 байт

const main=6;

Спробуйте в Інтернеті!

Як це працює

Без модифікатора const створена збірка виглядає приблизно так.

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

Лінкер GCC трактує останній рядок як натяк на те, що згенерованому об'єкту не потрібен виконуваний стек. Оскільки main явно розміщений у розділі даних , то його код, який він містить, не виконується, тому програма завершується, SIGSEGV (помилка сегментації).

Видалення або другого, або останнього рядка зробить створене виконувану роботу за призначенням. Останній рядок можна ігнорувати прапором компілятора -zexecstack( Спробуйте його в Інтернеті! ), Але це коштує 12 байт .

Більш короткою альтернативою є оголошення основним за допомогою модифікатора const , що призводить до наступної збірки.

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

Це працює без будь-яких прапорів компілятора. Зауважте, що main=6;було б записати визначену "функцію" в дані , але модифікатор const змушує GCC записувати її в родати , які (принаймні на моїй платформі) можуть містити код.


Любіть повне уникання навіть використання функції :) Як це працює в термінах С? Чи бачить компілятор main6 і намагається викликати його (який, напевно, змусив би його відмовитись та спробувати інструкцію)?
Mia yun Ruse

11
@JackDobson це невизначена поведінка, тому вона не працює з точки зору C; ви на милість компілятора. З цього приводу навіть Кланг навіть має попередження: "змінна назва" головна "із зовнішнім зв'язком має невизначену поведінку".
Боббі Сакамано

2
GCC скаржиться на mainте, що вона не є функцією, але лише у тому випадку, якщо ви включите попередження ( -Wallабо -pedanticзробите це).
zwol

Я думаю, що у виконуваних файлах для Unix-подібних систем досить стандартним є сегменти тексту / даних / bss . Лінкер розміщує .rodata розділ всередині текстового сегменту виконуваного файлу, і я думаю, що це буде так майже на будь-якій платформі. (Завантажувач програм ядра дбає лише про сегменти, а не про розділи).
Пітер Кордес

3
Також зауважте, що 06це лише недійсна інструкція в x86-64. У 32-бітному режимі це PUSH ESтак, тож ця відповідь працює лише з компіляторами, для яких за замовчуванням -m64. Див. Ref.x86asm.net/coder.html#x06 . Єдиний байт послідовність , яка гарантовано декодувати як неприпустиму інструкцію всіх майбутніх процесорів x86 є 2 байта UD2 : 0F 0B. Все інше може бути деяким майбутнім префіксом або кодуванням інструкцій. І все-таки прихильний класний спосіб отримати компілятор C, щоб наклеїти mainмітку на деякі байти!
Пітер Кордес

39

Швидкий, 5 байт

[][0]

Індекс доступу 0 порожнього масиву. Це дзвінок fatalError(), який друкує повідомлення про помилку і збої з SIGILL. Ви можете спробувати тут .


Це одна з хитріших;)
Мега Людина

26
... чому на Землі він зазнає аварії з СИГІЛЬ? Хто подумав, що це відповідний сигнал? Криваві хіпстери: D
Мюзер

4
@Asu Ні; fatalError()навмисно вибивається бігом ud2. Чому вони вирішили це зробити, я не знаю, але, можливо, вони вважали, що повідомлення про помилку "Незаконна інструкція" має сенс, оскільки програма зробила щось незаконне.
НіхтоНада

2
Блискуча. Я б сказав, що це також найкоротший код Swift, який може призвести до збоїв.
JAL

3
@JAL Так; Я не можу придумати нічого коротшого. Я спробував nil!, але компілятор не міг зробити висновок про тип результату. (Також привіт JAL!)
НіхтоНада

23

GNU C, 25 байт

main(){__builtin_trap();}

GNU C (специфічний діалект C з розширеннями) містить інструкцію навмисно руйнувати програму. Точна реалізація варіюється від версії до версії, але часто розробники роблять спробу здійснити збій якомога дешевше, що зазвичай передбачає використання незаконної інструкції.

Конкретна версія, яку я використовував для тестування gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0: однак ця програма викликає SIGILL на досить широкому асортименті платформ, і, таким чином, є досить портативною. Крім того, це робиться шляхом фактичного виконання незаконної інструкції. Ось код складання, який складається вище, з налаштуваннями оптимізації за замовчуванням:

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

ud2 це інструкція, що гарантії Intel завжди залишатимуться невизначеними.


11
−6:main(){asm("ud2");}
вхід

Крім того, я не знаю, як ми підраховуємо байти для необробленої збірки, але 00 00 0f 0bце машина машини для ud2
wchargin

5
@wchargin: це відповідь x86 + GNU C. Цей портативний для всіх систем GNU. Також зауважте, що UD2 - це лише 2 байти . IDK, де ви отримали ці 00байти; вони не є частиною машинного коду для UD2. До речі, як я коментував відповідь Денніса , наразі є однобайтові незаконні вказівки в x86-64, але вони не гарантовано залишатимуться таким.
Пітер Кордес

@wchargin: Ми рахуємо байти для функцій / програм машинного коду, як ви очікували. Дивіться деякі мої відповіді, наприклад, Adler32 в 32 байтах машинного коду x86-64 або GCD в 8 байтах машинного коду x86-32 .
Пітер Кордес

1
@ Руслан: Вони ні; 00 00декодує те саме в x86-64 (як add [rax], al). 00 00 0f 0bзазвичай SIGSEGV перед SIGILL, якщо у вас не трапиться вказівник, що записується rax.
Пітер Кордес

22

C (x86_64), 11, 30, 34 або 34 + 15 = 49 байт

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

Я подав пару рішень, які використовують функції бібліотеки для перекидання SIGILLрізними засобами, але, мабуть, це обман, оскільки функція бібліотеки вирішує проблему. Ось низка рішень, які не використовують функцій бібліотеки, і роблять різні припущення щодо того, де операційна система готова дозволити вам виконувати невиконаний код. (Константи тут вибрані для x86_64, але ви можете змінити їх, щоб отримати робочі рішення для більшості інших процесорів, які мають незаконні інструкції.)

06це найменший байт машинного коду, який не відповідає визначеній інструкції на процесорі x86_64. Отже, все, що нам потрібно зробити, - це виконати. (Крім того, 2Fвін також не визначений і відповідає одному друкованому символу ASCII.) Жоден з них не гарантовано завжди бути невизначеним, але вони не визначені на сьогодні.

Перша програма тут виконується 2Fз сегмента даних, доступних лише для читання. Більшість лінкери не здатні виробляти робочий стрибок від .textдо .rodata(або еквівалент їх ОС) , оскільки це не те , що коли - небудь буде корисно в правильно сегментированной програмі; Я ще не знайшов операційну систему, на якій це працює. Ви також повинні мати на увазі те, що багато компіляторів хочуть, щоб розглянутий рядок був широким рядком, що вимагало б додатковоїL; Я припускаю, що будь-яка операційна система, над якою працює, має досить застаріле уявлення про речі, і, таким чином, будує стандарт за попереднім C94 за замовчуванням. Можливо, що ніде ця програма не працює, але також можливо, що десь ця програма працює, і тому я перераховую її у цій збірці більш сумнівних, менш менш сумнівних потенційних відповідей. (Після того як я опублікував цю відповідь, Денніс також згадав про можливість main[]={6}спілкування в чаті, що має однакову довжину, і який не стикається з проблемами з шириною символів, і навіть натякнув на потенціал main=6; моє, як я про них не думав.)

Друга програма тут виконується 06з сегмента даних для читання-запису. У більшості операційних систем це призведе до помилки сегментації, тому що сегменти даних, що записуються, вважаються поганим недоліком дизайну, що робить експлуатацію ймовірною. Це не завжди так, тому, ймовірно, це працює на досить старій версії Linux, але я не можу її легко перевірити.

Третя програма виконується 06зі стека. Знову ж таки, це спричиняє помилку сегментації в даний час, тому що стек, як правило, класифікується як ненаписаний з міркувань безпеки. Документація на лінкер, яку я бачив, вказує на те, що вона була легальною для виконання зі стека (на відміну від попередніх двох випадків, це робиться іноді корисно), тому хоча я не можу це перевірити, я впевнений, що є деякі версія Linux (і, мабуть, інших операційних систем), на якій це працює.

Нарешті, якщо ви дасте -Wl,-z,execstack(15 байт штрафу) до gcc(якщо ви використовуєте GNU ldяк частину бекенда), це явно вимкне захист виконуваного стека, що дозволить третій програмі працювати і подавати сигнал незаконної роботи, як очікувалося. Я вже випробувано і перевірено це 49-байтовий версія для роботи. (Денніс згадує в чаті, що цей варіант, мабуть, працює з цим main=6, що дасть оцінку 6 + 15. Я дуже здивований, що це працює, враховуючи, що 6 очевидно не знаходиться в стеці; варіант посилання, очевидно, робить більше, ніж його назва підказує.)


У x86-64 / linux з gcc6 в режимі за замовчуванням (поблажливіший) const main=6;працює, як і кілька варіацій. Цей линкер (я підозрюю , теж ваш компонувальник) є здатним генерувати стрибок від .textдо .rodata; проблема ви мали в тому , що, без const, ви стрибаєте в записуваний сегмент даних ( .data), який не є виконуваним на сучасному обладнанні. Він би працював на старих x86, де апаратне забезпечення захисту пам’яті не могло позначати сторінки як прочитані, але не виконуються.
zwol

Зауважте, що навіть у C89 mainобов'язкова функція (§5.1.2.2.1) - я не знаю, чому gcc вважає, що оголошення mainяк об'єкт даних заслуговує лише на попередження, і лише з -pedanticкомандного рядка. Хтось ще на початку 1990-х, можливо, думав, що ніхто цього не зробить випадково, але це не так, як це було корисно робити спеціально за винятком такої гри.
zwol

1
... Знову читаючи, вам здається, що ви очікували main[]="/"переходу до сегмента даних, доступних лише для читання, тому що рядкові літерали містяться в родатах. Вас виявила різниця між char *foo = "..."та char foo[] = "...". char *foo = "..."є синтаксичним цукром для const char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, тому рядковий літерал дійсно входить у родату, і fooє окремою глобальною змінною, що записується, що вказує на нього. Однак char foo[] = "...", зважаючи на те, весь масив переходить у сегмент даних, що записується.
zwol

19

GNU як (x86_64), 3 байти

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

$ ./сигілля

Illegal instruction

$ objdump -d sigill

sigill:     file format elf64-x86-64

Disassembly of section .text:

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

Має бути спосіб виразити, що у двобайтовому "джерелі" ...
OrangeDog

О, розумний. Мені було цікаво, чи існує спосіб побудови цього способу, який би поставив точку входу на початок файлу (без декларацій) і який не спричинив би штрафи за незвичну конфігурацію системи побудови. Я не зміг його знайти, але, схоже, ти.

@ ais523: так, мій звичайний NASM / YASM build-script ( asm-link) для однофайлових іграшкових програм створив би виконуваний файл з цього джерела так само, оскільки ldза замовчуванням вводиться точка вступу до початку текстового сегмента чи щось подібне. Я просто не думав перейти на розмір джерела ASM на цьому: P
Пітер Кордес

18

Bash на Raspbian на QEMU, 4 (1?) Байт

Не моя робота. Я просто повідомляю про роботу іншого. Я навіть не в змозі перевірити претензію. Оскільки ключовою частиною цього виклику, здається, є пошук середовища, де цей сигнал буде піднятий і зафіксований, я не включаю розмір QEMU, Raspbian або bash.

27 лютого 2013 р. 20:49, користувач emlhalac повідомив про " отримання незаконної інструкції" під час спроби хронізувати "на форумі Raspberry Pi.

ping

виробляючи

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

Я вважаю , набагато коротші команди будуть проводити цей висновок, наприклад, tr.

EDIT: На підставі коментаря @ fluffy , зменшена загальна нижня межа вхідної довжини до "1?".


5
Я думаю, [команда переможе. :)
пухнастий

17

X86 MS-DOS COM-файл, 2 байти

EDIT: Як вказувалося в коментарях, DOS сам не захопить виняток із процесора та просто зависне (не лише додаток, вся ОС). Запуск 32-бітної ОС на базі NT, таких як Windows XP, дійсно викликає незаконний сигнал інструкції.

0F 0B

З документації :

Створює недійсний код. Ця інструкція надається для тестування програмного забезпечення для явного генерування недійсного коду.

Що досить зрозуміло. Збережіть як .com-файл, і запустіть будь-який DOS-емулятор. DOS-емулятори просто вийдуть з ладу. Запускається в ОС Windows XP, Vista або 7 32-бітних.

SIGILL на Windows XP


1
Це технічно призводить до того, що процесор генерує незаконне виключення інструкцій. Однак у DOS є дуже обмежений захист пам’яті та можливості обробки винятків, і я не здивуюся, якщо це просто призведе до невизначеного поведінки / аварії ОС. ОП не сказала, що ядро ​​повинно було виявити помилку і надрукувати на консолі "Незаконні інструкції".
десерт

4
Я подумав про це рішення, але не вважаю, що воно справедливе. Питання вимагає незаконного сигналу інструкції , а не просто незаконної пастки процесора інструкцій , тому метою було знайти операційну систему, яка б насправді генерувала сигнал у відповідь на #UDпастку. (Крім того, я вирішив фактично протестувати його, і, здавалося, кинути мій DOS-емулятор у нескінченний цикл.)

2
Я перевірив це на фактичних MS-DOS на AMD K6-II. Запустивши його, просто висить система, як із запуском EMM386, так і без нього. (EMM386 вловлює деякі помилки та зупиняє систему повідомленням, тому варто перевірити, чи не змінило це значення.)
Марк

2
Так, вікна, що базуються на DOS, повинні мати можливість дійсно вловлювати пастку та принаймні вибивати додаток.
Асу

2
@Я можу підтвердити, що це працює на XP 32-розрядному і, ймовірно, працює на всіх інших 32-бітних системах Windows. Я погоджуюся, що це не є рішенням для самого DOS, оскільки воно просто виходить з ладу.
десерт

13

C (32-розрядна Windows), 34 байти

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

Це працює лише в тому випадку, якщо компіляція без оптимізації (в іншому випадку незаконне кодування fфункції "оптимізоване").

Розбирання mainфункції виглядає приблизно так:

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

Ми можемо бачити, що він використовує pushінструкцію з буквальним значенням 0b0f(малоекземляра, тому її байти підміняються). callІнструкція виштовхує адресаповернення (в ...інструкції), який знаходиться в стеку близько параметра функції. Використовуючи [-1]переміщення, функція переосмислює зворотну адресу, тому вона вказує на 9 байт раніше, де 0f 0bзнаходяться байти .

Ці байти викликають виключення "невизначеної інструкції", як було розроблено.


12

Java, 50 43 24 байти

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

Це java.util.function.Consumer<Runtime>1 , команда якого вкрадена з пухнастої відповіді . Це працює, тому що ви повинні називати це як whateverNameYouGiveIt.accept(Runtime.getRuntime())!

Зауважте, що це створить новий процес і змусить його кидати SIGILL, а не кидати сам SIGILL.

1 - Технічно це також може бути тим, java.util.function.Function<Runtime, Process>що Runtime#exec(String)повертає a, java.lang.Processякий може бути використаний для управління процесом, який ви тільки що створили, виконавши команду shell.


Для того, щоб зробити щось більш вражаюче на такій багатослівній мові, ось вам 72 60 48-байтний бонус:

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

Це ще одна, Consumer<Runtime>яка проходить через ВСІ процеси (включаючи себе), змушуючи кожен кинути СИГІЛЬ. Краще підтяжка для жорстокого краху.


І ще один бонус (a Consumer<ANYTHING_GOES>), який принаймні робить вигляд, що кидає SIGILL у 20 байтах:

a->System.exit(132);

8

Perl, 9 байт

kill+4,$$

Просто викликає відповідну функцію бібліотеки для передачі сигналу процесу і отримує програму для самої сигналізації SIGILL. Тут немає жодних фактичних незаконних інструкцій, але це дає відповідний результат. (Я думаю, що це робить виклик досить дешевим, але якщо щось дозволено, це саме лазівка, яку ви б використали ...)


Прийшов сюди, щоб розмістити те саме, з пробілом замість +. :)
simbabque

2
Коли люди вивчають Perl для програмування не для гольфу, вони навчаються його за допомогою +. Після деякого часу в гольфі вони +час від часу показуються. Врешті-решт, вони написали достатньо програм, де їм потрібно було уникати пробілів з тих чи інших причин, що +стає звичною. (Він також аналізує менш неоднозначно, тому що це працює навколо запуску спеціального випадку в аналізаторі дужок.)

8

Мова об'єднаного асемблера ARM (UAL), 3 байти

nop

Наприклад:

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

Після виконання nopпроцесор інтерпретує .ARM.attributesрозділ як код і десь там зустрічається з незаконною інструкцією:

$ 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

Випробуваний на Raspberry Pi 3.


Це так чи інакше не працює на Pi 2.
Mega Man

7

Microsoft C (Visual Studio 2005 р. Далі), 16 байт

main(){__ud2();}

Я не можу легко перевірити це, але згідно з документацією, він повинен створювати незаконну інструкцію, навмисно намагаючись виконати інструкцію, призначену лише для ядра, від програми, призначеної для користувача. (Зауважте, що через те, що незаконна інструкція руйнує програму, нам не доведеться намагатися повернутися з mainцього приводу, це означає, що ця mainфункція стилю K&R є дійсною. Visual Studio, що ніколи не переходив з C89, як правило, погана річ, але вона прийшла в корисно тут.)


Чи можете ви компілювати для Linux з VS2015? Тому що я не думаю, що SIGILL визначено в Windows, чи не так?
Андрій Савіних

7

Рубін, 13 байт

`kill -4 #$$`

Я думаю, що можна припустити, що ми виконуємо це з оболонки * nix. Літерали backtick виконують задану команду shell. $$є запущеним процесом Ruby, а #для рядкової інтерполяції.


Без виклику оболонки безпосередньо:

Рубін, 17 байт

Process.kill 4,$$

6

Будь-яка оболонка (sh, bash, csh тощо), будь-яка POSIX (10 байт)

Тривіальна відповідь, але я не бачив, щоб хтось її розміщував.

kill -4 $$

Просто надсилає SIGILL до поточного процесу. Приклад виводу на OSX:

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

Ви можете зробити, kill -4 1якщо питання не конкретно про те, яка програма кидає SIGILL
Mark K Cowan

@MarkKCowan Хе, добре, хоча це передбачає корінь ...
пухнастий

2
You will have root in your programs- збийте байт зі своєї відповіді і одночасно трошки запитайте питання: D. БОНУС: Ви повинні вбитиinit
Марк К Коуан

2
@MarkKCowan: Увімкнений (сучасні версії?) Linux initнасправді не захищений від сигналів, які він спеціально не просив отримувати, навіть із root. Можливо, ви могли б обійти це за допомогою іншої ОС POSIX.

2
kill -4 2потім: D
Марк К Коуан

6

ELF + x86 код машини, 45 байт

Це має бути найменша виконана програма на машині Unix, яка викидає SIGILL (через те, що Linux не розпізнає виконуваний файл, якщо його менше).

Компілюйте з nasm -f bin -o a.out tiny_sigill.asmтестуванням на віртуальній машині x64.

Фактично 45 байт двійкового:

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

Список складання (див. Джерело нижче):

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

Відмова від відповідальності: код з наступного підручника щодо написання найменшої програми складання для повернення номера, але за допомогою opcode ud2 замість mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html


2
Я збирався опублікувати модифікований виконуваний файл саме цього підручника, але ти мене перебив. Це заслуговує на перемогу; Це справжній мінімалізм у сенсі системних ресурсів (для нього потрібно не більше 45 байтів як у файлі, так і в пам'яті, і однаково в обох), і немає роздутого інтерпретатора, як інші рішення асемблера. Це просто те, що воно є.
Iwillnotexist Idonotexist

5

AutoIt , 93 байти

Використання вбудованої збірки flatassembler:

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

Під час запуску в інтерактивному режимі SciTE він негайно вийде з ладу. Налагоджувач Windows повинен спливати на частку секунди. Вихід консолі буде приблизно таким:

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

Де -1073741795не визначений код помилки, кинутий WinAPI. Це може бути будь-яке від’ємне число.

Аналогічно за допомогою мого власного асемблера LASM :

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

5

NASM, 25 байт

Я не знаю, як це працює, тільки що це робиться на моєму комп'ютері (Linux x86_64).

global start
start:
jmp 0

Складіть і запустіть так:

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

Ви, ймовірно, можете скоротити його до чотирьох байт, якja 0
Марк К Коуан

1
або три якud2
Марк К Коуан

1
Можливо, тому, що він намагається перейти до якихось даних?
Асу

5

TI-83 Шестигранна збірка, 2 байти

PROGRAM:I
:AsmPrgmED77

Виконати як Asm(prgmI). Виконує незаконний код 0xed77. Я рахую кожну пару шістнадцяткових цифр як один байт.



3

x86 .COM, 1 байт

c

ARPLвикликає #UDв 16-бітному режимі



1

GNU C, 24 19 18 байт

-4 завдяки Деннісу
-1 завдяки стельовій кішці

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

Спробуйте в Інтернеті! Це передбачає ASCII та x86_64. Він намагається запустити машинний код 27, який ... є незаконним.


shortC , 10 5 4 байти

AV"'

Еквівалентний коду GNU C вище. Спробуйте в Інтернеті!


L"\6"Також є незаконним, якщо припустити x86_64.
Денніс

@Dennis Яка інструкція 0x06? Також Lне потрібно.
MD XF

Це не призначено.
Денніс

Це не призначено; ось що робить це незаконним. Також, 'це 39 = 0x27 , а не 0x39 .
Денніс

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.