分享
 
 
 

深入Windows NT/2000模块的组织

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

深入Windows NT/2000模块的组织

WebCrazy(http://webcrazy.yeah.net/)

在《小议Windows NT/2000分页机制 》中我对x86平台Windows NT/2000的非分页内存内部机制有了较为详细的说明,从中也可以看出地址空间可以分为进程空间与系统空间,其中每个进程有各自的进程空间,而所有的进程则共享同一个系统空间。所以Windows NT/2000在牵涉到模块管理时也涉及到进程私有的模块管理与系统共享模块管理两部分,下面我将从这两方面分别进行介绍。

正因为所有的进程共享同一个系统空间,所以系统模块主要是些操作系统代码模块或是些设备驱动程序代码等(它们一般进程都需要使用到),其位于系统4G内存的高端。Windows NT/2000内部由一系统变量PsLoadedModuleList指出,其具体结构为一双向链表。熟悉Windows NT/2000的人,都知道系统在发生蓝屏死机时,默认情况下都会将系统此时转储到MEMORY.DMP文件中,系统内核调试器i366kd或windbg在调试跟踪这个转储文件时也会根据这个系统变量重新装入系统崩溃前的已装载模块。我下面列出根据这个变量枚举系统模块的代码:

//-----------------------------------------------

//

// EnumKernelModules

// Only test on Windows 2000 Server Chinese Edition

// Build 2195(Free)!Programmed By WebCrazy

// (tsu00@263.net ) on 10-27-2000!

//

//-----------------------------------------------

ULONG PsLoadedModuleList=0x8046a4c0; //fetch from symbol file

#define KERNELMOD_IMAGEBASE_OFFSET 0x18

#define KERNELMOD_IMAGENAME_OFFSET 0x24

void EnumKernelModules()

{

PLIST_ENTRY pKernelModuleListHead, pKernelModuleListPtr;

PUNICODE_STRING pImageName;

if(((USHORT)NtBuildNumber)!=2195){

DbgPrint("Only test on Windows 2000 Server Build 2195!\n");

return;

}

DbgPrint("\n Base Addr\tModule Name");

DbgPrint("\n ---------\t-----------\n");

pKernelModuleListHead=pKernelModuleListPtr=(PLIST_ENTRY)(ULONG *)PsLoadedModuleList;

do{

pKernelModuleListPtr=pKernelModuleListPtr->Flink;

DbgPrint(" %08X",

*(ULONG *)((char *) pKernelModuleListPtr+KERNELMOD_IMAGEBASE_OFFSET));

pImageName = (PUNICODE_STRING)(ULONG *)((char *)

pKernelModuleListPtr+KERNELMOD_IMAGENAME_OFFSET);

DbgPrint("\t%S\n",pImageName->Buffer);

}while(pKernelModuleListPtr->Flink!=pKernelModuleListHead);

}

上面PsLoadedModuleList的值我直接从Symbol文件中获得,你可根据实际情况予以调整。好,先看看EnumKernelModules输出结果:

Base Addr Module Name

--------- -----------

80400000 \WINNT\System32\ntoskrnl.exe

80062000 \WINNT\System32\hal.dll

. .

. .

FD0F8000 \SystemRoot\System32\Drivers\Cdfs.SYS

FCDB1000 \SystemRoot\System32\DRIVERS\ipsec.sys

. .

. .

与Softice的mod命令基本相同,但值得注意的是Softice的mod命令不仅输出进程内核模块,而且也列出特定进程的用户态模块列表,那么系统又是如何管理进程特定模块的呢?

由于每个进程都拥有各自的模块,而所有这些模块都要求从用户态可以访问到。因此进程模块组织的数据结构应该位于用户态地址空间中,实际上Windows NT/2000进程模块列表是由PEB(Process Environment Block)结构中的成员指定,Windows NT/2000均将每个拥有用户态代码的进程的PEB置于0x7FFDF000处(2G空间以下,用户态代码可直接访问)。不过,Windows NT/2000一般通过TEB间接得到PEB的地址,即通过以下代码取得:

mov eax,fs:[18]

mov eax,[eax+30]

第一条语句获得当前线程的TEB地址,关于TEB及TEB地址的获得,请参阅《Windows NT/2000内部数据结构探究》,第二条语句获得位于TEB偏移30h处获得PEB地址。我想Windows NT/2000使用这种方法可能是考虑兼容性吧,我以下提供的代码直接使用了常量地址。

看看Windbg的分析吧:

> !ntsdexts.version

Version 5.0 (Build 2195) Uniprocessor Free

> !ntsdexts.peb

PEB at 7FFDF000

InheritedAddressSpace: No

ReadImageFileExecOptions: No

BeingDebugged: Yes

ImageBaseAddress: 01000000

Ldr.Initialized: Yes

Ldr.InInitializationOrderModuleList: 71f80 . 72808

Ldr.InLoadOrderModuleList: 71ee0 . 727f8

Ldr.InMemoryOrderModuleList: 71ee8 . 72800

01000000 D:\winnt\system32\calc.exe

77F80000 D:\WINNT\System32\ntdll.dll

77560000 D:\WINNT\system32\SHELL32.dll

77F40000 D:\WINNT\system32\GDI32.DLL

77E60000 D:\WINNT\system32\KERNEL32.DLL

77DF0000 D:\WINNT\system32\USER32.DLL

77D90000 D:\WINNT\system32\ADVAPI32.DLL

77D20000 D:\WINNT\system32\RPCRT4.DLL

77C50000 D:\WINNT\system32\SHLWAPI.DLL

77B30000 D:\WINNT\system32\COMCTL32.DLL

78000000 D:\WINNT\system32\MSVCRT.dll

SubSystemData: 0

ProcessHeap: 70000

ProcessParameters: 20000

WindowTitle: 'D:\winnt\system32\calc.exe'

ImageFile: 'D:\winnt\system32\calc.exe'

. .

. .

. .

Windbg的以上输出详细的显示了PEB各字段值,对其中数据跟踪分析后,我写了以下程序段直接读取系统结构获取进程模块列表:

//-----------------------------------------------

//

// EnumUserModules-information from PEB

// Only test on Windows 2000 Server Chinese Edition

// Build 2195(Free)!Programmed By WebCrazy

// (tsu00@263.net ) on 10-27-2000!

//

//-----------------------------------------------

#define PEBADDRESS 0x7ffdf000

#define PEB_LDR_DATA_OFFSET 0x0c

#define LDRDATA_IMAGEBASE_OFFSET 0x10

#define LDRDATA_IMAGENAME_OFFSET 0x1c

#pragma pack(4)

typedef struct _PEB_LDR_DATA

{

ULONG Length;

BOOLEAN Initialized;

PVOID SsHandle;

LIST_ENTRY InLoadOrderModuleList;

LIST_ENTRY InMemoryOrderModuleList;

LIST_ENTRY InInitializationOrderModuleList;

} PEB_LDR_DATA, *PPEB_LDR_DATA;

#pragma pack()

void EnumUserModules(void *kpeb)

{

PLIST_ENTRY pUserModuleListHead, pUserModuleListPtr;

PPEB_LDR_DATA pLdrData;

PUNICODE_STRING pImageName;

if(((USHORT)NtBuildNumber)!=2195){

DbgPrint("Only test on Windows 2000 Server Build 2195!\n");

return;

}

KeAttachProcess(kpeb);

pLdrData=(PPEB_LDR_DATA)(ULONG *)(*(ULONG *)(PEBADDRESS+PEB_LDR_DATA_OFFSET));

if(!pLdrData->Initialized){

DbgPrint("Process:%08X Not Initialized!\n",(ULONG)kpeb);

KeDetachProcess();

return;

}

DbgPrint("\n Base Addr\tModule Name");

DbgPrint("\n ---------\t-----------\n");

pUserModuleListHead=pUserModuleListPtr=

(PLIST_ENTRY)&(pLdrData->InMemoryOrderModuleList);

do{

pUserModuleListPtr=pUserModuleListPtr->Flink;

DbgPrint(" %08X",*(ULONG *)((char *)

pUserModuleListPtr+LDRDATA_IMAGEBASE_OFFSET));

pImageName = (PUNICODE_STRING)(ULONG *)((char *)

pUserModuleListPtr+LDRDATA_IMAGENAME_OFFSET);

DbgPrint("\t%S\n",pImageName->Buffer);

}while(pUserModuleListPtr->Flink!=pUserModuleListHead);

KeDetachProcess();

}

EnumUserModules程序段实现对特定进程(由参数kpeb所指定)模块的枚举,函数段并未实现对PEB合法性的检查,如Idle与system进程是纯内核态进程,他们并不存在用户态的PEB,解决办法可以通过检查TEB的合法性,这些进程TEB一般情况下都为0。EnumUserModules也没有对kpeb的合法性检查,其假设所有kpeb当前在系统中都存在,否则将出现意想不到的结果。虽然只涉及到用户态数据的读取,但程序段中使用了KeAttachProcess/KeDetachProcess内核例程,所以程序段只能在驱动代码中实现。EnumUserModules使用InMemoryOrderModuleList成员枚举模块列表的(见上Windbg输出结果,EnumUserModules的输出结果与其一致),当然你也可以使用InInitializationOrderModuleList或InLoadOrderModuleList成员。

上面已经说明了SoftICE中的mod命令将系统模块与进程模块列出,也就是说其实现了我提供的这两个程序段(SoftICE还输出PE模块的PE Header段,可以根据Base Addr按照PE规范取出PE Header的位置,另外我不确信SoftICE是不是使用同样的方法实现的)。

不论用户态的可执行Win32模块(.exe)或是核心态的驱动程序(.sys),还是系统动态链接库(.dll)在Windows NT/2000中均是以PE格式存在的,但也未必所有模块均为此格式,实际上所有文件均可以作为模块出现,如常见的nls文件等等。关于PE文件的装载,Windows NT/2000提供了以ldr开头的函数族,至于其结构已众所周知,我将不予介绍。

Windows 2000中实现了枚举系统模块的PSAPI与ToolHelp API(ToolHelp API在Win9X中早已实现,但Windows NT却仅使用PSAPI函数),我在跟踪分析这部分代码时原以为多少可以参阅一下这些函数的头文件中的一些譬如MODULEENTRY32或MODULEINFO等的定义,但系统内部却使用完全不同的格式.可以这样说系统内部的结构大而全且仅使用UNICODE格式,而这些API仅呈现API使用的部分定义,向用户隐藏了好多的内部特征。不过ToolHelp等使用Section对象(Win32 API称为FileMapping对象)映射整个模块实现模块的枚举,不过其最终都使用到EnumUserModules所引用的PEB数据。关于PEB还包含着许多系统数据,如ProcessHeap、ProcessParameters等等,感兴趣的话可以使用windbg/Softice好好挖掘挖掘!

参考资料:

1.David Solomom《Inside Windows NT,2nd Edition》

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有