intel sysret 漏洞在WIN7 X64下的實(shí)現(xiàn)分析。前半部分是網(wǎng)上現(xiàn)有的文章分析,后半部分為代碼實(shí)現(xiàn)分析
1. 漏洞淺析
在x64系統(tǒng)上,最重要的48位虛擬地址將被用于地址轉(zhuǎn)換,而此外48到63的任何虛擬地址必須是47位的副本。否則處理器會(huì)拋出異常:保護(hù)故障(GP)。
這會(huì)將虛擬地址分割位兩個(gè)區(qū)塊,如:
· 規(guī)范的高階半?yún)^(qū): 0xFFFFFF`FFFFFFFF 0xFFFF8000`00000000
· 規(guī)范的低階半?yún)^(qū): 0x00007FFF`FFFFFFFF 0x00000000`00000000
而所有這之間的地址都會(huì)被認(rèn)為是不規(guī)范的。
SYSRET指令被用于傳遞返回到普通用戶模式(user-mode)。它將RCX寄存器中的值復(fù)制到RIP寄存器中,并把Code Segment Selector位切換位普通用戶模式(user-mode)。然而,RCX寄存器是一個(gè)通用寄存器,它可能包含的任何值,包括不規(guī)范的地址。并且SYSRET指令一旦拋出異常是不負(fù)責(zé)退棧切換回用戶空間的,也不負(fù)責(zé)為GS寄存器做掃尾工作。這意味著,程序員在調(diào)用SYSRET指令前后都需要為GS,RSP,RBP做額外的處理。
而我們恰好發(fā)現(xiàn)intel的SYSRET指令實(shí)現(xiàn)中存在一個(gè)缺陷: 如果一個(gè)不規(guī)范的地址從RCX寄存器傳遞而拋出GP, 那么在CG,RBP和RSP返回普通用戶模式(user-mode)前, 其ring0的權(quán)限不會(huì)被取締(因?yàn)闆](méi)有任何掃尾工作)。
2. MS windows中的漏洞觸發(fā)
利用這個(gè)漏洞的關(guān)鍵是要拋出一個(gè)不規(guī)范的返回地址,而為了在MS Windows中觸發(fā)這個(gè)漏洞,我們可以有以下的方式:
· 映射內(nèi)存并在0x7FFF`FFFFFFFF位執(zhí)行一個(gè)系統(tǒng)調(diào)用。這將返回一個(gè)不規(guī)范的地址。然而,由于Windows地址空間的限制,這個(gè)地址是不可達(dá)的,因此此路不通羅馬。
· 尋找一個(gè)系統(tǒng)調(diào)用,并能手動(dòng)改變返回地址。
關(guān)于后者,可借力于UMS(User-Mode Scheduling 用戶模式計(jì)劃程序)。
PS: MSDN,UMS是一個(gè)輕量級(jí)的機(jī)制,應(yīng)用程序可以用它來(lái)安排自己的線程。應(yīng)用程序可以在用戶模式下自由進(jìn)行UMS線程間的切換而不必不涉及系統(tǒng)調(diào)度。
為了使用UMS線程,可以用CreateUmsCompletionList()函數(shù)創(chuàng)建一個(gè)的UMS調(diào)度列表。scheduler線程將被鏈接到此調(diào)度列表,而scheduler線程也將需要被創(chuàng)建(scheduler線程通過(guò)EnterUmsSchedulingMode()從普通線程晉升為UMS線程)。
如果UMS線程啟動(dòng)或阻塞,那么ExecuteUmsThread()函數(shù)需要被調(diào)用。如果沒(méi)有, scheduler需要確定哪些線程將隨后運(yùn)行。它將排列調(diào)度列表,選擇正確的線程。
EnterUmsSchedulingMode()函數(shù)是ntdll.dll中實(shí)現(xiàn)的。從匯編代碼中,我們可以看到,它得到當(dāng)前的UMS線程,完成鏈接調(diào)度列表,保存線程上下文(寄存器),然后調(diào)用RtlpUmsPrimaryContextWrap()函數(shù)。
1. .text:0000000078F33A20 RtlEnterUmsSchedulingMode
2. .text:0000000078F33A20
3. .text:0000000078F33A20 arg_0 = qword ptr 8
4. .text:0000000078F33A20 arg_8 = qword ptr 10h
5. .text:0000000078F33A20 arg_10 = qword ptr 18h
6. .text:0000000078F33A20
7. .text:0000000078F33A20 mov [rsp+arg_8], rbx
8. .text:0000000078F33A25 mov [rsp+arg_10], rsi
9. .text:0000000078F33A2A push rdi
10. .text:0000000078F33A2B sub rsp, 20h
11. .text:0000000078F33A2F mov rsi, [rcx+8]
12. .text:0000000078F33A33 mov rbx, [rcx+10h]
13. [...]
14. .text:0000000078F33A5D loc_78F33A5D:
15. .text:0000000078F33A5D mov rdx, rsi
16. .text:0000000078F33A60 xor ecx, ecx
17. .text:0000000078F33A62 call RtlpAttachThreadToUmsCompletionList
18. .text:0000000078F33A67 test eax, eax
19. .text:0000000078F33A69 js short loc_78F33AA0
20. .text:0000000078F33A6B lea rcx, [rsp+28h+arg_0]
21. .text:0000000078F33A70 call RtlGetCurrentUmsThread
22. .text:0000000078F33A75 test eax, eax
23. .text:0000000078F33A77 js short loc_78F33A94
24. .text:0000000078F33A79 mov rcx, [rsp+28h+arg_0]
25. .text:0000000078F33A7E call RtlpSaveUmsdebugRegisterState
26. .text:0000000078F33A83 test eax, eax
27. .text:0000000078F33A85 js short loc_78F33A94
28. .text:0000000078F33A87 mov rdx, rdi
29. .text:0000000078F33A8A mov rcx, rbx
30. .text:0000000078F33A8D call RtlpUmsPrimaryContextWrap
31. .text:0000000078F33A92 jmp short $+2
RtlpUmsPrimaryContextWrap()函數(shù)負(fù)責(zé)調(diào)用scheduler并保存線程信息在一個(gè)結(jié)構(gòu)中(ps:這是一個(gè)非文檔化的結(jié)構(gòu)),通過(guò)反匯編我們可以知道此結(jié)構(gòu)為:
RSP
RBP
返回地址
1. .text:0000000078EA03F0 RtlpUmsPrimaryContextWrap
2. .text:0000000078EA03F0
3. .text:0000000078EA03F0 var_108 = xmmword ptr -108h
4. .text:0000000078EA03F0 var_F8 = xmmword ptr -0F8h
5. .text:0000000078EA03F0 var_E8 = xmmword ptr -0E8h
6. .text:0000000078EA03F0 var_D8 = xmmword ptr -0D8h
7. .text:0000000078EA03F0 var_C8 = xmmword ptr -0C8h
8. .text:0000000078EA03F0 var_38 = byte ptr -38h
9. [...]
10. .text:0000000078EA0452 mov [rax+30h], r15
11. .text:0000000078EA0456 mov r10, gs:14A0h
12. .text:0000000078EA045F lea r10, [r10+10h]
13. .text:0000000078EA0463 lea r11, loc_78EA0493
14. .text:0000000078EA046A mov [r10+0D0h], rcx //這里將被HOOK
15. .text:0000000078EA0471 mov [r10+0A0h], rbp
16. .text:0000000078EA0478 mov [r10+98h], rsp
17. .text:0000000078EA047F mov [r10+0F8h], r11 // saved return
18. .text:0000000078EA0486 mov r12, 0
19. .text:0000000078EA048D xor r13, r13
20. .text:0000000078EA0490 mov r14, rdx
21. .text:0000000078EA0493
22. .text:0000000078EA0493 loc_78EA0493:
23. .text:0000000078EA0493 mov r10, gs:14A0h
24. .text:0000000078EA049C lea r10, [r10+10h]
25. .text:0000000078EA04A0 mov r11, [r10+0D0h] // scheduler func
26. .text:0000000078EA04A7 mov rcx, r12
27. .text:0000000078EA04AA mov rdx, r13
28. .text:0000000078EA04AD mov r8, r14
29. .text:0000000078EA04B0 call r11 // calls the scheduler function
30. .text:0000000078EA04B3 lea rcx, [rsp+138h+var_38]
31. .text:0000000078EA04BB movaps xmm6, [rsp+138h+var_108]
32. .text:0000000078EA04C0 movaps xmm7, [rsp+138h+var_F8]
如果我們調(diào)試內(nèi)核,在Ntoskrnl.exe的KeBuildPrimaryThreadContext()函數(shù)處設(shè)置bp,我們可以看到0x00000000`78EA0493被保存為返回到用戶空間的地址。
1. PAGE:FFFFF80002C5A070 KeBuildPrimaryThreadContext
2. PAGE:FFFFF80002C5A070
3. PAGE:FFFFF80002C5A070 arg_0 = qword ptr 8
4. PAGE:FFFFF80002C5A070 arg_20 = qword ptr 28h
5. PAGE:FFFFF80002C5A070 arg_28 = qword ptr 30h
6. PAGE:FFFFF80002C5A070
7. PAGE:FFFFF80002C5A070 mov [rsp+arg_0], rbx
8. PAGE:FFFFF80002C5A075 movsxd rbx, r9d
9. PAGE:FFFFF80002C5A078 mov r9, rdx
10. PAGE:FFFFF80002C5A07B xor r10d, r10d
11. PAGE:FFFFF80002C5A07E mov rax, [rcx+1B8h]
12. PAGE:FFFFF80002C5A085 mov r11, [rax]
13. PAGE:FFFFF80002C5A088 cmp r8, r10
14. PAGE:FFFFF80002C5A08B jz loc_FFFFF80002C5A168
15. [...]
16. PAGE:FFFFF80002C5A168 loc_FFFFF80002C5A168:
17. PAGE:FFFFF80002C5A168 mov rdx, [rdx+50h]
18. PAGE:FFFFF80002C5A16C mov rcx, [r9+58h]
19. PAGE:FFFFF80002C5A170 mov rax, [r11+108h]
20. PAGE:FFFFF80002C5A177 mov [rdx+168h], rax // saved RIP
21. PAGE:FFFFF80002C5A17E mov rax, [r11+0A8h]
22. PAGE:FFFFF80002C5A185 mov [rdx+180h], rax
23. PAGE:FFFFF80002C5A18C mov rax, [r11+0B0h]
24. PAGE:FFFFF80002C5A193 mov [rdx+158h], rax
25. PAGE:FFFFF80002C5A19A mov eax, 33h ; '3'
26. PAGE:FFFFF80002C5A19F mov [rdx+170h], ax
27. PAGE:FFFFF80002C5A1A6 mov eax, 2Bh ; '+'
28. PAGE:FFFFF80002C5A1AB mov [rdx+188h], ax
我們的想法是在ExecuteUmsThread()調(diào)用前破壞這個(gè)地址為非規(guī)范地址。而在用戶態(tài)的scheduler中,返回地址保存在: GS:[0x14a0] + 0x10 + 0x1F處。
內(nèi)核調(diào)度結(jié)束后,ntoskrnl.exe中的KiUmsFastReturnToUser()函數(shù)被調(diào)用。在調(diào)用SYSRET指令前, RSP, RBP和GS將會(huì)被重置為他們之前保存的副本,返回用戶態(tài)的地址也被移入RCX寄存器。
1. .text:FFFFF800028DD440 KiUmsFastReturnToUser
2. .text:FFFFF800028DD440
3. .text:FFFFF800028DD440 var_5046 = dword ptr -5046h
4. .text:FFFFF800028DD440 var_4FA6 = byte ptr -4FA6h
5. .text:FFFFF800028DD440 arg_42 = byte ptr 52h
6. .text:FFFFF800028DD440 arg_80 = byte ptr 88h
7. .text:FFFFF800028DD440 arg_190 = dword ptr 198h
8. .text:FFFFF800028DD440
9. .text:FFFFF800028DD440 sub rsp, 28h
10. .text:FFFFF800028DD444 mov rbx, gs:+188h
11. .text:FFFFF800028DD44D mov rcx, [rbx+1D8h]
12. .text:FFFFF800028DD454 lea rbp, [rcx+80h]
13. .text:FFFFF800028DD45B mov rax, cr8
14. [...]
15. .text:FFFFF800028DD596 loc_FFFFF800028DD596:
16. .text:FFFFF800028DD596 mov r8, [rbp+100h] // saved RSP
17. .text:FFFFF800028DD59D mov r9, [rbp+0D8h] // saved RBP
18. .text:FFFFF800028DD5A4 xor edx, edx
19. .text:FFFFF800028DD5A6 pxor xmm0, xmm0
20. .text:FFFFF800028DD5AA pxor xmm1, xmm1
21. .text:FFFFF800028DD5AE pxor xmm2, xmm2
22. .text:FFFFF800028DD5B2 pxor xmm3, xmm3
23. .text:FFFFF800028DD5B6 pxor xmm4, xmm4
24. .text:FFFFF800028DD5BA pxor xmm5, xmm5
25. .text:FFFFF800028DD5BE mov rcx, [rbp+0E8h] // saved ret address
26. .text:FFFFF800028DD5C5 mov r11, [rbp+0F8h]
27. .text:FFFFF800028DD5CC mov rbp, r9
28. .text:FFFFF800028DD5CF mov rsp, r8
29. .text:FFFFF800028DD5D2 swapgs // switch GS to user
30. .text:FFFFF800028DD5D5 sysret
31. .text:FFFFF800028DD5D8 db 66h, 66h, 66h, 66h, 66h, 66h
32. .text:FFFFF800028DD5D8 nop word ptr [rax+rax+00000000h]
33. .text:FFFFF800028DD5E7 db 66h, 66h, 66h, 66h, 66h, 66h
但是,如果此時(shí)RCX是不規(guī)范的,那么GP異常將在特權(quán)模式下被拋出。
3. Windows 7 & Windows 2008 R2 x64下的利用
GP異常拋出時(shí),RSP和RBP可控,GS指向用戶態(tài),PFH(protection fault handler)則被指向KiGeneralProtectionFault()函數(shù)
一種利用此漏洞的方式,是利用已控的RBP和RBP。因?yàn)镵iGeneralProtectionFault()將會(huì)把值寫入堆棧,且堆棧也是可控的;谶@些我們可以試試write-4 techniques。
ps: write-4 techniques - http://immunityinc.com/infiltrate/archives/kernelpool_infiltrate2011.pdf
1. .text:FFFFF800028DBAC0 KiGeneralProtectionFault
2. .text:FFFFF800028DBAC0
3. .text:FFFFF800028DBAC0 var_12D = byte ptr -12Dh
4. .text:FFFFF800028DBAC0 var_12C = dword ptr -12Ch
5. .text:FFFFF800028DBAC0 var_128 = qword ptr -128h
6. .text:FFFFF800028DBAC0 var_120 = qword ptr -120h
7. .text:FFFFF800028DBAC0 var_118 = qword ptr -118h
8. .text:FFFFF800028DBAC0 var_110 = qword ptr -110h
9. .text:FFFFF800028DBAC0 var_108 = qword ptr -108h
10. .text:FFFFF800028DBAC0 var_100 = qword ptr -100h
11. .text:FFFFF800028DBAC0 var_F8 = qword ptr -0F8h
12. .text:FFFFF800028DBAC0 var_E8 = xmmword ptr -0E8h
13. .text:FFFFF800028DBAC0 var_D8 = xmmword ptr -0D8h
14. .text:FFFFF800028DBAC0 var_C8 = xmmword ptr -0C8h
15. .text:FFFFF800028DBAC0 var_B8 = xmmword ptr -0B8h
16. .text:FFFFF800028DBAC0 var_A8 = xmmword ptr -0A8h
17. .text:FFFFF800028DBAC0 var_98 = xmmword ptr -98h
18. .text:FFFFF800028DBAC0 var_58 = word ptr -58h
19. .text:FFFFF800028DBAC0 arg_0 = qword ptr 10h
20. .text:FFFFF800028DBAC0 arg_8 = byte ptr 18h
21. .text:FFFFF800028DBAC0 arg_10 = qword ptr 20h
22. .text:FFFFF800028DBAC0 arg_24 = dword ptr 34h
23. .text:FFFFF800028DBAC0
24. .text:FFFFF800028DB600 push rbp
25. .text:FFFFF800028DB601 sub rsp, 158h
26. .text:FFFFF800028DB608 lea rbp, [rsp+80h]
27. .text:FFFFF800028DB610 mov [rbp+0D8h+var_12D], 1
28. .text:FFFFF800028DB614 mov [rbp+0D8h+var_128], rax
29. .text:FFFFF800028DB618 mov [rbp+0D8h+var_120], rcx
30. .text:FFFFF800028DB61C mov [rbp+0D8h+var_118], rdx
31. .text:FFFFF800028DB620 mov [rbp+0D8h+var_110], r8
32. .text:FFFFF800028DB624 mov [rbp+0D8h+var_108], r9
33. .text:FFFFF800028DB628 mov [rbp+0D8h+var_100], r10
34. .text:FFFFF800028DB62C mov [rbp+0D8h+var_F8], r11
35. .text:FFFFF800028DB630 test [rbp+0D8h+arg_8], 1
36. .text:FFFFF800028DB637 jz short loc_FFFFF800028DB65A
37. .text:FFFFF800028DB639 swapgs
38. .text:FFFFF800028DB63C mov r10, gs:188h
39. .text:FFFFF800028DB645 test byte ptr [r10+3], 3
40. .text:FFFFF800028DB64A mov [rbp+0D8h+var_58], 0
然而,因?yàn)槟繕?biāo)內(nèi)存周圍數(shù)據(jù)已被破壞,這使得此exp方法不可靠。
一個(gè)更好的方法是利用指向用戶空間的GS。我們的思路是,欺騙內(nèi)核調(diào)用GS中索引的函數(shù)。這種功能可以觸發(fā)頁(yè)錯(cuò)誤處理程序(所有這一切需要做的是產(chǎn)生此異常)。
1. .text:FFFFF800028DB65A cld
2. .text:FFFFF800028DB65B stmxcsr [rbp+0D8h+var_12C]
3. .text:FFFFF800028DB65F ldmxcsr dword ptr gs:180h
4. .text:FFFFF800028DB668 movaps [rbp+0D8h+var_E8], xmm0
5. .text:FFFFF800028DB66C movaps [rbp+0D8h+var_D8], xmm1
6. .text:FFFFF800028DB670 movaps [rbp+0D8h+var_C8], xmm2
7. .text:FFFFF800028DB674 movaps [rbp+0D8h+var_B8], xmm3
8. .text:FFFFF800028DB678 movaps [rbp+0D8h+var_A8], xmm4
9. .text:FFFFF800028DB67C movaps [rbp+0D8h+var_98], xmm5
10. .text:FFFFF800028DB680 mov eax, [rbp+0E0h]
11. .text:FFFFF800028DB686 test [rbp+0D8h+arg_10], 200h
12. .text:FFFFF800028DB691 jz short loc_FFFFF800028DB694
13. .text:FFFFF800028DB693 sti
14. .text:FFFFF800028DB694 loc_FFFFF800028DB694:
15. .text:FFFFF800028DB694 mov r10, [rbp+0D8h+arg_0]
16. .text:FFFFF800028DB69B mov r9, cr4
17. .text:FFFFF800028DB69F mov r8, cr0
18. .text:FFFFF800028DB6A3 mov edx, 8
19. .text:FFFFF800028DB6A8 mov ecx, 7Fh
20. .text:FFFFF800028DB6AD call KiBugCheckDisPatch
此函數(shù)叫做 KeBugCheckEx()
1. .text:FFFFF800028DD180 KiBugCheckDispatch
2. .text:FFFFF800028DD180
3. .text:FFFFF800028DD180 var_118= qword ptr -118h
4. .text:FFFFF800028DD180 var_108= xmmword ptr -108h
5. .text:FFFFF800028DD180 var_F8= xmmword ptr -0F8h
6. .text:FFFFF800028DD180 var_E8= xmmword ptr -0E8h
7. .text:FFFFF800028DD180 var_D8= xmmword ptr -0D8h
8. .text:FFFFF800028DD180 var_C8= xmmword ptr -0C8h
9. .text:FFFFF800028DD180 var_38= byte ptr -38h
10. .text:FFFFF800028DD180
11. .text:FFFFF800028DD180 sub rsp, 138h
12. .text:FFFFF800028DD187 lea rax, [rsp+138h+var_38]
13. .text:FFFFF800028DD18F movaps [rsp+138h+var_108], xmm6
14. .text:FFFFF800028DD194 movaps [rsp+138h+var_F8], xmm7
15. .text:FFFFF800028DD199 movaps [rsp+138h+var_E8], xmm8
16. [...]
17. .text:FFFFF800028DD1D3 mov [rax+20h], r13
18. .text:FFFFF800028DD1D7 mov [rax+28h], r14
19. .text:FFFFF800028DD1DB mov [rax+30h], r15
20. .text:FFFFF800028DD1DF mov [rsp+138h+var_118], r10
21. .text:FFFFF800028DD1E4 call KeBugCheckEx
22. .text:FFFFF800028DD1E4 KiBugCheckDispatch endp
KeBugCheckEx()函數(shù)需要將控制狀態(tài)寄存器保存到GS索引的一個(gè)內(nèi)存結(jié)構(gòu)。
1. .text:FFFFF800028DDC40 KeBugCheckEx
2. .text:FFFFF800028DDC40
3. .text:FFFFF800028DDC40 var_18= qword ptr -18h
4. .text:FFFFF800028DDC40 var_10= qword ptr -10h
5. .text:FFFFF800028DDC40 var_8= qword ptr -8
6. .text:FFFFF800028DDC40 arg_0= qword ptr 8
7. .text:FFFFF800028DDC40 arg_8= qword ptr 10h
8. .text:FFFFF800028DDC40 arg_10= qword ptr 18h
9. .text:FFFFF800028DDC40 arg_18= qword ptr 20h
10. .text:FFFFF800028DDC40 arg_20= qword ptr 28h
11. .text:FFFFF800028DDC40 arg_28= byte ptr 30h
12. .text:FFFFF800028DDC40
13. .text:FFFFF800028DDC40 mov [rsp+arg_0], rcx
14. .text:FFFFF800028DDC45 mov [rsp+arg_8], rdx
15. .text:FFFFF800028DDC4A mov [rsp+arg_10], r8
16. .text:FFFFF800028DDC4F mov [rsp+arg_18], r9
17. .text:FFFFF800028DDC54 pushfq
18. .text:FFFFF800028DDC55 sub rsp, 30h
19. .text:FFFFF800028DDC59 cli
20. .text:FFFFF800028DDC5A mov rcx, gs:20h
21. .text:FFFFF800028DDC63 mov rcx, [rcx+4BD8h]
22. .text:FFFFF800028DDC6A call RtlCaptureContext
23. .text:FFFFF800028DDC6F mov rcx, gs:20h
24. .text:FFFFF800028DDC78 add rcx, 40h
25. .text:FFFFF800028DDC7C call KiSaveProcessorControlState
26. .text:FFFFF800028DDC81 mov r10, gs:20h
27. .text:FFFFF800028DDC8A mov r10, [r10+4BD8h]
28. .text:FFFFF800028DDC91 mov rax, [rsp+38h+arg_0]
29. .text:FFFFF800028DDC96 mov [r10+80h], rax
30. .text:FFFFF800028DDC9D mov rax, [rsp+38h+var_8]
KeSaveProcessorControlState()函數(shù)將嘗試把cr0寄存器的內(nèi)容保存在GS:0x20處。
1. .text:FFFFF800028DDF70 KiSaveProcessorControlState
2. .text:FFFFF800028DDF70 mov rax, cr0
3. .text:FFFFF800028DDF73 mov [rcx], rax
4. .text:FFFFF800028DDF76 mov rax, cr2
5. .text:FFFFF800028DDF79 mov [rcx+8], rax
6. .text:FFFFF800028DDF7D mov rax, cr3
7. .text:FFFFF800028DDF80 mov [rcx+10h], rax
8. .text:FFFFF800028DDF84 mov rax, cr4
這可以被用來(lái)拋出一個(gè)頁(yè)錯(cuò)誤:
如果一個(gè)諸如0x54545454`54545454的值被存儲(chǔ)在GS:0x20,那么頁(yè)錯(cuò)誤將被觸發(fā)。
在頁(yè)錯(cuò)誤處理程序中,我們的目標(biāo)在于達(dá)到KiCheckForKernelApcDelivery()函數(shù)。它主要包括設(shè)置一個(gè)有效的指針GS:0x188(初始設(shè)置為0)。
1. .text:FFFFF800028DBC00 KiPageFault
2. .text:FFFFF800028DBC00
3. .text:FFFFF800028DBC00 var_158= dword ptr -158h
4. .text:FFFFF800028DBC00 var_138= dword ptr -138h
5. .text:FFFFF800028DBC00 var_12E= byte ptr -12Eh
6. .text:FFFFF800028DBC00 var_12D= byte ptr -12Dh
7. .text:FFFFF800028DBC00 var_12C= dword ptr -12Ch
8. .text:FFFFF800028DBC00 var_128= qword ptr -128h
9. [...]
10. .text:FFFFF800028DBC00 push rbp
11. .text:FFFFF800028DBC01 sub rsp, 158h
12. .text:FFFFF800028DBC08 lea rbp, [rsp+80h]
13. .text:FFFFF800028DBC10 mov [rbp+0D8h+var_12D], 1
14. .text:FFFFF800028DBC14 mov [rbp+0D8h+var_128], rax
15. .text:FFFFF800028DBC18 mov [rbp+0D8h+var_120], rcx
16. .text:FFFFF800028DBC1C mov [rbp+0D8h+var_118], rdx
17. .text:FFFFF800028DBC20 mov [rbp+0D8h+var_110], r8
18. .text:FFFFF800028DBC24 mov [rbp+0D8h+var_108], r9
19. .text:FFFFF800028DBC28 mov [rbp+0D8h+var_100], r10
20. .text:FFFFF800028DBC2C mov [rbp+0D8h+var_F8], r11
21. .text:FFFFF800028DBC30 test byte ptr [rbp+0D8h+arg_8], 1
22. .text:FFFFF800028DBC37 jz short loc_FFFFF800028DBCAD
23. .text:FFFFF800028DBC39 swapgs
24. .text:FFFFF800028DBC3C mov r10, gs:188h
25. .text:FFFFF800028DBC45 cmp [rbp+0D8h+arg_8], 33h ; '3'
26. [...]
27. .text:FFFFF800028DBCAD loc_FFFFF800028DBCAD:
28. ; KiPageFault+A6 j
29. .text:FFFFF800028DBCAD cld
30. .text:FFFFF800028DBCAE stmxcsr [rbp+0D8h+var_12C]
31. .text:FFFFF800028DBCB2 ldmxcsr dword ptr gs:180h
32. .text:FFFFF800028DBCBB movaps [rbp+0D8h+var_E8], xmm0
33. .text:FFFFF800028DBCBF movaps [rbp+0D8h+var_D8], xmm1
34. .text:FFFFF800028DBCC3 movaps [rbp+0D8h+var_C8], xmm2
35. .text:FFFFF800028DBCC7 movaps [rbp+0D8h+var_B8], xmm3
36. .text:FFFFF800028DBCCB movaps [rbp+0D8h+var_A8], xmm4
37. .text:FFFFF800028DBCCF movaps [rbp+0D8h+var_98], xmm5
38. .text:FFFFF800028DBCD3 mov eax, cs:KiCodePatchCycle
39. .text:FFFFF800028DBCD9 mov [rbp+0D8h+arg_24], eax
40. .text:FFFFF800028DBCDF mov eax, [rbp+0E0h]
41. .text:FFFFF800028DBCE5 mov rcx, cr2
42. .text:FFFFF800028DBCE8 test [rbp+0D8h+arg_10], 200h
43. .text:FFFFF800028DBCF3 jz short loc_FFFFF800028DBCF6
44. .text:FFFFF800028DBCF5 sti
45. [...]
46. .text:FFFFF800028DBCF6 loc_FFFFF800028DBCF6:
47. .text:FFFFF800028DBCF6 mov r9, gs:188h
48. .text:FFFFF800028DBCFF bt dword ptr [r9+4Ch], 0Bh
49. .text:FFFFF800028DBD05 jnb short loc_FFFFF800028DBD15
50. .text:FFFFF800028DBD07 test byte ptr [rbp+0F0h], 1
51. [...]
52. .text:FFFFF800028EACF2 loc_FFFFF800028EACF2:
53. .text:FFFFF800028EACF2 mov r12, gs:188h
54. .text:FFFFF800028EACFB mov [rbp+0D0h+var_78], rdi
55. .text:FFFFF800028EACFF mov rcx, [r12+70h]
56. .text:FFFFF800028EAD04 mov [rbp+0D0h+var_98], rcx
57. .text:FFFFF800028EAD08 cmp dword ptr [rcx+438h], 10h
58. .text:FFFFF800028EAD0F lea r14, [rcx+398h]
59. .text:FFFFF800028EAD16 ja loc_FFFFF800028EB0E2
60. .text:FFFFF800028EAD1C mov eax, cs:MiDelayPageFaults
61. .text:FFFFF800028EAD22 test eax, eax
62. [...]
63. .text:FFFFF800028EC79C loc_FFFFF800028EC79C:
64. .text:FFFFF800028EC79C call KiCheckForKernelApcDelivery
65. .text:FFFFF800028EC7A1 jmp loc_FFFFF800028EAF75
KiCheckForKernelApcDelivery()函數(shù)調(diào)用的KiDeliverApc():
1. .text:FFFFF8000288AF10 KiCheckForKernelApcDelivery
2. .text:FFFFF8000288AF10 push rbx
3. .text:FFFFF8000288AF12 sub rsp, 20h
4. .text:FFFFF8000288AF16 mov rax, cr8
5. .text:FFFFF8000288AF1A mov ecx, 1
6. .text:FFFFF8000288AF1F test al, al
7. .text:FFFFF8000288AF21 jnz short loc_FFFFF8000288AF3F
8. .text:FFFFF8000288AF23 xor ebx, ebx
9. .text:FFFFF8000288AF25 mov cr8, rcx
10. .text:FFFFF8000288AF29 xor r8d, r8d
11. .text:FFFFF8000288AF2C xor edx, edx
12. .text:FFFFF8000288AF2E xor ecx, ecx
13. .text:FFFFF8000288AF30 call KiDeliverApc
14. .text:FFFFF8000288AF35 mov cr8, rbx
這是一個(gè)實(shí)現(xiàn)代碼執(zhí)行的函數(shù)。它將提取GS:0x188中的指針,并在一系列解引用操作后設(shè)置R11寄存器,而R11寄存器用來(lái)調(diào)用另一個(gè)函數(shù)。
1. .text:FFFFF800028D1130 KiDeliverApc
2. .text:FFFFF800028D1130
3. .text:FFFFF800028D1130 var_78= dword ptr -78h
4. .text:FFFFF800028D1130 var_58= qword ptr -58h
5. .text:FFFFF800028D1130 var_50= qword ptr -50h
6. .text:FFFFF800028D1130 var_48= qword ptr -48h
7. .text:FFFFF800028D1130 var_40= qword ptr -40h
8. .text:FFFFF800028D1130 arg_0= qword ptr 8
9. [...]
10. .text:FFFFF800028D115B loc_FFFFF800028D115B:
11. .text:FFFFF800028D115B mov rbx, gs:188h
12. .text:FFFFF800028D1164 mov r15, [rbx+1D8h]
13. .text:FFFFF800028D116B mov r14, [rbx+70h]
14. .text:FFFFF800028D116F mov [rbx+79h], r9b
15. .text:FFFFF800028D1173 mov [rbx+1D8h], r8
16. .text:FFFFF800028D117A cmp [rbx+1C6h], r9w
17. .text:FFFFF800028D1182 jnz short loc_FFFFF800028D11A8
18. .text:FFFFF800028D1184 lock or [rsp+78h+var_78], r9d
19. .text:FFFFF800028D1189 lfence
20. .text:FFFFF800028D118C lea rsi, [rbx+50h]
21. [...]
22. .text:FFFFF800028D11EC loc_FFFFF800028D11EC:
23. .text:FFFFF800028D11EC mov r8, [rsi]
24. .text:FFFFF800028D11EF cmp r8, rsi
25. .text:FFFFF800028D11F2 jz loc_FFFFF800029296C7
26. .text:FFFFF800028D11F8 mov [rbx+79h], r9b
27. .text:FFFFF800028D11FC lea r10, [r8-10h]
28. .text:FFFFF800028D1200 prefetchw byte ptr [r10]
29. .text:FFFFF800028D1204 mov rcx, [r10+30h]
30. .text:FFFFF800028D1208 mov r11, [r10+20h]
31. .text:FFFFF800028D120C mov [rsp+78h+arg_10], rcx
32. .text:FFFFF800028D1214 mov rax, [r10+38h]
33. [...]
34. .text:FFFFF800028D12B0 loc_FFFFF800028D12B0:
35. .text:FFFFF800028D12B0 mov rax, [r8+8]
36. .text:FFFFF800028D12B4 mov rdx, [r8]
37. .text:FFFFF800028D12B7 mov [rax], rdx
38. .text:FFFFF800028D12BA mov [rdx+8], rax
39. .text:FFFFF800028D12BE mov [r10+52h], r9b
40. .text:FFFFF800028D12C2 lock and [rbx+88h], r9
41. .text:FFFFF800028D12CA movzx eax, r12b
42. .text:FFFFF800028D12CE mov cr8, rax
43. .text:FFFFF800028D12D2 lea rax, [rsp+78h+arg_18]
44. .text:FFFFF800028D12DA lea r9, [rsp+78h+var_48]
45. .text:FFFFF800028D12DF lea r8, [rsp+78h+var_40]
46. .text:FFFFF800028D12E4 lea rdx, [rsp+78h+arg_10]
47. .text:FFFFF800028D12EC mov rcx, r10
48. .text:FFFFF800028D12EF mov [rsp+78h+var_58], rax
49. .text:FFFFF800028D12F4 call r11
50. .text:FFFFF800028D12F7 xor r9d, r9d
51. .text:FFFFF800028D12FA jmp loc_FFFFF800028D1190
而如果R11寄存器指向一個(gè)內(nèi)核shellcode并且內(nèi)核調(diào)用它,則我們的shellcode就能可靠運(yùn)行了。
下面我結(jié)合代碼進(jìn)行下簡(jiǎn)單的說(shuō)明。
上面說(shuō)了一大通東西,其實(shí)關(guān)鍵就是
1, 掛鉤特殊函數(shù)使其產(chǎn)生本無(wú)法產(chǎn)生的特殊非規(guī)范地址,并使指令跳到這個(gè)特殊非規(guī)范地址從而觸發(fā)系統(tǒng)異常。
2, 系統(tǒng)發(fā)生異常時(shí)候,通過(guò)設(shè)置一些特定的數(shù)據(jù)跳轉(zhuǎn),跳轉(zhuǎn)到我們想要的地方。也就是最關(guān)鍵的函數(shù)
nt!KiDeliverApc,大家看代碼的時(shí)候,需要結(jié)合標(biāo)紅的字段就可以理解SHELLCODE的布局了。
觸發(fā)這個(gè)異常的時(shí)候,gs:188指向的是我們分配的0地址,所以
mov rbx, gs:188h rbx =0
lea rsi, [rbx+50h] rsi =0x50
mov r8, [rsi] r8 =0
lea r10, [r8-10h] r10 = -10h
mov r11, [r10+20h] r11 = 0x10
call r11 call的是我們分配地址0+0x10的地方。
也就是代碼里
*(PLONGLONG)((ULONG_PTR)0L+0x10) = KernelShellcodeAddress;
的精華所在,其他的大家看代碼也就清楚了。
說(shuō)明的是:
原始的老外代碼是VS2010 編譯的,我修改為最常用的VS2008 編譯,同時(shí)修改了些小BUG。
代碼調(diào)試可以調(diào)試到
斷點(diǎn)nt!KiUmsFastReturnToUser
Breakpoint 5 hit
nt!KiUmsFastReturnToUser+0x17e:
fffff800`0428907e 488b8de8000000 mov rcx,qword ptr [rbp+0E8h] //構(gòu)造的異常返回地址
2: kd> p
nt!KiUmsFastReturnToUser+0x185:
fffff800`04289085 4c8b9df8000000 mov r11,qword ptr [rbp+0F8h]
2: kd> p
nt!KiUmsFastReturnToUser+0x18c:
fffff800`0428908c 498be9 mov rbp,r9
2: kd> r
rax=0000000000000000 rbx=fffffa800fa0fb60 rcx=8000000000000000(構(gòu)造的異常返回地址)
rdx=0000000000000000 rsi=0000000076f8edc0 rdi=0000000000000000
rip=fffff8000428908c rsp=fffff880097d2bb0 rbp=fffff880097d2c60
r8=00000000002ff6e0 r9=00000000002ff6e0 r10=0000000000000000
r11=0000000000010246 r12=0000000000000001 r13=0000000000000001
r14=0000000000000000 r15=00000000771e84f0
iopl=0 nv up di pl zr na po nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000046
nt!KiUmsFastReturnToUser+0x18c:
fffff800`0428908c 498be9 mov rbp,r9
后面SYSRET 觸發(fā)異常后,不能對(duì)在異常處理的代碼下斷點(diǎn),否則會(huì)觸發(fā)藍(lán)屏。
還有masm64New.rules文件拷貝到你的X:\Program Files\Microsoft Visual Studio 9.0\VC\VCProjectDefaults,X為你VC2008所在的盤。然后就可以調(diào)試即可。
代碼里面也比較簡(jiǎn)單
1, 不是WIN764 位就退出
2, UMS函數(shù)初始化失敗也退出。
3, 判斷函數(shù)的參數(shù),或者帶PID,或者是EXE路勁,為了能使對(duì)應(yīng)的程序?yàn)镾YSTEM權(quán)限,及清除標(biāo)志g_CiEnabled,從而可以安裝加載非簽名驅(qū)動(dòng),這2個(gè)是為了表明內(nèi)核執(zhí)行代碼可能導(dǎo)致的危害性做的演示。
4, 分配0地址,并填入一些特殊數(shù)據(jù),確保執(zhí)行流程按指定的方向執(zhí)行。
5, 設(shè)置好SHELLCODE,并將shellcode入口點(diǎn)填入地址0X10,從而使其被觸發(fā)調(diào)用
6, 調(diào)用UMS線程,調(diào)用到我們的HOOK,填入非規(guī)范地址,從而觸發(fā)異常執(zhí)行。
最后補(bǔ)充下,這段代碼在WIN8 64位下應(yīng)該是無(wú)效的,因?yàn)閃IN8 64不允許分配0地址,也不允許內(nèi)核執(zhí)行應(yīng)用空間的代碼。