Описание
Существуют некоторые задачи, которые в режиме пользователя могут быть решены вызовом единственной функции, которая, впрочем, не может быть вызвана из режима ядра. В итоге, порой приходится вручную писать функции, которые в принципе уже существуют с поправкой на режим ядра. В данном примере рассматривается реализация функций GetModuleFileNameEx и NtReadVirtualMemory (начинка ReadProcessMemory) для режима ядра.
Структуры
typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[2];
PVOID Process;
BOOLEAN KernelApcInProgress;
BOOLEAN KernelApcPending;
BOOLEAN UserApcPending;
} KAPC_STATE, *PKAPC_STATE;
extern NTKERNELAPI VOID KeStackAttachProcess(IN PVOID Process, OUT PKAPC_STATE ApcState);
extern NTKERNELAPI VOID KeUnstackDetachProcess(IN OUT PKAPC_STATE ApcState);
Процедуры
NTSTATUS MyNtReadVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength)
{
PVOID ProcObj=NULL;
KAPC_STATE ApcState;
ObReferenceObjectByHandle(ProcessHandle, 0x10, PsProcessType, KernelMode, &ProcObj, NULL);
KeStackAttachProcess(ProcObj, &ApcState);
RtlCopyMemory(Buffer, BaseAddress, BufferLength);
KeUnstackDetachProcess(&ApcState);
ObfDereferenceObject(ProcObj);
return 0;
}
int GetModuleFileNameEx(HANDLE hProcess, HANDLE hModule, PULONG dName, PULONG dNameSize)
{
int rc;
PPROCESS_BASIC_INFORMATION pbi=NULL;
PPEB peb=NULL;
PPEB_LDR_DATA ldrdata=NULL;
PLDR_DATA_TABLE_ENTRY ldrentry=NULL;
// если мы смотрим чужой процесс, то нам недостаточно поставить указатель на буфер. Нам нужно выделить сам буфер, а пользователь не передал нам адрес переменной, которая получит конечный размер...
if ((dNameSize==0)&&(hProcess!=NtCurrentProcess())) return 0;
__try
{
pbi=ExAllocatePoolWithTag(PagedPool, sizeof(PROCESS_BASIC_INFORMATION), 654);
rc=ZwQueryInformationProcess(hProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);
if (rc==STATUS_SUCCESS)
{
if (hProcess==NtCurrentProcess())
{
ldrentry=pbi->PebBaseAddress->Ldr->InLoadOrderModuleList.Flink;
while(1)
{
if ((ldrentry->DllBase==hModule)|(hModule==0)) break;//hModule=0 - имя *.exe файла
if (ldrentry->InLoadOrderModuleList.Flink==NULL)
{
ExFreePool(pbi);
return 0;
}
ldrentry=ldrentry->InLoadOrderModuleList.Flink;
};
*dName=ldrentry->FullDllName.Buffer;
} else
{
SIZE_T j;
PVOID UserPool; //На самом деле это ни какой не UserPool!
UserPool=ExAllocatePoolWithTag(PagedPool, 4096, 1424);
rc=MyNtReadVirtualMemory(hProcess, pbi->PebBaseAddress, UserPool, sizeof(PEB), &j);
peb=UserPool;
rc=MyNtReadVirtualMemory(hProcess, peb->Ldr, UserPool, sizeof(PEB_LDR_DATA), NULL);
ldrdata=UserPool;
rc=MyNtReadVirtualMemory(hProcess, ldrdata->InLoadOrderModuleList.Flink, UserPool, sizeof(LDR_DATA_TABLE_ENTRY), NULL);
ldrentry=UserPool;
while(1){
if ((ldrentry->DllBase==hModule)|(hModule==0)) break;
if (ldrentry->InLoadOrderModuleList.Flink==NULL) {
ExFreePool(UserPool);
ExFreePool(pbi);
return 0;
};
MyNtReadVirtualMemory(hProcess, ldrentry->InLoadOrderModuleList.Flink, ldrentry, sizeof(LDR_DATA_TABLE_ENTRY), NULL);
};
if (dNameSize
*dNameSize=ldrentry->FullDllName.Length;
*dName=ExAllocatePoolWithTag(PagedPool, *dNameSize+2, 654);
MyNtReadVirtualMemory(hProcess, ldrentry->FullDllName.Buffer, *dName, *dNameSize+2, NULL);
DbgPrint("Result = %S", *dName);
//ATTENTION!!! YOU *SHOULD* CALL ExFreePool(*dName)!!!
ExFreePool(UserPool);
}
}
ExFreePool(pbi);
return 1;
} __except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Access Violation in GetModuleFileNameEx!");
}
return 0;
}
// далее идут процедуры данные Point'ом (не совсем то, что нам нужно, но полезно)
void* KMapUserAddressToKernel(IN void* pUserModeAddress, IN ULONG ulSize, OUT PMDL* ppMdl)
{
PMDL pUserModeMdl = NULL;
void* pMappedKernelAddr = NULL;
if (ppMdl == NULL) return NULL;
__try
{
pUserModeMdl = IoAllocateMdl(pUserModeAddress, ulSize, FALSE, FALSE, NULL);
if (pUserModeMdl != NULL)
{
MmProbeAndLockPages(pUserModeMdl, KernelMode, IoModifyAccess);
pMappedKernelAddr = MmMapLockedPages(pUserModeMdl, KernelMode);
if (pMappedKernelAddr != NULL)
{
pMappedKernelAddr = (PVOID) (((ULONG)PAGE_ALIGN(pMappedKernelAddr))+MmGetMdlByteOffset(pUserModeMdl));
*ppMdl = pUserModeMdl;
}
else
{
KUnmapMappedKernelAddress(pUserModeMdl);
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if (pUserModeMdl != NULL) IoFreeMdl(pUserModeMdl);
pMappedKernelAddr = NULL;
}
return pMappedKernelAddr;
}
void KUnmapMappedKernelAddress(IN PMDL pMdl)
{
if (pMdl == NULL) return;
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
}
Copyright
Перепечатка статьи разрешается только с уведомления автора и ссылкой на первоисточник.