Требуется получить EIP потока, отработавшего свой квант времени. Ну то есть просто выдрать EIP из его контекста. Интересуют лишь те потоки, которые были прерваны во время выполнения в 0 кольце. Пробовал варианты: - PsGetContextThread(). Для всех потоков упорно EIP = ntdll!KiFastSystemCallRet - Получить адрес из KTRAP_FRAME Thread->Tcb.TrapFrame->Eip, снова EIP = ntdll!KiFastSystemCallRet либо -1 для потоков процесса System - Посмотрел сорсики ядра, нашел какието махинации с KTRAP_FRAME: (PKTRAP_FRAME)((PUCHAR)EThread->Tcb.InitialStack - PSPALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) - sizeof(FX_SAVE_AREA)) - получается какойто непонятный указатель на KTRAP_FRAME. Оттуда либо 0, либо -1 либо ntdll!KiFastSystemCallRet Соответственно вопросы: 1) Относится ли KTHREAD.TrapFrame к сохраненному контексту потока? 2) Что за махинации с адресом KTHREAD.InitialStack и относитчя ли это к сохраненному контексту потока? 3) Где вообще сохраняется контекст? 4) По поводу ntdll!KiFastSystemCallRet - может я чегото непонимаю в переключении контекста, но почему у всех потоков EIP указывает туда, как будто их прервали в юзермоде сразу после возврата по sysexit 5) Не в тему и не особо интересует, но почему EIP = FFFFFFFF у потоков процесса System ? Это Worker Threads чтоли которые ожидают рабочих элементов или что? Смотрел код KiSwapThread;SwapContext не нашел ничего относящегося к переключению контекста потоков (плохо смотрел?)
Great Ха, а вот как происходит переключение потока так вот возврат в стеке разве esp у них одинаковы (там адрес) а ntdll!KiFastSystemCallRet это что-то типа iretd Да еще, а что SoftIce не катит трассировка переключения потоков ??
это просто ret. А вообще смысл предложения твоего я не вкурил) Равносильно дизасмингу или просмотру асм сорсов KiSwapThread. Оставил этот вариант на крайняк. Вдруг кто знает в теории как переключается контекст потока в винде, точнее куда он сохраняется.
Great Короче посмотри стек потока (он у каждого потока свой) и при прерывании при переходе в ring0 там сохраняется адрес возврата
Great по поводу EIP = FFFFFFFF у потоков процесса System, тут все проще те сами высвобождают квант времени или в сосоянии hlt, т.е. при переключении на поток system (основной) адрес не совсем нужен
Great Все драйверы это какбы dll для приложений и в большинстве случаев выполняются в контексте и потоке приложения user mode причем свои потоки создают крайне редко (я в нормальных драйверах не встречал, разве только в PnP) Т.е. в норме потоков в kernel mode - system и еще один два не более..
PROFi Я не про то. Допустим, какойто поток от какогото приложения начал выполнять, ну скажем, NtSuspendProcess. Он перешел в ядро, выполнил там часть кода (допустим референснул объект по хендлу и уже подготовился саспенднуть процесс) и тут его планировщик прервал - мол хватит, твой квант истек. А поток выполнялся в ядре внутри NtSuspendProcess. Вот я и говорю - получается что ни один поток не прервался в режиме ядра. Мистика? ADDED: Вообще понятия "поток в kernel mode" довольно расплывчатое, ибо потоку без разницы где выполняться =) Сейчас он в юзермоде, потом вызвал какуюнить апишку и ускакал внутрь ядра.
Great PreviousMode это не константа процессора, а лишь переменная Windows, посмотри в стеке сегмент возврата. А PreviousMode береттся из контекста текущего потока, а последний вызвал NtSuspendProcess, но ведь от этого он не стал потоком ядра, посто код ядра исполняется потоком пользовательского режима... Блин Во накрутил
Я имею в виду я ее не просто так взял, а из KTRAP_FRAME того же Ну в принципе достаточно просто старший бит EIP проверить, если установлен, значит адрес >2Gb. Хотя надежнее по сегменту - код ринг0 можно выполнять и ниже 2Гб... Ща попробую с просмотром стека повозиться. Кстати, KiFastSystemCallRet это просто RETN так что ни про какие сегменты тут речи быть не может..
Great я ее не просто так взял, а из KTRAP_FRAME того же Ну и что поток то ослася user mode, это процессор теперь работает в ring0, но все структуры потока не изменились, а вних четко UserMode вот и получается, что даже при прерывании из режима ядра PreviousMode = 1
Да ты прав.. туплю. И все же странновато что планировщик оставляет EIP=KiFastSystemCallRet. Хотя сегмент cs наверное перезагружается отдельно.. Хотя имхо было бы проще как ты сказал - оставить адрес на IRET и в стек пихнуть CS с EIP'ом. Ну.. что сделано то сделано=)
Great И все же странновато что планировщик оставляет EIP=KiFastSystemCallRet Ничего странного если учесть, что Windows работает и на Itanium и на Alpha процессорах, там все немножко подругому, а поскольку Win использует Flat модель памяти, то ему не нужно значений cs для возврата
Прога Sleeper: .code start: push -1 call [Sleep] ; never reach here ret .end start Дров выдает для процесса Sleeper.exe EPROCESS = f8fabda0, Name = sleeper.exe Threads [1]: 817a7878, proc f8fabda0, eip 7c90eb94, esp 0006ff50, [esp]: 7c90d85c 7c8023ed 00000000 0006ff80 И правда, стек верный (это результат трейса. Sleep -> SleepEx -> ZwDelayExecution -> KiFastSystemCall с остановом на SYSENTER): 0006FF50 7C90D85C RETURN to ntdll.ZwDelayExecution+0C 0006FF54 7C8023ED RETURN to kernel32.SleepEx+51 from ntdll.ZwDelayExecution 0006FF58 00000000 0006FF5C 0006FF80 Но этот поток был прерван принудительно вызовом ZwDelayExecution -> KeDelayExecutionThread -> KiSwapThread. Но если поток законно прерван по истечении кванта времени, то у него все равно в стеке какието адреса из kernel32 и/или ntdll. Попробую щас еще быстренько наваять другой дров, который создает девайс и в обработке io control'а засыпает навсегда. Чтобы юзермодный поток вызвал DeviceIoControl и уснул в режиме ядра. Еще попробую сделать JMP $ чтобы посмотреть как у потока принудительно отбирают квант времени..
Для проги, у которой на точке входа EB FE (jmp $): EPROCESS = ffb71a20, Name = infloop.exe Threads [1]: ffb96418, proc ffb71a20, eip 00401000, esp 0006ffc4, [esp]: 7c816d4f 012dd728 7c90e1fe 7ffdf000 Что-то тут не чисто=) Тут eip верный
Great Что тут интересного, ведь даже task manager выдает, что такой поток завис а потому ему сразу резко урезается кванты времени (во всяком случае на 2х процессорной машине) Т.е. как только будет переход на другой процесс - поток будет отмечен как не отвечающий, и время его работы урежется ... С этим столкнулся впервые на XP.
Great А что тут странного, ведь я говорю что если нормальному потоку выделяется полный квант времени, то у зависшего большая часть кванта отбирается насильно и делается это в другм месте, видимо поэтому и eip сохраняется. Но лучше пройтись SoftIce ом для более подробного разбора, к сожалению тут мои знания пока туманны.
Я не думаю, что в этом "другом месте" переключение контекста так уж сильно отличается от принудительного переключения. Afaik, там тоже дергается та же KiSwapThread