Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Игры OverTheWire

Когда учился в универе, CTF был не очень популярен и прошел мимо меня. Игры OverTheWire как раз в таком формате: чтобы пройти на следующий уровень надо найти спрятанный флаг (пароль), выполняя задания.

Минимальную базу по Linux можно получить, пройдя Bandit. Даже с учетом того, что я все там знаю, все равно было занятно.

Азы по web-безопасности покроет Natas, а по шифрованию — Krypton. Остальные — про реверс-инженеринг.

Ссылка • Комментировать

Культуры зависимостей

Неплохой доклад с тезисом, что различные подходы к управлению зависимостями в индустрии — это культурный вопрос, а не технический. Начинается, разумеется, с веба, а другим примером служат игры. Жирные зависимости — плохо (потому что большая часть вам не нужна), мелкие — тоже (left-pad). Не забыт и вопрос обновления — и часто плохо, и редко плохо (но это решаемо). Короче, перед добавлением зависимости надо думать, шансы прикидывать.

Ссылка • Комментировать

Сравнение Proguard и R8

ProGuard — это обфускатор и минификатор для java, а R8 — тоже минификатор для java и де-факто стандарт для Android. У последнего сложилась репутация как более мощной замены для ProGuard, некоторые не-Android проекты даже рассматривают замену ProGuard на R8 (например, Kotlin), благо формат настроек у них почти совпадает. У меня раньше в голове был образ, что R8 — это то же самое, что и ProGuard, только новее и лучше. Реальность полна разочарований, как говорится:)

Я буду рассматривать только вопрос минификации (обфусцировать java — очень странная идея), и стоит обговориться, что область ее применения очень ограничена — на серверах места полно, а на пользовательские системы java сейчас редко доставляют (Gradle тут скорее исключение).

Вот что я обнаружил, когда попробовал заменить кастомную минификацию в Gradle сначала на R8, а потом на ProGuard:

  1. Вывод R8 зависит от версии JVM, а ProGuard для работы нужна JVM с jmods, которые могут быть не включены в JDK.
  2. R8 не позволяет ничего настроить относительно ресурсов и, как следствие, мультирелизных jar, манифестов, неактуальных контрольных сумм и т.п.
  3. R8 нельзя заставить удалить класс или метод, если на него есть ссылки (даже если знаете, что это логически мертвый код).
  4. R8 переписывает метаданные Kotlin и ломается, если ваш Kotlin новее.
  5. R8 переписывает методы, и, с одной стороны, код получается меньше, но может из-за этого сломаться на новейших JVM/Kotlin с чем-то вроде java.lang.VerifyError: Bad invokespecial instruction: interface method reference is in an indirect superinterface.

При этом R8:

  1. Сжимает лучше, потому что работает на уровне методов, а ProGuard — на уровне классов. Т.е. ProGuard может оставить класс с 1 живым методом и сотней неиспользуемых.
  2. Требует меньше настроек “корневых” классов.
  3. Не такой строгий — если не видны какие-нибудь родительские классы, то предполагает, что они есть.
  4. Поддерживает Kotlin.
  5. Не имеет зависимостей — это один jar.

Мой сценарий довольно особенный и ProGuard оказался лучше, но для Android описанные минусы R8 слабо релевантны, так что для него он будет лучше.

Ссылка • Комментировать

ИИ-переписывание Bun

Многие наверняка слышали историю про то, что bun переписали с Zig на Rust с помощью тучи ИИ-агентов: впечатляющие графики, “новый уровень ИИ-инженеринга”, blazing fast™, убедительные результаты и т.п. Спонсирует все это Антропик, который купил bun в декабре. Эксперимент успешный, переписанный bun уже внутри Claude Code, аж с июня. А еще автор Bun на досуге запромптил Claude, чтобы сделать прорыв по гипотезе Римана. Короче, гений, миллионер, еще и плейбой наверняка.

Мало кто видел ответ создателя Zig на эту статью: “вы не разобрались”, проблема не в Zig и не в языках, потому что вопросики к автору bun были и до этой эпопеи.

А тем временем с момента статьи прошло больше месяца. Автор в режиме “ща, ща” все никак не зарелизит лучшую версию 1.4.0. На гитхабе при этом почти 5 тысяч открытых PR, большинство от агентов.

Выводы делайте сами, как говорится.

UPD: таки зарелизили.

Ссылка • Комментировать

Zero-defects code

Капсула времени: служебка Microsoft аж из 1989 года про нулевую терпимость к багам. Кажется, она не очень помогла, но вещи написаны хорошие, которые по большей части актуальны до сих пор.

Даже если идеал кода без багов недостижим, все равно надо к нему стремиться. Если думать, что баги неизбежны, то не будут стараться их предотвратить; будет фокус на количестве фич и скорости — будет соответствующее качество; надо править корень проблемы, а не симптомы и бороться со сложностью и т.п.. Увы, пока никто не придумал, как убедить руководителей в пользе долговременного планирования после того как прошел этап MVP, и как бороться с тем, что награждают не за качество работы.

Ссылка • Комментировать

Семантический diff

Из-за того, что в последнее время стало кратно больше код-ревью (потому что нейронку надо худо-бедно контролировать), многие начали присматриваться к “семантическим” инструментам для отображения изменений в коде, хотя они давно известны: Difftastic, sem, diffsitter, SemanticDiff и т.п.

Не могу сказать, что какой-то из инструментов произвел на меня вау-эффект: да, вроде получше, но не настолько, чтобы пересилить неудобства. Я честно пытался, но пользоваться ими на постоянной основе у меня не получилось: это все консольные инструменты, а мне окошки подавай с графической IDE. Да, вроде есть какая-то интеграция с VS Code у некоторых, но на спектре IDE-шности у меня он все еще ближе к текстовому редактору лежит.

В IntelliJ можно настроить внешний инструмент для разницы, но это по сути ярлык для вызова терминала (да и то без приседаний не обойтись). А еще у них есть тикет, чтобы сделать “нормально”, которому аж 21 год (sic!).

В итоге я, прости господи, навайбкодил плагин для IntelliJ, чтобы интегрировать консольные инструменты в окошко сравнения. Получилось не очень: сами модели в IntelliJ довольно ограничены и с помощью них все выразить не получается. Но все-таки, чуть-чуть лучше встроенного diff в некоторых сценариях.

Ссылка • Комментировать

50 оттенков Brainfuck

Brainfuck, хоть и весьма минималистичный (8 односимвольных команд), изначально задумывался как язык, для которого можно сделать минимальный компилятор (уже вторая версия была 240 байт, а на современном железе можно уложиться в 100).

Если же минимизировать количество команд — то легко уложиться в 2 простые команды (можете поиграться тут), или в одну посложнее.

А если минимизировать количество различных символов? Если отбросить эзотерику, одним из первых тут стал JSFuck, который выразил весь JS через 6 символов: +!()[]. А потом код-гольфисты продолжили:

  • JS дожали до 5 символов — []+=`. Как и в JSFuck — приколы типизации.
  • Ожидаемо нашлись варианты для Python (exc="%\n) и Perl (<>^es), но там скучный exec/eval.
  • Внезапно для Haskell надо всего 4 символа — ()=;, разумеется, не обошлось без λ-исчисления, точнее, SKI.
  • Для Си есть решение за 5 символов — +1;=$, в котором напрямую прописываются машинные коды.
  • В java унылые 02367?\abcdeitu, по сути просто обычный исходник, написанный через юникод-последовательности \u0a23, с гимнастикой для снижения количества нужных цифр.
  • В bash — аналогичный подход с 01456\$ ', zsh чуть интереснее с $#< (){}.
  • В PHP — 5 символов, (^.9), подходы похожи с JS: делаем числа, из них буквы, потом имена функций и т.д..

Если вернуться к эзотерике, то стоит упомянуть Whitespace, где нужны только \t \n. Но победителем будет бесспорно Unary с прикольной идеей: берем код на Brainfuck, преобразуем его (биективно) в число, пишем соответствующее количество нулей (или любых других символов), и программа готова.

Ссылка • Комментировать

Наглядный пример, почему важны хорошие генераторы случайных чисел и QA

Неплохой разбор вскрывшейся недавно уязвимости биткоин-кошелька Coldcard. Вкратце: из-за кривой сборки (в этой статье чуть подробнее расписано) вместо нормального генератора случайных чисел с физическим источником энтропии использовался программный, с гораздо меньшей энтропией. Как следствие, стало легко подобрать приватный ключ. В итоге украдено более 1500 BTC ($100 млн.+) с 7300+ адресов.

Ссылка • Комментировать

Время рефакторить

Мне всегда нравилось рефакторить — медленный дофамин, быстрая обратная связь, чувство достижения, автономность, можно разгрузиться от более вдумчивой работы и т.д. Однако обычно более-менее крупный рефакторинг занимает приличное время.

Сейчас, как мне кажется, сложились обстоятельства, благоприятствующие большим рефакторингам. Обычно рефакторинг довольно однообразный и рутинный в плане действий и редко влечет за собой подводные камни. Это хороший кандидат для одноразового скрипта, но если раньше такое было писать нецелесообразно (ну разве что состряпать что-то на коленке а-ля регулярку в IDE), то сейчас нейронка выплюнет его за пару секунд, и можно быстро проитерироваться. Кроме того, нейронки позволяют попробовать несколько вариантов (даже если это сотни измененных файлов) и выбрать подходящий. Как и раньше, уверенности добавят компилятор, статические проверки и тесты (и если их нет, то стоит позаботиться сначала о них). Вдобавок, все можно сделать автономно, пока ждешь код-ревью других своих PR в переполненной очереди.

Сам недавно сделал несколько рефакторингов: миграция с одной библиотеки на другую, аннотации публичного API, разбиение по модулям, удаление мертвого кода и т.п.

Ссылка • Комментировать