⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄

📁 兼容内核漫谈 适合想将Windows上的程序移植到其它平台上的朋友研究查看
💻
📖 第 1 页 / 共 5 页
字号:
  else
  {
    /* FIXME */
  }

   . . . . . .
   Status = PsCreatePeb(hProcess, Process, ImageBase);
                        /* FIXME - hProcess shouldn't be available at this point! */
   . . . . . .
  
   /*
    * Maybe send a message to the creator process's debugger
    */

   PspRunCreateProcessNotifyRoutine s(Process, TRUE);
  
   . . . . . .

   return Status;
}[/code]

    读者想必知道,LdrpMapSystemDll()的作用就是把ntdll.dll的映像映射到目标进程的用户空间,还包括获取其LdrInitializeThunk()、KiUserApcDispatcher()等函数的入口地址,具体的代码这里就不看了。接着的MmMapViewOfSection()则把目标EXE映像也映射到目标进程的用户空间。至于PsCreatePeb(),当然是创建PEB。PEB在用户空间的位置是0x7FFDF000。
    最后的PspRunCreateProcessNotifyRoutine s()依次调用预先设置在一个函数指针数组PiProcessNotifyRoutine[]中的函数,向有关方面发出已经创建了一个进程的通知。不过在ReactOS的0.2.6版中似乎还没有谁来设置这些函数,所以还只是空操作。
    倒是PsCreatePeb()还需要补充几句,因为从代码中看它还搞了点“副业”,就是把一个用于NLS的Section对象NlsSectionObject所代表的映像也映射到了目标进程的用户空间。这是因为PEB中的一些字段本来就与所用的语言文字有关。NLS是“National Language Support”即“本国语言支持”的缩写,主要就是不同的文字输入法。不过对此恐怕得要另作研究、另行撰文介绍,否则这儿就离题太远了。

    至此,作为一个对象的新建进程已经创建,并且已经挂入进程队列。不过,由NtCreateProcess()创建的新建进程在某些方面还是空白,有些手续也尚未完成,还是一个半成品,需要由创建者进一步将其变为成品并完成有关的手续,主要包括:
? l 设置新建进程的调度优先级。
? l 建立新建进程的“进程参数块”PPB。
? l 让新建进程从父进程继承允许遗传的已打开对象的Handle,把这些Handle复制给新建进程。
? l 向csrss发出已经创建了一个进程的通知。
? l 把PPB中的数据写入新建进程的PEB。
    下面我们回到CreateProcessW()的代码。

[code][CreateProcessW()]

   Status = NtSetInformationProcess(hProcess, ProcessPriorityClass,
                         &PriorityClass, sizeof(PROCESS_PRIORITY_CLASS));
   . . . . . .

   /* Create the PPB */
   RtlCreateProcessParameters(&Ppb, &ImagePathName_U, NULL,
                  lpCurrentDirectory ? &CurrentDirectory_U : NULL,
                  &CommandLine_U, lpEnvironment, NULL, NULL, NULL,
                  lpStartupInfo && lpStartupInfo->lpReserved2 ?
                                                &RuntimeInfo_U : NULL);
   . . . . . .
   /*
    * Translate some handles for the new process
    */
   if (Ppb->CurrentDirectoryHandle)
   {
      Status = NtDuplicateObject (NtCurrentProcess(),Ppb->CurrentDirectoryHandle,
                            hProcess, &Ppb->CurrentDirectoryHandle, 0, TRUE,
                            DUPLICATE_SAME_ACCESS);
   }
  
   /* Close the section */
   NtClose(hSection);

   /* Get some information about the process */
   NtQueryInformationProcess(hProcess,
        ProcessBasicInformation,
        &ProcessBasicInfo,
        sizeof(ProcessBasicInfo),
        &retlen);
   DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n",
   ProcessBasicInfo.UniqueProcessId);
   lpProcessInformation->dwProcessId = (DWORD)ProcessBasicInfo.UniqueProcessId;

   /* Tell the csrss server we are creating a new process */
   CsrRequest.Type = CSRSS_CREATE_PROCESS;
   CsrRequest.Data.CreateProcessRequest.NewProcessId =
     ProcessBasicInfo.UniqueProcessId;
   if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
     {
        /* Do not create a console for GUI applications */
        dwCreationFlags &= ~CREATE_NEW_CONSOLE;
        dwCreationFlags |= DETACHED_PROCESS;
     }
   else if (Sii.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
     {
        if (NULL == Ppb->hConsole)
          {
            dwCreationFlags |= CREATE_NEW_CONSOLE;
          }
     }
   CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags;
   CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher;
   Status = CsrClientCallServer(&CsrRequest, &CsrReply,
                   sizeof(CSRSS_API_REQUEST), sizeof(CSRSS_API_REPLY));
   . . . . . .

   Ppb->hConsole = CsrReply.Data.CreateProcessReply.Console;

   InputSet = FALSE;
   OutputSet = FALSE;
   ErrorSet = FALSE;

   /* Set the child console handles */

   /* First check if handles were passed in startup info */
   if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES))
   {
      if (lpStartupInfo->hStdInput)
      {
         Ppb->hStdInput = lpStartupInfo->hStdInput;
         InputSet = TRUE;
         InputDup = TRUE;
      }
      if (lpStartupInfo->hStdOutput)
      {
  Ppb->hStdOutput = lpStartupInfo->hStdOutput;
         OutputSet = TRUE;
         OutputDup = TRUE;
      }
      if (lpStartupInfo->hStdError)
      {
  Ppb->hStdError = lpStartupInfo->hStdError;
         ErrorSet = TRUE;
         ErrorDup = TRUE;
      }
   }

   /* Check if new console was created, use it for input and output if not overridden */
   if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE)
       && NT_SUCCESS(Status) && NT_SUCCESS(CsrReply.Status))
   {
      if (! InputSet)
      {
         Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
         InputSet = TRUE;
         InputDup = FALSE;
      }
      if (! OutputSet)
      {
         Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
         OutputSet = TRUE;
         OutputDup = FALSE;
      }
      if (! ErrorSet)
      {
         Ppb->hStdError = CsrReply.Data.CreateProcessReply.OutputHandle;
         ErrorSet = TRUE;
         ErrorDup = FALSE;
      }
   }

   /* Use existing handles otherwise */
   if (! InputSet)
   {
      Ppb->hStdInput = NtCurrentPeb()->ProcessParameters->hStdInput;
      InputDup = TRUE;
   }
   if (! OutputSet)
   {
      Ppb->hStdOutput = NtCurrentPeb()->ProcessParameters->hStdOutput;
      OutputDup = TRUE;
   }
   if (! ErrorSet)
   {
      Ppb->hStdError = NtCurrentPeb()->ProcessParameters->hStdError;
      ErrorDup = TRUE;
   }

   /* Now duplicate handles if required */
   if (InputDup)
   {
      if (IsConsoleHandle(Ppb->hStdInput))
      {
         Ppb->hStdInput = CsrReply.Data.CreateProcessReply.InputHandle;
      }
      else
      {
         DPRINT("Duplicate input handle\n");
         Status = NtDuplicateObject (NtCurrentProcess(), Ppb->hStdInput,
                                 hProcess, &Ppb->hStdInput,
                                 0, TRUE, DUPLICATE_SAME_ACCESS);
         . . . . . .
      }
   }

   if (OutputDup)
   {
      if (IsConsoleHandle(Ppb->hStdOutput))
      {
         Ppb->hStdOutput = CsrReply.Data.CreateProcessReply.OutputHandle;
      }
      else
      {
         DPRINT("Duplicate output handle\n");
         Status = NtDuplicateObject (NtCurrentProcess(), Ppb->hStdOutput,
                                 hProcess, &Ppb->hStdOutput,
                                 0, TRUE, DUPLICATE_SAME_ACCESS);
         . . . . . .
      }
   }

   . . . . . .

   /* Initialize some other fields in the PPB */
   if (lpStartupInfo)
     {
       Ppb->dwFlags = lpStartupInfo->dwFlags;
       if (Ppb->dwFlags & STARTF_USESHOWWINDOW)
  {
    Ppb->wShowWindow = lpStartupInfo->wShowWindow;
  }
     else
  {
    Ppb->wShowWindow = SW_SHOWDEFAULT;
  }
     Ppb->dwX = lpStartupInfo->dwX;
     Ppb->dwY = lpStartupInfo->dwY;
     Ppb->dwXSize = lpStartupInfo->dwXSize;
     Ppb->dwYSize = lpStartupInfo->dwYSize;
     Ppb->dwFillAttribute = lpStartupInfo->dwFillAttribute;
   }
   else
   {
       Ppb->Flags = 0;
   }
  
   /* Create Process Environment Block */
   DPRINT("Creating peb\n");

   KlInitPeb(hProcess, Ppb, &ImageBaseAddress, Sii.Subsystem);

   RtlDestroyProcessParameters (Ppb);[/code]
  


    前面已经准备下了一个数据结构PriorityClass,这里的NtSetInformationProcess()就把与调度优先级有关的信息设置到目标进程对象中去。
    此外,前面已经创建了PEB,并对其进行了最基本的设置,但是PEB是个不小的数据结构。特别地,PEB中还有个指针ProcessParameters,指向一个“进程参数块”PPB、即RTL_USER_PROCESS_PARAMETERS数据结构。这PPB也是在用户空间的,虽然是个独立存在的数据结构,逻辑上却可以看作是PEB的一部分。这里先通过RtlCreateProcessParameters()根据有关的信息在(创建者的用户空间)为新建进程创建起一个PPB的副本,经修改补充以后再通过KlInitPeb()写入新建进程的用户空间、并与其PEB建立起连接。
    下面陆续有一些对NtDuplicateObject()的调用。这就是用于跨进程复制Handle的系统调用,目的在于让新建进程继承其父进程的一些已打开的对象。不过这里只是复制了当前目录、标准输入、标准输出这三个对象,加上对标准出错信息通道的有条件复制(这里的代码中已略去),并且是从当前进程、而不是从父进程复制的,这样处理之正确与否待考。
    还有件事,就是向csrss报告新进程的创建,相当于“报户口”吧,这是由CsrClientCallServer()完成的。这些操作的结果有些也要记录在PPB中,所以对KlInitPeb()的调用是在完成了所有这些操作之后。
    至此,新进程的创建已经完成了。

    在Windows中,进程并非一个实际受调度运行的实体,也没有执行的上下文,而只是一个让线程赖以存身的框架。所以光创建进程而不创建其第一个线程、即其主线程,是没有意义的。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -