Обновить
32K+

Assembler *

Язык программирования низкого уровня

41,33
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Как я перестал бояться и полюбил ассемблер

Уровень сложностиПростой
Время на прочтение14 мин
Охват и читатели24K

Эта статья посвящена путешествию в мир ретропрограммирования. Надеюсь, в ней у меня получится передать вам то чувство восхищения, которое я испытал и которое заставило меня написать этот пост. Пост о том, как создавать ПО для компьютерной системы Atari ST, выпущенной в 1985 году.

Atari ST относится ко второй крупной волне домашних компьютеров. Первая волна, созданная на основе 8-битных CPU, принесла в наши дома такие знаковые машины, как Commodore C64 и Sinclair Spectrum. Вторую волну разрабатывали на основе 16-битных CPU; она породила Apple Macintosh, Commodore Amiga и, разумеется, Atari ST.

Atari ST 1040 STF с цветным монитором Atari SC1224

Типичный Atari ST (например, 1040 STFM) имел CPU Motorola 68000 с тактовой частотой 8 МГц и 1 МБ ОЗУ; он загружал ПО с 3,5-дюймовых гибких дисков. Его графические возможности состояли из монохромного режима высокого разрешения 640x400 и 16-цветного режима 320x200, получившего наибольшую популярность в играх.

Рабочий стол GEM Atari ST имел интерфейс, очень похожий на разработанный Xerox и Apple, у него были диспетчер файлов, иконки и многооконность. Это его монохромная версия высокого разрешения.

Если у вас нет реального Atari ST, то его можно просто эмулировать на современном компьютере. Первые эмуляторы появились ещё в 90-х. Хорошим считается Hatari, который существует для большинства современных платформ. В эмуляторе также есть современные инструменты разработки. В прошлом приходилось пользоваться неуклюжим ПО разработки, которое загружалось с дискет, а сегодня можно просто писать всё в VSCode и компилировать современным GCC. У нас есть доступ к современным графическим редакторам наподобие GIMP, и мы даже можем просить помощи у ИИ.

Читать далее

В заголовке моего ELF есть точка входа. Оказалось, её никто не читает

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели8.8K

Три статьи я собирал файл и отдавал его эмулятору, ни разу в него не заглянув. Заглянул. Внутри два разных описания одних и тех же байтов, ответ на вопрос, откуда взялся адрес 0x80000000, и поле, которое я заполнял зря.

Ну, открываем!

«Bro, what…?» #1. Первый контакт с crackme на Linux x86-64

Уровень сложностиСредний
Время на прочтение54 мин
Охват и читатели8.2K

Вы запускаете программу, о которой ничего не знаете. Она вежливо просит строку, а в ответ на ваш ввод насмешливо отвечает: «Bro, what are you trying to do?» И правда, что мы пытаемся сделать? Пытаемся понять ее.

Перед нами crackme – программа-головоломка, написанная для тренировки навыков обратной разработки: бинарник под Linux x86-64 без исходников и документации, который издевается над каждым, кто не смог его разгадать. Это первая статья цикла из трех о гибридном анализе крякми Getting Started Keygen (Mazzottis). Мы осмотрим файл штатными утилитами, найдем main в Ghidra, расшифруем «бессмысленные» имена переменных в реальную раскладку стека и подтвердим гипотезы в GDB. По пути встретим оптимизированный пролог без RBP, «хитрое» беззнаковое условие и std::string, спрятавшийся в трех переменных, которые на первый взгляд никак не связаны.

Во второй части цикла – мутационное тестирование и реконструкция скрытой структуры, в третьей – полный разбор хеш-функции и восстановление алгоритма на Python.

Читать первую часть

64 байта и одна константа: разбор переключения контекста в ядре на Rust

Уровень сложностиСложный
Время на прочтение7 мин
Охват и читатели10K

В прошлый раз я писал про потерянное пробуждение и получил в комментариях справедливое замечание, что примитив там классический. Так и есть. Сегодня про место, где классики меньше: как в моём ядре устроено переключение контекста, и почему ассемблер там знает смещение поля в структуре Rust.

Это неприятная связь. Ассемблеру нужен байтовый доступ к сохранённым регистрам, а раскладку структуры определяет компилятор. Если эти двое разойдутся во мнениях, вы не получите ошибку компиляции. Вы получите ядро, которое пишет регистры мимо и падает где-то далеко от места ошибки.

Читать далее

Моя рекурсия зависла навсегда, и это был правильный результат

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели11K

Написал рекурсию тем же приёмом, что во второй статье, и программа повисла навсегда: возвращаться ей было некуда. Чиню, завожу стек и по дороге выясняю, что регистра sp в наборе команд нет вовсе. А потом урезаю стек до 128 байт, и сборка об этом не говорит ни слова.

Ломать второй раз!

Попробуйте найти примеры кода для SME — я подожду

Уровень сложностиСложный
Время на прочтение9 мин
Охват и читатели7.6K

В этой части мы проверим, есть ли у SME учебная дорога, сравнимая с той, которую получили тензорные ядра GPU; затем разберём два реально полезных источника: Arm Learning Path и KleidiAI; после этого отделим то, чему они действительно учат, от того, где они останавливаются. К концу главы станет видно, какая именно «середина лестницы» отсутствует и почему следующая часть неизбежно приводит к BLIS.

Читать далее

Книги по реверс-инжинирингу

Время на прочтение4 мин
Охват и читатели10K

Это продолжение статьи Материалы по хакингу на русском.

Вкратце — я собираю автоматические переводы материалов по хакингу и выкладываю их на сайте библиотеки. В этой подборке — книги для тех, кто хочет понимать программы, железо и протоколы не по документации, а изнутри: от устройства компьютера и ассемблера до Windows Kernel, ARM, Java-байткода, автомобильных шин, VoIP и аппаратного реверса.

Читать далее

Мой код терял бы 230 байт из 231. Чтобы это увидеть, пришлось патчить QEMU

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели15K

Через четыре часа после первой статьи пришёл комментарий: в моём коде не хватает трёх инструкций, и на настоящей плате он рассыплется.

Читатель arteast был прав.

Сел воспроизводить поломку. Собрал два варианта, свой и правильный, прогнал на строке в 231 байт. Вывод побайтово одинаковый. Замедлил линию до предела. Ничего не изменилось. Написал программу, которая смотрит, бывает ли передатчик занят хоть когда-нибудь. При выводе в консоль не бывает.

Моя ошибка внутри эмулятора не проявляется вообще. Проверить себя было нечем.

Пришлось чинить эмулятор.

Ну, чини!

Двенадцать символов, двадцать один байт: как я научил голый RISC-V говорить «Привет, мир!»

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели10K

Без библиотек, без обвязок, без операционной системы под ногами. Реальный код на реальном железе — ну, почти реальном.
Пустая эмулируемая машина RISC-V, десяток строк ассемблера, и в терминале:
Сначала думал вывести «hello», как все.
Пусть будет «Привет, мир!»

Ну, привет!

Ваш ноутбучный процессор отрастил себе маленькое тензорное ядро

Уровень сложностиСложный
Время на прочтение6 мин
Охват и читатели10K

Часть 1 цикла о программировании Apple Scalable Matrix Extension (SME2) — от первых принципов до промышленной реализации GEMM.

Читать далее

Проектируем с нуля калькулятор на FPGA. Часть 9: погоня за последним разрядом

Время на прочтение14 мин
Охват и читатели9.2K

← Восьмая часть

Описанный в предыдущих частях калькулятор уже работал. Реализация 2021 года запускалась на реальном оборудовании, обрабатывала нажатия клавиш, вычисляла результаты и отображала их. Арифметика была корректной в том смысле, что большинство результатов было точным до 12 значимых разрядов, а это больше, чем требуется обычному пользователю.

Но «большинство» это не «все», а «примерно 12» — это не 15-16 разрядов, которые может и должна обеспечивать 16-разрядная BCD-машина. Существовали пограничные случаи, в которых результаты оказывались совершенно неверными. Имелись итеративные алгоритмы с точностью приемлемой, но не такой, какой она могла быть. Кроме того, в процессе тестирования я обнаружил ошибки, при отладке которых обнаружились фундаментальные баги в коде прототипа на C++. Это привело меня в смятение, ведь для их устранения мне бы пришлось переделать заново код прототипа. В конечном итоге, так я и поступил. Старый код я оставил в репозитории (Pathfinding/Methods) и с нуля разработал совершенно новую версию (Pathfinding/Proof). Я пообещал себе, что занимаюсь этим последний раз в жизни, поэтому стремился делать всё идеально.

В итоге, версия 2025 года устранила найденные мной проблемы. Это был не патч, а почти полное переписывание арифметического движка, расширение набора команд CPU и существенное увеличение библиотеки функций. В этом посте я расскажу об изменениях и их причинах.

Читать далее

Что такое 10 REM"_(C2SLFF4, или как в комментарий 1980 года спрятали машинный код

Время на прочтение9 мин
Охват и читатели12K

В июле 1980 года Recreational Computing напечатал листинг The Wizard's Castle — рогалика на BASIC для микрокомпьютера Exidy Sorcerer. Первая строка выглядела так: 10 REM"_(C2SLFF4 .

REM — это комментарий: интерпретатор его пропускает, писать туда что-то имеет смысл только для человека. Вот только читать здесь нечего, сплошная абракадабра из символов.

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

Читать далее

Пингвин в гостях у Дельфина, или UNIX‑like система на Flipper Zero

Уровень сложностиСредний
Время на прочтение23 мин
Охват и читатели14K

Когда на экране терминала появилось приглашение #, Flipper Zero уже сложно было назвать просто устройством для работы с радиопротоколами, NFC и инфракрасными пультами. Передо мной находился маленький Unix-подобный компьютер: с ядром, процессами, командной оболочкой и файловой системой на microSD.

Читать далее

Ближайшие события

Странные машины: как хакеры собирают процессор из данных

Уровень сложностиСредний
Время на прочтение17 мин
Охват и читатели25K

Как часто нам приходится читать в бюллетенях безопасности «Уязвимость... позволяющая нарушителю выполнить произвольный код с помощью специально сформированного запроса». Но что на самом деле скрывается за этой фразой? Что это за специальные запросы и как наша программа может выполнять чужой код, если мы досконально знаем в ней каждую строчку и каждую библиотеку?

И почему тогда Apple платит до двух миллионов долларов за одну найденную уязвимость и выстраивает многоуровневую аппаратную защиту — а айфоны всё равно взламывают по нажатию одной кнопки?

Всё дело в том, что сами атаки стали другими. Когда инженеры перекрыли большинство очевидных ходов, хакерам пришлось изменить сам подход к взлому. Вместо поиска лазеек они научились брать легитимные вычисления программы и строить поверх них... виртуальный процессор. Даже стандартную функцию вывода текста printf удалось превратить в Тьюринг-полный интерпретатор — то есть вычислитель, способный выполнить любой алгоритм.

Перед нами — Data-Only атаки, где взлом превращается в программирование на «невидимом» процессоре. Процессоре, команды которого — лишь побочный эффект работы нашей собственной программы.

Но чтобы понять, как мы здесь оказались, придётся вернуться на двадцать лет назад.

Читать далее

Проектируем с нуля калькулятор на FPGA. Часть 7: микрокод для самодельного CPU

Время на прочтение15 мин
Охват и читатели8.6K

← Шестая часть

В предыдущем посте мы спроектировали CPU. Я определился с набором команд, написал ассемблер, проверил каждый опкод и создал процессор, работающий в кремнии (или, точнее, в FPGA Altera Cyclone II EP2C5T144C8, что тоже довольно близко). Но у нас пока нет осмысленного ПО (микрокода калькулятора) для запуска на «железе».

В этой части проекта оправдали себя все эксперименты с прототипами на C++, описанные в частях 2 и 3.

Когда я начал писать addsub.asm (самую первую команду, которую я портировал), то не смотрел на пустую страницу, задаваясь вопросом, как работает BCD-сложение. У меня уже имелась эталонная реализация на C++ (addsub.cpp в проекте Proto), верифицированная на тысячах тестовых векторов. Алгоритм был известен, пограничные случаи найдены и охарактеризованы. Я проработал поведение защитного разряда и бита фиксации. Оставалось лишь транслировать это всё на язык ассемблера; задача всё равно сложная, но совершенно иного уровня сложности, нежели изобретение алгоритма в процессе его написания.

Я хотел бы сделать упор на этот двухэтапный процесс, потому что может показаться, что без него можно обойтись. Написание кода прототипа на C++ с последующей ручной трансляцией на язык ассемблера кажется избыточной и долгой работой. Однако она перестанет казаться избыточной к моменту, когда вы будете отлаживать неочевидный пограничный случай округления в 16-ниббловом BCD-вычитании. Наличие золотого эталона, с которым можно выполнять сравнения, не избыточно: это единственное, что стоит между вами и неделями кропотливого труда или даже провалом проекта.

Читать далее

Технология ELAM: как детектируются уязвимые драйверы Windows

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели10K

На дворе 2026 год, технологии развиваются, а хакеры становятся сильнее и изобретают новые способы обхода средств безопасности. Один из таких методов, который уже стал классикой в 2026 году — это BYOVD‑техника (Bring Your Own Vulnerable Driver). Суть проста: атакующий подсовывает в систему легитимный, но уязвимый драйвер, чтобы использовать его как рычаг для отключения защиты(например, чтобы убить процесс антивируса). То есть, в процессе атаки через BYOVD у хакера всегда есть уязвимый легитимный драйвер, но его ищут двумя путями.

Первый — это просто в наглую взять готовый паблик‑драйвер с сайта LoLDrivers, где их лежит целая куча, но такие общеизвестные драйверы антивирусы моментально заносят в черный список и блокируют через различные функции обратного вызова (каллбеки).

Второй намного интереснее — расковырять и найти уязвимость вручную в каком‑нибудь старом системном драйвере или софте для разгона видеокарты. Вот это даёт уникальный вектор атаки, потому что драйвера нет нигде в паблике, соответственно, в чёрные списки его заносить нет причин.

Используется эта техника потому, что современные антивирусы стали слишком сильными. Если посмотреть под капот любому актуальному хорошему защитнику, мы увидим там как минимум 4 собственных драйвера, которые контролируют процессы, следят за подключением разных физических устройств (USB), следят за тем, чтобы вредоносный процесс не смог проэксплуатировать какую‑то уязвимость(например, подмена токена у системного процесса на свой).

Исходя из всего, что я описал выше, возникает логичный вопрос: как мы можем пресекать способы эксплуатации системы через BYOVD‑драйверы? Ответ на этот вопрос прост — нам нужна технология ELAM.

Читать далее

Stream compaction на NEON. Векторизуем copy_if

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели7.4K

Как разогнать copy_if на NEON в 30+ раз без единой ветки в горячем цикле — эмулируем compress инструкцию, которой в NEON нет, через table lookup и немного битовой магии.

Читать далее

Методичка которую я формировал для себя, когда учил ассемблер x86-32. Ч.1

Уровень сложностиСредний
Время на прочтение25 мин
Охват и читатели11K

Небольшая статейка о самых-самых основах ассемблера х86 процессоров. Я расскажу вам о том, как всё работает и для чего вам нужно это знать, даже если вы обычный говнокодер)

Читать далее

Автомобильные сигнализации РФ и их безопасность. Часть 1

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели9.7K

Всем привет. В этот раз я решил затронуть тему безопасности устройств, которыми пользуются большинство автовладельцев. Речь пойдёт о трёх самых популярных автомобильных сигнализациях (иммобилайзерах), представленных на российском рынке.

Забегая вперёд, скажу, что отчёты обо всех найденных недостатках были направлены производителям, а также во ФСТЭК России. Из ответа регулятора я узнал, что в качестве уязвимостей отчёты зарегистрированы не будут, так как «данное программно-аппаратное средство не используется на объектах ГИС и КИИ». Производители же сообщили, что описанные недостатки устранят в новых моделях сигнализаций. За информацией о том, что делать с уже существующими моделями, я рекомендую обращаться к производителям.

Читать далее

Проектируем с нуля калькулятор на FPGA. Часть 6: CPU

Время на прочтение20 мин
Охват и читатели11K

← Четвёртая и пятая части

Это самый длинный пост всей серии, потому что он посвящён главной части этого проекта — всё вращается вокруг CPU.

Почему бы просто не взять готовый CPU?

Кто-то может заявить: зачем заморачиваться проектированием собственного CPU? Есть куча маленьких хорошо задокументированных процессоров и дешёвых микроконтроллеров, способных исполнять прошивку калькулятора. Zilog Z80 не так сложно реализовать на FPGA, и я в этом уже убедился (проект A-Z80, находящийся у меня на GitHub). Подойдёт и 6502. Маленький встраиваемый RISC тоже прекрасно справится с этой работой.

Отвечу честно: это было бы не так интересно, потому что подобное уже много раз делали. Но есть и другие (более удобные для меня) причины.

Наш калькулятор построен на BCD (двоично-десятичном коде),в котором каждый десятичный разряд хранится в отдельном 4-битном полубайте (ниббле). Это правильный выбор для калькулятора, и он определяет всё дальнейшее. Z80 (и другие стандартные CPU) работает на уровне байтов. Для индексации регистра мантиссы из 16 нибблов с ориентированным на байты процессором пришлось бы постоянно жонглировать сдвигами, масками и двумя нибблами на байт. На каждом шаге режимы адресации вступают в конфликт со схемой данных.

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

Читать далее