API函数的调用过程
API函數的調用過程(ring3)
Windows API
Application Programing Interface (應用程序接口) 簡稱API函數
Windows 有多少個API?
主要是存放在C:\WINDOWS\system32下面所有的dll
幾個重要的dll
Kernel32.dll:最核心的功能模塊,比如管理內存,進程和線程相關的函數等.
User32.dll:是Windows用戶界面相關的應用程序接口,如創建窗口和發送消息等.
GDI32.dll全稱是Graphical Device Interface(圖形設備接口),包含用于畫圖和顯示
Ntdll.dll:大多數API都會通過這個dll進入內核(0環)
絕大部分核心功能是在0環實現的,3環只是使用了0環提供給他的一個接口.
Kernel32.dll ->ReadProcessMemory
在C:\WINDOWS\system32\目錄下找到kernel32.dll模塊,放到IDA中 查看ReadProcessMemory的代碼
我們看到在用戶層的核心功能模塊中的ReadProcessMemory函數再將參數壓棧后,又調用了另一個模塊的函數NtReadVirtualMemory
ReadProcessMemory:
ring3所做的事情:
接下來看看NtReadVirtualMemory函數 (ring 0)所做的事情
這時候再打開另一個ntdll.dll模塊 查看其中的NtReadVirtualMemory函數:
這個函數傳進去一個調用號,以及一個地址,再去call這個地址中的值,這個值就是存在于內核的一個函數.
//這個函數的功能: 提供編號 找到函數 通過函數進入ring 0也就是說ntdll也只是做了個引薦人的功能,引薦進ring 0真正對內存讀寫是在ring 0實現的
那就再繼續跟跟看7FFE0300處的值是什么?
再繼續跟7c92e4f0:
這就跟到了sysenter 匯編指令:
該匯編指令的作用是?:
通過寄存器,切換EIP,ESP
1.將IA32_SYSENTER_CS 和IA32_SYSENTER_EIP分別裝到cs和eip寄存器中2.將IA32_SYSENTER_CS+8 和IA32_SYSENTER_ESP 分別裝載到ss和esp寄存器中,切換特權級0;之后程序在ring 0環境下跳轉到指定eip去執行,執行結束后使用sysexit 匯編指令返回,這條指令功能與sysenter相反:
1.將IA32_SYSENTER_CS+16裝載到cs寄存器,將edx寄存器中的指令的指針裝載到eip;2.將IA32_SYSENTER_CS+24裝載到ss寄存器中;3.cx寄存器中的指針裝載到esp中,切換到特權3IA32_SYSENTER_CS之類的屬于MSR寄存器KiFastSystemCall,KiIntSystemCall
操作系統會檢測CPU支不支持快速調用,如果支持,就會調用KiFastSystemCall 進ring 0,如果CPU比較老舊不支持快速調用 就會調用 KiIntSystemCall去進入ring 0
在ntdll.dll模塊中找到該函數
發現他的本質其實還是調用了int 2e 號中斷進入的ring 0
我們現在嘗試在ntoskrnl.exe模塊中查看一下int 2e是怎么進ring 0的?
SEP位
那CPU到底是怎么驗證支不支持KiFastSystemCall的呢?
CPUID 指令 //該指令需要傳入一個參數 //當eax = 1 來執行cpuid指令時,處理器的特征信息被放在ecx,和edx寄存器中,其中edx包含了一個SEP位(11位),該位指明了當前處理器是否支持當SEP位 == 1 時,說明是支持的
1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 15 11 0這兩種的區別
KiIntSystemCall:
這個主要是使用INT 2E 中斷門去做,中斷門中CS,EIP都已經在IDT表中存儲好了,SS與ESP需要TSS提供,所以使用一次int 2e 會讀取IDT中的CS,和查找TSS
KiFastSystemCall:
sysenter : 系統會提前將CS/SS/ESP/EIP的值存儲在MSR寄存器中,sysenter指令執行時,會將MSR寄存器值直接寫入相關寄存器,直接就是寄存器的讀,沒有讀內存的過程,這是快速調用的本質。
_KUSER_SHARED_DATA
這個結構體是在User層和Kernel層分別定義了一個_KUSER_SHARED_DATA結構體 用于User和Kernel層共享某些數據
他們使用固定的地址值映射,_KUSER_SHARED_DATA結構區域在User和Kernel層地址分別為:
User 層地址為:0x7ffe0000
Kernel層地址為:0xffdf0000
注意:雖然指向同一個物理頁,但在User層是只讀的,在Kernel層是可讀寫的
回到上面的內容:
也就是說,call這個地址里的內容,我們并不能武斷的就說這里面一定是什么,CPU新舊不同,可能會導致調用的函數是不同的.有可能是KiFastSystemCall,也有可能是KiIntSystemCall
附件:
| IA32_SYSENTER_CS | 174H |
| IA32_SYSENTER_ESP | 175H |
| IA32_SYSENTER_EIP | 176H |
SS = CS + 8
可以通過RDMSR/WRMST 來進行讀寫(操作系統使用WRMST寫該寄存器)
內核模塊:
ntoskrnl.exe(CPU以10-10-12分頁模式啟動) ntkrnlpa.exe(CPU以2-9-9-12分頁模式啟動)總結
以上是生活随笔為你收集整理的API函数的调用过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器人学导论原书第三版
- 下一篇: Xilinx SDK 初学之–API函数