過 DNF TP 驅動保護(一)

文章目錄:

                 

01. 博文簡介:

02. 環境及工具準備:

03. 分析 TP 所做的保護:

04. 幹掉 NtOpenProcess 中的 Deep InLine Hook:

05. 幹掉 NtOpenThread 中的 Deep InLine Hook:

06. 幹掉 NtReadVirtualMemory 中的 InLine Hook:

07. 幹掉 NtWriteVirtualMemory 中的 InLine Hook:

08. 幹掉 KiAttachProcess 的 InLine Hook:

09. 幹掉 NtGetContextThread 中的 InLine Hook:

10. 幹掉 NtSetContextThread 中的 InLine Hook:

11. 幹掉 DbgkpQueueMessage 中的 InLine Hook:

12. 幹掉 DbgkpSetProcessDebugObject 中的 InLine Hook:

13. 幹掉 Debug 清零:

                                            

                                            

共四篇,本篇爲第一篇。

                                            

                                            

01. 博文簡介:

                         

 

 

 

 

 

本篇博文僅僅是我對過 TP 保護所作的一個總結,裏面沒有啥高深的技術,

僅僅是 Hook 而已,並且只有些 InLine Hook 和 SSDT Hook 的代碼,

這些對大牛而言都是小菜一碟,所以大牛們可以直接飄過咯 ^_^

然後就是關於本篇博文,估計會比較長,所以我會按照上面的目錄分出來一,二,三,四篇相繼發表。

                 

我先來裝回逼科普下 TP 吧,直接從百度百科抄襲點過來:

TP 系統全稱 TenProtect,是由騰訊自主研發推出的安全系統,可以有效保護遊戲不受外掛侵犯,同時具備反木馬盜號功能,

能有效的防止用戶遊戲帳號和虛擬財產被竊取。騰訊 TP 系統主要作用爲外掛檢測、反盜號、反非法工作室、防非法消息。

                 

具體功能如下:

反注入:TP系統能有效的阻止非法模塊對遊戲進行注入;

反加速:TP系統能防止遊戲客戶端的非法加速功能;

反模擬按鍵:TP系統能有效阻止模擬按鍵程序;

反脫機: TP系統能針對非正常登錄遊戲的行爲進行檢測;

反調試: TP系統採用內核級反調試技術,保護遊戲進程不被調試和分析;

反木馬: TP系統可以保護玩家帳號不被木馬程序竊取;

檢測外掛功能:TP系統能對外掛功能進行檢測;

指令混淆: TP系統能對正常指令進行虛擬和變形,加大外掛作者逆向難度;

特徵匹配: TP系統採用特徵碼匹配技術,能準確檢測到外掛的使用;

文件校驗:TP系統可以準確檢測遊戲目錄下的文件是否被第三方程序篡改;

遊戲內存數據校驗: TP系統所特有技術手段可以準確感知到遊戲關鍵數據的異常;

遊戲進程保護: TP系統可以保護遊戲進程不被第三方程序讀寫;

遊戲虛擬財產保護: 在玩家因不當操作引起帳號泄漏情況下,TP系統也可以保護玩家帳號內虛擬財產不被不法份子轉移;

                 

我幾個日子弄了過 TP 的驅動保護,算下來前前後後也弄了半來個月,

雖然比較累,但還是收穫了蠻多東西,這篇博文就是將如何過掉 TP 做的一個總結而已,

在這篇文章中我會一一介紹過掉 TP 所 Hook 的各種 API 的思路,並附上簡要的代碼,

在過 TP 驅動保護的過程中以及一些思路和一些代碼也很大程度上都是來自國內的幾大論壇,

主要是看雪,一蓑煙雨,DebugMan 等論壇,這裏對我所借鑑的那些哥們說 Many Thanks。

同時也得特別感謝劉總,很多地方若沒有劉總的指導,則還指不定何時能夠弄出來呢。

                 

值得一提的是,我現在所做的過 TP 驅動保護只支持 32 位 XP,在所有的 32 位 XP 上都可以正常運行,

不過 Win7 的話還不行,因爲裏面用到了搜索特徵碼來定位未導出 API,而我只針對 XP 做了處理。

                 

免責聲明:

此文僅作爲技術交流,有心之人切記不要拿來做壞事,尤其是不要拿來做傷天害理,或者傷害企鵝利益的事情,

對於那些有心要做壞事的,則所有後果或者反正是壞的方面的責任都與我無關,

如果此文傷害了某些公司的利益或者之類的,請站內消息或者留言聯繫我,本人看到後會第一時間關閉此文。

                                

                                

02. 環境及工具準備:

                                

前面也提過了,此次過 TP 的驅動保護僅僅只適用於 XP 系統,所以,首先你得準備個虛擬機,

然後裝個 XP 的系統,至於是 XP SP2 還是 XP SPxxx 就隨便了,當然,如果你喜歡 BSOD 的話,

也完全可以裝個其他的系統,然後的話,就得準備幾個專業工具了,首先一個當然是 Xuetr 了,

不過 TP 能夠檢測出 Xuetr,所以 Xuetr 在 XP 機器上和 TP 同時運行時,

輕則導致 TP 彈出警告框,重則藍屏,這個看個人運氣了。

然後還有一個工具也很重量級,也是 Rootkit 檢測工具,叫做 Kernel Detective,

並且更重要的是 TP 和 Kernel Detective 是可以並存的,不會像 Xuetr 那樣會被 TP 檢測出來,

不過 Kernel Detective 想比與 Xuetr 來說,Xuetr 能夠掃描內核的 InLine Hook,這個很強大,

這兩個工具都很重要,其次就是 WinDbg 和 OD 以及 CE 了。

至於 WinDbg 的話自然是用來調試 Windows 內核或者調試驅動程序了,

而 OD 和 CE 的話可以用來測試咱所寫的驅動是否真正的有效果,也就是測試是否真正的過了 TP 保護。

最後就是開發環境了,我的是 Visual Studio 2010 + Visual DDK + WDK,這個可以隨意搭建。

                                

                                

03. 分析 TP 所做的保護:

                                

如果真要分析 TP 所做的保護的話,還是比較麻煩的,不過好在各種論壇裏面,各種前輩給指出了明路,

比如墮落天才有一篇極好的文章,不過這篇文章是 2010 年 12 月份的了,中間 TP 也不是吃飯的,肯定是有更新了,

(繼續爲墮落天才打廣告)

文章名稱:《散談遊戲保護那點事~就從_TP開始入手吧》

文章地址:http://bbs.pediy.com/showthread.php?t=126802

不過這篇文章的參考價值還是很大的,比如在 NtOpenProcess,NtOpenThread 等等系統服務的 Hook 上,

TP 也還是差不多的,也就是變化不大,甚至很多的代碼都可以拿過來直接用,而至於 TP 更新的一些內核函數的 Hook 的話,

也可以從其他論壇裏面找到一些,所以最主要的一點就是放狗搜索,放狗搜索到一些資料以後,

可以用 WinDbg 或者 Kernel Detective 來驗證這個內核 API 是否真的被 TP 所幹掉了。

具體的俺也不曉得要怎麼說了,總結一句就是放狗搜索。

下面放出幾張截圖,我是用 Xuetr 進行掃描的,

image

image

 

                                

                                

04. 幹掉 NtOpenProcess 中的 Deep InLine Hook:

                                

TP Hook NtOpenProcess 的直接效果就是咱在應用層裏面調用 OpenProcess(DNF 進程) 失敗,

並且在 OD 或者 CE 裏面也根本找不到 DNF 遊戲的進程,更別提什麼打開或者附加了,

這使得咱根本對 DNF 無從下手。研究過 TP 的都知道,TP 在 NtOpenProcess 中是下了深層的 InLine 鉤子,

這個也早已經不是什麼祕密,各個論壇上的都知道,是 Hook 的 ObOpenObjectByPointer,

對於這個,可以使用 Xuetr 掃描內核鉤子掃描出來(TP 對 Xuetr 好像敏感,在 XP 機上可能藍屏)。

在一些簡單的 InLine Hook 中,咱都是直接拿內核 API 的頭 5 個或者頭 7 個字節做 Hook,

這種 Hook 方式是很容易被幹掉的,直接 SSDT Hook 就可以幹掉,

對於用 SSDT Hook 幹掉淺層的 InLine Hook 可以參考看雪上墮落天才的文章:

文章名稱:《SSDT Hook 的妙用 - 對抗 Ring0 InLine Hook》

文章地址:http://bbs.pediy.com/showthread.php?t=40832

不過 TP 是做的 Deep InLine Hook,也就是 Hook 的是 NtOpenProcess 深層的地址,而不是函數頭,

要想用 SSDT Hook 來幹掉的話,除非自己重寫 NtOpenProcess,否則很難幹掉,

而且 TP 在對 NtOpenProcess 上還有檢測,所以即使是重寫 NtOpenProcess 也很麻煩,

因爲在重寫中也必須要繞過 TP 可以被 TP 檢測到,從而彈出經典的 TP 警告框。

                                

在這裏咱可以在 Kernel Detective 中看到它所做的 InLine Hook,

首先是啓動 Kernel Detective,然後在 SSDT 子菜單中,找到 NtOpenProcess,

然後在上面右鍵,在右鍵菜單中選擇反彙編當前地址,從而就會跳轉到 NtOpenProcess 的反彙編代碼中了,

由於我的電腦太爛了,開個虛擬機,再跑個 DNF,再主機裏面開個 Visual Studio 的話,估計半天會沒反應,

所以這裏截圖截的都是沒有啓動 DNF 的圖,也就是在 TP 還沒有進行 Hook 時候的截圖,

對於電腦配置好的朋友,可以自己去測試,測試結果除了地址外,其他基本都是一樣的,

image

image

                                

那麼如何實現幹掉 TP 對 NtOpenProcess 所做的 Hook 呢 ?

一般幹掉的意思就是恢復 Hook,但是恢復 Hook 有一個很嚴重的問題,那就是很容易就被 TP 檢測到了,

其實可以換個思路,爲什麼一定要幹掉 TP 對 NtOpenProcess 所做的 Hook 呢 ?

就算被幹掉了,還得幹掉 TP 用來檢測 NtOpenProcess 的 Hook 是否被幹掉的線程之類的,

這樣就比較麻煩了,爲何不直接繞過 TP 的 Hook 呢 ?

要想繞過 TP 的保護的話,我們也可以下一個 InLine Hook,如果發現是 DNF 進程的話,那好啊,

咱直接跳到 TP 下的 InLine Hook 中執行(這樣 TP 還是執行它原來的代碼,從而檢測不出來被改變了)

而如果不是 DNF 進程的話,那咱就跳過 TP 下的 InLine Hook 就好了,

上面這樣說是說不清楚的,來點乾脆的,寫點僞代碼比較容易看懂:

                                

TP 啓動之前,也就是 Hook 之前的僞代碼:

   1:  push dword ptr[ebp-38]
   2:  push dword ptr[ebp-24]
   3:  call ObOpenObjectByPointer
   4:  mov edi,eax
   5:  lea eax,dword ptr[ebp-B8]

                                

TP 啓動之後,也就是 Hook 之後的僞代碼:

   1:  push dword ptr[ebp-38]
   2:  push dword ptr[ebp-24]
   3:  call TPHookedObOpenObjectByPointer    //這裏代表 TP Hook ObOpenObjectByPointer 的函數
   4:  mov edi,eax
   5:  lea eax,dword ptr[ebp-B8]

                                

繞過 TP 所做的 Hook 的僞代碼(DNF 檢測不出來自己被繞過了,要是能檢測出來也就不叫繞過了):

   1:  push dword ptr[ebp-38]
   2:  push dword ptr[ebp-24]
   3:  if(是 DNF 進程)
   4:  {
   5:      call TPHookedObOpenObjectByPointer
   6:  }
   7:  else
   8:  {
   9:      call ObOpenObjectByPointer
  10:  }
  11:  mov edi,eax
  12:  lea eax,dword ptr[ebp-B8]

                                

有了僞代碼以後,我們要做的也就比較清楚了,要想實現“繞過 TP 所做的 Hook 的僞代碼”的話,

咱得自己也下一個 InLine Hook,至於我們在哪裏下 InLine Hook 的話,也很明白,

至少得再 call ObOpenObjectByPointer 之前吧,否則都已經進入 TP 的 Hook 了,還談什麼繞過呢 ?

下面給出一副截圖來標記將要下我們自己的 InLine Hook 的位置,

image

                                

現在已經知道要在哪個位置下 InLine Hook 了,那麼下一個問題就是咱如何才能得到這個地址呢?

辦法自然是搜索特徵碼了,具體的實現方式可以看下面的截圖,通過搜索特徵碼咱就可以得到咱要下 Hook 的地址了。

image

                                

既然要下 InLine Hook 的位置也找到了,同時,如何繞過 TP 的 InLine Hook 的僞代碼也出來了,

那麼就只需要在找到的位置處安裝一個 InLine Hook,同時完成我們 Hook 時的過濾代碼就 OK 了。

下面對如何繞過 TP 的 InLine Hook 的僞代碼再做一個詳細點的說明,具體的都已經很簡單了,

我們已經得到了 0x805C0D74 這個地址,這個地址 + 6 即是 0x805C0D7A,對應的就是 call 指令了,

所以如果是 DNF 進程的話,我們就直接跳到這個指令上來,從而執行 call TPHookedObOpenObjectByPointer,

   1:  __asm
   2:  {
   3:      push    dword ptr [ebp-38h]
   4:      push    dword ptr [ebp-24h]
   5:      jmp     0x805C0D7A
   6:  }

同時 0x805C0D74 + 11 = 0x805C0D7F 也就是 mov 指令,也就是說如果不是 DNF 進程的話,

咱自己實現下面的代碼就 OK 了,也就是調用內核原始的 ObOpenObjectByPointer,

ObOpenObjectByPointer 這個函數是內核導出函數,可以使用 MmGetSystemRoutineAddress 獲取其地址,

   1:  __asm
   2:  {
   3:      push    dword ptr [ebp-38h]
   4:      push    dword ptr [ebp-24h]
   5:      call    ObOpenObjectByPointer
   6:      jmp     0x805C0D7F 
   7:  }

                                

下面是先貼出安裝 InLine Hook 的代碼,用來幹掉 TP 對 call ObOpenObjectPointer 的 Hook

   1:  /************************************************************************/
   2:  /* 安裝鉤子從而過掉 TP 保護所 Hook 的 NtOpenProcess - 讓 TP 失效
   3:  /************************************************************************/
   4:  VOID InstallPassTPNtOpenProcess()
   5:  {
   6:      CHAR szCode[7] = 
   7:      {
   8:          (char)0xff,
   9:          (char)0x75,
  10:          (char)0xc8,
  11:          (char)0xff,
  12:          (char)0x75,
  13:          (char)0xdc,
  14:          (char)0xe8
  15:      };
  16:   
  17:      /* 獲取原生的 NtOpenProcess 和 ObOpenObjectByPointer 的地址 */
  18:      uOriginNtOpenProcessAddr = MmGetSystemFunAddress(L"NtOpenProcess");
  19:      uOriginObOpenObjectByPointerAddr = MmGetSystemFunAddress(L"ObOpenObjectByPointer");
  20:   
  21:      /* 從 NtOpenProcess 這個地址開始搜索長度爲 7 的特徵碼字符串,得到的地址將會被安裝 InLine Hook */
  22:      uMyHookedNtOpenProcessAddr = SearchFeature(uOriginNtOpenProcessAddr, szCode, 7) - 7;
  23:   
  24:      /* 計算出自定義 InLine Hook 的跳轉地址 */
  25:      uMyHookedNtOpenProcessJmpAddr = uMyHookedNtOpenProcessAddr + 11;
  26:   
  27:      /* 計算出 TP InLine Hook 的跳轉地址 */
  28:      uTPHookedNtOpenProcessJmpAddr = uMyHookedNtOpenProcessAddr + 6;
  29:   
  30:      /* 安裝一個 InLine Hook */
  31:      InstallInLineHook(uMyHookedNtOpenProcessAddr, (ULONG)InLineHookNtOpenProcess);
  32:   
  33:      KdPrint(("Pass TP - NtOpenProcess Installed."));
  34:  }

                                

下面再給出我們自己 InLine Hook 的中繼實現:

   1:  /************************************************************************/
   2:  /* 自定義的 NtOpenProcess,用來實現 InLine Hook Kernel API
   3:  /************************************************************************/
   4:  NTSYSHOOKAPI void InLineHookNtOpenProcess()
   5:  {
   6:      __asm
   7:      {
   8:          push    dword ptr [ebp-38h]
   9:          push    dword ptr [ebp-24h]
  10:      }
  11:   
  12:      /* 開始過濾 */
  13:      if(ValidateCurrentProcessIsDNF() == TRUE)
  14:      {
  15:          __asm
  16:          {
  17:              /* 如果是 DNF 進程調用的話,則調用已經被 TP Hook 的 NtOpenProcess */
  18:              jmp        uTPHookedNtOpenProcessJmpAddr
  19:          }
  20:      }
  21:   
  22:      __asm
  23:      {
  24:          /* 如果不是 DNF 進程調用的話,則調用 ntoskrnl.exe 中的 NtOpenProcess */
  25:          call    uOriginObOpenObjectByPointerAddr
  26:          jmp     uMyHookedNtOpenProcessJmpAddr
  27:      }
  28:  }

                                

                                

05. 幹掉 NtOpenThread 中的 Deep InLine Hook:

                                

上面已經幹掉了 NtOpenProcess 中的 Deep InLine Hook 了,其實很多人都能猜得到,

既然 TP 搞掉了 NtOpenProcess,那麼 TP 就沒有理由不搞掉 NtOpenThread 這個內核服務了,

不錯,TP 在內核中確實也幹掉了 NtOpenThread 這個內核服務,並且同樣用的 Deep InLine Hook,

並且跟 NtOpenProcess 一樣,NtOpenThread 中也是對 ObOpenObjectByPointer 做的 InLine Hook,

不相信的童鞋可以分別在啓動 DNF 遊戲之前和之後用 Kernel Detective 經過反彙編查看 NtOpenThread 的反彙編代碼,

比較兩次的反彙編代碼就可以看出來 TP 在 NtOpenThread 中所動的手腳了,具體的步驟可以如下:

先找到 NtOpenThread 的反彙編地址,然後再在反彙編代碼中找到 call ObOpenObjectByPointer(TP 啓動之前),

image

image

                                

和幹掉 NtOpenProcess 中的 Deep InLine Hook 一樣,我們還是使用繞過去的方式來做,

由於前面已經以這種方式分析分析過 NtOpenThread 了,所以咱直接來分析地址就 OK 了,

首先我們一樣搜索特徵碼定位到我們將要安裝 InLine Hook 的地址,

image

                                

下面對如何繞過 TP 的 InLine Hook 的再做一個詳細點的說明,

我們已經得到了 0x805C0FF6 這個地址,這個地址 + 6 即是 0x805C0FFC,對應的就是 call 指令了,

所以如果是 DNF 進程的話,我們就直接跳到這個指令上來,從而執行 call TPHookedObOpenObjectByPointer,

   1:  __asm
   2:  {
   3:      push    dword ptr [ebp-34h]
   4:      push    dword ptr [ebp-20h]
   5:      jmp     0x805C0FFC
   6:  }

同時 0x805C0FF6 + 11 = 0x805C1001 也就是 mov 指令,也就是說如果不是 DNF 進程的話,

咱自己實現下面的代碼就 OK 了,也就是調用內核原始的 ObOpenObjectByPointer,

ObOpenObjectByPointer 這個函數是內核導出函數,可以使用 MmGetSystemRoutineAddress 獲取其地址,

   1:  __asm
   2:  {
   3:      push    dword ptr [ebp-34h]
   4:      push    dword ptr [ebp-20h]
   5:      call    ObOpenObjectByPointer
   6:      jmp     0x805C1001 
   7:  }

                                

下面先貼出用來安裝 InLine Hook 的代碼,用來幹掉 TP 對 Call ObOpenObjectByPointer 做的 Hook:

   1:  /************************************************************************/
   2:  /* 安裝鉤子從而過掉 TP 保護所 Hook 的 NtOpenThread - 讓 TP 失效
   3:  /************************************************************************/
   4:  VOID InstallPassTPNtOpenThread()
   5:  {
   6:      CHAR szCode[7] = 
   7:      {
   8:          (char)0xff,
   9:          (char)0x75,
  10:          (char)0xcc,
  11:          (char)0xff,
  12:          (char)0x75,
  13:          (char)0xe0,
  14:          (char)0xe8
  15:      };
  16:   
  17:      /* 獲取原生的 NtOpenThread 和 ObOpenObjectByPointer 的地址 */
  18:      uOriginNtOpenThreadAddr = MmGetSystemFunAddress(L"NtOpenThread");
  19:      uOriginObOpenObjectByPointerAddr = MmGetSystemFunAddress(L"ObOpenObjectByPointer");
  20:   
  21:      /* 從 NtOpenThread 這個地址開始搜索長度爲 7 的特徵碼字符串,得到的地址將會被安裝 InLine Hook */
  22:      uMyHookedNtOpenThreadAddr = SearchFeature(uOriginNtOpenThreadAddr, szCode, 7) - 7;
  23:      uMyHookedNtOpenThreadJmpAddr = uMyHookedNtOpenThreadAddr + 11;
  24:      uTPHookedNtOpenThreadJmpAddr = uMyHookedNtOpenThreadAddr + 6;
  25:   
  26:      InstallInLineHook(uMyHookedNtOpenThreadAddr, (ULONG)InLineHookNtOpenThread);
  27:   
  28:      KdPrint(("Pass TP - NtOpenThread Installed."));
  29:  }

                                

下面再給出我們自己 InLine Hook 的中繼實現:

   1:  /************************************************************************/
   2:  /*  自定義的 NtOpenThread,用來實現 InLine Hook Kernel API
   3:  /************************************************************************/
   4:  NTSYSHOOKAPI void InLineHookNtOpenThread()
   5:  {
   6:      __asm
   7:      {
   8:          push    dword ptr [ebp-34h]
   9:          push    dword ptr [ebp-20h]
  10:      }
  11:   
  12:      /* 開始過濾 */
  13:      if(ValidateCurrentProcessIsDNF() == TRUE)
  14:      {
  15:          __asm
  16:          {
  17:              /* 如果是 DNF 進程調用的話,則調用已經被 TP Hook 的 NtOpenThread */
  18:              jmp        uTPHookedNtOpenThreadJmpAddr
  19:          }
  20:      }
  21:   
  22:      __asm
  23:      {
  24:          /* 如果不是 DNF 進程調用的話,則調用 ntoskrnl.exe 中的 NtOpenThread */
  25:          call    uOriginObOpenObjectByPointerAddr
  26:          jmp     uMyHookedNtOpenThreadJmpAddr
  27:      }
  28:  }

                                

 

                                                

總結:

                                                

《過 DNF TP 驅動保護》的第一篇到這裏就結束了,經過上面的處理,

我們已經過掉了 TP 在 NtOpenProcess 和 NtOpenThread 中的 InLine Hook,

現在已經能在 OD 或 CE 裏看到 DNF 遊戲進程並且在 Ring3 下也可以調用 OpenProcess 打開 DNF 進程了,

不過完成了這些離過 DNF TP 驅動保護還很遠,詳情還得留到下回分解了。

下面給出兩張截圖來顯示一下咱的戰果:

image

image

                                       

現已支持過掉最新版本的 TP 保護(2013年04月23日),

如有需要者(有償提供),請聯繫 QQ:1751048662

                   

版權所有,迎轉載,但轉載請註明: 轉載自  Zachary.XiaoZhen - 夢想的天空

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章