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

От­ладчи­ки обо­их уров­ней — как ядер­ного, так и прик­ладно­го — совер­шенно не прис­пособ­лены для иссле­дова­ния прог­рамм, интенсив­но исполь­зующих струк­турные исклю­чения (они же structured exceptions, более извес­тные как SEH, где пос­ледняя бук­ва дос­талась в нас­ледс­тво от сло­ва handling — обра­бот­ка). И хотя OllyDbg дела­ет некото­рые шаги в этом нап­равле­нии, без написа­ния собс­твен­ных скрип­тов/мак­росов не обой­тись. Генера­ция исклю­чения «телепор­тиру­ет» нас куда‑то внутрь NTDLL.DLL, в тол­щу слу­жеб­ного кода, выпол­няюще­го поиск и переда­чу управле­ния на SEH-обра­бот­чик, который нас инте­ресу­ет боль­ше все­го. Как в него попасть? Отладчик не дает отве­та, а тупая трас­сиров­ка тре­бует немало вре­мени.

Впро­чем, SEH — это ерун­да. Начиная с XP появи­лась под­дер­жка обра­бот­ки век­торных исклю­чений (VEH), уси­лен­ная в Server 2003 и, соот­ветс­твен­но, в Вис­те / Server 2008. Отладчи­ки об этом вооб­ще не зна­ют, откры­вая раз­работ­чикам защит огромные воз­можнос­ти для анти­отладки и обла­мывая начина­ющих хакеров косяка­ми. Я покажу, как побороть SEH/VEH-штуч­ки в любом отладчи­ке типа Syser, Soft-Ice или WinDbg. К сожале­нию, OllyDbg содер­жит гру­бую ошиб­ку в «движ­ке» и для отладки SEH/VEH-прог­рамм не под­ходит. Ну не то что­бы сов­сем не под­ходит, но повозить­ся при­дет­ся (секс будет — и мно­го).

 

SEH fundamentals

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

Ис­клю­чение, сге­нери­рован­ное про­цес­сором, тут же перех­ватыва­ется ядром опе­раци­онной сис­темы, которое его дол­го и нуд­но мутузит, но в кон­це кон­цов воз­вра­щает управле­ние на прик­ладной уро­вень, вызывая фун­кцию NTDLL.DLL!KiUserCallbackDispatcher. При пошаго­вой трас­сиров­ке отладчи­ки прик­ладно­го/ядер­ного уров­ня про­пус­кают ядер­ный код, сра­зу же ока­зыва­ясь в NTDLL.DLL!KiUserCallbackDispatcher. То есть при трас­сиров­ке кода XOR EAX,EAX/MOV EAX,[EAX] сле­дующей выпол­няемой коман­дой ока­зыва­ется пер­вая инс­трук­ция фун­кции NTDLL.DLL!KiUserCallbackDispatcher. Сюр­приз, да?

При выпол­нении KiUserCallbackDispatcher извле­кает ука­затель на цепоч­ку обра­бот­чиков струк­турных исклю­чений, хра­нящий­ся по адре­су FS:[00000000h], и вызыва­ет пер­вый обра­бот­чик через фун­кцию ExecuteHandler, переда­вая ему спе­циаль­ные парамет­ры.

В зависи­мос­ти от зна­чения, воз­вра­щен­ного обра­бот­чиком, фун­кция KiUserCallbackDispatcher либо про­дол­жает «рас­кру­чивать» спи­сок струк­турных исклю­чений, либо оста­нав­лива­ет «рас­крут­ку», воз­вра­щая управле­ние коду, породив­шему исклю­чение. Исхо­дя из типа исклю­чения (trap или fault) управле­ние переда­ется либо машин­ной коман­де, сге­нери­ровав­шей исклю­чение, либо сле­дующей инс­трук­ции (под­робнее об этом мож­но про­читать в ману­алах Intel).

Спи­сок обра­бот­чиков струк­турных исклю­чений пред­став­ляет собой прос­той односвяз­ный спи­сок.

Фор­мат спис­ка обра­бот­чиков струк­турных исклю­чений
_EXCEPTION_REGISTRATION struc
prev dd ? ; // Предыдущий обработчик, -1 — конец списка
handler dd ? ; // Указатель на SEH-обработчик
_EXCEPTION_REGISTRATION ends

Об­работ­ка струк­турных исклю­чений име­ет сле­дующий про­тотип и воз­вра­щает одно из трех зна­чений, опи­сан­ных в MSDN: EXCEPTION_CONTINUE_SEARCH, EXCEPTION_CONTINUE_EXECUTION или EXCEPTION_EXECUTE_HANDLER.

Про­тотип обра­бот­чика струк­турных исклю­чений
handler(PEXCEPTION_RECORD pExcptRec, PEXCEPTION_REGISTRATION pExcptReg,
CONTEXT * pContext, PVOID pDispatcherContext, FARPROC handler);

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

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

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

 

VEH fundamentals

На­чиная с XP появи­лась под­дер­жка век­торных исклю­чений — раз­новид­ность SEH, одна­ко реали­зован­ная незави­симо от нее и работа­ющая парал­лель­но. Дру­гими сло­вами, добав­ление нового век­торно­го обра­бот­чика никак не зат­рагива­ет SEH-цепоч­ку, и, соот­ветс­твен­но, наобо­рот.

Ме­ханизм обра­бот­ки век­торных исклю­чений работа­ет по тому же прин­ципу, что и SEH, вызывая уже зна­комую нам фун­кцию NTDLL.DLL!KiUserCallbackDispatcher. В свою оче­редь, она вызыва­ет NTDLL.DLL!RtlCallVectoredExceptionHandlers, рас­кру­чива­ющую спи­сок век­торных обра­бот­чиков с пос­леду­ющей переда­чей управле­ния.

SEH и VEH кон­цепту­аль­но очень схо­жи. Они пре­дос­тавля­ют оди­нако­вые воз­можнос­ти, и вся раз­ница меж­ду ними в том, что вмес­то руч­ного манипу­лиро­вания со спис­ками обра­бот­чиков теперь у нас есть API-фун­кции AddVectoredExceptionHandler и RemoveVectoredExceptionHandler, уста­нав­лива­ющие век­торные обра­бот­чики и уда­ляющие их из спис­ка, ука­затель на который хра­нит­ся в неэк­спор­тиру­емой перемен­ной _RtlpCalloutEntryList внут­ри NTDLL.DLL (по одно­му экзем­пля­ру на каж­дый про­цесс). Плюс упрости­лось написа­ние локаль­ных/гло­баль­ных обра­бот­чиков исклю­чений, что в слу­чае с SEH — боль­шая проб­лема. Но по‑преж­нему век­торная обра­бот­ка при­дер­жива­ется прин­ципа «соци­аль­ного кодек­са»: все обра­бот­чики дол­жны сле­довать опре­делен­ным пра­вилам и нич­то не меша­ет одно­му из них объ­явить себя самым глав­ным и пос­лать дру­гих на хрен.

Описание новых VEH-функций на MSDN
Опи­сание новых VEH-фун­кций на MSDN

Пос­коль­ку 9x/W2K-сис­темы еще дос­таточ­но широко рас­простра­нены, поль­зовать­ся век­торной обра­бот­кой без осо­бой на то нуж­ды могут толь­ко дураки. Во вся­ком слу­чае, необ­ходимо исполь­зовать динами­чес­кую заг­рузку век­торных фун­кций, экспор­тиру­емых биб­лиоте­кой KERNEL32.DLL, и, если их там не ока­жет­ся, либо выдать сооб­щение об ошиб­ке, либо дезак­тивиро­вать защит­ный модуль, работа­ющий на базе VEH.

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

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

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

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

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


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

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

    Подписаться

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