Задача такая:Делаю перехват Api путем инжекта jmp на тело своего обработчика. В обработчике нужно потокобезопасно сохранить регистры исходного потока, подменить стек на свой, выполнить действия по обработке, восстановить стек и регистры. Более подробно алгоритм представляется следующим: 1)потокобезопасно запоминаем регистры использующиеся для подмены стека, 2)меняем стек (StackBase,StackLimit,Esp) 3)pusha 4)тело основного обработчика 5)popa 6)восстанавливаем старый стек 7)восстанавливаем используемые регистры при подмене стека 8)jmp на api. Сообственно интересует конкретная реализация пунктов 1,2,6,7, причем главное условие сделать это нужно не трогая вообще стек исходного потока (любые операции со стеком исходного потока запрещены!). Естественно заранее еще до установки перехвата выделена память в обьеме достаточном для хранения потоковых данных и своих стеков. Заранее благодарен за ответы.
тогда тебе лучше не jump на обработчик а что-то типа 0xcc или 0xf,0xb получишь ексепшын с хорошо замороженым потоком - делай что хочешь, сохраняй, переключай я бы так сделал, особенно если на 2003-ХП то доступны векторные обработчики - самое то
что значит "потокобезопасно запоминаем регистры использующиеся для подмены стека"? для того чтобы такое сделать нужно либо приостанавливать все остальные потоки приложения (что рано или поздно может привести к их взаимной блокировке или еще чего), либо на авось их запомнить и надеятся что это произошло "потокобезопасно". И потом, как реализуешь перехват? Постоянно меняешь 5 байт при вызове настоящей/подменяной функции или вытаскиваешь из функции целое число инструкций, а сам код не трогаешь потом? Если первый вариант, то в многопоточной среде это все упадет хоть что ты не делай. А во втором просто запоминай параметры стека в регистрах eax, esi, edi (API функция их все равно поменяет), после подмены стека запихай их в свой стек, вызови функцию а потом восстанови регистры назад и все
explosion-> Потокобезопасно означает что для каждого потока в система создает стек со своим адресом. Тоесть мне надо для каждого потока переключится на собстенный стек (адрес стека должен меняться в зависемости от контекста текущего потока). Кстати перехватываются не только системные вызовы а вызовы и в собственных dll процесса. Так что после порчи eax,esi,edi система точно вылетит в аут Перехват осуществляется вариантом 2. z0mailbox-> Спасибо за совет. Опиши сам процесс поподробней.
в таргетном процессе говоришь AddVectoredExceptionFilter() находишь нужный апи копируешь к себе несколько байтов которые перезатрутся ставишь рид-райт протект перезатираешь эти байты (в этот момент надо чтобы никто в этот апи не входил) восстанавливаешь протект на всякий случай собственно все, восстанавливается обратным порядком в хендлере проверяешь код ексепшына, например если перезатирал 0f-0b то будет "инвалид опкоде" потом по адресу ексепшына из ассоц.массива вытаскиваешь обработчик весь обработчик защищен - в начале все что можно сохраняет в конце восстанавливает на выходе вызываешь перезатертые байты и после них джамп работать будешь в текущем потоке, но в другом контексте, и регистры и стек - все твое если хочешь в другом потоке - тогда надо все то же самое но через дебуг апи и из другого процесса но там будет геморрой и тормоза из-за постоянных ReadProcessMemory
Спасибо за подробную инструкцию, за выходные сам справился. Единственное замечание к выше приведенному тексту, что сохранять нужно число байтов равное целой команде+ в случае относительного jmp или callа пересчитывать смещение с поправкой адреса.
вообще то поуму было бы DWORD SuspendThread( HANDLE hThread ); затем BOOL GetThreadContext( HANDLE hThread, LPCONTEXT lpContext ); , после BOOL SetThreadContext( HANDLE hThread, const CONTEXT* lpContext ); а на последок не помешало бы и DWORD ResumeThread( HANDLE hThread );
да, там работает самописная функция GetOpcodeSize() я же упрощенно написал ексепшен хандлер вызывается в этом же треде так что не совсем "поуму"
<ексепшен хандлер вызывается в этом же треде так что не совсем "поуму" > Скажи, какие пункты при предложенном мною варианте невыполнимы ? у тебя есть все регистры потока, кроме того, многое можно получить из TEB, поток остановлен. Адрес SEH у тебя тоже есть. Немогу понять почему нельзя ?
речь идет о выполнении VEH-a (или SEH-а) он (Handler) выполняется в том же потоке в котором произошло Exception поток не остановлен ты наверное что-то другое имел в виду
В обработчик VEH передается исключение в виде структуры PExceptionPointers, одним из членов которой является PContextRecord->ссылка на context потока в котором произошло исключение. Поэтому алгоритм простой делаем нашу обработку после чего меняем EIP в PContextRecord на наш буффер содержащий первую команду перехваченной функции+jmp на оставшееся тело функции и возвращаем результат EXCEPTION_CONTINUE_EXECUTION.
ну да, это тех. мелочи можно сделать обработку и показать EIP на выход можно показать EIP на обработчик (я так делаю, потому что у меня для каждого exception EIP у меня отдельный handler EIP, т.е. фактически ассоц. массив) я только подчеркнул что это все в одном и том же потоке происходит а то тут предлагали Suspend/Resume thread