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

Уже дав­но ник­то не трас­сиру­ет прог­раммы от начала и до кон­ца — слиш­ком уто­митель­но и неп­родук­тивно. Одна­ко не сто­ит пол­ностью спи­сывать трас­сиров­ку со сче­тов, она и сей­час живее всех живых!

За­путан­ные учас­тки кода, ответс­твен­ные за про­вер­ку серий­ного номера, клю­чево­го фай­ла или рас­шифров­ку прог­раммы, доволь­но час­то про­гоня­ются отладчи­ком в пошаго­вом режиме. Кро­ме того, отладчик может «нег­ласно» задей­ство­вать трас­сиров­ку для выпол­нения некото­рых опе­раций. В час­тнос­ти, в OllyDbg уста­нов­ка точ­ки оста­нова на коман­ду и/или диапа­зон EIP-адре­сов реали­зует­ся как раз через трас­сиров­ку. Ее же исполь­зуют мно­гие пла­гины, нап­ример популяр­ный FindString, выпол­няющий поиск задан­ной стро­ки в регис­трах (трак­тует их как ука­зате­ли). Рас­паков­щики упа­кован­ных фай­лов (осо­бен­но уни­вер­саль­ные) активно исполь­зуют трас­сиров­ку для осво­бож­дения от упа­ков­щика и вос­ста­нов­ления ори­гиналь­ной точ­ки вхо­да в прог­рамму (Original Entry Point, или, сок­ращен­но, OEP).

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

 

Трассировка в процессорах x86

Ес­ли TF-флаг, хра­нящий­ся в регис­тре EFLSGS (и гнез­дящий­ся в вось­мом бите, счи­тая от нуля), взве­ден, то пос­ле исполне­ния каж­дой коман­ды про­цес­сор генери­рует пре­рыва­ние INT 01h или EXCEPTION_SINGLE_STEP (80000004h) — как его «обоз­вали» раз­работ­чики Windows. Исклю­чение сос­тавля­ют коман­ды, модифи­циру­ющие регистр SS (селек­тор сте­ка) и мас­киру­ющие пре­рыва­ние на выпол­нение сле­дующей коман­ды. На этот шаг раз­работ­чики про­цес­соров пош­ли потому, что в коде час­то встре­чают­ся конс­трук­ции вида MOV SS, new_ss/MOV ESP, new_ESP. Лег­ко сооб­разить, что, если пре­рыва­ние про­изой­дет пос­ле того, как новый селек­тор сте­ка уже обоз­начен, а ука­затель вер­шины сте­ка еще не ини­циали­зиро­ван, мы получим неоп­ределен­ное поведе­ние сис­темы, ведущее к кра­ху (а ведь сущес­тву­ет коман­да LSS, одним махом заг­ружа­ющая и SS, и ESP, но она не отно­сит­ся к чис­лу самых популяр­ных).

Прос­тей­ший спо­соб обна­руже­ния трас­сиров­ки сос­тоит в чте­нии регис­тра фла­гов (EFLAGS) и про­вер­ке сос­тояния бита TF. Если он не равен нулю — нас кто‑то злос­тно трас­сиру­ет. С прик­ладно­го уров­ня про­читать содер­жимое регис­тра фла­гов мож­но самыми раз­ными спо­соба­ми: коман­дой PUSHFD, затал­кива­ющей фла­ги в стек, генера­цией исклю­чения (при которой SEH-обра­бот­чику переда­ется кон­текст потока вмес­те со все­ми регис­тра­ми, вклю­чая регистр фла­гов); наконец, кон­текст мож­но получить API-фун­кци­ей GetThreadContext.

Се­год­ня мы будем говорить лишь о пер­вом спо­собе — коман­де PUSHFD. При кажущей­ся незамыс­ловатос­ти она скры­вает целый пласт хит­ростей, извес­тных далеко не вся­кому хакеру.

 

Эксперимент #1 — «чистый» PUSHFD

На­пишем нес­ложную прог­рам­мку, затал­кива­ющую в стек регистр фла­гов через PUSHFD и тут же вытал­кива­ющую ее обратно в EAX для тес­тирова­ния зна­чения бита TF.

Прос­тей­шая прог­рамма TF-0x0-simple.c для обна­руже­ния трас­сиров­ки через PUSHFD
char yes[]="debugger is detected :-)";
char noo[]="debugger is not detected";
nezumi()
{
char *p=noo; // Презумпция невиновности is on ;-)
__asm
{
; int 03 ; Для отладки
pushfd ; сохраняем флаги в стеке, включая и TF
pop eax ; Выталкиваем сохраненные флаги в eax
and eax, 100h ; Проверяем состояние TF-бита
jz not_under_dbg ; Если TF не взведен, нас не трассируют…
mov [p], offset yes ; …ну или мы не смогли это обнаружить ;)
not_under_dbg:
}
MessageBox(0, p, p, MB_OK);
}

От­компи­лиру­ем ее сле­дующим обра­зом.

cl.exe /c /Ox /Os /G6 TF-0x0-simple.c
link.exe TF-0x0-simple.obj /ENTRY:nezumi /MERGE:.rdata=.text
/ALIGN:16 /DRIVER /FIXED /SUBSYSTEM:CONSOLE KERNEL32.LIB USER32.lib

Все это шаманс­тво пот­ребова­лось:

  • что­бы убить стар­товый код и начать прог­рамму с инте­ресу­ющей нас фун­кции nezumi();
  • что­бы сок­ратить раз­мер прог­раммы, рав­ный в дан­ном слу­чае 768 бай­там.

Не обра­щая вни­мания на ругатель­ство лин­кера warning LNK4078: multiple ".text" sections found with different attributes (40000040), запус­тим прог­рамму. Убе­дим­ся, что она чес­тно говорит: debugger is not detected. А теперь заг­рузим ее в MS VC dbg и будем трас­сировать (кла­виша F11), пока не дос­тигнем пер­вого call’а (им будет MessageBox). Ага, debugger is detected! Цель дос­тигну­та!

Те­перь испы­таем cdb.exe из набора Debugging Tools. Пос­коль­ку он орга­ничес­ки не уме­ет сто­пить­ся на OEP, рас­коммен­тиру­ем int 03 и переком­пилиру­ем прог­рамму: заг­рузим ее в отладчик, ука­зав имя фай­ла в коман­дной стро­ке. Пер­вый раз отладчик всплы­вает в ntdll!DbgBreakPoint по int 03h. Это всплы­тие нам совер­шенно не инте­рес­но, так что пишем g для про­дол­жения выпол­нения прог­раммы и попада­ем на «наш» собс­твен­ный int 03h, сто­ящий в начале nezumi().

Пос­ледова­тель­но отда­вая коман­ду t, трас­сиру­ем фун­кцию до дос­тижения call’а, а потом говорим g. Отладчик не обна­ружен! Как так? А очень прос­то — CDB отсле­жива­ет коман­ду PUSHFD и эму­лиру­ет ее выпол­нение, «вычищая» TF-бит из сте­ка. Ана­логич­ным обра­зом себя ведут Soft-Ice, Syser, OllyDbg и мно­гие дру­гие «пра­виль­ные» отладчи­ки. А вот IDA и GDB «чес­тно» показы­вают TF-бит, как он есть, чем и обна­ружи­вают свое при­сутс­твие.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии