Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #78, ИЮНЬ 2005 г.

Дизассемблер своими руками

GPcH (www.dotfix.net)

Хакер, номер #078, стр. 078-114-1


Создание простенького дизассемблера в домашних условиях

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

Все же, для чего может пригодиться самодельный дизассемблер? Полноценная программа вроде IDA — это понятно, такая нужна всякому, но зачем свой собственный простенький дизассемблер? Оказывается, применений такой классной штуковине куча. Вспомнить хотя бы упаковщики исполняемых файлов, сжимающие твои программки более чем в два раза (к примеру, UPX или ASpack). Знаешь ли ты, как пишут распаковщики для таких прог? Ты правильно думаешь, что тут не обошлось без темы этой статьи. Ядро распаковщиков, особенно статических (распаковывающих программу без запуска), основано именно на дизассемблере, который в совокупности с анализатором кода позволяет понять код подопытной программы и распаковать ее, используя нужный алгоритм. Если ты когда-нибудь решишь написать такой распаковщик, тебе без самопального дизассемблера не обойтись. А задумывался ли ты, как работают все современные защиты программ? Чтобы извратить код до неузнаваемости, они дизассемблируют твою прогу команда за командой, делая код метаморфным и внедряя попутно мусорные инструкции. Я уже не говорю про виртуальные машины, которые вообще представляют собой кодер-декодер ассемблерных команд в псевдокод и наоборот. В общем, применений у самодельного дизассемблера может быть куча, полезен он необычайно. Осталось только его написать :).

[принцип работы]

Ты уже наверняка задаешься вопросом: «А как вообще дизассемблер работает и почему бы не написать его с нуля?». Ты получишь ответ, если осознаешь, насколько сложно написать дизассемблер, используя только интеловские мануалы. Я лишь кратко рассмотрю принципы кодирования ассемблерных команд, чтобы принцип дизассемблирования стал более понятным.

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

Единственный обязательный параметр команды — это код операции (опкод), остальные будут или не будут использоваться в зависимости от сложности команды. Например префикс — байт, идущий перед опкодом, встречается довольно редко, зато и сделать он может очень многое. В частности, значение префикса 66h меняет размерности регистров и адресов для инструкции. При этом в 16-битной программе этот префикс позволяет юзать 32-битные регистры, а в 32-битной — 16-битные. Поля modR/M позволяют определить формат данных, которыми оперирует инструкция, будь то регистры, адреса и прочее. Поле SIB расширяет возможности адресации 32-битного режима. Процессор узнает о присутствии этого поля по битам 100b в поле R/M. Далее идут непосредственно смещения и операнды, которые должны быть описаны в структуре modR/M+SIB.

Содержание  Вперед на стр. 078-114-2