Win10 DiSPATCH_LEVEL下读取物理内存
2020-04-03 17:36:55 Author: bbs.pediy.com(查看原文) 阅读量:219 收藏

[原创]Win10 DiSPATCH_LEVEL下读取物理内存

15小时前 266

[原创]Win10 DiSPATCH_LEVEL下读取物理内存

时间:2020年4月3日02:37:58
地点:帝都-西二旗
人物:不对
测试机器: win10 X64 1803之后的版本

       本文经过长时间的搜索和灵感迸发而来的大杂烩,如有雷同,算我抄你

       win10(或者说windows)读取物理内存方式有很多种,但是在DISPATCH_LEVEL下读取物理内存的方式就少的可怜了,原因是DISPATCH_LEVEL无法执行缺页中断,所以像MDL的方法就会直接导致蓝屏。这里一般的情况下,我会推荐使用MmMapIoSpace,将物理地址映射成虚拟地址。但是在win10 的1803版本之后,这个方法也不太适用了,那么有没有替代的方法甚至是更为通杀的方法呢?

      肯定是有的,不然我就不会写这个文章了!

      首先我们先来分析,分页页表等级分为9-9-9-9-12 (4 * 9 + 12 = 48),这个我应该没有记错,我们的页表存在于Cr3,然而现在MmMapIoSpace不让用了,所以,我们只能从另一个方向入手:PTE,我写了一个程序,源代码如下:

 
#include "stdio.h"

int main() {
	unsigned char* pUserBuffer = (unsigned char *)"Hello World!\n";
	printf("0x%p\n", pUserBuffer);
	getchar();
	printf("%s\n", pUserBuffer);
	getchar();
}

      这段代码是将一个字符串的虚拟地址打印出来,然后等待按键,再然后输入该字符串,编译后,放入虚拟机中,看看实际运行情况我们查看一下运行情况:


    此时我们可以得到字符串的虚拟地址,0x00DD86EC,我们通过PTE读取这个虚拟地址的物理地址基址,公式是 物理地址基址 = *(ULONG_PTR *)(PTE_BASE + ( 0x00DD86EC  >> 12) * 8)  & 0xFFFFFFFFF000  ,那么这个PTE_BASE 是多少呢?论坛里面的hzqst 大神总结了几种方法,https://bbs.pediy.com/thread-254276.htm ,这里就不在赘述,我们采用的是tandasat的方法。


那么,现在的PTE_BASE就是 0xFFFFFB8000000000,我们带入公式中算一下,结果为 fffffb8000006ec0,目前为止我们需要挂靠进程,才能读到对应的内容:


通过公式我们可以出,物理地址的基址是 0x11cfe000,我们再加上原虚拟地址的低12位偏移0x6eC,查看一下物理内存:


可以看到我们能够正确的读取了。

    讲到这里,应该已经能猜到我的方法了,但是我还是打算说出来,希望大家能表示惊讶一下,就是构造一段连续的物理地址,然后根据PTE_BASE找到自己对应的PTE,将自己的地址挂靠到对应的物理地址上面

    那么自己手工构造怎么构造呢?如果你想到了PLM4,那么恭喜你,你想的太深了,我们只需要申请一段NonPage内存就可以了,这样子,系统会自动替我们构造好,问题又来了,我们需要申请多大的呢?我们注意到一个PTE可以描述的是4KB大小的物理地址,所以,我们就申请4KB就好了。

   笔者不太了解ExAllocateMemoryWithTag如果申请0x1000(4KB)个字节会是具体申请多少,在这里,笔者选用了MmAllocateContiguousMemory,根据文档,只要是4KB对齐的大小,申请出来的内存都会是4kb对齐的(就是低12位为0)。

   现在看来思路清晰了,我们申请的内存挂靠到对应的物理地址的4kb对齐的头部地址,然后再加上物理地址的低12位偏移,就可以了。

   结合实际情况就是:我们设我们申请出来的内存虚拟地址为X,则X的PTE描述地址为:p =  (PTE_BASE + (x >> 12) * 8) ,将 p 地址中的 48 ~ 12位替换为要读取的物理地址的48 ~ 12位,然后我们就可以通过 p + offset 读取到内容了。(我们暂时不考虑内容会被交换到硬盘上)

代码如下:

#include "ntddk.h"

void DriverUnload(PDRIVER_OBJECT pDriverObject) {

}

extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pUnicodeString) {
	pDriverObject->DriverUnload = DriverUnload;
	KIRQL kIrql = KeRaiseIrqlToDpcLevel();
	ULONG_PTR PTE_BASE = 0xFFFFF68000000000;
	ULONG_PTR pReadPhysicalAddress = 0x708c6EC;
	PHYSICAL_ADDRESS dtPhysical;
	dtPhysical.QuadPart = -1;
	unsigned char* p = (unsigned char *)MmAllocateContiguousMemory(0x1000, dtPhysical);
	if (p)
	{
		KdPrint(("MmAllocateContiguousMemory Address : 0x%p\n", p));

		ULONG_PTR* pPte = (ULONG_PTR *)(PTE_BASE + (((ULONG_PTR)p & 0xFFFFFFFFF000) >> 12) * 8);
		ULONG_PTR nOldValue = *pPte;  //保存原来的值
		*pPte = (nOldValue & ~(0xFFFFFFFFF000)) | (pReadPhysicalAddress & 0xFFFFFFFFF000);

		unsigned char* pReadStart = p + (pReadPhysicalAddress & 0xFFF);
		for (size_t i = 0; i < 16; i++)
		{
			KdPrint(("%c", pReadStart[i]));
		}

		KdPrint(("\n"));

		*pPte = nOldValue;   //恢复原来的值

		MmFreeContiguousMemory(p);
	}

	KeLowerIrql(kIrql);

	return STATUS_SUCCESS;
}


2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!

最后于 14小时前 被不对编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-258596.htm
如有侵权请联系:admin#unsafe.sh