關於StyleXP反跟蹤程式碼的分析以及WinDbg簡單教學 (7千字)

看雪資料發表於2015-11-15

目標軟體:Style XP 0.9 beta RC2
目標檔案:StyleXP.exe
使用環境:WINDOW XP
使用工具:WinDbg,wasm32

下載地址:http://www.tgtsoft.com/download.html

    Style XP是更改WINDOW XP“皮膚”的工具。通過使用皮膚,它可以改變Windows的外觀介面,而且還提供

了皮膚製作軟體。下載安裝的過程非常簡便,在機器重啟後變可令你Win XP外觀煥然一新,整體感覺要比

Winblinds看上去要輕盈淡雅。未註冊只能用30天。

    Style XP的反跟蹤程式碼做的很有特色,雖然比不上aspr等“大牌”程式,但只花費了很小的代價,就基本

達到的anit-debug的效果。
 
    因為剛裝好window xp,還沒除錯好soft-ice,只好用DDK工具集裡的WinDbg了。(其實WinDbg的功能一點

也不比soft-ice遜色,還可以一邊除錯一邊看MSDN的幫助文擋)


開啟WinDbg,選File->Open Executable,裝入StyleXP.exe,f5執行後,被中斷在一條int3的指令上:

* Reference To: COMCTL32.InitCommonControls, Ord:0011h
                                  |
:00422FA4 8B35E0404B00            mov esi, dword ptr [004B40E0]
:00422FAA FFD6                    call esi
:00422FAC 57                      push edi
:00422FAD E81DFA0200              call 004529CF
:00422FB2 59                      pop ecx
:00422FB3 8B4508                  mov eax, dword ptr [ebp+08]
:00422FB6 8B80C8000000            mov eax, dword ptr [eax+000000C8]
:00422FBC 8945E0                  mov dword ptr [ebp-20], eax
:00422FBF CC                      int 03    《==========中斷在這裡
:00422FC0 FFD6                    call esi
:00422FC2 57                      push edi
:00422FC3 E807FA0200              call 004529CF

原來是用SEH來實現anti-debug的,那好辦,下命令“SXD *”這條命令是讓WinDbg忽略所有的異常,只在debug

視窗輸出資訊。類似與soft-ice中的“faults off”命令。再下命令“GN”,即“Go Unhandled Exception”

(執行,但不處理異常情況)滿以為搞定了,誰知程式居然自動退出了!看來還有暗樁。重新裝入StyleXP,一

步一步跟蹤來到這裡:


:00422AA4 8D86CC000000            lea eax, dword ptr [esi+000000CC]
:00422AAA 8BCE                    mov ecx, esi
:00422AAC 50                      push eax
:00422AAD E8DB200800              call 004A4B8D

* Reference To: KERNEL32.GetTickCount, Ord:0186h
                                  |
:00422AB2 8B1D28444B00            mov ebx, dword ptr [004B4428]
:00422AB8 FFD3                    call ebx
:00422ABA 8986C0000000            mov dword ptr [esi+000000C0], eax


以上程式碼call KERNEL32.GetTickCount 將當前的時間儲存在[esi+000000C0]中

* Reference To: ole32.CoUninitialize, Ord:0059h
                                  |
:00422AC0 FF15F8494B00            Call dword ptr [004B49F8]
:00422AC6 8D45DC                  lea eax, dword ptr [ebp-24]
:00422AC9 50                      push eax
:00422ACA 57                      push edi
:00422ACB 56                      push esi
:00422ACC 68722F4200              push 00422F72
:00422AD1 6800000100              push 00010000
:00422AD6 57                      push edi

* Reference To: KERNEL32.CreateThread, Ord:004Dh
                                  |
:00422AD7 FF153C444B00            Call dword ptr [004B443C]
:00422ADD 3BC7                    cmp eax, edi
:00422ADF 8945F0                  mov dword ptr [ebp-10], eax
:00422AE2 7416                    je 00422AFA
:00422AE4 6AFF                    push FFFFFFFF
:00422AE6 50                      push eax

* Reference To: KERNEL32.WaitForSingleObject, Ord:02FDh
                                  |
:00422AE7 FF152C444B00            Call dword ptr [004B442C]


然後產生一個子執行緒(子執行緒地址為00422F72),再將本身的主執行緒掛起,直到子執行緒結束。(子執行緒的作用

後面有解釋)


:00422AED 8D45E0                  lea eax, dword ptr [ebp-20]
:00422AF0 50                      push eax
:00422AF1 FF75F0                  push [ebp-10]

* Reference To: KERNEL32.GetExitCodeThread, Ord:011Fh
                                  |
:00422AF4 FF1538444B00            Call dword ptr [004B4438]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00422AE2(C)
|
:00422AFA 817DE0E8030000          cmp dword ptr [ebp-20], 000003E8
:00422B01 7732                    ja 00422B35
:00422B03 FFD3                    call ebx      〈===KERNEL32.GetTickCount
:00422B05 2B86C0000000            sub eax, dword ptr [esi+000000C0]
:00422B0B 3D983A0000              cmp eax, 00003A98  〈== 3a98(hex)就是15000(dec)
:00422B10 7723                    ja 00422B35

上面程式碼再次call KERNEL32.GetTickCount,將當前時間和剛才的比較,如果大於15秒就over。


:00422B12 E8EC1C0800              call 004A4803
:00422B17 8B4008                  mov eax, dword ptr [eax+08]
:00422B1A 57                      push edi
:00422B1B 50                      push eax
:00422B1C 68BF304200              push 004230BF
:00422B21 6A09                    push 00000009

* Reference To: USER32.SetWindowsHookExA, Ord:0267h
                                  |
:00422B23 FF155C484B00            Call dword ptr [004B485C]
:00422B29 817DE0E8030000          cmp dword ptr [ebp-20], 000003E8
:00422B30 8945F0                  mov dword ptr [ebp-10], eax
:00422B33 7607                    jbe 00422B3C


產生“鉤子”程式(WH_DEBUG)


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004227A2(U), :004229A6(U), :00422B01(C), :00422B10(C)
|
:00422B35 33C0                    xor eax, eax
:00422B37 E971010000              jmp 00422CAD

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00422B33(C)
|
:00422B3C FFD3                    call ebx
:00422B3E 2B86C0000000            sub eax, dword ptr [esi+000000C0]
:00422B44 3D983A0000              cmp eax, 00003A98
:00422B49 760E                    jbe 00422B59

再次call KERNEL32.GetTickCount,將當前時間和剛才的比較,如果大於15秒就over。

將上面程式碼總結一下:
1)記錄一個時間點。
2)產生一個子執行緒,並且再將本身的主執行緒掛起,直到子執行緒結束。
3)在子執行緒中計算是否註冊以及是否過期,並且使用SEH技術,用int3斷點指令觸發debuger(如果有的話),

這時會有時間上的延遲。

4)當子執行緒退出,比較第一步的時間點,如果大於15秒,就說明本身被除錯。(因為除錯時要下斷點,會有時

間延遲)

要去掉暗裝也容易,將cmp eax, 00003A98該為xor eax,eax即可。這樣就可以除錯子執行緒了。
因為註冊碼比較部分挺複雜,我用爆破的方法使它永遠不過期。
下斷點“BP GetSystemTime”很容易找到關鍵:

:00478283 8B4C2410                mov ecx, dword ptr [esp+10]
:00478287 83C0FC                  add eax, FFFFFFFC
:0047828A 83C104                  add ecx, 00000004
:0047828D 50                      push eax
:0047828E 51                      push ecx
:0047828F 8B4C241C                mov ecx, dword ptr [esp+1C]
:00478293 E8A8150000              call 00479840
:00478298 8B4C2410                mov ecx, dword ptr [esp+10]
:0047829C 3B01                    cmp eax, dword ptr [ecx]
:0047829E 7412                    je 004782B2  〈==這裡判斷是否將時間改回原來
:004782A0 BE090404C0              mov esi, C0040409
:004782A5 56                      push esi
:004782A6 6A00                    push 00000000
:004782A8 682A070000              push 0000072A
:004782AD E929040000              jmp 004786DB


以下程式碼計算過期的時間
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0047829E(C)
|
:004782B2 668B4104                mov ax, word ptr [ecx+04]
:004782B6 668BD0                  mov dx, ax
:004782B9 8BC8                    mov ecx, eax
:004782BB 66C1EA09                shr dx, 09〈==dx為年份
:004782BF C1E905                  shr ecx, 05
:004782C2 81C2D0070000            add edx, 000007D0  〈==年份加上2000
:004782C8 83E01F                  and eax, 0000001F  〈===eax為天
:004782CB 83E10F                  and ecx, 0000000F  〈ecx==為月
:004782CE 668954241C              mov word ptr [esp+1C], dx
:004782D3 6689442420              mov word ptr [esp+20], ax
:004782D8 8B542420                mov edx, dword ptr [esp+20]
:004782DC 66894C241E              mov word ptr [esp+1E], cx
:004782E1 8B44241E                mov eax, dword ptr [esp+1E]
:004782E5 8B4C241C                mov ecx, dword ptr [esp+1C]



在:004782C2 處將edx的值該為一個很大的數就可以了。

相關文章