Вызов функций из ntdll

Тема в разделе "WASM.BEGINNERS", создана пользователем nikifar, 18 май 2009.

  1. nikifar

    nikifar New Member

    Публикаций:
    0
    Регистрация:
    18 май 2009
    Сообщения:
    6
    Здравствуйте, я новичёк в программировании драйверов. Мне нужно перехватить окно в котором осуществляется ввод(в user mode GetForegroundWindow) т.е. нужно вызвать NtUserGetForegroundWindow(ранее этот вопрос обсуждался на форуме тема "Как определить активное акно",но я попробовал, и получил BSOD). Ещё я пробую дёргать эту функцию из SSDT, но она возвращает 0. Вот мой код :
    Код (Text):
    1. PVOID GetInfoTable(ULONG ATableType)
    2. {
    3.   ULONG mSize = 0x4000;
    4.   PVOID mPtr = NULL;
    5.   NTSTATUS St;
    6.   do
    7.   {
    8.      mPtr = ExAllocatePool(PagedPool, mSize);
    9.      memset(mPtr, 0, mSize);
    10.      if (mPtr)
    11.      {
    12.         St = ZwQuerySystemInformation(ATableType, mPtr, mSize, NULL);
    13.      } else return NULL;
    14.      if (St == STATUS_INFO_LENGTH_MISMATCH)
    15.      {
    16.         ExFreePool(mPtr);
    17.         mSize = mSize * 2;
    18.      }
    19.   } while (St == STATUS_INFO_LENGTH_MISMATCH);
    20.   if (St == STATUS_SUCCESS) return mPtr;
    21.   ExFreePool(mPtr);
    22.   return NULL;
    23. }
    24.  
    25.  
    26. HANDLE GetCsrPid()
    27. {
    28.   HANDLE Process, hObject;
    29.   HANDLE CsrId = (HANDLE)0;
    30.   OBJECT_ATTRIBUTES obj;
    31.   CLIENT_ID cid;
    32.   UCHAR Buff[0x100];
    33.   POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff;
    34.   PSYSTEM_HANDLE_INFORMATION_EX Handles;
    35.   ULONG r;
    36.  
    37.   Handles = GetInfoTable(SystemHandleInformation);
    38.  
    39.   if (!Handles) return CsrId;
    40.  
    41.   for (r = 0; r < Handles->NumberOfHandles; r++)
    42.   {
    43.     if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
    44.     {
    45.       InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
    46.  
    47.       cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
    48.       cid.UniqueThread = 0;
    49.  
    50.       if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
    51.       {
    52.         if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle,NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ACCESS)))
    53.         {
    54.           if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL)))
    55.           {
    56.             if (ObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
    57.             {
    58.               CsrId = (HANDLE)Handles->Information[r].ProcessId;
    59.             }
    60.           }
    61.  
    62.           ZwClose(hObject);
    63.         }
    64.  
    65.         ZwClose(Process);
    66.       }
    67.     }
    68.   }
    69.  
    70.   ExFreePool(Handles);
    71.   return CsrId;
    72. }
    73.  
    74. VOID GetActiveWindowHandle(IN PDEVICE_OBJECT DeviceObject, PVOID Context)
    75. {
    76.     NTSTATUS status;
    77.     HANDLE wnd;
    78.  
    79.     status = PsLookupProcessByProcessId((ULONG)GetCsrPid(), &crsEProc);
    80.         if (!NT_SUCCESS( status ))
    81.     {
    82.         DbgPrint("PsLookupProcessByProcessId() error\n");
    83.     }
    84.    
    85.     DbgPrint("Process ID = %d", (ULONG)GetCsrPid());
    86.  
    87.     KeAttachProcess(crsEProc);
    88.     originalGetForegroud = (_NtUserGetForegroundWindow_)KeServiceDescriptorTableShadow[1].ServiceTable[0x194];
    89.         DbgPrint("WND = %x", originalGetForegroud());
    90.     KeDetachProcess();
    91. }
     
  2. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    нельзя так делать, нужна Zw-обертка, которая через int2e/sysenter сделает вызов
     
  3. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Во-вторых (сорри, что двумя постами) по-моему поток должен быть ГУЙным потоком, чтоб такие gdi API ядерные вызывать.
     
  4. nikifar

    nikifar New Member

    Публикаций:
    0
    Регистрация:
    18 май 2009
    Сообщения:
    6
    Как мне сделать Zw обёртку ? И как(откуда) мне взять GUI поток ??
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Универсальная обертка, пользуйся
    Код (Text):
    1. __declspec(naked)
    2. NTSTATUS
    3. _cdecl
    4. ZwXXX(
    5.   IN ULONG                SdtNumber,
    6.   ... )
    7. {
    8.     __asm
    9.     {
    10.         mov eax, [esp+4]
    11.         lea edx, [esp+8]
    12.         int 0x2e
    13.         ret
    14.     }
    15. }
    Юзать, например, так:
    Первый параметр - номер в ссдт (вместе с полем номера таблицы), остальные параметры - аргументы (любое число).
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Стуб("Zw обёртка") не нужен. Насчёт GUI-треда верно сказано, при первом вызове стуба выполняется не экспортируемая PsConvertToGuiThread(), собственно и выполняющая необходимую инициализацию. Нужно найти KiSystemService из любого экспортируемого стуба и её юзать, либо Int 0x2e использовать(PreviousMode в этом случае будет установлен в зависимости от селектора кодового сегмента, в KernelMode). Использовать Sysenter нельзя, ибо поток прыгнет в юзермод после отработки.
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    А чтобы юзать - да, нужен гуи поток.
    Я щас не поленился и написал тестовый дров.
    Берешь самую частовызываемую функцию ntos sdt (это NtWaitForMultipleObjects и NtClose), в обработчике хука смотришь в обработчике - если поток GUI (Thread->ServiceTable != KeServiceDescriptorTable), тогда вызываешь ZwXXX (GetForegroundWindow) и сигналишь контрольный эвент, иначе ничего не делаешь.
    А в кодесе обычном ставишь хук на NtWaitForMultipleObjects и ждешь на контрольном эвенте.
    Примерный код:

    Код (Text):
    1. //
    2. // всякие нужные глобальные переменные :)
    3. //
    4.  
    5. ULONG nGetForegroundWindow;
    6.  
    7. ULONG ServiceTableOffset;
    8. PVOID OldSdt;
    9. KEVENT SynchEvent;
    10.  
    11. ULONG ExecutedOK = FALSE;
    12.  
    13. // Сишный враппер
    14. VOID xTest()
    15. {
    16.     PETHREAD Thread = PsGetCurrentThread();
    17.     PEPROCESS Process = PsGetCurrentProcess();
    18.  
    19.     KdPrint(("In NewSdt()\n"));
    20.     KdPrint(("Thread = %p, Process = %p\n", Thread, Process));
    21.  
    22.     // Это гуи поток?
    23.    
    24.     PVOID Table = *(PVOID*)((PUCHAR)Thread + ServiceTableOffset);
    25.     if (Table == KeServiceDescriptorTable)
    26.     {
    27.         KdPrint(("Non-GUI thread\n"));
    28.         return;
    29.     }
    30.  
    31.     //
    32.     // ДА-дА! Это гуи поток
    33.     //
    34.  
    35.     KdPrint(("In GUI thread!\n"));
    36.  
    37.     // Делаем что нам надо
    38.     PVOID Wnd = (PVOID) ZwXXX (nGetForegroundWindow);
    39.     KdPrint(("Wnd = %p\n", Wnd));
    40.  
    41.     ExecutedOK = 1;
    42.     KeSetEvent (&SynchEvent, 0, FALSE);
    43. }
    44.  
    45. // Обработчик SDT
    46. __declspec(naked) void NewSdt()
    47. {
    48.     __asm
    49.     {
    50.         cmp [ExecutedOK], 1
    51.         jz _1
    52.  
    53.         call xTest
    54.  
    55. _1:
    56.         jmp [OldSdt]
    57.     }
    58. }
    59.  
    60. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
    61. {
    62.     // демонстрационный хард-код ;(
    63.     ULONG Major, Minor;
    64.     PsGetVersion (&Major, &Minor, 0, 0);
    65.     if (Major == 5 && Minor == 1)
    66.         nGetForegroundWindow = 0x1194;
    67.     else if (Major == 5 && Minor == 2)
    68.         nGetForegroundWindow = 0x1193;
    69.     else
    70.     {
    71.         KdPrint(("Unknown windows version %d.%d\n", Major, Minor));
    72.         return STATUS_INVALID_PARAMETER;
    73.     }
    74.  
    75.     // Ищем оффсет Thread->ServiceTable
    76.     PUCHAR Thread = (PUCHAR) PsGetCurrentThread();
    77.     for (ULONG i=0; i<PAGE_SIZE; i++)
    78.     {
    79.         PVOID *p = (PVOID*)(Thread + i);
    80.         if (MmIsAddressValid (p))
    81.         {
    82.             if (*p == KeServiceDescriptorTable)
    83.             {
    84.                 ServiceTableOffset = i;
    85.                 KdPrint(("ServiceTableOffset = %lx\n", ServiceTableOffset));
    86.                 break;
    87.             }
    88.         }
    89.     }
    90.  
    91.     if (!ServiceTableOffset)
    92.     {
    93.         KdPrint(("ServiceTableOffset not found!\n"));
    94.         return STATUS_UNSUCCESSFUL;
    95.     }
    96.  
    97.     // Ищем номер NtWaitForMultipleObjects
    98.     ULONG nSdt = GetFunctionSdtNumber ("NtWaitForMultipleObjects");
    99.     if (!nSdt)
    100.     {
    101.         KdPrint(("NtCreateFile not found!\n"));
    102.         return STATUS_UNSUCCESSFUL;
    103.     }
    104.  
    105.     // Инициализируем синхронизирующий эвент
    106.     KeInitializeEvent (&SynchEvent, SynchronizationEvent, FALSE);
    107.  
    108.     // Хук SDT
    109.     OldSdt = KeServiceDescriptorTable[0].ServiceTable[nSdt];
    110.     KeServiceDescriptorTable[0].ServiceTable[nSdt] = NewSdt;
    111.  
    112.     // Ждем пока обработчик найдет гуи поток и выполнит что нам надо
    113.     KeWaitForSingleObject (&SynchEvent, Executive, KernelMode, FALSE, NULL);
    114.  
    115.     // Снимаем хук
    116.     KeServiceDescriptorTable[0].ServiceTable[nSdt] = OldSdt;
    117.  
    118.     // На всякий случай ждем - вдруг какие-то потоки еще застряли внутри нашего хука
    119.     // Не очень хорошо, но для демонстрационных целей сойдет
    120.     for (int i=0; i<5; i++)
    121.     {
    122.         LARGE_INTEGER Timeout = {-10000 * 100, -1};
    123.         KeDelayExecutionThread (KernelMode, FALSE, &Timeout);
    124.         ZwYieldExecution();
    125.     }
    126.  
    127.     return STATUS_UNSUCCESSFUL;
    128. }
    PS. Как оказалось NtWaitForMultipleObjects вызывается часто из VMwareUser.exe, а вот NtClose - из WinLogon. Она больше подходит для реальной системы
    PPS. winlogon и NtClose что-то тоже иногда возвращают ноль. вообщем выполнять пока будет не ноль)
    Как-то не очень получилось..
     
  8. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Clerk
    Искать кисистемсервис смысла нет. Насчет PsConvertToGuiThread - проще уж найти GUI-поток и подцепиться к нему. Все равно потоки процесса System не конвертятся. Даже если аттачнуть к csrss. Почему - хз.
    См код в посте выше
    Правда? А почему ты дальше пишешь про int 2e/call KiSystemService?
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Great
    Если тред GUI, то не нужна. Для вызова ядерного сервиса не теневого никакой стуб не нужен, я это имел ввиду.
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    *нужна
     
  11. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Ээ.. как это не нужен ? Стаб всегда нужен для вызова любых сервисов ...
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    barton
    Зачем он нужен, если поток нормальный(уточняю: стек ядерный, селекторы тоже, прев. моде соответствующий) ?
     
  13. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Clerk

    Почему PreviousMode соответствующий ? Чему соответствующий ?
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Если нужны проверки, тогда = UserMode, если такие проверки не нужны тогда KernelMode.
    Тоесть по вашему если я хочу к примеру выполнить NtConnectPort() я её не смогу заюзать ?
     
  15. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Не особо понял.. Ты видимо хочешь найти частный случай, доказав, что все-таки можно из ядра юзать sst-сервисы напрямую, без всяких оберток, нарушая весь принцип вызовы системных сервисов. Заодно, обьяснив ТС что такое previous mode, что такое ядерный стек и прочие совершенно не нужные ему в контексте данной задачи вещи, вместо того, чтоб юзать обертку, которая дает тебе возможность не думать ни о каких previousmode
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    barton
    Я ничего не хочу доказать, просто ваше мнение интересно(я то при своём). Юзайте что хотите. Тока вот у стуба недостаток - если я юзаю NtOpenProcess() как функцию, а не как сервис, то я к сст не обращаюсь. Если я её юзаю через стуб как сервис при активной проактивке я попадаю в его логово через сст, а дальше что делать с потоком решит фаерволл. Согласитесь в большинстве случаев это главное требование.)
     
  17. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Я понял. Мне интересно было то, что я вдруг подумал, что меня проглючило насчет previous mode и функции реально можно всегда вызывать без оберток. Проглючило с утра. Если интересно именно мое мнение, то оно насчет этого такое:
    если опять "обходы фаерволов" брать и прочую хэкерную штуку, то конечно лучше вообще тогда NtOpenProcess написать самопальную. На ассемблере обязательно или в опкодах=) Я не сторонник нарушения логики кода из-за внешних требований типа обхода фаерволов. Лучше вынести снятие хуков в одну абстрагированую задачу, снять хуки, а потом юзать нормальный документированый код как другую абстрагированую задачу.
    Это типа как с крипторами. На вебхаке. Советуют прям в коде бота делать шифрование строк и мусор для антиреверса. Если задача№1 == "сделать покрипченого бота", то я бы предпочел бы сделать отдельно абстрагированый от задачи№1 криптор и абстрагированого от задачи№1 бота, совместив их потом абстрагированым от 1 и 2 части механизмом)
     
  18. barton

    barton New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2008
    Сообщения:
    164
    Адрес:
    Czechoslovakia
    Хотя, есть конечно такое понятие, как "минусы насталько несущественны, а плюсов настолько много, что можно принебречь". Может быть в данной задаче оно как раз имеет смысл.
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    barton
    Имхо после прочтения этого топега и на руткитсах я пришёл к выводу что вы не осознаёте суть механизма вызова системных сервисов, дальнейшая дискуссия невозможна.
     
  20. nikifar

    nikifar New Member

    Публикаций:
    0
    Регистрация:
    18 май 2009
    Сообщения:
    6
    Спасибо за пояснения. Но как мне вызвать NtUserGetForegroundWindow в определённый момет, т.е. когда я захочу, а не когда будет вызвана KeWaitForMultipleObjects. ?
    Как мне можно найти GUI поток в котором я смогу вызывать свою функцию.