Фсем привет вопрос такой: Есть ли какой-то способ послать сообщение из ринг0 какому-то потоку в юзермод? (аналог PostThreadMessage)? подозреваю, что нет если так, то может у кого есть идеи, как из драйвера "пробудить" процесс из ожидания (в частности - ожидания следующего сообщения, или в более общем случае - любого из WaitForXXXObject)? наверное стоит также описать для чего это надо: Есть поток работающий в ring0. Ему надо запусть процесс в Юзер-моде от имени explorer.exe. Пробовал 2 техники: - Apc (установка потока explorer.exe в Alreted, и создание юзер-модной APC ф-ции) - Атач к explorer.exe, внедрение обработчика и модификация Import Address Table ентрисов - в частности вызова ф-ции WaitMessage и DispatchMessageW. оба метода работают, но имеют недостаток: Если система чиста, и абсолютно "спокойна" (никакой активности, сети нет, эксплорер-бар внизу спрятан, и т.п.), то может пройти достаточно большой промежуток времени, прежде чем моя процедура активизируется смотрел в Процесс-Эксплорере, в таком "спокойном" состоянии Explorer.exe может проводить вобще без переключения контекстов очень долгое время - в этом та вся и проблема.. как его вывести из этого состояния? Помогло бы единственное сообщение, посланное потоку эксплорера.. есть мысли по этому поводу? кстати, второй метод (перехват DispatchMessageW) гораздо более предпочтителен, т.к. метод с APC не работает на всех системах, т.к. н-р на Vista/w2k3 смещения в KRPOCESS для установки Alerted отличаются от XP/2k, а необходим метод, рабочий на всех x32 windows, а в последствии и порт на Vista/w2k3 x64 спасибо заранее.. Олег
"кривым" решением оказался вызов IoRaiseInformationalHardError сразу после инжекта. результат достигнут - при этом вызове, explorer.exe просыпается и прокачивает несколько сообщений, и код активизируется. побочный продукт - сообщение на экране. у этого метода 2 недостатка: - собственно само сообщение на экране - если попытаться создать ещё 1 процесс, и вызвать IoRaiseInformationalHardError по второму разу, то сообщение не появляется второй раз, и explorer.exe продолжает спать.. т.е. метод действует тока 1 раз (при условии что пользователь не среагирует на первое сообщение) может у кого-нить есть ещё идеи как подобным образом можно "разбудить" explorer.exe и прокачать сообщения?
Ke(Zw-)SetEvent для евента и так далее. Обычная схема - создается общий Event, доступный из р3 и р0, в р3 он просто открывается и ожидается. В р0 он открывается и когда нужно - пульсируется (Ke/ZwPulseEvent),юзермодный поток пробуждается и может запросить у драйвера какую-либо инфу.
Great ага, согласен с asd.. н-р кого нужно пульсировать, если explorer.exe вызвал user32.dll!WaitMessage ? и потом, даже если так сделать, не факт, что он потом не грохнется, из-за того, что пульс был, а сообщения в очереди так и нет.. может есть какой-нить способ добавить сообщение в очередь вручную из ядра? ещё пришла мысль о том, чтобы изменить на время граф. режим, и обратно - эексплорер должен получить в этом случае WM_PAINT и другие сопутствующие.. в соседней ветке обсуждался вывод на экран: InbvAcquireDisplayOwnership InbvResetDisplay это изменяет режим экрана, и по идее - при возвращении обратно, все должно перерисоваться, но вот предложенной ф-ции InbvSetDisplayOwnership котороя должна вернуть все обратно - я не нашел в экспорте ntoskrnl.exe по-прежнему - нужны идеи, как ещё можно "разбудить" explorer.exe спасибо..
Проблема вот в чем. Вот код функции InbvAcquireDisplayOwnership: Code (Text): .text:805299BB _InbvAcquireDisplayOwnership@0 proc near .text:805299BB ; CODE XREF: KeBugCheck2(x,x,x,x,x,x)+5DFp .text:805299BB ; PopSaveHiberContext(x)+C7p ... .text:805299BB mov eax, _InbvResetDisplayParameters .text:805299C0 test eax, eax .text:805299C2 jz short loc_805299D3 .text:805299C4 cmp _InbvDisplayState, 2 .text:805299CB jnz short loc_805299D3 .text:805299CD push 50 .text:805299CF push 80 .text:805299D1 call eax .text:805299D3 .text:805299D3 loc_805299D3: ; CODE XREF: InbvAcquireDisplayOwnership()+7j .text:805299D3 ; InbvAcquireDisplayOwnership()+10j .text:805299D3 and _InbvDisplayState, 0 .text:805299DA retn .text:805299DA _InbvAcquireDisplayOwnership@0 endp То есть она кроме захвата дисплея сбрасывает режим в 80х50. А InbvSetDisplayOwnership не делает обратного: Code (Text): .text:805299E7 ; __stdcall InbvSetDisplayOwnership(x) .text:805299E7 _InbvSetDisplayOwnership@4 proc near ; CODE XREF: PopInvokeSystemStateHandler(x,x)+27Ap .text:805299E7 .text:805299E7 bOwned = byte ptr 8 .text:805299E7 .text:805299E7 mov edi, edi .text:805299E9 push ebp .text:805299EA mov ebp, esp .text:805299EC mov al, [ebp+bOwned] .text:805299EF neg al .text:805299F1 sbb eax, eax .text:805299F3 and eax, 0FFFFFFFEh .text:805299F6 inc eax .text:805299F7 inc eax .text:805299F8 mov _InbvDisplayState, eax .text:805299FD pop ebp .text:805299FE retn 4 .text:805299FE _InbvSetDisplayOwnership@4 endp Поэтому даже если ты найдешь ее адрес.. оно не вернет старый режим. хотя хз.. надо проверить
Great понятно.. значит это не решение - и нет документированного способа ресетнуть графику из кернела (с возвратом).. но ведь должен быть какой-то способ типа IoRaiseInformationalHardError, но без недостатков - чтобы дернуть пару сообщений в explorer.exe.. есть ещё идеи?
Попробуй сделать win32k.NtUserPostMessage( HWND_BROADCAST, WM_PAINT, 0, 0 ) или NtUserPostThreadMessage
n0name А разве ZwCreateThread - это не юзермодная ф-ция? она ведь в ntdll, и находится в адресном юзермодном адресном пространстве.. Почему бы тогда не вызвать напрямую kernel32!CreateThread? - она на том-же уровне, что и ZwCreateThread.. Вобще - я не пробовал такого.. - думал, что нельзя вызывать из ring0 юзермодные ф-ции.. Ты уверен, что этот способ сработает? если так, то конечно стоит попробовать..
Great наверное это сработает.. но у меня тогда такой вопрос: как найти адреса этих ф-ций? в ДДК их нет, т.е. - они не экспортируемые каким-либо модулем ядра.. где взять их адреса?
Great да, это переходник - там SysEnter или int но я так понимаю, мне из ядра надо вызывать не саму экспортируемую NtCreateThread, а то место, куда идет вход по sysenter? так вот - как вычислить это место?
Поскольку ZwCreateThread не экспортируется ядром, тебе нужно промапить ntdll, найти там номер ZwCreateThread в SSDT и вызвать ее напрямую из KeServiceDescriptorTable->ntoskrnl.ServiceTable[]
в KeServiceDescriptorTable->win32k.ServiceTable[] набросал примерный код: Code (Text): #include <ntddk.h> #define DPRINT DbgPrint void DriverUnload(IN PDRIVER_OBJECT DriverObject) { DPRINT ("[+] Driver unloaded"); } typedef PVOID* PNTPROC; typedef struct _SYSTEM_SERVICE_TABLE { PNTPROC ServiceTable; PULONG CounterTable; ULONG ServiceLimit; PUCHAR ArgumentTable; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE; typedef struct _SERVICE_DESCRIPTOR_TABLE { SYSTEM_SERVICE_TABLE ntoskrnl; SYSTEM_SERVICE_TABLE win32k; SYSTEM_SERVICE_TABLE iis; SYSTEM_SERVICE_TABLE unused; } SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE; extern "C" extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; typedef void* HWND; typedef unsigned int UINT, WPARAM, LPARAM; // Только для Windows XP SP2 UP 2600 Free !! #define NtUserPostMessage_Num 0x11DB #define HWND_BROADCAST 0xFFFF #define WM_PAINT 0x0F BOOLEAN NTAPI PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) { PVOID NtUserPostMessage = KeServiceDescriptorTable->win32k.ServiceTable[ NtUserPostMessage_Num ]; __asm jmp [NtUserPostMessage]; } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = DriverUnload; DPRINT("[~] Driver loading"); PostMessage( HWND_BROADCAST, WM_PAINT, 0, 0 ); DPRINT("[+] Driver initialization successful"); return STATUS_SUCCESS; } UPD: Тут конечно shadow нужна.. UPD2: номер надо еще and'ануть с 0xFFF чтобы получился индекс сервиса в таблице
Great спасибо.. получается код специфичный для конкретной ОС - что не есть хорошо мой код должен работать на всех х32 виндах начиная с win2k, с любыми сервиспаками (включая ещё не вышедшие) не хотелось бы переходить на код вида: if (_WinVer==XXX) offset = yyy и т.п. а кроме того - как вычилять эту константу NtUserPostMessage_Num для других версий винды? но всеравно спасибо - хоть какое-то, да решение..
ratix эти константы получаются динамически путём несложных телодвижений(по крайней мере в 2k и xp). Надо в ntdll найти нужную ф-ию и там первой командой идёт mov eax,xxxxxxxx. это хххххххх и есть искомое число. Add Упс. А вот из user32.dll эти константы автоматом не очень то достанешь