首页
社区
课程
招聘
[未解决,已结帖] [求助]关于PTEhook的问题 50.00雪花
发表于: 2022-12-2 22:10 14062

[未解决,已结帖] [求助]关于PTEhook的问题 50.00雪花

2022-12-2 22:10
14062

如题,我PTEHook,但是我的虚拟机是大页的,所以我就是用大页的Hook

一开始我是用的4kb小页PTE顺序排列,假装一个PDE大页的。但是会蓝屏,我就准备大页换大页


一开始我连替换都不行,后面看了白皮书和经过指导才知道替换2MB的大页物理地址也得是2MB对齐的。

后来大页能替换了,但是我挂了半小时 发现虚拟机直接死了 


求大佬解决,这是替换之后的

这是死了之后

代码贴一下  申请内存我用的是申请的非分页内存池的:

ULONG_PTR PTEHOOK::PteHook::fn_init_isolation(HANDLE ProcessId, ULONG_PTR LineAddress)
{

	//直接修改这个
	//PULONG_PTR pPmle4e, pPdpte, pPde, pPte;

	//这个函数的功能是修改pmle4e pdpte pde pte 因此实现隔离物理页 
	//这个时候就可以随便修改内存 而不改变其他地方的物理内存了
	PageAttrHide::PteTable table = { 0 };
	table.pLineAddr = LineAddress;
	KAPC_STATE Apc = { 0 };
	PEPROCESS Process = 0;

	//申请的内存 一般来说 申请3页即可 大页2MB 无需申请pde那一页来替换
	PVOID Pml4e = 0;
	PVOID Pdpte = 0;
	PVOID Pde = 0;


	ULONG_PTR FlagTemp = 0;

	//要替换的 新的 旧的物理地址
	PHYSICAL_ADDRESS NewPml4e = { 0 };
	PHYSICAL_ADDRESS OldPml4e = { 0 };
	PHYSICAL_ADDRESS NewPdpte = { 0 };
	PHYSICAL_ADDRESS OldPdpte = { 0 };
	PHYSICAL_ADDRESS NewPde = { 0 };
	PHYSICAL_ADDRESS OldPde = { 0 };
	PHYSICAL_ADDRESS NewPte = { 0 };
	PHYSICAL_ADDRESS OldPte = { 0 };
	PHYSICAL_ADDRESS _Cr3 = { 0 };
	

	//物理地址映射线性地址 用于修改页表的内容
	PULONG_PTR Cr3Page=0,Pml4ePage=0,PdptePage=0,PdePage=0,PtePage = 0;


	enum PageSize
	{
		small, //4kb
		medium, //2mb
		big//1gb

	};

	int nPageSize = small;


	//get ptes
	PageAttrHide::GetLineAddrPteTable(&table);

	if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process))){

		DbgPrintEx(77, 0, "[OxygenDriver]err process id\r\n");

		return (ULONG_PTR)0;

	}

	KeStackAttachProcess(Process, &Apc);

	//alloc a page size mem for pml4e

	Pml4e = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'PML4');

	Pdpte = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'Pdpt');

	Pde = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'Pde');

	
	//isolate pml4e

	//get alloc mem physical addr


	//获取老的页表  
	OldPml4e = *(PPHYSICAL_ADDRESS)(table.Pml4e);

	OldPdpte = *(PPHYSICAL_ADDRESS)(table.PdPte);

	OldPde = *(PPHYSICAL_ADDRESS)(table.Pde);

	OldPte = *(PPHYSICAL_ADDRESS)(table.Pte);
	//获取老页表指针


	//获取新的页表

	table.pLineAddr = (ULONG_PTR)Pml4e;

	PageAttrHide::GetLineAddrPteTable(&table);

	NewPml4e = *(PPHYSICAL_ADDRESS)(table.Pte);

	table.pLineAddr = (ULONG_PTR)Pdpte;

	PageAttrHide::GetLineAddrPteTable(&table);

	NewPdpte = *(PPHYSICAL_ADDRESS)(table.Pte);
	
	table.pLineAddr = (ULONG_PTR)Pde;

	PageAttrHide::GetLineAddrPteTable(&table);

	NewPde = *(PPHYSICAL_ADDRESS)(table.Pte);

	//save pml4e-pde attributes

	NewPml4e.QuadPart &= 0x000ffffffffff000;
	
	FlagTemp = OldPml4e.QuadPart & 0xfff0000000000FFF;

	NewPml4e.QuadPart |= FlagTemp;

	NewPdpte.QuadPart &= 0x000ffffffffff000;

	FlagTemp = OldPdpte.QuadPart & 0xfff0000000000FFF;

	NewPdpte.QuadPart |= FlagTemp;

	NewPde.QuadPart &= 0x000ffffffffff000;

	FlagTemp = OldPde.QuadPart & 0xfff0000000000FFF;

	NewPde.QuadPart |= FlagTemp;


	//get cr3

	_Cr3.QuadPart = __readcr3();

	Cr3Page =(PULONG_PTR)MmGetVirtualForPhysical(_Cr3);

	//判断页面大小

	if (BitTest((PLONG)&OldPdpte.QuadPart, 7)) {
		//1Gb
		nPageSize = big;

	}
	else {

		nPageSize = BitTest((PLONG)&OldPde.QuadPart, 7) ? medium : small;

	}


	if (nPageSize == big) {

		//1GB太离谱 申请太多非分页直接寄

		DbgPrintEx(77, 0, "[OxygenDriver]:can not support 1GB page isolate!!\r\n");

		KeUnstackDetachProcess(&Apc);

		return 0;


	}
	else if (nPageSize == medium) {

		//记得移位

		DbgBreakPoint();

		int pml4eindex = (LineAddress & 0x0000FF8000000000)>>39;

		int pdpteindex = (LineAddress & 0x0000007FC0000000)>>30;

		int pdeindex = (LineAddress & 0x000000003FE00000)>>21;

		//不需要pte的索引了 因为是2MB


		//把原先的2MB内存 复制到申请是2MB里面去

		PHYSICAL_ADDRESS low = { 0 };
		PHYSICAL_ADDRESS high;
		high.QuadPart = MAXULONG64;



		//申请一块连续的物理内存 就可以假装大页
		//物理页也要对齐!!!!21位为0 坑死了
		PVOID p2MbMemory_ = MmAllocateContiguousMemorySpecifyCache(1024 * PAGE_SIZE, low, high, low, MmCached);

		int i = 0;

		for (;i<1024;i++) {

			//找到2MB对齐的位置
			table.pLineAddr = (UINT64)p2MbMemory_ + PAGE_SIZE * i;

			PageAttrHide::GetLineAddrPteTable(&table);

			UINT64 uPte = *(PULONG_PTR)table.Pte;

			//去掉属性位
			uPte &= 0x000ffffffffff000;

			//看下是否是21位对齐
			uPte &= 0x1fffff;

			if (!uPte) break;

		}


		PVOID p2MbMemory= (PVOID)((UINT64)p2MbMemory_ + PAGE_SIZE * i);

		



		memcpy(p2MbMemory, (PVOID)(LineAddress & 0xffffffffffe00000), 512 * PAGE_SIZE);

		//把这2MB内存的pte复制到假的pde里面 这样 假的pde做好了



		UINT64 uPdetmp;

		table.pLineAddr = (UINT64)p2MbMemory;

		PageAttrHide::GetLineAddrPteTable(&table);

		uPdetmp = *(PULONG_PTR)table.Pte;

		uPdetmp &= 0x000ffffffffff000;

		//去掉物理地址
		NewPde.QuadPart &= 0xfff0000000000fff;

		NewPde.QuadPart |= uPdetmp;


		NewPde.QuadPart |= 0x80;



		//做假的pdpte

		PHYSICAL_ADDRESS PhyPdpte = { 0 };

		//去掉属性位
		PhyPdpte.QuadPart = OldPdpte.QuadPart & 0x000ffffffffff000;

		PdptePage = (PULONG_PTR)MmGetVirtualForPhysical(PhyPdpte);

		//复制
		memcpy(Pdpte, PdptePage, PAGE_SIZE);


		//找到索引并替换

		//((PULONG_PTR)Pdpte)[pdeindex] = NewPde.QuadPart;

		((PULONG_PTR)Pdpte)[pdeindex] = NewPde.QuadPart;
		//去做假的Pml4e

		PHYSICAL_ADDRESS PhyPml4e = { 0 };

		PhyPml4e.QuadPart=OldPml4e.QuadPart & 0x000ffffffffff000;

		Pml4ePage = (PULONG_PTR)MmGetVirtualForPhysical(PhyPml4e);

		//复制

		memcpy(Pml4e, Pml4ePage, PAGE_SIZE);

		//找到pdpte的索引 替换物理地址

		((PULONG_PTR)Pml4e)[pdpteindex] = NewPdpte.QuadPart;

		//去做cr3指向的pml4e的替换 自此页表隔离完毕

		LARGE_INTEGER __cr3;

		__cr3.QuadPart = __readcr3();

		KeUnstackDetachProcess(&Apc);
		HANDLE hSection = nullptr;
		OBJECT_ATTRIBUTES objattr = { 0 };
		UNICODE_STRING usPhysicalMemory = { 0 };
		RtlInitUnicodeString(&usPhysicalMemory, L"\\Device\\PhysicalMemory");
		InitializeObjectAttributes(&objattr, &usPhysicalMemory, 0, 0, 0);
		UINT64 nSize = PAGE_SIZE;
		PVOID cr3tmp = 0;

		if (!NT_SUCCESS(ZwOpenSection(&hSection, SECTION_ALL_ACCESS, &objattr))) {

			//err

			DbgPrintEx(77, 0, "[+]failed to open physec\r\n");

			return false;

		}


		if (!NT_SUCCESS(ZwMapViewOfSection(hSection,
			NtCurrentProcess(),
			&cr3tmp, 0, PAGE_SIZE,
			&__cr3, &nSize, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE
		))) {

			DbgPrintEx(77, 0, "[+]unable to map cr3\r\n");

			return 0;
		}

		

		((PULONG_PTR)cr3tmp)[pml4eindex] = NewPml4e.QuadPart;

		//2MB的页表隔离完毕

		KdPrint(("[+]Big page hook! bsod is coming\r\n"));



[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (8)
雪    币: 2141
活跃值: (5173)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
已解决,不能申请非分页内存池的内存 要自己申请连续物理内存
2022-12-3 10:29
0
雪    币: 45
活跃值: (2802)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
Oxygen1a1 已解决,不能申请非分页内存池的内存 要自己申请连续物理内存
卧槽 谢谢兄弟 这几天也在写这个功能, 遇到和你一样的问题 快裂开了
2023-2-22 17:15
0
雪    币: 0
活跃值: (236)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
页目录常驻内存,内核的页目录是处于非交换分页池中的。不可以被换出去。且其在物理内存中占有一片连续的4K空间。
2023-4-4 13:01
0
雪    币: 35
活跃值: (1796)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
Oxygen1a1 已解决,不能申请非分页内存池的内存 要自己申请连续物理内存
兄弟你指的是 pt pd这个表不能用内存池的内存还是 p2MbMemory 那里不能用内存池的内存 我看你p2MbMemory是用连续内存的申请啊
2023-8-13 04:24
0
雪    币: 412
活跃值: (643)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
大佬 pte hook后 有时候不会跳转到自己的函数上是为什么  例如r3调用了100次  只有90次跳转到自己函数上了 是为什么 而且这种情况似乎只存在于多核处理器上
2024-4-24 13:19
0
雪    币: 10960
活跃值: (2920)
能力值: ( LV5,RANK:71 )
在线值:
发帖
回帖
粉丝
7
invlpg
2024-4-24 13:41
0
雪    币: 412
活跃值: (643)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
joker陈 invlpg
抱歉大佬 我提供的信息有误 我遇到的问题是在较大内存的虚拟机或物理机上 存在这个问题 在小内存的虚拟机上就没问题  
2024-4-25 00:21
0
雪    币: 412
活跃值: (643)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
NMNP码农 抱歉大佬 我提供的信息有误 我遇到的问题是在较大内存的虚拟机或物理机上 存在这个问题 在小内存的虚拟机上就没问题 [em_5]
尝试过在所有核心都调用了一次invlpg  问题依旧
2024-4-25 00:22
0
游客
登录 | 注册 方可回帖
返回
//