先簡單介紹下PatchGuard ,摘自百度百科
PatchGuard就是Windows Vista的內核保護系統,防止任何非授權軟件試圖“修改”Windows內核,也就是說,Vista內核的新型金鍾罩。
PatchGuard為Windows Vista加入一個新安全操作層,此前我們為您介紹過的ASLR(Address Space Layout Randomization)亦在這個安全層之下。
PatchGuard能夠有效防止內核驅動模式改動或替換Windows內核的任何內容,第三方軟件將無法再給Windows Vista內核添加任何“補丁”。
就是微軟從x64結構體系開始加的一層保護技術,對內核關鍵位置進行檢測,如果發現內核關鍵位置被修改就直接藍屏,而且在x64下還引入了DES,即驅動的加載需要數字簽名。我們在x64下就無法在像x86下那樣"為所欲為"了。比如x86下玩的超級Happy的重載內核在x64下基本不可能了,SSDT不能hook了,DebugPort不能清零了等等。但是在Win7 x64出來沒多久 國外的大牛FYYRE就放出了內核破解工具,這里給出鏈接 http://fyyre.ivory-tower.de/ 隨后就有大牛公布了源代碼,我也只是學習大牛的源代碼,記錄自己的學習歷程。
先貼上FYYRE的原文
//Disable PatchGuard - the easy/lazy way. //for Vista SP2 & Windows 7 (X64) // //by Fyyre (thank you Roxaz for helping me to test) //http://fyyre.l2-fashion.de/ //http://twitter.com/Fyyre last update: 19/03/2011 This txt file provides a general overview/outline for bypassing signature validation of critical system files (ntoskrnl, mainly) during the Vista/Win 7 boot phase. It is documentation of the steps taken from start to finish, to reach the desired goal of removing kernel patch protection "PatchGuard" without use of a driver. We will call this the 'lazy/easy' way to kill PatchGuard. We cannot modify ntoskrnl without winload taking up issue... winload.exe is the Windows loader for Vista & Windows 7. Along with this, he makes some verification of digital signatures and checking to make sure the files have not been modified. If modification of ntoskrnl is detected, the result is winload *refusing* to boot Windows and launching a WinPE looking "Recovery Mode". PART I { additional }: new way for patch of winload.exe Function ImgpValidateImageHash - signature we locate: 8B C3 49 8B 5B 20 49 8B 73 28 49 8B 7B 30 4D 8B -- you may play with this one to make him smaller. as for this patching, use of dUP2... size of not a concern. First bytes replaced with xor eax, eax (STATUS_SUCCESS) .. all validations successful. PART I: disassembly and modification of winload.exe Starting from OslpMain, after loading the System registry hives(registry)... occurs a call to OslInitializeCodeIntegrity: .text:00000000004016C3 call OslpLoadSystemHive .text:00000000004016C3 .text:00000000004016C8 cmp eax, ebx .text:00000000004016CA mov edi, eax .text:00000000004016CC jl loc_401A08 .text:00000000004016CC .text:00000000004016D2 mov ecx, ebp .text:00000000004016D4 call OslInitializeCodeIntegrity <<-- =( .text:00000000004057E8 OslInitializeCodeIntegrity proc near original code -->> We will replace four bytes here: 48 8B C4 53 .text:00000000004057E8 mov rax, rsp .text:00000000004057EB push rbx .text:00000000004057EC push rbp with: 0B0h, 01h, 0C3h, 090h ... which produce: mov al, 1 ret nop Save as winload.exe as osloader.exe (or whatever..) & correct PE checksum (LordPE and/or CFF_Explorer will do). Copy osloader.exe to \Windows\System32 PART II - new BCD entry: bcdedit /copy {current} /d "PatchGuard Disabled" "The entry was successfully copied to {01234567-89ab-cdef-00ff-fff000ffffff}" <<-- GUID of new entry. each is different! bcdedit /timeout 10 <<-- number of seconds to show boot menu. bcdedit /set {01234567-89ab-cdef-00ff-fff000ffffff} nointegritychecks 1 <<-- no validation of winload bcdedit /set {01234567-89ab-cdef-00ff-fff000ffffff} recoveryenabled 0 <<-- optional... i dislike this feature, therefore disable. bcdedit /set {01234567-89ab-cdef-00ff-fff000ffffff} path \Windows\system32\osloader.exe bcdedit /set {01234567-89ab-cdef-00ff-fff000ffffff} kernel ntkrnlmp.exe (name of modified ntos... =)) Part III: Skip Initialization of PatchGuard - - (driver not required) As for this .txt, and PatchGuard... we are concerned with one function KiInitializePatchGuard(*1) which is called by KiFilterFiberContext. KiInitializePatchGuard is a very large function located in the INIT section of ntoskrnl, you can easily locate him via two calls from KiFilterFiberContext, by examination xrefs to exported dword InitSafeBootMode, searching for db 20h dup(90h) + db 044h ... or 48 81 EC 58 0F 00 00 to name a few... PatchGuard does not initialize if we boot into safe mode. So to disable we just patch one conditional jxx KiInitializePatchGuard: original code -->> INIT:000000014055D359 sub rsp, 0F58h INIT:000000014055D360 xor edi, edi INIT:000000014055D362 cmp cs:InitSafeBootMode, edi INIT:000000014055D368 jz short loc_14055D371 INIT:000000014055D368 INIT:000000014055D36A mov al, 1 INIT:000000014055D36C jmp loc_1405600D9 modified code -->> INIT:000000014055D359 sub rsp, 0F58h INIT:000000014055D360 xor edi, edi INIT:000000014055D362 cmp cs:InitSafeBootMode, edi INIT:000000014055D368 nop INIT:000000014055D369 nop INIT:000000014055D36A mov al, 1 INIT:000000014055D36C jmp loc_1405600D9 <<-- to end of KiInitializePatchGuard and back to KiFilterFiberContext... and important detail: The first jxx in KiInitializePatchGuard must not be taken & al == 1. When we return to KiFilterFiberContext, the jxx must be taken, and EBX must not be xor'd ... (unless enjoy BSOD). INIT:0000000140567110 loc_140567110: INIT:0000000140567110 test al, al INIT:0000000140567112 jnz short loc_140567116 INIT:0000000140567112 INIT:0000000140567114 INIT:0000000140567114 loc_140567114: INIT:0000000140567114 xor ebx, ebx <<-- bad INIT:0000000140567114 Anyways... nop the first jxx in KiInitializePatchGuard... save modified ntoskrnl.exe with a different name (i.e. ntkrnlmp.exe) ... fix checksum (PE header). Then copy your modified kernel to \Windows\system32 -- with bcdedit -->> bcdedit /set {guid-of-new-entry} kernel ntkrnlmp.exe When you reboot the system, loading your modified kernel should be a success... He will load without PatchGuard initializing, which will allow you to once again play in kernel mode without receiving BSOD as result... This could be worked into mbr bootkit code as well... this is beyond the scope of our intention. -Fyyre references: *1: Bypassing PatchGuard on Windows x64, by Skywing 12/1/2005
根據文章我們先將winload.exe放入ida中,根據文章中定位到OslpMain函數(這里我已經導入了winload.exe的符號表)
.text:00000000004016BE 4C 8B C6 mov r8, rsi .text:00000000004016C1 8B CD mov ecx, ebp .text:00000000004016C3 E8 94 04 00 00 call OslpLoadSystemHive //加載注冊表單元 .text:00000000004016C8 3B C3 cmp eax, ebx .text:00000000004016CA 8B F8 mov edi, eax .text:00000000004016CC 0F 8C 36 03 00 00 jl loc_401A08 .text:00000000004016D2 8B CD mov ecx, ebp .text:00000000004016D4 E8 03 41 00 00 call OslInitializeCodeIntegrity
發現加載了注冊表單元之后調用了OslInitializeCodeIntegrity函數,我們繼續跟進
原來的代碼
.text:00000000004057DC OslInitializeCodeIntegrity proc near .text:00000000004057DC 48 8B C4 mov rax, rsp .text:00000000004057DF 53 push rbx .text:00000000004057E0 55 push rbp .text:00000000004057E1 57 push rdi .text:00000000004057E2 41 54 push r12
我們要做的就是替換掉最開始的一個字節,讓整個函數不再向下執行,因為在接下來會調用BlImgQueryCodeIntegrityBootOptions,因為BlImgQueryCodeIntegrityBootOptioins會校驗Ntoskrnl.exe的數字簽名的有效性,如果非法的話就拒絕加載Ntoskrnl.exe,我們需要繞過這個函數
.text:00000000004057FB 48 8D 50 10 lea rdx, [rax+10h] .text:00000000004057FF 4C 89 68 20 mov [rax+20h], r13 .text:0000000000405803 49 8B FD mov rdi, r13 .text:0000000000405806 4C 89 68 C8 mov [rax-38h], r13 .text:000000000040580A E8 21 B6 02 00 call BlImgQueryCodeIntegrityBootOptions
所以在OllInitializeCodeIntegrity 函數開始部分就直接返回,跳過BlImgQueryCodeIntegrityBootOptioins
將 48 8B C4 mov rax, rsp 替換成 B0 01 mov al , 1 C3 ret
接下來就是Ntoskrnl.exe了
根據文章中的說明,定位到KiFilterFiberContext函數,發現對KiInitializePatchGuard的調用
INIT:0000000140577106 8B D1 mov edx, ecx INIT:0000000140577108 41 8B C9 mov ecx, r9d INIT:000000014057710B E8 30 62 FF FF call KiInitializePatchGuard //這里是我自己重命名了,本來的只是一個地址,符號表中沒有
在KiInitializePathcGuard函數開始的地方就對啟動模式進行了檢測
NIT:000000014056D360 33 FF xor edi, edi INIT:000000014056D362 39 3D 88 21 D1 FF cmp cs:InitSafeBootMode, edi //檢測是否以安全模式啟動,如果以安全模式啟動PatchGuard就不會被初始化 INIT:000000014056D368 74 07 jz short loc_14056D371 //這里的跳轉才是對PatchGuard就行正在初始化,我們將其nop掉 INIT:000000014056D36A B0 01 mov al, 1
INIT:000000014056D36C E9 68 2D 00 00 jmp loc_1405700D9 //直接跳轉到KiInitilizePatchGuard函數的結尾,不初始化
然后就是保存,然后在啟動項中添加我們自己的“內核”。