由_SEGMENT结构的变化引出的PAE问题

由_SEGMENT结构的变化引出的PAE问题


在根据微软提供的符号文件查找_SEGMENT中BaseAddress成员偏移的时候,发现这个成员的在结构中的偏移在ntoskrnl.exe/ntkrnlmp.exe中与ntkrnlpa.exe/ntkrpamp.exe中是不同的,自Windows 2000至Windows 2003都这样,而且_SEGMENT结构都不同。因此google了一下,找到了这几个文件的区别( Ntoskrnl)。这几个文件都是Windows的内核,但只会有一个被加载并运行,文件的选择是根据CPU数目及是否开启PAE支持决定的。(注:PAE仅用于32位系统。)
具体如下:

Names of kernel

  • NTOSKRNL.EXE : 1 CPU
  • NTKRNLMP.EXE : N CPU SMP
  • NTKRNLPA.EXE : 1 CPU, PAE
  • NTKRPAMP.EXE : N CPU SMPPAE

《深入解析Windows操作系统 第四版》第43页表2.2列出了与上述内容一致的信息。

《深入解析Windows操作系统 第四版》第436页最后一段说明,要想选择支持PAE的内核,必须在boot.ini中通过/PAE开关来引导系统。但是通过用WinDbg调试在VMWare中的Winows XP sp2 32bit发现,在boot.ini并未使用/PAE开关时,系统加载的内核竟然是ntkrnlpa.exe。这说明,某种原因造成/PAE开关默认开启。
感谢Wikipedia,感谢 Physical_Address_Extension
Windows XP Service Pack 2 and later, by default, on processors with the no-execute (NX) or execute-disable (XD) feature, runs in PAE mode in order to allow NX.[11] The NX (or XD) bit resides in bit 63 of the page table entry and, without PAE, page table entries only have 32 bits; therefore PAE mode is required if the NX feature is to be exploited. However, desktop versions of Windows (Windows XP, Windows Vista) limit physical address space to 4 GiB for driver compatibility and licensing[12] reasons.

记忆中NX bit貌似是DEP(数据执行保护)功能中用到的。考虑到DEP是XP sp2中加入的新功能,也就顺理成章了。也就是说,开启DEP功能的系统默认开启PAE支持。这一推论在MSDN中一篇关于PAE的文章中得到证实。

由此看来,_SEGMENT中BaseAddress成员偏移需要根据CPU数量和是否开启PAE来获得。

但是,在ntddk.h中发现如下定义

#if (NTDDI_VERSION >= NTDDI_VISTA)
extern NTSYSAPI volatile CCHAR KeNumberProcessors;
#else
#if (NTDDI_VERSION >= NTDDI_WINXP)
extern NTSYSAPI CCHAR KeNumberProcessors;
#else
extern PCCHAR KeNumberProcessors;
#endif
#endif

而且,MSDN中KeNumberProcessors的说明中也说:

Windows Server 2008 includes support for Dynamic Hardware Partitioning (DHP) in the Windows Datacenter and Enterprise Edition SKUs. As part of DHP, Windows Server 2008 supports hot adding CPUs at runtime. In a hot-add CPU environment, the number of processors may not remain constant during runtime.

Accordingly, in Windows Server 2008, code that can determine the number of processors must use KeQueryActiveProcessors instead of direct references to the kernel variable, KeNumberProcessors.

Requirements

Versions: Obsolete in Windows Vista with Service Pack 1 (SP1), Windows Server 2008, and later operating systems.


也就是说,获取CPU数目想要做到Compile Once, Run Any-version NT Platforms可不太容易。

那么我们能不能直接获取当前系统使用的内核文件的名称呢?

经过调试得到一个重要的信息:
kd> dd PsLoadedModuleList
805541a0  821fc3a8 820430c0 00000000 00000000
805541b0  00000000 00000000 00000000 00000000
kd> dt _LDR_DATA_TABLE_ENTRY 821fc3a8 
nt!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY [ 0x821fc340 - 0x805541a0 ]
   +0x008 InMemoryOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x010 InInitializationOrderLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x018 DllBase          : 0x804d8000 
   +0x01c EntryPoint       : 0x8068e6dc 
   +0x020 SizeOfImage      : 0x1f6100
   +0x024 FullDllName      : _UNICODE_STRING "WINDOWSsystem32ntkrnlpa.exe"
   +0x02c BaseDllName      : _UNICODE_STRING "ntoskrnl.exe"
   +0x034 Flags            : 0xc004000
   +0x038 LoadCount        : 1
   +0x03a TlsIndex         : 0
   +0x03c HashLinks        : _LIST_ENTRY [ 0x0 - 0x1f6612 ]
   +0x03c SectionPointer   : (null) 
   +0x040 CheckSum         : 0x1f6612
   +0x044 TimeDateStamp    : 0
   +0x044 LoadedImports    : (null) 
   +0x048 EntryPointActivationContext : (null) 
   +0x04c PatchInformation : 0x0074006e 

通过FullDllName就能获得当前使用的内核文件的准确路径和名称了。代码如下:

typedef enum _ENUM_KERNEL_FILE
{
EKF_unknown = 0,
EKF_ntoskrnl,
EKF_ntkrnlpa,
EKF_ntkrnlmp,
EKF_ntkrpamp,
} ENUM_KERNEL_FILE;

#define PAE_ENABLED(a) ((a)==EKF_ntkrnlpa || (a)==EKF_ntkrpamp)
#define PAE_DISABLED(a) ((a)==EKF_ntoskrnl || (a)==EKF_ntkrnlmp)

// 在DriverEntry中调用
ENUM_KERNEL_FILE GetKernelFileType(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING usNtoskrnl;
UNICODE_STRING usNtkrnlpa;
UNICODE_STRING usNtkrnlmp;
UNICODE_STRING usNtkrpamp;
UNICODE_STRING usFileName;

WCHAR szNtoskrnl[] = L"ntoskrnl.exe";
WCHAR szNtkrnlpa[] = L"ntkrnlpa.exe";
WCHAR szNtkrnlmp[] = L"ntkrnlmp.exe";
WCHAR szNtkrpamp[] = L"ntkrpamp.exe";

PUNICODE_STRING pusFileFullName = NULL;

PLIST_ENTRY PsLoadedModuleList = ((PLIST_ENTRY)(DriverObject->DriverSection))->Flink;
// _LDR_DATA_TABLE_ENTRY
// +0x024 FullDllName
// 2000到Win7都一样
pusFileFullName = (PUNICODE_STRING)RVATOVA(PsLoadedModuleList->Flink, 0x24);

RtlInitUnicodeString(&usFileName, &pusFileFullName->Buffer[pusFileFullName->Length/2-12]);   //24字节=12宽字符
RtlInitUnicodeString(&usNtkrnlpa, szNtkrnlpa);
RtlInitUnicodeString(&usNtkrnlmp, szNtkrnlmp);
RtlInitUnicodeString(&usNtkrpamp, szNtkrpamp);
RtlInitUnicodeString(&usNtoskrnl, szNtoskrnl);

if (0 == RtlCompareUnicodeString(&usFileName, &usNtoskrnl, TRUE))
{
    return EKF_ntoskrnl;
}
if (0 == RtlCompareUnicodeString(&usFileName, &usNtkrnlpa, TRUE))
{
    return EKF_ntkrnlpa;
}

if (0 == RtlCompareUnicodeString(&usFileName, &usNtkrnlmp, TRUE))
{
    return EKF_ntkrnlmp;
}

if (0 == RtlCompareUnicodeString(&usFileName, &usNtkrpamp, TRUE))
{
    return EKF_ntkrpamp;
}

return EKF_unknown;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值