reactos操作系统实现(84)

来源:互联网 发布:法国黑人知乎 编辑:程序博客网 时间:2024/04/27 11:32

在系统里User32.dllkernel32.dllshell32.dllgdi32.dllrpcrt4.dllcomctl32.dlladvapi32.dllversion.dlldll代表了Win32 API的基本提供者。Win32 API中的所有调用最终都转向了ntdll.dll,再由它转发至ntoskrnl.exentdll.dll是本机 API用户模式的终端。真正的接口在ntoskrnl.exe里完成。事实上,内核模式的驱动大部分时间调用这个模块,如果它们请求系统服务。Ntdll.dll的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过软件中断int 2Eh进入ntoskrnl.exe,就是通过中断门切换CPU特权级。比如kernel32.dll导出的函数DeviceIoControl()实际上调用ntdll.dll中导出的NtDeviceIoControlFile(),反汇编一下这个函数可以看到,EAX载入magic0x38,实际上是系统调用号,然后EDX指向堆栈。目标地址是当前堆栈指针ESP+4,所以EDX指向返回地址后面一个,也就是指向在进入NtDeviceIoControlFile()之前存入堆栈的东西。事实上就是函数的参数。下一个指令是int 2Eh,转到中断描述符表IDT位置0x2E处的中断处理程序。

下面就来分析怎么样加载NTDLL.DLL,具体实现代码始下:

#001  NTSTATUS

#002  NTAPI

#003  PsLocateSystemDll(VOID)

#004  {

#005      OBJECT_ATTRIBUTES ObjectAttributes;

#006      IO_STATUS_BLOCK IoStatusBlock;

#007      HANDLE FileHandle, SectionHandle;

#008      NTSTATUS Status;

#009      ULONG_PTR HardErrorParameters;

#010      ULONG HardErrorResponse;

#011 

 

初始化NTDLL.DLL的对象,其中PsNtDllPathName是它的名称//SystemRoot//system32//ntdll.dll。在前面已经把系统路径设置好了。

#012      /* Locate and open NTDLL to determineImageBase and LdrStartup */

#013     InitializeObjectAttributes(&ObjectAttributes,

#014                                &PsNtDllPathName,

#015                                 0,

#016                                 NULL,

#017                                 NULL);

 

打开文件NTDLL.DLL

#018      Status = ZwOpenFile(&FileHandle,

#019                          FILE_READ_ACCESS,

#020                         &ObjectAttributes,

#021                          &IoStatusBlock,

#022                          FILE_SHARE_READ,

#023                          0);

#024      if (!NT_SUCCESS(Status))

#025      {

#026          /* Failed, bugcheck */

#027         KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 2, 0, 0);

#028      }

#029 

 

检查NTDLL.DLL文件是否合法。

#030      /* Check if the image is valid */

#031      Status = MmCheckSystemImage(FileHandle,TRUE);

#032      if (Status ==STATUS_IMAGE_CHECKSUM_MISMATCH)

#033      {

#034          /* Raise a hard error */

#035          HardErrorParameters =(ULONG_PTR)&PsNtDllPathName;

#036          NtRaiseHardError(Status,

#037                           1,

#038                           1,

#039                          &HardErrorParameters,

#040                           OptionOk,

#041                           &HardErrorResponse);

#042          return Status;

#043      }

#044 

 

NTDLL.DLL文件创建代码和数据段。

#045      /* Create a section for NTDLL */

#046      Status =ZwCreateSection(&SectionHandle,

#047                              SECTION_ALL_ACCESS,

#048                               NULL,

#049                               NULL,

#050                               PAGE_EXECUTE,

#051                               SEC_IMAGE,

#052                               FileHandle);

#053      ZwClose(FileHandle);

#054      if (!NT_SUCCESS(Status))

#055      {

#056          /* Failed, bugcheck */

#057         KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 3, 0, 0);

#058      }

#059 

 

添加引用段对象。

#060      /* Reference the Section */

#061      Status =ObReferenceObjectByHandle(SectionHandle,

#062                                        SECTION_ALL_ACCESS,

#063                                        MmSectionObjectType,

#064                                         KernelMode,

#065                                        (PVOID*)&PspSystemDllSection,

#066                                         NULL);

#067      ZwClose(SectionHandle);

#068      if (!NT_SUCCESS(Status))

#069      {

#070          /* Failed, bugcheck */

#071         KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 4, 0, 0);

#072      }

#073 

 

       NTDLL.DLL映射到内核空间。PspSystemDllBase是动态连接库的基地址。

#074      /* Map it */

#075      Status =PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase, FALSE);

#076      if (!NT_SUCCESS(Status))

#077      {

#078          /* Failed, bugcheck */

#079          KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED,Status, 5, 0, 0);

#080      }

#081 

#082      /* Return status */

#083      return Status;

#084  }