Содержание статьи
Вокруг INT 03h
Программная точка останова на исполнение (software breakpoint on execution) физически представляет собой однобайтовую процессорную инструкцию CCh (INT
), внедряемую дебаггером непосредственно в отлаживаемый код с неизбежной перезаписью оригинального содержимого. Встретившись с INT 03h, процессор генерирует исключение типа EXCEPTION_BREAKPOINT, перехватываемое отладчиком. Он останавливает выполнение программы и автоматически восстанавливает содержимое байта, «испорченного» точкой останова.
Именно так и поступает «Ольга» при нажатии клавиши F2 и SoftICE по F7. Достоинство программных точек останова в том, что их количество ограничено только архитектурными особенностями отладчика (то есть практически неограниченно). В то время как аппаратных точек останова, поддерживаемых процессором на железном уровне, всего четыре.
Недостаток же программных точек останова в том, что они требуют модификации отлаживаемого кода, а это легко обнаруживает ломаемая программа тривиальным подсчетом контрольной суммы. Причем защита может не только задетектить бряк, но и снять его, восстановив исходное значение «брякнутого» байта вручную. Бряк, естественно, не сработает, хотя отладчик продолжит подсвечивать брякнутую строку, вводя хакера в заблуждение (отладчик хранит список точек останова внутри своего тела и не проверяет присутствие INT 03h в отлаживаемом коде).
Многие отладчики (в том числе и «Ольга») устанавливают в точку входа (Entry Point) программный бряк. Его легко обнаружить из функции DllMain
статически прилинкованной динамической библиотеки, возвратив принудительный ноль — что означает «ошибка инициализации» и приводит к аварийному завершению отлаживаемого приложения задолго до того, как точка входа получит управление.
Пример, демонстрирующий детекцию отладчика из статически прилинкованной DLL
BOOL WINAPI dllmain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ #define PE_off 0x3C // PE magic word raw offset #define EP_off 0x28 // Relative Entry Point filed offset #define SW_BP 0xCC // Software breakpoint opcode char buf[_MAX_PATH]; DWORD pe_off, ep_off; BYTE* base_x, *ep_adr; // Obtain exe base address GetModuleFileName(0, buf, _MAX_PATH); // Manual PE-header parsing to find EP value base_x = (BYTE*) GetModuleHandle(buf); pe_off = *((DWORD*)(base_x + PE_off)); ep_off = *((DWORD*)(base_x + pe_off + EP_off)); ep_adr = base_x + ep_off; // RVA to VA // Check EP for software breakpoint (some debuggers set software breakpoint on EP to get control) if (*ep_adr == SW_BP) return 0; // 0 means DLL initialization fails return 1;}
К сожалению, отучить «Ольгу» ставить бряки в точку входа очень непросто (если вообще возможно), и приходится пускаться на хитрости. Открываем ломаемый exe в HIEW и внедряем в точку входа двухбайтовую команду EBh
, соответствующую машинной инструкции l1:
. Это приводит к зацикливанию программы и дает нам возможность приаттачить дебаггер к отлаживаемому процессу. Как вариант, можно впендюрить INT
во вторую (третью, четвертую) команду от точки входа, запустив программу «вживую» (вне отладчика).
Поскольку исключение, генерируемое INT
, некому обрабатывать, операционная система выплевывает сообщение о критической ошибке, предлагая запустить JIT (Just-in-Time) отладчик. В его роли может выступить и «Ольга» (Options → Just-In-Time Debugging → Make Olly just-in-time debuuger). Кстати говоря, подобная техника носит название Break’n’Enter и довольно широко распространена. В частности, ее поддерживают PE-TOOLS и многие другие хакерские утилиты.
Но вернемся к нашим баранам. Попытка установить программную точку останова на самомодифицирующийся (упакованный или зашифрованный) код ведет к краху, причем безо всякого участия со стороны защиты. Надеюсь, не нужно объяснять почему? Ну хорошо. Возьмем тривиальный криптор, работающий через byte
. Допустим, мы устанавливаем бряк на команду PUSH
. После шифровки она превращается в 36h. Представим, что поверх 36h установлена точка останова — CCh. Тогда после расшифровки (CCh
) мы получим AAh (STOSB). Это, естественно, вызовет крах, так как мы не только потеряли PUSH
, но еще и регистры ES:EDI смотрят черт знает куда, вызывая ACCESS VIOLATION!
Впрочем, тут возможны детали. Иногда программу расшифровывает не прикладной код, находящийся непосредственно в ломаемой программе, а драйвер защиты, исполняющийся совершенно в другом контексте. Кстати, о контекстах.
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»