查看文章 |
++++++++++++++++++++++++++++ 这是Windows Internals第6章的内容。发现描述的还算详细。读了总比不读强。于是纪录之,老鸟飘过---- <一> 进程相关 EPROCESS算是进程的代表,它还保留着与之相关的其他信息。进程是死的,其中的线程才是活的。进程就好比一个容器,装着很多活跃的线程而已[没有线程的进程注定要死亡,因为它没有活力]。对了,还有PEB、TEB[这2个结构存在于用户进程空间中,其他的都在系统的高2GB地址范围里] 。见图: ![]() ① 明确KPCR、KPRCB、ETHREAD、KTHREAD、EPROCESS、KPROCESS、TEB、PEB ---- KPCR(Kernel's Processor Control Region,内核进程控制区域)是一个不会随WINDOWS版本变动而改变的固定结构体,在它的末尾[偏移0x120]指向KPRCB结构。 nt!_KPCR KPRCB同样是一个不会随WINDOWS版本变动而改变的固定结构体。它包含有指向当前KTHREAD的指针,偏移值0x004。其实也就是知道了当前的ETHREAD基地址。[因为ETHREAD的第一项便是KTHREAD,ETHREAD在后面讨论,现在讨论进程相关] [通过 KeGetCurrentPrcb() 函数即可得到PKPRCB,具体参见WRK]
展开KTHREAD,其中的_KAPC_STATE结构中包含当前KPROCESS的地址 nt!_KTHREAD +0x034 ApcState : struct _KAPC_STATE, 5 elements, 0x18 bytes 而EPROCESS的第一项正是KPROCESS。联想我们熟悉的断EPROCESS链表隐藏进程的手法。通过PsGetCurrentProcess得到的其实是当前KPROCESS的地址,而KPROCESS就是EPROCESS结构体的第一项,这样就得到了当前的EPROCESS。然后遍历整个链表。。。 ---->>大致流程:PsGetCurrentProcess()函数---->_PsGetCurrentProcess()宏----->KeGetCurrentThread()函数 ---->>具体细节: FORCEINLINE 呵呵,偶画个图更直观些,也更方便记忆 ![]() 关于KPROCESS。里面保存了一些有用的信息,我们来简单的瞅下。 nt!_KPROCESS PEB是很有用的东西,写shellcode、定位EPROCESS等都可以用到它。PEB在EPROCESS偏移0x1b0处 nt!_EPROCESS ---->>获得PEB的地址是非常简单的。可以通过EPROCESS的偏移,也可以用硬编码实现[不同进程的PEB高位都是一样的] 当然可以直接用Windbg来查看当前的PEB的结构 lkd>dt _peb lkd> !peb ② 与进程相关的一些内核变量、计数、函数 ----
关于PspCidTable参见gz1X大虾的:基于pspCidTable的进程检测技术 这些变量的申明保存在WRK的Psinit.c中。先看下PspCreateProcess的参数
初始化Queue header:InitializeListHead(&PsActiveProcessHead);
创建系统进程,并且把系统进程的EPROCESS保存在PsInitialSystemProcess中。见代码: InitializeObjectAttributes (&ObjectAttributes, if (!NT_SUCCESS (PspCreateProcess (&PspInitialSystemProcessHandle, if (!NT_SUCCESS (ObReferenceObjectByHandle (PspInitialSystemProcessHandle, return FALSE; strcpy((char *) &PsIdleProcess->ImageFileName[0], "Idle"); // EPROCESS OFFEST+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO if (PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName != NULL) {
![]()
相关的函数就更多了,具体请参见原版WINDWOS INTERNALS 6[附件里有] ③ 一个进程的诞生,CreateProcess的步骤 ---- 用户程序可以调用CreateProcess、CreateProcessAsUser、CreateProcessWithTokenWor、CreateProcessWithLogonW创建进程。而进程的创建主要由3部分参合进来完成的:Kernel32.dll、the Windows executive、子系统进程CSRSS.exe。 CreateProcess创建进程的大致步骤:
CreateProcess在打开文件运行之前,会检查参数中的flags,决定如何设置新进程的优先级。 ---->> stage 1: 打开并运行文件<<---- 如果是PE文件,直接运行;如果不是PE格式,系统根据相应的格式选择相应的加载措施:
与Ntvdm.exe相关的注册表在HKLM\SYSTEM\CurrentControlSet\Control\WOW下 到此,CreateProcess已经成功的打开了一个有效的文件,并且为它创建了一个section object。但并没有映射到内存中,仅仅是打开了而已。a section object被成功的创建了并不能说明此文件是一个有效的Windows image,因为文件可能是DLL或者POSIX。 接着检查注册表IFEO,系统如果发现某个程序文件在IFEO列表中,它就会首先来读取Debugger参数,如果该参数不为空,系统则会把Debugger参数里指定的程序文件名作为用户试图启动的程序执行请求来处理,而仅仅把用户试图启动的程序作为Debugger参数里指定的程序文件名的参数发送过去。 联想到了很久的映像劫持病毒。 ---->> stage 2: 创建进程内核对象<<---- CreateProcess-->NtCreateProcess-->NtCreateProcessEx-->PspCreateProcess来创建进程内核对象。如下: ----- stage2.1 设置EPROCESS----- if (!NT_SUCCESS (ObCreateObjectType (&NameString, // 函数PspCreateProcess中创建EPROCESS RtlZeroMemory (Process, sizeof(EPROCESS)); ----- stage2.2 创建进程地址空间-----
Status = MmInitializeProcessAddressSpace (Process, } else if (Parent != NULL) { //如果存在父进程 Flags &= ~PROCESS_CREATE_FLAGS_ALL_LARGE_PAGE_FLAGS; } 2.> Hyperspace page ----- stage2.5 设置PEB---- Peb = Process->Peb; } else { // 如果是CLONE进程,PEB只要从父进程里面拷贝一份就可以了 InitialPeb.InheritedAddressSpace = TRUE; ----- stage2.6 完成进程内核对象的创建----- 4.> 线程创建的时间被设定,然后当线程的句柄可用的时候,返回到最初的调用者CreateProcess中[Kernel32.dll] [接下一篇] 上传的附件
|











