Windows内核系统调用分析
系統(tǒng)調(diào)用
? ? 進(jìn)程 ——> 調(diào)用OS API;OS進(jìn)程管理 ——> 調(diào)配進(jìn)程。
? ? 僅從用戶進(jìn)程角度,OS就像是一個(gè)被動響應(yīng)的運(yùn)行時(shí)庫。Windows提供了一個(gè)系統(tǒng)調(diào)用界面作為外層,即Win32API;Linux的CRuntime庫標(biāo)準(zhǔn),Windows也支持。用戶進(jìn)程通過調(diào)用這些OS接口,可以部分操作系統(tǒng)內(nèi)核。
? ? 硬件] 設(shè)備驅(qū)動] 核心層] 管理層] 系統(tǒng)服務(wù)界面,中斷入口(不公開)] 系統(tǒng)DLL(公開)] ——>API
? ? 用戶進(jìn)程沒有調(diào)用內(nèi)核函數(shù)(特權(quán)指令)的權(quán)限,只有調(diào)用API,通過API函數(shù)內(nèi)的“自陷中斷”進(jìn)入“系統(tǒng)態(tài)”調(diào)用系統(tǒng)函數(shù)。或者是“異常中斷”出錯進(jìn)入OS運(yùn)行。
? Win32API{
? __asm{
? push ?ebp ? KiSystemService()
? mov ?eax, ?151 ?//系統(tǒng)函數(shù)號 ?{ ?中斷,保護(hù)CPU環(huán)境,進(jìn)入系統(tǒng)態(tài)
? lea ? ?edx, 9[ebp] //用戶區(qū)參數(shù)棧地址 ?copy棧參數(shù)塊到系統(tǒng)內(nèi)存
? int ? ?0x2e //中斷id,進(jìn)入IDT表對應(yīng)函數(shù) ——> ? ?執(zhí)行eax寄存器里的id調(diào)用函數(shù)
? pop ?ebp ? 返回結(jié)果,copy回用戶區(qū)
? ret ? 10 //返回結(jié)果參數(shù),9+1 ?關(guān)中斷,基本是開頭的逆操作 ? ? ? ? ? ? ? ? ?}
? }
? } //如果用戶參數(shù)少,可以直接在寄存器中傳,用戶指定fastcall方式
??
? ? 除外部IO外,自陷和異常也是IDT表中的中斷項(xiàng)(255個(gè),外設(shè)中斷預(yù)留100個(gè)左右),自陷中斷有:
? int ?0x3 (2c\ 2d) ? KiTrap3() ,DEBUG調(diào)試用
? 0x2e ? ?KiSystemService() ,系統(tǒng)函數(shù)調(diào)用
? 0x2b 內(nèi)核可以調(diào)用用戶空間的子程序,子程序執(zhí)行完再返回內(nèi)核,就用這個(gè)中斷
? 0x2a 獲取精確CPU時(shí)間,輕型調(diào)用,普通中斷開銷大,無法取到精確的時(shí)間 ?
? ? 通常的特權(quán)指令調(diào)用都通過KiSystemService() ,通過系統(tǒng)函數(shù)調(diào)用號id跳轉(zhuǎn)到函數(shù)地址上。Windows核心和Liunx類似,有200多個(gè)核心函數(shù),但MS又把視窗界面函數(shù)也移入內(nèi)核中。
另外:不同的用戶進(jìn)程,有各自的系統(tǒng)堆棧空間,供其調(diào)用的內(nèi)核函數(shù)使用(是彼此獨(dú)立的)。
windows內(nèi)核情景分析--系統(tǒng)調(diào)用?
Windows的地址空間分用戶模式與內(nèi)核模式,低2GB的部分叫用戶模式,高2G的部分叫內(nèi)核模式,位于用戶空間的代碼不能訪問內(nèi)核空間,位于內(nèi)核空間的代碼卻可以訪問用戶空間
一個(gè)線程的運(yùn)行狀態(tài)分內(nèi)核態(tài)與用戶態(tài),當(dāng)指令位于用戶空間時(shí),就表示當(dāng)前處于內(nèi)核態(tài),當(dāng)指令位于內(nèi)核空間時(shí),就處于內(nèi)核態(tài).
一個(gè)線程由用戶態(tài)進(jìn)入內(nèi)核態(tài)的途徑有3種典型的方式:
1、 主動通過int 2e(軟中斷自陷方式)或sysenter指令(快速系統(tǒng)調(diào)用方式)調(diào)用系統(tǒng)服務(wù)函數(shù),主動進(jìn)入內(nèi)核
2、 發(fā)生異常,被迫進(jìn)入內(nèi)核
3、 發(fā)生硬件中斷,被迫進(jìn)入內(nèi)核
現(xiàn)在討論第一種進(jìn)入內(nèi)核的方式:(又分為兩種方式)
1、 通過老式的int 2e指令方式調(diào)用系統(tǒng)服務(wù)(因?yàn)槔鲜絚pu沒提供sysenter指令)
如ReadFile函數(shù)調(diào)用系統(tǒng)服務(wù)函數(shù)NtReadFile
Kernel32.ReadFile() ?//點(diǎn)號前面表示該函數(shù)的所在模塊
{
//所有Win32 API通過NTDLL中的系統(tǒng)服務(wù)存根函數(shù)調(diào)用系統(tǒng)服務(wù)進(jìn)入內(nèi)核
NTDLL.NtReadFile();
}
NTDLL.NtReadFile()
{
? ?Mov eax,152 ? //我們要調(diào)用的系統(tǒng)服務(wù)函數(shù)號,也即SSDT表中的索引,記錄在eax中
? ?If(cpu不支持sysenter指令)
? ?{
? ? ? Lea edx,[esp+4] //用戶空間中的參數(shù)區(qū)基地址,記錄在edx中
? ? ? Int 2e ?//通過該自陷指令方式進(jìn)入KiSystemService,‘調(diào)用’對應(yīng)的系統(tǒng)服務(wù)
? ?}
? ?Else
? ?{
? ? ? Lea edx,[esp +4] //用戶空間中的參數(shù)區(qū)基地址,記錄在edx中
? ? ? Sysenter //通過sysenter方式進(jìn)入KiFastCallEntry,‘調(diào)用’對應(yīng)的系統(tǒng)服務(wù)
? ?}
? ?Ret 36 //不管是從int 2e方式還是sysenter方式,系統(tǒng)調(diào)用都會返回到此條指令處
}
Int 2e的內(nèi)部實(shí)現(xiàn)原理:
該指令是一條自陷指令,執(zhí)行該條指令后,cpu會自動將當(dāng)前線程的當(dāng)前棧切換為本線程的內(nèi)核棧(棧分用戶棧、內(nèi)核棧),保存中斷現(xiàn)場,也即那5個(gè)寄存器。然后從該cpu的中斷描述符表(簡稱IDT)中找到這個(gè)2e中斷號對應(yīng)的函數(shù)(也即中斷服務(wù)例程,簡稱ISR),jmp 到對應(yīng)的isr處繼續(xù)執(zhí)行,此時(shí)這個(gè)ISR本身就處于內(nèi)核空間了,當(dāng)前線程就進(jìn)入內(nèi)核空間了
Int 2e指令可以把它理解為intel提供的一個(gè)內(nèi)部函數(shù),它內(nèi)部所做的工作如下
Int 2e
{
? ?Cli ?//cpu一中斷,立馬自動關(guān)中斷
? ?Mov esp, TSS.內(nèi)核棧地址 //切換為內(nèi)核棧,TSS中記錄了當(dāng)前線程的內(nèi)核棧地址
? ?Push SS
? ?Push esp
? ?Push eflags
? ?Push cs
Push eip ?//這5項(xiàng)工作保存了中斷現(xiàn)場【標(biāo)志、ip、esp】
Jmp ?IDT[中斷號] ?//跳轉(zhuǎn)到對應(yīng)本中斷號的isr
}
明白了IDT,就可以看到0x2e號中斷的isr為KiSystemService,顧名思義,這個(gè)中斷號專用于提供系統(tǒng)服務(wù)。
https://www.cnblogs.com/jadeshu/articles/10663613.html
利用Windbg初步解析系統(tǒng)調(diào)用
https://cloud.tencent.com/developer/news/240246
Windbg初步解析系統(tǒng)調(diào)用
其實(shí)我以前沒怎么用過,編程的時(shí)候很少調(diào)試,即便調(diào)試也是依賴編譯器的調(diào)試。
最近要解析系統(tǒng)調(diào)用,解析的時(shí)候出了點(diǎn)問題,沒有辦法解析到NtReadFile系統(tǒng)調(diào)用中讀的內(nèi)容。這事兒很奇怪,其他的系統(tǒng)調(diào)用都可以解析到,這個(gè)就不行。
于是,我寫了一個(gè)簡單的讀文件程序進(jìn)行測試。代碼如下
代碼很簡單,就不說了。64位debug模式下編譯通過后,用windbg打開,
設(shè)置斷點(diǎn):bu ntdll!ZwReadFile
執(zhí)行g(shù)命令,開始運(yùn)行
連續(xù)按F10執(zhí)行到syscall完成
R命令查看寄存器值
dq rsp+0x30得到buffer地址
da [buffer地址] 就可以看到buffer的內(nèi)容了。如下所示,內(nèi)容很簡單,是“1 2 3 4 5 6 7 8 9 0”,和我在hello.txt中寫入的一樣。
總結(jié)
以上是生活随笔為你收集整理的Windows内核系统调用分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows内核对象管理
- 下一篇: Flex和Bison简介和Windows