天天看點

核心學習-系統調用下系統調用的學習

系統調用的學習

上文回顧

上篇文章分析得到:

1.3環進0環的兩種方式,分别是中斷門和快速調用,CPU支援快速調用,那麼_KUSER_SHARED_DATA 結構體的 SystemCall 屬性指向的函數是 KiFastSystemCall,執行 KiFastSystemCall,使用快速調用的方式進0環;如果不支援,那麼SystemCall 指向的函數是KiIntSystemCall,執行 KiIntSystemCall,使用中斷門的方式進0環。

2.快速調用不需要通路記憶體,而中斷門需要讀TSS和IDT表

3.int 0x2e 和 sysenter 指令進0環後,分别調用了兩個函數 KiSystemService 和 KiFastCallEntry。

4.原來的寄存器存儲到了_KTRAP_FRAME 結構體裡,3環API參數指針通過EDX傳給0環。

上篇文章分析結果,兩個函數最後執行同一段代碼,如圖

圖中标記的是407781函數,之後是執行的相同代碼部分,7781函數在_KiFastCallEntry函數内部。圖檔太大沒法截圖全部。

核心學習-系統調用下系統調用的學習

KiSystemService / KiFastCallEntry 填充_KTRAP_FRAME 後續部分

這兩個函數雖然入口不同,但是填充完 _KTRAP_FRAME 後,就會執行相同的代碼。

預備知識:

eax中存儲的系統服務号 0BAh

edx存儲的三環的參數指針

系統服務表

_KTHREAD+0xE0= +0x0e0 ServiceTable : Ptr32 Void

有兩張系統服務表,第一張是用來找核心函數的,第二張是找Win32k.sys驅動函數的

結構:0x10大小

typedef struct _SERVICE_DESCRIPTOR_TABLE
{
    PULONG ServiceTableBase;			// 指針,指向函數位址,每個成員占4位元組
    PULONG ServiceCounterTableBase;		// 目前系統服務表被調用的次數
    ULONG  NumberOfService;				// 服務函數的總數
    PUCHAR ParamTableBase;				// 服務函數的參數總長度,以位元組為機關,每個成員占一個位元組
    									// 如:服務函數有兩個參數,每個參數占四位元組,那麼對應參數總長度為8
    									// 函數位址成員 與 參數總長度成員 一一對應
} SSDTEntry, *PSSDTEntry;

           
  1. 系統服務表裡的函數都是來自核心檔案導出的函數
  2. 它并不包含核心檔案導出的所有函數,而是3環最常用的核心函數
SSDT表

全稱:System Services Descriptor Table(系統服務描述符表)

SSDT的每個成員叫做系統服務表

檢視SSDT表

kd> dd nt!KeServiceDescriptorTable
           
核心學習-系統調用下系統調用的學習

第二張表為0,使用KeServiceDescriptorTable這個公開的導出函數,我們無法看到win32k.sys這張表結構

核心學習-系統調用下系統調用的學習

win32k.sys系統服務表已經可見

系統服務号:低12位就是函數參數表和函數位址表的下标,而第13位(下标12)如果是0,表示找第一張系統服務表Ntoskrl.exe,如果是1,那麼找第二張表win32k.sys.後12位是函數位址表和函數參數表的索引。

分析

.text:00407781
.text:00407781 loc_407781:                             ; CODE XREF: _KiBBTUnexpectedRange+18↑j
.text:00407781                                         ; _KiSystemService+6E↑j
.text:00407781                 mov     edi, eax					;eax中是系統服務号
.text:00407783                 shr     edi, 8						;edi右移8位
.text:00407786                 and     edi, 30h					;判斷系統服務号12位,0:edi == 0x00 ;1:edi == 0x10
.text:00407789                 mov     ecx, edi
.text:0040778B                 add     edi, [esi+0E0h];		[esi+0E0h]:_KTHREAD+0xE0=ServiceTable,edi指向系統服務表,這裡将系統服務表所在位址直接加上edi的運算結果,巧妙地得到要查哪張表(兩張表是連續的),每張表占16位元組
.text:00407791                 mov     ebx, eax
.text:00407793                 and     eax, 0FFFh				;與運算後,隻保留系統服務号低12位
.text:00407798                 cmp     eax, [edi+8]				;edi指向系統服務表,[edi+8]:NumberOfService,判斷要找的函數是否超出範圍
.text:0040779B                 jnb     _KiBBTUnexpectedRange	;若大于系統調用号的個數則跳轉,即系統調用号越界
.text:004077A1                 cmp     ecx, 10h					;ecx 儲存的是 edi 與0x30與運算後的結果,隻能是0x00或0x10
.text:004077A4                 jnz     short loc_4077C0		;若系統調用号小于0x1000,則跳轉
.text:004077A6                 mov     ecx, ds:0FFDFF018h		;隻有當ecx == 0x10才會向下執行,作用是動态加載GUI等圖形相關函數
.text:004077AC                 xor     ebx, ebx
.text:004077AE
.text:004077AE loc_4077AE:                             ; DATA XREF: _KiTrap0E+110↓o
.text:004077AE                 or      ebx, [ecx+0F70h]
.text:004077B4                 jz      short loc_4077C0
.text:004077B6                 push    edx
.text:004077B7                 push    eax
.text:004077B8                 call    ds:_KeGdiFlushUserBatch
.text:004077BE                 pop     eax
.text:004077BF                 pop     edx
.text:004077C0
.text:004077C0 loc_4077C0:                             ; CODE XREF: _KiFastCallEntry+B4↑j
.text:004077C0                                         ; _KiFastCallEntry+C4↑j
.text:004077C0                 inc     dword ptr ds:0FFDFF638h;
.text:004077C6                 mov     esi, edx						;edx:三環參數指針
.text:004077C8                 mov     ebx, [edi+0Ch]			; [edi+0Ch]:ParamTableBase(參數表指針)
.text:004077CB                 xor     ecx, ecx						;eax儲存的是3環傳入的系統調用号
.text:004077CD                 mov     cl, [eax+ebx]				;eax儲存的是3環傳入的系統調用号,ebx儲存的是是參數表指針,這條指令的目的是得到核心函數的參數總長度,存入cl
.text:004077D0                 mov     edi, [edi]						;取出系統調用表的第一個成員(函數位址指針)
.text:004077D2                 mov     ebx, [edi+eax*4]			 ;函數位址指針 + 系統調用号*4(乘4是因為每個成員占4位元組),ebx中存入函數位址
.text:004077D5                 sub     esp, ecx 						;提升堆棧,提升高度為cl,目的是要把三環堆棧中的參數存進來
.text:004077D7                 shr     ecx, 2 							;參數總長度/4=參數個數
.text:004077DA                 mov     edi, esp					;設定參數的0環堆棧位址
.text:004077DC                 cmp     esi, ds:_MmUserProbeAddress	;判斷esi與使用者程式能通路的最大位址範圍,是否越界
.text:004077E2                 jnb     loc_407990 					;如果越界了 進行跳轉,處理異常
.text:004077E8
.text:004077E8 loc_4077E8:                             ; CODE XREF: _KiFastCallEntry+2A4↓j
.text:004077E8                                         ; DATA XREF: _KiTrap0E+106↓o
.text:004077E8                 rep movsd						;複制參數(執行幾次取決于參數個數<-004077D7結果 )到0環的堆棧
.text:004077EA                 call    ebx 						;調用核心函數NtReadVirtualMemory

           

實驗:

檢視函數位址:

核心學習-系統調用下系統調用的學習

[函數位址表 + 系統服務号*4] = 核心函數位址 805aa712

核心學習-系統調用下系統調用的學習

檢視參數位址

核心學習-系統調用下系統調用的學習

[參數表 + 系統服務号] = 核心函數參數個數(機關:位元組)14

核心學習-系統調用下系統調用的學習

檢視核心函數反彙編:

核心學習-系統調用下系統調用的學習