反除錯實戰系列一 x64dbg+IDA 過IsDebuggerPresent

語言: CN / TW / HK

前言

挺久之前就想開一個反除錯系列的坑,而且正好可以用這個實戰系列來鞏固所學

這次分析的程式為64位,用到的除錯工具有:IDA Pro (64-bit)  x64dbg

這次的CrackMe並不難,有興趣的可以嘗試先自己動手破解看看


反除錯介紹

在實戰之前,先大致介紹一下反除錯

什麼是反除錯

反除錯技術,顧名思義就是用來防止被除錯的一種技術

簡單的反除錯往往是識別是否被除錯,如果是則退出程式,封禁賬號等等        (檢測)

再複雜些可以在反彙編程式碼中插入花指令,使偵錯程式的反彙編引擎無法正確解析反彙編指令(干擾)

門檻較高的反除錯則可以是從驅動層將除錯許可權清零,使得偵錯程式失效等等        (許可權清零)

反除錯的手段可以大致歸納為:檢測、干擾、許可權清零 三種


反除錯的常見手段

反除錯手段層出不窮,可以分為兩類:

  • Ring0(核心層反除錯)
  • Ring3(應用層反除錯)

Ring3

Windows API中提供了兩個用於檢測是否被除錯的函式:

  • IsDebuggerPresent
  • CheckRemoteDebuggerPresent

Windows API 作用
IsDebuggerPresent 確定呼叫程序是否由使用者模式偵錯程式進行除錯
CheckRemoteDebuggerPresent 確定是否正在除錯指定的程序

除了使用上述兩個Windows API外 還有不少在Ring3下的反除錯手段:

檢測 PEB(Process Environment Block)程序環境塊 中的BeingDebuggedProcessHeap

除了檢測PEB外,還可以檢測 軟體斷點、硬體斷點程式碼校驗等等

除了檢測,之前提到的插入花指令進行干擾也屬於Ring3中的反除錯手段

在Ring3下的反除錯手段 五花八門,這裡僅列舉出了一小部分


Ring0

在Ring0下的反除錯保護,TenProtect不可謂不強,在先前的【原創】TP驅動保護分析系列一 定位TenProtect保護中已經提及

這裡限於篇幅原因不再贅述


反除錯實戰

前面稍微補充了一點關於反除錯的知識,接下來正式進入實戰環節

要除錯的程式

為了更好地起到學習作用,這次要除錯的程式是我自己寫的一個小demo,是一個MFC程式(練習了一波MFC)

image-20210503173142596

介面比較簡陋,畢竟是個小demo,不要介意

關於這個demo的程式碼之後也會放在後面的附件裡,有需要的可以自行取用(* ̄3 ̄)╭


實戰流程

查殼

首先使用PE工具:DIE(Detect It Easy) 查殼

image-20210503182249040

可以看到,程式並沒有加殼,並且是64位程式、用MFC編寫


關閉ASLR

使用MFC編譯出的64位程式預設是開啟ASLR的,不利於除錯,需要先關閉


什麼是ASLR

ASLR全稱Address Space Layout Randomization,又稱地址空間配置隨機化地址空間佈局隨機化


ASLR的作用

地址空間配置隨機載入利用隨機方式配置資料地址空間,使某些敏感資料配置到一個惡意程式無法事先獲知的地址,令攻擊者難以進行攻擊

粗俗地說,就是使得每次除錯工具(如OD、x64dbg等)載入程式後,地址是隨機動態分配的,無法使用固定的地址進行定位


ASLR的體現

上面純粹的說明可能不是很直觀,接下來使用x64dbg載入程式

image-20210503184317064

可以看到,x64dbg預設是中斷在了系統斷點,我們需要它執行到OEP(程式入口點)

使用快捷鍵:ALT+F9 執行到OEP(程式沒有加殼,所以可以執行到OEP),或者 除錯→執行到使用者程式碼


到達OEP


得到了:

image-20210503185325655

可以看到此時的EntryPoint為:

 複製程式碼 隱藏程式碼
00007FF6950D14F1 | E9 CADE0000              | jmp <crackme.wWinMainCRTStartup>              |

記錄下此時的地址為:00007FF6950D14F1

如果學習過PE就會知道 EntryPoint的地址 = EntryPoint + ImageBase

(不瞭解這個知識點的可以回顧:PE檔案筆記五 PE檔案頭之擴充套件PE頭)

image-20210503185622558

從前面的DIE工具的檢視中可以得到:

正常的 EntryPoint的地址 = EntryPoint + ImageBase  = 0x114F1 + 0x140000000 = 0x1400114F1

但是此時的地址很明顯不等於0x1400114F1,這就是ASLR的體現


使用PE工具關閉ASLR

知道了ASLR會干擾除錯,於是要使用PE工具關閉ASLR

關閉ASLR

ASLR由 擴充套件PE頭中的DllCharacteristics決定,關於DllCharacteristics可參考:DllCharacteristics


驗證ASLR的關閉

關閉完ASLR,再使用x64dbg載入程式,檢視此時的OEP:

image-20210503191219952

可以發現,此時的EntryPoint地址就和前面計算出來的地址一致,為:0x1400114F1


x64dbg定位反除錯

載入程式以後,要先讓程式跑起來再設定相關的API斷點,於是先執行

使用快捷鍵:F9 使得程式執行起來

但是當執行F9後,會發現程式直接退出了(不使用除錯工具時程式是可以正常執行的);這也就是本帖的關鍵了:反除錯

通過上面的操作,可以推測出:程式檢測當前是否正在被除錯,如是是則直接退出程式

推斷出大致的流程後,可以寫出虛擬碼:

 複製程式碼 隱藏程式碼
void AntiDebug(){                //反除錯函式
    bool IsBeingDebugged=checkIsDebug();//通過某種方式判斷當前程式是否正在被除錯
    if (IsBeingDebugged){        //如果正在被除錯
        exit();                                //退出程式
    }
}

可以得出呼叫情況為:AntiDebug→exit

於是可以從exit(退出程式)入手,開始定位

退出程式一般會使用到ExitProcess()這個Windows API,於是對這個函式下斷點

image-20210503192924459

在底下的命令列輸入:

 複製程式碼 隱藏程式碼
bp ExitProcess

然後可以得到:

image-20210503193044899


確定設定完斷點後,按F9讓程式執行起來,然後斷點斷下:

image-20210503193240187


注意堆疊中呼叫情況:

image-20210503193317550

找到呼叫的該程式的函式,可以懷疑這個函式相當於AntiDebug函式(用來反除錯)


image-20210503193514900

選中這一行,然後回車,檢視其對應的反彙編


得到:

image-20210503193606227

不難發現在呼叫exit函式的前面呼叫了IsDebuggerPresent來檢測是否被除錯


IDA Pro分析反除錯

為了更清晰地分析程式碼,使用x64dbg定位到了關鍵函式後,可以搭配IDA Pro進行分析

使用IDA Pro載入程式後,按G鍵彈出:

image-20210503194315804


這裡要跳轉的地址為前面得到的地址:這裡填14001A1D8

image-20210503194407263


跳轉後得到:

image-20210503194442007


選中函式的頭部,按快捷鍵:F5檢視其對應的虛擬碼:

image-20210503194618513


得到:

image-20210503194802393


即:

 複製程式碼 隱藏程式碼
__int64 StartAddress_0()
{
  __int64 *v0; // rdi
  __int64 i; // rcx
  __int64 v3; // [rsp+0h] [rbp-30h] BYREF

  v0 = &v3;
  for ( i = 70i64; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 = (__int64 *)((char *)v0 + 4);
  }
  sub_140011C12(&unk_14004201F);
  if ( IsDebuggerPresent() )                                                                //通過IsDebuggerPresent判斷是否被除錯
    exit(0);                                                                                                //如果檢測到被除錯則退出程式
  Sleep(0x64u);                                                                                                //為防止執行緒佔用過高,使用Sleep
  beginthreadex(0i64, 0, StartAddress, 0i64, 0, 0i64);                //啟動檢測執行緒
  return 0i64;
}

到這裡其實就已經十分清晰了,接下來開始處理反除錯


IDA Pro處理反除錯

分析出了該函式就是個反除錯函式,於是可以直接在函式頭部使其返回,讓反除錯函式無效

這裡要用到IDA Pro的KeyPatch功能:

選中函式的頭部,然後右鍵 → Key Patch → Patch:

keyPatch


Patch完結果如下:

image-20210503200226681


接下來要將Patch完的結果匯出到檔案:

Edit→ Patch Program → Apply patches to input file

image-20210503200440658


image-20210503200549048

確定匯出即可(匯出的時候,記得要先關閉x64dbg,不然程式被佔用會無法匯出)

image-20210503200642669


驗證反除錯的處理

此時再使用x64dbg載入程式 並讓程式執行起來,可以發現此時就可以正常運行了:

image-20210503201037198


x64定位Crack相關函式

擺脫了反除錯的干擾後,終於可以正式開始Crack了

一般來說,對於沒有加殼的程式直接搜尋字串即可,但這裡字串是被加密的,於是不能通過字串直接定位

換個角度,可以通過對相關的API函式下斷進行定位

這裡可以發現當輸入了錯誤的密碼後,等待Crack中變成了密碼錯誤

image-20210503201507775


這很顯然是對標籤文字的修改,可以嘗試對SetWindowTextW下斷點:

image-20210503201638038

 複製程式碼 隱藏程式碼
bp SetWindowTextW

image-20210503201719965


設定完斷點後,再點選確定來觸發斷點:

image-20210503201900612


觀察此時的堆疊情況:

image-20210503202152598

可以看到,堆疊中有輸入的密碼:610 和 要設定的文字:密碼錯誤

於是可以以此為突破口,繼續分析


選中 L"密碼錯誤"上面的函式,按回車檢視其對應的反彙編

image-20210503202426839


image-20210503202501821


翻看附近的程式碼,可以看到在程式碼下方不遠處可以找到:

image-20210503203628172

這裡就算定位到了關鍵的函式處,接下來使用IDA Pro進行分析


IDA Pro分析Crack相關函式

在IDA Pro中 按G彈出跳轉地址視窗,然後填入要跳轉的地址:140019272

image-20210503203721623


得到:

image-20210503203853910


接下來故技重施,選中函式的頭部,然後按F5檢視虛擬碼:

image-20210503204015648


得到:

image-20210503204046921

到了這裡其實基本上就已經水落石出了,為了留點懸念,接下來的步驟等有人Crack出來後再放出( ̄︶ ̄*))

Crack出來的要求:逆推出正確的密碼(該密碼唯一)


總結

該篇是反除錯實戰這個系列的開篇之作,此次實戰只涉及了一個最簡單的反除錯:IsDebuggerPresent

後續還會不斷更新其它反除錯實戰內容(應該會吧?咕咕咕(づ ̄ 3 ̄)づ),希望大家多多支援(。・∀・)ノ゙

稍微總結一下此篇的內容:

  • 反除錯的手段可以大致歸納為:檢測、干擾、許可權清零 三種
  • 分析程式時,可以採取x64dbg搭配IDA Pro 動靜結合的方式進行分析
  • ASLR可以使用PE工具關閉,之後除錯起來更方便
  • 反除錯的手段五花八門,重點在於如何定位,一般都是以某個相關函式作為突破口進行分析