Драйвер и NtQuerySystemInformation

Тема в разделе "WASM.NT.KERNEL", создана пользователем Crash, 9 фев 2006.

  1. Crash

    Crash New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2004
    Сообщения:
    73
    Здравствуйте!



    Кто-нибудь знает, как использовать функции MmProbeAndLockPages и MmMapLockedPages?



    Я пишу драйвер, а в нем реализую перехват NtQuerySystemInformation. Системы Windows 2000/XP падают при обращении Диспетчера задач к этой функции. BSOD.

    Видимо проблема с адресом указателя ASystemInformation. Параметр ASystemInformation нужно отобразить на системное адресное пространство и зафиксировать в памяти.

    Делают это вышеперечисленные функции, но я не знаю, как их использовать. Может кто приведет кусок кода?



    Вот код драйвера:


    Код (Text):
    1.  
    2. #include <ntddk.h>
    3.  
    4. typedef UCHAR BYTE;
    5. typedef ULONG DWORD;
    6. typedef DWORD* PDWORD;
    7.  
    8. typedef enum _SYSTEM_INFORMATION_CLASS
    9. {
    10.     SystemBasicInformation = 0,
    11.     SystemPerformanceInformation = 2,
    12.     SystemTimeOfDayInformation = 3,
    13.     SystemProcessInformation = 5,
    14.     SystemProcessorPerformanceInformation = 8,
    15.     SystemInterruptInformation = 23,
    16.     SystemExceptionInformation = 33,
    17.     SystemRegistryQuotaInformation = 37,
    18.     SystemLookasideInformation = 45
    19. } SYSTEM_INFORMATION_CLASS;
    20.  
    21. NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength OPTIONAL);
    22.  
    23. #pragma pack(push,1)
    24.  
    25. typedef struct _far_jmp
    26. {
    27.     BYTE  PushOp;
    28.     PVOID PushArg;
    29.     BYTE  RetOp;
    30. } far_jmp, *pfar_jmp;
    31.  
    32. typedef struct _OldCode
    33. {
    34.     USHORT One;
    35.     ULONG  TWO;
    36. } OldCode, *POldCode;
    37.  
    38. #pragma pack(pop)
    39.  
    40. OldCode OldNtQuerySystemInformation;
    41. PVOID NewNtQuerySystemInformationAdr;
    42.  
    43. //True функция для перехватываемой функции
    44. NTSTATUS TrueNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS ASystemInformationClass,PVOID ASystemInformation,DWORD ASystemInformationLength,PDWORD AReturnLength)
    45. {
    46.     ULONG    CR0Reg;
    47.     NTSTATUS Result;
    48.     POldCode Func = (POldCode)NtQuerySystemInformation;
    49.     pfar_jmp Fnjp = (pfar_jmp)NtQuerySystemInformation;
    50.    
    51.     __asm
    52.     {
    53.         cli                     // запрещаем прерывания
    54.         mov eax, cr0
    55.         mov CR0Reg,eax
    56.         and eax,0xFFFEFFFF      // сбросить WP bit
    57.         mov cr0, eax
    58.     }
    59.  
    60.     // снимаем перехват
    61.     Func->One = OldNtQuerySystemInformation.One;
    62.     Func->TWO = OldNtQuerySystemInformation.TWO;
    63.  
    64.     Result = NtQuerySystemInformation(ASystemInformationClass,ASystemInformation,AS ystemInformationLength,AReturnLength);
    65.  
    66.     //устанавливаем перехват
    67.     Fnjp->PushOp  = 0x68;
    68.     Fnjp->PushArg = NewNtQuerySystemInformationAdr;
    69.     Fnjp->RetOp   = 0xC3;
    70.  
    71.     __asm
    72.     {
    73.         mov eax, CR0Reg    
    74.         mov cr0, eax            // востановить содержимое CR0
    75.         sti                     // разрешаем прерывания
    76.     }
    77.  
    78.     return Result;
    79. }
    80.  
    81. //функция - обработчик перехвата
    82. NTSTATUS NewNtQuerySystemInformation(SYSTEM_INFORMATION_CLASS ASystemInformationClass,PVOID ASystemInformation,DWORD ASystemInformationLength,PDWORD AReturnLength)
    83. {
    84.     if(!MmIsAddressValid(ASystemInformation))
    85.         return STATUS_INVALID_PARAMETER;
    86.     __try
    87.     {
    88.            //Здесь будет реализована обработка...
    89.     }
    90.     __except(EXCEPTION_EXECUTE_HANDLER)
    91.     {
    92.         return STATUS_INVALID_PARAMETER;
    93.     }
    94.     return TrueNtQuerySystemInformation(ASystemInformationClass,ASystemInformatio n,ASystemInformationLength,AReturnLength);
    95. }
    96.  
    97. VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
    98. {
    99.     ULONG CR0Reg;
    100.     NTSTATUS Result;
    101.     POldCode Func = (POldCode)NtQuerySystemInformation;
    102.    
    103.     __asm
    104.     {
    105.         cli                     // запрещаем прерывания
    106.         mov eax, cr0
    107.         mov CR0Reg,eax
    108.         and eax,0xFFFEFFFF      // сбросить WP bit
    109.         mov cr0, eax
    110.     }
    111.  
    112.     // снимаем перехват
    113.     Func->One = OldNtQuerySystemInformation.One;
    114.     Func->TWO = OldNtQuerySystemInformation.TWO;
    115.  
    116.     __asm
    117.     {
    118.         mov eax, CR0Reg    
    119.         mov cr0, eax            // востановить содержимое CR0
    120.         sti                     // разрешаем прерывания
    121.     }
    122.  
    123.     return;
    124. }
    125.  
    126. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
    127. {
    128.     ULONG CR0Reg;
    129.     POldCode Func = (POldCode)NtQuerySystemInformation;
    130.     pfar_jmp Fnjp = (pfar_jmp)NtQuerySystemInformation;
    131.    
    132.     //устанавливаем перехват  
    133.     __asm
    134.     {
    135.         cli                     // запрещаем прерывания
    136.         mov eax, cr0
    137.         mov CR0Reg,eax
    138.         and eax,0xFFFEFFFF      // сбросить WP bit
    139.         mov cr0, eax
    140.     }
    141.  
    142.     NewNtQuerySystemInformationAdr = NewNtQuerySystemInformation;
    143.  
    144.     OldNtQuerySystemInformation.One  = Func->One;
    145.     OldNtQuerySystemInformation.TWO  = Func->TWO;
    146.  
    147.     Fnjp->PushOp  = 0x68;
    148.     Fnjp->PushArg = NewNtQuerySystemInformationAdr;
    149.     Fnjp->RetOp   = 0xC3;
    150.  
    151.  
    152.     __asm
    153.     {
    154.         mov eax, CR0Reg    
    155.         mov cr0, eax            // востановить содержимое CR0
    156.         sti                     // разрешаем прерывания
    157.     }
    158.    
    159.     //назначаем процедуру выгрузки драйвера
    160.     DriverObject->DriverUnload = DriverUnload;
    161.  
    162.     return STATUS_SUCCESS;
    163. }
    164.  
     
  2. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Не используй кривой способ хуков с постоянной установкой/снятием джампа. Он годится только для юзермода, и только если нужна максимальная простота. Юзай лучше SDT хуки.

    Вторая твоя ошибка в том, что нельзя использовать MmIsAddressValid для юзермодных адресов, эта функция подходит только для nonpaged пула.

    И для того чтобы получить в обработчике хука доступ к данным, совсем не надо ничего переотображать. А если так охото, то в общем случае выглядит так:


    Код (Text):
    1.  
    2. Mdl = IoAllocateMdl(Addr, Len, FALSE, FALSE, NULL);
    3. if (Mdl)
    4. {
    5.    __try
    6.    {
    7.       MmProbeAndLockPages(Mdl, UserMode, IoWriteAccess);
    8.      
    9.       SysAddr = MmGetSystemAddressForMdl(Mdl);
    10.      
    11.       if (SysAddr)
    12.       {
    13.         //тут делаем что надо
    14.                 }
    15.      
    16.       MmUnlockPages(Mdl);
    17.    }
    18.    __except(EXCEPTION_EXECUTE_HANDLER){}
    19.    IoFreeMdl(Mdl);
    20. }
    21.  
     
  3. Crash

    Crash New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2004
    Сообщения:
    73
    А какой есть другой способ получения доступа к данным в обработчике?
     
  4. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    ЛОЛ!

    Способ очень простой, прость бери и получай доступ :)

    mov eax, [addr]
     
  5. blockhead

    blockhead New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2007
    Сообщения:
    11
    Почему не использовать кривой способ хуков с постоянной установкой/снятием джампа ?
    Цитата - Перехват через SDT несомненно удобен, но у него имеется один недостаток - его легко обнаружить и удалить.
    А как иначе перехватывать, если не через SDT и не через "кривые" хуки ?
     
  6. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Время, возможность ошибки => BSoD.
    Я делал вот так:
    Код (Text):
    1. void WriteFarJmp(PUCHAR pWriteAddr, ULONG dwJmpAddr){
    2.         *pWriteAddr = 0x68;
    3.         pWriteAddr++;
    4.         *(PULONG)pWriteAddr = dwJmpAddr;
    5.         pWriteAddr += 4;
    6.         *pWriteAddr = 0xC3;
    7. }
    8.  
    9. void HookFunction(){
    10.     ULONG dwCopySize = 0, i;
    11.  
    12.     NtYieldExecution = *KeServiceDescriptorTable->NtoskrnlTable.ServiceTable[SYSCALL_NUMBER(ZwYieldExecution)];
    13.     for (i = 0; i < COMMAND_COUNT; i++)
    14.         dwCopySize += SizeOfCode((PUCHAR)NtYieldExecution_New + dwCopySize, NULL);
    15.     while (dwOldCodeSize < dwCopySize + 6)
    16.         dwOldCodeSize += SizeOfCode((PUCHAR)NtYieldExecution + dwOldCodeSize, NULL);
    17.     NtYieldExecution_Old = ExAllocatePool(NonPagedPool, dwOldCodeSize + 6);
    18.     if (!NtYieldExecution_Old)
    19.         return ;
    20.     memcpy(NtYieldExecution_Old, NtYieldExecution, dwOldCodeSize);
    21.     WriteFarJmp((PUCHAR)NtYieldExecution_Old + dwOldCodeSize, (ULONG)NtYieldExecution + dwOldCodeSize);
    22.     MODIFY_START
    23.     memcpy((PVOID)NtYieldExecution, NtYieldExecution_New, dwCopySize);
    24.     WriteFarJmp((PUCHAR)NtYieldExecution + dwCopySize, (ULONG)NtYieldExecution_New + dwCopySize);
    25.     MODIFY_END
    26. }
    27.  
    28. void UnHookFunction(){
    29.     if (!NtYieldExecution_Old)
    30.         return ;
    31.     memcpy(NtYieldExecution, NtYieldExecution_Old, dwOldCodeSize);
    32.     ExFreePool(NtYieldExecution_Old);
    33. }
    Вызов оригинальной функции очень прост:
    Код (Text):
    1. NTSTATUS NtYieldExecution_New(){
    2.     DbgPrint("NtYieldExecution called.");
    3.     return ((TNtYieldExecution)(NtYieldExecution_Old))();
    4. }
     
  7. blockhead

    blockhead New Member

    Публикаций:
    0
    Регистрация:
    21 фев 2007
    Сообщения:
    11
    Спасибо за код, но можно в кратце узнать работу функции WriteFarJmp. И код не совсем полный, в частности, что скрывается за MODIFY_START и MODIFY_END, что - то вроде
    Код (Text):
    1. __asm
    2. {
    3.         cli
    4.     mov eax, cr0
    5.     mov CR0Reg,eax
    6.     and eax,0xFFFEFFFF
    7.     mov cr0, eax
    8. }
    и
    Код (Text):
    1. __asm
    2. {
    3.         sti
    4.     mov eax, CR0Reg    
    5.     mov cr0, eax            // востановить содержимое CR0
    6. }
    соответсвенно или я ошибаюсь ? И dwOldCodeSize не объявлена, но это ладно главное ее начальное значение - 0 ?
     
  8. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Код (Text):
    1. PVOID NtYieldExecution_Old = NULL;
    2. ULONG dwOldCodeSize = 0;
    3. PVOID NtYieldExecution = NULL;
    По адресу pWriteAddr, записывает push pJmpAddr/ret. Что при выполнении сделает скачек на pJmpAddr.
    Код (Text):
    1. #define MODIFY_START _asm cli\
    2.                      _asm mov eax, cr0\
    3.                      _asm push eax\
    4.                      _asm and eax, 0xFFFEFFFF\
    5.                      _asm mov cr0, eax
    6.  
    7. #define MODIFY_END _asm pop eax\
    8.                    _asm mov cr0, eax\
    9.                    _asm sti
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Код (Text):
    1. KfRaiseIrql( HIGH_LEVEL );
    2. __asm cli;
    ?
     
  10. k3internal

    k3internal New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2007
    Сообщения:
    607
    Great
    <__asm cli;>

    После этого тебе уже ничего не страшно. Зачем тогда уровень прерывания задирать ?
    Да, кстати, это только на однопроцессорных системах поможет
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    k3internal
    ну всетаки лучше на всякий пожарный и IRQL поднять.
    а если префикс LOCK ? хотя не удастся записать 6 байт в одну команду. так что есть маленький шанс того, что кто-то вызовет функцию пока мы еще не записали хук.
     
  12. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    А еще у какого-то потока может закончиться время между инструкциями прямо посередине хука. И против этого никакой lock не поможет

    хм :\
     
  13. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Вот куплю проц 2ядерный и буду тестить :)
     
  14. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    если бы можно было записать это одной командой, то LOCK бы помог. А для двух команд его ставить бесполезно.
    зы. Какое нафиг время? А как же CLI и IRQL на уровне HIGH? Выше DPC/Dispatch потоки вообще не планируются. ПРо HIGH я вообще молчу..