Посылка сообщения из ring0 в usermode

Тема в разделе "WASM.NT.KERNEL", создана пользователем ratix, 20 авг 2007.

  1. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Фсем привет

    вопрос такой:
    Есть ли какой-то способ послать сообщение из ринг0 какому-то потоку в юзермод? (аналог PostThreadMessage)?


    подозреваю, что нет :dntknw:

    если так, то может у кого есть идеи, как из драйвера "пробудить" процесс из ожидания (в частности - ожидания следующего сообщения, или в более общем случае - любого из WaitForXXXObject)?

    наверное стоит также описать для чего это надо:

    Есть поток работающий в ring0. Ему надо запусть процесс в Юзер-моде от имени explorer.exe.
    Пробовал 2 техники:
    - Apc (установка потока explorer.exe в Alreted, и создание юзер-модной APC ф-ции)
    - Атач к explorer.exe, внедрение обработчика и модификация Import Address Table ентрисов - в частности вызова ф-ции WaitMessage и DispatchMessageW.

    оба метода работают, но имеют недостаток: Если система чиста, и абсолютно "спокойна" (никакой активности, сети нет, эксплорер-бар внизу спрятан, и т.п.), то может пройти достаточно большой промежуток времени, прежде чем моя процедура активизируется :dntknw:
    смотрел в Процесс-Эксплорере, в таком "спокойном" состоянии Explorer.exe может проводить вобще без переключения контекстов очень долгое время - в этом та вся и проблема.. как его вывести из этого состояния?

    Помогло бы единственное сообщение, посланное потоку эксплорера..

    есть мысли по этому поводу?

    кстати, второй метод (перехват DispatchMessageW) гораздо более предпочтителен, т.к. метод с APC не работает на всех системах, т.к. н-р на Vista/w2k3 смещения в KRPOCESS для установки Alerted отличаются от XP/2k, а необходим метод, рабочий на всех x32 windows, а в последствии и порт на Vista/w2k3 x64

    спасибо заранее..

    Олег
     
  2. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    "кривым" решением оказался вызов
    IoRaiseInformationalHardError
    сразу после инжекта.

    результат достигнут - при этом вызове, explorer.exe просыпается и прокачивает несколько сообщений, и код активизируется.
    побочный продукт - сообщение на экране.
    у этого метода 2 недостатка:
    - собственно само сообщение на экране
    - если попытаться создать ещё 1 процесс, и вызвать IoRaiseInformationalHardError по второму разу, то сообщение не появляется второй раз, и explorer.exe продолжает спать.. т.е. метод действует тока 1 раз (при условии что пользователь не среагирует на первое сообщение)

    может у кого-нить есть ещё идеи как подобным образом можно "разбудить" explorer.exe и прокачать сообщения?
     
  3. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Ke(Zw-)SetEvent для евента и так далее.

    Обычная схема - создается общий Event, доступный из р3 и р0, в р3 он просто открывается и ожидается.
    В р0 он открывается и когда нужно - пульсируется (Ke/ZwPulseEvent),юзермодный поток пробуждается и может запросить у драйвера какую-либо инфу.
     
  4. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    Great
    Дык нет в ехплорере нашего потока, который ждёт нашего евента.
     
  5. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Great

    ага, согласен с asd.. н-р кого нужно пульсировать, если explorer.exe вызвал user32.dll!WaitMessage ?
    и потом, даже если так сделать, не факт, что он потом не грохнется, из-за того, что пульс был, а сообщения в очереди так и нет..

    может есть какой-нить способ добавить сообщение в очередь вручную из ядра?


    ещё пришла мысль о том, чтобы изменить на время граф. режим, и обратно - эексплорер должен получить в этом случае WM_PAINT и другие сопутствующие..
    в соседней ветке обсуждался вывод на экран:
    InbvAcquireDisplayOwnership
    InbvResetDisplay

    это изменяет режим экрана, и по идее - при возвращении обратно, все должно перерисоваться, но вот предложенной ф-ции
    InbvSetDisplayOwnership
    котороя должна вернуть все обратно - я не нашел в экспорте ntoskrnl.exe :dntknw:


    по-прежнему - нужны идеи, как ещё можно "разбудить" explorer.exe

    спасибо..
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Проблема вот в чем. Вот код функции InbvAcquireDisplayOwnership:

    Код (Text):
    1. .text:805299BB _InbvAcquireDisplayOwnership@0 proc near
    2. .text:805299BB                                         ; CODE XREF: KeBugCheck2(x,x,x,x,x,x)+5DFp
    3. .text:805299BB                                         ; PopSaveHiberContext(x)+C7p ...
    4. .text:805299BB                 mov     eax, _InbvResetDisplayParameters
    5. .text:805299C0                 test    eax, eax
    6. .text:805299C2                 jz      short loc_805299D3
    7. .text:805299C4                 cmp     _InbvDisplayState, 2
    8. .text:805299CB                 jnz     short loc_805299D3
    9. .text:805299CD                 push    50
    10. .text:805299CF                 push    80
    11. .text:805299D1                 call    eax
    12. .text:805299D3
    13. .text:805299D3 loc_805299D3:                           ; CODE XREF: InbvAcquireDisplayOwnership()+7j
    14. .text:805299D3                                         ; InbvAcquireDisplayOwnership()+10j
    15. .text:805299D3                 and     _InbvDisplayState, 0
    16. .text:805299DA                 retn
    17. .text:805299DA _InbvAcquireDisplayOwnership@0 endp
    То есть она кроме захвата дисплея сбрасывает режим в 80х50. А InbvSetDisplayOwnership не делает обратного:

    Код (Text):
    1. .text:805299E7 ; __stdcall InbvSetDisplayOwnership(x)
    2. .text:805299E7 _InbvSetDisplayOwnership@4 proc near    ; CODE XREF: PopInvokeSystemStateHandler(x,x)+27Ap
    3. .text:805299E7
    4. .text:805299E7 bOwned          = byte ptr  8
    5. .text:805299E7
    6. .text:805299E7                 mov     edi, edi
    7. .text:805299E9                 push    ebp
    8. .text:805299EA                 mov     ebp, esp
    9. .text:805299EC                 mov     al, [ebp+bOwned]
    10. .text:805299EF                 neg     al
    11. .text:805299F1                 sbb     eax, eax
    12. .text:805299F3                 and     eax, 0FFFFFFFEh
    13. .text:805299F6                 inc     eax
    14. .text:805299F7                 inc     eax
    15. .text:805299F8                 mov     _InbvDisplayState, eax
    16. .text:805299FD                 pop     ebp
    17. .text:805299FE                 retn    4
    18. .text:805299FE _InbvSetDisplayOwnership@4 endp
    Поэтому даже если ты найдешь ее адрес.. оно не вернет старый режим. хотя хз.. надо проверить
     
  7. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Great
    понятно.. значит это не решение - и нет документированного способа ресетнуть графику из кернела (с возвратом)..

    но ведь должен быть какой-то способ типа IoRaiseInformationalHardError, но без недостатков - чтобы дернуть пару сообщений в explorer.exe..

    есть ещё идеи?
     
  8. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    А почему бы не создать поток в процессе через ZwCreateThread?
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Попробуй сделать win32k.NtUserPostMessage( HWND_BROADCAST, WM_PAINT, 0, 0 )
    или NtUserPostThreadMessage
     
  10. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    n0name
    А разве ZwCreateThread - это не юзермодная ф-ция? она ведь в ntdll, и находится в адресном юзермодном адресном пространстве..

    Почему бы тогда не вызвать напрямую kernel32!CreateThread? - она на том-же уровне, что и ZwCreateThread..

    Вобще - я не пробовал такого.. - думал, что нельзя вызывать из ring0 юзермодные ф-ции.. Ты уверен, что этот способ сработает? если так, то конечно стоит попробовать..
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    а мне казалось что это переходник в NtCreateThread в ядре..
     
  12. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    n0name
    там еще надо цсрсс уведомлять и все такое..
     
  13. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Great
    наверное это сработает.. но у меня тогда такой вопрос:
    как найти адреса этих ф-ций? в ДДК их нет, т.е. - они не экспортируемые каким-либо модулем ядра.. где взять их адреса?
     
  14. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Great
    да, это переходник - там SysEnter или int
    но я так понимаю, мне из ядра надо вызывать не саму экспортируемую NtCreateThread, а то место, куда идет вход по sysenter? так вот - как вычислить это место?
     
  15. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Поскольку ZwCreateThread не экспортируется ядром, тебе нужно промапить ntdll, найти там номер ZwCreateThread в SSDT и вызвать ее напрямую из KeServiceDescriptorTable->ntoskrnl.ServiceTable[]
     
  16. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    в KeServiceDescriptorTable->win32k.ServiceTable[]
    набросал примерный код:

    Код (Text):
    1. #include <ntddk.h>
    2. #define DPRINT DbgPrint
    3.  
    4. void DriverUnload(IN PDRIVER_OBJECT DriverObject)
    5. {
    6.     DPRINT ("[+] Driver unloaded");
    7. }
    8.  
    9. typedef PVOID* PNTPROC;
    10. typedef struct _SYSTEM_SERVICE_TABLE
    11. {
    12.     PNTPROC ServiceTable;
    13.     PULONG  CounterTable;
    14.     ULONG   ServiceLimit;
    15.     PUCHAR  ArgumentTable;
    16. }
    17. SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
    18. typedef struct _SERVICE_DESCRIPTOR_TABLE
    19. {
    20.    SYSTEM_SERVICE_TABLE ntoskrnl;  
    21.    SYSTEM_SERVICE_TABLE win32k;    
    22.    SYSTEM_SERVICE_TABLE iis;
    23.    SYSTEM_SERVICE_TABLE unused;    
    24. }
    25. SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;
    26. extern "C" extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
    27.  
    28. typedef void* HWND;
    29. typedef unsigned int UINT, WPARAM, LPARAM;
    30.  
    31. // Только для Windows XP SP2 UP 2600 Free !!
    32. #define NtUserPostMessage_Num 0x11DB
    33.  
    34. #define HWND_BROADCAST 0xFFFF
    35. #define WM_PAINT 0x0F
    36.  
    37. BOOLEAN NTAPI PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
    38. {
    39.     PVOID NtUserPostMessage = KeServiceDescriptorTable->win32k.ServiceTable[ NtUserPostMessage_Num ];
    40.  
    41.     __asm jmp [NtUserPostMessage];
    42. }
    43.  
    44.  
    45. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
    46. {
    47.     DriverObject->DriverUnload = DriverUnload;
    48.     DPRINT("[~] Driver loading");
    49.  
    50.     PostMessage( HWND_BROADCAST, WM_PAINT, 0, 0 );
    51.  
    52.     DPRINT("[+] Driver initialization successful");
    53.     return STATUS_SUCCESS;
    54. }
    UPD: Тут конечно shadow нужна..
    UPD2: номер надо еще and'ануть с 0xFFF чтобы получился индекс сервиса в таблице
     
  17. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Great
    спасибо..

    получается код специфичный для конкретной ОС -
    что не есть хорошо :dntknw:
    мой код должен работать на всех х32 виндах начиная с win2k, с любыми сервиспаками (включая ещё не вышедшие)

    не хотелось бы переходить на код вида:
    if (_WinVer==XXX)
    offset = yyy
    и т.п.

    а кроме того - как вычилять эту константу NtUserPostMessage_Num для других версий винды?


    но всеравно спасибо - хоть какое-то, да решение..
     
  18. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    видимо парсить код user32.PostMessage =(
     
  19. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    ratix
    эти константы получаются динамически путём несложных телодвижений(по крайней мере в 2k и xp). Надо в ntdll найти нужную ф-ию и там первой командой идёт mov eax,xxxxxxxx. это хххххххх и есть искомое число.

    Add
    Упс. А вот из user32.dll эти константы автоматом не очень то достанешь:dntknw:
     
  20. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Дада, придется парсить код PostMessage()