NtReadVirtualMemory函数位于ntdll中,作用就是把用户态的函数调用翻译成相应的系统调用,进入内核态。内核中一般有一个相同名字的处理函数,接收到该类型的系统调用后做实际的工作。
NTSTATUS STDCALL
NtReadVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN ULONG NumberOfBytesToRead,
OUT PULONG NumberOfBytesRead)
{
NTSTATUS Status;
PMDL Mdl;
PVOID SystemAddress;
PEPROCESS Process;
DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
"Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
Buffer,NumberOfBytesToRead);
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_WRITE,
NULL,
UserMode,
(PVOID*)(&Process),
NULL);
if (Status != STATUS_SUCCESS)
{
return(Status);
}
}
struct _EPROCESS
{
/* Microkernel specific process state. */
KPROCESS Pcb;
}
typedef struct _KPROCESS
{
DISPATCHER_HEADER DispatcherHeader; /* 000 */
LIST_ENTRY ProfileListHead; /* 010 */
PHYSICAL_ADDRESS DirectoryTableBase; /* 018 这是cr3*/
}
Mdl = MmCreateMdl(NULL,Buffer, NumberOfBytesToRead);
MmProbeAndLockPages(Mdl,UserMode,IoWriteAccess);
KeAttachProcess(Process);
SystemAddress = MmGetSystemAddressForMdl(Mdl);
memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
KeDetachProcess();
if (Mdl->MappedSystemVa != NULL)
{
MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
}
MmUnlockPages(Mdl);
ExFreePool(Mdl);
ObDereferenceObject(Process);
*NumberOfBytesRead = NumberOfBytesToRead;
return(STATUS_SUCCESS);
}
memcpy(Buffer, BaseAddress, NumberOfBytesToRead);
VOID STDCALL
KeAttachProcess (PEPROCESS Process)
{
KIRQL oldlvl;
PETHREAD CurrentThread;
PULONG AttachedProcessPageDir;
ULONG PageDir;
DPRINT("KeAttachProcess(Process %x)\n",Process);
CurrentThread = PsGetCurrentThread();
if (CurrentThread->OldProcess != NULL)
{
DbgPrint("Invalid attach (thread is already attached)\n");
KEBUGCHECK(0);
}
KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
KiSwapApcEnvironment(&CurrentThread->Tcb, &Process->Pcb);
/* The stack of the current process may be located in a page which is
not present in the page directory of the process we're attaching to.
That would lead to a page fault when this function returns. However,
since the processor can't call the page fault handler 'cause it can't
push EIP on the stack, this will show up as a stack fault which will
crash the entire system.
To prevent this, make sure the page directory of the process we're
attaching to is up-to-date. */
AttachedProcessPageDir = ExAllocatePageWithPhysPage(Process->Pcb.DirectoryTableBase);
MmUpdateStackPageDir(AttachedProcessPageDir, &CurrentThread->Tcb);
ExUnmapPage(AttachedProcessPageDir);
CurrentThread->OldProcess = PsGetCurrentProcess();
CurrentThread->ThreadsProcess = Process;
PageDir = Process->Pcb.DirectoryTableBase.u.LowPart;
DPRINT("Switching process context to %x\n",PageDir);
Ke386SetPageTableDirectory(PageDir);
KeLowerIrql(oldlvl);
}