首页
论坛
课程
招聘
[原创]x64下获取随机页表基址的思路
2022-5-14 00:43 2277

[原创]x64下获取随机页表基址的思路

2022-5-14 00:43
2277

没什么用的话

昨天在看周哥讲x64内核的时候,得知了windows10的某个版本开始,页表基址不再固定了。
今天晚上突然有了个思路,就动手把他敲出来了,这种思路是不是已经烂大街了我也不确定,就当发出来学习交流吧。

原理

这里用x32的10-10-12分页举例吧,比较好理解,理解了x64的也差不多的

 

启用了保护模式和分页机制后,咱就不能直接访问物理地址了,都会被cpu当作虚拟地址进行转换。

 

但是cr3存的又是物理地址,不能直接操作页表了,那咋办呢?

 

聪明的前辈们,选择在页目录表中选择一项(共1024项,每一项4字节),使其存储的物理地址与页目录表的基址(cr3)相同,这样子就可以构造一个访问页表的虚拟地址了,大概就是让cpu在地址转换的过程中绕圈圈

  • 画个图吧
    图片描述

思路

  • x64也必然是随机选择PXT的其中一项PXE来存储PXT的物理地址,实现的随机页表基址
  • 那么就可以通过构造所有可能指向PXT的虚拟地址(共512项),转换为物理地址,再与cr3比较,最终得到正确的PXT基址。
  • 只要知道了存储PXT的物理地址的PXE的PXI,构造PPT/PDT/PTT基址都很简单了

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PVOID GetPXTBase() {
    UINT64 cr3 = __readcr3();
    KdPrint(("yuyu:cr3:%p\n", cr3));
    for (UINT64 i = 0; i < 512; i++) {
        // 构造虚拟地址,这个0xffff.. 可加可不加
        PVOID pxtBase = (PVOID)(0xffff000000000000 | (i << 12) | (i << 21) | (i << 30) | (i << 39));
        PHYSICAL_ADDRESS physical = MmGetPhysicalAddress(pxtBase);
        KdPrint(("yuyu:i:%d 物理:%p 虚拟:%p\n", i, physical.QuadPart, pxtBase));
        if (cr3 == physical.QuadPart) {
            return pxtBase;
        }
    }
    return NULL;
}

图片描述

结尾

理解有限,如有错误,还请指正

2022/5/14补充

  • 其实除开这个之外,我先想到的是另一个思路,即构造所有可能存储PXT的物理地址的PXE的虚拟地址
    • 依旧是512项,探测地址是否可访问,读取8字节;
    • 将其当作PXE,取出物理页面基址,再与cr3进行比较。
  • 但是这种方法有概率出现问题,即存放的数据可能正好与cr3相同,但所在页面并不是PXT。
    • 因此我就没有写出来,不过我想了一下,还是贴出来了,也算是一种思路嘛。

【公告】看雪招聘大学实习生!看雪20年安全圈的口碑,助你快速成长!

最后于 6天前 被yuyuaqwq编辑 ,原因:
收藏
点赞0
打赏
分享
最新回复 (7)
雪    币: 1114
活跃值: 活跃值 (1456)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
はつゆき 活跃值 2022-5-14 00:54
2
0
思路是对的,并且已经有厂在用了
https://bbs.pediy.com/thread-254276.htm
雪    币: 205
活跃值: 活跃值 (108)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yuyuaqwq 活跃值 2022-5-14 00:55
3
0
はつゆき 思路是对的,并且已经有厂在用了 https://bbs.pediy.com/thread-254276.htm

谢谢佬回复,这个帖我看过了,思路差不多,不过还是有点区别的,鹅厂是通过映射cr3来比较的,我这个并没有映射

最后于 2022-5-14 01:03 被yuyuaqwq编辑 ,原因:
雪    币: 190
活跃值: 活跃值 (21)
能力值: ( LV9,RANK:289 )
在线值:
发帖
回帖
粉丝
咋回事儿啊 活跃值 2022-5-14 01:39
4
0
char __fastcall LocatePteBase()
{
  unsigned __int64 v0; // rax
  __int64 v1; // krB8_8
  __int64 i; // krA0_8
  __int64 index; // rsi
  __int64 v4; // r9
  PHYSICAL_ADDRESS v5; // krA0_8
  unsigned __int64 v6; // krD8_8
  __int64 v7; // krE8_8
  unsigned __int64 v8; // kr30_8
  unsigned int v9; // eax
  char v10; // cf
  ULONG v11; // krB0_4
  void *v14; // rax
  __int64 v15; // r9
  unsigned __int64 VA; // [rsp+44h] [rbp+8h]

  v0 = __readcr3();
  v1 = v0 & 0xFFFFFFFFFF000i64;
  for ( i = 1i64; ; i = index + 1 )
  {
    VA = (i | ((i | ((i | (i << 9)) << 9)) << 9)) << 12;
    index = i;
    v5 = (*(PHYSICAL_ADDRESS (__stdcall **)(PVOID))pfnMmGetPhysicalAddress_0)((PVOID)VA);
    v6 = VA;
    v7 = v4;
    if ( v5.QuadPart == v1 )
      break;
    if ( (unsigned __int64)(index + 1) >= 0x200 )
    {
      SelfAutoIndex = 0i64;
      goto LABEL_11;
    }
  }
  if ( (VA >> 47) & 1 != 0 )
    v6 = VA | 0xFFFF000000000000ui64;
  SelfAutoIndex = index;
  if ( !v6
    || (PteBase = (index << 39) | 0xFFFF000000000000ui64,
        PdeBase = (index << 30) | (index << 39) | 0xFFFF000000000000ui64,
        PpeBase = (index << 21) | PdeBase,
        PxeBase = (index << 21) | PdeBase | (index << 12),
        PxeBase != v6) )
  {
LABEL_11:
    v11 = -536870756;
LABEL_12:
    DbgPrintEx(6, v11, L"\n", v7);
    return 0;
  }
  return 1;
}

来自vgk

雪    币: 11011
活跃值: 活跃值 (5076)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
hzqst 活跃值 3 2022-5-14 10:02
5
0
咋回事儿啊 char&nbsp;__fastcall&nbsp;LocatePteBase() { &nbsp;&nbsp;unsigned&nbsp;__int64& ...
vgk不是基本上全v了,这段咋找到的?
雪    币: 200
活跃值: 活跃值 (2079)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
ookkaa 活跃值 2022-5-14 10:53
6
0
MmPteBase  不是有这玩意吗
雪    币: 1114
活跃值: 活跃值 (1456)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
はつゆき 活跃值 2022-5-14 18:33
7
0
ookkaa MmPteBase 不是有这玩意吗
未导出
雪    币: 190
活跃值: 活跃值 (21)
能力值: ( LV9,RANK:289 )
在线值:
发帖
回帖
粉丝
咋回事儿啊 活跃值 2022-5-14 20:39
8
0
hzqst vgk不是基本上全v了,这段咋找到的?
全程序vm还原 就像be
游客
登录 | 注册 方可回帖
返回