能力值:
( LV9,RANK:280 )
|
-
-
2 楼
msdn:如果调用方将 AllocateDestinationString 设置为 TRUE,则例程会将 DestinationString 的 Buffer 成员替换为它分配的缓冲区的指针。 即使例程返回错误状态代码,也可以覆盖旧值。
可能RtlAnsiStringToUnicodeString内部调ExAlloc分配内存的时候由于verifier设定,随机分配失败导致Buffer的值被覆盖成不知道什么东西了(可能是栈上的随机数据?),导致unload的时候显示Buffer是无效内存
你最好检查一下RtlAnsiStringToUnicodeString的返回值是不是STATUS_SUCCESS
最后于 2023-5-10 22:22
被hzqst编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
已测试,但看起来RtlAnsiStringToUnicodeString返回值是正常的,而且就算返回失败,紧接在它后面的MmIsAddressValid也应该失败。
(正文代码已更新)
|
能力值:
( LV10,RANK:163 )
|
-
-
4 楼
加载和卸载在同一线程里面弄的吗?
|
能力值:
( LV9,RANK:280 )
|
-
-
5 楼
yimingqpa
加载和卸载在同一线程里面弄的吗?
正常途径加载卸载的话都是插workitem到workerthread里弄的,但是题目这个问题我觉得跟线程没什么关系,他这块内存又不是给某个特定进程分配的
|
能力值:
( LV3,RANK:20 )
|
-
-
6 楼
https://blog.csdn.net/r250414958/article/details/108561713 MmIsValidAddress分析
|
能力值:
( LV10,RANK:163 )
|
-
-
7 楼
chatgpt: 在您的代码中,当开启了Verifier.exe的 "Force IRQL Checking" 选项时,您在驱动程序卸载函数DriverUnload中调用了MmIsAddressValid函数来检查g_ustr.Buffer的内存是否可访问,但返回值却为FALSE。而在未开启 "Force IRQL Checking" 选项时,MmIsAddressValid函数返回值为TRUE。这可能是由于 "Force IRQL Checking" 选项引起的内核地址空间访问权限的变化导致的。
在驱动程序的加载函数DriverEntry中,您成功地使用RtlAnsiStringToUnicodeString函数将一个ANSI_STRING类型的字符串转换为一个UNICODE_STRING类型的字符串,并为其分配了足够的内存空间。但在驱动程序卸载函数DriverUnload中,您使用MmIsAddressValid函数来检查g_ustr.Buffer的内存是否可访问,这可能是不必要的,因为您已经确定该内存空间是可用的。
根据我的测试,当我在Verifer.exe中启用了 "Force IRQL Checking" 选项时,MmIsAddressValid函数返回FALSE,因为此时驱动程序在卸载过程中尝试访问了非法的内存地址空间。这是因为,Windows内核在卸载驱动程序时会释放驱动程序所占用的所有内存空间,包括驱动程序中使用的所有内存空间。因此,当您在卸载过程中访问驱动程序中已释放的内存空间时,MmIsAddressValid函数将会返回FALSE。
因此,我建议您在卸载驱动程序时不要再访问g_ustr.Buffer指针,因为该内存空间已经被释放,并且您已经确定它在加载驱动程序时是可用的。如果您需要访问该内存空间中的数据,请在驱动程序退出之前将数据保存到另一个内存空间中。
希望这可以帮助您解决问题。如果您需要更多的帮助,请随时提供更多的信息和代码片段。
|
能力值:
( LV9,RANK:280 )
|
-
-
8 楼
PeterZheng
已测试,但看起来RtlAnsiStringToUnicodeString返回值是正常的,而且就算返回失败,紧接在它后面的MmIsAddressValid也应该失败。(正文代码已更新)
PVOID __fastcall ExpAllocateStringRoutine(SIZE_T NumberOfBytes) { return ExAllocatePoolWithTag(PagedPool, NumberOfBytes, 0x67727453u); } 看了下6楼又去看了下IDA,这下应该破案了
|
能力值:
( LV4,RANK:50 )
|
-
-
9 楼
因为是分配得分页内存。你自己使用非分页内存分配内存,然后用第三个FALSE参数取调用RtlAnsiStringToUnicodeString试试。
|
能力值:
( LV4,RANK:50 )
|
-
-
10 楼
MmIsValidAddress对分页内存判断不正确的。。。应该尽量避免调用这个函数!
最后于 2023-5-12 10:49
被fengyunabc编辑
,原因:
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
所以原因是由于verifier导致分页内存被换出,而MmIsAddressValid只检查内存页面的P位,导致不识别分页内存被换出的情况?
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
参考WRK复原了MmIsAddressValid函数,但是发现在UnloadRoutine的时候,PTE页的P位和A2位都被置0,貌似不是页面被换出的情形?
#include <ntifs.h>
UNICODE_STRING g_ustr = {0};
typedef struct _MMPTE_HARDWARE {
unsigned long long P : 1; // present (1 = present)
unsigned long long RW : 1; // read/write
unsigned long long US : 1; // user/supervisor
unsigned long long PWT : 1; // page-level write-through
unsigned long long PCD : 1; // page-level cache disabled
unsigned long long A : 1; // accessed
unsigned long long Reserved : 1; // dirty
unsigned long long PS : 1; // page size (0 = 4-KB page)
unsigned long long G : 1; // global page
unsigned long long A1 : 1; // available 1 aka copy-on-write
unsigned long long A2 : 1; // available 2/ is 1 when paged to disk
unsigned long long A3 : 1; // available 3
unsigned long long PFN : 28; // page-frame number
unsigned long long reserved1 : 12; // reserved
unsigned long long WS : 11; // SoftwareWsIndex
unsigned long long NE : 1; // NoExecute
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;
typedef struct _MMPTE {
union {
ULONG_PTR Long;
MMPTE_HARDWARE Hard;
} u;
} MMPTE, *PMMPTE;
#define PAGE_SHIFT 12L
#define PXE_BASE 0xFFFFF6FB7DBED000UI64
#define PXE_SELFMAP 0xFFFFF6FB7DBEDF68UI64
#define PPE_BASE 0xFFFFF6FB7DA00000UI64
#define PDE_BASE 0xFFFFF6FB40000000UI64
#define PTE_BASE 0xFFFFF68000000000UI64
#define PTE_PER_PAGE 512
#define PDE_PER_PAGE 512
#define PPE_PER_PAGE 512
#define PXE_PER_PAGE 512
#define PTI_MASK_AMD64 (PTE_PER_PAGE - 1)
#define PDI_MASK_AMD64 (PDE_PER_PAGE - 1)
#define PPI_MASK (PPE_PER_PAGE - 1)
#define PXI_MASK (PXE_PER_PAGE - 1)
#define VIRTUAL_ADDRESS_BITS 48
#define VIRTUAL_ADDRESS_MASK ((((ULONG_PTR)1) << VIRTUAL_ADDRESS_BITS) - 1)
#define PTI_SHIFT 12
#define PDI_SHIFT 21
#define PPI_SHIFT 30
#define PXI_SHIFT 39
#define PTE_SHIFT 3
#define MiGetPxeOffset(va) ((ULONG)(((ULONG_PTR)(va) >> PXI_SHIFT) & PXI_MASK))
#define MiGetPxeAddress(va) ((PMMPTE)PXE_BASE + MiGetPxeOffset(va))
#define MiGetPpeAddress(va) \
((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PPI_SHIFT) << PTE_SHIFT) + PPE_BASE))
#define MiGetPdeAddress(va) \
((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PDI_SHIFT) << PTE_SHIFT) + PDE_BASE))
#define MiGetPteAddress(va) \
((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PTI_SHIFT) << PTE_SHIFT) + PTE_BASE))
#define MI_PDE_MAPS_LARGE_PAGE(PDE) ((PDE)->u.Hard.PS == 1)
BOOLEAN MyMmIsAddressValid(PVOID Address) {
ULONG_PTR StartAddress = (ULONG_PTR)Address;
PMMPTE PointerPte = NULL;
UINT_PTR kernelbase = 0x7fffffffffffffffULL;
UINT_PTR toppart = 0;
if (!StartAddress) {
return FALSE;
}
// cannonical check. Bits 48 to 63 must match bit 47
toppart = (StartAddress >> 47);
if (toppart & 1) {
// toppart must be 0x1ffff
if (toppart != 0x1ffff)
return FALSE;
} else {
// toppart must be 0
if (toppart != 0)
return FALSE;
}
PointerPte = MiGetPxeAddress (Address);
if (PointerPte->u.Hard.P == 0) {
return FALSE;
}
PointerPte = MiGetPpeAddress (Address);
if (PointerPte->u.Hard.P == 0) {
return FALSE;
}
PointerPte = MiGetPdeAddress (Address);
if (PointerPte->u.Hard.P == 0) {
return FALSE;
}
if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {
return TRUE;
}
PointerPte = MiGetPteAddress (Address);
if (PointerPte->u.Hard.P == 0) {
return FALSE;
}
if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {
return FALSE;
}
return TRUE;
}
VOID DriverUnload(PDRIVER_OBJECT pDrvObj) {
/*
* 当开启verifier的Force IRQL Checking时"MmIsAddressValid"会返回False,否则返回True
*/
KIRQL irql = KeGetCurrentIrql();
DbgPrint("Unload IRQL [%d] \n", irql);
DbgBreakPoint();
DbgPrint("Ustr --> [%wZ][%d] \n", &g_ustr, MyMmIsAddressValid(g_ustr.Buffer));
RtlFreeUnicodeString(&g_ustr);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pUstrRegPath) {
NTSTATUS status = STATUS_SUCCESS;
ANSI_STRING ansiString;
RtlInitAnsiString(&ansiString, "abbccddee");
pDrvObj->DriverUnload = DriverUnload;
status = RtlAnsiStringToUnicodeString(&g_ustr, &ansiString, TRUE);
DbgPrint("RtlAnsiStringToUnicodeString return [0x%X] \n", status);
if (!NT_SUCCESS(status)) {
return STATUS_UNSUCCESSFUL;
}
/*
* 此处不影响,"MmIsAddressValid"的返回值依然是True
*/
DbgBreakPoint();
DbgPrint("Ustr --> [%wZ][%d] \n", &g_ustr, MyMmIsAddressValid(g_ustr.Buffer));
return STATUS_SUCCESS;
}
|
能力值:
(RANK:15 )
|
-
-
13 楼
有问题的应该不是MmIsAddressValid,而是RtlAnsiStringToUnicodeString,Verifier会把他用IAT HOOK替换成VerifierRtlAnsiStringToUnicodeString
|
|
|