Windows系统调用学习笔记(一)—— API函数调用过程
Windows系統(tǒng)調(diào)用學(xué)習(xí)筆記(一)—— API函數(shù)調(diào)用過程
- Windows API
- 實驗1:分析ReadProcessMemory
- 第一步:定位函數(shù)
- 第二步:開始分析
- 總結(jié)
- 實驗2:分析NtReadVirtualMemory
- 第一步:定位函數(shù)
- 第二步:開始分析
- 總結(jié)
- 實驗3:編寫一個ReadProcessMemory函數(shù)
- 第一步:獲得變量地址
- 第二步:構(gòu)造自定義ReadProcessMemory
- 第三步:調(diào)用自定義ReadProcessMemory
Windows API
描述:
Application Programming Interface,簡稱 API 函數(shù)。
Windows有多少個API?
主要是存放在 C:\WINDOWS\system32 下面所有的dll
幾個重要的DLL
Kernel32.dll:最核心的功能模塊,比如管理內(nèi)存、進程和線程相關(guān)的函數(shù)等
User32.dll:是Windows用戶界面相關(guān)應(yīng)用程序接口,如創(chuàng)建窗口和發(fā)送消息等
GDI32.dll:全稱是Graphical Device Interface(圖形設(shè)備接口),包含用于畫圖和顯示文本的函數(shù)。比如要顯示一個程序窗口,就調(diào)用了其中的函數(shù)來畫這個窗口
Ntdll.dll:大多數(shù)API都會通過這個DLL進入內(nèi)核(0環(huán))
實驗1:分析ReadProcessMemory
第一步:定位函數(shù)
第二步:開始分析
-
首先將我們傳入的參數(shù)進行壓棧
-
調(diào)用了其它模塊的函數(shù):NtReadVirtualMemory(函數(shù)名紅色說明不在當(dāng)前模塊)
-
若返回結(jié)果小于0,跳轉(zhuǎn)至loc_7C802204
loc_7C802204調(diào)用了sub_7C809419 -
sub_7C809419內(nèi)部調(diào)用了另一個函數(shù)RtlNtStatusToDosError
這個函數(shù)的作用是設(shè)置錯誤號 -
從sub_7C809419出來后,將eax清零,跳轉(zhuǎn)到loc_7C802F9
loc_7C802F9只做了一件事情,那就是返回
至此,我們可以知道,當(dāng)調(diào)用ReadProcessMemory失敗時,返回結(jié)果為0 -
若NtReadVirtualMemory返回結(jié)果大于等于0,返回結(jié)果為1
總結(jié)
實驗2:分析NtReadVirtualMemory
第一步:定位函數(shù)
這4行代碼就是NtReadVirtualMemory的所有代碼
第二步:開始分析
-
mov eax, 0BAh
0BAh:編號,對應(yīng)操作系統(tǒng)內(nèi)核中某個函數(shù)的編號
我們所用到的API函數(shù),只要進0環(huán),都要提供一個編號 -
mov edx, 7FFE0300h
7FFE0300h:函數(shù)地址,該函數(shù)決定了我們用什么方式進0環(huán) -
該函數(shù)的功能:提供一個編號和一個函數(shù),通過這個函數(shù)進入0環(huán)
總結(jié)
真正讀取進程內(nèi)存的函數(shù)在0環(huán)實現(xiàn),我們所用的函數(shù)只是系統(tǒng)提供給我們的函數(shù)接口
實驗3:編寫一個ReadProcessMemory函數(shù)
要求:不使用任何DLL,直接調(diào)用0環(huán)函數(shù)
意義:自己實現(xiàn)的API,可以避免3環(huán)程序被惡意掛鉤
第一步:獲得變量地址
運行以下代碼(進程1):
#include <stdio.h>int main() {int num = 0x12345678;printf("&num = %x \n", &num);getchar();return 0; }運行結(jié)果:
注意:不要讓進程結(jié)束
第二步:構(gòu)造自定義ReadProcessMemory
代碼如下
void MyReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) {__asm{lea eax, [ebp+0x14]push eax ; ReturnLengthpush [ebp+0x14] ; BufferLengthpush [ebp+0x10] ; Bufferpush [ebp+0x0C] ; BaseAddresspush [ebp+0x08] ; ProcessHandlemov eax, 0BAhmov edx, espint 02eh ; Windows操作系統(tǒng)提供IDT[0x2e]給用戶進行內(nèi)核調(diào)用add esp, 20} }第三步:調(diào)用自定義ReadProcessMemory
完整代碼(進程2):
void MyReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead) {__asm{lea eax, [ebp+0x14]push eax ; ReturnLengthpush [ebp+0x14] ; BufferLengthpush [ebp+0x10] ; Bufferpush [ebp+0x0C] ; BaseAddresspush [ebp+0x08] ; ProcessHandlemov eax, 0BAhmov edx, espint 02eh ; Windows操作系統(tǒng)提供IDT[0x2e]給用戶進行內(nèi)核調(diào)用add esp, 20} }int main() {DWORD pBuffer; // 接收數(shù)據(jù)的緩沖區(qū)HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, PID); // 獲得進程句柄,PID修改為進程1的PIDMyReadProcessMemory(hProcess, (PVOID)0x12ff7c, &pBuffer, 4, 0); // 調(diào)用自定義的ReadProcessMemoryprintf("pBuffer = %x \n", pBuffer); // 打印從其他進程中讀取的數(shù)據(jù)getchar();return 0; }運行結(jié)果:
成功從進程1中讀取了變量num的值!
總結(jié)
以上是生活随笔為你收集整理的Windows系统调用学习笔记(一)—— API函数调用过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows保护模式学习笔记(十四)—
- 下一篇: Windows系统调用学习笔记(二)——