Здравствуйте! Перевел код перехода в ринг0 (описан тут - http://www.wasm.ru/article.php?article=apihook_3) с Дельфи на C. Все отрабатывает до call far [FarCall], и падает в BSOD c KMODE_EXCEPTION_NOT_HANDLED. Видимо что-то я все же не так сделал, либо шлюз неправильно настроил, либо call far либо еще что-то. В оригинальном коде непонятно, как шлюз настраивать - код заполнения дескриптора непонятно что делает, и не слишком вяжется с описанием дескриптора - http://wasm.ru/article.php?article=pipm02. Мой код в аттаче
Для начала, все процессорные структуры должны быть выравнены по 1 байту: Код (Text): #pragma pack(push,1) typedef struct _TAG_GDT_INFO { WORD Limit; LPVOID Base; } GDT_INFO, *PGDT_INFO; #pragma pack(pop) Так же для FAR_CALL, GATE_DESCRIPTOR и CALL_THUNK
Да, они все выровнены так: Код (Text): #include <PshPack1.h> typedef struct _TAG_CALL_THUNK { // call far [FarCall] BYTE callFar1; //0xFF BYTE callFar2; //0x1D DWORD offsetFarCall; BYTE retCode; // 0xC3 } CALL_THUNK, *PCALL_THUNK; #include <PopPack.h> PshPack1.h и PopPack.h содержат, насколько я знаю, прагмы pragma push и pragma pop соответственно.
Функция quasiMmGetPhysicalAddress получает физический адрес для маленьких страниц памяти. А если в системе 256 и больше Мб оперативки, то ядро маппится на большую страницу. Соответственно, получаешь неверный физический адрес и пишешь callgate не в ту область памяти. Либо отключи большие страницы, либо по-другому получай физический адрес. ЗЫ: Кроме того, возможно включено PAE. Тогда опять же получение физического адреса отличается
Да, памяти больше, чем 256. Большие страницы - это по 4 мб? Разве такое бывает? В том смысле, разве такое используется? А как это обойти? Опять же, как проверить и как обойти?
Чтобы выключить PAE надо в boot.ini прописать Код (Text): /nopae /noexecute=alwaysoff А большие страницы бывают и очень даже широко используются Код (Text): \HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management DWORD LargePageMinimum определяет минимальный объем ОЗУ, при котором включать LargePages. Его забить в 0xFFFFFFFF
Снова хотелось бы возродить тему, т.к ответы топикстартеру не удовлетворили моего любопытства Код (Text): CurrentGate := PGateDescriptor(DWORD(ptrGDT) + offset); repeat CurrentGate := PGateDescriptor(DWORD(CurrentGate) + SizeOf(TGateDescriptor)); if (CurrentGate.Attributes and $FF00) = 0 then begin OldGate := CurrentGate^; CurrentGate.Selector := $08; // ring0 code selector ????? CurrentGate.OffsetLo := DWORD(@Ring0CallProc); ??? CurrentGate.OffsetHi := DWORD(@Ring0CallProc) shr 16; ??? CurrentGate.Attributes := $EC00; ??? FarCall.Offset := 0; FarCall.Selector := DWORD(CurrentGate) - DWORD(ptrGDT) - offset; Break; end; until DWORD(CurrentGate) >= DWORD(ptrGDT) + gdt.limit + offset; Извиняйте, что на [censored] delph-е, не хотел перебивать пока, заюзал код оригинала. Код из статьи MS-Rem-а про переход в 0 кольцо, используя прописывание своего дескриптора в GDT. Собственно интересуют строчки, помеченные вопросами, а в особенности - строчка с 5-ю вопросами. То ли я ламер и не так понял что-либо, то ли в 2 младшие байта адреса базы сегмента заносится 0x08, а в 2 младших байта лимита сегмента заносятся 2 младших байта адреса функции Ring0CallProc???
там же все понятно записано. в поле Selector (там селектор, логично?) заносится 8. в поле Offset, двумя порциями заносятся младшие и старшие части оффсета (адреса). сначала в OffsetLo, потом в OffsetHi. и в атрибуты заносится ec00 тут уже не маны читать на проц надо, а учебник по дельфи
CrystalIC То, что нужно, thanks Great Меня просто глюкануло, я не подумал, насколько дескриптор шлюза вызова отличается от дескриптора кода или данных... ЗЫ. в поле Selector (там селектор, логично?) Для меня нет связи между авторским названием поля cтруктуры или переменной и тем, что автор может туда запихнуть. тут уже не маны читать на проц надо, а учебник по дельфи Спасибо, но лучше не стоит ))
Так почитай все-таки маны на проц и устройство шлюзов. Intel Architectures Software Developer's Manual творит чудеса