32位和64位系統內核函數調用從ZwProtectVirtualMemory到NtProtectVirtualMemory


0x01 前言

  我們知道R3層中,Zw系列函數和Nt系列函數函數是一樣的,但是在內核Zw系列函數調用了Nt系列函數,但是為什么要在內核設置一個Zw系列函數而不是直接調用Nt函數呢?Zw系列函數又是怎么調用Nt系列函數的呢?我們利用IDA分析NtosKrnl.exe文件。

 

0x02 ZwProtectVirtualMemory

  我們先看看ZwProtectVirtualMemory的實現

.text:00406170 ; NTSTATUS __stdcall ZwProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG ProtectSize, ULONG NewProtect, PULONG OldProtect)
.text:00406170 _ZwProtectVirtualMemory@20 proc near    ; CODE XREF: RtlpCreateStack(x,x,x,x,x)+FAp
.text:00406170
.text:00406170 ProcessHandle   = dword ptr  4
.text:00406170 BaseAddress     = dword ptr  8
.text:00406170 ProtectSize     = dword ptr  0Ch
.text:00406170 NewProtect      = dword ptr  10h
.text:00406170 OldProtect      = dword ptr  14h
.text:00406170
.text:00406170                 mov     eax, 89h  ;Nt函數的系統調用號
.text:00406175                 lea     edx, [esp+ProcessHandle] ;使用EDX指向堆棧上的參數塊
.text:00406179                 pushf        ;EFLAGS
.text:0040617A                 push    8    ;CS   KGDT_R0_CODE
.text:0040617C                 call    _KiSystemService
.text:00406181                 retn    14h    ;5個參數,20字節
.text:00406181 _ZwProtectVirtualMemory@20 endp

  這里89h為NtProtectVirtualMemory函數在SSDT函數中的調用號,CS寄存器,最后位為0表示當前處於內核態,然后調用KiSystemService函數

 

0x03 KiSystemService

  我們接着看KiSystemService的函數實現

.text:00407631 _KiSystemService proc near              ; CODE XREF: ZwAcceptConnectPort(x,x,x,x,x,x)+Cp
.text:00407631                                         ; ZwAccessCheck(x,x,x,x,x,x,x,x)+Cp ...
.text:00407631
.text:00407631 arg_0           = dword ptr  4
.text:00407631
.text:00407631                 push    0
.text:00407633                 push    ebp
.text:00407634                 push    ebx
.text:00407635                 push    esi
.text:00407636                 push    edi
.text:00407637                 push    fs              ; 保存用戶空間的fs
.text:00407639                 mov     ebx, 30h        ; KGDT_R0_PCR
.text:0040763E                 mov     fs, ebx         ; 使FS段的起點與KPCR數據結構對齊
.text:00407640                 push    dword ptr ds:0FFDFF000h
.text:00407646                 mov     dword ptr ds:0FFDFF000h, 0FFFFFFFFh
.text:00407650                 mov     esi, ds:0FFDFF124h ; #define KPCR_CURRENT_THREAD 0x124
.text:00407650                                         ; 指向當前cpu正在運行的線程
.text:00407650                                         ; FS:0x124
.text:00407650                                         ; PCR的大小只有0x54,這里偏移到了KPRCB中的CurrentThread
.text:00407656                 push    dword ptr [esi+140h]
.text:0040765C                 sub     esp, 48h
.text:0040765F                 mov     ebx, [esp+68h+arg_0] ; 系統調用前夕的CS映像
.text:00407663                 and     ebx, 1          ; 0環的最低位為0,3環的最低位為1
.text:00407666                 mov     [esi+140h], bl  ; 新的"先前模式"  [esi+KTHREAD_PREVIOUS_MODE]
.text:0040766C                 mov     ebp, esp
.text:0040766E                 mov     ebx, [esi+134h] ; KTHREAD結構中的指針TrapFrame [esi+KTHREAD_TRAP_FRAME]
.text:00407674                 mov     [ebp+3Ch], ebx  ; 暫時保存在這里 [ebp+KTRAP_FRAME_EDX]
.text:00407677                 mov     [esi+134h], ebp ; 新的TrapFrame,指向堆棧上的框架 [esi+KTHREAD_TRAP_FRAME]
...
.text:0040769E                 sti
.text:0040769F                 jmp     loc_407781
.text:0040769F _KiSystemService endp

 

  這里首先要在系統態堆棧上構建一個系統調用"框架Frame",或稱為"自陷框架",其作用主要是用來保存發生自陷時CPU中各寄存器的"現場",或者說"上下文",以備返回用戶空間時予以恢復。
  Windows內核有個特殊的基本要求,只要CPU在內核運行,FS寄存器就指向一個KPCR的數據結構,FS的值為0x30,其0-1位為0,表示0環,第2位為0,表示GDT表,為1則表示LDT表,3-15位為6,表示在GDT的下標為6的表項中的地址即為KPCR的地址。KPCR是處理器控制塊,在單處理器中只有一個KPCR,在多CPU的系統中,每個CPU都有自己的KPCR結構。
  CPU從用戶空間進入系統空間時會將當時寄存器CS的內容壓入系統態堆棧,CS的最低位就可以說明當時運行於何種模式的標志位。這里取出CS最低位保存在ETHREAD的PREVIOUS_MODE上。
  更新ETHREAD中的TrapFrame框架,保存舊的框架。

 

0x04 KiFastCallEntry

  KiSystemService中的jmp loc_407781跳轉到KiFastCallEntry函數中,代碼如下:

.text:004076F0 _KiFastCallEntry proc near              ; DATA XREF: _KiTrap01+6Fo
.text:004076F0                                         ; KiLoadFastSyscallMachineSpecificRegisters(x)+24o
.text:004076F0
.text:004076F0 var_B           = byte ptr -0Bh
.text:004076F0
.text:004076F0 ; FUNCTION CHUNK AT .text:004076C8 SIZE 00000023 BYTES
.text:004076F0 ; FUNCTION CHUNK AT .text:00407990 SIZE 00000014 BYTES
.text:004076F0
.text:004076F0                 mov     ecx, 23h        ;  KGDT_R3_DATA OR RPL_MASK
.text:004076F5                 push    30h
.text:004076F7                 pop     fs              ; 只要進入內核..fs->KPCR(Kernel's Processor Control Region,內核進程控制區域)
.text:004076F9                 mov     ds, ecx         ; 使用23h選擇子
.text:004076FB                 mov     es, ecx
.text:004076FD                 mov     ecx, ds:0FFDFF040h ; _KPCR->_KTSS
.text:00407703                 mov     esp, [ecx+4]    ; 取出_KTSS->esp0
.text:00407703                                         ; 這里是模擬自陷框架,以形成和中斷, 異常統一的框架 _KTRAP_FRAME
.text:00407706                 push    23h             ; KGDT_R3_DATA OR RPL_MASK
.text:00407708                 push    edx             ; R3 ss:esp
.text:00407709                 pushf                   ; R3 Eflags
.text:0040770A
.text:0040770A loc_40770A:                             ; CODE XREF: _KiFastCallEntry2+22j
.text:0040770A                 push    2
.text:0040770C                 add     edx, 8          ; edx -> args 用戶態參數
.text:0040770F                 popf                    ; Eflags = 2 中斷已關閉
.text:00407710                 or      [esp+0Ch+var_B], 2 ; 開啟R3 Eflags的中斷標記
.text:00407715                 push    1Bh             ; R3 cs:eip
.text:00407717                 push    dword ptr ds:0FFDF0304h ; ntdll!KiFastSystemCallRet
.text:0040771D                 push    0               ; 為了和中斷保持一致, 中斷會有錯誤碼, 同時用於返回值
.text:0040771F                 push    ebp
.text:00407720                 push    ebx
.text:00407721                 push    esi
.text:00407722                 push    edi
.text:00407723                 mov     ebx, ds:0FFDFF01Ch ; ebx<-_KPCR.SelfPcr 這是pcr的指針
.text:00407729                 push    3Bh
.text:0040772B                 mov     esi, [ebx+124h] ; esi=_KPCR.PrcbData.CurrentThread _KTHREAD
.text:00407731                 push    dword ptr [ebx] ; 異常鏈表
.text:00407733                 mov     dword ptr [ebx], 0FFFFFFFFh ; 初始化鏈表
.text:00407739                 mov     ebp, [esi+18h]  ; 獲取線程堆棧
.text:0040773C                 push    1               ; MODE_MASK = User Mode
.text:0040773E                 sub     esp, 48h        ; 分配剩余 _KTRAP_FRAME 框架
.text:00407741                 sub     ebp, 29Ch       ; (_FX_SAVE_AREA)NPX_FRAME_LENGTH=210h, (_KTRAP_FRAME)KTRAP_FRAME_LENGTH=8C
.text:00407747                 mov     byte ptr [esi+140h], 1 ; MODE_MASK = 1 設置線程模式
.text:00407747                                         ; 現在_KTRAP_FRAME已經建立完成
.text:00407747                                         ; 057
.text:00407747                                         ; 計算初始堆棧線程的初始堆棧指針,包含NPX和_KTRAP_FRAME
.text:00407747                                         ; 058
.text:00407747                                         ; 如果 ebp 和 esp 不相等, 那么這是一個V86模式的線程. 拒絕調用.
.text:0040774E                 cmp     ebp, esp
.text:00407750                 jnz     loc_4076C8      ; 處理V86模式的代碼不看了.
.text:00407756                 and     dword ptr [ebp+2Ch], 0 ; 清空 Dr7 調試寄存器
.text:0040775A                 test    byte ptr [esi+2Ch], 0FFh ; 線程是否被調試狀態
.text:0040775E                 mov     [esi+134h], ebp ; ebp = _KTRAP_FRAME 保存新的 TrapFrame
.text:00407764                 jnz     Dr_FastCallDrSave ; 如果線程被調試, 那么還要做些處理, 這里先不管.
.text:0040776A
.text:0040776A loc_40776A:                             ; CODE XREF: Dr_FastCallDrSave+10j
.text:0040776A                                         ; Dr_FastCallDrSave+7Cj
.text:0040776A                 mov     ebx, [ebp+60h]  ; ebx = _KTRAP_FRAME->Ebp
.text:0040776D                 mov     edi, [ebp+68h]  ; edi = _KTRAP_FRAME->Eip
.text:00407770                 mov     [ebp+0Ch], edx  ; edx = 參數指針
.text:00407773                 mov     dword ptr [ebp+8], 0BADB0D00h
.text:0040777A                 mov     [ebp+0], ebx    ; _KTRAP_FRAME.DbgEbp = _KTRAP_FRAME->Ebp
.text:0040777D                 mov     [ebp+4], edi    ; _KTRAP_FRAME.DbgEip = _KTRAP_FRAME->Eip
.text:00407780                 sti
.text:00407781
.text:00407781 loc_407781:                             ; CODE XREF: _KiBBTUnexpectedRange+18j
.text:00407781                                         ; _KiSystemService+6Ej
.text:00407781                 mov     edi, eax        ; 系統調用號
.text:00407783                 shr     edi, 8          ; NtProtectVirtualMemory 89h = 10001001
.text:00407783                                         ; shr右移8位為0
.text:00407783                                         ; Shadow SSDT函數索引都在0x1000以上
.text:00407786                 and     edi, 30h
.text:00407789                 mov     ecx, edi        ; 如果是shadow ecx = 10h,否則ecx =0h (bit11 bit12)
.text:0040778B                 add     edi, [esi+0E0h] ; 確定是哪個表
.text:0040778B                                         ; 本線程的系統調用表
.text:0040778B                                         ; EDI指向描述塊0或描述塊1
.text:00407791                 mov     ebx, eax        ; 將eax中的索引值,賦值給ebx
.text:00407793                 and     eax, 0FFFh      ; SERVICE_NUMBER_MASK定義為0xFFF
.text:00407798                 cmp     eax, [edi+8]    ; 檢查系統調用號是否越界
.text:00407798                                         ; SERVICE_DESCRIPTOR_LIMIT定義為8
.text:0040779B                 jnb     _KiBBTUnexpectedRange ; 系統調用號越界,超過SSDT表中的Number

 

  我們這里是直接跳轉到loc_407781的地方,再此之前的代碼是通過用戶層調用Native API的時候進行的處理。

  這里eax保存着系統調用號,在KTHREAD中有一個指針ServiceTable,如果是gui線程則指向KeServiceDescriptorTableShadow[],如果不是則指向KeServiceDescriptor[]。這里檢查了系統調用號是否越界。多數情況下不會越界,我們繼續往下看:

.text:004077A1                 cmp     ecx, 10h        ; 測試是否調用 Shadow Ssdt
.text:004077A4                 jnz     short NotWin32K ; 不跳則是shadow
.text:004077A6                 mov     ecx, ds:0FFDFF018h ;  ecx = _KPCR->_NT_TIB->Self 指向 _TEB
.text:004077AC                 xor     ebx, ebx
.text:004077AE
.text:004077AE loc_4077AE:                             ; DATA XREF: _KiTrap0E+110o
.text:004077AE                 or      ebx, [ecx+0F70h] ; _TEB.GdiBatchCount
.text:004077B4                 jz      short NotWin32K
.text:004077B6                 push    edx             ; edx = argc
.text:004077B7                 push    eax             ; eax = Index
.text:004077B8                 call    ds:_KeGdiFlushUserBatch
.text:004077BE                 pop     eax             ; eax = Index
.text:004077BF                 pop     edx             ; edx  = argc
.text:004077C0
.text:004077C0 NotWin32K:                              ; CODE XREF: _KiFastCallEntry+B4j
.text:004077C0                                         ; _KiFastCallEntry+C4j
.text:004077C0                 inc     dword ptr ds:0FFDFF638h ; _KPRCB->KeSystemCalls++, 記錄系統調用次數
.text:004077C6                 mov     esi, edx        ; 使ESI指向用戶空間堆棧上的參數塊
.text:004077C8                 mov     ebx, [edi+0Ch]  ; ebx = ssdt->ParamTableBase
.text:004077C8                                         ; [edi+SERVICE_DESCRIPTOR_NUMBER]
.text:004077CB                 xor     ecx, ecx
.text:004077CD                 mov     cl, [eax+ebx]   ; 寄存器ECX  cl = 參數總共占得字節大小
.text:004077D0                 mov     edi, [edi]      ; edi=ssdt->ServiceTableBase
.text:004077D0                                         ; EDI指向具體的系統調用表
.text:004077D0                                         ; [edi+SERVICE_DESCRIPTOR_BASE]
.text:004077D2                 mov     ebx, [edi+eax*4] ; 函數指針
.text:004077D5                 sub     esp, ecx        ; 系統堆棧上留出空間
.text:004077D7                 shr     ecx, 2          ; 除4,參數個數
.text:004077DA                 mov     edi, esp        ; edi = 內核棧的參數位置
.text:004077DC                 cmp     esi, ds:_MmUserProbeAddress ; 參數塊的位置不得高於MmSystemRangeStart-0x10000
.text:004077E2                 jnb     AccessViolation
.text:004077E8
.text:004077E8 loc_4077E8:                             ; CODE XREF: _KiFastCallEntry+2A4j
.text:004077E8                                         ; DATA XREF: _KiTrap0E+106o
.text:004077E8                 rep movsd               ; 復制參數,以ESI為源,EDI為目標,ECX為循環次數
.text:004077E8                                         ; ecx是參數個數,從用戶棧復制參數到內核棧,原來SSDT所有參數都是4個字節為單位的.
.text:004077EA                 call    ebx             ; 調用目標函數

 

  這里將ECX與0x10比較,如果不是0x10則為基本調用表(SSDT函數),轉到NotWin32K處。這里ecx的cl保存着KSERVICE_TABLE_DESCRIPTOR結構體中的Number,將cl右移2位就是參數的個數,后面重復執行的movsd的次數就是參數的個數,不過復制之前要調整堆棧指針,將ESP與移位前的ECX相減,在系統空間堆棧上 空出相應的字節數。注意movsd指令以ESI所指處為源,以EDI所指處為目標,另一方面,指令獲得函數的指針賦值為ebx,最后call ebx實現了對目標函數的調用。
  一些安全軟件對KiFastCallEntry通過Hook實現過濾SSDT框架的時候,通常是在ebx完成賦值之后,在call ebx之前,替換這中間的地方,進入fake1函數,將保存好的參數push,比如edi保存的SSDT表地址,ebx保存函數地址,eax保存調用號,ecx保存參數個數,在這中間hook,可以直接利用系統初始化好的寄存器,然后調用filter函數,通過寄存器的值,過濾指定的SSDT函數,替換ebx的值,然后繼續執行KiFastCallEntry中的call ebx,這樣就可以過濾整個SSDT系統調用了。

  當執行完成call ebx,從目標函數返回時我們繼續看下面的指令:

.text:004077EC
.text:004077EC loc_4077EC:                             ; CODE XREF: _KiFastCallEntry+2AFj
.text:004077EC                                         ; DATA XREF: _KiTrap0E+126o ...
.text:004077EC                 mov     esp, ebp        ; 恢復棧頂,此時棧頂是KTRAP_FRAME
.text:004077EE
.text:004077EE KeReturnFromSystemCall:                 ; CODE XREF: _KiBBTUnexpectedRange+38j
.text:004077EE                                         ; _KiBBTUnexpectedRange+43j
.text:004077EE                 mov     ecx, ds:0FFDFF124h ; ecx = _KTHREAD
.text:004077F4                 mov     edx, [ebp+3Ch]  ; edx = KTRAP_FRAME->Edx
.text:004077F4                                         ; 從堆棧中取出保存着的框架指針
.text:004077F4                                         ; [ebp+KTRAP_FRAME_EDX]
.text:004077F7                 mov     [ecx+134h], edx ; KThread->TrapFrame = KTRAP_FRAME->Edx 恢復ring3 陷阱幀.
.text:004077F7 _KiFastCallEntry endp ; sp-analysis failed

  首先將堆棧指針恢復指向系統調用框架即自陷框架的底部,因為這些參數已經失去意義,然后把原先保存在堆棧上的先前自陷框架指針恢復到當前線程的控制塊中。

 

0x05 KiServiceExit

  然后繼續執行KiServiceExit函數

.text:004077FD _KiServiceExit  proc near               ; CODE XREF: _KiSetLowWaitHighThread+7Cj
.text:004077FD                                         ; NtContinue(x,x)+42j ...
.text:004077FD
.text:004077FD arg_C           = dword ptr  10h
.text:004077FD arg_10          = dword ptr  14h
.text:004077FD arg_40          = dword ptr  44h
.text:004077FD arg_44          = dword ptr  48h
.text:004077FD arg_48          = dword ptr  4Ch
.text:004077FD arg_60          = dword ptr  64h
.text:004077FD arg_64          = dword ptr  68h
.text:004077FD arg_68          = dword ptr  6Ch
.text:004077FD arg_6C          = dword ptr  70h
.text:004077FD
.text:004077FD ; FUNCTION CHUNK AT .text:00407908 SIZE 00000088 BYTES
.text:004077FD
.text:004077FD                 cli                     ; 關中斷
.text:004077FE                 test    dword ptr [ebp+70h], 20000h ;  _KTRAP_FRAME->EFlags is this a V86 frame
.text:00407805                 jnz     short CHECK_FOR_APC_DELIVER ;  跳則不是V86
.text:00407807                 test    byte ptr [ebp+6Ch], 1 ; KTRAP_FRAME->SegCs 測試CS是否是R3選擇子
.text:0040780B                 jz      short loc_407864 ; 如果CPL非0則跳.
.text:0040780D
.text:0040780D CHECK_FOR_APC_DELIVER:                  ; CODE XREF: _KiServiceExit+8j
.text:0040780D                                         ; _KiServiceExit+63j
.text:0040780D                 mov     ebx, ds:0FFDFF124h ; ebx->_KTHREAD
.text:00407813                 mov     byte ptr [ebx+2Eh], 0 ;  清除線程警覺位. APC有關.
.text:00407817                 cmp     byte ptr [ebx+4Ah], 0 ; 這里判斷是否有APC掛起
.text:0040781B                 jz      short loc_407864 ; 沒有APC掛起
.text:0040781B                                         ; 如果先前模式是內核模式,就往前跳轉到下面,不遞交APC請求
.text:0040781D                 mov     ebx, ebp
.text:0040781F                 mov     [ebx+44h], eax  ;  保存調用例程的返回值
.text:00407822                 mov     dword ptr [ebx+50h], 3Bh
.text:00407829                 mov     dword ptr [ebx+38h], 23h
.text:00407830                 mov     dword ptr [ebx+34h], 23h
.text:00407837                 mov     dword ptr [ebx+30h], 0
.text:0040783E                 mov     ecx, 1          ;  APC_LEVEL 將當前線程IRQL調整到APC_LEVEL
.text:00407843                 call    ds:__imp_@KfRaiseIrql@4 ; 這是快速調用模式的函數,通過寄存器傳遞參數
.text:00407849                 push    eax             ; 保存舊的IRQL.
.text:0040784A                 sti                     ;  開中斷以后, 有可能帶來線程切換
.text:0040784B                 push    ebx             ; _KTRAP_FRAME
.text:0040784C                 push    0               ; Null exception frame
.text:0040784E                 push    1               ; Previous mode = User Mode
.text:00407850                 call    _KiDeliverApc@12 ; 執行內核APC,並未用戶空間APC的執行進行准備
.text:00407855                 pop     ecx             ; 從堆棧恢復老的運行級別
.text:00407856                 call    ds:__imp_@KfLowerIrql@4 ; 恢復原來的運行級別,在這里應該是PASSIVE_LEVEL
.text:0040785C                 mov     eax, [ebx+44h]  ;  重新讀出Eax
.text:0040785F                 cli
.text:00407860                 jmp     short CHECK_FOR_APC_DELIVER ; 這是一個循環, 循環的處理APC
.text:00407860 ; ---------------------------------------------------------------------------
.text:00407862                 align 4
.text:00407864
.text:00407864 loc_407864:                             ; CODE XREF: _KiServiceExit+Ej
.text:00407864                                         ; _KiServiceExit+1Ej
.text:00407864                 mov     edx, [esp+arg_48] ; ExceptionList   arg_48 = 0x4C
.text:00407868                 mov     ebx, large fs:50h
.text:0040786F                 mov     large fs:0, edx ;  還原線程seh
.text:00407876                 mov     ecx, [esp+arg_44]
.text:0040787A                 mov     esi, large fs:124h ;  esi-->_KTHREAD
.text:00407881                 mov     [esi+140h], cl  ;  _KTHREAD.PreviousMode = _KTRAP_FRAME.PreviousPreviousMode
.text:00407887                 test    ebx, 0FFh       ; 當前線程是否在調試
.text:0040788D                 jnz     short loc_407908 ; 是被調試, 則跳走
.text:0040788F
.text:0040788F loc_40788F:                             ; CODE XREF: _KiServiceExit+11Bj
.text:0040788F                                         ; _KiServiceExit+14Aj
.text:0040788F                 test    [esp+arg_6C], 20000h ; 判斷當前是否是V86模式.
.text:0040788F                                         ; arg_6c = 0x70
.text:00407897                 jnz     loc_408188      ; 是, 則跳走
.text:0040789D                 test    word ptr [esp+arg_68], 0FFF8h ; FRAME_EDITED
.text:004078A4                 jz      loc_40795E
.text:004078AA                 cmp     word ptr [esp+arg_68], 1Bh ;  set/clear ZF
.text:004078B0                 bt      word ptr [esp+arg_68], 0 ; test MODE_MASK      set/clear CF
.text:004078B7                 cmc
.text:004078B8                 ja      loc_40794C      ; jmp if CF=0 and ZF=0
.text:004078BE                 cmp     word ptr [ebp+6Ch], 8 ; _KTRAP_FRAME.Cs 選擇子的合法性
.text:004078C3                 jz      short loc_4078CA ; 如果CS是內核模式, 那么我們直接就可以跳到恢復通用寄存器的地方
.text:004078C5
.text:004078C5 loc_4078C5:                             ; CODE XREF: _KiServiceExit+15Cj
.text:004078C5                 lea     esp, [ebp+50h]  ;  恢復FS
.text:004078C8                 pop     fs
.text:004078CA                 assume fs:nothing
.text:004078CA
.text:004078CA loc_4078CA:                             ; CODE XREF: _KiServiceExit+C6j
.text:004078CA                 lea     esp, [ebp+54h]  ; 獲取edi的值
.text:004078CD                 pop     edi
.text:004078CE                 pop     esi
.text:004078CF                 pop     ebx
.text:004078D0                 pop     ebp
.text:004078D1                 cmp     word ptr [esp-60h+arg_64], 80h
.text:004078D8                 ja      loc_4081A4
.text:004078DE                 add     esp, 4
.text:004078E1                 test    [esp-64h+arg_64], 1 ; 是從用戶空間發起的調用
.text:004078E1 _KiServiceExit  endp ; sp-analysis failed
.text:004078E1
.text:004078E9
.text:004078E9 ; =============== S U B R O U T I N E =======================================
.text:004078E9
.text:004078E9
.text:004078E9 _KiSystemCallExitBranch proc near       ; DATA XREF: KiEnableFastSyscallReturn():loc_439CBBr
.text:004078E9                                         ; KiEnableFastSyscallReturn()+26w ...
.text:004078E9                 jnz     short _KiSystemCallExit ; 測試是否是從內核種發起的調用
.text:004078EB                 pop     edx
.text:004078EC                 pop     ecx
.text:004078ED                 popf
.text:004078EE                 jmp     edx             ; 從內核中發起的調用, 在這里返回
.text:004078F0 ; ---------------------------------------------------------------------------
.text:004078F0
.text:004078F0 _KiSystemCallExit:                      ; CODE XREF: _KiSystemCallExitBranchj
.text:004078F0                                         ; _KiSystemCallExit2+5j
.text:004078F0                                         ; DATA XREF: ...
.text:004078F0                 iret
.text:004078F0 _KiSystemCallExitBranch endp ; sp-analysis failed
.text:004078F0
.text:004078F1
.text:004078F1 ; =============== S U B R O U T I N E =======================================
.text:004078F1
.text:004078F1
.text:004078F1 _KiSystemCallExit2 proc near            ; DATA XREF: KiRestoreFastSyscallReturnState()+16o
.text:004078F1
.text:004078F1 arg_5           = byte ptr  9
.text:004078F1
.text:004078F1                 test    [esp+arg_5], 1
.text:004078F6                 jnz     short _KiSystemCallExit ;  不為0是則是通過自陷指令進入內核的
.text:004078F8                 pop     edx             ; New R3 EIP
.text:004078F9                 add     esp, 4          ;  Skip R3 DS
.text:004078FC                 and     [esp-8+arg_5], 0FDh ; NOT EFLAGS_INTERRUPT_MASK ; 關閉中斷標記位
.text:00407901                 popf                    ; 還原eflag
.text:00407902                 pop     ecx             ;  ecx = _KTRAP_FRAME.esp  r3 的棧頂
.text:00407903                 sti                     ; 開中斷
.text:00407904                 sysexit                 ; 退出內核模式.
.text:00407906                 iret
.text:00407906 _KiSystemCallExit2 endp ; sp-analysis failed

在KiServiceExit執行的時候,首先關閉中斷,然后檢查是否有APC請求,如果有就通過KiDeliverApc遞交APC請求(插入線程apc隊列)。

最后會通過TrapFrame返回r3或者返回內核調用Zw函數的地方。

 

0x06 NtProtectVirtualMemory

 我們再看看call ebx之后調用Nt函數的情況,NtProtectVirtualMemory代碼如下:

PAGE:0049ACB1 ; NTSTATUS __stdcall NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG ProtectSize, ULONG NewProtect, PULONG OldProtect)
PAGE:0049ACB1 _NtProtectVirtualMemory@20 proc near    ; DATA XREF: .text:0040B8CCo
PAGE:0049ACB1
PAGE:0049ACB1 var_54          = dword ptr -54h
PAGE:0049ACB1 Status          = dword ptr -3Ch
PAGE:0049ACB1 LastProtect     = dword ptr -38h
PAGE:0049ACB1 CurrentProcess  = dword ptr -34h
PAGE:0049ACB1 var_30          = dword ptr -30h
PAGE:0049ACB1 AccessMode      = byte ptr -2Ch
PAGE:0049ACB1 Attached        = dword ptr -28h
PAGE:0049ACB1 CapturedBase    = dword ptr -24h
PAGE:0049ACB1 CapturedRegionSize= dword ptr -20h
PAGE:0049ACB1 Object          = dword ptr -1Ch
PAGE:0049ACB1 ms_exc          = CPPEH_RECORD ptr -18h
PAGE:0049ACB1 ProcessHandle   = dword ptr  8
PAGE:0049ACB1 BaseAddress     = dword ptr  0Ch
PAGE:0049ACB1 ProtectSize     = dword ptr  10h
PAGE:0049ACB1 NewProtect      = dword ptr  14h
PAGE:0049ACB1 OldProtect      = dword ptr  18h
PAGE:0049ACB1
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:004B9A0D SIZE 00000024 BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:004E7866 SIZE 00000018 BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:0051C445 SIZE 00000023 BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:0051C46D SIZE 0000000E BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:0051C480 SIZE 00000044 BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:0051C4C9 SIZE 00000004 BYTES
PAGE:0049ACB1 ; FUNCTION CHUNK AT PAGE:0051C4D2 SIZE 00000008 BYTES
PAGE:0049ACB1
PAGE:0049ACB1                 push    44h
PAGE:0049ACB3                 push    offset stru_413468
PAGE:0049ACB8                 call    __SEH_prolog
PAGE:0049ACBD                 xor     ebx, ebx
PAGE:0049ACBF                 mov     [ebp+Attached], ebx
PAGE:0049ACC2                 mov     ecx, [ebp+NewProtect] ; NewProtect
PAGE:0049ACC5                 call    @MiMakeProtectionMask@4 ; ProtectionMask = MiMakeProtectionMask (NewProtect);
PAGE:0049ACCA                 cmp     eax, 0FFFFFFFFh ; MM_INVALID_PROTECTION
PAGE:0049ACCD                 jz      loc_51C445      ; STATUS_INVALID_PAGE_PROTECTION
PAGE:0049ACD3                 mov     eax, large fs:124h ; PsGetCurrentThread()
PAGE:0049ACD9                 mov     ecx, [eax+44h]  ; EHTREAD中的Process指針
PAGE:0049ACDC                 mov     [ebp+CurrentProcess], ecx ; PsGetCurrentProcessByThread (CurrentThread)
PAGE:0049ACDF                 mov     al, [eax+140h]  ; PreviousMode
PAGE:0049ACE5                 mov     [ebp+AccessMode], al
PAGE:0049ACE8                 test    al, al
PAGE:0049ACEA                 jz      loc_4E7866      ; PreviousMode = 0(jz為0 跳轉)
PAGE:0049ACEA                                         ; 用戶層調用則不跳轉
PAGE:0049ACF0                 mov     [ebp+ms_exc.registration.TryLevel], ebx
PAGE:0049ACF3                 mov     edi, [ebp+BaseAddress]
PAGE:0049ACF6                 mov     eax, _MmUserProbeAddress     ;ProbeForWritePointer (BaseAddress);
PAGE:0049ACFB                 cmp     edi, eax
PAGE:0049ACFD                 jnb     loc_51C44F
PAGE:0049AD03
PAGE:0049AD03 loc_49AD03:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817A0j
PAGE:0049AD03                 mov     eax, [edi]
PAGE:0049AD05                 mov     [edi], eax
PAGE:0049AD07                 mov     esi, [ebp+ProtectSize]
PAGE:0049AD0A                 mov     eax, _MmUserProbeAddress    ;ProbeForWriteUlong_ptr (RegionSize);
PAGE:0049AD0F                 cmp     esi, eax
PAGE:0049AD11                 jnb     loc_51C456
PAGE:0049AD17
PAGE:0049AD17 loc_49AD17:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817A7j
PAGE:0049AD17                 mov     eax, [esi]
PAGE:0049AD19                 mov     [esi], eax
PAGE:0049AD1B                 mov     ebx, [ebp+OldProtect]
PAGE:0049AD1E                 mov     eax, _MmUserProbeAddress        ;ProbeForWriteUlong (OldProtect);
PAGE:0049AD23                 cmp     ebx, eax
PAGE:0049AD25                 jnb     loc_51C45D
PAGE:0049AD2B
PAGE:0049AD2B loc_49AD2B:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817B2j
PAGE:0049AD2B                 mov     eax, [ebx]
PAGE:0049AD2D                 mov     [ebx], eax
PAGE:0049AD2F                 mov     ecx, [edi]
PAGE:0049AD31                 mov     [ebp+CapturedBase], ecx        ;CapturedBase = *BaseAddress;
PAGE:0049AD34                 mov     edx, [esi]
PAGE:0049AD36                 mov     [ebp+CapturedRegionSize], edx        ;CapturedRegionSize = *RegionSize;
PAGE:0049AD39                 or      [ebp+ms_exc.registration.TryLevel], 0FFFFFFFFh
PAGE:0049AD3D
PAGE:0049AD3D loc_49AD3D:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+4CBC8j
PAGE:0049AD3D                 mov     eax, _MmHighestUserAddress
PAGE:0049AD42                 cmp     ecx, eax        ; CapturedBase>MM_HIGHEST_USER_ADDRESS
PAGE:0049AD44                 ja      RETURN_STATUS_INVALID_PARAMETER_2 ; 跳轉無效的參數
PAGE:0049AD4A                 sub     eax, ecx        ; MM_HIGHEST_USER_ADDRESS-CapturedBase
PAGE:0049AD4C                 cmp     eax, edx        ; >CapturedRegionSize
PAGE:0049AD4E                 jb      RETURN_STATUS_INVALID_PARAMETER_3 ; 跳轉無效的參數
PAGE:0049AD54                 test    edx, edx        ; edx=0
PAGE:0049AD56                 jz      RETURN_STATUS_INVALID_PARAMETER_3 ; 跳轉無效的參數
PAGE:0049AD5C                 push    0               ; HandleInformation
PAGE:0049AD5E                 lea     eax, [ebp+Object]
PAGE:0049AD61                 push    eax             ; Object
PAGE:0049AD62                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0049AD65                 push    _PsProcessType  ; ObjectType
PAGE:0049AD6B                 push    8               ; DesiredAccess   PROCESS_VM_OPERATION
PAGE:0049AD6D                 push    [ebp+ProcessHandle] ; Handle
PAGE:0049AD70                 call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)
PAGE:0049AD75                 test    eax, eax
PAGE:0049AD77                 jl      loc_49AE0B      ; 返回0則跳走
PAGE:0049AD7D                 mov     eax, [ebp+Object]
PAGE:0049AD80                 cmp     [ebp+CurrentProcess], eax ; 比較ObRef..得到的Process是否等於CurrentProcess
PAGE:0049AD83                 jnz     loc_4B9A1B      ; 不等於,調用KeStackAttachProcess附加到進程空間
PAGE:0049AD89
PAGE:0049AD89 loc_49AD89:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+1ED7Bj
PAGE:0049AD89                 lea     eax, [ebp+LastProtect]
PAGE:0049AD8C                 push    eax             ; &LastProtect
PAGE:0049AD8D                 push    [ebp+NewProtect] ; NewProtect
PAGE:0049AD90                 lea     eax, [ebp+CapturedRegionSize]
PAGE:0049AD93                 push    eax             ; &CapturedRegionSize
PAGE:0049AD94                 lea     eax, [ebp+CapturedBase]
PAGE:0049AD97                 push    eax             ; &CapturedBase
PAGE:0049AD98                 push    [ebp+Object]    ; Process
PAGE:0049AD9B                 call    _MiProtectVirtualMemory@20 ; MiProtectVirtualMemory(x,x,x,x,x)
PAGE:0049ADA0                 mov     [ebp+Status], eax
PAGE:0049ADA3                 cmp     [ebp+Attached], 0 ; 是否附加了,之前KeStackDetachProcess調用的時候修改的
PAGE:0049ADA7                 jnz     loc_4B9A0D      ; 調用KeUnStackDetachProcess
PAGE:0049ADAD
PAGE:0049ADAD loc_49ADAD:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+1ED65j
PAGE:0049ADAD                 mov     ecx, [ebp+Object] ; Object
PAGE:0049ADB0                 call    @ObfDereferenceObject@4 ; ObfDereferenceObject(x)
PAGE:0049ADB5                 mov     [ebp+ms_exc.registration.TryLevel], 1
PAGE:0049ADBC                 cmp     [ebp+AccessMode], 0
PAGE:0049ADC0                 jz      short loc_49ADF5 ; 內核模式跳轉
PAGE:0049ADC0                                         ; *RegionSize = CapturedRegionSize;
PAGE:0049ADC0                                         ; *BaseAddress = CapturedBase;
PAGE:0049ADC0                                         ; *OldProtect = LastProtect;
PAGE:0049ADC2                 mov     eax, _MmUserProbeAddress
PAGE:0049ADC7                 cmp     edi, eax
PAGE:0049ADC9                 jnb     loc_51C4A3
PAGE:0049ADCF
PAGE:0049ADCF loc_49ADCF:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817F8j
PAGE:0049ADCF                 mov     eax, [edi]
PAGE:0049ADD1                 mov     [edi], eax
PAGE:0049ADD3                 mov     eax, _MmUserProbeAddress
PAGE:0049ADD8                 cmp     esi, eax
PAGE:0049ADDA                 jnb     loc_51C4AE
PAGE:0049ADE0
PAGE:0049ADE0 loc_49ADE0:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+81803j
PAGE:0049ADE0                 mov     eax, [esi]
PAGE:0049ADE2                 mov     [esi], eax
PAGE:0049ADE4                 mov     eax, _MmUserProbeAddress
PAGE:0049ADE9                 cmp     ebx, eax
PAGE:0049ADEB                 jnb     loc_51C4B9
PAGE:0049ADF1
PAGE:0049ADF1 loc_49ADF1:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+8180Ej
PAGE:0049ADF1                 mov     eax, [ebx]
PAGE:0049ADF3                 mov     [ebx], eax
PAGE:0049ADF5
PAGE:0049ADF5 loc_49ADF5:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+10Fj
PAGE:0049ADF5                 mov     eax, [ebp+CapturedRegionSize]
PAGE:0049ADF8                 mov     [esi], eax
PAGE:0049ADFA                 mov     eax, [ebp+CapturedBase]
PAGE:0049ADFD                 mov     [edi], eax
PAGE:0049ADFF                 mov     eax, [ebp+LastProtect]
PAGE:0049AE02                 mov     [ebx], eax
PAGE:0049AE04
PAGE:0049AE04 loc_49AE04:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+81824j
PAGE:0049AE04                 or      [ebp+ms_exc.registration.TryLevel], 0FFFFFFFFh
PAGE:0049AE08                 mov     eax, [ebp+Status]
PAGE:0049AE0B
PAGE:0049AE0B loc_49AE0B:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+C6j
PAGE:0049AE0B                                         ; NtProtectVirtualMemory(x,x,x,x,x)+81799j ...
PAGE:0049AE0B                 call    __SEH_epilog
PAGE:0049AE10                 retn    14h
PAGE:0049AE10 _NtProtectVirtualMemory@20 endp

  我們看到中間有個地方對於PreviousMode有一個判斷,如果PreviousMode為用戶模式則不跳轉,為內核模式則跳轉,我們看看跳轉的代碼:

PAGE:0049ACEA                 jz      loc_4E7866      ; PreviousMode = 0(jz為0 跳轉)
PAGE:0049ACEA                                         ; 用戶層調用則不跳轉
PAGE:004E7866 loc_4E7866:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+39j
PAGE:004E7866                 mov     esi, [ebp+ProtectSize]
PAGE:004E7869                 mov     edx, [esi]
PAGE:004E786B                 mov     [ebp+CapturedRegionSize], edx
PAGE:004E786E                 mov     edi, [ebp+BaseAddress]
PAGE:004E7871                 mov     ecx, [edi]
PAGE:004E7873                 mov     [ebp+CapturedBase], ecx
PAGE:004E7876                 mov     ebx, [ebp+OldProtect]
PAGE:004E7879                 jmp     loc_49AD3D
PAGE:0049AD3D loc_49AD3D:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+4CBC8j
PAGE:0049AD3D                 mov     eax, _MmHighestUserAddress
PAGE:0049AD42                 cmp     ecx, eax        ; CapturedBase>MM_HIGHEST_USER_ADDRESS
PAGE:0049AD44                 ja      RETURN_STATUS_INVALID_PARAMETER_2 ; 跳轉無效的參數
PAGE:0049AD4A                 sub     eax, ecx        ; MM_HIGHEST_USER_ADDRESS-CapturedBase
PAGE:0049AD4C                 cmp     eax, edx        ; >CapturedRegionSize
PAGE:0049AD4E                 jb      RETURN_STATUS_INVALID_PARAMETER_3 ; 跳轉無效的參數
PAGE:0049AD54                 test    edx, edx        ; edx=0
PAGE:0049AD56                 jz      RETURN_STATUS_INVALID_PARAMETER_3 ; 跳轉無效的參數
PAGE:0049AD5C                 push    0               ; HandleInformation
PAGE:0049AD5E                 lea     eax, [ebp+Object]
PAGE:0049AD61                 push    eax             ; Object
PAGE:0049AD62                 push    dword ptr [ebp+AccessMode] ; AccessMode
PAGE:0049AD65                 push    _PsProcessType  ; ObjectType
PAGE:0049AD6B                 push    8               ; DesiredAccess   PROCESS_VM_OPERATION
PAGE:0049AD6D                 push    [ebp+ProcessHandle] ; Handle
PAGE:0049AD70                 call    _ObReferenceObjectByHandle@24 ; ObReferenceObjectByHandle(x,x,x,x,x,x)

  可以看到如果是內核模式,直接跳過了校驗參數合法性的部分,直接走入下面的ObRegerenceObjectByHandle,跳過的代碼如下所示:

PAGE:0049ACF0                 mov     [ebp+ms_exc.registration.TryLevel], ebx
PAGE:0049ACF3                 mov     edi, [ebp+BaseAddress]
PAGE:0049ACF6                 mov     eax, _MmUserProbeAddress     ;ProbeForWritePointer (BaseAddress);
PAGE:0049ACFB                 cmp     edi, eax
PAGE:0049ACFD                 jnb     loc_51C44F
PAGE:0049AD03
PAGE:0049AD03 loc_49AD03:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817A0j
PAGE:0049AD03                 mov     eax, [edi]
PAGE:0049AD05                 mov     [edi], eax
PAGE:0049AD07                 mov     esi, [ebp+ProtectSize]
PAGE:0049AD0A                 mov     eax, _MmUserProbeAddress    ;ProbeForWriteUlong_ptr (RegionSize);
PAGE:0049AD0F                 cmp     esi, eax
PAGE:0049AD11                 jnb     loc_51C456
PAGE:0049AD17
PAGE:0049AD17 loc_49AD17:                             ; CODE XREF: NtProtectVirtualMemory(x,x,x,x,x)+817A7j
PAGE:0049AD17                 mov     eax, [esi]
PAGE:0049AD19                 mov     [esi], eax
PAGE:0049AD1B                 mov     ebx, [ebp+OldProtect]
PAGE:0049AD1E                 mov     eax, _MmUserProbeAddress        ;ProbeForWriteUlong (OldProtect);
PAGE:0049AD23                 cmp     ebx, eax
PAGE:0049AD25                 jnb     loc_51C45D

  所以我們可以看出PreviousMode為內核模式的時候會比用戶模式檢查的地方少,效率會快一些。

0x07 x64位下的內核Zw調用Nt函數

.text:00000001400795E0                ZwProtectVirtualMemory proc near        ; CODE XREF: KiOpPatchCode+C9p
.text:00000001400795E0                                                        ; KiOpPatchCode+1E2p ...
.text:00000001400795E0 48 8B C4                       mov     rax, rsp
.text:00000001400795E3 FA                             cli                     ; 關中斷
.text:00000001400795E4 48 83 EC 10                    sub     rsp, 10h        ; 開辟棧區
.text:00000001400795E8 50                             push    rax             ; 保存棧頂
.text:00000001400795E9 9C                             pushfq                  ; ELFALGS
.text:00000001400795EA 6A 10                          push    10h
.text:00000001400795EC 48 8D 05 7D 28+                lea     rax, KiServiceLinkage
.text:00000001400795F3 50                             push    rax
.text:00000001400795F4 B8 4D 00 00 00                 mov     eax, 4Dh        ; 函數索引0x4D
.text:00000001400795F9 E9 C2 5F 00 00                 jmp     KiServiceInternal
.text:00000001400795F9                ZwProtectVirtualMemory endp
.text:000000014007F5C0                KiServiceInternal proc near             ; CODE XREF: ZwMapUserPhysicalPagesScatter+19j
.text:000000014007F5C0                                                        ; ZwWaitForSingleObject+19j ...
.text:000000014007F5C0
.text:000000014007F5C0                var_140         = byte ptr -140h
.text:000000014007F5C0                var_30          = qword ptr -30h
.text:000000014007F5C0                var_28          = qword ptr -28h
.text:000000014007F5C0                var_20          = qword ptr -20h
.text:000000014007F5C0                var_18          = qword ptr -18h
.text:000000014007F5C0
.text:000000014007F5C0 48 83 EC 08                    sub     rsp, 8
.text:000000014007F5C4 55                             push    rbp
.text:000000014007F5C5 48 81 EC 58 01+                sub     rsp, 158h       ; 棧區
.text:000000014007F5CC 48 8D AC 24 80+                lea     rbp, [rsp+80h]  ; 棧底
.text:000000014007F5D4 48 89 9D C0 00+                mov     [rbp+0E8h+var_28], rbx ; mov     TrRbx[rbp], rbx
.text:000000014007F5DB 48 89 BD C8 00+                mov     [rbp+0E8h+var_20], rdi ; mov     TrRdi[rbp], rdi
.text:000000014007F5E2 48 89 B5 D0 00+                mov     [rbp+0E8h+var_18], rsi ; mov     TrRsi[rbp], rsi
.text:000000014007F5E9 FB                             sti                     ; 開中斷
.text:000000014007F5EA 65 48 8B 1C 25+                mov     rbx, gs:188h    ; PcCurrentThread  get current thread address
.text:000000014007F5F3 0F 0D 8B D8 01+                prefetchw byte ptr [rbx+1D8h] ; prefetch with write intent
.text:000000014007F5FA 0F B6 BB F6 01+                movzx   edi, byte ptr [rbx+1F6h] ; save previous mode in trap frame
.text:000000014007F601 40 88 7D A8                    mov     [rbp+0E8h+var_140], dil
.text:000000014007F605 C6 83 F6 01 00+                mov     byte ptr [rbx+1F6h], 0 ; set thread previous mode
.text:000000014007F60C 4C 8B 93 D8 01+                mov     r10, [rbx+1D8h] ; save previous frame pointer address
.text:000000014007F613 4C 89 95 B8 00+                mov     [rbp+0E8h+var_30], r10
.text:000000014007F61A 4C 8D 1D 3D 01+                lea     r11, KiSystemServiceStart ;  get address of service start
.text:000000014007F621 41 FF E3                       jmp     r11             ;  finish in common code
.text:000000014007F621                KiServiceInternal endp

  ZwProtectVirtualMemory調用了KiServiceLinkage,把系統服務序號放進eax后又調用了KiServiceInternal,KiServiceInternal又調用了KiSystemServiceStart。KiServiceLinkage和KiServiceInternal是初始化系統服務的,KiSystemServiceStart則是開始執行系統服務。我們再看看KiSystemServiceStart干了些什么:

.text:000000014007F640                KiSystemCall64  proc near               ; DATA XREF: KiInitializeBootStructures+26Eo
.text:000000014007F640
...
.text:000000014007F75E                KiSystemServiceStart:                   ; DATA XREF: KiServiceInternal+5Ao
.text:000000014007F75E                                                        ; .data:00000001401EE648o
.text:000000014007F75E 48 89 A3 D8 01+                mov     [rbx+1D8h], rsp ; ThTrapFrame[rbx]  set current frame pointer address
.text:000000014007F765 8B F8                          mov     edi, eax
.text:000000014007F767 C1 EF 07                       shr     edi, 7          ; SERVICE_TABLE_SHIFT
.text:000000014007F76A 83 E7 20                       and     edi, 20h        ; SERVICE_TABLE_MASK
.text:000000014007F76D 25 FF 0F 00 00                 and     eax, 0FFFh      ; SERVICE_NUMBER_MASK
.text:000000014007F772
.text:000000014007F772                KiSystemServiceRepeat:                  ; CODE XREF: KiSystemCall64+47Bj
.text:000000014007F772 4C 8D 15 C7 20+                lea     r10, KeServiceDescriptorTable ; get table base address
.text:000000014007F779 4C 8D 1D 00 21+                lea     r11, KeServiceDescriptorTableShadow
.text:000000014007F780 F7 83 00 01 00+                test    dword ptr [rbx+100h], 80h
.text:000000014007F78A 4D 0F 45 D3                    cmovnz  r10, r11
.text:000000014007F78E 42 3B 44 17 10                 cmp     eax, [rdi+r10+10h]
.text:000000014007F793 0F 83 E9 02 00+                jnb     loc_14007FA82
.text:000000014007F799 4E 8B 14 17                    mov     r10, [rdi+r10]
.text:000000014007F79D 4D 63 1C 82                    movsxd  r11, dword ptr [r10+rax*4] ; get system service offset
.text:000000014007F7A1 49 8B C3                       mov     rax, r11
.text:000000014007F7A4 49 C1 FB 04                    sar     r11, 4
.text:000000014007F7A8 4D 03 D3                       add     r10, r11        ; add table base to
.text:000000014007F7AB 83 FF 20                       cmp     edi, 20h        ; check if GUI service
.text:000000014007F7AE 75 50                          jnz     short loc_14007F800 ; if ne,not GUI service
.text:000000014007F7B0 4C 8B 9B B8 00+                mov     r11, [rbx+0B8h] ; get user TEB address
.text:000000014007F7B7
.text:000000014007F7B7                KiSystemServiceGdiTebAccess:            ; DATA XREF: KiSystemServiceHandler+Do
.text:000000014007F7B7 41 83 BB 40 17+                cmp     dword ptr [r11+1740h], 0 ; check batch queue depth
.text:000000014007F7BF 74 3F                          jz      short loc_14007F800 ; if e,batch queue empty
.text:000000014007F7C1 48 89 45 B0                    mov     [rbp-50h], rax
.text:000000014007F7C5 48 89 4D B8                    mov     [rbp-48h], rcx  ; mov TrRcx[rbp],rcx    save system service arguments
.text:000000014007F7C9 48 89 55 C0                    mov     [rbp-40h], rdx
.text:000000014007F7CD 49 8B D8                       mov     rbx, r8
.text:000000014007F7D0 49 8B F9                       mov     rdi, r9
.text:000000014007F7D3 49 8B F2                       mov     rsi, r10        ; save system service address
.text:000000014007F7D6 FF 15 34 1F 23+                call    cs:KeGdiFlushUserBatch ; call flush GDI user batch routine
.text:000000014007F7DC 48 8B 45 B0                    mov     rax, [rbp-50h]  ; restore system service arguments
.text:000000014007F7E0 48 8B 4D B8                    mov     rcx, [rbp-48h]
.text:000000014007F7E4 48 8B 55 C0                    mov     rdx, [rbp-40h]
.text:000000014007F7E8 4C 8B C3                       mov     r8, rbx
.text:000000014007F7EB 4C 8B CF                       mov     r9, rdi
.text:000000014007F7EE 4C 8B D6                       mov     r10, rsi        ; restore system service address
.text:000000014007F7F1                                db      66h, 66h, 66h, 66h, 66h, 66h
.text:000000014007F7F1 66 66 66 66 66+                nop     word ptr [rax+rax+00000000h]
.text:000000014007F800
.text:000000014007F800                loc_14007F800:                          ; CODE XREF: KiSystemCall64+16Ej
.text:000000014007F800                                                        ; KiSystemCall64+17Fj
.text:000000014007F800 83 E0 0F                       and     eax, 0Fh        ; ; Check if system service has any in memory arguments.
.text:000000014007F803 0F 84 B7 00 00+                jz      KiSystemServiceCopyEnd ; if z, no in memory arguments
.text:000000014007F809 C1 E0 03                       shl     eax, 3          ; compute argument bytes for dispatch
.text:000000014007F80C 48 8D 64 24 90                 lea     rsp, [rsp-70h]  ; allocate stack argument area
.text:000000014007F811 48 8D 7C 24 18                 lea     rdi, [rsp+190h+var_178] ; compute copy destination address
.text:000000014007F816 48 8B B5 00 01+                mov     rsi, [rbp+100h] ;  get previous stack address  TrRsp[rbp]
.text:000000014007F81D 48 8D 76 20                    lea     rsi, [rsi+20h]  ; compute copy source address
.text:000000014007F821 F6 85 F0 00 00+                test    byte ptr [rbp+0F0h], 1 ; check if previous mode user   TrSegCs[rbp]
.text:000000014007F828 74 16                          jz      short loc_14007F840 ; if z, previous mode kernel
.text:000000014007F82A 48 3B 35 CF 17+                cmp     rsi, cs:MmUserProbeAddress ; check if source address in range
.text:000000014007F831 48 0F 43 35 C7+                cmovnb  rsi, cs:MmUserProbeAddress ; if ae, reset copy source address
.text:000000014007F839 0F 1F 80 00 00+                nop     dword ptr [rax+00000000h]
.text:000000014007F840
.text:000000014007F840                loc_14007F840:                          ; CODE XREF: KiSystemCall64+1E8j
.text:000000014007F840 4C 8D 1D 79 00+                lea     r11, KiSystemServiceCopyEnd ; get copy ending address
.text:000000014007F847 4C 2B D8                       sub     r11, rax        ; substract number of bytes to copy
.text:000000014007F84A 41 FF E3                       jmp     r11
.text:000000014007F84A                ; ---------------------------------------------------------------------------
.text:000000014007F84D 0F 1F 00                       align 10h
.text:000000014007F850
.text:000000014007F850                KiSystemServiceCopyStart:               ; DATA XREF: KiSystemServiceHandler+1Ao
.text:000000014007F850 48 8B 46 70                    mov     rax, [rsi+70h]  ; copy fourteenth argument
.text:000000014007F854 48 89 47 70                    mov     [rdi+70h], rax
.text:000000014007F858 48 8B 46 68                    mov     rax, [rsi+68h]  ; copy thirteenth argument
.text:000000014007F85C 48 89 47 68                    mov     [rdi+68h], rax
.text:000000014007F860 48 8B 46 60                    mov     rax, [rsi+60h]  ; copy twelfth argument
.text:000000014007F864 48 89 47 60                    mov     [rdi+60h], rax
.text:000000014007F868 48 8B 46 58                    mov     rax, [rsi+58h]  ; copy eleventh argument
.text:000000014007F86C 48 89 47 58                    mov     [rdi+58h], rax
.text:000000014007F870 48 8B 46 50                    mov     rax, [rsi+50h]  ; copy tenth argument
.text:000000014007F874 48 89 47 50                    mov     [rdi+50h], rax
.text:000000014007F878 48 8B 46 48                    mov     rax, [rsi+48h]  ; copy nineth argument
.text:000000014007F87C 48 89 47 48                    mov     [rdi+48h], rax
.text:000000014007F880 48 8B 46 40                    mov     rax, [rsi+40h]  ; copy eighth argument
.text:000000014007F884 48 89 47 40                    mov     [rdi+40h], rax
.text:000000014007F888 48 8B 46 38                    mov     rax, [rsi+38h]  ; copy seventh argument
.text:000000014007F88C 48 89 47 38                    mov     [rdi+38h], rax
.text:000000014007F890 48 8B 46 30                    mov     rax, [rsi+30h]  ; copy sixth argument
.text:000000014007F894 48 89 47 30                    mov     [rdi+30h], rax
.text:000000014007F898 48 8B 46 28                    mov     rax, [rsi+28h]  ; copy fifth argument
.text:000000014007F89C 48 89 47 28                    mov     [rdi+28h], rax
.text:000000014007F8A0 48 8B 46 20                    mov     rax, [rsi+20h]  ; copy fourth argument
.text:000000014007F8A4 48 89 47 20                    mov     [rdi+20h], rax
.text:000000014007F8A8 48 8B 46 18                    mov     rax, [rsi+18h]  ; copy third argument
.text:000000014007F8AC 48 89 47 18                    mov     [rdi+18h], rax
.text:000000014007F8B0 48 8B 46 10                    mov     rax, [rsi+10h]  ; copy second argument
.text:000000014007F8B4 48 89 47 10                    mov     [rdi+10h], rax
.text:000000014007F8B8 48 8B 46 08                    mov     rax, [rsi+8]    ; copy first argument
.text:000000014007F8BC 48 89 47 08                    mov     [rdi+8], rax
.text:000000014007F8C0
.text:000000014007F8C0                KiSystemServiceCopyEnd:                 ; CODE XREF: KiSystemCall64+1C3j
.text:000000014007F8C0                                                        ; DATA XREF: KiSystemServiceHandler+27o ...
.text:000000014007F8C0 F7 05 BE 7D 18+                test    cs:dword_140207688, 40h
.text:000000014007F8CA 0F 85 50 02 00+                jnz     loc_14007FB20
.text:000000014007F8D0 41 FF D2                       call    r10             ; call system service
.text:000000014007F8D3
.text:000000014007F8D3                loc_14007F8D3:                          ; CODE XREF: KiSystemCall64+535j
.text:000000014007F8D3 65 FF 04 25 38+                inc     dword ptr gs:2238h ; increment number of system calls  gs:[PcSystemCalls]
.text:000000014007F8DB
.text:000000014007F8DB                KiSystemServiceExit:                    ; CODE XREF: KiSystemCall64+49Cj
...
.text:000000014007FB75                KiSystemCall64  endp 

  KiSystemServiceStart調用了KiSystemServiceRepeat,KiSystemServiceRepeat根據系統服務序號來選擇SSDT還是ShadowSSDT(到了KiSystemServiceRepeat才真正調用Nt函數,通過call r11調用了Nt函數)。KiSystemServiceRepeat執行完成之后,會調用KiSystemServiceExit(系統服務調用完畢,會有返回信息)

  我們接下來再看看NtProtectVirtualMemory函數的實現

PAGE:0000000140398B2C                NtProtectVirtualMemory proc near        ; DATA XREF: .text:0000000140081568o
PAGE:0000000140398B2C
PAGE:0000000140398B2C                var_78          = qword ptr -78h
PAGE:0000000140398B2C                var_70          = qword ptr -70h
PAGE:0000000140398B2C                var_68          = qword ptr -68h
PAGE:0000000140398B2C                LastProtect     = dword ptr -58h
PAGE:0000000140398B2C                var_54          = dword ptr -54h
PAGE:0000000140398B2C                Object          = qword ptr -50h
PAGE:0000000140398B2C                CaptureRegionSize= qword ptr -48h
PAGE:0000000140398B2C                CapturedBase    = qword ptr -40h
PAGE:0000000140398B2C                ApcState        = byte ptr -38h
PAGE:0000000140398B2C                var_8           = byte ptr -8
PAGE:0000000140398B2C                OldProtect      = qword ptr  28h
PAGE:0000000140398B2C
PAGE:0000000140398B2C                ; FUNCTION CHUNK AT PAGE:00000001403C8D10 SIZE 0000001E BYTES
PAGE:0000000140398B2C
PAGE:0000000140398B2C 48 8B C4                       mov     rax, rsp
PAGE:0000000140398B2F 48 89 70 08                    mov     [rax+8], rsi
PAGE:0000000140398B33 48 89 78 10                    mov     [rax+10h], rdi
PAGE:0000000140398B37 4C 89 60 18                    mov     [rax+18h], r12
PAGE:0000000140398B3B 4C 89 68 20                    mov     [rax+20h], r13
PAGE:0000000140398B3F 41 56                          push    r14
PAGE:0000000140398B41 48 81 EC 90 00+                sub     rsp, 90h
PAGE:0000000140398B48 41 8B F9                       mov     edi, r9d        ; NewProtect
PAGE:0000000140398B4B 4D 8B E8                       mov     r13, r8         ; RegionSize
PAGE:0000000140398B4E 4C 8B E2                       mov     r12, rdx        ; *BaseAddress
PAGE:0000000140398B51 4C 8B D1                       mov     r10, rcx        ; ProcessHandle
PAGE:0000000140398B54 41 8B C9                       mov     ecx, r9d
PAGE:0000000140398B57 E8 A4 AE CF FF                 call    MiMakeProtectionMask ; MiMakeProtectionMask (NewProtect);
PAGE:0000000140398B5C 83 F8 FF                       cmp     eax, 0FFFFFFFFh
PAGE:0000000140398B5F 0F 84 AB 01 03+                jz      loc_1403C8D10   ; error
PAGE:0000000140398B65 65 48 8B 04 25+                mov     rax, gs:188h    ; 獲得線程體
PAGE:0000000140398B6E 48 8B 70 70                    mov     rsi, [rax+70h]  ; 線程所屬的Process
PAGE:0000000140398B72 44 8A 88 F6 01+                mov     r9b, [rax+1F6h] ; PreviousMode
PAGE:0000000140398B79 45 84 C9                       test    r9b, r9b
PAGE:0000000140398B7C 0F 84 3E 01 00+                jz      loc_140398CC0   ; 如果是KernelMode就跳轉
PAGE:0000000140398B7C 00                                                     ; 如果是UserMode就繼續執行
PAGE:0000000140398B82 49 8B CC                       mov     rcx, r12        ; BaseAddress
PAGE:0000000140398B85 48 8B 05 74 84+                mov     rax, cs:MmUserProbeAddress ; ProbeForWrite (BaseAddress, sizeof(PVOID64), sizeof(PVOID64));
PAGE:0000000140398B8C 4C 3B E0                       cmp     r12, rax
PAGE:0000000140398B8F 48 0F 43 C8                    cmovnb  rcx, rax        ; 大於等於時傳送
PAGE:0000000140398B93 48 8B 01                       mov     rax, [rcx]
PAGE:0000000140398B96 48 89 01                       mov     [rcx], rax
PAGE:0000000140398B99 49 8B C8                       mov     rcx, r8         ; RegionSize
PAGE:0000000140398B9C 48 8B 05 5D 84+                mov     rax, cs:MmUserProbeAddress ; ProbeForWrite (RegionSize, sizeof(ULONGLONG), sizeof(ULONGLONG));
PAGE:0000000140398BA3 4C 3B C0                       cmp     r8, rax
PAGE:0000000140398BA6 48 0F 43 C8                    cmovnb  rcx, rax        ; 大於等於時傳送
PAGE:0000000140398BAA 48 8B 01                       mov     rax, [rcx]
PAGE:0000000140398BAD 48 89 01                       mov     [rcx], rax
PAGE:0000000140398BB0 4C 8B B4 24 C0+                mov     r14, [rsp+98h+OldProtect]
PAGE:0000000140398BB8 49 8B CE                       mov     rcx, r14
PAGE:0000000140398BBB 48 8B 05 3E 84+                mov     rax, cs:MmUserProbeAddress ; ProbeForWriteUlong (OldProtect);
PAGE:0000000140398BC2 4C 3B F0                       cmp     r14, rax
PAGE:0000000140398BC5 48 0F 43 C8                    cmovnb  rcx, rax
PAGE:0000000140398BC9 8B 01                          mov     eax, [rcx]
PAGE:0000000140398BCB 89 01                          mov     [rcx], eax
PAGE:0000000140398BCD 49 8B 14 24                    mov     rdx, [r12]
PAGE:0000000140398BD1 48 89 54 24 58                 mov     [rsp+98h+CapturedBase], rdx ; CapturedBase = *BaseAddress;
PAGE:0000000140398BD6 49 8B 08                       mov     rcx, [r8]
PAGE:0000000140398BD9 48 89 4C 24 50                 mov     [rsp+98h+CaptureRegionSize], rcx ; CapturedRegionSize = *RegionSize;
PAGE:0000000140398BDE EB 05                          jmp     short loc_140398BE5
PAGE:0000000140398BE0                ; ---------------------------------------------------------------------------
PAGE:0000000140398BE0 E9 BD 00 00 00                 jmp     loc_140398CA2
PAGE:0000000140398BE5                ; ---------------------------------------------------------------------------
PAGE:0000000140398BE5
PAGE:0000000140398BE5                loc_140398BE5:                          ; CODE XREF: NtProtectVirtualMemory+B2j
PAGE:0000000140398BE5                                                        ; NtProtectVirtualMemory+1ADj
PAGE:0000000140398BE5 48 8B 05 24 84+                mov     rax, cs:MmHighestUserAddress ; 合法性校驗
PAGE:0000000140398BEC 48 3B D0                       cmp     rdx, rax        ; CapturedBase>MM_HIGHEST_USER_ADDRESS
PAGE:0000000140398BEF 0F 87 11 01 00+                ja      RETURN_STATUS_INVALID_PARAMETER_2
PAGE:0000000140398BF5 48 2B C2                       sub     rax, rdx        ; MM_HIGHEST_USER_ADDRESS64-CapturedBase
PAGE:0000000140398BF8 48 3B C1                       cmp     rax, rcx
PAGE:0000000140398BFB 0F 82 19 01 03+                jb      RETURN_STATUS_INVALID_PARAMETER_3 ; 小於跳轉
PAGE:0000000140398C01 48 85 C9                       test    rcx, rcx        ; CapturedRegionSize是否為0
PAGE:0000000140398C04 0F 84 1A 01 03+                jz      RETURN_STATUS_INVALID_PARAMETER_4
PAGE:0000000140398C0A 48 83 64 24 30+                and     [rsp+98h+var_68], 0 ; POBJECT_HANDLE_INFORMATION   NULL
PAGE:0000000140398C10 48 8D 44 24 48                 lea     rax, [rsp+98h+Object]
PAGE:0000000140398C15 48 89 44 24 28                 mov     [rsp+98h+var_70], rax ; Process
PAGE:0000000140398C1A C7 44 24 20 44+                mov     dword ptr [rsp+98h+var_78], 746C6644h ; Tag
PAGE:0000000140398C22 4C 8B 05 F7 83+                mov     r8, cs:PsProcessType ; PsProcessType
PAGE:0000000140398C29 BA 08 00 00 00                 mov     edx, 8          ; PROCESS_VM_OPERATION
PAGE:0000000140398C2E 49 8B CA                       mov     rcx, r10        ; ProcessHandle
PAGE:0000000140398C31 E8 AA D8 FD FF                 call    ObReferenceObjectByHandleWithTag ; NTSTATUS ObReferenceObjectByHandleWithTag(
PAGE:0000000140398C31                                                        ;   _In_      HANDLE                     Handle,
PAGE:0000000140398C31                                                        ;   _In_      ACCESS_MASK                DesiredAccess,
PAGE:0000000140398C31                                                        ;   _In_opt_  POBJECT_TYPE               ObjectType,
PAGE:0000000140398C31                                                        ;   _In_      KPROCESSOR_MODE            AccessMode,
PAGE:0000000140398C31                                                        ;   _In_      ULONG                      Tag,
PAGE:0000000140398C31                                                        ;   _Out_     PVOID                      *Object,
PAGE:0000000140398C31                                                        ;   _Out_opt_ POBJECT_HANDLE_INFORMATION HandleInformation
PAGE:0000000140398C31                                                        ; );
PAGE:0000000140398C36 85 C0                          test    eax, eax
PAGE:0000000140398C38 78 68                          js      short loc_140398CA2
PAGE:0000000140398C3A 48 3B 74 24 48                 cmp     rsi, [rsp+98h+Object] ; 是否是當前進程
PAGE:0000000140398C3F 0F 85 99 00 00+                jnz     loc_140398CDE   ; 不是則跳走調用KeAttachProcess
PAGE:0000000140398C45 33 F6                          xor     esi, esi
PAGE:0000000140398C47
PAGE:0000000140398C47                loc_140398C47:                          ; CODE XREF: NtProtectVirtualMemory+1C6j
PAGE:0000000140398C47 48 8D 44 24 40                 lea     rax, [rsp+98h+LastProtect] ; &LastProtect
PAGE:0000000140398C4C 48 89 44 24 20                 mov     [rsp+98h+var_78], rax ; &LastProtect
PAGE:0000000140398C51 44 8B CF                       mov     r9d, edi        ; NewProtect
PAGE:0000000140398C54 4C 8D 44 24 50                 lea     r8, [rsp+98h+CaptureRegionSize] ; CapturedRegionSize
PAGE:0000000140398C59 48 8D 54 24 58                 lea     rdx, [rsp+98h+CapturedBase] ; CapturedBase
PAGE:0000000140398C5E 48 8B 4C 24 48                 mov     rcx, [rsp+98h+Object] ; Process
PAGE:0000000140398C63 E8 B8 F9 FF FF                 call    MiProtectVirtualMemory
PAGE:0000000140398C68 8B F8                          mov     edi, eax
PAGE:0000000140398C6A 89 44 24 44                    mov     [rsp+98h+var_54], eax
PAGE:0000000140398C6E 85 F6                          test    esi, esi        ; 為0則是  調用過KeStackAttachProcess,需要恢復
PAGE:0000000140398C70 0F 85 81 00 00+                jnz     loc_140398CF7   ; 調用KeUnStackDetachProcess
PAGE:0000000140398C76
PAGE:0000000140398C76                loc_140398C76:                          ; CODE XREF: NtProtectVirtualMemory+1D5j
PAGE:0000000140398C76 48 8B 4C 24 48                 mov     rcx, [rsp+98h+Object] ; Object
PAGE:0000000140398C7B E8 C0 17 CF FF                 call    ObfDereferenceObject ; 減少引用計數
PAGE:0000000140398C80 90                             nop
PAGE:0000000140398C81 48 8B 44 24 50                 mov     rax, [rsp+98h+CaptureRegionSize] ; CapturedRegionSize
PAGE:0000000140398C86 49 89 45 00                    mov     [r13+0], rax
PAGE:0000000140398C8A 48 8B 44 24 58                 mov     rax, [rsp+98h+CapturedBase] ; CapturedBase
PAGE:0000000140398C8F 49 89 04 24                    mov     [r12], rax
PAGE:0000000140398C93 8B 44 24 40                    mov     eax, [rsp+98h+LastProtect]
PAGE:0000000140398C97 41 89 06                       mov     [r14], eax
PAGE:0000000140398C9A EB 04                          jmp     short loc_140398CA0
PAGE:0000000140398C9C                ; ---------------------------------------------------------------------------
PAGE:0000000140398C9C 8B 7C 24 44                    mov     edi, [rsp+98h+var_54]
PAGE:0000000140398CA0
PAGE:0000000140398CA0                loc_140398CA0:                          ; CODE XREF: NtProtectVirtualMemory+16Ej
PAGE:0000000140398CA0 8B C7                          mov     eax, edi
PAGE:0000000140398CA2
PAGE:0000000140398CA2                loc_140398CA2:                          ; CODE XREF: NtProtectVirtualMemory+B4j
PAGE:0000000140398CA2                                                        ; NtProtectVirtualMemory+10Cj ...
PAGE:0000000140398CA2 4C 8D 9C 24 90+                lea     r11, [rsp+98h+var_8]
PAGE:0000000140398CAA 49 8B 73 10                    mov     rsi, [r11+10h]
PAGE:0000000140398CAE 49 8B 7B 18                    mov     rdi, [r11+18h]
PAGE:0000000140398CB2 4D 8B 63 20                    mov     r12, [r11+20h]
PAGE:0000000140398CB6 4D 8B 6B 28                    mov     r13, [r11+28h]
PAGE:0000000140398CBA 49 8B E3                       mov     rsp, r11
PAGE:0000000140398CBD 41 5E                          pop     r14
PAGE:0000000140398CBF C3                             retn
PAGE:0000000140398CC0                ; ---------------------------------------------------------------------------
PAGE:0000000140398CC0
PAGE:0000000140398CC0                loc_140398CC0:                          ; CODE XREF: NtProtectVirtualMemory+50j
PAGE:0000000140398CC0 49 8B 08                       mov     rcx, [r8]
PAGE:0000000140398CC3 48 89 4C 24 50                 mov     [rsp+98h+CaptureRegionSize], rcx ; CapturedRegionSize
PAGE:0000000140398CC8 49 8B 14 24                    mov     rdx, [r12]
PAGE:0000000140398CCC 48 89 54 24 58                 mov     [rsp+98h+CapturedBase], rdx ; CapturedBase
PAGE:0000000140398CD1 4C 8B B4 24 C0+                mov     r14, [rsp+98h+OldProtect]
PAGE:0000000140398CD9 E9 07 FF FF FF                 jmp     loc_140398BE5
PAGE:0000000140398CDE                ; ---------------------------------------------------------------------------
PAGE:0000000140398CDE
PAGE:0000000140398CDE                loc_140398CDE:                          ; CODE XREF: NtProtectVirtualMemory+113j
PAGE:0000000140398CDE 48 8D 54 24 60                 lea     rdx, [rsp+98h+ApcState] ; ApcState
PAGE:0000000140398CE3 48 8B 4C 24 48                 mov     rcx, [rsp+98h+Object] ; Process
PAGE:0000000140398CE8 E8 23 87 D1 FF                 call    KeStackAttachProcess ; VOID KeStackAttachProcess(
PAGE:0000000140398CE8                                                        ;   _Inout_ PRKPROCESS   Process,
PAGE:0000000140398CE8                                                        ;   _Out_   PRKAPC_STATE ApcState
PAGE:0000000140398CE8                                                        ; );
PAGE:0000000140398CED BE 01 00 00 00                 mov     esi, 1
PAGE:0000000140398CF2 E9 50 FF FF FF                 jmp     loc_140398C47
PAGE:0000000140398CF7                ; ---------------------------------------------------------------------------
PAGE:0000000140398CF7
PAGE:0000000140398CF7                loc_140398CF7:                          ; CODE XREF: NtProtectVirtualMemory+144j
PAGE:0000000140398CF7 48 8D 4C 24 60                 lea     rcx, [rsp+98h+ApcState]
PAGE:0000000140398CFC E8 1F 84 D1 FF                 call    KeUnstackDetachProcess ;
PAGE:0000000140398CFC                                                        ; VOID KeUnstackDetachProcess(
PAGE:0000000140398CFC                                                        ;   _In_ PRKAPC_STATE ApcState
PAGE:0000000140398CFC                                                        ; );
PAGE:0000000140398D01 E9 70 FF FF FF                 jmp     loc_140398C76
PAGE:0000000140398D06                ; ---------------------------------------------------------------------------
PAGE:0000000140398D06
PAGE:0000000140398D06                RETURN_STATUS_INVALID_PARAMETER_2:      ; CODE XREF: NtProtectVirtualMemory+C3j
PAGE:0000000140398D06 B8 F0 00 00 C0                 mov     eax, 0C00000F0h
PAGE:0000000140398D0B EB 95                          jmp     short loc_140398CA2
PAGE:0000000140398D0B                ; ---------------------------------------------------------------------------
PAGE:0000000140398D0D 90 90 90 90 90+                align 20h
PAGE:0000000140398D0D 90 90 90 90 90+NtProtectVirtualMemory endp

  這里也是根據KernelMode和UserMode的不同而選擇性的驗證BaseAddress,如果是KernelMode這個地方就沒有進行ProbeForWrite驗證,直接跳過驗證步驟。

 

0x08 總結

  1.Zw函數會在KiSystemService中將ETHREAD中的PreviousMode改為KernelMode,最后在Nt函數中如果是KernelMode就會跳過對參數是否可寫的驗證,如果是UserMode就會驗證。如果是UserMode,訪問內核地址會報錯,所以如果內核中直接調用Nt函數,需要手動將PreviousMode修改為KernelMode否則無法訪問內核地址,而修改PreviousMode並且通過系統服務表獲取SSDT函數這個過程是很復雜的,直接調用內核導出的Zw函數就行,不過在調用Zw函數的時候需要自己對地址的可寫性驗證。而且通過Zw函數調用會在系統空間堆棧上有個屬於本次調用的自陷框架。
  2.32位下Zw函數會將內核模式保存在CS最后一位上,調用KiSystemService修改PreviousMode為KernelMode,接着跳轉到KiFastCallEntry中間的地方,初始化一些寄存器,最后通過call ebx的方式調用Nt函數,最后通過KiSystemExit返回。
   64位下Zw函數會調用KiServiceInternal,在這個函數中修改PerviousMode為KernelMode,然后跳轉到KiSystemCall64中的KiSystemServiceStart部分,接着在KiSystemServiceRepeat部分通過jmp r11調用Nt函數,最后通過KiSystemServiceExit函數返回。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM