06.04.2000 Kern32Vx - еще о нахождении kernel32.dll. [Voodoo]

    Приветствую тебя уважаемый читатель-"писатель" ;). 
Речь сегодня пойдет о импорте функций из кернела для "переносимого 
кода". Обычно импорт в "переносимом коде" происходит следующим способом:
получаем точку входа, по ней находим MZ заголовок, далее находим 
PE заголовок, там находим импорты кернела, по ним находим MZ заголовок 
кернела, далее PE заголовок, и наконец добираемся до таблицы экспортов
откуда сохраняем адреса нужных API. Во всяком случае этим алгоритмом 
пользовался я сам когда ваял Win32.Magic.1590. Написав DINA v2.0 я 
вспомнил о импорте. Когда код выполняется в стеке этот алгоритм уже не 
работает ("код" запускается вне приложения которое импортирует кернел).
    Существуют  и другие методы ипорта. Так  было предложено использовать
SEH, точнее последний указатель на обработчик исключения. Обычно (если 
прога его не переназначила) он находится внутри кернела, т.е. можно найти
сразу MZ кернела. Этот метод применим в "коде" который получает управление
первым. Если "код" получает управление методом OEP, то нет гарантии что 
к моменту получения управления "final" exception handler будет находиться 
в кернеле. Хотя если учесть этот факт то можно наряду с MZ кернела  
искать и MZ приложения.
   Еще одна вариация на тему SEH и импорты. При возникновении исключения 
получает управление первый обработчик. Он разбирает исключение и если он 
его не обрабатывает  выполняются следующий код:
MOV EAX,1
RET
Это передача управления на следующий по цепочке обработчик. И так будет 
продолжаться до "final" exception handler. Он уже выведет сообщение 
типа "Программа выполнила коректную операцию и будет выгружена".Если какой 
либо обработчик исправит аварийную ситуацию, выполняются следующий код:
MOV EAX,0
RET
Что значит :reload context & continue execution.
После исключения ss:[eps]= адрес процедуры которая определяет что делать:
"выполнять" или "выгружать". Этими привилегиями обладает операционная 
система. В NT она (процедура) лежит в NTDLL.dll, в МД - в KERNELL32.dll.
Идея в том чтобы взять этот адрес за точку входа и двигаясь по уменьшению
искать MZ. При этом следует проверять имя длл`ки. В интишке за KERNEL32.dll
следует NTDLL.dll поэтому  после NTDLL мы найдем KERNEL32. Не знаю как 
дело обстоит в WIN2k но думаю что "кто ищет тот всегда находит".Последний
алгоритм был реализован в процедуре GetKernelHandlerA в файле kernvx32.inc.
Она в EDI возвращает смещение на MZ кернела. Процедура KernVx32Init в том 
же kernvx32.inc настраивает механизм импорта через SEH. Ее параметром 
является регистр EDI в котором должен находится оффсет на MZ длл`ки. Далее 
мы просто пушим параметры API, пушим APINAMECRC32 и пишем EXEPTION.
EXEPTION - это переменная в файле exeption.inc. Она может принимать два 
значения: DEBUG и NODEBUG. В случае NODEBUG исключение вызывается с 
помощью db 0cch что затрудняет отладку. В случае DEBUG исключение 
вызывается с помощью  db 0ffh,0ffh,0ffh,0c3h,90h,90h,90h (хотя достаточно 
dw 0ffffh). Если APINAMECRC32 найдена в длл`ке (для которой  проинстален 
KernVx32) то выполняется API иначе  EAX=-1.  Для смены DLL следует 
выполнить код типа:
 call LockDLLName
 db 'NEWDLLNAME.dll',0
 LockDLLName:
 Push zGetModuleHandlerA
 EXIPTION
 xor edx,edx                  ;
 pop dword ptr fs:[edx]   ; 
 pop edx                        ;  
 mov edi,eax 
 call KernVx32Init
Более подробно применение показано в примере kernvx32.asm 
PS.
Интересно как енто будет работать под win2k :


 Статья для журнала Top Device