Получение данных от NtQueryVirtualMemory и т.п. в KernelMode

Тема в разделе "WASM.NT.KERNEL", создана пользователем m0zg, 31 май 2011.

  1. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    Поставил хук на NtQueryVirtualMemory в ядре. В обработчике нужно вызвать оригинальную ф-цию с классом информации MemoryMappedFilenameInformation,
    (независимо от того, с каким классом MEMORY_INFORMATION_CLASS был вызов из UserMode), затем сравнить полученное имя с "константой" и если оно не совпадает, вернуть оригинальную ф-цию, иначе поправленный результат её выполнения.
    Видимо проблемма в том, что данные, выдаваемые этой функцией должны записываться в UserMode, поэтому если адрес выходного буфера указывает на диапазон KernelMode, её вызов приводит к STATUS_ACCESS_VIOLATION

    Вот здесь http://www.woodmann.com/forum/archive/index.php/t-7661.html человек вроде пытался сделать почти то что мне нужно, но на англицком я так и не понял получилось у него или нет - у меня не работает.

    Код (Text):
    1. ...
    2. fpNtQueryVirtualMemory = (NTQUERYVIRTUALMEMORY) InterlockedExchange( (PLONG) &g_pMappedSystemCallTable[0xB2], (LONG) MyNtQueryVirtualMemory);
    3. ...
    4.  
    5. NTSTATUS
    6. NTAPI
    7. MyNtQueryVirtualMemory(
    8.                        __in HANDLE ProcessHandle,
    9.                        __in PVOID BaseAddress,
    10.                        __in MEMORY_INFORMATION_CLASS MemoryInformationClass,
    11.                        __out_bcount(MemoryInformationLength) PVOID MemoryInformation,
    12.                        __in SIZE_T MemoryInformationLength,
    13.                        __out_opt PSIZE_T ReturnLength
    14.                        )
    15. {
    16. ...
    17. pBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 0); // pBuffer в диапозоне KernelMode
    18.  
    19.             pMdl = IoAllocateMdl(
    20.                 (PVOID)pBuffer,               // PVOID  VirtualAddress
    21.                 PAGE_SIZE,  // ULONG  Length
    22.                 FALSE,              // BOOLEAN  SecondaryBuffer
    23.                 FALSE,              // BOOLEAN  ChargeQuota
    24.                 NULL                // IN OUT PIRP  Irp  OPTIONAL
    25.                 );
    26.                
    27.             //MmBuildMdlForNonPagedPool(pMdl);
    28.  
    29.             MmProbeAndLockPages (
    30.                 pMdl,               // IN OUT PMDL  MemoryDescriptorList
    31.                 KernelMode,         // KPROCESSOR_MODE  AccessMode
    32.                 IoWriteAccess       // LOCK_OPERATION  Operation
    33.                 );
    34.  
    35.             // Map the pages into the process
    36.  
    37.             pMappedBuffer = MmMapLockedPagesSpecifyCache(
    38.                 pMdl,               // PMDL  MemoryDescriptorList
    39.                 UserMode,           // KPROCESSOR_MODE  AccessMode
    40.                 MmCached,           // MEMORY_CACHING_TYPE  CacheType
    41.                 NULL,               // PVOID  BaseAddress
    42.                 FALSE,              // ULONG  BugCheckOnFailure
    43.                 NormalPagePriority  // MM_PAGE_PRIORITY  Priority
    44.                 );
    45.  
    46. pMappedFileName = (PUNICODE_STRING)pMappedBuffer; // pMappedFileName в диапозоне UserMode
    47.  
    48. ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize); //STATUS_ACCESS_VIOLATION
    49. ...
    50. if (0 == _wcsicmp((wchar_t*)((ULONG)pMappedFileName->Buffer + pMappedFileName->Length - g_usModuleName.Length), g_usModuleName.Buffer))
    51. ...
    52. return STATUS_FILE_INVALID;
    53. ...
    54. return fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength);
    55. }
    пробовал еще вот так:
    Код (Text):
    1. NTSTATUS
    2. NTAPI
    3. MyNtQueryVirtualMemory(
    4.                        __in HANDLE ProcessHandle,
    5.                        __in PVOID BaseAddress,
    6.                        __in MEMORY_INFORMATION_CLASS MemoryInformationClass,
    7.                        __out_bcount(MemoryInformationLength) PVOID MemoryInformation,
    8.                        __in SIZE_T MemoryInformationLength,
    9.                        __out_opt PSIZE_T ReturnLength
    10.                        )
    11. {
    12. ...
    13.     hCallerProcessId = PsGetCurrentProcessId();
    14.     CLIENT_ID cid = {hCallerProcessId,NULL};
    15.     OBJECT_ATTRIBUTES attr;
    16.     InitializeObjectAttributes(&attr, NULL, 0, NULL, NULL);
    17. ntStatus = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &attr, &cid);//STATUS_SUCCESS // процесс вызвавший ZwQueryVirtualMemory
    18.  
    19.     PVOID TmpBaseAddress = NULL;
    20.     SIZE_T RegionSize = PAGE_SIZE;
    21. ntStatus = ZwAllocateVirtualMemory(hProcess,&TmpBaseAddress,0,&RegionSize,MEM_COMMIT,PAGE_READWRITE);//STATUS_SUCCESS
    22. pMappedFileName = (PUNICODE_STRING)TmpBaseAddress;
    23. ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize); //STATUS_ACCESS_VIOLATION
    24. //По задумке, данные должны были ВРЕМЕННО попасть в UserMode в тот же вызывающий процесс
    25. }
    В общем вопрос скорее в том, как мне выделить память под буфер для этой функции чтобы в ядре получить результат.
     
  2. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    NtAllocateVirtualMemory?
     
  3. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    А Вы второй пример смотрели? я там уже использовал ZwAllocateVirtualMemory. Память выделяется - толку нет.
     
  4. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    Код исполняется на !IRQL. Совершенно нет разницы юзермод это или K-mode(разница в модуле, тоесть нтос а не нтдлл, но это не связано с сурсом).
     
  5. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    Попробовал сделать так:

    Код (Text):
    1.             pBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 0);
    2.             pMdl = IoAllocateMdl(pBuffer, PAGE_SIZE, FALSE, FALSE, NULL);
    3.             MmBuildMdlForNonPagedPool(pMdl);
    4.             pMappedFileName = (PUNICODE_STRING) MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
    5.             KeInitializeSpinLock(&spinLock);
    6.             KeAcquireSpinLock(&spinLock, &oldIrql);
    7.             ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize);
    8.             KeReleaseSpinLock(&spinLock, oldIrql);
    теперь получаю крэш с IRQL_NOT_LESS_OR_EQUAL
     
  6. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    В перехватчиках Nt-сервисов при вызове оригинальной функции, если вызов пришёл из UM, то режим исполнения тоже будет UM и буфера должны быть выделены в пользовательском а.п., иначе access violation будет, и это by design. Нужно использовать ZwAllocateVirtualMemory() или пуловую память, спроецированную в а.п. текущего процесса. Спинлоки использовать при вызове Nt-сервисов категорически запрещено, особенно если плохо понимаете, что делаете. Откровенно говоря, какой-то особой проблемы я не вижу, с вызовом ZwAllocateVirtualMemory() всё должно прекрасно работать, что именно не получается во втором варианте? Кстати, в этой функции можно просто передать ZwCurrentProcess() вместо хендла процесса, ничего открывать дополнительно не требуется.
     
  7. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    В первом посте во втором варианте как раз пытался это осуществить.
    ZwAllocateVirtualMemory(ZwCurrentProcess(),&TmpBaseAddress,NULL,&RegionSize,MEM_COMMIT,PAGE_READWRITE) == STATUS_SUCCESS
    fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, (PVOID)TmpBaseAddress, PAGE_SIZE, &ReturnSize) == STATUS_ACCESS_VIOLATION

    В первом варианте пробовал.

    В общем ОБА ВАРИАНТА действительно рабочие, нашел я свой косяк - "ReturnSize" указывал на KernelMode =). Поставил NULL - все заработало.
    Спасибо всем за внимание, особенно x64, который по человечески все растолковал и убедил что все должно работать, а то я бы еще неделю искал третий вариант...