Недавно Great опубликовал интерсный метод для выдачи модального диалога из ядра. http://gr8.cih.ms/?entry=entry015. Обнаружил, что в Windows 7, данный метод не работает. ExRaiseHardError возвращает STATUS_SUCCESS, но диалог не отображается. Можно ли как-то это "поправить".
Я, кстати, апдейтнул исходный код, чтобы выводить диалог из контекста любого процесса. (код в блоге работает только из system) нужно доставить WorkItem системному процессу и + там поменял ExRaiseHardError на ZwRaiseHardError http://www.everfall.com/paste/id.php?ynz09b03jl5l - исходник вызывать нужно DisplayMessage как и раньше. она все сделает. но предварительно в инициализации вызвать GuiInitialize() как реализовать GetFunctionSdtNumber, думаю, сами разберетесь. Найти базу ntdll, найти в экспорте ntdll функцию и вынуть оттуда номер из инструкции mov eax, NUMBER Посмотрим. я себе как раз слил win7 (по работе надо было).
А можно ли полный исходник, или скомпилированный драйвер? Хочется быстро проверить - работает ли данный метод в Win7 или нет?
Great Начал рабраться сам, не могу понять, что такое Код (Text): extern PEPROCESS PsSystemProcess; Где PsSystemProcess определен?
эту переменную тоже надо определить и заполнить указателем на системный процесс. ну собственно раз так усердно просите.. код GetFunctionSsdtNumber и нужных ей функций Код (Text): #include "nt.h" PVOID OriginalSdt; typedef struct _SYSTEM_MODULES { ULONG ModulesCount; #pragma warning(disable: 4200) SYSTEM_MODULE_INFORMATION Modules[0]; #pragma warning(default: 4200) } SYSTEM_MODULES, *PSYSTEM_MODULES; PVOID GetSystemInformation ( SYSTEM_INFORMATION_CLASS InfoClass ) /** Get system information by class. ZwQuerySystemInformation wrapper */ { NTSTATUS Status; PVOID Buffer; ULONG Size = PAGE_SIZE * 4; ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); do { ULONG t; Buffer = ExAllocatePool (PagedPool, Size); Status = ZwQuerySystemInformation ( InfoClass, Buffer, Size, &t ); if (!NT_SUCCESS(Status)) ExFreePool (Buffer); Size = Size + PAGE_SIZE*4; } while (Status == STATUS_INFO_LENGTH_MISMATCH); if (!NT_SUCCESS(Status)) { return NULL; } return Buffer; } PVOID FindNtdll() { PSYSTEM_MODULES Modules = (PSYSTEM_MODULES) GetSystemInformation (SystemModuleInformation); PVOID Ntdll = NULL; if (Modules) { for (ULONG i=0; i<Modules->ModulesCount; i++) { _strlwr (Modules->Modules[i].ImageName); if (strstr (Modules->Modules[i].ImageName, "ntdll")) { Ntdll = Modules->Modules[i].Base; break; } } ExFreePool (Modules); } return Ntdll; } PVOID FindImageProcedureByNameOrPointer( IN PVOID Base, IN PCHAR FunctionName OPTIONAL, IN PVOID FunctionEntry OPTIONAL ) { PIMAGE_DOS_HEADER mz; PIMAGE_FILE_HEADER pfh; PIMAGE_OPTIONAL_HEADER poh; PIMAGE_EXPORT_DIRECTORY pexd; PULONG AddressOfFunctions; PULONG AddressOfNames; PUSHORT AddressOfNameOrdinals; ULONG i; // Get headers *(PUCHAR*)&mz = (PUCHAR)Base; *(PUCHAR*)&pfh = (PUCHAR)Base + mz->e_lfanew + sizeof(IMAGE_NT_SIGNATURE); *(PIMAGE_FILE_HEADER*)&poh = pfh + 1; // Get export *(PUCHAR*)&pexd = (PUCHAR)Base + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; *(PUCHAR*)&AddressOfFunctions = (PUCHAR)Base + pexd->AddressOfFunctions; *(PUCHAR*)&AddressOfNames = (PUCHAR)Base + pexd->AddressOfNames; *(PUCHAR*)&AddressOfNameOrdinals = (PUCHAR)Base + pexd->AddressOfNameOrdinals; // Find function for( i=0; i<pexd->NumberOfNames; i++ ) { PCHAR name = ((char*)Base + AddressOfNames[i]); PVOID addr = (PVOID*)((ULONG)Base + AddressOfFunctions[AddressOfNameOrdinals[i]]); if (ARGUMENT_PRESENT (FunctionName)) { if( !strcmp( name, FunctionName ) ) { return addr; } } else if (ARGUMENT_PRESENT (FunctionEntry)) { if (FunctionEntry == addr) return name; } else { ASSERTMSG ("SHOULD NOT REACH HERE", ARGUMENT_PRESENT(FunctionName) || ARGUMENT_PRESENT(FunctionEntry)); } } return NULL; } ULONG GetFunctionSdtNumber (PCHAR Function) { static PVOID Ntdll = NULL; if (!Ntdll) { Ntdll = FindNtdll(); if (!Ntdll) return -1; } ULONG Number = -1; PVOID Proc = FindImageProcedureByNameOrPointer (Ntdll, Function, NULL); if (Proc) { Number = *(ULONG*)( (PUCHAR)Proc + 1 ); } return Number; } код DriverEntry Код (Text): PEPROCESS PsSystemProcess; // Driver entry point NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { KdPrint(("[~] DriverEntry()\n")); PsSystemProcess = PsGetCurrentProcess(); GuiInitialize(); DisplayMessage (L"The matrix has you", OptionOk); KdPrint(("[+] Driver initialization successful\n")); return STATUS_UNSUCCESSFUL; } код nt.h со всякими полезными определениями структур http://www.everfall.com/paste/id.php?8vv1owxtiaqy теперь если все части вместе собрать, должно скопмпилироваться. полных исходников/бинарей не выслать не могу - дорабатывал уже в другом проекте, где это юзается и там много лишнего кода. но того, что я дал, должно хватить для компиляции
Great Большое спасибо! Все скомпилировалось. Под ХР работает, по Win7 - нет. ExRaiseHardError банальным образом ничего не делает.
Да, я пореверсил, оказалось, что в вин7 csrss.exe не обрабатывает hard errorы от процесса System, откуда я собственно и вызываю. Надо вызывать из контекста другого процесса. Например, lsass.exe Кстати, в висте кто-нибудь тестил?
Наверное, в висте тоже блочится. Я пока что писать аттач к lsass для висты/вин7 не буду. Работа ждет. Будет время - напишу
То есть достаточно найти PKPROCESS lsass и заменить Код (Text): KeStackAttachProcess ((PKPROCESS)PsSystemProcess, &ApcState); на Код (Text): KeStackAttachProcess ((PKPROCESS)ps_lsass, &ApcState) ?
А не проще будет поток создать и нормальную MessageBox* вызвать ? И окно нормально будет и никаких проблем с совместимостью.
Может и проще. Но, соданный из ядра поток не будет GUI потоком. Сколько я не возился - не смог зарегистрировать созданный из ядра поток и превратить его в GUI. Доплнительное достоинство ExRaiseHardError - созданный диалог модален и отпадает необходимость в синхонизации. Еще очень важное достоинство - любой антивирус относится абсолютно равнодушно к ExRaiseHardError.
Любой антивирус и детектор руткитов относится равнодушно к регистрации дебуггера и сервису 0x30404 порта \ApiPort создающему удалённый поток, также как и захват контекста и всё остальное.
Clerk Извините пожалуйста за оффтопик, но где можно почитать про сервисы портов, в частности интересует \SmApiPort \ApiPort и \WxApiPort ?
документированно нигде. в исходниках win2k, если у тебя есть. либо разреверсить CreateProcessInternalW и CsrClientCallServer и посмотреть как оно общается с ApiPort
Посмотрел как оболочка выводин сообщения(это если в NtRaiseHardError указать OptionOkNoWait). csrss обрабатывает запрос на порт, в конечном итоге HardErrorHandler() -> CheckShellHardError() посылает сообщение проводнику, который выводит сообщение. В трей сообщение выводится если параметр ShellErrorMode = 1 в разделе HKLM\System\CurrentControlSet\Control\Windows. Главное параметры корректные передать, иначе слетит проводник. Вот пример: Код (Text): .data MessageId ULONG ? ; -> RegisterWindowMessage() SizeOfData ULONG (_ends - Undef2) MsgData PVOID Undef2 Undef2 ULONG 0 Status NTSTATUS STATUS_SUCCESS Undef3 ULONG 0 DtMsgTitle ULONG (offset MsgTitle - offset Undef2) DtMsgText ULONG (offset MsgText - offset Undef2) MsgTitle WCHAR "M","e","s","s","a","g","e",":",0 MsgText WCHAR "H","e","l","l","o"," ","W","o","r","l","d","!",0 _ends db 0 MsgName CHAR "HardError",0 .code Entry proc Local Result:ULONG invoke RegisterWindowMessage, addr MsgName mov MessageId,eax invoke GetTaskmanWindow ;'MSTaskSwWClass' mov edx,eax invoke SendMessageTimeout, edx, WM_COPYDATA, 0, addr MessageId, SMTO_NORMAL or SMTO_ABORTIFHUNG, 3000, addr Result ret Entry endp end Entry Структура сообщения, но не все поля определил: Код (Text): HARDERROR_MESSAGE struct MessageId ULONG ? ; -> RegisterWindowMessage() SizeOfData ULONG ? MsgData PVOID ? ;[...] ;MsgData: DtAppName ULONG ? ; (MsgData + DtAppName):PWCHAR Status NTSTATUS ? Undefined2 ULONG ? ; DtMsgTitle ULONG ? ; OPTIONAL, (MsgData + DtMsgTitle):PWCHAR DtMsgText ULONG ? ; (MsgData + DtMsgText):PWCHAR ;Buffer WCHAR 1 DUP (?) HARDERROR_MESSAGE ends ID обязательно для этой строки, иначе в проводнике проверка и он не пропустит вызов. Собственно результат: Разумеется из ядра это не юзабельно. Нужно посмотреть как там на ErrorPort сообщения посылаются посредством LpcRequestWaitReplyPort().