首页
社区
课程
招聘
[原创]Win10 DiSPATCH_LEVEL下读取物理内存
发表于: 2020-4-3 02:28 15498

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

2020-4-3 02:28
15498

0x01 前言:

       win10(或者说windows)读取物理内存方式有很多种,但是在DISPATCH_LEVEL下读取物理内存的方式就少的可怜了,原因是DISPATCH_LEVEL无法执行缺页中断,所以像MDL的方法就会直接导致蓝屏。这里一般的情况下,我会推荐使用MmMapIoSpace,将物理地址映射成虚拟地址。但是在win10 的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,查看一下物理内存:

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

0x04 驱动代码的实现:

    讲到这里,应该已经能猜到我的方法了,但是我还是打算说出来,希望大家能表示惊讶一下,就是构造一段连续的物理地址,然后根据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;
}

0x05 运行结果:


   

0x06 参考文章:

#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,查看一下物理内存:

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


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-4-3 02:40 被不对编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (32)
雪    币: 1485
活跃值: (1135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
帖子不错。楼主你测试一下调用门中断门在win10是否可以用?
2020-4-3 07:17
0
雪    币: 181
活跃值: (621)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
2020-4-3 09:00
0
雪    币: 73
活跃值: (923)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
mark下,回头慢慢研究,读取物理内存数据应该是很多地方都会用到的
2020-4-3 09:34
0
雪    币: 83
活跃值: (1087)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
very good
2020-4-3 20:17
0
雪    币: 954
活跃值: (123)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我就喜欢这种言简意赅的文章。
最后于 2020-4-6 15:10 被tdsss编辑 ,原因:
2020-4-6 15:10
0
雪    币: 1129
活跃值: (2761)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
学习了,感谢分享
2020-4-6 23:59
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢分享,留个mark
2020-4-7 05:18
0
雪    币: 5039
活跃值: (2626)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
9
代码很骚,只不过这内存没法确保有效性,有蓝屏概率
2020-4-9 20:47
0
雪    币: 7065
活跃值: (3106)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
10
FaEry 代码很骚,只不过这内存没法确保有效性,有蓝屏概率
一般情况下这种PTE都是可写的吧?实在不行就只能在低IRQ的时候请求了。。
2020-4-10 10:36
0
雪    币: 5039
活跃值: (2626)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
11
不对 一般情况下这种PTE都是可写的吧?实在不行就只能在低IRQ的时候请求了。。
DPC_LEVEL访问PagedOut容易炸,低Level下可以,UserMode用__try__except包着,KernelMode用MmIsAddressValid包着 就很稳...
最后于 2020-4-13 09:55 被FaEry编辑 ,原因:
2020-4-13 09:54
1
雪    币: 74
活跃值: (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感谢分享
2020-4-13 15:22
0
雪    币: 7065
活跃值: (3106)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
13
FaEry 不对 一般情况下这种PTE都是可写的吧?实在不行就只能在低IRQ的时候请求了。。 DPC_LEVEL访问PagedOut容易炸,低Level下可以,Us ...
当时考虑过这个问题,我申请的那个页面是永驻的,所以应该不会被换出,然后是当前Cr3存在的情况下,系统肯定是帮忙挂载好了对应的物理地址,所以应该访问也没有啥问题,唯一的缺点就是不知道是否可写,不知道我这样理解对不对
2020-4-13 22:37
0
雪    币: 12363
活跃值: (5884)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
14
代码有漏洞,在配置高容量内存条的机子上,MmAllocateContinguousMemory申请的页可能处于2M大分页或1G大分页中,此时的PTE要么清零要么根本不存在,楼上说的概率蓝屏应该指的就是这种情况
2020-10-20 09:22
0
雪    币: 7065
活跃值: (3106)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
15
hhkqqs 代码有漏洞,在配置高容量内存条的机子上,MmAllocateContinguousMemory申请的页可能处于2M大分页或1G大分页中,此时的PTE要么清零要么根本不存在,楼上说的概率蓝屏应该指的就是 ...
受教了,是否可以使用ExAllocatePool来进行替换呢?
2020-10-20 10:33
0
雪    币: 2674
活跃值: (2304)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
不错的贴子!从WIN10系统开始提供了:MmMapIoSpaceEx,还没有试过,
马上试下!如果适用,就逆一下。
2020-10-20 11:25
0
雪    币: 12363
活跃值: (5884)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17
不对 [em_67]受教了,是否可以使用ExAllocatePool来进行替换呢?
ExAllocatePool虽然在长度≥0x1000的时候也是页对齐,但和Mmxxx一样拥有内存充足下优先分配大分页的特点,最好的方案是参考我之前某篇帖子的思路,MmAllocatexxx只用于分配建立新PML4T和PDPT页表项内容的内存,在PML4T的512项里面选一项占坑,把想访问的虚拟地址直接往这里做拷贝,如果是访问物理地址,直接在这里面找一项未使用的PTE填充物理页帧号\有效位\可写位,再刷tlb就稳得一批了。因为这个连续空间已经被自己占坑,你完全不用担心操作系统会动你映射的内容。
2020-10-20 14:03
0
雪    币: 12363
活跃值: (5884)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
18
我帖子里也有计算大分页情况下拿到MmAllocxxx和ExAllocxxx申请到的物理页帧号的代码,主要是利用了操作系统申请大分页时页帧号和虚拟页帧号对齐的特点,当然也可以MmGetPhysicalForVirtual(不喜欢用这个,没准哪天就变成MmMapIoSpace一样的下场了)
2020-10-20 14:06
0
雪    币: 7065
活跃值: (3106)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
19
hhkqqs ExAllocatePool虽然在长度≥0x1000的时候也是页对齐,但和Mmxxx一样拥有内存充足下优先分配大分页的特点,最好的方案是参考我之前某篇帖子的思路,MmAllocatexxx只用于分配建 ...
理解你的意思了,你是从PML4T的位置就开始替换成自己的了,受教了!,我去改进一下思路
2020-10-20 14:22
0
雪    币: 12363
活跃值: (5884)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
20
不对 理解你的意思了,你是从PML4T的位置就开始替换成自己的了,受教了![em_13],我去改进一下思路

如果只是简单地访问某个物理页,直接申请一页内存,第一项填一个Valid和LargePage位为1的PDPT项,按你的需求给Dirty1(Intel's R/W bit)和NoExecute置位,物理页帧号填你要访问的页帧号。再把申请的这页内存的物理页帧号填进某个没使用的PML4T里面,再刷下TLB,你就能随意使用从你想用的物理页开始,长度为1G的物理内存了。我原帖干的很多事都是映射已有的虚拟地址,稍微补充下就能做到既映射已有虚拟地址也映射物理地址了

最后于 2020-10-20 14:37 被hhkqqs编辑 ,原因:
2020-10-20 14:29
0
雪    币: 7065
活跃值: (3106)
能力值: ( LV4,RANK:52 )
在线值:
发帖
回帖
粉丝
21
hhkqqs 不对 理解你的意思了,你是从PML4T的位置就开始替换成自己的了,受教了![em_13],我去改进一下思路 如果只是简单地访问某个物理页,直接申请一页内存,第一 ...
学习了!我这就去研究研究!
2020-10-20 14:48
0
雪    币: 515
活跃值: (3272)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wem
22
好贴
2020-10-21 00:19
0
雪    币: 12476
活跃值: (9432)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
学习了~~,评论也很精彩。。。
2020-10-21 16:28
0
雪    币: 2674
活跃值: (2304)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
24
hhkqqs 代码有漏洞,在配置高容量内存条的机子上,MmAllocateContinguousMemory申请的页可能处于2M大分页或1G大分页中,此时的PTE要么清零要么根本不存在,楼上说的概率蓝屏应该指的就是 ...

是否可以这样理解:
9-9-9-9-12
PTE: 2的12次方=4KB字节小分页,可描述(2的36次方=64G)个4KB字节小分页
PDE:   2的21次方=2MB字节大分页,可描述(2的27次方=128M)个2MB字节大分页
PPE:   2的30次方=1GB字节大分页,,可描述(2的18次方= 256K)个1GB字节大分页
PXE:   2的39次方=512GB字节大分页,可描述(2的9次方=512)个512GB字节大分页
不过最后1个似乎没有看到过。64位系统中物理地址为48位,理论上物理内存最大可为 2的48次方=256TB字节.
目前在windows分页管理方面才刚开始学习了解,上述纯属数学推导,别见笑哈!

最后于 2021-2-5 18:13 被低调putchar编辑 ,原因:
2021-2-4 19:47
0
雪    币: 12363
活跃值: (5884)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
25
低调putchar hhkqqs 代码有漏洞,在配置高容量内存条的机子上,MmAllocateContinguousMemory申请的页可能处于2M大分页或1G大分页中,此时的PTE ...
没错,512G分页对配置要求太高了估计一般人接触不到
2021-2-5 01:40
0
游客
登录 | 注册 方可回帖
返回
//