(47) reverse analysis KiSystemService function filling


1, Review


In the previous course, we learned what API system calls do in the 3-ring part. There are two ways to enter the 0-ring: interrupt gate and quick call. We call two different functions KiSystemService and KiFastCallEntry respectively. In this article, we will reverse analyze the KiSystemService function filling_ KTRAP_ Disassembly code of frame part.


Before analyzing, consider four questions:


  • After entering the 0 loop, where does the original register exist?

  • How to find the kernel function to be executed according to the system call number (stored in eax)?

  • When calling, the parameter is stored in the stack of 3 rings. How to pass it to the kernel function?

  • How do the two call methods return to the third ring?


To analyze KiSystemService and KiFastCallEntry, we need to understand several structures first_ Trap_Frame,_ ETHREAD,_ KTHREAD,_ KPCR,_ NT_TIB and_ KPRCB.


Next, the structures involved are introduced in turn according to the code execution order of KiSystemService.




First, review the TSS table. There is only one TSS table, but there are hundreds of threads in the system. When the thread enters ring 0, suppose to use the interrupt gate, and the ESP and SS of ring 0 are obtained from the TSS table. How to ensure that each thread has its own stack and does not conflict with each other? The answer is that the TSS table will be modified during thread switching to ensure that the ESP and SS in the TSS correspond to the current thread when each thread executes.


_ Trap_Frame is closely related to 0 ring stack. When the user-defined interrupt enters the 0 ring and involves the lifting of rights, the CPU will push the values of five registers into the 0 ring stack, which we learned in the course of interrupt gate:


The above figure is incomplete.


In fact, the stack of the complete ring 0 is long. After the interrupt gate enters the ring 0, the new ESP points to the offset 0x068 (Eip):





+0x000 DbgEbp           : Uint4B
+0x004 DbgEip           : Uint4B
+0x008 DbgArgMark       : Uint4B
+0x00c DbgArgPointer    : Uint4B
+0x010 TempSegCs        : Uint4B
+0x014 TempEsp          : Uint4B
+0x018 Dr0              : Uint4B
+0x01c Dr1              : Uint4B
+0x020 Dr2              : Uint4B
+0x024 Dr3              : Uint4B
+0x028 Dr6              : Uint4B
+0x02c Dr7              : Uint4B
+0x030 SegGs            : Uint4B
+0x034 SegEs            : Uint4B
+0x038 SegDs            : Uint4B
+0x03c Edx              : Uint4B
+0x040 Ecx              : Uint4B
+0x044 Eax              : Uint4B
+0x048 PreviousPreviousMode : Uint4B
+0x04c ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs            : Uint4B
+0x054 Edi              : Uint4B
+0x058 Esi              : Uint4B
+0x05c Ebx              : Uint4B
+0x060 Ebp              : Uint4B
+0x064 ErrCode          : Uint4B
+0x068 Eip              : Uint4B
+0x06c SegCs            : Uint4B
+0x070 EFlags           : Uint4B
+0x074 HardwareEsp      : Uint4B
+0x078 HardwareSegSs    : Uint4B
+0x07c V86Es            : Uint4B
+0x080 V86Ds            : Uint4B
+0x084 V86Fs            : Uint4B
+0x088 V86Gs            : Uint4B


It can't be called the stack length of 0 ring. Like this_ Trap_ The frame structure is actually the use convention of windows for the kernel stack. It stipulates what data different offsets are used to store.


When we reverse the KiSystemService later, we will find that the first instruction is push 0, which means setting ErrCode = 0.


First question: after entering the 0 ring, where does the original register exist?


Seeing this structure, I believe you have the answer. We can verify the conjecture through reverse KiSystemService.




These three structures store the information of the current CPU. In fact, these three structures are one structure, but they are abstracted into three parts. The fixed address is 0xffdff000.


KPCR (Processor Control Region) means CPU control area. Each CPU has a KPCR structure.


   +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


It mainly stores SEH structured exception linked list and a pointer to itself.


   +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




   +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




These two are actually the same structure, just introduced_ Used in KPRCB + 0x04_ KTHREAD. These two structures store thread related information.




   +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




   +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


5, Reverse analysis KiSystemService


After learning the above five structures, we can understand how to initialize the KiSystemService function_ Trap_Frame.


.text:00466481 ; =============== S U B R O U T I N E =======================================
.text:00466481 _KiSystemService proc near              ; CODE XREF: ZwAcceptConnectPort(x,x,x,x,x,x)+Cp
.text:00466481                                         ; ZwAccessCheck(x,x,x,x,x,x,x,x)+Cp ...
.text:00466481 var_104         = dword ptr -104h
.text:00466481 var_100         = dword ptr -100h
.text:00466481 var_D0          = dword ptr -0D0h
.text:00466481 var_CC          = dword ptr -0CCh
.text:00466481 var_C8          = dword ptr -0C8h
.text:00466481 var_B0          = dword ptr -0B0h
.text:00466481 var_AC          = dword ptr -0ACh
.text:00466481 var_A8          = dword ptr -0A8h
.text:00466481 var_A3          = byte ptr -0A3h
.text:00466481 var_73          = byte ptr -73h
.text:00466481 arg_0           = dword ptr  4
.text:00466481 arg_64          = dword ptr  68h
.text:00466481 arg_69          = byte ptr  6Dh
.text:00466481                 push    0               ; The error code is initialized to 0
.text:00466483                 push    ebp             ; Save the value of the 3-ring register
.text:00466484                 push    ebx
.text:00466485                 push    esi
.text:00466486                 push    edi
.text:00466487                 push    fs
.text:00466489                 mov     ebx, 30h
.text:0046648E                 mov     fs, bx          ; set up fs The selected child is 0 x30
.text:0046648E                                         ; check GDT Table get ffc093df`f0000001
.text:0046648E                                         ; fs.base = ffdff000,Point to current CPU of KPCR structure
.text:00466491                 assume fs:nothing
.text:00466491                 push    dword ptr ds:0FFDFF000h ; Save old ExceptionList,Then clear the new into-1
.text:00466497                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh
.text:004664A1                 mov     esi, ds:0FFDFF124h ; esi point CurrentThread
.text:004664A7                 push    dword ptr [esi+140h] ; preservation CurrentThread.PreviousMode
.text:004664A7                                         ; PreviousMode = 0 Indicates that it is called from the 0 ring
.text:004664A7                                         ; PreviousMode != 0 It means calling from the 3rd ring
.text:004664AD                 sub     esp, 48h        ; esp point _KTRAP_FRAME
.text:004664B0                 mov     ebx, [esp+68h+arg_0]
.text:004664B4                 and     ebx, 1
.text:004664B7                 mov     [esi+140h], bl  ; used CS The results of and 1 are stored PreviousMode
.text:004664BD                 mov     ebp, esp        ; ebp point _KTRAP_FRAME
.text:004664BF                 mov     ebx, [esi+134h]
.text:004664C5                 mov     [ebp+3Ch], ebx  ; _KTRAP_FRAME.Edx Point to the old CurrentThread.TrapFrame
.text:004664C8                 mov     [esi+134h], ebp ; CurrentThread.TrapFrame Point to current _KTRAP_FRAME
.text:004664CE                 cld                     ; df = 0
.text:004664CF                 mov     ebx, [ebp+60h]  ; 3 ring ebp
.text:004664D2                 mov     edi, [ebp+68h]  ; 3 ring eip
.text:004664D5                 mov     [ebp+0Ch], edx  ; _KTRAP_FRAME.DbgArgPointer = edx
.text:004664D5                                         ; This step is to save 3 rings API Parameter pointer
.text:004664D8                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:004664DF                 mov     [ebp+0], ebx    ; _KTRAP_FRAME.DbgEbp = _KTRAP_FRAME.Ebp
.text:004664E2                 mov     [ebp+4], edi    ; _KTRAP_FRAME.DbgEip = _KTRAP_FRAME.Eip
.text:004664E5                 test    byte ptr [esi+2Ch], 0FFh
.text:004664E9                 jnz     Dr_kss_a        ; test CurrentThread.DebugActive
.text:004664E9                                         ; If you are debugging, save the debugging related registers to _KTRAP_FRAME
.text:004664EF loc_4664EF:                             ; CODE XREF: Dr_kss_a+10j
.text:004664EF                                         ; Dr_kss_a+7Cj
.text:004664EF                 sti                     ; Allow interrupt
.text:004664F0                 jmp     loc_4665CD


6, Summary


We have solved the first and fourth problems.


  • After entering the 0 loop, where does the original register exist?

  • How to find the kernel function to be executed according to the system call number (stored in eax)?

  • When calling, the parameter is stored in the stack of 3 rings. How to pass it to the kernel function?

  • How do the two call methods return to the third ring?


The original register is stored in_ Trap_ In the frame structure, the API parameter pointer of ring 3 is passed to ring 0 through EDX.

Author: hambaga
Source: CSDN
Original text: https://blog.csdn.net/Kwansy/article/details/109426688
Copyright notice: This article is the author's original article. Please attach the blog link for reprint!
Content resolution By: CSDN,CNBLOG blog article one click reprint plug-in

Posted by jeff21 on Sat, 07 May 2022 02:07:24 +0300