Опубликованы исходные тексты работ, победивших в двадцать восьмом конкурсе IOCCC (International Obfuscated C Code Contest), участникам которого предлагалось подготовить наиболее запутанный и трудноразбираемый код на языке Си. 28 конкурс проведён после четырёхлетнего перерыва и примечателен разрешением использовать кодировку UTF-8 в коде...Подробнее: https://www.opennet.dev/opennews/art.shtml?num=63668
Волчок прекрасен!
а ты пробовал компилить?
Аплодисменты участникам. Каждый раз удивляют победители.
Тут кстати документалка, как авторы готовили свои проекты:
https://www.youtube.com/watch?v=dQw4w9WgXcQ
Хорошая документалка, обожаю такие, всем рекомендую к просмотру!
Измудренного.
Ну такого, ну заковыристого.
Создавать эффективные приложения с небольшим количеством кода — вот причина, по которой я обожаю язык Си.
Поддержка кода и исправление бегов в понятие "эффективные приложения" входит))?
Или как наовнякали, так пусть работает.
Ну пока за пределы буфера не выйдет.
> Поддержка кода и исправление бегов в понятие "эффективные приложения" входит))?Нет, конечно. Туда не входит даже проверки данных/параметров на корректность, ибо эффективность сразу улетучивается.
А зачем все это нужно, если у сишочника в случае чего есть универсальная отмаза "и чо, я этот хэллоуворлд писал в одно лицо для самого себя, и в моем конкретном случае все работает111"? (Если что, это был реальный аргумент от одного местного эксперта).
> Нет, конечно. Туда не входит даже проверки данных/параметров на корректность, ибо эффективность сразу улетучиваетсяВ своем последнем проекте я тоже пришел к данному решению. Проверка производится до вызова функций, реализующих алгоритм. Функции считают, что входные данные и параметры абсолютно корректны.
Если Вы посмотрите на реализации математических алгоритмов во многих математических библиотеках, там это не так. И это действительно снижает эффективность, увеличивает объем кода и дополнительно грузит программиста, отвлекая от реализации алгоритмов.
> снижает эффективностьЕсли предположить, что наша функция всегда будет складывать 2+2, как по вашему должна выглядеть эффективная функция (алгоритм) сложения - всегда возвращающая 4 (return 4;)? И эту фукцию разве корректно формально называть "эффективной функцией сложения двух чисел"?
int getRandomNumber() {
return 4; // chosen by fair dice roll
//guaranteed to be random
}
ну мы же рассуждаем про "эффективность" в контексте "избавлений от проверок на допустимые значения ВХОДНЫХ параметров", а в вашем "классическом" примере нет входных параметров.
Проверка параметров это дикие тормоза, совершенно бесполезные, не решающие никаких задач, просто изгадить код. Такое проходит только в корпоративном гвнокоде, где на производительность плевать "докупят еще серверов", но для программ пользователя такое свинство недопустимо.
Корректность важнее производительности: в чём смысл кода, если он выполняет не то, что тебе нужно?
Решение задачи "допускать к дальнейшей обработке только данные, удовлетворяющие бизнес-инварианту" не считается?
Есть функции, внутренние, где проверки излишни. Потому что у этих самых функций есть своя функциональность и предсказуемое поведение, при предсказуемых и заранее определенных вводных данных.
Проверки нужно выполнять только во внешних функциях, которые взаимодействуют с внешним миром. Обмазывать абсолютно все функции в коде проверками это моветон и признак плохого программирования.
> Есть функции, внутренние, где проверки излишни. Потому что у этих самых функций
> есть своя функциональность и предсказуемое поведение, при предсказуемых и заранее определенных
> вводных данных.А потом их кто-то внутри вызывает с иными входными данными и... отстреливает себе ногу.
И заодно своим пользователям.> Обмазывать абсолютно все функции в коде проверками это моветон и признак плохого программирования.
Обмазывать их приходится только в недоязыках. Где напр. нужно или в каждом вызове нужно проверять на null, или получать дыру.
В нормальных языках это решается в системой типов, которые не дают передать невалидные данные.
> А потом их кто-то внутри вызывает с иными входными данными и... отстреливает себе ногу.для этого существуют тесты и дебагверсия.
> с небольшим количеством кодЛол, а как только у нас что-то больше хэллоуврлда, то внезапно появляются самописные строки, контейнеры и всякая банальшина типа split_string() (естественно, без тестов и проверок).
Вам показывают проекты из серии "Программисты шутят", а Вы относитесь к ним слишком серьезно. Реальные проекты на C выглядят иначе.
> Вам показывают проекты из серии "Программисты шутят",Ты хотел сказть маются уетой?
> а Вы относитесь к ним слишком серьезно.
Эх(((, к вам когда-то на собеседование приходили всякие олимпиадники?
> Реальные проекты на C выглядят иначе.
Теорема г-на Эскобара говорит противоположное))
Думаете такой фигни в проде не будет?
Типа неявных манипуляций юникодом или "код с огромным числом операторов goto"?
о чем вы? ассемблер не пробовали? там ваша эффективность будет еще выше.
Я пробовал. Действительно выше.
> Создавать эффективные приложения с небольшим количеством кода — вот причина, по которой я обожаю язык Си.Но именно этого он и не умеет от слова совсем. Стандартная библиотека настолько никакая что там нет даже строк, не говоря даже о хэшмапах. А язык настолько никакой, что половину кода будет занимать бойлерплейт для обработки ошибок и освобождения памяти.
Всем ставить, HaikuOs.
Зачем возобновили этот ужас?
Как показывает опыт перла, такие конкурсы предвестники забвения.
Уу. 41 год забывают, забывают и никак не могут забыть. Конкурс проводится с 1984 года. Большинство комментаторов ОпенНета еще не родились, когда конкурс проводился в первый раз. И похоже, что все отметившиеся на сегодня здесь, не доживут до того момента, когда конкурс будут проводить в последний раз.
> Конкурс проводится с 1984 года.В США чемпионат по метанию лепешек навоза проводится с 1970х (В РФ с 2010го вроде бы).
А соревнование по броскам йоркширским пудингом было еще в 1839 году, правда с перерывами.
И скорее всего переживет всех отметившихся сегодня.Польза от сего конкурса примерно такая же как от вышеперечисленных.
Хотя... возможно метание навозом даже полезнее.
Грэйдон Хор тоже участвовал в конкурсе необычных и бесполезных вещей в IT. Победил. Теперь его проект некоторые люди считают панацеей от кривых рук в программировании.
> Теперь его проект некоторые люди считают панацеей от кривых рук в программировании.Проблема в том, что еще не родился сишник с прямыми руками.
Доказано 40+ годами написания сишных дыреней.
Ну-да, ну-да.
В "безопасных" языках такие перлы учудили, что умудрились сделать дыры там, где в сишных аналогичных проектах их не было. Например CVE-2023-42456 и CVE-2025-46718. Там еще и десяток других ошибок обработки строк и переменных окружения есть, позволяющее обойти ограничения /etc/sudoers, которых нет в оригинале. Три ошибки просто нельзя исправить из-за особенностей языка.
Ой! Это же кривые руки разработчика! Но в безопасном языке - это норма и не является проблемой языка, а в "небезопасном" - это проблема языка.
А ничего что это логические ошибки? И еще не придумано способа избегать логических ошибок, кроме формальной верификации. Как только придумают, я буду первым кто будет топить за закапывания раста.Зато в дыpяшке можно нажать 28 раз Back Space и обойти ввод пароля (opennet.ru/opennews/art.shtml?num=43536) Какой еще йазыг позволяет такой проделать!
Раз ты вспомнил sudo - вот логические CVE-2021-23240, CVE-2019-19234.
Но в комплекте идут CVE-2021-23239 с race condition, CVE-2021-3156 с buffer overflow и прочие типикАл сишные баги.
> А ничего что это логические ошибки?А ничего, что при работе с памятью тоже логические ошибки?
Для C и C++ есть требования как работать с памятью. И требования эти есть с с 1978 года. И есть лица, которые нарушают стандарты работы с языком. То есть это логическая ошибка.> И еще не придумано способа избегать логических ошибок, кроме формальной верификации
Давай тогда орать, что раст дырявый язык только потому, что и в нем при делении требуется верификация делителя на то, чтобы он был не нулем!
> вот логические
Ну то есть, для тебя логические только там, где тебе удобно, а там, где не удобно - это дырявость языка.
> с buffer overflow и прочие типикАл сишные баги.
Про которые еще 50 лет назад говорилось, как их не допускать.
Я еще раз спрашиваю: Почему отсутствие проверки деления на ноль в Rust - это логическая ошибка, а отсутствие проверки границ буфера - это ошибка языка?
Ничего, что с помощью таких фич можно делать успешные атаки на систему?И да. Почему программа C при краше после вызова деления на ноль за собой чистить в ОЗУ, а в Rust не чистит? И не надо говорить, что libstdc так делает.
> А ничего, что при работе с памятью тоже логические ошибки?Нет, это особое подмножество ошибок. Которые по какой-то "странной случайности" характерны именно для сишки. И которые продолжают делать с завидной регулярностью.
Раст позволяет избавиться от этого большого подмножества. Сишка - нет.> И требования эти есть с с 1978 года.
Да ну)) Они обязательны к исполнению? Что, неужели нет??? Вот как бы и все.
Для надежности сделали misra c. Который кacтpиpовали настолько, что там даже динамического выделения памяти нет. Потому что проще запретить, чем чтобы сишники не накосячили.
> И есть лица, которые нарушают стандарты работы с языком.
И эти лица - 99.9%+ сишников :)
> отсутствие проверки деления
выполнит произвольный код?
Или софтина гарантировано упадет с паникой (и заодно запишет в какой строке это произошло)?
Более того, в расте при попытке писать за границы массива тоже будет паника.
А в сишечке... а что угодно может быть. Начиная от порчи данных до дарения рута.> Ничего, что с помощью таких фич можно делать успешные атаки на систему
Ну так мы регулярно наблюдаем успешные атаки с переполнением буфера в сишечке.
К чему вы это пишете?
> Нет, это особое подмножество ошибок. Которые по какой-то "странной случайности" характерныДля кого характерны? Для васянов, которые языки программирования изучают по комиксам и по видосикам от таких же васянов?
Открываешь любой учебник MIT, Berkly, Бауменки и там черным по белому написано, что программист обязан делать.> Раст позволяет избавиться от этого большого подмножества. Сишка - нет.
От тупости он не позволяет избавиться.
> Да ну)) Они обязательны к исполнению? Что, неужели нет??? Вот как бы
> и все.Не сидеть в графике под рутом в никсах и не сидеть под учеткой с правами админа в винде тоже не обязательно к исполнению.
Не вытаскивать при включенном ПК планки ОЗУ тоже не обязательны к исполнению.> Потому что проще запретить, чем чтобы сишники не
> накосячили.
>> И есть лица, которые нарушают стандарты работы с языком.
> И эти лица - 99.9%+ сишников :)И 100% писунов на раст. Как мне понравилась фича sudo-rs, позволяющая без прав в sudoers замочить систему через выполнение
env <перезадание переменных окружения> sudo ...
в переменных задать "/" "-fr" "rm" "/bin/exec". (Бага выложена в телеграм канале Kali)
А все потому, что, если инструмент позволяет не думать, что делаешь, ты на 100% сделаешь фигню.> выполнит произвольный код?
> Или софтина гарантировано упадет с паникой (и заодно запишет в какой строке
> это произошло)?Софтина выпадет в осадок, оставив страницы памяти не очищенными с сохраненной таблицей выделенной под переменные памяти. Читай, любой, кто хочет.
> Более того, в расте при попытке писать за границы массива тоже будет
> паника.Угу. Но память не очищается.
> А в сишечке... а что угодно может быть. Начиная от порчи данных
> до дарения рута.А в расте дарится все содержимое памяти. А так как разработчик не имеет привычки подчищать память с конфиденциальными данными, то можно выдернуть любые данные, например введенные пароли.
> Ну так мы регулярно наблюдаем успешные атаки с переполнением буфера в сишечке.
А так мы уже наблюдаем атаки через кривой код на расте там, где в сишечных аналогах не было дыр.
> К чему вы это пишете?К тому, что если не думать, что делаешь, то никакой умный язык программирования вам не поможет.
> Давай тогда орать, что раст дырявый язык только потому, что и в нем при делении требуется верификация делителя на то, чтобы он был не нулем!Не требуется, компилятор Rust сам вставит проверку. Если поделить на ноль, то будет паника в рантайме и stack unwinding (а не SIGFPE).
> Я еще раз спрашиваю: Почему отсутствие проверки деления на ноль в Rust - это логическая ошибка, а отсутствие проверки границ буфера - это ошибка языка?
В Rust по умолчанию есть и проверка границ, и проверка деления на ноль. Если они не нужны, есть unsafe методы без проверок.
И, кстати, при делении знаковых чисел проверки на ноль недостаточно, при делении INT_MIN на -1 происходит знаковое переполнение, и результат будет INT_MIN.
В Rust будет паника, а си-писака добавит в программу баг, который будет спать и ждать своего часа Х.> Ничего, что с помощью таких фич можно делать успешные атаки на систему?
Нельзя. Паника это не порча памяти, её можно перехватить и обработать, в худшем случае это контролируемое завершение программы.
В очередной раз сишник хотел сумничать, но вместо этого громко газифицировал лужу.
> и проверка деления на ноль.Тогда почему есть метод атаки на сервисы написанные на Rust через передача данных, в который произойдет деление на ноль?
> а си-писака добавит в программу баг, который будет спать и ждать своего часа Х.
Перестань пользоваться компилятором MSVSС. ANSI C не позволяет выполнять операции за границами числовых переменных.
Помнится в 2023 году в расте можно было сложить две переменные integer на 32-хбитной системе со значением -2147483648, чтобы сломать всю программу.
> паника в рантайме
> в худшем случае это контролируемое завершение программы.Так это и есть - завершение приложения без отчистки памяти при нормальной настройки системы.
И да. Раст не умеет проверять значения в математических функциях при делении.
А ведь конкурсы, еще на сайте Alt Linux есть, тусовка.
> Виртуальная машина, способная запускать Doom 1/2 на современным ПК.
> Код 40 строк.Там 40 строк только если все писать в одну строку с ограничением на 80 символов в строек.
Если отформатировать нормально - то получает раза в 2.5 больше, смотря какой стиль скобок выбрать. Плюс все обмазано дефайнами, а если оформить нормально, то в итоге получается обычная сишная дрисня.
> 40 строк...и тонна байткода
Беллард хоть что-нибудь взял?
Если зайти по ссылке: https://www.ioccc.org/2024/kurdyukov3/ogvm.html
Написать в текстовом поле: doomp.bin
Нажать кнопку Start, то запустится Doom прямо в браузере.Автор также бонусом добавил нативную JIT (быстрый JIT без оптимизаций) версию с поддержкой архитектур x86, x86_64, aarch64 и e2k.
Web версия тоже содержит JIT, только на JS, JS позволяет генерить и выполнять JS код во время выполнения.
> Утилита для удаления артефактов из JPEG-изображений
Это урезанная обфусцированная копия утилиты JPEG Quant Smooth (есть в некоторых дистрибутивах линукс как jpegqs).
> На первый взгляд программа возводит в квадрат числа от 1 до 10, но на деле показывается рецепт приготовления жареного лосося. Код 15 строк и содержит манипуляции с незаметными символами Unicode.Объясните. Никакого рецепта по ссылке не вижу. Компилировал, выводит квадраты чисел.
Как компилировал?
Качай 2024_cable2.tar.bz2 и запускайgcc prog.c
./a.outSeason salmon fillets with olive oil, lemon juice, garlic, salt, and pepper, then grill over medium heat for 4-6 minutes per side until flaky and cooked through.
$ cat prog.c
#include <stdio.h>unsigned int *salmon = U" is very yummy";
#define grill ;while(putchar(*salmon++))
#undef grill#define grill
#undef grillint main() {
for (int i = 1; i <= 10; i++) {
printf("%d * %d = %d\n", i, i, i*i);
}
}$ cat -A prog.c
#include <stdio.h>$
$
unsigned int *salmon = U"M-sM- M-^A......^@M-^@is very yummy";$
$
#define grillM-sM- M-^AM-^A ;while(putchar(*salmon++))$
#undef grill$
$
#define M-sM- M-^AM-^A grillM-sM- M-^AM-^A$
#undef grill$
$
int main() {M-sM- M-^AM-^A M-sM- M-^AM-^A$
for (int i = 1; i <= 10; i++) {$
printf("%d * %d = %d\n", i, i, i*i);$
}$
}$
Так Си и так запутанный! Сколько новостей было что люди не справляются с буфером.
Те, кто справились, перебежали в растоманы.
я боролся с багами в С++. оказалось что я забываю ставить звездочку или амперсанд.
о, в победителях числится автор fpdoom
Конкурсная работа с запуском Doom была написана в сентябре 2020-го, и потом опыт её создания помог в портировании Doom на телефон. Можно заметить, что у патча для ванильного Doom из конкурса и патча к Doom для FPDoom есть много общего.
А как же, Duke Nukem.
вот вы бухтите о проблемах с памятью в Си, а иногда это не баг, а фича!https://serverfault.com/questions/86968/dnsmasq-how-to-incre...
> You can actually bypass the 3600 second --min-cache-ttl check by exploiting an integer overflow bug in the dnsmasq C source code, without any need for recompiling. Here is a value which works:
>
> Via CLI: --min-cache-ttl=6442450943
>
> Via dnsmasq.conf: min-cache-ttl=6442450943
я так раньше routing cache в древних linux отключал
Конечно не баг, а фича.
И тормозящщие приложения не Баг, а фича.
Это такой вайб.
Они бы лучше устраивали конкурс по максимальному количеству уязвимостей.
Некоторые работы странные: требуют тонны бинарей байткодов, подготовленных другими самописными утилитами. Так можно что угодно сложное сделать...
>Размер исходного кода программы не должен превышать 4096 байтТы о чём?
Горжусь за чисто-сишников, за чувство юмора и развитое воображение!
В конкурсе по написанию понятного кода на языке Си победить никто не смог…
А ха-ха-ха ха!
Ну хотя бы, Hello World, то умеют.
Так это не запутанный код, а просто обфускация...
что такое обфускация?
Вообще конечно каждый раз восхищаюсь победителями, только Си способен такие талантливые вещи проворачивать. Востину язык для хакинга.
На Perl посмотри
Такие вещи, которые делаются в конкурсе IOCCC, нигде не делаются.
Ещё раз, какие вещи? Все победители абсолютно тривиальны. В нулевых были интересные работы, а сейчас одна банальщина.
Талантливое здесь... что именно? Обзывать переменные одной буквой и склеивать код в одну строку можно на любом ЯП, даже питоне. Писать короткие программы тоже, причём на других ЯП это сильно проще, потому что у них в стандартной библиотеке есть хоть что-то.
Кроме лосося, слабо, просто очень слабо. Берём произвольный ничем не выдающийся код, обфусцируем стандартным образом (по сути однобуквенные названия переменных), форматируем в виде изображения стандартным образом. Всё.
> слабо, просто очень слабоСлабо выписать опкоды виртуалки для дума?
> Помощник в решении головоломки Wordle, в которой нужно угадать пятибуквенное слово за шесть попыток (код).С помощью ИИ транслировал код на Nim: sharetext.io/04773086
Самое сложное в программировании - писать простой, понятный и достаточно оптимальный код. На любом языке.
Это очень сложно. Поэтому те, кто это "неасилил", придумываеет подобные конкурсы и учавствует в них.
Хотел сказать "Да не, не сложно", но вспомнил, что прошло уже 20 лет. :-|