1 进程与线程
1.1 进程结构体
kd> dt _EPROCESS
nt!_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
+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
+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
- CreateTime:进程创建时间;
- ExitTime:进程退出时间;
- UniqueProcessId:PID;
- AtiveProcessLinks:存储所有进程的双向链表;
- QuotaUsage、QuotaPeak:物理页相关信息;
- CommitCharge、PeakVirtualSize、VirtualSize:虚拟内存相关信息;
- ObjectTable:句柄表;
- VadRoot:标记已被使用的低2G虚拟地址;
- ImageFileName:进程对应的镜像文件名;
- ActiveThreads:活动线程数;
- PCB:进程控制块;
- PEB:进程环境块;
PCB
存储进程的控制信息:
kd> dt _KPROCESS
nt!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER
+0x010 ProfileListHead : _LIST_ENTRY
+0x018 DirectoryTableBase : [2] Uint4B
+0x020 LdtDescriptor : _KGDTENTRY
+0x028 Int21Descriptor : _KIDTENTRY
+0x030 IopmOffset : Uint2B
+0x032 Iopl : UChar
+0x033 Unused : UChar
+0x034 ActiveProcessors : Uint4B
+0x038 KernelTime : Uint4B
+0x03c UserTime : Uint4B
+0x040 ReadyListHead : _LIST_ENTRY
+0x048 SwapListEntry : _SINGLE_LIST_ENTRY
+0x04c VdmTrapcHandler : Ptr32 Void
+0x050 ThreadListHead : _LIST_ENTRY
+0x058 ProcessLock : Uint4B
+0x05c Affinity : Uint4B
+0x060 StackCount : Uint2B
+0x062 BasePriority : Char
+0x063 ThreadQuantum : Char
+0x064 AutoAlignment : UChar
+0x065 State : UChar
+0x066 ThreadSeed : UChar
+0x067 DisableBoost : UChar
+0x068 PowerState : UChar
+0x069 DisableQuantum : UChar
+0x06a IdealNode : UChar
+0x06b Flags : _KEXECUTE_OPTIONS
+0x06b ExecuteOptions : UChar
- Header:头部标识,用于3环API的调用;
- DirectoryTableBase:保存当前进程的CR3值;
- KernelTime:进程在0环运行的时间;
- UserTime:进程在3环运行的时间;
- Affinity:多核调用相关;
- BasePriority:改进程中所有线程中的最低优先级;
PEB
存储进程运行时的环境信息:
kd> dt _PEB
nt!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 Void
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 Void
+0x1fc ProcessAssemblyStorageMap : Ptr32 Void
+0x200 SystemDefaultActivationContextData : Ptr32 Void
+0x204 SystemAssemblyStorageMap : Ptr32 Void
+0x208 MinimumStackCommit : Uint4B
1.2 线程结构体
kd> dt _ETHREAD
nt!_ETHREAD
+0x000 Tcb : _KTHREAD
+0x1c0 CreateTime : _LARGE_INTEGER
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
+0x1c0 ApcNeeded : Pos 2, 1 Bit
+0x1c8 ExitTime : _LARGE_INTEGER
+0x1c8 LpcReplyChain : _LIST_ENTRY
+0x1c8 KeyedWaitChain : _LIST_ENTRY
+0x1d0 ExitStatus : Int4B
+0x1d0 OfsChain : Ptr32 Void
+0x1d4 PostBlockList : _LIST_ENTRY
+0x1dc TerminationPort : Ptr32 _TERMINATION_PORT
+0x1dc ReaperLink : Ptr32 _ETHREAD
+0x1dc KeyedWaitValue : Ptr32 Void
+0x1e0 ActiveTimerListLock : Uint4B
+0x1e4 ActiveTimerListHead : _LIST_ENTRY
+0x1ec Cid : _CLIENT_ID
+0x1f4 LpcReplySemaphore : _KSEMAPHORE
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
+0x208 LpcReplyMessage : Ptr32 Void
+0x208 LpcWaitingOnPort : Ptr32 Void
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
+0x210 IrpList : _LIST_ENTRY
+0x218 TopLevelIrp : Uint4B
+0x21c DeviceToVerify : Ptr32 _DEVICE_OBJECT
+0x220 ThreadsProcess : Ptr32 _EPROCESS
+0x224 StartAddress : Ptr32 Void
+0x228 Win32StartAddress : Ptr32 Void
+0x228 LpcReceivedMessageId : Uint4B
+0x22c ThreadListEntry : _LIST_ENTRY
+0x234 RundownProtect : _EX_RUNDOWN_REF
+0x238 ThreadLock : _EX_PUSH_LOCK
+0x23c LpcReplyMessageId : Uint4B
+0x240 ReadClusterSize : Uint4B
+0x244 GrantedAccess : Uint4B
+0x248 CrossThreadFlags : Uint4B
+0x248 Terminated : Pos 0, 1 Bit
+0x248 DeadThread : Pos 1, 1 Bit
+0x248 HideFromDebugger : Pos 2, 1 Bit
+0x248 ActiveImpersonationInfo : Pos 3, 1 Bit
+0x248 SystemThread : Pos 4, 1 Bit
+0x248 HardErrorsAreDisabled : Pos 5, 1 Bit
+0x248 BreakOnTermination : Pos 6, 1 Bit
+0x248 SkipCreationMsg : Pos 7, 1 Bit
+0x248 SkipTerminationMsg : Pos 8, 1 Bit
+0x24c SameThreadPassiveFlags : Uint4B
+0x24c ActiveExWorker : Pos 0, 1 Bit
+0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
+0x24c MemoryMaker : Pos 2, 1 Bit
+0x250 SameThreadApcFlags : Uint4B
+0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
+0x250 LpcExitThreadCalled : Pos 1, 1 Bit
+0x250 AddressSpaceOwner : Pos 2, 1 Bit
+0x254 ForwardClusterOnly : UChar
+0x255 DisablePageFaultClustering : UChar
- Cid:包含所属进程ID和线程ID;
- ThreadsProcess:指向所属进程;
- ThreadListEntry:包含所有线程的双向链表;
- TCB:线程控制块;
- TEB:线程环境块;
TCB
kd> dt _KTHREAD
nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 MutantListHead : _LIST_ENTRY
+0x018 InitialStack : Ptr32 Void
+0x01c StackLimit : Ptr32 Void
+0x020 Teb : Ptr32 Void
+0x024 TlsArray : Ptr32 Void
+0x028 KernelStack : Ptr32 Void
+0x02c DebugActive : UChar
+0x02d State : UChar
+0x02e Alerted : [2] UChar
+0x030 Iopl : UChar
+0x031 NpxState : UChar
+0x032 Saturation : Char
+0x033 Priority : Char
+0x034 ApcState : _KAPC_STATE
+0x04c ContextSwitches : Uint4B
+0x050 IdleSwapBlock : UChar
+0x051 Spare0 : [3] UChar
+0x054 WaitStatus : Int4B
+0x058 WaitIrql : UChar
+0x059 WaitMode : Char
+0x05a WaitNext : UChar
+0x05b WaitReason : UChar
+0x05c WaitBlockList : Ptr32 _KWAIT_BLOCK
+0x060 WaitListEntry : _LIST_ENTRY
+0x060 SwapListEntry : _SINGLE_LIST_ENTRY
+0x068 WaitTime : Uint4B
+0x06c BasePriority : Char
+0x06d DecrementCount : UChar
+0x06e PriorityDecrement : Char
+0x06f Quantum : Char
+0x070 WaitBlock : [4] _KWAIT_BLOCK
+0x0d0 LegoData : Ptr32 Void
+0x0d4 KernelApcDisable : Uint4B
+0x0d8 UserAffinity : Uint4B
+0x0dc SystemAffinityActive : UChar
+0x0dd PowerState : UChar
+0x0de NpxIrql : UChar
+0x0df InitialNode : UChar
+0x0e0 ServiceTable : Ptr32 Void
+0x0e4 Queue : Ptr32 _KQUEUE
+0x0e8 ApcQueueLock : Uint4B
+0x0f0 Timer : _KTIMER
+0x118 QueueListEntry : _LIST_ENTRY
+0x120 SoftAffinity : Uint4B
+0x124 Affinity : Uint4B
+0x128 Preempted : UChar
+0x129 ProcessReadyQueue : UChar
+0x12a KernelStackResident : UChar
+0x12b NextProcessor : UChar
+0x12c CallbackStack : Ptr32 Void
+0x130 Win32Thread : Ptr32 Void
+0x134 TrapFrame : Ptr32 _KTRAP_FRAME
+0x138 ApcStatePointer : [2] Ptr32 _KAPC_STATE
+0x140 PreviousMode : Char
+0x141 EnableStackSwap : UChar
+0x142 LargeStack : UChar
+0x143 ResourceIndex : UChar
+0x144 KernelTime : Uint4B
+0x148 UserTime : Uint4B
+0x14c SavedApcState : _KAPC_STATE
+0x164 Alertable : UChar
+0x165 ApcStateIndex : UChar
+0x166 ApcQueueable : UChar
+0x167 AutoAlignment : UChar
+0x168 StackBase : Ptr32 Void
+0x16c SuspendApc : _KAPC
+0x19c SuspendSemaphore : _KSEMAPHORE
+0x1b0 ThreadListEntry : _LIST_ENTRY
+0x1b8 FreezeCount : Char
+0x1b9 SuspendCount : Char
+0x1ba IdealProcessor : UChar
+0x1bb DisableBoost : UChar
- InitialStack、StackLimit 、KernelStack:用于线程切换;
- State:指示线程状态;
- ApcState、ApcQueueLock、ApcStatePointer、SavedApcState:APC相关;
- Waitblock:正在等待的对象;
- ServiceTable:指向TSS;
- TrapFrame:指向栈帧;
- PreviousMode:程序调用时的权限;
TEB
kd> dt _TEB
nt!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1 : [54] Ptr32 Void
+0x1a4 ExceptionCode : Int4B
+0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1 : [24] UChar
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : Ptr32 Void
+0x6c0 GdiClientPID : Uint4B
+0x6c4 GdiClientTID : Uint4B
+0x6c8 GdiThreadLocalInfo : Ptr32 Void
+0x6cc Win32ClientInfo : [62] Uint4B
+0x7c4 glDispatchTable : [233] Ptr32 Void
+0xb68 glReserved1 : [29] Uint4B
+0xbdc glReserved2 : Ptr32 Void
+0xbe0 glSectionInfo : Ptr32 Void
+0xbe4 glSection : Ptr32 Void
+0xbe8 glTable : Ptr32 Void
+0xbec glCurrentRC : Ptr32 Void
+0xbf0 glContext : Ptr32 Void
+0xbf4 LastStatusValue : Uint4B
+0xbf8 StaticUnicodeString : _UNICODE_STRING
+0xc00 StaticUnicodeBuffer : [261] Uint2B
+0xe0c DeallocationStack : Ptr32 Void
+0xe10 TlsSlots : [64] Ptr32 Void
+0xf10 TlsLinks : _LIST_ENTRY
+0xf18 Vdm : Ptr32 Void
+0xf1c ReservedForNtRpc : Ptr32 Void
+0xf20 DbgSsReserved : [2] Ptr32 Void
+0xf28 HardErrorsAreDisabled : Uint4B
+0xf2c Instrumentation : [16] Ptr32 Void
+0xf6c WinSockData : Ptr32 Void
+0xf70 GdiBatchCount : Uint4B
+0xf74 InDbgPrint : UChar
+0xf75 FreeStackOnTermination : UChar
+0xf76 HasFiberData : UChar
+0xf77 IdealProcessor : UChar
+0xf78 Spare3 : Uint4B
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
+0xf88 Wx86Thread : _Wx86ThreadState
+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
+0xf98 ImpersonationLocale : Uint4B
+0xf9c IsImpersonating : Uint4B
+0xfa0 NlsCache : Ptr32 Void
+0xfa4 pShimData : Ptr32 Void
+0xfa8 HeapVirtualAffinity : Uint4B
+0xfac CurrentTransactionHandle : Ptr32 Void
+0xfb0 ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME
+0xfb4 SafeThunkCall : UChar
+0xfb5 BooleanSpare : [3] UChar
1.3 KPCR
包含处理器控制相关的信息。
kd> dt _KPCR
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32 Void
+0x038 IDT : Ptr32 _KIDTENTRY
+0x03c GDT : Ptr32 _KGDTENTRY
+0x040 TSS : Ptr32 _KTSS
+0x044 MajorVersion : Uint2B
+0x046 MinorVersion : Uint2B
+0x048 SetMember : Uint4B
+0x04c StallScaleFactor : Uint4B
+0x050 DebugActive : UChar
+0x051 Number : UChar
+0x052 Spare0 : UChar
+0x053 SecondLevelCacheAssociativity : UChar
+0x054 VdmAlert : Uint4B
+0x058 KernelReserved : [14] Uint4B
+0x090 SecondLevelCacheSize : Uint4B
+0x094 HalReserved : [16] Uint4B
+0x0d4 InterruptMode : Uint4B
+0x0d8 Spare1 : UChar
+0x0dc KernelReserved2 : [17] Uint4B
+0x120 PrcbData : _KPRCB
NtTib:线程信息块;
Prcb:指向扩展结构KPRCB;
IDT、GDT:指向描述符表基址;
TSS:指向TSS;
Number:CPU编号;
PrcbData:扩展结构;
NT_TIB
kd> dt _NT_TIB
ntdll!_NT_TIB
+0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : Ptr32 Void
+0x008 StackLimit : Ptr32 Void
+0x00c SubSystemTib : Ptr32 Void
+0x010 FiberData : Ptr32 Void
+0x010 Version : Uint4B
+0x014 ArbitraryUserPointer : Ptr32 Void
+0x018 Self : Ptr32 _NT_TIB
- ExceptionList:异常链表;
KPRCB
kd> dt _KPRCB
nt!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD
+0x008 NextThread : Ptr32 _KTHREAD
+0x00c IdleThread : Ptr32 _KTHREAD
+0x010 Number : Char
+0x011 Reserved : Char
+0x012 BuildType : Uint2B
+0x014 SetMember : Uint4B
+0x018 CpuType : Char
+0x019 CpuID : Char
+0x01a CpuStep : Uint2B
+0x01c ProcessorState : _KPROCESSOR_STATE
+0x33c KernelReserved : [16] Uint4B
+0x37c HalReserved : [16] Uint4B
+0x3bc PrcbPad0 : [92] UChar
+0x418 LockQueue : [16] _KSPIN_LOCK_QUEUE
+0x498 PrcbPad1 : [8] UChar
+0x4a0 NpxThread : Ptr32 _KTHREAD
+0x4a4 InterruptCount : Uint4B
+0x4a8 KernelTime : Uint4B
+0x4ac UserTime : Uint4B
+0x4b0 DpcTime : Uint4B
+0x4b4 DebugDpcTime : Uint4B
+0x4b8 InterruptTime : Uint4B
+0x4bc AdjustDpcThreshold : Uint4B
+0x4c0 PageColor : Uint4B
+0x4c4 SkipTick : Uint4B
+0x4c8 MultiThreadSetBusy : UChar
+0x4c9 Spare2 : [3] UChar
+0x4cc ParentNode : Ptr32 _KNODE
+0x4d0 MultiThreadProcessorSet : Uint4B
+0x4d4 MultiThreadSetMaster : Ptr32 _KPRCB
+0x4d8 ThreadStartCount : [2] Uint4B
+0x4e0 CcFastReadNoWait : Uint4B
+0x4e4 CcFastReadWait : Uint4B
+0x4e8 CcFastReadNotPossible : Uint4B
+0x4ec CcCopyReadNoWait : Uint4B
+0x4f0 CcCopyReadWait : Uint4B
+0x4f4 CcCopyReadNoWaitMiss : Uint4B
+0x4f8 KeAlignmentFixupCount : Uint4B
+0x4fc KeContextSwitches : Uint4B
+0x500 KeDcacheFlushCount : Uint4B
+0x504 KeExceptionDispatchCount : Uint4B
+0x508 KeFirstLevelTbFills : Uint4B
+0x50c KeFloatingEmulationCount : Uint4B
+0x510 KeIcacheFlushCount : Uint4B
+0x514 KeSecondLevelTbFills : Uint4B
+0x518 KeSystemCalls : Uint4B
+0x51c SpareCounter0 : [1] Uint4B
+0x520 PPLookasideList : [16] _PP_LOOKASIDE_LIST
+0x5a0 PPNPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x6a0 PPPagedLookasideList : [32] _PP_LOOKASIDE_LIST
+0x7a0 PacketBarrier : Uint4B
+0x7a4 ReverseStall : Uint4B
+0x7a8 IpiFrame : Ptr32 Void
+0x7ac PrcbPad2 : [52] UChar
+0x7e0 CurrentPacket : [3] Ptr32 Void
+0x7ec TargetSet : Uint4B
+0x7f0 WorkerRoutine : Ptr32 void
+0x7f4 IpiFrozen : Uint4B
+0x7f8 PrcbPad3 : [40] UChar
+0x820 RequestSummary : Uint4B
+0x824 SignalDone : Ptr32 _KPRCB
+0x828 PrcbPad4 : [56] UChar
+0x860 DpcListHead : _LIST_ENTRY
+0x868 DpcStack : Ptr32 Void
+0x86c DpcCount : Uint4B
+0x870 DpcQueueDepth : Uint4B
+0x874 DpcRoutineActive : Uint4B
+0x878 DpcInterruptRequested : Uint4B
+0x87c DpcLastCount : Uint4B
+0x880 DpcRequestRate : Uint4B
+0x884 MaximumDpcQueueDepth : Uint4B
+0x888 MinimumDpcRate : Uint4B
+0x88c QuantumEnd : Uint4B
+0x890 PrcbPad5 : [16] UChar
+0x8a0 DpcLock : Uint4B
+0x8a4 PrcbPad6 : [28] UChar
+0x8c0 CallDpc : _KDPC
+0x8e0 ChainedInterruptList : Ptr32 Void
+0x8e4 LookasideIrpFloat : Int4B
+0x8e8 SpareFields0 : [6] Uint4B
+0x900 VendorString : [13] UChar
+0x90d InitialApicId : UChar
+0x90e LogicalProcessorsPerPhysicalProcessor : UChar
+0x910 MHz : Uint4B
+0x914 FeatureBits : Uint4B
+0x918 UpdateSignature : _LARGE_INTEGER
+0x920 NpxSaveArea : _FX_SAVE_AREA
+0xb30 PowerState : _PROCESSOR_POWER_STATE
- CurrentThread:指向当前线程;
- NextThread:指向即将切换的下一个进程;
- IdleThread:指向空闲的进程;
2 线程切换
操作系统中的线程有三种状态:就绪、等待和运行。
正在运行的线程保存在KPCR中,就绪和等待的线程保存在对应的链表中。
2.1 等待链表
一个双向链表,当线程调用了 Sleep() 或者 WaitForSingleObject() 等函数时,就挂到这个链表。
kd> dd KiWaitListHead l2
80553d88 82016e08 82018e08
2.2 就绪链表
由32个双向链表组成,下标表示线程运行级别。
kd> dd KiDispatcherReadyListHead l40
80554820 80554820 80554820 80554828 80554828
80554830 80554830 80554830 80554838 80554838
80554840 80554840 80554840 80554848 80554848
80554850 80554850 80554850 80554858 80554858
80554860 80554860 80554860 80554868 80554868
80554870 80554870 80554870 80554878 80554878
80554880 80554880 80554880 80554888 80554888
80554890 80554890 80554890 80554898 80554898
805548a0 805548a0 805548a0 805548a8 805548a8
805548b0 805548b0 805548b0 805548b8 805548b8
805548c0 805548c0 805548c0 805548c8 805548c8
805548d0 805548d0 805548d0 805548d8 805548d8
805548e0 805548e0 805548e0 805548e8 805548e8
805548f0 805548f0 805548f0 805548f8 805548f8
80554900 80554900 80554900 80554908 80554908
80554910 80554910 80554910 80554918 80554918
2.3 模拟线程切换
#include "StdAfx.h"
#include <windows.h>
#include "ThreadSwitch.h"
//定义线程栈的大小
#define GMTHREADSTACKSIZE 0x80000
//当前线程的索引
int CurrentThreadIndex = 0;
//线程的列表
GMThread_t GMThreadList[MAXGMTHREAD] = {NULL, 0};
//线程状态的标志
enum FLAGS
{
GMTHREAD_CREATE = 0x1,
GMTHREAD_READY = 0x2,
GMTHREAD_SLEEP = 0x4,
GMTHREAD_EXIT = 0x8,
};
//启动线程的函数
void GMThreadStartup(GMThread_t* GMThreadp)
{
GMThreadp->func(GMThreadp->lpParameter);
GMThreadp->Flags = GMTHREAD_EXIT;
Scheduling();
return;
}
//空闲线程的函数
void IdleGMThread(void* lpParameter)
{
printf("IdleGMThread---------------\n");
Scheduling();
return;
}
//向栈中压入一个uint值
void PushStack(unsigned int** Stackpp, unsigned int v)
{
*Stackpp -= 1;
**Stackpp = v;
return;
}
//初始化线程的信息
void InitGMThread(GMThread_t* GMThreadp, char* name, void (*func)(void* lpParameter), void* lpParameter)
{
unsigned char* StackPages;
unsigned int* StackDWordParam;
GMThreadp->Flags = GMTHREAD_CREATE;
GMThreadp->name = name;
GMThreadp->func = func;
GMThreadp->lpParameter = lpParameter;
StackPages = (unsigned char*)VirtualAlloc(NULL, GMTHREADSTACKSIZE, MEM_COMMIT, PAGE_READWRITE);
ZeroMemory(StackPages, GMTHREADSTACKSIZE);
GMThreadp->initialStack = StackPages + GMTHREADSTACKSIZE;
StackDWordParam = (unsigned int*)GMThreadp->initialStack;
//入栈
PushStack(&StackDWordParam, (unsigned int)GMThreadp);//startup 函数所需要的参数
PushStack(&StackDWordParam, (unsigned int)0);//你好奇这里为什么放0,简单来说是为了平衡堆栈,其次是因为调用startup是要参数的,pop startup->eip后 esp也就是这里,进函数后会把mov ebp,esp 然后ebp+8 就是函数默认的参数位置,这也就是这里为什么多push一个四字节。
PushStack(&StackDWordParam, (unsigned int)GMThreadStartup);
PushStack(&StackDWordParam, (unsigned int)5);
PushStack(&StackDWordParam, (unsigned int)7);
PushStack(&StackDWordParam, (unsigned int)6);
PushStack(&StackDWordParam, (unsigned int)3);
PushStack(&StackDWordParam, (unsigned int)2);
PushStack(&StackDWordParam, (unsigned int)1);
PushStack(&StackDWordParam, (unsigned int)0);
//当前线程的栈顶
GMThreadp->KernelStack = StackDWordParam;
GMThreadp->Flags = GMTHREAD_READY;
return;
}
//将一个函数注册为单独线程执行
int RegisterGMThread(char* name, void(*func)(void*lpParameter), void* lpParameter)
{
int i;
for (i = 1; GMThreadList[i].name; i++) {
if (0 == _stricmp(GMThreadList[i].name, name)) {
break;
}
}
initGMThread(&GMThreadList[i], name, func, lpParameter);
return (i & 0x55AA0000);
}
//切换线程
__declspec(naked) void SwitchContext(GMThread_t* SrcGMThreadp, GMThread_t* DstGMThreadp)
{
__asm {
push ebp
mov ebp, esp
push edi
push esi
push ebx
push ecx
push edx
push eax
mov esi, SrcGMThreadp
mov edi, DstGMThreadp
mov [esi+GMThread_t.KernelStack], esp
//经典线程切换,另外一个线程复活
mov esp, [edi+GMThread_t.KernelStack]
pop eax //esp在上面已经切换到新的线程栈中,这个栈再pop eax,拿到的就是保存的esp(初始化的esp/运行时esp)
pop edx
pop ecx
pop ebx
pop esi
pop edi
pop ebp
ret //把栈顶的值弹到eip中,在这里弹出的就是startup的地址到eip中
}
}
//这个函数会让出cpu,从队列里重新选择一个线程执行
void Scheduling(void)
{
int i;
int TickCount;
GMThread_t* SrcGMThreadp;
GMThread_t* DstGMThreadp;
TickCount = GetTickCount();
SrcGMThreadp = &GMThreadList[CurrentThreadIndex];
DstGMThreadp = &GMThreadList[0];
for (i = 1; GMThreadList[i].name; i++) {
if (GMThreadList[i].Flags & GMTHREAD_SLEEP) {
if (TickCount > GMThreadList[i].SleepMillsecondDot) {
GMThreadList[i].Flags = GMTHREAD_READY;
}
}
if (GMThreadList[i].Flags & GMTHREAD_READY) {
DstGMThreadp = &GMThreadList[i];
break;
}
}
CurrentThreadIndex = DstGMThreadp - GMThreadList;
SwitchContext(SrcGMThreadp, DstGMThreadp);
return;
}
void GMSleep(int MilliSeconds)
{
GMThread_t* GMThreadp;
GMThreadp = &GMThreadList[CurrentThreadIndex];
if (GMThreadp->Flags != 0) {
GMThreadp->Flags = GMTHREAD_SLEEP;
GMThreadp->SleepMillsecondDot = GetTickCount() + MilliSeconds;
}
Scheduling();
return;
}
2.4 线程切换
主动切换
在Windows内核中,也存在类似的线程切换函数,调用链如下,最终在SwapContext中完成ESP的切换。
KiSwapThread
KiSwapContext
SwapContext
时钟中断切换
除了线程的主动切换,也可以通过中断和异常从外部实现线程的切换。而时钟中断是最常用的导致线程切换的中断,但是如果线程屏蔽了中断且不会产生异常,那么该线程将无法被动切换。
时钟中断导致的线程切换有两种情况。
第一种情况是存在备用线程(KPCR.PrcbData.NextThread),此时线程会在时间片结束后立即进行切换:
KiDispatchInterrupt
SwapContext
第二种情况是在当前次时钟中断时,当前线程对应的KPCR.PrcbData.QuantumEnd属性减为0,则会调用KiQuantumEnd寻找新的线程进行切换。
KiDispatchInterrupt
KiQuantumEnd
SwapContext
2.5 源码分析
KiSwapThread:
@KiSwapThread@0 proc near
mov edi, edi
push esi
push edi
db 3Eh ;
mov eax, ds:0FFDFF020h ; 获取KPRCB
mov esi, eax
mov eax, [esi+8] ; 获取NextThread
test eax, eax
mov edi, [esi+4] ; 获取CurrentThread
jz short loc_80501CAC
and dword ptr [esi+8], 0 ; NextThread清0
jmp short loc_80501CCF ; 赋值NextThread
loc_80501CCF:
mov ecx, eax ; 赋值NextThread
call @KiSwapContext@4 ; 调用KiSwapContext(x)
KiSwapContext:
@KiSwapContext@4 proc near
var_10= dword ptr -10h
var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
sub esp, 10h
mov [esp+10h+var_4], ebx ; 压栈
mov [esp+10h+var_8], esi
mov [esp+10h+var_C], edi
mov [esp+10h+var_10], ebp
mov ebx, ds:0FFDFF01Ch ; 获取KPCR
mov esi, ecx ; 获取NextThread
mov edi, [ebx+124h] ; 获取CurrentThread
mov [ebx+124h], esi ; 将NextThread的值赋给KPRCB中的CurrentThread字段
mov cl, [edi+58h] ; 获取TCB中的WaitIrql字段
call SwapContext ; 调用SwapContext
mov ebp, [esp+10h+var_10] ; 弹栈
mov edi, [esp+10h+var_C]
mov esi, [esp+10h+var_8]
mov ebx, [esp+10h+var_4]
add esp, 10h
retn
@KiSwapContext@4 endp
SwapContext:
SwapContext proc near ; CODE XREF: KiUnlockDispatcherDatabase(x)+72↑p
; KiSwapContext(x)+29↑p
; KiDispatchInterrupt()+7A↑p
or cl, cl
mov byte ptr es:[esi+2Dh], 2 ; 修改NextThread的State字段
pushf
loc_805428E8: ; CODE XREF: KiIdleLoop()+5A↓j
mov ecx, [ebx] ; 获取Nt_Tib
cmp dword ptr [ebx+994h], 0 ; NpxSaveArea字段,与FPU和SSE寄存器相关
push ecx
jnz loc_80542A2D
cmp ds:_PPerfGlobalGroupMask, 0
jnz loc_80542A04
loc_80542905: ; CODE XREF: SwapContext+12C↓j
; SwapContext+13D↓j
; SwapContext+148↓j
mov ebp, cr0
mov edx, ebp
mov cl, [esi+2Ch] ; 获取NextThread的DebugActive字段
mov [ebx+50h], cl ; 放入KPCR中
cli
mov [edi+28h], esp ; 将当前的ESP放入CurrentThread中的KernelStack
mov eax, [esi+18h] ; 获取新的StackLimit和InitialStack
mov ecx, [esi+1Ch]
sub eax, 210h ; 抬栈底,将下面的FPU去掉
mov [ebx+8], ecx ; 放入KPCR中
mov [ebx+4], eax
xor ecx, ecx
mov cl, [esi+31h] ; 获取NpxState
and edx, 0FFFFFFF1h
or ecx, edx
or ecx, [eax+20Ch]
cmp ebp, ecx
jnz loc_805429FC
lea ecx, [ecx+0]
loc_80542940: ; CODE XREF: SwapContext+11F↓j
test dword ptr [eax-1Ch], 20000h ; 检测是否为V86模式
jnz short loc_8054294C ; 获取TSS
sub eax, 10h ; 如果是V86模式,则再次抬栈
loc_8054294C: ; CODE XREF: SwapContext+67↑j
mov ecx, [ebx+40h] ; 获取TSS
mov [ecx+4], eax ; 将当前EAX值(栈顶)赋给TSS寄存器中的ESP0
mov esp, [esi+28h] ; 将NextThread的KernelStack赋给ESP
mov eax, [esi+20h] ; 获取PEB
mov [ebx+18h], eax ; 将PEB赋值给Nt_TiB
sti
mov eax, [edi+44h] ; 比较两个线程的ApcState.Process,判断是否为同一个进程
cmp eax, [esi+44h]
mov byte ptr [edi+50h], 0
jz short loc_80542994 ; 获取TEB
mov edi, [esi+44h] ; 获取目标线程的_KProcess
test word ptr [edi+20h], 0FFFFh ; 判断LdtDescriptor
jnz short loc_805429CE
xor eax, eax
loc_80542975: ; CODE XREF: SwapContext+117↓j
lldt ax
xor eax, eax
mov gs, eax ; 清除gs
assume gs:GAP
mov eax, [edi+18h] ; 获取新的CR3
mov ebp, [ebx+40h] ; 获取TSS
mov ecx, [edi+30h] ; 获取IopmOffset
mov [ebp+1Ch], eax ; 修改TSS中的CR3
mov cr3, eax ; 修改CR3寄存器
mov [ebp+66h], cx ; 修改IO权限位图
jmp short loc_80542994 ; 获取TEB
; ---------------------------------------------------------------------------
align 4
loc_80542994: ; CODE XREF: SwapContext+86↑j
; SwapContext+AF↑j
mov eax, [ebx+18h] ; 获取TEB
mov ecx, [ebx+3Ch] ; 获取GDT
mov [ecx+3Ah], ax ; 修改GDT表项
shr eax, 10h
mov [ecx+3Ch], al
mov [ecx+3Fh], ah
inc dword ptr [esi+4Ch] ; 修改ContextSwitches
inc dword ptr [ebx+61Ch]
pop ecx
mov [ebx], ecx ; 赋值Nt_Tib
cmp byte ptr [esi+49h], 0 ; 判断KernelApcPending是否为0
jnz short loc_805429BD ; 返回1表示有APC需要执行
popf
xor eax, eax
retn
2.6 实验1:跨进程读写
由于驱动程序本身在高2G内存中运行,所以直接修改CR3读取低2G内存后修改回来即可。
#include <ntddk.h>
UINT32 g_cr3 = 0;
// 卸载驱动
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriObj)
{
DbgPrint("Unload Driver!\n");
return STATUS_SUCCESS;
}
NTSTATUS ReadNotePad(VOID)
{
PVOID* mem = (UINT32*)ExAllocatePoolWithTag(NonPagedPool, 4, NULL);
// 更改CR3
_asm {
mov eax, cr3
mov g_cr3, eax
mov eax, 0x09380340
mov cr3, eax
}
// 读取低2G内存地址
RtlMoveMemory(mem, (PVOID)0xAB128, 4);
DbgPrint("The Text is %p\n", *mem);
// 改回CR3
_asm {
mov eax, g_cr3
mov cr3, eax
}
//ExFreePool(mem);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
DbgPrint("Load Driver!\n");
pDriver->DriverUnload = UnloadDriver;
return ReadNotePad();
}
3 APC
3.1 APC结构
KAPC
APC结构体,位于TCB中的SuspendApc字段:
kd> dt _KAPC
nt!_KAPC
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 Spare0 : Uint4B
+0x008 Thread : Ptr32 _KTHREAD
+0x00c ApcListEntry : _LIST_ENTRY
+0x014 KernelRoutine : Ptr32 void
+0x018 RundownRoutine : Ptr32 void
+0x01c NormalRoutine : Ptr32 void
+0x020 NormalContext : Ptr32 Void
+0x024 SystemArgument1 : Ptr32 Void
+0x028 SystemArgument2 : Ptr32 Void
+0x02c ApcStateIndex : Char
+0x02d ApcMode : Char
+0x02e Inserted : UChar
- Thread:APC所属的线程;
- ApcListEntry:APC挂入的队列,是一个双向链表;
- KernelRoutine:指向APC释放函数;
- NormalRoutine:用户APC总入口或真正的内核APC函数;
- NormalContext:真正的用户APC函数;
- SystemArgument:APC函数的参数;
- ApcMode:标识用户APC / 内核APC;
- Inserted:0时表示当前APC未挂入,1时表示已经挂入;
- ApcStateIndex:
0:表示原始环境;
1:表示挂靠环境;
2:表示当前环境;
3:表示挂入APC时的当前环境;
KAPC_STATE
APC队列结构体,位于KTHREAD中的ApcState字段:
kd> dt _KAPC_STATE
nt!_KAPC_STATE
+0x000 ApcListHead : [2] _LIST_ENTRY
+0x010 Process : Ptr32 _KPROCESS
+0x014 KernelApcInProgress : UChar
+0x015 KernelApcPending : UChar
+0x016 UserApcPending : UChar
- ApcListHead: 用户、内核APC队列;
- Process:线程所属进程;
- KernelApcInProgress:内核APC是否正在执行;
- KernelApcPending:是否有正在等待的内核APC;
- UserApcPending:是否有正在等待的用户APC;
SavedApcState
备用APC队列,同样位于KTHREAD中,和ApcState字段一样,也是KAPC_STATE结构体。用于在该线程进行进程挂靠时暂时存储ApcState字段的值。
那么在进程挂靠时,ApcState中存储的就是所挂靠进程的APC队列。
ApcStatePointer
存储两个APC队列的指针,在正常情况下,分别执行ApcState和SavedApcState,在挂靠时交换。
ApcStateIndex
标识线程状态,0表示正常状态,1表示挂靠状态。
ApcQueueable
标识当前是否允许挂入APC,1表示允许挂入。
3.2 APC挂入
在3环DLL注入时使用到的QueueUserAPC函数就是线程的APC挂入过程,调用链如下:
QueueUserAPC
NtQueueApcThread
KeInitializeApc
KeInsertQueueApc
KiInsertQueueApc
KeInitializeApc
此函数用于在插入APC前初始化一个新的KAPC结构体;
参数定义:
VOID KeInitializeApc
(
IN PKAPC Apc, //KAPC 指针
IN PKTHREAD Thread, //目标线程
IN KAPC_ENVIRONMENT Environment, //四种状态
IN PKKERNEL_ROUTINE KernelRoutine, //销毁 KAPC 的函数地址
IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL,
IN PKNORMAL_ROUTINE NormalRoutine, //用户 APC 总入口或者内核 APC 函数
IN KPROCESSOR_MODE Mode, //要插入用户 APC 队列还是内核 APC 队列
IN PVOID Context //内核APC:NULL,用户APC:真正的APC函数
)
代码分析:
mov edi, edi
push ebp
mov ebp, esp
mov eax, [ebp+arg_0] ; 获取KAPC
mov edx, [ebp+arg_8] ; 获取Env
cmp edx, 2 ; 判断Env的值是否为2
mov ecx, [ebp+arg_4] ; 获取Thread
mov word ptr [eax], 12h ; KAPC结构体赋值
mov word ptr [eax+2], 30h ; '0'
jnz short loc_804FBA6A ; 如果Env是2则跳转
mov dl, [ecx+165h] ; 获取KTHREAD中的ApcStateIndex
loc_804FBA6A: ; CODE XREF: KeInitializeApc(x,x,x,x,x,x,x,x)+1C↑j
mov [eax+8], ecx ; 继续赋值KAPC
mov ecx, [ebp+arg_C]
mov [eax+14h], ecx
mov ecx, [ebp+arg_10]
mov [eax+2Ch], dl
mov [eax+18h], ecx
mov ecx, [ebp+arg_14] ; NormalRoutine
xor edx, edx
cmp ecx, edx ; 判断是否为内核模式
mov [eax+1Ch], ecx
jz short loc_804FBA96 ; 内核模式下赋值KAPC
mov cl, [ebp+arg_18] ; 用户模式下继续赋值KAPC
mov [eax+2Dh], cl
mov ecx, [ebp+arg_1C]
mov [eax+20h], ecx
jmp short loc_804FBA9C ; KAPC中最后的Inserted赋值为0
; ---------------------------------------------------------------------------
loc_804FBA96: ; CODE XREF: KeInitializeApc(x,x,x,x,x,x,x,x)+40↑j
mov [eax+2Dh], dl ; 内核模式下赋值KAPC
mov [eax+20h], edx
loc_804FBA9C: ; CODE XREF: KeInitializeApc(x,x,x,x,x,x,x,x)+4E↑j
mov [eax+2Eh], dl ; KAPC中最后的Inserted赋值为0
pop ebp
retn 20h
KiInsertQueueApc
插入已经初始化的KPRC结构体;
参数定义:
VOID FASTCALL KiInsertQueueApc
(
IN PKAPC Apc, // KAPC指针(指向一个已经初始化完成的APC)
IN KPRIORITY PriorityBoost
)
代码分析:
mov edi, edi
push ebp
mov ebp, esp
push ecx
mov eax, ecx ; 获取KAPC
cmp byte ptr [eax+2Eh], 0 ; 判断Inserted字段
mov ecx, [eax+8] ; 获取Thread
mov [ebp+var_4], edx
jz short loc_804FEC5E ; 判断ApcStateIndex值是否为3
xor al, al ; 若已经被插入,直接返回
leave
retn
; ---------------------------------------------------------------------------
loc_804FEC5E: ; CODE XREF: KiInsertQueueApc(x,x)+12↑j
cmp byte ptr [eax+2Ch], 3 ; 判断ApcStateIndex值是否为3
jnz short loc_804FEC6D ; 判断NormalRoutine是否为0
mov dl, [ecx+165h] ; 获取KTHREAD中的ApcStateIndex
mov [eax+2Ch], dl
loc_804FEC6D: ; CODE XREF: KiInsertQueueApc(x,x)+1C↑j
cmp dword ptr [eax+1Ch], 0 ; 判断NormalRoutine是否为0
movsx edx, byte ptr [eax+2Ch] ; 获取ApcStateIndex
push ebx
push esi
push edi
mov edi, [ecx+edx*4+138h] ; 根据ApcStateIndex获取ApcStatePointer
mov dl, [eax+2Dh] ; 获取ApcMode
jz short loc_804FECC4 ; 当NormalRoutine为0时跳转
test dl, dl ; 判断是否为内核APC
jz short loc_804FECAC ; 处理内核APC
cmp dword ptr [eax+14h], offset _PsExitSpecialApc@20 ; 判断APC释放函数的类型
jnz short loc_804FECAC ; 处理内核APC
movsx ebx, dl ; 处理用户APC
mov byte ptr [ecx+4Ah], 1 ; 修改UserApcPending
lea edi, [edi+ebx*8] ; 获取要插入的APC队列
mov ebx, [edi] ; 获取APC队列
lea esi, [eax+0Ch] ; 获取当前的KAPC结构体中ApcListEntry字段的地址
mov [esi], ebx ; 前驱指针放入原先的前驱指针
mov [esi+4], edi ; 后继指针放入原先的节点地址
mov [ebx+4], esi ; 原队列的末尾节点的后继指针指向新插入的节点
mov [edi], esi ; 当前节点作为尾节点
jmp short loc_804FECEB ; 用户APC插入完成
; ---------------------------------------------------------------------------
loc_804FECAC: ; CODE XREF: KiInsertQueueApc(x,x)+40↑j
; KiInsertQueueApc(x,x)+49↑j
movsx ebx, dl ; 处理内核APC
lea edi, [edi+ebx*8] ; 获取APC队列,同上
mov ebx, [edi+4]
lea esi, [eax+0Ch]
mov [esi], edi
mov [esi+4], ebx
mov [ebx], esi
mov [edi+4], esi
jmp short loc_804FECEB ; 获取ApcStateIndex
; ---------------------------------------------------------------------------
loc_804FECC4: ; CODE XREF: KiInsertQueueApc(x,x)+3C↑j
movsx esi, dl
lea edi, [edi+esi*8] ; 获取APC队列
mov esi, [edi+4] ; 获取后继节点
jmp short loc_804FECD8 ; 后继节点和APC队列相等,即链表是否为空
; ---------------------------------------------------------------------------
loc_804FECCF: ; CODE XREF: KiInsertQueueApc(x,x)+94↓j
cmp dword ptr [esi+10h], 0 ; 判断进程号是否为0
jz short loc_804FECDC ; 插入APC
mov esi, [esi+4] ; 获取另外一个APC队列?
loc_804FECD8: ; CODE XREF: KiInsertQueueApc(x,x)+87↑j
cmp esi, edi ; 后继节点和APC队列相等,即链表是否为空
jnz short loc_804FECCF ; 判断进程号是否为0
loc_804FECDC: ; CODE XREF: KiInsertQueueApc(x,x)+8D↑j
mov ebx, [esi] ; 插入APC
lea edi, [eax+0Ch]
mov [edi], ebx
mov [edi+4], esi
mov [ebx+4], edi
mov [esi], edi
loc_804FECEB: ; CODE XREF: KiInsertQueueApc(x,x)+64↑j
; KiInsertQueueApc(x,x)+7C↑j
movsx edi, byte ptr [eax+2Ch] ; 获取ApcStateIndex
mov byte ptr [eax+2Eh], 1 ; Inserted字段置为1
movzx esi, byte ptr [ecx+165h] ; 获取TCB中的ApcStateIndex
cmp edi, esi ; 比较两个ApcStateIndex字段
pop edi
pop esi
pop ebx
jnz short loc_804FED70 ; ApcStateIndex不同则跳转
test dl, dl ; 判断ApcMode,用户模式则跳转
jnz short loc_804FED42 ; 用户模式处理,判断State
mov dl, [ecx+2Dh] ; 获取线程的State
cmp dl, 2
mov byte ptr [ecx+49h], 1 ; 赋值KernelApcPending字段为1
jnz short loc_804FED1B ; 线程State不为2则跳转
mov cl, 1
call ds:__imp_@HalRequestSoftwareInterrupt@4 ; HalRequestSoftwareInterrupt(x)
jmp short loc_804FED70 ; 异常退出
; ---------------------------------------------------------------------------
loc_804FED1B: ; CODE XREF: KiInsertQueueApc(x,x)+C9↑j
cmp dl, 5 ; 判断State是否等于5
jnz short loc_804FED70 ; 异常退出
cmp byte ptr [ecx+58h], 0 ; 判断WaitIrql是否为0
jnz short loc_804FED70 ; 异常退出
xor edx, edx
cmp [eax+1Ch], edx ; 判断NormalRoutine是否为0
jz short loc_804FED3A
cmp [ecx+0D4h], edx ; 判断KernelApcDisable
jnz short loc_804FED70 ; 异常退出
cmp [ecx+48h], dl ; 判断KernelApcInProgress
jnz short loc_804FED70 ; 异常退出
loc_804FED3A: ; CODE XREF: KiInsertQueueApc(x,x)+E5↑j
push edx
mov edx, 100h
jmp short loc_804FED68
; ---------------------------------------------------------------------------
loc_804FED42: ; CODE XREF: KiInsertQueueApc(x,x)+BD↑j
cmp byte ptr [ecx+2Dh], 5 ; 用户模式处理,判断State
jnz short loc_804FED70 ; 异常退出
cmp byte ptr [ecx+59h], 1 ; 判断WaitMode
jnz short loc_804FED70 ; 异常退出
cmp byte ptr [ecx+164h], 0 ; 判断Alertable
jnz short loc_804FED5D ; UserApcPending置为1
cmp byte ptr [ecx+4Ah], 0 ; 判断UserApcPending
jz short loc_804FED70 ; 异常退出
loc_804FED5D: ; CODE XREF: KiInsertQueueApc(x,x)+10F↑j
mov byte ptr [ecx+4Ah], 1 ; UserApcPending置为1
push 0
mov edx, 0C0h
loc_804FED68: ; CODE XREF: KiInsertQueueApc(x,x)+FA↑j
push [ebp+var_4]
call @KiUnwaitThread@16 ; 唤醒线程
loc_804FED70: ; CODE XREF: KiInsertQueueApc(x,x)+B9↑j
mov al, 1 ; 异常退出
leave
retn
3.3 APC调用
线程切换
在线程切换时,SwapContext函数会判断KernelApcPending是否为0,如果不为0则会返回1,在KiSwapThread中会对该返回值进行判断,从而调用KiDeliverApc:
loc_80501CCF: ; CODE XREF: KiSwapThread()+1A↑j
mov ecx, eax
call @KiSwapContext@4 ; KiSwapContext(x)
test al, al ; 判断SwapContext返回值
mov cl, [edi+58h] ; 获取WaitIrql
mov edi, [edi+54h] ; 获取WaitStatus
mov esi, ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
jz short loc_80501CF6
mov cl, 1 ; NewIrql
call esi ; KfLowerIrql(x) ; KfLowerIrql(x)
xor eax, eax
push eax
push eax
push eax
call _KiDeliverApc@12
退出0环
当线程调用API或异常中断返回到3环时,在KiServiceExit函数中会对UserApcPending字段进行判断,最后同样调用KiDeliverApc函数进行处理。
3.4 APC执行
KiDeliverApc
此函数完成内核APC的执行,以及用户APC执行前的处理,将继续调用KiInitializeUserApc函数处理用户APC。
函数定义:
_KTRAP_FRAME *__stdcall KiDeliverApc
(
BOOLEAN CanUserAPC,
int unknown,
_KTRAP_FRAME *trapframe
);
代码分析:
_KiDeliverApc@12 proc near
LockHandle= _KLOCK_QUEUE_HANDLE ptr -28h
var_1C= dword ptr -1Ch
BugCheckParameter1= dword ptr -18h
var_14= dword ptr -14h
var_10= dword ptr -10h
var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
arg_0= byte ptr 8
arg_4= dword ptr 0Ch
arg_8= dword ptr 10h
mov edi, edi
push ebp
mov ebp, esp
sub esp, 28h
mov ecx, [ebp+arg_8] ; 获取TrapFrame
test ecx, ecx
jz short loc_804FEA54
mov edx, [ecx+68h] ; 获取EIP
mov eax, offset _ExpInterlockedPopEntrySListResume@0 ; ExpInterlockedPopEntrySListResume()
cmp edx, eax
jb short loc_804FEA54
cmp edx, offset _ExpInterlockedPopEntrySListEnd@0 ; ExpInterlockedPopEntrySListEnd()
ja short loc_804FEA54
mov [ecx+68h], eax
loc_804FEA54: ; CODE XREF: KiDeliverApc(x,x,x)+D↑j
; KiDeliverApc(x,x,x)+19↑j
; KiDeliverApc(x,x,x)+21↑j
push ebx
push esi
push edi
mov eax, large fs:124h ; 获取CurrentThread
mov esi, eax
mov eax, [esi+134h] ; 获取TrapFrame
mov [ebp+var_1C], eax
mov eax, [esi+44h] ; 获取Process
mov [esi+134h], ecx ; 更改TrapFrame
lea ecx, [esi+0E8h] ; SpinLock
lea edx, [ebp+LockHandle] ; LockHandle
mov [ebp+BugCheckParameter1], eax
call ds:__imp_@KeAcquireInStackQueuedSpinLock@8 ; KeAcquireInStackQueuedSpinLock(x,x)
mov byte ptr [esi+49h], 0 ; KernelApcPending置0
lea ebx, [esi+34h] ; 获取ApcState
jmp loc_804FEB70 ; 判断内核APC列表是否为空
; ---------------------------------------------------------------------------
loc_804FEA8F: ; CODE XREF: KiDeliverApc(x,x,x)+144↓j
mov eax, [ebx] ; 获取前驱指针
lea edi, [eax-0Ch] ; 获取KAPC结构体
mov ecx, [edi+14h] ; 获取KernelRoutine
mov [ebp+var_14], ecx
mov ecx, [edi+1Ch] ; 获取NormalRoutine,即内核APC函数
test ecx, ecx ; 判断内核函数是否存在
mov [ebp+var_4], ecx
mov edx, [edi+20h] ; 获取NormalContext
mov [ebp+var_10], edx
mov edx, [edi+24h] ; SystemArgument1
mov [ebp+var_C], edx
mov edx, [edi+28h] ; SystemArgument2
mov [ebp+var_8], edx
jnz short loc_804FEAF2 ; 内核APC函数存在则跳转
mov ecx, [eax]
mov eax, [eax+4]
mov [eax], ecx
mov [ecx+4], eax
lea ecx, [ebp+LockHandle] ; LockHandle
mov byte ptr [edi+2Eh], 0
call ds:__imp_@KeReleaseInStackQueuedSpinLock@4 ; KeReleaseInStackQueuedSpinLock(x)
lea eax, [ebp+var_8] ; 直接调用KernelRoutine释放APC
push eax
lea eax, [ebp+var_C]
push eax
lea eax, [ebp+var_10]
push eax
lea eax, [ebp+var_4]
push eax
push edi
call [ebp+var_14]
lea edx, [ebp+LockHandle] ; LockHandle
lea ecx, [esi+0E8h] ; SpinLock
call ds:__imp_@KeAcquireInStackQueuedSpinLock@8 ; KeAcquireInStackQueuedSpinLock(x,x)
jmp short loc_804FEB70 ; 判断内核APC列表是否为空
; ---------------------------------------------------------------------------
loc_804FEAF2: ; CODE XREF: KiDeliverApc(x,x,x)+86↑j
cmp byte ptr [esi+48h], 0 ; 判断KernelApcInProgress
jnz loc_804FEC05
cmp dword ptr [esi+0D4h], 0 ; 判断KernelApcDisable
jnz loc_804FEC05
mov ecx, [eax] ; 从队列中删除当前APC节点
mov eax, [eax+4]
mov [eax], ecx
mov [ecx+4], eax
lea ecx, [ebp+LockHandle] ; LockHandle
mov byte ptr [edi+2Eh], 0 ; Inserted置0
call ds:__imp_@KeReleaseInStackQueuedSpinLock@4 ; KeReleaseInStackQueuedSpinLock(x)
lea eax, [ebp+var_8] ; 参数压栈
push eax
lea eax, [ebp+var_C]
push eax
lea eax, [ebp+var_10]
push eax
lea eax, [ebp+var_4]
push eax
push edi
call [ebp+var_14] ; 调用KernelRoutine,释放APC
cmp [ebp+var_4], 0 ; 判断NormalRoutine
jz short loc_804FEB5D
xor cl, cl ; NewIrql
mov byte ptr [esi+48h], 1 ; KernelApcInProgress置1
call ds:__imp_@KfLowerIrql@4 ; KfLowerIrql(x)
push [ebp+var_8] ; 压入参数
push [ebp+var_C]
push [ebp+var_10]
call [ebp+var_4] ; 调用APC函数
mov cl, 1 ; NewIrql
call ds:__imp_@KfRaiseIrql@4 ; KfRaiseIrql(x)
mov [ebp+LockHandle.OldIrql], al
loc_804FEB5D: ; CODE XREF: KiDeliverApc(x,x,x)+10A↑j
lea edx, [ebp+LockHandle] ; LockHandle
lea ecx, [esi+0E8h] ; SpinLock
call ds:__imp_@KeAcquireInStackQueuedSpinLock@8 ; KeAcquireInStackQueuedSpinLock(x,x)
mov byte ptr [esi+48h], 0 ; KernelApcInProgress置0
loc_804FEB70: ; CODE XREF: KiDeliverApc(x,x,x)+5C↑j
; KiDeliverApc(x,x,x)+C2↑j
cmp [ebx], ebx ; 判断内核APC列表是否为空
jnz loc_804FEA8F ; 获取前驱指针
lea ecx, [esi+3Ch] ; 获取用户APC队列
mov eax, [ecx] ; 获取前驱指针
cmp eax, ecx ; 判断链表是否为空
jz loc_804FEC05 ; 用户APC队列为空的跳转
cmp [ebp+arg_0], 1 ; 判断传入的参数CanUserAPC是否为1
jnz short loc_804FEC05
cmp byte ptr [esi+4Ah], 0 ; 判断UserApcPending
jz short loc_804FEC05
mov byte ptr [esi+4Ah], 0 ; UserApcPending置0
lea edi, [eax-0Ch] ; 获取KAPC
mov ecx, [edi+1Ch] ; 获取NormalRoutine
mov ebx, [edi+14h] ; 获取KernelRoutine
mov [ebp+var_4], ecx ; NormalRoutine
mov ecx, [edi+20h]
mov [ebp+var_10], ecx ; NorlamContext
mov ecx, [edi+24h]
mov [ebp+var_C], ecx ; Arg1
mov ecx, [edi+28h]
mov [ebp+var_8], ecx ; Arg2
mov ecx, [eax] ; 添加APC队列
mov eax, [eax+4]
mov [eax], ecx
mov [ecx+4], eax
lea ecx, [ebp+LockHandle] ; LockHandle
mov byte ptr [edi+2Eh], 0
call ds:__imp_@KeReleaseInStackQueuedSpinLock@4 ; KeReleaseInStackQueuedSpinLock(x)
lea eax, [ebp+var_8] ; 释放APC
push eax
lea eax, [ebp+var_C]
push eax
lea eax, [ebp+var_10]
push eax
lea eax, [ebp+var_4]
push eax
push edi
call ebx
cmp [ebp+var_4], 0 ; 判断NormalRoutine
jnz short loc_804FEBEC ; 调用KiInitializeUserApc处理用户APC
push 1
call _KeTestAlertThread@4 ; KeTestAlertThread(x)
jmp short loc_804FEC0E
; ---------------------------------------------------------------------------
loc_804FEBEC: ; CODE XREF: KiDeliverApc(x,x,x)+1B3↑j
push [ebp+var_8] ; 调用KiInitializeUserApc处理用户APC
push [ebp+var_C]
push [ebp+var_10]
push [ebp+var_4]
push [ebp+arg_8]
push [ebp+arg_4]
call _KiInitializeUserApc@24 ; KiInitializeUserApc(x,x,x,x,x,x)
jmp short loc_804FEC0E
; ---------------------------------------------------------------------------
loc_804FEC05: ; CODE XREF: KiDeliverApc(x,x,x)+C8↑j
; KiDeliverApc(x,x,x)+D5↑j
; KiDeliverApc(x,x,x)+151↑j
; KiDeliverApc(x,x,x)+15B↑j
; KiDeliverApc(x,x,x)+161↑j
lea ecx, [ebp+LockHandle] ; LockHandle
call ds:__imp_@KeReleaseInStackQueuedSpinLock@4 ; KeReleaseInStackQueuedSpinLock(x)
loc_804FEC0E: ; CODE XREF: KiDeliverApc(x,x,x)+1BC↑j
; KiDeliverApc(x,x,x)+1D5↑j
mov ecx, [ebp+BugCheckParameter1]
cmp [esi+44h], ecx
jz short loc_804FEC30
mov eax, large fs:994h
push eax ; BugCheckParameter4
movzx eax, byte ptr [esi+165h]
push eax ; BugCheckParameter3
push dword ptr [esi+44h] ; BugCheckParameter2
push ecx ; BugCheckParameter1
push 5 ; BugCheckCode
call _KeBugCheckEx@20 ; KeBugCheckEx(x,x,x,x,x)
; ---------------------------------------------------------------------------
loc_804FEC30: ; CODE XREF: KiDeliverApc(x,x,x)+1E6↑j
mov eax, [ebp+var_1C]
pop edi
mov [esi+134h], eax
pop esi
pop ebx
leave
retn 0Ch
_KiDeliverApc@12 endp
KiInitializeUserApc
CONTEXT结构体:
kd> dt _CONTEXT
ntdll!_CONTEXT
+0x000 ContextFlags : Uint4B
+0x004 Dr0 : Uint4B
+0x008 Dr1 : Uint4B
+0x00c Dr2 : Uint4B
+0x010 Dr3 : Uint4B
+0x014 Dr6 : Uint4B
+0x018 Dr7 : Uint4B
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : Uint4B
+0x090 SegFs : Uint4B
+0x094 SegEs : Uint4B
+0x098 SegDs : Uint4B
+0x09c Edi : Uint4B
+0x0a0 Esi : Uint4B
+0x0a4 Ebx : Uint4B
+0x0a8 Edx : Uint4B
+0x0ac Ecx : Uint4B
+0x0b0 Eax : Uint4B
+0x0b4 Ebp : Uint4B
+0x0b8 Eip : Uint4B
+0x0bc SegCs : Uint4B
+0x0c0 EFlags : Uint4B
+0x0c4 Esp : Uint4B
+0x0c8 SegSs : Uint4B
+0x0cc ExtendedRegisters : [512] UChar
函数定义:
KiInitializeUserApc
(
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
代码分析:
_KiInitializeUserApc@24 proc near ; CODE XREF: KiDeliverApc(x,x,x)+1D0↑p
ExceptionRecord= _EXCEPTION_RECORD ptr -34Ch
var_2FC= dword ptr -2FCh
var_2F8= dword ptr -2F8h
var_2F4= dword ptr -2F4h
BugCheckParameter3= dword ptr -2F0h
var_2EC= dword ptr -2ECh
var_2E8= dword ptr -2E8h
var_228= dword ptr -228h
var_224= dword ptr -224h
var_1C= dword ptr -1Ch
ms_exc= CPPEH_RECORD ptr -18h
arg_0= dword ptr 8
arg_4= dword ptr 0Ch
arg_8= dword ptr 10h
arg_C= dword ptr 14h
arg_10= dword ptr 18h
arg_14= dword ptr 1Ch
; __unwind { // __SEH_prolog
push 33Ch
push offset stru_804DA0B0
call __SEH_prolog
mov eax, ___security_cookie
mov [ebp+var_1C], eax
mov eax, [ebp+arg_0]
mov [ebp+var_2F4], eax
mov ebx, [ebp+arg_4] ; 获取TrapFrame
mov [ebp+BugCheckParameter3], ebx
test byte ptr [ebx+72h], 2 ; 判断是否为V86模式
jnz loc_80502B7B
mov [ebp+var_2E8], 10017h
lea ecx, [ebp+var_2E8] ; 获取ContextFrame
push ecx
push eax
push ebx
call _KeContextFromKframes@12 ; 备份TrapFrame
; __try { // __except at loc_80502B4E
and [ebp+ms_exc.registration.TryLevel], 0
mov eax, 2DCh
mov [ebp+var_2F8], eax
mov esi, [ebp+var_224] ; 获取原栈顶ESP3
and esi, 0FFFFFFFCh ; 将栈顶按4字节对齐
sub esi, eax ; 抬栈(ContextFrame + 4个参数)
mov [ebp+var_2EC], esi
push 4 ; Alignment
push eax ; Length
push esi ; Address
call _ProbeForWrite@12 ; ProbeForWrite(x,x,x)
lea edi, [esi+10h] ; 复制TrapFrame到ContextFrame中
mov ecx, 0B3h
lea esi, [ebp+var_2E8]
rep movsd
mov dword ptr [ebx+6Ch], 1Bh ; 修改TrapFrame中的CS
push 23h ; '#'
pop eax
mov [ebx+78h], eax ; 修改TrapFrame中的SS,DS,ES,FS,GS
mov [ebx+38h], eax
mov [ebx+34h], eax
mov dword ptr [ebx+50h], 3Bh ; ';'
and dword ptr [ebx+30h], 0
mov ecx, [ebp+var_228] ; 获取ContextFrame中的EFlags
test ecx, 20000h ; 判断是否为V86模式
jz short loc_80502AC6 ; 是V86模式则跳转
cmp byte ptr _KeI386VdmIoplAllowed, 0
jz short loc_80502AC6
mov eax, _KeI386EFlagsAndMaskV86
and eax, ecx
or eax, _KeI386EFlagsOrMaskV86
jmp short loc_80502AD4
; ---------------------------------------------------------------------------
loc_80502AC6: ; CODE XREF: KiInitializeUserApc(x,x,x,x,x,x)+AE↑j
; KiInitializeUserApc(x,x,x,x,x,x)+B7↑j
and ecx, 3E0DD7h
or ecx, 200h
mov eax, ecx
loc_80502AD4: ; CODE XREF: KiInitializeUserApc(x,x,x,x,x,x)+C6↑j
mov [ebx+70h], eax
mov eax, large fs:124h
mov [ebp+var_2FC], eax
cmp byte ptr [eax+30h], 0
jz short loc_80502AED ; 获取当前3环栈顶
or byte ptr [ebx+71h], 30h
loc_80502AED: ; CODE XREF: KiInitializeUserApc(x,x,x,x,x,x)+E9↑j
mov eax, [ebp+var_2EC] ; 获取当前3环栈顶
mov [ebx+74h], eax ; 修改TrapFrame中的ESP
mov ecx, _KeUserApcDispatcher ; 获取KiUserApcDispatcher函数地址
mov [ebx+68h], ecx ; 将函数地址赋给TrapFrame中的EIP
and dword ptr [ebx+64h], 0 ; ErrorCode置0
mov ecx, [ebp+arg_8] ; 获取NormalRoutine
mov [eax], ecx ; 将NormalRoutine赋值到栈顶地址
push 4
pop ecx
add eax, ecx
mov [ebp+var_2EC], eax
mov edx, [ebp+arg_C] ; 获取NormalContext
mov [eax], edx ; 放入栈顶下的地址
add eax, ecx
mov [ebp+var_2EC], eax
mov edx, [ebp+arg_10] ; 获取Arg1, Arg2
mov [eax], edx
add eax, ecx
mov [ebp+var_2EC], eax
mov edx, [ebp+arg_14]
mov [eax], edx
add eax, ecx
mov [ebp+var_2EC], eax
jmp short loc_80502B77
; ---------------------------------------------------------------------------
loc_80502B3C: ; DATA XREF: .text:stru_804DA0B0↑o
; __except filter // owned by 80502A49
mov eax, [ebp+ms_exc.exc_ptr]
push dword ptr [eax]
lea eax, [ebp+ExceptionRecord]
push eax
call _KiCopyInformation@8 ; KiCopyInformation(x,x)
retn
; ---------------------------------------------------------------------------
loc_80502B4E: ; DATA XREF: .text:stru_804DA0B0↑o
; __except(loc_80502B3C) // owned by 80502A49
mov esp, [ebp+ms_exc.old_esp]
mov eax, [ebp+BugCheckParameter3]
mov ecx, [eax+68h]
mov [ebp+ExceptionRecord.ExceptionAddress], ecx
push 1 ; char
push 1 ; int
push eax ; BugCheckParameter3
push [ebp+var_2F4] ; int
lea eax, [ebp+ExceptionRecord]
push eax ; ExceptionRecord
call _KiDispatchException@20 ; KiDispatchException(x,x,x,x,x)
; } // starts at 80502A49
loc_80502B77: ; CODE XREF: KiInitializeUserApc(x,x,x,x,x,x)+13C↑j
or [ebp+ms_exc.registration.TryLevel], 0FFFFFFFFh
loc_80502B7B: ; CODE XREF: KiInitializeUserApc(x,x,x,x,x,x)+2D↑j
mov ecx, [ebp+var_1C]
call @xHalReferenceHandler@4 ; xHalReferenceHandler(x)
call __SEH_epilog
retn 18h
; } // starts at 805029FE
_KiInitializeUserApc@24 endp
KiUserApcDispatcher
函数定义:
VOID KiUserApcDispatcher
(
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN PKNORMAL_ROUTINE NormalRoutine
);
代码分析:
_KiUserApcDispatcher@20 proc near
arg_C= byte ptr 10h
lea edi, [esp+arg_C] ; 获取ContextFrame
pop eax ; 获取NormalContext
call eax ; 调用用户层APC函数
push 1
push edi ; 压入ContextFrame
call _ZwContinue@8 ; 返回0环
nop
_KiUserApcDispatcher@20 endp