Freeldr中镜像加载相关的操作在Freeldr/Freeldr/windows/Peloader.c文件中。
首先来看看如何加载一个PE镜像。这个操作在WinLdrLoadImage函数中。
这个函数的三个参数分别为镜像的Arc路径FileName, 镜像所处内存的内存属性MemoryType, 加载后镜像的基地址由ImageBasePA返回。
- BOOLEAN
- WinLdrLoadImage(IN PCHAR FileName,
- TYPE_OF_MEMORY MemoryType,
- OUT PVOID *ImageBasePA)
- {
- ......
- /* 在屏幕中央显示 Loading xxx... */
- sprintf(ProgressString, "Loading %s...", strchr(FileName, '//') + 1);
- UiDrawBackdrop();
- UiDrawProgressBarCenter(1, 100, ProgressString);
- /*打卡Arc路径的文件,并读取前两个sector。用来读取PE头*/
- Status = ArcOpen(FileName, OpenReadOnly, &FileId);
- if (Status != ESUCCESS)
- {
- //UiMessageBox("Can not open the file");
- return FALSE;
- }
- Status = ArcRead(FileId, HeadersBuffer, SECTOR_SIZE * 2, &BytesRead);
- if (Status != ESUCCESS)
- {
- UiMessageBox("Error reading from file");
- ArcClose(FileId);
- return FALSE;
- }
- /* 获得NT头指针 */
- NtHeaders = RtlImageNtHeader(HeadersBuffer);
- if (!NtHeaders)
- {
- UiMessageBox("Error - no NT header found");
- ArcClose(FileId);
- return FALSE;
- }
- /* 检测是否是可执行镜像 */
- if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
- {
- UiMessageBox("Not an executable image");
- ArcClose(FileId);
- return FALSE;
- }
- /* 从PE头中获得section数量, 并且获得节表的首地址 */
- NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
- SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
- /* 首先以PE头中的ImageBase为基地址申请存放镜像的内存, 如果失败就从任意地址申请内存 */
- PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
- (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
- MemoryType);
- if (PhysicalBase == NULL)
- {
- /* It's ok, we don't panic - let's allocate again at any other "low" place */
- PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
- if (PhysicalBase =