Win7x64系统过TP的一些尝试和目前遇到的问题
生活随笔
收集整理的這篇文章主要介紹了
Win7x64系统过TP的一些尝试和目前遇到的问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
其實渣新學內核編程不過半個月時間,帖中難免有幼稚的想法和錯誤,遇到的問題我會用藍色文字表述,還請各位前輩指正,感激不盡!
我把自己目前的進展和遇到的問題一起說說吧:
x64系統過TP大概分兩步,首先要過雙機調試,然后要過應用層調試。
1、過雙機調試,這里也分兩步
(1)首先要保證debug模式下啟動游戲不藍屏。
我也是第一次研究TP,對這之前的保護不了解,不過看網上所說這個啟動藍屏似乎是最近幾個月新加的。
要過這個需要對內核調試引擎有一定的了解,不過還好我們是站在巨♂人♀的肩膀上,在看雪找到了篇帖子,比較詳細的分析了系統啟動時內核調試引擎初始化的幾個標志。
TP只是檢測了其中一個(待定), KdEnteredDebugger ,它通過MDL映射來判斷這個標志是不是True,如果是就藍屏,解決方法我照抄了那篇帖子,直接在Hook一下IoAllocateMdl,
把判斷的地址改到一個恒為False的地方這樣就可以繞過了
[C++]?純文本查看?復制代碼 ?
不過這樣做帶來一個問題,藍屏是不藍屏了,TP的驅動模塊也能加載,但只能啟動登陸客戶端Client.exe,在登陸后啟動DNF.exe時TP會再進行一次檢測,
這次就會造成虛擬機卡死,估計還是和調試模式的檢測有關。
我用了個折中的解決辦法,就是用戶態調試的時候不進入Debug模式,這樣就能啟動DNF.exe了,不過實在是不方便
(2)使雙機調試能下斷點
關于雙機調試中斷點原理和異常的處理流程,我是看了《軟件調試》這本書和http://www.xfocus.net/articles/200412/765.html這片帖子,有了些了解。
對于TP來說,他是不斷調用KdDisableDebuger()這個函數來清零KdDebuggerEnabled ,調試引擎就是在KeUpdateSystemTime()這個函數里不斷檢測這個標志來確定異常處理的流程
解決方法,一開始我是直接HooK KdDisableDebuger(),開頭
[Asm]?純文本查看?復制代碼 ?
直接STATUS_SUCCESS然后返回,不讓它做其他處理,
但是毫無效果,還是下不了斷點,不知道是怎么回事……
后來想了個辦法,直接修改KeUpdateSystemTime()里面檢測的地方,和上面一樣,讓它檢測其它地址……
[C++]?純文本查看?復制代碼 ?
要改的地方有3處,我只貼了一處的代碼。這樣就能下各種斷點了。
2、雙機調試之后就是用戶態調試了
x64系統上TP目前做的保護還不是特別多,這也是我選x64入手的原因之一
TP修改了 DebugObject中 ValIDAccessMask一項,這個就是調試權限,代碼中我們恢復下就可以了。
windbg下輸入以下命令就可以定位到 ValidAccessMask,下硬件斷點就能找到 ValidAccessMask清零的地方。
至于如何在自己的代碼中定位這個變量,我是通過SSDT表查找NtCreateDebugObject這個內核函數地址,里面定位 DbgkDebugObjectType
再根據下面的結構體加幾個偏移地址( +0x040 +? 0x01c)來找到 ValidAccessMask。應該有更好的定位方法……
[Asm]?純文本查看?復制代碼 ?
從清零代碼那里的windbg信息來看,沒有地址標號的提示(TesSafe+xxxx),這代碼似乎不是在一個驅動模塊里?
關于恢復的方法,大體上能想到3種:
1、開一個IoTimer或者DpcTimer或者干脆開個線程,不斷對 ValidAccessMask地址寫入它原來的值
2、自己代碼內利用調試寄存器下硬件斷點,然后hook IDT 1號中斷服務子程,在里面恢復 ValidAccessMask
3、 自己代碼內利用調試寄存器下硬件斷點,定位到上面的清零代碼,nop之(我在windbg里直接nop掉是可以的,沒有模塊自校驗)
目前我嘗試了第一種方法,開了個IoTimer,雖說1s一次會造成一些概率問題,但測試而已,簡單粗暴就好。
[C++]?純文本查看?復制代碼 ?
至于為什么會有后兩種想法,是因為我覺得其作用不僅僅在于次,通過調試寄存器和1號中斷應該還可以作很多事情,不僅僅是寫個0x1f000f而已……
不過雖說想法很好,我還沒開始實踐……這中間似乎涉及到多核CPU還有用戶棧內核棧切換的許多知識……
好了,現在可以開OD附加了,那么問題來了,學挖掘……哦不…………
還是先請前輩們看看效果圖:
這是開另一個任意程序調試的OD,一切正常:
?
這是附加了DNF.exe,反匯編窗口基本全是0,右鍵看不到模塊信息……
這個就是傳說中的DebugPort清零嗎?如果是的話,我在自己研究下恢復,如果不是,哪是什么問題造成了這種現象?
?
另外從圖上游戲界面可以看到,DNF檢測到了非法模塊,這個不知道會有什么影響……
我把自己目前的進展和遇到的問題一起說說吧:
x64系統過TP大概分兩步,首先要過雙機調試,然后要過應用層調試。
1、過雙機調試,這里也分兩步
(1)首先要保證debug模式下啟動游戲不藍屏。
我也是第一次研究TP,對這之前的保護不了解,不過看網上所說這個啟動藍屏似乎是最近幾個月新加的。
要過這個需要對內核調試引擎有一定的了解,不過還好我們是站在巨♂人♀的肩膀上,在看雪找到了篇帖子,比較詳細的分析了系統啟動時內核調試引擎初始化的幾個標志。
TP只是檢測了其中一個(待定), KdEnteredDebugger ,它通過MDL映射來判斷這個標志是不是True,如果是就藍屏,解決方法我照抄了那篇帖子,直接在Hook一下IoAllocateMdl,
把判斷的地址改到一個恒為False的地方這樣就可以繞過了
[C++]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | PMDL newIoAllocateMdl( ????????__in_opt PVOID? VirtualAddress, ????????__in ULONG? Length, ????????__in BOOLEAN? SecondaryBuffer, ????????__in BOOLEAN? ChargeQuota, ????????__inout_opt PIRP? Irp? OPTIONAL) { ????????if (VirtualAddress == KdEnteredDebugger) ????????{ ????????????????//DbgPrint("[KdEnteredDebugger] address: %p\n", KdEnteredDebugger); ????????????????VirtualAddress = (PUCHAR)KdEnteredDebugger + 0x30;? //據觀察,+0x30 的位置恒為0 ????????} ????????return oldIoAllocateMdl(VirtualAddress, Length, SecondaryBuffer, ChargeQuota, Irp); } |
不過這樣做帶來一個問題,藍屏是不藍屏了,TP的驅動模塊也能加載,但只能啟動登陸客戶端Client.exe,在登陸后啟動DNF.exe時TP會再進行一次檢測,
這次就會造成虛擬機卡死,估計還是和調試模式的檢測有關。
我用了個折中的解決辦法,就是用戶態調試的時候不進入Debug模式,這樣就能啟動DNF.exe了,不過實在是不方便
(2)使雙機調試能下斷點
關于雙機調試中斷點原理和異常的處理流程,我是看了《軟件調試》這本書和http://www.xfocus.net/articles/200412/765.html這片帖子,有了些了解。
對于TP來說,他是不斷調用KdDisableDebuger()這個函數來清零KdDebuggerEnabled ,調試引擎就是在KeUpdateSystemTime()這個函數里不斷檢測這個標志來確定異常處理的流程
解決方法,一開始我是直接HooK KdDisableDebuger(),開頭
[Asm]?純文本查看?復制代碼 ?
| 1 2 | xor rax, rax ret |
后來想了個辦法,直接修改KeUpdateSystemTime()里面檢測的地方,和上面一樣,讓它檢測其它地址……
[C++]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 | //替換KeUpdateSystemTime函數中兩個KdDebuggerEnabled變量地址為DummyKdDebuggerEnabled KUSTPatchAddr1 = SearchAddressBySig((PUCHAR)KeUpdateSystemTimeAddr + 0x100, 0x100, UPSig1, sizeof(UPSig1)) ; if (KUSTPatchAddr1 != NULL) { ????KUSTPatchAddr1 += sizeof(UPSig1); ????//64位匯編,變量均為相對rip地址,下同 ????DisableWriteProtect64(); ????*(PULONG)KUSTPatchAddr1 = (PUCHAR)pDummyKdDebuggerEnabled - ((PUCHAR)KUSTPatchAddr1 - 2) - 6; //指令長度為6 ????EnableWriteProtect64(); } |
要改的地方有3處,我只貼了一處的代碼。這樣就能下各種斷點了。
2、雙機調試之后就是用戶態調試了
x64系統上TP目前做的保護還不是特別多,這也是我選x64入手的原因之一
TP修改了 DebugObject中 ValIDAccessMask一項,這個就是調試權限,代碼中我們恢復下就可以了。
windbg下輸入以下命令就可以定位到 ValidAccessMask,下硬件斷點就能找到 ValidAccessMask清零的地方。
至于如何在自己的代碼中定位這個變量,我是通過SSDT表查找NtCreateDebugObject這個內核函數地址,里面定位 DbgkDebugObjectType
再根據下面的結構體加幾個偏移地址( +0x040 +? 0x01c)來找到 ValidAccessMask。應該有更好的定位方法……
[Asm]?純文本查看?復制代碼 ?
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | dq DbgkDebugObjectType dt _OBJECT_TYPE fffffa80`24e33250 清零前: 1: kd> dt _OBJECT_TYPE_INITIALIZER fffffa80`24e33250+0x040 nt!_OBJECT_TYPE_INITIALIZER ???+0x000 Length?????????? : 0x70 ???+0x002 ObjectTypeFlags? : 0x8 '' ???+0x002 CaseInsensitive? : 0y0 ???+0x002 UnnamedObjectsOnly : 0y0 ???+0x002 UseDefaultObject : 0y0 ???+0x002 SecurityRequired : 0y1 ???+0x002 MaintainHandleCount : 0y0 ???+0x002 MaintainTypeList : 0y0 ???+0x002 SupportsObjectCallbacks : 0y0 ???+0x004 ObjectTypeCode?? : 0 ???+0x008 InvalidAttributes : 0 ???+0x00c GenericMapping?? : _GENERIC_MAPPING ???+0x01c ValidAccessMask? : 0x1f000f ???+0x020 RetainAccess???? : 0 ???+0x024 PoolType???????? : 0 ( NonPagedPool ) ???+0x028 DefaultPagedPoolCharge : 0 ???+0x02c DefaultNonPagedPoolCharge : 0x58 ???+0x030 DumpProcedure??? : (null) ???+0x038 OpenProcedure??? : (null) ???+0x040 CloseProcedure?? : 0xfffff800`01f0ddb0???? void? nt!DbgkpCloseObject+0 ???+0x048 DeleteProcedure? : 0xfffff800`01d66fe0???? void? nt!CmpConfigureProcessors+0 ???+0x050 ParseProcedure?? : (null) ???+0x058 SecurityProcedure : 0xfffff800`01dd25f0???? long? nt!SeDefaultObjectMethod+0 ???+0x060 QueryNameProcedure : (null) ???+0x068 OkayToCloseProcedure : (null) 清零后: 0: kd> dt _OBJECT_TYPE_INITIALIZER fffffa80`24e51250+0x040 nt!_OBJECT_TYPE_INITIALIZER ???+0x000 Length?????????? : 0x70 ???+0x002 ObjectTypeFlags? : 0x8 '' ???+0x002 CaseInsensitive? : 0y0 ???+0x002 UnnamedObjectsOnly : 0y0 ???+0x002 UseDefaultObject : 0y0 ???+0x002 SecurityRequired : 0y1 ???+0x002 MaintainHandleCount : 0y0 ???+0x002 MaintainTypeList : 0y0 ???+0x002 SupportsObjectCallbacks : 0y0 ???+0x004 ObjectTypeCode?? : 0 ???+0x008 InvalidAttributes : 0 ???+0x00c GenericMapping?? : _GENERIC_MAPPING ???+0x01c ValidAccessMask? : 0 ???+0x020 RetainAccess???? : 0 ???+0x024 PoolType???????? : 0 ( NonPagedPool ) ???+0x028 DefaultPagedPoolCharge : 0 ???+0x02c DefaultNonPagedPoolCharge : 0x58 ???+0x030 DumpProcedure??? : (null) ???+0x038 OpenProcedure??? : (null) ???+0x040 CloseProcedure?? : 0xfffff800`01eb5db0???? void? nt!DbgkpCloseObject+0 ???+0x048 DeleteProcedure? : 0xfffff800`01d0efe0???? void? nt!CmpConfigureProcessors+0 ???+0x050 ParseProcedure?? : (null) ???+0x058 SecurityProcedure : 0xfffff800`01d7a5f0???? long? nt!SeDefaultObjectMethod+0 ???+0x060 QueryNameProcedure : (null) ???+0x068 OkayToCloseProcedure : (null) 清零代碼: fffff880`0bcdc4cc 54????????????? push??? rsp fffff880`0bcdc4cd 33c0??????????? xor???? eax,eax fffff880`0bcdc4cf 87434c????????? xchg??? eax,dword ptr [rbx+4Ch] fffff880`0bcdc4d2 33c0??????????? xor???? eax,eax fffff880`0bcdc4d4 874350????????? xchg??? eax,dword ptr [rbx+50h] fffff880`0bcdc4d7 33c0??????????? xor???? eax,eax fffff880`0bcdc4d9 87435c????????? xchg??? eax,dword ptr [rbx+5Ch] // ValidAccessMask? fffff880`0bcdc4dc 833d9585000000? cmp???? dword ptr [fffff880`0bce4a78],0 fffff880`0bcdc4e3 0f8544feffff??? jne???? fffff880`0bcdc32d fffff880`0bcdc4e9 33c9??????????? xor???? ecx,ecx fffff880`0bcdc4eb ff15df6b0000??? call??? qword ptr [fffff880`0bce30d0] fffff880`0bcdc4f1 488b4c2440????? mov???? rcx,qword ptr [rsp+40h] fffff880`0bcdc4f6 4833cc????????? xor???? rcx,rsp fffff880`0bcdc4f9 e822570000????? call??? fffff880`0bce1c20 fffff880`0bcdc4fe 488b5c2468????? mov???? rbx,qword ptr [rsp+68h] fffff880`0bcdc503 4883c450??????? add???? rsp,50h fffff880`0bcdc507 5f????????????? pop???? rdi fffff880`0bcdc508 c3????????????? ret |
從清零代碼那里的windbg信息來看,沒有地址標號的提示(TesSafe+xxxx),這代碼似乎不是在一個驅動模塊里?
關于恢復的方法,大體上能想到3種:
1、開一個IoTimer或者DpcTimer或者干脆開個線程,不斷對 ValidAccessMask地址寫入它原來的值
2、自己代碼內利用調試寄存器下硬件斷點,然后hook IDT 1號中斷服務子程,在里面恢復 ValidAccessMask
3、 自己代碼內利用調試寄存器下硬件斷點,定位到上面的清零代碼,nop之(我在windbg里直接nop掉是可以的,沒有模塊自校驗)
目前我嘗試了第一種方法,開了個IoTimer,雖說1s一次會造成一些概率問題,但測試而已,簡單粗暴就好。
[C++]?純文本查看?復制代碼 ?
| 1 2 3 4 5 6 | VOID OnTimer(DEVICE_OBJECT? *DeviceObject, PVOID? Context) { ????????DisableWriteProtect64(); ????????*g_pValidAccessMask = 0x1f000f; ????????EnableWriteProtect64(); } |
至于為什么會有后兩種想法,是因為我覺得其作用不僅僅在于次,通過調試寄存器和1號中斷應該還可以作很多事情,不僅僅是寫個0x1f000f而已……
不過雖說想法很好,我還沒開始實踐……這中間似乎涉及到多核CPU還有用戶棧內核棧切換的許多知識……
好了,現在可以開OD附加了,那么問題來了,學挖掘……哦不…………
還是先請前輩們看看效果圖:
這是開另一個任意程序調試的OD,一切正常:
?
這是附加了DNF.exe,反匯編窗口基本全是0,右鍵看不到模塊信息……
這個就是傳說中的DebugPort清零嗎?如果是的話,我在自己研究下恢復,如果不是,哪是什么問題造成了這種現象?
?
另外從圖上游戲界面可以看到,DNF檢測到了非法模塊,這個不知道會有什么影響……
總結
以上是生活随笔為你收集整理的Win7x64系统过TP的一些尝试和目前遇到的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Xcode中的隐藏宝藏:模拟器里如何快速
- 下一篇: 宽带码分多址系统中多径衰落与多址干扰的影