0x00
一、Windows API編程相關知識
- Windows的工作模式、Windows的內存管理、異常處理
- Windows應用程序的編程環境
- Win32彙編程序結構
- Windows API
二、Win32彙編語言程序設計 - 80x86處理器寄存器
- IA-32指令系統,標號、變量和數據結構
- 使用子程序(參數傳遞、堆棧平衡等)
0x01
Windows工作模式及內存管理
1、Windows系統的特點
- 圖形用戶界面。告別命令行,所見即所得;
- 多任務系統。多個程序同時運行,提高效率;
- 大量的函數調用。程序員可把精力放在程序邏輯結構和用戶界面上;
- 和設備的無關性。應用程序不用關心具體的硬件型號;
- 內存管理。內存分頁和虛擬內存,4GB地址空間。
2、 Windows工作模式 - 實模式 :提供不受保護的段,用於實現早期處理器的16位執行環境;使用20位地址線。
- 保護模式:32位地址線,尋址空間達到4GB。支持多任務和程序優先級。保護模式出現的原因是:保護進程地址空間。
- 虛擬86模式:是以任務形式在保護模式上執行。支持任務切換和內存分頁。虛擬86模式採用和實模式一樣的尋址方式,尋址空間爲1MB=1024KB。
注意:實模式可以切換到保護模式,保護模式可以和虛擬86模式相互切換,從實模式切換到保護模式是通過控制寄存器CR0的控制位PE。不支持從實模式直接切換到虛擬86模式。
Windows工作模式比較:
注意:虛擬86模式以保護模式爲基礎,是以任務形式在保護模式上執行。利用分頁機制,將不同虛擬86任務的地址空間映射到不同物理地址上。每個虛擬86任務都認爲自己在使用獨享的1MB地址空間。
0x02
Windows的內存管理
實模式下的內存尋址方式: 實模式支持內存分段模型。邏輯地址由16位段選擇器和16位段內偏移地址組成。16位段選擇器用於確定一個20位的段基址;再與16位段內偏移地址相加,得到邏輯地址對應的線性地址。由於段內偏移地址是16位的,因此,線性地址空間由一系列64KB大的段組成(一個地址上存放一個字節)。實模式不支持內存分頁,因此,線性地址即爲物理地址。
注:xxxx:yyyy格式的虛擬地址在內存中的實際位置是:xxxx*10h+yyyy
20位地址線,尋址空間1M
保護模式下內存尋址:
- 保護模式支持內存分段模型。保護模式與實模式的主要區別在於:段寄存器中存放的不再是段基址,而是描述符表的索引。保護模式下對內存的分段是強制的,分頁是可選的。
- 保護模式下內存尋址時,16位的段寄存器存放的不是段基地址,而是描述符表的索引地址,段內偏移地址長度32位;段描述符是64位,因爲需要包含地址空間定義的一些安全屬性;
- GDT/GDTR, LDT/LDTR;
- 段選擇器高13位表示索引,第0,1位表示段選擇器的請求特權級,第2位TI表示段描述符的位置:TI=0表示在GDT中,TI=1表示在LDT中。
- 段描述符中的32位線性基地址與32位段內偏移地址相加,得到線性地址,如果不分頁則線性地址與物理地址直接對應。
- 保護模式下,線性地址空間大小爲4G,32位地址線。
注意:保護模式下,16位的段寄存器存放的不是段地址,而是段選擇器;
段選擇器高13位表示索引,第0,1位表示城區的當前優先級,第2位TI表示段描述符的位置
全局描述符表GDT:
在 32 位保護模式下,段地址是 32 位的線性地址,如果未開啓分頁功能,該線性地址就是物理地址。
保護模式下,16位的段寄存器存放的不是段地址,而是段選擇器;
段選擇器高13位表示索引,第2位TI表示段描述符的位置內存分頁機制:
CR0寄存器中第31位(PG位)決定是否分頁:
- PG=0不啓用分頁,線性地址即爲物理地址;
- PG=1啓用分頁,線性地址經過頁表映射得到物理地址;
- 一級頁表的映射:
32位虛擬內存地址=20位頁表索引+12位頁內偏移 - 二級頁表的映射方式:
32位虛擬內存地址=10位頁目錄索引+10位頁表索引+12位頁內偏移
從Windows的內存安排看Win32編程中的幾個重要概念:
- 每個應用程序都有自己的4GB尋址空間,用於存放操作系統、系統DLL、用戶的DLL代碼,應用程序代碼、數據等。
- 不同應用程序的線性地址空間是隔離的。在某個程序所屬的時間片中,其他程序的代碼和數據沒有被映射到可尋址的線性地址中,所以是不可訪問的。
- DLL程序沒有自己的私有空間,它們總被映射到其他應用程序的地址空間中,當做其他應用程序的一部分運行。
0x03
Windows的特權保護
80386實模式下的中斷和異常處理:
- 發生n號中斷或異常,或者執行到int n 指令時,CPU到n*4的地址取出中斷服務程序地址;
- 將標誌寄存器、CS,IP寄存器值壓入堆棧;
- 執行中斷服務程序;
- 服務程序執行到iret時,CPU從堆棧中彈出標誌寄存器、取出CS、IP並返回。
注:每個中斷向量4字節
80386保護模式下的中斷和異常處理:
-
異常處理往往是從用戶程序切換到系統程序,低優先級切換到高優先級;
-
那麼,怎樣確保高優先級代碼能夠安全的被低優先級代碼調用?
-
中斷門,自陷門,任務門
-
中斷描述符:門的種類&入口地址,8字節,放在中斷描述符表中
80386的保護機制: -
段的類型檢查:
段的類型由段描述符指定,主要屬性有是否可執行,是否可讀寫。
CS/DS/SS等段選擇器是否能裝入某種類型的段描述符是有限制的。
例如,不可執行的段不能裝入CS;不可寫的段不能裝入SS。 -
訪問數據時的級別檢查:
低優先級的代碼不能訪問高優先級的數據段。
80386 GDT中的DPL域(描述符優先級)指定了這個段可以被訪問的最低優先級;
段選擇器中的RPL域(請求優先級)指定了當前執行代碼的優先級;
DPL≥RPL,該段才能訪問,否則產生保護異常;
0x04
Windows應用程序的編程環境
MASM編譯器和鏈接器:
0x05
Win32彙編程序結構
-
使用的指令集
內存模式:win32 程序代碼和數據使用同一個4GB段;CS/DS/SS/ES全部使用平坦模式
子程序/API調用方式:參數傳遞、堆棧平衡 -
.data/.data?/.const/.code.data
可讀可寫的已定義變量, .data段存放在可執行文件的_data節區
.data?可讀可寫的未初始化數據段, .data?段存放在可執行文件的_BSS節區
.const不能寫的常量段 -
代碼段一般放在PE文件的_TEXT節區;
程序在運行時,代碼段可寫嗎?
For example,UPX…….
0x06
Windows API
- API(應用程序接口)是windows操作系統提供的一套編程函數庫,提供應用程序運行所需的窗口管理,圖形設備接口、內存管理等各項服務功能。這些函數採用DLL實現。
- Win32 API的核心由三個DLL提供:
KERNEL 32.DLL——系統服務功能。任務管理,動態鏈接、內存管理等
GDI32.DLL——圖形設備接口。利用顯卡驅動程序顯示文本、圖像等
USER32.DLL——用戶服務接口。建立窗口、傳送消息等 - 調用API的過程:利用堆棧傳遞參數,調用者把參數壓入堆棧,DLL中的函數再從堆棧中取出參數處理。
注意:在源程序編譯鏈接程可執行文件後,call MessageBox語句中的MessageBox會被換成一個指向可執行文件導入表的地址。而導入表中指向MessageBox函數的實際地址由系統根據User32.dll在內存中的位置動態填入。
API函數的返回值:
- 返回值存放在eax寄存器中;如果返回的內容超過了一個eax所能容納的長度,怎麼辦?
- Answer:Win32 API採用的方法一般是eax中返回一個指向返回數據的指針。
Win32 環境下,和字符串相關的API函數有兩類,分別對應不同字符集:
ANSI字符集:每個字符一個字節寬,API函數名尾部帶“A”
Unicode字符集:每個字符兩個字節寬, API函數名尾部帶“W” - User32.dll中只有MessageBoxA和MessageBoxW,why源程序中仍可以用MessageBox?
- include語句:將程序調用到的API函數所在的DLL文件包含進來
include <DLL名.inc> 例如: include <user32.inc>
Includelib語句:告訴鏈接器在鏈接的時候到指定的庫文件中去找API函數的位置
includelib 庫文件名 例如: includelib user32.lib
0x07
80x86處理器的寄存器
通用寄存器、指令寄存器、段寄存器、標誌寄存器、系統地址寄存器(GDTR/LDTR)、控制寄存器(CR0,CR2,CR3)
CR0:保護模式允許位、任務切換位
CR1:頁故障地址寄存器
CR2:頁表目錄寄存器,存放頁表目錄的物理基地址
-
指令指針寄存器
32位指令指針寄存器EIP存放指令指針,即當前代碼段中將被執行的下一條指令的線性地址偏移。程序運行時,CPU根據CS段寄存器和EIP寄存器的地址偏移讀取下一條指令,然後將EIP寄存器的值自增,增大的大小爲被讀取指令的字節數。
EIP寄存器更改的途徑:一是通過跳轉和函數調用返回指令JMP,CALL,RET等,二是通過中斷或異常進行修改。 -
段寄存器
6個16位的段寄存器: CS,SS,DS,ES,FS,GS分別用於存儲保護模式下邏輯地址中的段選擇器。
代碼段寄存器CS:存放應用程序代碼所在的段的段描述符索引(代碼段線性基址),CS+EIP得到下一條指令的線性地址。
棧段寄存器SS:存放棧段的段描述符索引(棧段的線性基址)
數據段寄存器(DS,ES,FS,GS):DS數據段含有程序使用的大部分數據;ES數據段可以爲某些串指令存放目的數據;FS段寄存器可用於計算結構化異常處理SEH, 線程環境塊TEB,進程環境塊PEB。
0x08
IA-32指令系統
以funadd(arg1,arg2)爲例,在Win32環境下,採用stdcall調用方式,堆棧的變化過程:
要求:能夠根據彙編指令分析出堆棧內容、堆棧指針的整個變化過程