1. 程式人生 > >關於Win7 x64下過TP保護(核心層)(轉)

關於Win7 x64下過TP保護(核心層)(轉)

首先特別感謝夢老大,本人一直沒搞懂異常處理機制,看了他的教程之後終於明白了。
在他的教程裡我學到了不少東西。
第一次在論壇發帖,就說說Win7 x64位下怎麼過TP保護。如果有講錯的地方,還望指出。
說不定我發帖後一星期TP就會大更新呢。
打字排版好辛苦。 
先說說核心層,看大家的反應後再說說應用層的保護。(包括解決CE非法問題)

除錯物件:DXF
除錯工具:OD、Windbg
除錯環境:Win7 SP1 X64

除錯先言:我記得TP最近的一次大更新是在去年的暑假,在那之前的ring0保護和現在的已經大有不同了。
不過還是少不了DebugPort清零。


核心層部分:
x64下因為有PatchGuard的限制,很多保護都被巨硬給抹掉了。
比如SSDT Hook Inline Hook 所以TP無法繼續使用這些保護手段了。
除非騰Xun冒著被巨硬吊銷數字簽名的風險來阻止我們除錯。
我曾經在看雪論壇裡看過有個人寫的文章,它親自測試在x64環境下清零除錯埠,結果發生了藍屏,
所以在x64下TP是不會清零的。這樣就省了不少的事情。


但是自從那次TP大更新後新加入了ValidAccessMask清零。
那麼在ring0中 TP除了ValidAccessMask清零,還有反雙機除錯,這裡不是我們討論的範疇。
我們只是討論如何才能正常除錯遊戲,於是在核心層我們只要解決ValidAccessMask清零就可以了。

除錯許可權(ValidAccessMask)的清零
這個標誌位其實是DebugObject (除錯物件)的許可權,如果為0將導致無法建立除錯物件(缺少許可權)。
常見的情況就是OD無法附加任何程序,這個保護剛剛出的時候很多菜鳥都沒搞懂,包括我自己(知道被我師傅說我等級太低時的心情是什麼?)。
這個DebugObject在很多除錯函式中都有用到 ,比如NtCreateDebugObject就有需要訪問除錯物件。
所以要想辦法恢復這個標誌位。
我們有三種選擇:1、自己恢復原來的值 2、找到TP清零的位置Nop掉 3、移位(重建DebugObject)
這裡我選擇了第一種。

具體步驟如下:
①定位DebugObject:
在NtCreateDebugObject裡就有DebugObject的地址。
1: kd> uf NtCreateDebugObject
nt!NtCreateDebugObject:
fffff800`042697a0 48895c2408      mov     qword ptr [rsp+8],rbx
fffff800`042697a5 4889742410      mov     qword ptr [rsp+10h],rsi
fffff800`042697aa 57              push    rdi
fffff800`042697ab 4883ec70        sub     rsp,70h
fffff800`042697af 418bf9          mov     edi,r9d
fffff800`042697b2 8bf2            mov     esi,edx
fffff800`042697b4 488bd9          mov     rbx,rcx
fffff800`042697b7 65488b042588010000 mov   rax,qword ptr gs:[188h]
fffff800`042697c0 448a90f6010000  mov     r10b,byte ptr [rax+1F6h]
fffff800`042697c7 4584d2          test    r10b,r10b
fffff800`042697ca 7414            je      nt!NtCreateDebugObject+0x40 (fffff800`042697e0)
nt!NtCreateDebugObject+0x2c:
fffff800`042697cc 488b052d38e5ff  mov     rax,qword ptr [nt!MmUserProbeAddress (fffff800`040bd000)]
fffff800`042697d3 483bc8          cmp     rcx,rax
fffff800`042697d6 480f43c8        cmovae  rcx,rax
fffff800`042697da 488b01          mov     rax,qword ptr [rcx]
fffff800`042697dd 488901          mov     qword ptr [rcx],rax
nt!NtCreateDebugObject+0x40:
fffff800`042697e0 48832300        and     qword ptr [rbx],0
fffff800`042697e4 41f7c1feffffff  test    r9d,0FFFFFFFEh
fffff800`042697eb 740a            je      nt!NtCreateDebugObject+0x57 (fffff800`042697f7)
nt!NtCreateDebugObject+0x4d:
fffff800`042697ed b80d0000c0      mov     eax,0C000000Dh
fffff800`042697f2 e9e4000000      jmp     nt!NtCreateDebugObject+0x13b (fffff800`042698db)
nt!NtCreateDebugObject+0x57:
fffff800`042697f7 488d442450      lea     rax,[rsp+50h]
fffff800`042697fc 4889442440      mov     qword ptr [rsp+40h],rax
fffff800`04269801 8364243800      and     dword ptr [rsp+38h],0
fffff800`04269806 8364243000      and     dword ptr [rsp+30h],0
fffff800`0426980b c744242868000000 mov     dword ptr [rsp+28h],68h
fffff800`04269813 488364242000    and     qword ptr [rsp+20h],0
fffff800`04269819 458aca          mov     r9b,r10b
fffff800`0426981c 488b158dd3daff  mov     rdx,qword ptr [nt!DbgkDebugObjectType (fffff800`04016bb0)]
fffff800`04269823 418aca          mov     cl,r10b
fffff800`04269826 e84572f1ff      call    nt!ObCreateObject (fffff800`04180a70)
fffff800`0426982b 4c8b4c2450      mov     r9,qword ptr [rsp+50h]
fffff800`04269830 4c894c2460      mov     qword ptr [rsp+60h],r9
fffff800`04269835 85c0            test    eax,eax
fffff800`04269837 0f889e000000    js      nt!NtCreateDebugObject+0x13b (fffff800`042698db)
這個紅字就是了 
繼續定位ValidAccessMask的地址。

1: kd> dq fffff800`04016bb0
fffff800`04016bb0  fffffa80`00c33200 00000000`00000000
fffff800`04016bc0  fffff8a0`0009a010 0000002a`00000012
fffff800`04016bd0  00000024`000000a1 fffff880`0119d9a0
fffff800`04016be0  00000002`00000001 fffff880`095deacc
fffff800`04016bf0  fffff800`03f873f0 00000000`00000007
fffff800`04016c00  00000003`00000000 fffff800`03e10448
fffff800`04016c10  fffffa80`01bae060 00000000`00000000
fffff800`04016c20  00000000`00000000 00000003`00000101

1: kd> dt _OBJECT_TYPE fffffa80`00c33200
nt!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0xfffffa80`00c33200 - 0xfffffa80`00c33200 ]
   +0x010 Name             : _UNICODE_STRING "DebugObject"
   +0x020 DefaultObject    : (null) 
   +0x028 Index            : 0xb ''
   +0x02c TotalNumberOfObjects : 0
   +0x030 TotalNumberOfHandles : 0
   +0x034 HighWaterNumberOfObjects : 0
   +0x038 HighWaterNumberOfHandles : 0
  +0x040 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0b0 TypeLock         : _EX_PUSH_LOCK
   +0x0b8 Key              : 0x75626544
   +0x0c0 CallbackList     : _LIST_ENTRY [ 0xfffffa80`00c332c0 - 0xfffffa80`00c332c0 ]

1: kd> dt _OBJECT_TYPE_INITIALIZER fffffa80`00c33200+40
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
   +0x002 CacheAligned     : 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`042b18e0     void  nt!DbgkpCloseObject+0
   +0x048 DeleteProcedure  : 0xfffff800`04105200     void  nt!xHalEndOfBoot+0
   +0x050 ParseProcedure   : (null) 
   +0x058 SecurityProcedure : 0xfffff800`04170530     long  nt!SeDefaultObjectMethod+0
   +0x060 QueryNameProcedure : (null) 
   +0x068 OkayToCloseProcedure : (null) 

於是我們就定位到了VaildAccessMask的地址了。

②恢復工作
它的預設值是0x1F000F
當我們自己手動修改成0時。
使用OD附加任意程序。
<ignore_js_op>
 
無法附加,那我們就要手動恢復成0x1F000F。
具體方式我採用開DPC定時器的方法恢復,恢復的頻率不會和TP的衝突。
程式碼我貼出一部分,部分函式需要自己手動編寫,因為在64位下編寫驅動尋找SSDT等都比較麻煩。
這些函式大家可以去網上一些x64驅動編寫的教程裡面抄下。
我在這裡推薦下Tesla.Angela的教程《WIN64驅動程式設計基礎教程》

  1. #ifndef PROC
  2. #define PROC
  3.  
  4. PVOID pNtCreateDebugObject;
  5. PVOID pDbgkDebugObject;
  6. PVOID pDebugObject;
  7. PVOID pValidMask;
  8.  
  9.  
  10. KTIMER PassObjTimer;
  11. KDPC PassObjDpc;
  12. LARGE_INTEGER PassObjTime;
  13.  
  14. PVOID pKeStackAttachProcess;
  15. PVOID pKeStackAttachProcessJmpAddr;
  16. byte  bufKeStackAttachProcess[13];
  17.  
  18. VOID
  19. PassObj(
  20. __in struct _KDPC  *Dpc,
  21. __in_opt PVOID  DeferredContext,
  22. __in_opt PVOID  SystemArgument1,
  23. __in_opt PVOID  SystemArgument2
  24. )
  25. {
  26.         __try
  27.         {
  28.                 WriteProtectOff();
  29.                 *((ULONG*)pValidMask) = 0x1F000F;
  30.                 WriteProtectOn();
  31.         }
  32.         __except (1)
  33.         {
  34.                 KeCancelTimer(&PassObjTimer);
  35.                 return;
  36.         }
  37.         KeSetTimer(&PassObjTimer, PassObjTime, &PassObjDpc);
  38.         return;
  39. }
  40.  
  41. VOID PassObjectMask()
  42. {
  43.         PVOID pTargetAddr;
  44.         pNtCreateDebugObject = (PVOID)GetSSDTFunctionAddress(144);
  45.         pTargetAddr = (PVOID)(((ULONG64)pNtCreateDebugObject) + 0x7C);
  46.         pDbgkDebugObject=(PVOID)(MAKE_TARGETADDR((*((ULONG*)(((ULONG64)pTargetAddr) + 3))), (ULONG64)pTargetAddr));
  47.         pDebugObject = (PVOID)(*((ULONG64*)pDbgkDebugObject));
  48.         pValidMask = (PVOID)(((ULONG64)pDebugObject) + 0x40 + 0x1c);
  49.         PassObjTime.QuadPart = -10000 * 100;
  50.         KeInitializeTimer(&PassObjTimer);
  51.         KeInitializeDpc(&PassObjDpc, &PassObj, NULL);
  52.         KeSetTimer(&PassObjTimer, PassObjTime, &PassObjDpc);
  53. }
  54.  
  55. VOID UnPassObjectMask()
  56. {
  57.         KeCancelTimer(&PassObjTimer);
  58. }
  59. #endif