- 探索CR4
- 探索页面
- CR3寄存器于页遍历
- 虚拟地址->物理地址
[驱动开发]探索CR4
英特尔® 64 位和 IA-32 架构开发人员手册合订本
第3卷第四章第五小节《4-LEVEL PAGING AND 5-LEVEL PAGING》
判断CPU是四级分页还是五级分页
page: 3074
该寄存器的值决定了映射层级是4/5,
- 1:5级分页
- 0:4级分页
1 | //__readcr4() & 0x1000 |
[驱动开发]探索页面
CR3寄存器于页遍历
CR3 寄存器设计 CR3[512][512][512][512]
个人觉得这块儿和CSAPP上面讲的差不多
1 | //1.得到CR3寄存器的值,从而得到一级页表地址 |
-
CR3
的PPN
是第12位,共40bit,所以一级页表是这个值。CR3
的尾12位没有用全为0,同时,那么向右移12位等效于16禁止右移位 -
得到
Level_1_PageTable
的值过后,可以使用函数MmGetVirtualForPhysical
获得该内存地址的值,从而遍历一级页表。要判断当前L1pt.P
是否有效,同时L1pt.U_S
可以判断该页的权限,详细可以看开发者手册Table 4-20
-
依次循环可以遍历完整个内存页(下图中L4pt放不下了)
虚拟地址->物理地址
程序按照4KB分页个数太多不利于实验,可以强制将其分页为1GB,这样便于翻译
编写一个测试程序,该程序能申请出一页的内存,并打印其值
使用PsGetCurrentProcess
获得当前进程PROCESS
对象,若相等则不启用新方法
使用KeStackAttachProcess
附加到要翻译的内存的PROCESS
对象中,使用老方法输出就OK了,最后KeUnstackDetachProcess
脱离
-
?如何使用按照名字查找进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
NTSTATUS
QuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID* SystemInformation)
{
NTSTATUS Status;
PVOID Buffer;
ULONG BufferSize = 4096;
do
{
Buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, BufferSize, 'bisQ');
if (!Buffer) return STATUS_NO_MEMORY;
Status = NtQuerySystemInformation(SystemInformationClass, Buffer, BufferSize, &BufferSize);
if (NT_SUCCESS(Status)) {
*SystemInformation = Buffer;
return Status;
}
ExFreePool(Buffer);
if (STATUS_INFO_LENGTH_MISMATCH != Status) return Status;
} while (TRUE);
}
NTSTATUS
LookUpProcessByImageName(PCWSTR ImageName, PEPROCESS* Process)
{
NTSTATUS Status;
PSYSTEM_PROCESS_INFORMATION ProcessInformationArray = NULL;
Status = QuerySystemInformation(SystemProcessInformation, &ProcessInformationArray);
if (!NT_SUCCESS(Status)) return Status;
PSYSTEM_PROCESS_INFORMATION CurrentInformation = ProcessInformationArray;
UNICODE_STRING ImageNameUnicodeString;
RtlInitUnicodeString(&ImageNameUnicodeString, ImageName);
while (TRUE)
{
if (RtlCompareUnicodeString(&CurrentInformation->ImageName, &ImageNameUnicodeString, FALSE) == 0)
{
Status = PsLookupProcessByProcessId(CurrentInformation->UniqueProcessId, Process);
ExFreePool(ProcessInformationArray);
return Status;
}
if (CurrentInformation->NextEntryOffset == 0)
{
ExFreePool(ProcessInformationArray);
return STATUS_NOT_FOUND;
}
CurrentInformation = (PSYSTEM_PROCESS_INFORMATION)((PUCHAR)CurrentInformation + CurrentInformation->NextEntryOffset);
}
}大致思路和win32下按名称查找PID差不多
-
具体过程
这里以
0x00000254000003BC Str1
为例子,加载插件打印,耐心等待。。。这时候的数据大小就有83KB了
format(0x00000254000003BC, "064b")
,内存前16位为空是没有用的-
高9位
int(format(0x00000254000003BC, "064b")[16:][:9],2)
-
再9位
int(format(0x00000254000003BC, "064b")[16:][9:18],2)
该页表的PS=1,则不需要查找下一个页表了(而且后面也没有了)
-
得到的
Pa
就是物理页的首地址 + 剩余的30bit位作为VPO
= 物理地址hex(0x00000001C0000000+int(format(0x00000254000003BC, "064b")[16:][18:],2))
得到
PA+VPO = 0x1c00003bc
-
暂停系统,Windbg -> memory window -> 右键 -> proeries -> physical memory
-
尝试修改
再次刷新应该就是
1234
了成功修改
-
官方文档
2938/4834