Win10 DiSPATCH_LEVEL下读取物理内存

  • A+
所属分类:逆向工程
Win10 DiSPATCH_LEVEL下读取物理内存

本文为看雪论坛优秀文章

看雪论坛作者ID:不对




Win10 DiSPATCH_LEVEL下读取物理内存

0x01 前言

Win10 DiSPATCH_LEVEL下读取物理内存


win10(或者说windows)读取物理内存方式有很多种,但是在DISPATCH_LEVEL下读取物理内存的方式就少的可怜了,原因是DISPATCH_LEVEL无法执行缺页中断,所以像MDL的方法就会直接导致蓝屏。

这里一般的情况下,我会推荐使用MmMapIoSpace,将物理地址映射成虚拟地址。但是在win10 的1803版本之后,这个方法也不太适用了,那么有没有替代的方法甚至是更为通杀的方法呢?


Win10 DiSPATCH_LEVEL下读取物理内存

0x02 正常的流程

Win10 DiSPATCH_LEVEL下读取物理内存

首先我们先来分析,分页页表等级分为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%pn", pUserBuffer); getchar(); printf("%sn", pUserBuffer); getchar();}

这段代码是将一个字符串的虚拟地址打印出来,然后等待按键,再然后输入该字符串,编译后,放入虚拟机中,看看实际运行情况我们查看一下运行情况:
Win10 DiSPATCH_LEVEL下读取物理内存
此时我们可以得到字符串的虚拟地址,0x00DD86EC,我们通过PTE读取这个虚拟地址的物理地址基址,公式是 物理地址基址 = *(ULONG_PTR *)(PTE_BASE + ( 0x00DD86EC  >> 12) * 8)  & 0xFFFFFFFFF000  ,那么这个PTE_BASE 是多少呢?论坛里面的hzqst 大神总结了几种方法,https://bbs.pediy.com/thread-254276.htm ,这里就不在赘述,我们采用的是tandasat的方法。
Win10 DiSPATCH_LEVEL下读取物理内存
那么,现在的PTE_BASE就是 0xFFFFFB8000000000,我们带入公式中算一下,结果为 fffffb8000006ec0,目前为止我们需要挂靠进程,才能读到对应的内容:
Win10 DiSPATCH_LEVEL下读取物理内存
通过公式我们可以出,物理地址的基址是 0x11cfe000,我们再加上原虚拟地址的低12位偏移0x6eC,查看一下物理内存:
Win10 DiSPATCH_LEVEL下读取物理内存
可以看到我们能够正确的读取了。

    
Win10 DiSPATCH_LEVEL下读取物理内存

0x03 驱动代码的实现

Win10 DiSPATCH_LEVEL下读取物理内存

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


运行结果:

Win10 DiSPATCH_LEVEL下读取物理内存

参考文章:

https://bbs.pediy.com/thread-254276.htm
https://bbs.pediy.com/thread-253677.htm


Win10 DiSPATCH_LEVEL下读取物理内存

- End -


Win10 DiSPATCH_LEVEL下读取物理内存


看雪ID:不对

https://bbs.pediy.com/user-home-572364.htm

  *本文由看雪论坛 不对 原创,转载请注明来自看雪社区。




# 往期推荐





Win10 DiSPATCH_LEVEL下读取物理内存
公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]



Win10 DiSPATCH_LEVEL下读取物理内存

球分享

Win10 DiSPATCH_LEVEL下读取物理内存

球点赞

Win10 DiSPATCH_LEVEL下读取物理内存

球在看



Win10 DiSPATCH_LEVEL下读取物理内存

点击“阅读原文”,了解更多!

本文始发于微信公众号(看雪学院):Win10 DiSPATCH_LEVEL下读取物理内存

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: