Windows 2000 меня не интересует. Делаю: Код (Text): mov eax, fs:[0x34] mov eax, dword ptr [eax + 0x10] // eax <- NtoskrnlBase Отлично работает на однопроцессорных системах. На многопроцессорных обламывается из-за того, что KPCR у каждого процессора свой, и _KPCR->KdVersionBlock = 0 на ядрах, отличных от нулевого. К примеру, на моей системе: Код (Text): lkd> !pcr 0 KPCR for Processor 0 at ffdff000: Major 1 Minor 1 NtTib.ExceptionList: ffffffff NtTib.StackBase: b34eedf0 NtTib.StackLimit: b34eb000 NtTib.SubSystemTib: 00000000 NtTib.Version: 00000000 NtTib.UserPointer: 00000000 NtTib.SelfTib: 7ffd9000 SelfPcr: ffdff000 Prcb: ffdff120 Irql: 00000000 IRR: 00000000 IDR: ffffffff InterruptMode: 00000000 IDT: 8003f400 GDT: 8003f000 TSS: 80042000 CurrentThread: 88e726a8 NextThread: 00000000 IdleThread: 8055be60 DpcQueue: lkd> !pcr 1 KPCR for Processor 1 at bab40000: Major 1 Minor 1 NtTib.ExceptionList: ffffffff NtTib.StackBase: b3c2edf0 NtTib.StackLimit: b3c29000 NtTib.SubSystemTib: 00000000 NtTib.Version: 00000000 NtTib.UserPointer: 00000000 NtTib.SelfTib: 7ffde000 SelfPcr: bab40000 Prcb: bab40120 Irql: 00000000 IRR: 00000000 IDR: ffffffff InterruptMode: 00000000 IDT: bab44590 GDT: bab44190 TSS: bab40d70 CurrentThread: 8946b020 NextThread: 00000000 IdleThread: bab42e20 Значения селектора FS различны на различных ядрах. И что хуже всего для меня, различны и DWORD'ы по FS:[0x34]. Сначала было желание сделать: Код (Text): mov eax, [0xFFDFF034] mov KdVersionBlock, eax Но в таком случае теряется совместимость с Win Vista, Win 7. Можно в цикле выполнять код до тех пор, пока _KPCR.Number != 0, но это совсем через задницу и далеко не факт, что вообще когда-нибудь станет верно (например, если Affinity для текущего потока установлено таким образом, чтобы его код не выполнялся на 0м ядре) Была идея использовать _KPRCB.MultiThreadSetMaster, но его смещение различно на различных ОС, к тому же нет гарантии, что он указывает именно туда, куда нужно. Собственно задача: получить указатель на структуру _KPCR для нулевого ядра (без использования API). Реально ?
Базы сегментов различны, сам селектор всюду одинаков, индексирует 6-й дескриптор в GDT, соответственно 0x30 в регистре Fs. Массив указателей на PCR каждого процессора находится в переменной хал HalpProcessorPCR(см. HalInitializeProcessor). PCR первого процессора находится по физическому адресу 0x40000, вероятно во всей линейке, нужно проверить с помощью MmGetVirtualForPhysical().
Не то, я забыл что вам база ядра нужна Лучше классический способ - найти гденибудь указатель в ядро и просканить память вниз до хидера. Про KdVersionBlock вроде у Грита в блоге было.
Да, конечно же у меня описка, селектор везде 0x30 - разная база сегмента. Насчёт массива указателей в HalpProcessorPCR я знаю, только до неё добраться ещё нужно. Дело в том, что KdVersionBlock даёт мне достаточно информации, а именно базу ядра, указатель PsLoadedModuleList, BuildNumber, номер сервис пака (критично для совместимости с Win2003 - в SP0/1(2) заметно отличаются структуры _KTHREAD/_ETHREAD и др.). У Great по теме фактически ничего нет.
На Вирустехе нашёл коррелирующую тему (http://www.virustech.org/f/viewtopic.php?id=57), но решения нет. На самом деле задача сводится к выполнению кода на 0м процессоре (нужен аналог KeSetSystemAffinityThread, либо, что ещё хуже, использование DCP/IPI) - что фактически без API не реализуемо (на данном этапе выполения не известна ОС - универсального кода, работающего на XP - 7, думаю, не придумать); либо к поиску списка структур KPCR/KPRCB, что тоже не просто. В конце-концов топорный вариант с бесконечным циклом работает (как показала практика рано или поздно код выполняется на нужном процессоре), но такое решение меня не устраивает.
x64 Проблемно без функционала ядра доставить DPC. AntiFreeze Зачем тебе нужен этот KdVersionBlock, он ищется сложнее чем само ядро, которое ты через эту инфу найти хочешь(он кстати в секции данных ядра находится). Если уж так нужно, то как и посоветовал мне Грит в том топике, реализуй все манипуляции с IPI в ручную. Можно есчо использовать прерывание 0x2e, тоесть сервисы, в таком случае где ядро знать не нужно, необходима таблица Version/ServiceId, например чтонибудь типа NtSystemDebugControl(не знаю как с совместимостью), или NtQuerySystemInformation. Не понятно только одно - зачем так усложнять.
Clerk На самом деле просто обидно, что элегантное решение в несколько ассемблерных команд в итоге сведётся к банальному scandown, разбору таблицы экспорта и т.п. x64 Использование DPC невозможно по той причине, что на данном этапе выполения кода не известны адреса нужных API (можно конечно самостоятельно реализовать KeInitializeDpc, KeSetTargetProcessorDpc (не сложно) и KeInsertQueueDpc (надо ковырять)) Но это, ровно как и ручная реализация IPI, усложнит метод настолько, что про него можно будет сказать - цель не оправдывает средства. В общем ясно, повожусь ещё день с этой проблемой, и если ничего толкового не придумаю, буду использовать старые проверенные методы. Всем спасибо.
Сегодня проверил. На XP-2003 действительно MmGetVirtualForPhysical() от 0x40000 возвращает правильный виртуальный адрес. На Vista и Win 7 - нет. Что именно не так, то ли PCR нулевого процессора находится в физической памяти не по тому адресу, то ли функция неверно преобразовывает этот адрес (что, думаю, маловероятно) - разбираться не стал.
Посмотрел на виртуалке и на реальной машине: На Вин7 виртуальный адрес 0x82952C00, физический, согласно MmGetPhysicalAddress - 0x2952C00 Vista SP1, виртуальный 0x81D2F800, физический - 0x1D2F800 Причём адреса "плавают" после перезагрузок.