这里是参考链接
https://www.bilibili.com/video/av26193169?t=992&p=19
这篇博客是根据 这个 教程写的
然后 大佬 说了一个函数 感觉挺有必要注意的
if (!MmIsAddressValid(DbgDir))
break;
这样判断内存是否可用 其实是不对的
这个内存 只会判断 这个地址是否有效 而 我们读入的内存是r3层的
如果 这个 内存 转换进了 物理层 而出现了缺页
那么 这个函数 判断不出来 结果会让我们 蓝屏
正确的应该这样写
__try
{
ProbeForRead((processbaseaddr+offset),sizeof(readcode),1);
RtlCopyMemory((PVOID)readcode, (PVOID)(processbaseaddr + offset), sizeof(readcode));
}
__except (1)
{
DbgPrint("Memory is error\n");
}
这样就能看这个内存可读不可读了
然后整体代码就是
#include<ntifs.h>
#include<windef.h>
NTKERNELAPI
PVOID
PsGetProcessSectionBaseAddress(
__in PEPROCESS Process
);
BYTE readcode[4] = {0};
ULONG offset = 0x10;
VOID MyProcessNotift(HANDLE ParentId,HANDLE ProcessId,BOOLEAN Create)
{
if (Create&&ProcessId!=4&&ProcessId!=0)
{
PEPROCESS tempEp = NULL;
NTSTATUS status = STATUS_SUCCESS;
PUCHAR processbaseaddr = NULL;
KAPC_STATE temp_stack = { 0 };
status = PsLookupProcessByProcessId(ProcessId,&tempEp);
if (tempEp)
{
ObDereferenceObject(tempEp);
processbaseaddr = (PUCHAR)PsGetProcessSectionBaseAddress(tempEp);
if (!processbaseaddr)
{
DbgPrint("get process addr file!\n");
return;
}
RtlZeroMemory(readcode, sizeof(readcode));
KeStackAttachProcess(tempEp, &temp_stack);
__try
{
ProbeForRead((processbaseaddr+offset),sizeof(readcode),1);
RtlCopyMemory((PVOID)readcode, (PVOID)(processbaseaddr + offset), sizeof(readcode));
}
__except (1)
{
DbgPrint("Memory is error\n");
}
KeUnstackDetachProcess(&temp_stack);
for (int i = 0; i < sizeof(readcode); i++)
{
DbgPrint("read %x", readcode[i]);
}
return;
}
}
}
VOID Unload(PDRIVER_OBJECT driver)
{
PsSetCreateProcessNotifyRoutine(MyProcessNotift, TRUE);
DbgPrint("Unload\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
NTSTATUS status = STATUS_SUCCESS;
status = PsSetCreateProcessNotifyRoutine(MyProcessNotift, FALSE);
driver->DriverUnload = Unload;
if (!NT_SUCCESS(status))
{
DbgPrint("creat processNotify Failed\n");
}
return STATUS_SUCCESS;
}
我们获取的是 基地址 也就是 400010
我们来看一下
在这里 就能看的出来
然后我们看一下 内存读出的结果
正确读出。。。