先来介绍几个重要的结构。Freeldr虽然是个引导程序,严格来讲不属于操作系统的一部分,但它也有一些类似Windows系统中的数据结构。
LOADER_PARAMETER_BLOCK这个可以看作Freeldr的PEB,结构也和PEB非常相似。
/include/reactos/arc/arc.h
- typedef struct _LOADER_PARAMETER_BLOCK
- {
- LIST_ENTRY LoadOrderListHead;
- LIST_ENTRY MemoryDescriptorListHead;
- LIST_ENTRY BootDriverListHead;
- ......
- } LOADER_PARAMETER_BLOCK, *PLOADER_PARAMETER_BLOCK;
这里我们只看前三个域。和PEB中一样,前三个元素是三个表头,Freeldr每加载一个模块就会生成一个LDR_DATA_TABLE_ENTRY结构,并将这个结构连入这三个链表。
LoadOrder是按照夹在顺序排序的,Memory按照内存位置排序,BootDriver按照分区号排序。在Freeldr中只使用了LoadOrderListHead。
LDR_DATA_TABLE_ENTRY的结构定义在include/ndk/Ldrtypes.h中
- typedef struct _LDR_DATA_TABLE_ENTRY
- {
- LIST_ENTRY InLoadOrderLinks; // 用来连入LoadOrderListHead等的表头
- LIST_ENTRY InMemoryOrderModuleList;
- LIST_ENTRY InInitializationOrderModuleList;
- PVOID DllBase; // 模块基地址
- PVOID EntryPoint; // 入口点
- ULONG SizeOfImage; // 内存镜像大小
- UNICODE_STRING FullDllName; // 文件全路径
- UNICODE_STRING BaseDllName; // 模块名, 不一定和全路径的文件名相同
- ULONG Flags; // 一些标志
- USHORT LoadCount; // 引用计数
- USHORT TlsIndex;
- union
- {
- LIST_ENTRY HashLinks;
- struct
- {
- PVOID SectionPointer;
- ULONG CheckSum; // 校验和
- };
- };
- union
- {
- ULONG TimeDateStamp;
- PVOID LoadedImports;
- };
- PVOID EntryPointActivationContext;
- PVOID PatchInformation;
- } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
我做过注释的是Freeldr实际用到的域。注意这里BaseDllName中记录的模块名不一定和模块的实际文件名相同。许多BaseDllName是硬编码的只具有参考意义。
上一节读的WinLdrLoadImage函数,只是把文件从硬盘中读出来按照PE格式对其,并没有涉及上面所说的结构。所以Freeldr中WinLdrLoadImage往往都是和WinLdrAllocateDataTableEntry函数配合使用的。WinLdrLoadImage负责加载镜像,WinLdrAllocateDataTableEntry负责生成、初始化对应的LDR_DATA_TABLE_ENTRY结构。
- BOOLEAN
- WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
- IN PCCH BaseDllName,
- IN PCCH FullDllName,
- IN PVOID BasePA,
- OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
- {
- PVOID BaseVA = PaToVa(BasePA);
- ......
- /* 申请LDR_DATA_TABLE_ENTRY结构 */
- DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY));