// 遍历MMPFN 获取真实CR3地址
for (ULONG64 i = 0; i < maxCount; ++i)
{
ULONG64 Buddy = (ULONG64)local_MMPFN.u1.Buddy;
if (Buddy == NULL)
continue;
// 计算解密后的 eprocess 值
ULONG64 EPROCESS = (((Buddy>>0xD)&0xFFFFFFFFFFFFFFF0)|0xFFFF800000000000);
if (Buddy == eproc || EPROCESS== eproc)
{
dribase = i<< PAGE_SHIFT; //这里就是你要的真实CR3地址
break;
}
}
因为我们不需要从EPROCESS中拿dirbase 不管CR3加密与否
0: kd> dt _KPROCESS
nt!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER
+0x018 ProfileListHead : _LIST_ENTRY
+0x028 DirectoryTableBase : Uint8B
关于CR3的加密 就是 各大AC修改了EPROCESS->DirectoryTableBase的数值 然后接管了内核全局异常处理
KeAttachProcess或者操作错误的CR3 都会触发异常 然后走它的异常接管 它上报或者给你返回空字节的分页给你
这就是为什么频繁的附加进程上下文导致GG和读不到数据
那么就有人要问了为什么要这样运算 (((Buddy>>0xD)&0xFFFFFFFFFFFFFFF0)|0xFFFF800000000000) ,你去问微软
至于外面杂七杂八一大堆的解密 这里不做点评 ,你觉得好用你就去用
W7-W10是这套固定的运算方法 W7的MMPFN中EPROCESS并未经过运算保存 直接就是对象地址
W10需要位运算还原出对象地址 这套方案不管加密没加密都能返回正确的EPROCESS
maxCount=最大物理页数量 MmGetPhysicalMemoryRanges可以获取到
接下来是W11各版本的通杀方案 这里以24H2为例子
Owning Process ffffad8b1c7f3080 Image: procexp64.exe
ffffad8b1c7f3080+0x28=0x0000001146a3002 CR3 00000001`146a3002&~FFF >> 12 =1146A3 页目录索引
然后众所周知MMPFN结构大小为0x30 固定的 其中+0x0=加密后的对象地址 +0x8=ptebaseaddress w7中+0x10=tebaseaddress
根据以上信息得知该MMPFN地址为MmPfnDataBase+0x1146A3 *0x30
CR3解密之MMPFN->EPROCESS通杀分析
00008000`638fe613 这个数值就是加密后的对象地址
CR3解密之MMPFN->EPROCESS通杀分析
MMPFN调试下断得出MiGetPageTablePfnBuddyRaw为解密对象地址的函数,参数1为MMPFN地址
CR3解密之MMPFN->EPROCESS通杀分析
mov rdx, 00008000638fe613h //加密后的对象地址 EPROCESS
mov ecx, 0401ffffh //MMPFN+0x24的数值
and ecx,3FF0000h
shr rdx,1
shl rcx,0Fh
btr edx,1Fh
or rcx,rdx
mov rax,0FFFFFF0000000000h
add rax,rcx
dec rcx
shl rcx,4
####### add rcx, cs:qword_140E38538 //读出来的值为ffffad8000000000h
add rcx, ffffad8000000000h //这个数值跟PTE一样 是动态的 每次启动系统都会变化
ret
uint64_t DecryptProcess(uint64_t encrypt)
{
//0x401ffff=MMPFN+0x24 ULONG
//0xffffad8000000000=动态读 ULONG64
//以上两个数据需要自行读取
return ((encrypt >> 1 | ((unsigned __int64)(0x401ffff & 0x3FF0000) << 15)) - 1) * 0x10 | 0xffffad8000000000;
}
24H2中直接用这套算法就能解密出对象地址
CR3解密之MMPFN->EPROCESS通杀分析
MiGetPageTablePfnBuddyRaw上层调用为:MiGetPfnPidSafe 顾名思义 安全获取PfnPid 我们跟进去看看
CR3解密之MMPFN->EPROCESS通杀分析
MiGetPfnPidSafe(__int64 a1, unsigned int a2) 两个参数 参数1 mmpfn地址,参数2 标识 写1即可
v5 = MiGetPageTablePfnBuddyRaw(a1); 这里拿到解密后的对象地址 EPROCESS
return *(unsigned int *)(v5 + 0x1D0);
0: kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x1c8 ProcessLock : _EX_PUSH_LOCK
+0x1d0 UniqueProcessId : Ptr64 Void
总结:W11各版本中 call MiGetPageTablePfnBuddyRaw即可拿到解密后的对象地址 call MiGetPfnPidSafe就是拿到mmpfn所属pid