Поставил хук на NtQueryVirtualMemory в ядре. В обработчике нужно вызвать оригинальную ф-цию с классом информации MemoryMappedFilenameInformation, (независимо от того, с каким классом MEMORY_INFORMATION_CLASS был вызов из UserMode), затем сравнить полученное имя с "константой" и если оно не совпадает, вернуть оригинальную ф-цию, иначе поправленный результат её выполнения. Видимо проблемма в том, что данные, выдаваемые этой функцией должны записываться в UserMode, поэтому если адрес выходного буфера указывает на диапазон KernelMode, её вызов приводит к STATUS_ACCESS_VIOLATION Вот здесь http://www.woodmann.com/forum/archive/index.php/t-7661.html человек вроде пытался сделать почти то что мне нужно, но на англицком я так и не понял получилось у него или нет - у меня не работает. Код (Text): ... fpNtQueryVirtualMemory = (NTQUERYVIRTUALMEMORY) InterlockedExchange( (PLONG) &g_pMappedSystemCallTable[0xB2], (LONG) MyNtQueryVirtualMemory); ... NTSTATUS NTAPI MyNtQueryVirtualMemory( __in HANDLE ProcessHandle, __in PVOID BaseAddress, __in MEMORY_INFORMATION_CLASS MemoryInformationClass, __out_bcount(MemoryInformationLength) PVOID MemoryInformation, __in SIZE_T MemoryInformationLength, __out_opt PSIZE_T ReturnLength ) { ... pBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 0); // pBuffer в диапозоне KernelMode pMdl = IoAllocateMdl( (PVOID)pBuffer, // PVOID VirtualAddress PAGE_SIZE, // ULONG Length FALSE, // BOOLEAN SecondaryBuffer FALSE, // BOOLEAN ChargeQuota NULL // IN OUT PIRP Irp OPTIONAL ); //MmBuildMdlForNonPagedPool(pMdl); MmProbeAndLockPages ( pMdl, // IN OUT PMDL MemoryDescriptorList KernelMode, // KPROCESSOR_MODE AccessMode IoWriteAccess // LOCK_OPERATION Operation ); // Map the pages into the process pMappedBuffer = MmMapLockedPagesSpecifyCache( pMdl, // PMDL MemoryDescriptorList UserMode, // KPROCESSOR_MODE AccessMode MmCached, // MEMORY_CACHING_TYPE CacheType NULL, // PVOID BaseAddress FALSE, // ULONG BugCheckOnFailure NormalPagePriority // MM_PAGE_PRIORITY Priority ); pMappedFileName = (PUNICODE_STRING)pMappedBuffer; // pMappedFileName в диапозоне UserMode ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize); //STATUS_ACCESS_VIOLATION ... if (0 == _wcsicmp((wchar_t*)((ULONG)pMappedFileName->Buffer + pMappedFileName->Length - g_usModuleName.Length), g_usModuleName.Buffer)) ... return STATUS_FILE_INVALID; ... return fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength); } пробовал еще вот так: Код (Text): NTSTATUS NTAPI MyNtQueryVirtualMemory( __in HANDLE ProcessHandle, __in PVOID BaseAddress, __in MEMORY_INFORMATION_CLASS MemoryInformationClass, __out_bcount(MemoryInformationLength) PVOID MemoryInformation, __in SIZE_T MemoryInformationLength, __out_opt PSIZE_T ReturnLength ) { ... hCallerProcessId = PsGetCurrentProcessId(); CLIENT_ID cid = {hCallerProcessId,NULL}; OBJECT_ATTRIBUTES attr; InitializeObjectAttributes(&attr, NULL, 0, NULL, NULL); ntStatus = ZwOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &attr, &cid);//STATUS_SUCCESS // процесс вызвавший ZwQueryVirtualMemory PVOID TmpBaseAddress = NULL; SIZE_T RegionSize = PAGE_SIZE; ntStatus = ZwAllocateVirtualMemory(hProcess,&TmpBaseAddress,0,&RegionSize,MEM_COMMIT,PAGE_READWRITE);//STATUS_SUCCESS pMappedFileName = (PUNICODE_STRING)TmpBaseAddress; ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize); //STATUS_ACCESS_VIOLATION //По задумке, данные должны были ВРЕМЕННО попасть в UserMode в тот же вызывающий процесс } В общем вопрос скорее в том, как мне выделить память под буфер для этой функции чтобы в ядре получить результат.
А Вы второй пример смотрели? я там уже использовал ZwAllocateVirtualMemory. Память выделяется - толку нет.
Код исполняется на !IRQL. Совершенно нет разницы юзермод это или K-mode(разница в модуле, тоесть нтос а не нтдлл, но это не связано с сурсом).
Попробовал сделать так: Код (Text): pBuffer = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, 0); pMdl = IoAllocateMdl(pBuffer, PAGE_SIZE, FALSE, FALSE, NULL); MmBuildMdlForNonPagedPool(pMdl); pMappedFileName = (PUNICODE_STRING) MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority); KeInitializeSpinLock(&spinLock); KeAcquireSpinLock(&spinLock, &oldIrql); ntStatus = fpNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryMappedFilenameInformation, pMappedFileName, PAGE_SIZE, &ReturnSize); KeReleaseSpinLock(&spinLock, oldIrql); теперь получаю крэш с IRQL_NOT_LESS_OR_EQUAL
В перехватчиках Nt-сервисов при вызове оригинальной функции, если вызов пришёл из UM, то режим исполнения тоже будет UM и буфера должны быть выделены в пользовательском а.п., иначе access violation будет, и это by design. Нужно использовать ZwAllocateVirtualMemory() или пуловую память, спроецированную в а.п. текущего процесса. Спинлоки использовать при вызове Nt-сервисов категорически запрещено, особенно если плохо понимаете, что делаете. Откровенно говоря, какой-то особой проблемы я не вижу, с вызовом ZwAllocateVirtualMemory() всё должно прекрасно работать, что именно не получается во втором варианте? Кстати, в этой функции можно просто передать ZwCurrentProcess() вместо хендла процесса, ничего открывать дополнительно не требуется.
В первом посте во втором варианте как раз пытался это осуществить. 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, который по человечески все растолковал и убедил что все должно работать, а то я бы еще неделю искал третий вариант...