Posts

軟件調試(12) - Win32堆,CRT堆簡介及堆溢出攻擊及系統檢測溢出方案

Win32堆與CRT堆 ------------------------------------------------ 堆分配函數: malloc / HeapAlloc/ new 堆的基本運作: 內存管理器(Memory Manager)把一塊較大的內存空間,委托給堆管理器(Heap Manager)來管理,堆管理器將大塊內存分割成不同大小的很多個小塊來滿足應用程序的需要 而實現內存委托的一系列函數,稱為池管理器(Pool Manager) Windows在創建進程時,加載器函數執行進程用戶態初始化階段會調用RtlCreateHeap函數為新的進程創建第一個堆 稱為默認堆 默認堆: 由LdrpInitializeProcess所調用RtlCreateHeap建立 此時新進程中只有EXE模塊和NTDLL模塊,EXE模塊中的用戶代碼還未執行,創建好的堆句柄會存放在PEB中ProcessHeap字段, 與棧類似也有HeapSegmentReserve和HeapSegmentCommit兩個字段來決定默認堆的保留大小和提交大小 分配私有Win32堆: 用戶透過HeapCreate函數創建自己的堆 函數原型: HANDLE WINAPI HeapCreate( _In_ DWORD flOptions, _In_ SIZE_T dwInitialSize, _In_ SIZE_T dwMaximumSize ); 刪除則是調用: BOOL WINAPI HeapDestroy( _In_ HANDLE hHeap ); 堆列表: 每個進程的PEB結構以列表方式記錄當前進程的所有堆句柄: NumberOfHeap 是堆總數 ProcessHeaps 每個堆的句柄,它是一個數組 MaximumNumberOfHeaps 可分配堆總數 如果NumberOfHeap == MaximumNumberOfHeaps 堆管理器則增大MaximumNumberOfHeaps 的值並重新分配ProcessHeaps 分配堆空間: 使用HeapAlloc可以在指定堆中分配空間 函數原形: LPVOID WINAPI HeapAlloc( _In_ HANDLE hHeap, _In_ DWORD dwFlags,...

軟件調試(11) - 棧安全檢查,溢出及緩沖區溢出

用戶態及內核態棧 -------------------------------------------- TSS會記錄了不同優先級所使用的棧的基本信息 TSS+0x4 到 TSS+0x28的24字節是用來記錄棧的段信息和棧指針ss:esp 每個Win32線程都有兩個棧: 一是用戶態棧,記錄在_TEB->_NT_TIB 一是內核態棧,記錄在_KTHREAD 他們記著線程棧的詳細資料 用戶態棧- 1MB x86內核態棧-12KB x64內核態棧-24KB 考慮到gui線程在調用gdi服務時通常需要更大的棧段空間,所以在一個線程被轉為GUI線程後,內核態棧一般會被替換成一個更新的新棧 -------------------------------------------- 內核棧的創建: PspCreateThread是Windows內核態用於創建線程的一個重要內部函數 不論是PspCreateSystemThread或NtCreateThread 由PspCreateThread創建內核態棧,大小總是默認大小的內核態棧 但Windows線程在第一次調用Win32子系統服務時,將其轉變為GUI線程->轉化後系統的PsConvertToGuiThread函數會為該線程重新建立一個棧,然後使用KeSwitchKernelStack切換到新的棧,新的棧是可以改變大小的,稱為大內核態棧(Large Kernel Stack) 棧大小的最大值記錄在MmLargeStackSize 在一個線程被轉變為GUI線程 其KTHREAD結構的LargeStack會改為1 同時其Win32Thread字段會由0變為非0 棧段不會立即增大,在需要增大時調用MmGrowKernelStack函數來增長棧 ------------------------------------------------------- 用戶態棧的創建 初始線程: CreateProcess->NtCreateProcess->BaseCreateStack(調用NtCreateThread前)初始化用戶態棧 初始線程外: CreateThread / CreateRemoteThread->BaseCreateSt...

軟件調試(10) - 棧和函數調用

用戶態及內核態棧 -------------------------------------------- TSS會記錄了不同優先級所使用的棧的基本信息 TSS+0x4 到 TSS+0x28的24字節是用來記錄棧的段信息和棧指針ss:esp 每個Win32線程都有兩個棧: 一是用戶態棧,記錄在_TEB->_NT_TIB 一是內核態棧,記錄在_KTHREAD 他們記著線程棧的詳細資料 用戶態棧- 1MB x86內核態棧-12KB x64內核態棧-24KB 考慮到gui線程在調用gdi服務時通常需要更大的棧段空間,所以在一個線程被轉為GUI線程後,內核態棧一般會被替換成一個更新的新棧 -------------------------------------------- 內核棧的創建: PspCreateThread是Windows內核態用於創建線程的一個重要內部函數 不論是PspCreateSystemThread或NtCreateThread 由PspCreateThread創建內核態棧,大小總是默認大小的內核態棧 但Windows線程在第一次調用Win32子系統服務時,將其轉變為GUI線程->轉化後系統的PsConvertToGuiThread函數會為該線程重新建立一個棧,然後使用KeSwitchKernelStack切換到新的棧,新的棧是可以改變大小的,稱為大內核態棧(Large Kernel Stack) 棧大小的最大值記錄在MmLargeStackSize 在一個線程被轉變為GUI線程 其KTHREAD結構的LargeStack會改為1 同時其Win32Thread字段會由0變為非0 棧段不會立即增大,在需要增大時調用MmGrowKernelStack函數來增長棧 ------------------------------------------------------- 用戶態棧的創建 初始線程: CreateProcess->NtCreateProcess->BaseCreateStack(調用NtCreateThread前)初始化用戶態棧 初始線程外: CreateThread / CreateRemoteThread->BaseCreateSt...

軟件調試(9) - 深入探討Windows結構化異常(SEH)底層實現

r3/r0一樣, FS:[0] 保存著SEH的鏈表頭 應用層: TEB與TIB結構 TEB中的起始處是指向TIB的地址,TIB第一個字段位exceptionList即為鏈表表頭 內核層 KPCR與TIB結構 KPCR->TIB TIB的ExceptionList字段 ------------------------------------------------------- 該字段位於TIB的起始處 typedef struct _EXCEPTION_REGISTERATION_RECORD{ struct _EXCEPTION_REGISTERATION_RECORD *next; //0xFFFFFFFF代表最後一個節點 ULONG handler; //異常處理器的地址(需符合seh函數原形) } EXCEPTION_DISPOSITION SehHandler(_EXCEPTION_RECORD *exceptionRecord, //處理的異常 void * EstablisherFrame, //異常函數的EBP _CONTEXT *contextRecord, //線程上下文 void * DispatcherContext //分發函數 ) TIB自身不在棧中,而SEH鏈表則是存在棧中 登記異常函數 ------------------------------------------------------- push seh_handler //處理函數地址 棧空間: push FS:[0] //舊的鏈表節點處理器地址 FS:[0] move FS:[0],ESP //登記新結構 SEH_HANDLER ..... mov esp,dword ptr fs:[0] //保存下一個結構地址 pop dword ptr fs:[0] //將下一個結構的地址變成鏈表頭 用戶態版本RtlDispatchException ------------------------------------------------------- (內核中的異常分發:修改EIP到R3的KiUserExceptionDispatcher->)RtlD...

軟件調試(8) - 探討從應用層到內核層的中斷與異常管理

硬件異常 IDT 在idtr讀取idt表基址 ------------------------- 門描述符: 任務門 - 用於任務切換 里面包含用於選擇任務狀態段(tss)的段選擇子 中斷門 - 用於描述中斷處理例程入口 陷阱門 - 用於描述異常處理例程入口 任務門: 描述的是一個TSS段->CPU要做的是切換到這個TSS段所代表的線程,然後開始執行這個線程,TSS段是用來保存任務信息的一段內存區,其格式由CPU定義 Windows會為每個CPU創建3-4個tss 1: 處理NMI 2: 處理#DF(double fault) 異常中再異常 3: 處理機器檢查異常 軟件異常 -------------------------- EXCEPTION_RECORD 結構 typdef struct _EXCEPTION_RECORD{ DWORD ExceptionCode //異常代碼 DWORD ExceptionFlags //異常標志 struct _EXCEPTION_RECORD* ExceptionRecord; //相關的另一個異常 PVOID ExceptionAddress; //異常發生地址 DWORD NumberParameters; //參數數組元素 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //參數數組 }EXCEPTION_RECORD, *PEXCEPTION_RECORD; #define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT #define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP 登記CPU異常 --------------------------- KiTrapXX例程在完成針對本異常的動作後,會調用CommonDispatchException->KiDispatchException 並通過寄存器將如下信息傳送到函數 1. 異常代碼->EAX 2. 異常指令地址->EBX 3. 其他信息作為附帶參數(最多3個),EDX(參數1),ESI(參數2),...

軟件調試(7) - 調試體系之內核調試原理

內核調試器通過內核調試引擎 控制或調試內核 內核其他部份->內核調試引擎->內核調試器 調試器通過內核調試協議 訪問和控制目標系統 內核調試API: KdAPI - 類似遠程調用方式訪問內核 與系統內核的接口函數 與調試器通信函數 斷點管理 - 使用KdpBreakpointTable記錄斷點 內核調試api - 提供調試信息給內核調試引擎 系統內核控制函數 - KdEnterDebugger 與 KdExitDebugger 管理函數 - KdEnableDebugger 與KdDisableDebugger ETW支持函數 - event log... 驅動程序更新服務 - 本地內核調試支持(XP後) kdcom.dll 負責通信部份 收/發數據包 - KdSendPacket - KdReceivePacket 接收電源狀態變化 - KdD0Transition ,喚醒系統用 - KdD3Transition ,休眠時用 內核調試引擎初始化: BIOS->Harddisk引導程式->執行NTLDR.exe->CPU初始化->切換保護模式->啟用分頁機制->通過配置boot.ini得到windows系統的系統目錄並加載系統內核文(ntoskrnl.exe)先檢查他的導入表並加載依賴文(包括內核調試通信模塊KDCOM.dll)->讀取注册表的hive->加載其中定義的啟動類型的驅動程序->完成所有工作->找到內核文件的PE文件頭找到入口函數->kISystemStartup->進入初始化三部曲-> 1. 調用HalInitializeProcessor() 初始化CPU 2. 調用KdInitSystem 初始化內核調試引擎 3. 調用KiInitializeKenrel開始內核初始化 KiInitializeKenrel->KeInitializeThread -> ExpInitializeExecutive() ExpInitializeExecutive進行大量工作包括進程管理器初始化: 進程管理器初始化: - 定義進程/線程內核對象類型 - 建立記錄系統中所有進程的鏈...

軟件調試(6) - 深入探討調試體系啟動及附加調試

用戶 <=== UI線程 <=== 調試器 ===> 調試工作線程 ===> 被調試進程 (獲取調試對象) (設置調試對象) 調試器 ----------------------------------------------------------------- DbgSsReserved[0] => 被調試線程鏈表頭 DbgSsReserved[1] => 調試對象的句柄 //判斷是否句柄 !handle xxxxx 鏈表頭結構: typedef struct _DBGSS_THREAD_DATA { struct _DBGSS_THREAD_DATA *Next; HANDLE ThreadHandle; HANDLE ProcessHandle; DWORD ProcessID; DWORD ThreadID; BOOLEAN HandleMarked; //退出標志 }DBGSS_THREAD_DATA,*PDBGSS_THREAD_DATA; WaitForDebugEvent , ContinueDebugEvent 會維護DbgSsReserved[0]鏈表 WinXP=> Ntdll!DbgUiGetThreadDebugObject 和Ntdll!DbgUiSetThreadDebugObject 實際上就是讀寫鏈表 WaitForDebugEvent => 從teb獲取調試對象 DbgSsReserved[1] 由kernel32的調試API所設置, 如果Windbg不是調用他來調試 *而CreateProcess時R3層會把他設置為非0 但在CreateProcess後Windbg會調用DbgUiSetThreadDebugObject設置為0 被調試進程 和原本進程的差異 ------------------------------------------------------------------ 1. EPROCESS Debugport字段不為0, 內核空間判斷一個進程是否正在被調試的主要特征 2. PEB的BeingDebugged字段不為0, 用戶態判斷是否正在被調試的主要方法 3. 可...