Хочу осуществить перехват Native API без драйвера, но возникла очередная проблемка (предыдущую решал здесь: "Точка входа функции", полезно прочитать для составления общей картины). Для осуществления перехвата вхожу в Ring0 и копирую функцию - обработчик в Kernel Spase. Память под обработчик предварительно выделяю с помощью ExAllocatePool. Проблема же заключается в следующем: как только я заменяю адрес в KiServiceTable на адрес своего обработчика, немедленно получаю BSOD. Код проверял уже раз 10, а ошибки так и не нашел. Самое же интересное, что этот обработчик я могу успешно вызывать и из своей проги и из специально мной написанной тестовой (первая программа копирует обработчик в Kernel Spase, а из второй я его вызываю). В общем, сам я могу рулить кодом как хочу, когда же пытаюсь его установить в качестве обработчика, то получаю BSOD. У меня есть предположение, что ядро при вызове обработчика каким то образом "узнает", что этот код находится в области "данных" или что он не принадлежит библиотекам загруженным в Kernel Spase. P.S. Прошу меня простить за возможный "бред", т.к. я пока довольно плохо представляю организацию памяти в Kernel Spase и механику работы ядра. ---------------------- С уважением Евгений.
В аттаче в архив с исходниками. Пароль единица. Проект выполнен в Microsoft Visual Studio .NET 2003 Enterprise Architect v7.1. WARNING!!! Проект собирать только в Release Mode, иначе будут некорректно вычисляться адреса начала и конца, а так же размер копируемой функции - перехватчика. Поясняющие комментарии в конце файла Ring0.cpp в теле метода InstallInterception(...) класса CStealth. ---------------------- С уважением Евгений. _1509768412__r0.rar
Могу ошибаться,но как мне кажется виноват HLL.Попробуй перепиши на С.Вероятно скажу бред,но при том когда ты записываешь в память,выделенную ExAllocatePool,код обработчика,туда записываются адреса переходов относительно твоей проги(Ring3 адреса).Из-за виртуальной трансляции твои адреса невидны из Ring0,а все обращения из Ring0 по невыделенной памяти из приводят к bsod'у.
Под HLL вероятно ты понимаешь (High-Level Language), но я же уже писал что с помощью одной программы я копирую в Kernel Spase область памяти функцию, а с помощью другой программы ее исполняю! Все работает как часы! Как это можно объяснить? Почитал тут книжку "Соломон Д. и Руссинович М. Внутреннее устройство Microsoft Windows 2000." Там подробно описывается организация системной памяти в WinNT, так вот облясть системной памяти жестко раздеяется по областям: "Системный код. Содержит образ операционной системы, HAL и драйверы устройств, используемые для загрузки системы.", ..., "Пул подкачиваемой памяти. Системная куча подкачиваемой памяти.", ...,"Пул неподкачиваемой памяти. Системная куча неподкачиваемой памя- ти, обычно состоящая из двух частей, которые располагаются внизу и ввер- ху системного пространства.", ..., и т.д. Может все-таки ядро как-то отслеживает области памяти, в которых находится код? Может влияют атрибуты страниц памяти: READ_WRITE, READ, WHRITE и т.д.? ---------------------- С уважением Евгений.
но я же уже писал что с помощью одной программы я копирую в Kernel Spase область памяти функцию, а с помощью другой программы ее исполняю! Каким образом ты передаёшь указатель на выделенную память во вторую прогу?
electron Элементаро! Первая программа выделяет память, копирует функцию в Kernel Spase и завершаясь выдает Hendle в десятичной си-сме. Потом я запускаю вторую программу, банально копирую Handle в текстовое поле, жму кнопку Start и получаю результаты работы функции. После прога конечно освобождает выделенную память. Если хочешь, могу выслать пример на мыло. Ну так что? У кого какие будут мысли? ---------------------- С уважением Евгений.
Udzhen а помоему просто нужно взять айс и протрассировать. Либо лучше бы выслал dump bsod. Куда информативнее.
Damp BSOD в аттаче. С помошью WinDbg открывается без проблемм. Надеюсь на Вашу помощь. P.S. Я в низкоуровневом программировании новичок, так что сильно не ругайте. ---------------------- С уважением Евгений. 1997799291__WER53c6.dir00.zip
Попробуй такой код: #pragma pack(push,1) typedef struct _ntcall { UCHAR callop; // call ULONG addr; UCHAR retop; //ret }ntcall,*pntcall #pragma pop(1) { ntcall myntcall; ULONG mycr0 pMem=ExAllocatePool(PagedPool,sizeof(_ntcall)); myntcall.callop=0xE8; memcpy(&myntcall.addr,&KeServiceDescriptorTable->ntoskrnl.ServiceTable[numberOfService],sizeof(DWORD)); ntcall.retop=0xc3; memcpy(pMem,&myntcall,sizeof(_ntcall)) __asm { cli mov eax, cr0 mov mycr0,eax and eax,0xFFFEFFFF mov cr0, eax } *(PULONG)((ULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTable+numbe rOfService)=pMem; __asm { mov eax, mycr0 mov cr0, eax sti } } numberOfService-номер функции в STT. если я ничего не напутал,должна просто вызваться функция,но в обработчике.
"*(PULONG)((ULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTable+numb e rOfService)=pMem;" ошибся,должно быть так: KeServiceDescriptorTable->ntoskrnl.ServiceTable[numberOfService]=pMem;
electron Дизассемблировав ntoskrnl.exe мы можем увидеть, что например ф-я ZwOpenProcess всего лишь "переходник", т.е. внутри нее есть call на какой-то участок кода. Может быть, этот вариант и прокатит (т.к. весь код будет в одном адресном пространстве), но пример уже теряет свою красоту и эффективность. Видимо придется выкачивать SoftIce и смотреть из под него. Но все равно спасибо. С нетерпением жду ваших предположений по поводу решения данного вопроса. ---------------------- С уважением Евгений.
"переходник" - это NtOpenProcess. В сети куча примеров хука SDT, статьи и даже в некоторых книгах целые главы этому посвящены. Может быть имеет смысл их найти и прочитать?
Udzhen т.е. внутри нее есть call на какой-то участок кода. На участок кода внутри самого ntoskrnl.exe. Может быть, этот вариант и прокатит (т.к. весь код будет в одном адресном пространстве) Если я не ошибаюсь,ring0 код может быть только один,для всех процессов.
electron Да именно так, прошу прощения за неточность. Сейчас даже уверен, что прокатит, но ошибку я уже вроде как локализовал, поэтому время на эксперименты терять не буду. Сегодня попробовал поставить хук не на ZwOpenProcess, а на очень редко вызываемую функцию ZwPulseEvent... В результате BSOD'а не происходит, что доказывает, что ошибка в самом обработчике перехвата (Если попытаться вызвать эту функцию, BSOD гарантирован). Буду разбираться, хотя если честно ума не приложу в чем проблема. Дело в том, что функция обработчик (как видно из сырков) практически ничего не делает. В ней лишь небольшая ассемблерная вставка и вызов оригинальной функции. Кроме того, код функции был протестирован с помощью тестовых прог, о которых я говорил выше. Теперь мне ничего не остается, как дизассемблировать и изучить код ntoskrnl.exe и сгенерированный код функции - обработчика перехвата и из этого сделать соответствующие выводы. О результатах сообщу дополнительно, но если у кого возникнет желание покопаться в моих сырках, я буду только рад. ---------------------- С уважением Евгений.
Из того, что помню: Свен Шрайбер: "Недокументированные возможности Windows" Greg Hoglund, Jamie Butler: "Subverting the Windows Kernel" Dabak, Prasad: "Undocumented Windows NT"
2Four-F: Ты не читал Коберниченко?.. У него есть книга "Недокументированные возможности Windows".. Но что там - я даже не представляю, негде взять..
Есть такая книга. Но с тех пор утекло уже очень много воды ( и огненной тоже ). Имеется масса более современной литературы. Так что "используй то, что под рукою, и не ищи себе другое" (с) Элиас Фог.