CreateProcess进程创建的内核跟踪分析

*[标题]:CreateProcess进程创建的内核跟踪分析
*[作者]:gz1X [gz1x(at)tom(dot)com]
*[来自]:中国黑客联盟 [CHU]

   
*[正文]:


[实现流程]
——————————————————————
1.打开需要执行的文件(.exe);
2.创建执行体进程对象; //<-------重点
3.创建初始线程; //<-------重点
4.通知WIN32子系统设置新进程和线程;
5.启动执行体开始执行;
6.完成地址空间的初始化,开始执行程序。


[阶段一]
——————————————————————
当我们调用CreateProcess函数时,需要指定一个文件映象,一般是.exe文件。
CreateProcess第一件事就是打开这个文件,为它创建一个文件映射对象。但是并没有真正映射到内存中。
这里需要注意的是,能创建文件映射对象并不代表文件是有效的win32文件,dll文件也能被成功打开。
显然,如果是dll,CreateProcess将失败。

现在我们来验证,反汇编kernel32.dll,可以看到:
.text:7C802367 CreateProcessA  proc near               ; CODE XREF: LoadModule+126p
//..此处省略
.text:7C80238C                 push    0
.text:7C80238E                 call    CreateProcessInternalA
.text:7C802393                 pop     ebp
.text:7C802394                 retn    28h
.text:7C802394 CreateProcessA  endp
再接着看CreateProcessInternalA函数,跟进去可以看到这里:
.text:7C81DEC2                 call    CreateProcessInternalW
在往里跟,进CreateProcessInternalW的领空,走过:
.text:7C8197A8                 call    ds:NtQueryInformationJobObject
到这里:
.text:7C8197D9                 cmp     [eax], bl
.text:7C8197DB                 jz      loc_7C818CE6
接下来就是关键代码了,挑重点的函数调用列举出来:
.text:7C818D2C                 call    ds:NtAllocateVirtualMemory   //设置内存映象空间;
.text:7C818E6B                 call    ds:RtlDosPathNameToNtPathName_U  //将DOS文件名转换成NT文件名;
.text:7C818F3A                 call    esi ; NtOpenFile   //打开.exe文件;
.text:7C818F71                 call    ds:NtCreateSection   //建立文件映射对象;
.text:7C819098                 call    ds:NtQuerySection   //取得文件映射对象的相关信息;
.text:7C8190E4                 call    LdrQueryImageFileExecutionOptions
检查是否是一个POSIX文件,是则运行POSIX.EXE;
.text:7C819238                 call    ds:NtCreateProcessEx
调用系统函数创建进程执行体。
大致上从函数名再结合上面给出的解释,很容易能猜到各个函数实现的功能,由于各个函数都是未公开的,详细函数声明您可以到:
http://undocumented.ntinternals.net/


[阶段二] -0
——————————————————————
为了方便说明,我们先通过Windbg把当前进程的EPROCESS块结构了解清楚:
0:000> dt _eprocess
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS                      //<------内核进程块
   +0x06c ProcessLock      : _EX_PUSH_LOCK
   +0x070 CreateTime       : _LARGE_INTEGER
   +0x078 ExitTime         : _LARGE_INTEGER
   +0x080 RundownProtect   : _EX_RUNDOWN_REF
   +0x084 UniqueProcessId  : Ptr32 Void //<-------进程标识符
   +0x088 ActiveProcessLinks : _LIST_ENTRY
   +0x090 QuotaUsage       : [3] Uint4B
   +0x09c QuotaPeak        : [3] Uint4B
   +0x0a8 CommitCharge     : Uint4B
   +0x0ac PeakVirtualSize  : Uint4B
   +0x0b0 VirtualSize      : Uint4B
   +0x0b4 SessionProcessLinks : _LIST_ENTRY
   +0x0bc DebugPort        : Ptr32 Void
   +0x0c0 ExceptionPort    : Ptr32 Void
   +0x0c4 ObjectTable      : Ptr32 _HANDLE_TABLE
   +0x0c8 Token            : _EX_FAST_REF //<-------访问令牌
   +0x0cc WorkingSetLock   : _FAST_MUTEX
   +0x0ec WorkingSetPage   : Uint4B
   +0x0f0 AddressCreationLock : _FAST_MUTEX
   +0x110 HyperSpaceLock   : Uint4B
   +0x114 ForkInProgress   : Ptr32 _ETHREAD
   +0x118 HardwareTrigger  : Uint4B
   +0x11c VadRoot          : Ptr32 Void //<-------虚拟地址空间
   +0x120 VadHint          : Ptr32 Void
   +0x124 CloneRoot        : Ptr32 Void
   +0x128 NumberOfPrivatePages : Uint4B
   +0x12c NumberOfLockedPages : Uint4B
   +0x130 Win32Process     : Ptr32 Void //<-------win32子系统进程块
   +0x134 Job              : Ptr32 _EJOB
   +0x138 SectionObject    : Ptr32 Void
   +0x13c SectionBaseAddress : Ptr32 Void
   +0x140 QuotaBlock       : Ptr32 _EPROCESS_QUOTA_BLOCK
   +0x144 WorkingSetWatch  : Ptr32 _PAGEFAULT_HISTORY
   +0x148 Win32WindowStation : Ptr32 Void
   +0x14c InheritedFromUniqueProcessId : Ptr32 Void
   +0x150 LdtInformation   : Ptr32 Void
   +0x154 VadFreeHint      : Ptr32 Void
   +0x158 VdmObjects       : Ptr32 Void
   +0x15c DeviceMap        : Ptr32 Void
   +0x160 PhysicalVadList  : _LIST_ENTRY
   +0x168 PageDirectoryPte : _HARDWARE_PTE_X86
   +0x168 Filler           : Uint8B
   +0x170 Session          : Ptr32 Void
   +0x174 ImageFileName    : [16] UChar
   +0x184 JobLinks         : _LIST_ENTRY
   +0x18c LockedPagesList  : Ptr32 Void
   +0x190 ThreadListHead   : _LIST_ENTRY
   +0x198 SecurityPort     : Ptr32 Void
   +0x19c PaeTop           : Ptr32 Void
   +0x1a0 ActiveThreads    : Uint4B
   +0x1a4 GrantedAccess    : Uint4B
   +0x1a8 DefaultHardErrorProcessing : Uint4B
   +0x1ac LastThreadExitStatus : Int4B
   +0x1b0 Peb              : Ptr32 _PEB //<--------进程环境块
   +0x1b4 PrefetchTrace    : _EX_FAST_REF
   +0x1b8 ReadOperationCount : _LARGE_INTEGER
   +0x1c0 WriteOperationCount : _LARGE_INTEGER
   +0x1c8 OtherOperationCount : _LARGE_INTEGER
   +0x1d0 ReadTransferCount : _LARGE_INTEGER
   +0x1d8 WriteTransferCount : _LARGE_INTEGER
   +0x1e0 OtherTransferCount : _LARGE_INTEGER
   +0x1e8 CommitChargeLimit : Uint4B
   +0x1ec CommitChargePeak : Uint4B
   +0x1f0 AweInfo          : Ptr32 Void
   +0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f8 Vm               : _MMSUPPORT
   +0x238 LastFaultCount   : Uint4B
   +0x23c ModifiedPageCount : Uint4B
   +0x240 NumberOfVads     : Uint4B
   +0x244 JobStatus        : Uint4B
   +0x248 Flags            : Uint4B
   +0x248 CreateReported   : Pos 0, 1 Bit
   +0x248 NoDebugInherit   : Pos 1, 1 Bit
   +0x248 ProcessExiting   : Pos 2, 1 Bit
   +0x248 ProcessDelete    : Pos 3, 1 Bit
   +0x248 Wow64SplitPages  : Pos 4, 1 Bit
   +0x248 VmDeleted        : Pos 5, 1 Bit
   +0x248 OutswapEnabled   : Pos 6, 1 Bit
   +0x248 Outswapped       : Pos 7, 1 Bit
   +0x248 ForkFailed       : Pos 8, 1 Bit
   +0x248 HasPhysicalVad   : Pos 9, 1 Bit
   +0x248 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x248 SetTimerResolution : Pos 12, 1 Bit
   +0x248 BreakOnTermination : Pos 13, 1 Bit
   +0x248 SessionCreationUnderway : Pos 14, 1 Bit
   +0x248 WriteWatch       : Pos 15, 1 Bit
   +0x248 ProcessInSession : Pos 16, 1 Bit
   +0x248 OverrideAddressSpace : Pos 17, 1 Bit
   +0x248 HasAddressSpace  : Pos 18, 1 Bit
   +0x248 LaunchPrefetched : Pos 19, 1 Bit
   +0x248 InjectInpageErrors : Pos 20, 1 Bit
   +0x248 VmTopDown        : Pos 21, 1 Bit
   +0x248 Unused3          : Pos 22, 1 Bit
   +0x248 Unused4          : Pos 23, 1 Bit
   +0x248 VdmAllowed       : Pos 24, 1 Bit
   +0x248 Unused           : Pos 25, 5 Bits
   +0x248 Unused1          : Pos 30, 1 Bit
   +0x248 Unused2          : Pos 31, 1 Bit
   +0x24c ExitStatus       : Int4B
   +0x250 NextPageColor    : Uint2B
   +0x252 SubSystemMinorVersion : UChar
   +0x253 SubSystemMajorVersion : UChar
   +0x252 SubSystemVersion : Uint2B
   +0x254 PriorityClass    : UChar
   +0x255 WorkingSetAcquiredUnsafe : UChar
   +0x258 Cookie           : Uint4B


[阶段二] -1
——————————————————————
第二步创建执行体进程对象,大致上包括以下几个方面:
1.设置EPROCESS块;
2.创建初始进程空间地址;
3.创建内核进程块;
4.决定进程地址空间的设置;
5.设置PEB;
6.完成执行体进程对象的设置。
这几项大都是内核实现的,详细的过程可以参考书目[Inside Windows NT],这里只把一些关键的东西挑出来。

那么我们反汇编ntoskrnl.exe,找到:
PAGE:004AAE82 __stdcall NtCreateProcessEx(x, x, x, x, x, x, x, x, x) proc near
PAGE:004AAE82                                         ; CODE XREF: NtCreateProcess(x,x,x,x,x,x,x,x)+3Dp
PAGE:004AAE82                                         ; DATA XREF: .text:0040B768o
//...
PAGE:004AAEDF                 call    PspCreateProcess(x,x,x,x,x,x,x,x,x)
//...
PAGE:004AAEE9                 retn    24h
PAGE:004AAEE9 __stdcall NtCreateProcessEx(x, x, x, x, x, x, x, x, x) endp

好,下面就是重头戏了。跟进PspCreateProcess:

PAGE:004AB2CB                 push    esi             ; HandleInformation
PAGE:004AB2CC                 lea     eax, [ebp+Object]
PAGE:004AB2CF                 push    eax             ; Object
PAGE:004AB2D0                 push    dword ptr [ebp+PreviousMode] ; AccessMode
PAGE:004AB2D3                 push    _PsProcessType  ; ObjectType
PAGE:004AB2D9                 push    80h             ; DesiredAccess
PAGE:004AB2DE                 push    [ebp+Handle]    ; Handle
PAGE:004AB2E1                 call    ObReferenceObjectByHandle(x,x,x,x,x,x)
这次调用ObReferenceObjectByHandle作用主要是设置父进程,为后面新进程的创建做好准备。

PAGE:004AB300                 mov     [ebp+var_64], eax
PAGE:004AB303                 mov     eax, ds:_PsMinimumWorkingSet
PAGE:004AB308                 mov     [ebp+var_60], eax
PAGE:004AB30B                 mov     eax, ds:_PsMaximumWorkingSet
这几句就是在设置进程的最小和最大工作集了。

PAGE:004AB32E                 call    ObCreateObject(x,x,x,x,x,x,x,x,x)
为对象表头和对象体分配内存,并初始化对象参数。

PAGE:004AB363                 call    PspInheritQuota(x,x)
PAGE:004AB36C                 call    ObInheritDeviceMap(x,x)
这句设定进程配额块和DosDevices,将新进程的配额块移动到父进程配额块地址处;
在此之后,将执行以下操作:
Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
Process->SessionId = Parent->SessionId;

PAGE:004AB3B3                 call    ObReferenceObjectByHandle(x,x,x,x,x,x)
创建页表项以映射初始页面;

PAGE:004AB3E4                 push    edi
PAGE:004AB3E5                 push    ebx
PAGE:004AB3E6                 call    DbgkCopyProcessDebugPort(x,x)
设置调试端口,如果有必要,也会设置异常端口;

PAGE:004AB402                 call    PspInitializeProcessSecurity(x,x)
设置访问令牌,新的进程将继承父进程的配置;

PAGE:004AB424                 call    MmCreateProcessAddressSpace(x,x,x)
创建初始进程地址空间;

PAGE:004AB460                 call    KeInitializeProcess(x,x,x,x,x)
PAGE:004AB465                 mov     al, _PspForegroundQuantum
创建内核进程块,,对KPROCESS块进行设置,_PspForegroundQuantum中包含时间片的初始值;

PAGE:004AB4A4                 call    ObInitProcess(x,x)
进程地址空间一旦建立,接下来就是attach上去,不过在此之前,先需要对KPROCESS进行初始化;

PAGE:004AB4CB                 call    MmInitializeProcessAddressSpace(x,x,x,x)
初始化地址空间,有四种模式,包括:
Boot Process,System Process,Cloned User Process ,New User Process;

PAGE:004AB4DF                 call    PspMapSystemDll(x,x)
支持重定向,有必要的话将ntdll.dll、语言支持表映射到进程中;

PAGE:004AB512                 push    _PspCidTable
PAGE:004AB518                 call    ExCreateHandle(x,x)
为进程分配一个CID标识,在句柄表中设置CID;

PAGE:004AB582                 call    MmCreatePeb(x,x,x)
创建PEB,为PEB分配一个页面,并初始化;
它将继续调用_MiCreatePebOrTeb,详细信息可以反汇编__stdcall MmCreatePeb(x, x, x)。

PAGE:004AB5A2                 call    ExAcquireFastMutexUnsafe(x)
PAGE:004AB5B3                 mov     dword ptr [eax], offset _PsActiveProcessHead
PAGE:004AB5BE                 mov     dword_4896DC, eax
PAGE:004AB5C3                 mov     ecx, offset _PspActiveProcessMutex
PAGE:004AB5C8                 call    ExReleaseFastMutexUnsafe(x)
把新进程块插入到活动进程表的末端(_PsActiveProcessHead);

PAGE:004AB60F                 call    SeCreateAccessStateEx(x,x,x,x,x,x)
创建AccessState结构体;

PAGE:004AB630                 call    ObInsertObject(x,x,x,x,x,x)
将新进程的句柄返回给调用函数CreateProcess,然后返回到用户态继续;
再接下去是检查控制权限安全性,然后取得进程创建时间,不再多做讨论。



[阶段三]
——————————————————————
我们返回到用户态,kernel32.dll里接着走:

.text:7C82C968                 call    ds:NtSetInformationProcess
设置对象属性,枚举值_PROCESSINFOCLASS描述了信息类;

.text:7C819BB0                 call    ds:NtQueryInformationProcess
这里取得ProcessBasicInfo的信息,参考ntddk.h:
typedef struct _PROCESS_BASIC_INFORMATION {
    NTSTATUS ExitStatus;
    PPEB PebBaseAddress;
    KAFFINITY AffinityMask;
    KPRIORITY BasePriority;
    ULONG UniqueProcessId;
    ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION;
值PPEB PebBaseAddress是关键,指向PEB结构的地址。
之后将执行:Peb = ProcessInfo.PebBaseAddress;获取了之后,将开始调整堆栈;

先不管堆栈怎么建立,继续...
在NtCreateThread之前,.text:7C819D2B loc_7C819D2B:
.text:7C819D3F                 call    sub_7C81021C
跟进去,可以看到:
.text:7C81024B                 call    ds:RtlImageNtHeader
.text:7C8102DF                 mov     ebx, ds:NtAllocateVirtualMemory
//...
.text:7C810356                 call    ebx ; NtAllocateVirtualMemory
.text:7C810385                 call    ds:NtProtectVirtualMemory
好象在对某些值进行设置调整,并试图在进程产生的地址空间中设置内存;
记住这里,我们将在不久之后讨论这个“好象在对某些值进行设置调整,并试图...”;

==========================================================================
那么是什么值呢?堆栈又怎么调整?
我们不妨从核心态来了解相关的信息,之后我们再从用户态还原出这些函数:
进入ntoskrnl.exe,我们看NTSTATUS __stdcall RtlCreateUserProcess:

INIT:005CABC6 __stdcall RtlCreateUserProcess(x, x, x, x, x, x, x, x, x, x) proc near
//...
INIT:005CABF4                 call    RtlpOpenImageFile(x,x,x,x)
同样是打开文件映象;

INIT:005CAC18                 call    ZwCreateSection(x,x,x,x,x,x,x)
INIT:005CAC50                 call    RtlGetNtGlobalFlags()
INIT:005CAC87                 call    ZwCreateProcess(x,x,x,x,x,x,x,x)
和ring3状态下基本类似,创建进程;

INIT:005CACA0                 call    ZwQuerySection(x,x,x,x,x)
INIT:005CACBA                 call    ZwQueryInformationProcess(x,x,x,x,x)
正如我们这里的第三步,为创建线程做好准备;

INIT:005CAD8E                 call    ZwAllocateVirtualMemory(x,x,x,x,x,x)
INIT:005CADAC                 call    ZwWriteVirtualMemory(x,x,x,x,x)
INIT:005CAE42                 call    RtlCreateUserThread(x,x,x,x,x,x,x,x,x,x)
分配空间,将参数压入,到此为止,线程创建完毕;

现在我们就跟进RtlCreateUserThread,看看到底做了什么:
PAGE:004EA78C __stdcall RtlCreateUserThread(x, x, x, x, x, x, x, x, x, x) proc near
//...
PAGE:004EA7DE                 call    RtlpCreateStack(x,x,x,x,x)
PAGE:004EA804                 call    RtlInitializeContext(x,x,x,x,x)
PAGE:004EA863                 call    ZwCreateThread(x,x,x,x,x,x,x,x)
原来是创建了堆栈,并初始化线程上下文,然后调用ZwCreateThread正式创建线程;
===========================================================================

再返回到用户态,接着上面的NtQueryInformationProcess往下看:
.text:7C819BF5                 call    ds:RtlAllocateHeap
.text:7C819C1F                 call    GetFullPathNameW
.text:7C819C33                 call    GetFileAttributesW
将参数压入新进程地址空间,检查路径,确认路径存在;

.text:7C819CE7                 call    sub_7C81A2CE
.text:7C819CFB                 call    ds:RtlFreeUnicodeString
这里是个重点,在RtlFreeUnicodeString前调用了一个函数,是什么?我们跟进去...

当我们试图跟踪的时候,发现了什么?一大堆的调用类似:
mov     esi, ds:RtlInitUnicodeString
call    esi ; RtlInitUnicodeString
但是幸运的是我们发现了这个函数调用:
.text:7C81A454                 call    ds:RtlCreateProcessParameters
这个函数的作用是将进程的环境信息放进RTL_USER_PROCESS_PARAMETERS缓冲区中;
并在之后看到了内存操作函数:
.text:7C81A4EF                 call    ds:NtAllocateVirtualMemory
.text:7C81A516                 mov     esi, ds:NtWriteVirtualMemory
.text:7C81A51C                 call    esi ; NtWriteVirtualMemory
它们将设置诸如环境块(EnvironmentBlock)、进程信息块(ProcessParameterBlock)、PEB等;

OK,这些是什么?组合起来,这就是著名的_BasePushProcessParameters,多么美妙!
它的作用是将诸如exe文件路径、命令行参数、路径、窗口信息等压栈,并调整由进程产生的地址空间;

好,我们回到前面,不是有个莫名其妙的“好象在对某些值进行设置调整,并试图...”么?
得到了_BasePushProcessParameters,就不难知道,它就是同样著名的_BaseCreateStack,哈!!

跳回到.text:7C819D2B loc_7C819D2B,也就是_BaseCreateStack处,往下看:
.text:7C819D6C                 call    sub_7C8103A3
跟进去,是一些值的设定,但是同样幸运的是,我们看到了这个:
.text:7C8103F4                 mov     dword ptr [eax+0C0h], 3000h
想起些什么了么?对,就是 Context->EFlags = 0x3000;
那么很容易推断,这个call就是_BaseInitializeContext;

好了,对应于核心态,所有的用户态堆栈函数全部还原出来了,我们整理下思路:
NtQueryInformationProcess之后进行堆栈操作,先后执行了
_BasePushProcessParameters、_BaseCreateStack、_BaseInitializeContext;

万事具备,接下来就只差线程的创建了:
.text:7C819DCD                 call    ds:NtCreateThread
而实际上,我们查看函数原型:
  NTSYSAPI
  NTSTATUS
  NTAPI
  NtCreateThread(
      OUT PHANDLE ThreadHandle,
      IN ACCESS_MASK DesiredAccess,
      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
      IN HANDLE ProcessHandle,
      OUT PCLIENT_ID ClientID,
      IN PCONTEXT Context, /* see _BaseInitializeContext */
      IN StackInformation* StackInfo, /* see _BaseCreateStack */
      IN BOOLEAN CreateSuspended  /* ==1 */
  );
相应的参数结构就是由还原出的堆栈函数进行填充的;
不过目前这个线程还是挂起的,当所有的设定完成后,我们将用NtResumeThread让它工作。


[阶段四]
[阶段五]
——————————————————————
引用Gloomy在《研究CreateProcess》中最后的“陈词”:
“终于,在对PE映象的SubSystem主要域的数据进行处理之后,通过LPC转到Win32服务。进程应该只在Win32子系统下创建。”
在所有必要的执行体进程和线程对象创建以后,kernerl32.dll发送信息给Win32子系统,设置新的进程和线程。

接着call    ds:NtCreateThread,继续我们的旅程:
.text:7C819EA2                 push    98h
.text:7C819EA7                 push    10000h
.text:7C819EAC                 push    dword ptr [ebp-690h]
.text:7C819EB2                 lea     eax, [ebp-398h]
.text:7C819EB8                 push    eax
.text:7C819EB9                 call    ds:CsrClientCallServer
当然,在此之前有必要检查和设置一些标志,否则NtTerminateProcess;
我们来看需要传递哪些信息:
1.进程和线程句柄 2.创建标志中的项 3.进程创建者的ID 4.是否属于Win32程序
然后调用ds:CsrClientCallServer发送给Win32子系统,向CSRSS注册新的进程和线程;
子系统要完成的操作就不再废话,参考资料5。

.text:7C819EF5                 lea     eax, [ebp-6ACh]
.text:7C819EFB                 push    eax
.text:7C819EFC                 push    dword ptr [ebp-67Ch]
.text:7C819F02                 call    ds:NtResumeThread
完成了所有的进程环境设置,分配了线程资源,调用NtResumeThread开始初始线程的执行;


[阶段六]
——————————————————————
NtCreateThread()在MmCreateTeb()之后KeInitThread(),然后KeStartThread()等等。
KeInitThread()启动后将初始化线程上下文,标记Thread->State = Initialized,然后:
PspUserThreadStartup(),它将调用KiInitializeUserApc()为线程设置用户态的APC。
而APC的初始化需要LdrInitializeThunk(),我们从它入手,完成进程和线程的最后的设置。

.text:7C941616 ; START OF FUNCTION CHUNK FOR LdrInitializeThunk
//...
检查LdrpProcessInitialized是否为0,是则调用LdrpInitializeProcess();
如果已经初始化完毕,则调用LdrpInitializeThread();

.text:7C941634                 call    LdrpInitializeProcess  //SUB_7C941ABC

好,我们跟进去,看到:
.text:7C941ABC LdrpInitializeProcess proc near         ; CODE XREF: LdrInitializeThunk+204B6p

.text:7C941B44                 call    RtlImageNtHeader
检查ProcessParameters中的文件映射名;

.text:7C941B8D                 call    RtlNormalizeProcessParams
在注册表中搜索ImageFileExecutionOptions,如下:
ProcessParameters= RtlNormalizeProcessParams(Peb->ProcessParameters)

.text:7C941BD1                 call    RtlInitNlsTables
.text:7C941BDA                 call    RtlResetRtlTranslations
初始化TLS和FLS的进程数据结构;

text:7C941BE9                 call    RtlImageDirectoryEntryToData
将进程信息关联到映象文件;

//...
.text:7C941D99                 call    RtlInitializeCriticalSection
设置临界区;

.text:7C941E44                 call    RtlCreateHeap
两次调用RtlCreateHeap,设置为:
ProcessHeap= RtlCreateHeap()
LdrpHeap= RtlCreateHeap()

.text:7C941E74                 call    RtlInitializeAtomPackage
//...
之后将设置dll搜索路径,获取路径,初始化装载的模块;
然后调用LdrpWalkImportDescriptor()遍历IDT,并装载关联的DLL;LdrpInitializeTls()之后所有模块装载完毕;
此时检查PEB.BeingDebugged是否被置位,是则调用DbgBreakPoint()通知调试器。
最后调用LdrpRunInitializeRoutines()启动例程初始化所有的DLL。
接着转到线程初始化,完成收尾:
LdrpInitializeThread()中调用LdrpCallInitRoutine(DLL_THREAD_ATTACH)唤醒DLL初始化例程;
如果存在TLS,则调用LdrpCallTlsInitializers(DLL_THREAD_ATTACH)进行初始化。

到此,所有的工作都完成了。由于设置了陷阱框架,当线程在核心态运行的陷阱被取消,映象将回到用户态开始执行。


*[参考资料]:
——————————————————————
1. 《反汇编CreateProcess》 董岩,Gloomy
2. Windows NT Source Code
3. Kernel32.dll, Ntdll.dll, ntoskrnl.exe
4. http://undocumented.ntinternals.net/
5. 《Inside Windows NT》 David A.Solomon   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值