/
/
假设的全局变量,在实际驱动程序中需要正确初始化
extern PVOID MmAllocateMappingAddress_MEM;
extern PVOID ExAllocatePoolWithTag_mem;
extern PVOID qword_12D48;
extern CHAR byte_12B40[
256
];
/
/
假设的大小
/
/
假设的函数原型,这些函数在 ntoskrnl.exe 中
extern NTSTATUS ObfDereferenceObject(PVOID
Object
);
extern NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS
*
Process);
extern PHYSICAL_ADDRESS MmGetPhysicalAddress(PVOID BaseAddress);
extern PVOID MmGetVirtualForPhysical(PHYSICAL_ADDRESS PhysicalAddress);
extern PVOID MmAllocateMappingAddress(SIZE_T NumberOfBytes, ULONG Tag);
extern VOID MmFreeMappingAddress(PVOID BaseAddress, ULONG Tag);
extern PVOID ExAllocatePoolWithTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
extern VOID ExFreePool(PVOID P);
extern KIRQL KeGetCurrentIrql();
extern void _disable();
extern void _enable();
extern __int64 GetCr3(__int64 a1);
extern
int
loc_1061();
/
/
假设的函数
/
/
将内联汇编改写成C
/
C
+
+
__try { \
ProbeForRead(addr,
1
,
1
); \
} __except (EXCEPTION_EXECUTE_HANDLER) {} \
}
NTSTATUS tlb_relate(
HANDLE ProcessId,
PVOID TargetAddress,
SIZE_T Size,
PVOID SourceAddress,
ULONG Flag)
{
/
/
检查参数有效性
if
(!ProcessId || !TargetAddress || !SourceAddress || (Size
-
1
) >
0xFFF
) {
return
STATUS_INVALID_PARAMETER;
}
/
/
1.
获取目标进程的 EPROCESS
PEPROCESS TargetProcess
=
nullptr;
NTSTATUS status
=
PsLookupProcessByProcessId(ProcessId, &TargetProcess);
if
(!NT_SUCCESS(status)) {
return
status;
}
/
/
2.
获取目标进程的 CR3
__int64 ProcessCr3
=
GetCr3((__int64)TargetProcess);
__int64 OriginalCr3
=
ProcessCr3;
/
/
保存原始 CR3 值
ObfDereferenceObject(TargetProcess);
/
/
获取构建号
int
BuildNumber
=
loc_1061();
if
(BuildNumber
=
=
-
1
) {
return
STATUS_INVALID_PARAMETER;
}
/
/
3.
初始化内部缓冲区和映射地址空间
if
(!MmAllocateMappingAddress_MEM)
{
MmAllocateMappingAddress_MEM
=
MmAllocateMappingAddress(
0x200000
,
'MyTg'
);
/
/
使用
'MyTg'
作为tag
}
if
(!ExAllocatePoolWithTag_mem)
{
ExAllocatePoolWithTag_mem
=
ExAllocatePoolWithTag(NonPagedPool,
0x200000
,
'MyTg'
);
/
/
使用
'MyTg'
作为tag
}
if
(!MmAllocateMappingAddress_MEM || !ExAllocatePoolWithTag_mem)
{
if
(MmAllocateMappingAddress_MEM) {
MmFreeMappingAddress(MmAllocateMappingAddress_MEM,
'MyTg'
);
MmAllocateMappingAddress_MEM
=
nullptr;
/
/
避免double free
}
if
(ExAllocatePoolWithTag_mem)
{
ExFreePool(ExAllocatePoolWithTag_mem);
ExAllocatePoolWithTag_mem
=
nullptr;
/
/
避免 double free
}
return
STATUS_INSUFFICIENT_RESOURCES;
}
if
(!qword_12D48)
{
qword_12D48
=
*
reinterpret_cast<PVOID
*
>(reinterpret_cast<char
*
>(MmGetVirtualForPhysical)
+
0x22
);
}
/
/
计算在缓冲区内的偏移
__int64 IndexOffset
=
(__int64)BuildNumber <<
12
;
char
*
pInternalBuffer
=
reinterpret_cast<char
*
>(ExAllocatePoolWithTag_mem)
+
IndexOffset;
char
*
pMappingAddress
=
reinterpret_cast<char
*
>(MmAllocateMappingAddress_MEM)
+
IndexOffset;
/
/
4.
根据 Flag 预复制数据
if
(Flag && (Flag !
=
1
)) {
RtlCopyMemory(pInternalBuffer, SourceAddress, Size);
}
/
/
5.
提升 IRQL 并禁用中断 (进入关键区)
KIRQL OldIrql
=
KeGetCurrentIrql();
if
(OldIrql < DISPATCH_LEVEL) {
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
}
/
/
6.
遍历页表
SIZE_T BytesRemaining
=
Size;
SIZE_T BytesCopied
=
0
;
while
(BytesRemaining >
0
) {
PVOID CurrentVirtualAddress
=
reinterpret_cast<char
*
>(TargetAddress)
+
BytesCopied;
/
/
6.1
计算页表索引
ULONG64 PML4EIndex
=
((ULONG64)CurrentVirtualAddress >>
39
) &
0x1FF
;
ULONG64 PDPEIndex
=
((ULONG64)CurrentVirtualAddress >>
30
) &
0x1FF
;
ULONG64 PDEIndex
=
((ULONG64)CurrentVirtualAddress >>
21
) &
0x1FF
;
ULONG64 PTEIndex
=
((ULONG64)CurrentVirtualAddress >>
12
) &
0x1FF
;
ULONG64 PageOffset
=
(ULONG64)CurrentVirtualAddress &
0xFFF
;
/
/
6.2
获取并修改 PTE
ULONG64
*
pPTE
=
reinterpret_cast<ULONG64
*
>(reinterpret_cast<char
*
>(qword_12D48)
+
(((ULONG64)pMappingAddress >>
9
) &
0x7FFFFFFFF8
));
Barrier();
ULONG64 OriginalPTE
=
*
pPTE;
/
/
6.2
.
1
获取 PML4E
*
pPTE
=
(ProcessCr3 &
0xFFFFFFFFFF000ULL
) | (PML4EIndex <<
3
) |
0x1E3
;
__invlpg(pMappingAddress);
Barrier();
ULONG64 PML4E
=
*
reinterpret_cast<PULONG64>(pMappingAddress
+
(PML4EIndex
*
sizeof(ULONG64)));
if
(!(PML4E &
1
) || ((OriginalCr3 ^ PML4E) &
0xFFFFFFFFFF000ULL
)
=
=
0
)
{
goto Cleanup;
}
/
/
6.2
.
2
获取 PDPE
*
pPTE
=
(PML4E &
0xFFFFFFFFFF000ULL
) | (PDPEIndex <<
3
) |
0x1E3
;
__invlpg(pMappingAddress);
Barrier();
ULONG64 PDPE
=
*
reinterpret_cast<PULONG64>(pMappingAddress
+
(PDPEIndex
*
sizeof(ULONG64)));
if
(!(PDPE &
1
))
{
goto Cleanup;
}
if
(!(PDPE &
0x80
))
/
/
如果不是大页(
1GB
)
{
/
/
6.2
.
3
获取 PDE
*
pPTE
=
(PDPE &
0xFFFFFFFFFF000ULL
) | (PDEIndex <<
3
) |
0x1E3
;
__invlpg(pMappingAddress);
Barrier();
ULONG64 PDE
=
*
reinterpret_cast<PULONG64>(pMappingAddress
+
(PDEIndex
*
sizeof(ULONG64)));
if
(!(PDE &
1
))
/
/
检查有效位
{
goto Cleanup;
}
if
(!(PDE &
0x80
))
/
/
如果不是大页 (
2MB
)
{
/
/
6.2
.
4
获取 PTE
*
pPTE
=
(PDE &
0xFFFFFFFFFF000ULL
) | (PTEIndex <<
3
) |
0x1E3
;
__invlpg(pMappingAddress);
Barrier();
ULONG64 PTE
=
*
reinterpret_cast<PULONG64>(pMappingAddress
+
(PTEIndex
*
sizeof(ULONG64)));
if
(!(PTE &
1
))
/
/
检查有效位
{
goto Cleanup;
}
/
/
6.2
.
5
4KB
页复制
PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress.QuadPart
=
(PTE &
0xFFFFFFFFFF000ULL
) | PageOffset;
/
/
设置 PTE 为可读写等
ULONG64 PTEFlags
=
483
;
if
(Flag
=
=
2
)
{
PTEFlags
=
511
;
}
*
pPTE
=
PhysicalAddress.QuadPart &
0xFFFFFFFFFFFFF000ULL
| PTEFlags;
__invlpg(pMappingAddress);
Barrier();
PVOID DestAddress
=
pMappingAddress
+
PageOffset;
PVOID SrcAddress
=
nullptr;
if
(Flag
=
=
0
) {
/
/
写
SrcAddress
=
pInternalBuffer
+
BytesCopied;
}
else
{
/
/
读
SrcAddress
=
DestAddress;
DestAddress
=
pInternalBuffer
+
BytesCopied;
}
SIZE_T BytesToCopyInPage
=
min
(
4096
-
PageOffset, BytesRemaining);
RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
BytesRemaining
-
=
BytesToCopyInPage;
BytesCopied
+
=
BytesToCopyInPage;
}
else
{
/
/
6.2
.
6
处理
2MB
大页
PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress.QuadPart
=
(PDE &
0xFFFFFFFE00000ULL
) | ((ULONG64)CurrentVirtualAddress &
0x1FFFFF
);
/
/
设置 PTE 为可读写等
ULONG64 PTEFlags
=
483
;
if
(Flag
=
=
2
)
{
PTEFlags
=
511
;
}
*
pPTE
=
PhysicalAddress.QuadPart &
0xFFFFFFFFFFFFF000ULL
| PTEFlags;
__invlpg(pMappingAddress);
Barrier();
PVOID DestAddress
=
pMappingAddress
+
((ULONG64)CurrentVirtualAddress &
0xFFF
);
PVOID SrcAddress
=
nullptr;
if
(Flag
=
=
0
) {
/
/
写
SrcAddress
=
pInternalBuffer
+
BytesCopied;
}
else
{
/
/
读
SrcAddress
=
DestAddress;
DestAddress
=
pInternalBuffer
+
BytesCopied;
}
SIZE_T BytesToCopyInPage
=
min
(
4096
-
((ULONG64)CurrentVirtualAddress &
0xFFF
), BytesRemaining);
RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
BytesRemaining
-
=
BytesToCopyInPage;
BytesCopied
+
=
BytesToCopyInPage;
}
}
else
{
/
/
6.2
.
7
处理
1GB
页
PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress.QuadPart
=
(PDPE &
0xFFFFFC0000000ULL
) | ((ULONG64)CurrentVirtualAddress &
0x3FFFFFFF
);
/
/
设置 PTE 为可读写等
ULONG64 PTEFlags
=
483
;
if
(Flag
=
=
2
)
{
PTEFlags
=
511
;
}
*
pPTE
=
PhysicalAddress.QuadPart &
0xFFFFFFFFFFFFF000ULL
| PTEFlags;
__invlpg(pMappingAddress);
Barrier();
PVOID DestAddress
=
pMappingAddress
+
((ULONG64)CurrentVirtualAddress &
0xFFF
);
PVOID SrcAddress
=
nullptr;
if
(Flag
=
=
0
) {
/
/
写
SrcAddress
=
pInternalBuffer
+
BytesCopied;
}
else
{
/
/
读
SrcAddress
=
DestAddress;
DestAddress
=
pInternalBuffer
+
BytesCopied;
}
SIZE_T BytesToCopyInPage
=
min
(
4096
-
((ULONG64)CurrentVirtualAddress &
0xFFF
), BytesRemaining);
RtlCopyMemory(DestAddress, SrcAddress, BytesToCopyInPage);
BytesRemaining
-
=
BytesToCopyInPage;
BytesCopied
+
=
BytesToCopyInPage;
}
}
Cleanup:
/
/
7.
恢复 PTE、IRQL 和中断
*
pPTE
=
OriginalPTE;
__invlpg(pMappingAddress);
Barrier();
if
(OldIrql < DISPATCH_LEVEL) {
KeLowerIrql(OldIrql);
}
/
/
8.
如果 Flag 为
0
,将数据从内部缓冲区复制到 SourceAddress
if
(Flag
=
=
0
) {
RtlCopyMemory(SourceAddress, pInternalBuffer, Size);
}
/
/
9.
清空内部缓冲区, 设置标志位, 返回
RtlZeroMemory(pInternalBuffer, Size);
byte_12B40[BuildNumber]
=
0
;
return
(NTSTATUS)(BytesRemaining
=
=
0
? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
}