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 явно не в стеке; опция ссылки, очевидно, делает больше, чем его название подсказывает.)
raise(SIGILL)
?