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

Трудовая дисциплина

Крис Касперски aka мыщъх

Хакер, номер #088, стр. 088-114-4


Во-первых, метка debugger_is_present не определена и вставлена чисто для наглядности, во-вторых, мы уже установили обработчик структурных исключений, флаг трассировки - взвели, а вот о том, что после завершения проверки на отладчик все необходимо вернуть обратно, забыли! Поэтому перед употреблением листинг необходимо слегка доработать, например, так:

[законченная программа anti-debug.c]

main()

{

int a; // через эту переменную мы возвратим значение eax

__asm{ // ассемблерная вставка — начало

push offset my_seh

push dword ptr fs:[0]

mov fs:[0],esp

pushf

or dword ptr[esp],100h ;set trap flag

popf

xor eax,eax

my_seh:

pop dword ptr fs:[0] ; восстанавливаем старый обработчик

add esp,4 ; восстанавливаем стек

mov a,eax ; возвращаем результат в переменной а

} ; ассемблерная вставка - конец

// проверка переменной a на равенство нулю

printf("%s\n",a?"no debugger":"under debugger");

}

Не самый лучший вариант, конечно. При входе в обработчик структурных исключений мы должны выйти из него через недокументированную API-функцию Continue, хотя… будет работать и так. Поэтому не будем отвлекаться на мелочи технической реализации, а сосредоточимся на оформлении ассемблерной вставки.

Мы удаляем "jnz debugger_is_present", а вместо этого возвращаем значение через предварительно объявленную переменную "a". Компилируем программу как обычно ("cl.exe anti-debug.c") и пытаем, то есть делаем попытку запустить. При прогоне под SoftICE, OllyDbg или любым другим неэмулирующим отладчиком на экране покажется "under debugger" или "no debugger". Значит, наша программа работает правильно, и трансляция удалась! Отрываем мыщъху хвост от радости, тем более что с крышей у него проблемы (ну, с головой). Прохудилась и течет зараза, а времени на ремонт нет. Так что мыщъх пишет эти строки, сидя на ноотропах в состоянии измененного сознания и не вполне вменяем, а потому временами не совсем адекватен. Ладно, это мои личные проблемы, так что не высаживайтесь (мы с Крисом, наверное, разные ноотропы кушаем - меня от моих прет. - Прим. Горлума).

А вот другой классический пример:

.code ; секция кода

start: ; точка входа

push 0 ; uType

push 0 ; lpCamtion

push offset s0 ; lpText

push 0 ; hWnd

call MessageBoxA ; зовем функцию

ret ; после нажатия на ок выходим отсюда на хер

.data ; секция данных

s0 db "hello,wordl",0Dh,0Ah,0 ; строка, которую мы будем выводить

end start

Попытка загнать текст программы в ассемблерную вставку ни к чему хорошему не приводит. Компилятор кроет нас матом и компилить отказывается. Вот… «не в эфире будет сказано»! Приходится действовать стратегически. То есть свирепо и радикально. Убираем директивы .code и .data вместе с ненужной инструкцей "ret" (в оригинале она завершает программу, пользуясь тем фактом, что при запуске PE-файла на вершине стека лежит адрес на термирующую процедуру, однако в стековом фрейме нашей ассемблерной вставки ничего подобного нет).

Назад на стр. 088-114-3  Содержание  Вперед на стр. 088-114-5