0x00
进程是运行在操作系统上的人员,操作系统是软件的管理机构负责分配软件的资源。在进程未被启动时,系统不为其分配资源。
运行中的进程在系统中所拥有的资源
• 虚拟地址空间
• 全局唯一的PID
• 可执行映像,可执行文件在内存中的表示
• 一个或多个线程
• 在内核空间中的EPROCESS(进程执行块,executive process block),保存有进程的信息
• 在内核空间中的对象句柄表,记录和索引进程打开/创建的内核对象。操作系统根据表格将用户模式下的句柄翻译成指向内核对象的指针
• 描述内存目录表起始位置的基地址,简称页目录基地址(DirBase),当CPU切换到该进程/任务时,会把该地址加载到页基地址寄存器(X86之CR3,ARM之TTBR)
• 一个PEB(进程环境块,Process Environment Block)
• 一个访问令牌(access token),用于表示该进程的用户,安全组以及优先级
。。。
0x01
进程空间是系统为保护每个进程都独立运行互不打扰的运行所设置的保护模式,进程空间中的地址是虚拟地址空间。
在进程运行时,进程的指针指向的只能是在虚拟地址空间中。
与之相对的是内核空间。内核空间是固定统一的,会映射到所有应用程序的进程空间中,内核空间是共享的。为了保护不被破坏,内核空间会被系统用CPU硬件保护机制。从系统的角度看,内核空间的权限和用户空间的权限级别不同。
从数据结构看,NT内核(windows内核)使用EPROCESS结构描述进程。
• 符号文件可能不同
kd> dt _EPROCESS 873a7768
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS //内核进程块,记录与任务调度有关的信息
+0x098 ProcessLock : _EX_PUSH_LOCK
+0x0a0 CreateTime : _LARGE_INTEGER 0x01d6b36e`e770a058 //创建时间
+0x0a8 ExitTime : _LARGE_INTEGER 0x0 //退出时间
+0x0b0 RundownProtect : _EX_RUNDOWN_REF
+0x0b4 UniqueProcessId : 0x00001570 Void //进程ID
+0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x82980358 - 0x87551660 ]
+0x0c0 ProcessQuotaUsage : [2] 0x1900
+0x0c8 ProcessQuotaPeak : [2] 0x1a30
+0x0d0 CommitCharge : 0x21c
+0x0d4 QuotaBlock : 0x874c1380 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : (null)
+0x0dc PeakVirtualSize : 0x4d3e000
+0x0e0 VirtualSize : 0x45f5000
+0x0e4 SessionProcessLinks : _LIST_ENTRY [ 0x8f2d8010 - 0x8755168c ]
+0x0ec DebugPort : (null) //用户态调试端口
+0x0f0 ExceptionPortData : 0x8e7486f0 Void //异常端口,新改动,将其设置为联合体,原为ExceptionPort
+0x0f0 ExceptionPortValue : 0x8e7486f0
+0x0f0 ExceptionPortState : 0y000
+0x0f4 ObjectTable : 0x9d34b648 _HANDLE_TABLE // 对象句柄表
+0x0f8 Token : _EX_FAST_REF // 访问令牌 、、在这里应该有一个VadRoot,用于虚拟地址描述符二叉树的根节点
+0x0fc WorkingSetPage : 0xdbe
+0x100 AddressCreationLock : _EX_PUSH_LOCK
+0x104 RotateInProgress : (null)
+0x108 ForkInProgress : (null)
+0x10c HardwareTrigger : 0
+0x110 PhysicalVadRoot : (null)
+0x114 CloneRoot : (null)
+0x118 NumberOfPrivatePages : 0x1ca
+0x11c NumberOfLockedPages : 0
+0x120 Win32Process : 0xffa1aba8 Void
+0x124 Job : (null)
+0x128 SectionObject : 0x9d380198 Void
+0x12c SectionBaseAddress : 0x00b10000 Void
+0x130 Cookie : 0x385481f5
+0x134 Spare8 : 0
+0x138 WorkingSetWatch : (null)
+0x13c Win32WindowStation : 0x00000038 Void
+0x140 InheritedFromUniqueProcessId : 0x000014dc Void
+0x144 LdtInformation : (null)
+0x148 VdmObjects : (null)
+0x14c ConsoleHostProcess : 0
+0x150 DeviceMap : 0x9841c6d8 Void
+0x154 EtwDataSource : (null)
+0x158 FreeTebHint : 0x7ffd4000 Void
+0x160 PageDirectoryPte : _HARDWARE_PTE_X86
+0x160 Filler : 0
+0x168 Session : 0x8f2d8000 Void// 所属会话对象
+0x16c ImageFileName : [15] "taskmgr.exe"
+0x17b PriorityClass : 0x3 ''
+0x17c JobLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x184 LockedPagesList : 0x8e6f2138 Void
+0x188 ThreadListHead : _LIST_ENTRY [ 0x873a76e8 - 0x875295d0 ]//线程列表
+0x190 SecurityPort : (null)
+0x194 PaeTop : (null)
+0x198 ActiveThreads : 0xb
+0x19c ImagePathHash : 0x5f5f473d
+0x1a0 DefaultHardErrorProcessing : 0x8000
+0x1a4 LastThreadExitStatus : 0n0
+0x1a8 Peb : 0x7ffd9000 _PEB//进程环境块
+0x1ac PrefetchTrace : _EX_FAST_REF
+0x1b0 ReadOperationCount : _LARGE_INTEGER 0x2
+0x1b8 WriteOperationCount : _LARGE_INTEGER 0x0
+0x1c0 OtherOperationCount : _LARGE_INTEGER 0x5be
+0x1c8 ReadTransferCount : _LARGE_INTEGER 0x7ff4
+0x1d0 WriteTransferCount : _LARGE_INTEGER 0x0
+0x1d8 OtherTransferCount : _LARGE_INTEGER 0x451e
+0x1e0 CommitChargeLimit : 0
+0x1e4 CommitChargePeak : 0x21c
+0x1e8 AweInfo : (null)
+0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f0 Vm : _MMSUPPORT
+0x25c MmProcessLinks : _LIST_ENTRY [ 0x82985f50 - 0x87551804 ]
+0x264 HighestUserAddress : 0x7fff0000 Void
+0x268 ModifiedPageCount : 0
+0x26c Flags2 : 0xd000
+0x26c JobNotReallyActive : 0y0
+0x26c AccountingFolded : 0y0
+0x26c NewProcessReported : 0y0
+0x26c ExitProcessReported : 0y0
+0x26c ReportCommitChanges : 0y0
+0x26c LastReportMemory : 0y0
+0x26c ReportPhysicalPageChanges : 0y0
+0x26c HandleTableRundown : 0y0
+0x26c NeedsHandleRundown : 0y0
+0x26c RefTraceEnabled : 0y0
+0x26c NumaAware : 0y0
+0x26c ProtectedProcess : 0y0
+0x26c DefaultPagePriority : 0y101
+0x26c PrimaryTokenFrozen : 0y1
+0x26c ProcessVerifierTarget : 0y0
+0x26c StackRandomizationDisabled : 0y0
+0x26c AffinityPermanent : 0y0
+0x26c AffinityUpdateEnable : 0y0
+0x26c PropagateNode : 0y0
+0x26c ExplicitAffinity : 0y0
+0x270 Flags : 0x164d0801
+0x270 CreateReported : 0y1
+0x270 NoDebugInherit : 0y0
+0x270 ProcessExiting : 0y0//正在退出标志
+0x270 ProcessDelete : 0y0//删除标志
+0x270 Wow64SplitPages : 0y0
+0x270 VmDeleted : 0y0
+0x270 OutswapEnabled : 0y0
+0x270 Outswapped : 0y0
+0x270 ForkFailed : 0y0
+0x270 Wow64VaSpace4Gb : 0y0
+0x270 AddressSpaceInitialized : 0y10
+0x270 SetTimerResolution : 0y0
+0x270 BreakOnTermination : 0y0
+0x270 DeprioritizeViews : 0y0
+0x270 WriteWatch : 0y0
+0x270 ProcessInSession : 0y1
+0x270 OverrideAddressSpace : 0y0
+0x270 HasAddressSpace : 0y1
+0x270 LaunchPrefetched : 0y1
+0x270 InjectInpageErrors : 0y0
+0x270 VmTopDown : 0y0
+0x270 ImageNotifyDone : 0y1
+0x270 PdeUpdateNeeded : 0y0
+0x270 VdmAllowed : 0y0
+0x270 CrossSessionCreate : 0y1
+0x270 ProcessInserted : 0y1
+0x270 DefaultIoPriority : 0y010
+0x270 ProcessSelfDelete : 0y0
+0x270 SetTimerResolutionLink : 0y0
+0x274 ExitStatus : 0n259
+0x278 VadRoot : _MM_AVL_TABLE//前面的虚拟地址描述符二叉树的根节点
+0x298 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x2a8 TimerResolutionLink : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x2b0 RequestedTimerResolution : 0
+0x2b4 ActiveThreadsHighWatermark : 0xc
+0x2b8 SmallestTimerResolution : 0
+0x2bc TimerResolutionStackRecord : (null)
• 系统分为内核和用户,内核空间中的地址不用更改,减少计算开支,编写内核代码方便,区分内核和用户用权限管理。即0环,3环。跨权限访问会停止访问并产生保护性异常(#GP)。用户态(R3)访问内核态(R0)可以通过调用系统服务来间接访问内核空间中的数据或间接调用、执行内核空间中的代码。执行时会短暂切换模式(系统调用或软中断调用门)。
○ int 2E 切换内核模式
§ 用readfile()说明。使用ntdll的readfile,反汇编显示,先将readfile对应的系统服务号(0xa1,和版本有关)放入EAX寄存器中,将参数指针放入EDX寄存器中,然后通过陷阱int n发出调用。
Ntdll!NtReadFile:// windows 2000
77f8fb5b mov eax,0xa1
77f8fb62 lea edx,[esp+0x4]
77f8fb66 int 2e
77f8fb68 ret 0x24
查看idt表(中带你描述符表,系统启动初始化时便注册完成)
kd> !idt 2e
Dumping IDT: 80b95400
2e: 8287c67e nt!KiSystemService
KiSystemService是内核态中专门用来分发系统调用的例程。
§ 在调用KiSystemService之前,需要先进行权限检查、分配内核栈。接下来,KiSystemService通过服务ID从系统服务分发表(SSDT)中查找到服务函数地址和参数描述,将用户态的参数复制到该线程的内核栈中,执行,IRET返回结果;
○ 快速系统调用
§ 快速系统调用,快速的原因是,把系统服务例程地址放到寄存器中(快速读取)和避免权限检查(定义特权指令)。
□ SYSENTER/SYSEXIT 通过CPUID指令检测CPU是否支持快速系统调用指令(EDX寄存器的SEP标志位),不支持继续使用int 2e。
® 在全局描述符表(GDT)中建立4个段描述符,分别用来描述供SYSENTER 指令进入内核模式时使用的代码段(CS)和栈段(SS),以及SYSEXIT指令从内核模式返回用户模式时使用的代码段和栈段。
® SYSENTER/SYSEXIT 用于指定新的程序指针,也就是SYSENTER指令要跳转到的目标例程地址。Windows系统会将其设置为KiFastCallEntry的地址,因为KiFastCallEntry例程时Windows内核中专门用来受理快速系统调用的。SYSENTER_CS_MSR指定新的代码段,也就是KiFastCallEntry所在的代码段。SYSENTER_ESP_MSR用于指定新的栈指针(ESP)。新的栈段由SYSENTER_CS_MSR加8得来
® 将一小段名为SystemCallSub的代码复制到SharedUserData内存区,该内存区会被映射到每个win32进程的进程空间中。以保证当应用程序每次进行系统调用时,NTDLL.DLL中的残根(stub)函数便调用这段SystemCallStub代码。SystemCallStub的内容因系统硬件的不同而不同。
□ 内部实现和调用门类似,只是通过调用shareuserdata内存区域,借用ecx寄存器使用,快速调用。返回时也需要取出保存的原权限和栈区指针。