幻影使用的反跟蹤技術

看雪資料發表於2003-06-21

本人水平較低,寫這篇文章主要是想向大家學習,本人不解之處望各位能給與解答,並懇請大家指正錯誤。
工具:      trw2000
目標:      dbpe  2.33

一、隨機改變關鍵程式碼的記憶體地址
動態載入dbpe  2.33 開始不遠處看到如下程式碼
call     @1
@1:    pop   ebp
       sub ebp 406913
call 指令將eip進棧,下一句pop ebp 執行後ebp的值為當前程式碼的記憶體地址。減去一個固定值,將得到相對偏移量,運用以上兩句程式碼可以對程式進行重定位,以後的程式碼採用如下形式間址定址:
     MOV  EAX, [EBP+412345]
也就是說,程式碼放到任何地址都不會發生記憶體定址錯誤。後面程式會使用CreateFileMapping、MapViewOfFile等API函式申請一段記憶體地址,用REP MOVB將程式碼轉移過去,這樣程式每次執行,關鍵部分的程式碼地址都會不同,達到反跟蹤的目的.

二、花指令的使用
Dbpe的花指令共有五種
1、
0167:004FE036  PUSHF  
0167:004FE037  PUSH     BYTE +10               設定迴圈次數

0167:004FE039  JNC      004FE046               沒用
0167:004FE03B  JMP      SHORT 004FE03F
0167:004FE03D  DB       C1                     花指令
0167:004FE03E  DB       51                     花指令
0167:004FE03F  CALL     004FE04A
0167:004FE044  DB       CA                     花指令
0167:004FE045  DB       11                     花指令
0167:004FE046  JNC      004FE03F
0167:004FE048  POP      EBX
0167:004FE049  DB       CD                     花指令
0167:004FE04A  ADD      ESP,BYTE +04           平衡堆疊
0167:004FE04D  JMP      SHORT 004FE051
0167:004FE04F  DB       99                     花指令
0167:004FE050  DB       EB                     花指令
0167:004FE051  DEC      DWORD [ESP]
0167:004FE054  JNO      004FE057               沒用
0167:004FE056  DB       E8    
0167:004FE057  JNS      004FE039               判斷[ESP]是否=-1,不等則轉
0167:004FE059  JPE      004FE05C
0167:004FE05B  DB       75                     花指令
0167:004FE05C  ADD      ESP,BYTE +04          平衡堆疊用
0167:004FE05F  POPF    
0167:004FE060  JMP      SHORT 004FE063
0167:004FE062  DB      75    
處理方法將第一句改為JMP 4FE063,後面的改為NOP
2、
0167:004FE063  PUSHF  
0167:004FE064  JC       004FE070
0167:004FE066  JMP      SHORT 004FE069
0167:004FE068  DB       63    
0167:004FE069  CALL     004FE073
0167:004FE06E  JMP      SHORT 004FE0E7
0167:004FE070  JC       004FE066
0167:004FE072  DB       83    
0167:004FE073  ADD      ESP,BYTE +04
0167:004FE076  POPF    
0167:004FE077  JMP      SHORT 004FE07A
0167:004FE079  DB       75    
0167:004FE07A  PUSH     EAX

處理辦法,將這些程式碼直接改為nop
3 常規的花指令
        jz            @1
        jnz           @1
        db xx                           花指令
@1    xxxxxx

4       jc            @1
       jnc           @1
       db xx
@1   xxxxxx
5
      jno           @1
      jne           @1
      db xx
@1  xxxxxx
3 4 5 三種花指令,直接改為nop即可,用程式實現自動取出花指令很容易,VB部分程式碼如下,data()為讀入的檔案byte程式碼
Private Sub DeFlower(StartPos As Long, EndPos As Long)
Dim i As Long
For i = StartPos To EndPos

'discard the flower instruction as such
'pushf
'push 10 ...

If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) + Hex(data(i + 4)) + Hex(data(i + 5)) + Hex(data(i + 6)) = "9C6A1073BEB2" Then
    data(i) = &HE9
    data(i + 1) = &H28
    data(i + 2) = 0
    data(i + 3) = 0
    data(i + 4) = 0
    Call ChangData(i, 5, 44)
      i = i + 44
      GoTo sw
    End If

'discard the flower instruction as such
'pushf
'jc xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) + Hex(data(i + 4)) = "9C72AEB1" Then
   data(i) = &HEB
   data(i + 1) = &H15
   Call ChangData(i, 2, 22)
   i = i + 22
      GoTo sw
    End If

'discard the flower instruction as such
'jz xxxxxxxx
'jnz xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) = "743751" Then
   Call ChangData(i, 0, 4)
   i = i + 4
      GoTo sw
    End If

'discard the flower instruction as such
'jc xxxxxxxx
'jnc xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) = "723731" Then
   Call ChangData(i, 0, 4)
   i = i + 4
      GoTo sw
    End If

'discard the flower instruction as such
'jpe xxxxxxxx
'jpo xxxxxxxx ...
If Hex(data(i)) + Hex(data(i + 1)) + Hex(data(i + 2)) + Hex(data(i + 3)) = "7A37B1" Then
   Call ChangData(i, 0, 4)
   i = i + 4
      GoTo sw
    End If

sw:
Next i
End Sub

Private Sub ChangData(Pos As Long, StartPos As Integer, EndPos As Integer)
For j = Pos + StartPos To Pos + EndPos
      data(j) = &H90
    Next j
End Sub

三、UPX解碼
用以上方式去處花指令,只能去處很小的一部分,因為程式大量的程式碼是一段一段解碼後執行,解碼一段,執行一段,記憶體中不出現完全解碼的檔案,這樣可以有效的對付反跟蹤。處理辦法是:多次執行去花程式。
大段的程式碼軟體使用了upx加解密,程式開始處使用了一次,後面恢復被加密程式各個段使用的也是這種方式。
0167:004FE0F0  PUSH     BYTE +04
0167:004FE0F2  PUSH     DWORD 1000
0167:004FE0F7  PUSH     EAX
0167:004FE0F8  PUSH     BYTE +00
0167:004FE0FA  CALL     NEAR [EBP+004384F6]  -〉VirtualAlloc
申請一段記憶體地址 返回值eax=申請記憶體的首地址
push    eax
push    ebx         4fe3c5加密段首地址
call     4fe234      upx解碼程式
返回值=解碼位元組
後面用rep movsb將解密後程式碼寫回4fe3c5,再用VirtualAlloc釋放申請的記憶體,一般來說,解密後的程式碼大於解密前的,但D.Boy在程式中預留了位置,這樣就可以先將解密的資料W成一個檔案,貼到程式的對應位置,前面用一個JMP指令跳過解碼的指令。去花指令。

四、垃圾指令與MMX
程式用CPUID指令判斷CPU是否支援MMX指令集,如果支援就用MMX指令動態解密執行,程式碼中間插入了大量的垃圾程式碼來干擾跟蹤者的視線。如
mov eax , 47ad4470
mov ebx , 6421c319            垃圾程式碼
movq mm2,mm3
sub ebx, ebx                  垃圾程式碼
pcmpeqd mm0, mm1
mmx指令集網上有大量的介紹,中英文都有,這裡就不細說了。但這段程式碼很長,而且是翻譯一段,執行一段,這裡需要一定的耐心。

五、利用int3反跟蹤
這裡看看如下程式碼,這是去處花指令的,以後同
sidt      [esi]                      取中斷向量表
mov     esi,  [esi+2]
mov     ax,  [esi+18]             取int3的原入口地址,
mov     bx,  [esi+1e]
mov     [ebp+xxxx] ,ax           儲存int3的原入口地址
mov     [ebp+yyyy] ,bx
mov     eax , 4241aa
add      eax ,ebp                 eax為新的int3入口地址
mov     [esi+18], ax               將int3的入口地址指向自己的程式
mov     shr  eax,10
mov     [esi+1e],ax
利用如上程式碼,就改變了int3的入口地址,跳是軟體如trw2000也會將int3的入口地址指向自己的程式,這樣就可以有效的對付大部分除錯軟體,這裡第一次設定的將int3的入口地址為52f876,執行52f876的程式碼時,獲得的是ring0級許可權。自己的程式也可以用這種方法獲得ring0級許可權。
程式利用int3跳到自己的程式碼部分解密下一段程式碼,同時設定新的入口,另一個分支是call ebx。看看如下程式碼:
         CMP      EAX,52554E53        
         JNZ      0052F8EF
         CALL     EBX                    程式後半部用到
         IRET    
0052F8EF  CMP      EBX,554E434F
         JNZ      NEAR 0052FB58
0052F905  MOV      AH,[ESI]               解密
         XOR      AH,AL
         NOT      AH
         MOV      [ESI],AH
         INC      ESI
         DEC      ECX                    解密長度,開始幾段都相同
         CMP      ECX,BYTE +00
         JNZ      NEAR 0052F905
         DEC      AL                      下一段解密XOR的值為這次的減1
         LEA      EDI,[EBP+00437D36]
         SIDT     [EDI]                   重設INT3的入口地址
         MOV      EDI,[EDI+02]
         MOV      EBX,[ESP]            *注1
         CMP      BYTE [EBX],E9        E9 為JMP
         JNZ      0052FA82
         ADD      EBX,BYTE +05         JMP的指令長度,INT3設到JMP的下一句
         JMP      0052FA94
0052FA82  ADD      EBX,BYTE +02
0052FA94  MOV      [EDI+18],BX
         SHR      EBX,10
         MOV      [EDI+1E],BX
         MOV      EBX,0155
         MOV      DR7,EBX              *注2
         MOV      EBX,554E434F
0052FB58  IRET    
*注1:INT3執行後,先將標誌暫存器內容入棧,CS暫存器擴充套件到32位入棧,EIP入棧,執行IRET時以相反出棧,[ESP]為INT3下一句的地址
*注2:DR7為除錯控制暫存器,只有在ring0許可權時才能操作此暫存器,以後的程式碼中還會見到dr0 dr1 dr2 dr3,它們是除錯斷點暫存器,dr6為除錯狀態暫存器。
這段程式碼也是解密一段執行一段,去花程式不起作用,但這段程式碼長度結構都相同,我猜想是由程式自動生成的,這樣就可以把這段w出來,用自己的程式解密(程式碼略),找到程式碼開始變化時地址位置,手動跟蹤時直接跳過去,到後面大段解碼完成後,將解碼後的程式碼寫回源程式,去掉解碼部分程式碼。這種方法還是很繁瑣,大家有好的方法如能告知不勝感激。

六、判斷中斷向量
sidt      [esi]                      取中斷向量表
mov     esi,  [esi+2]
mov     ax,  [esi+2e0]            
mov     bx,  [esi+6]
xor      ax ,bx
jnz     error
如果沒有跟蹤軟體時ax與bx的值相同,如果不同那麼……

七、判斷駐留程式
push  0
push  0
push  0
push  0
push  0
push  0
push  esi
call   CreateFileA
cmp  eax ,  -1
jnz   error
esi 指向的內容\\.\BW2K\.\\, \\.\SUPERBPM\.\\  \\.\ICEDUMP\.\\  \\.\REGVXD\.\\    \\.\NTICE\.\\   \\.\SIWVID\.\\    \\.\SICE\.\\      \\.\FILEVXD\.\\
如果這幾種程式沒有駐留,CreateFileA返回值eax應為ffffffff,程式就用此方法反跟蹤

八、檔案校驗
檔案校驗共出現兩次
@1  mov   bl, [edi]           edi程式碼地址
   xor    bl,cl
   add    eax, ebx
   inc    edi
   dec    ecx
   cmp   ecx ,0             長度
   jnz    @1
   lea    ebx,[ebp+42cf59]
   cmp   [ebp+42d1a8] ,eax     比較校驗和是否相當
   jnz   error
利用prodump抓取的影像檔案的校驗和,與原來的肯定要不同
九、利用定時器反跟蹤
push     ebx
push     1f4
push     xxx
push     xxx
call      SetTimer
定時器的時間間隔為500ms,ebx指向事件程式碼,事件程式碼用到了上面提到的int3反跟蹤技術獲得ring0許可權,這樣程式執行後開啟除錯軟體也會被程式發現。

十、不明之處
程式碼如下
 mov  eax, [fs:word 30]            不明
 
push    0
 call     GetModuleHandleA
 test     edx,edx                    不明
 jns     error
 cmp    [edx+8],  -1                不明
 jnz     error
 mov    [edx+50], 1000              不明
 mov    [edx+6] , 1010               不明
 。。。。。。
eax的返回之正確為400000,edx的值為819xxxxx,懷疑與執行緒有關,執行到mov    [edx+6] , 1010時當機,不明所以,望指教。

SWay[CCG]


討論:

SWay[CCG]:

下面引用由linson2003/06/21 03:55pm 發表的內容:
這段我不明白啊,能否詳細說說原理?
檔案校驗共出現兩次
@1  mov   bl, [edi]           edi程式碼地址
  xor    bl,cl
  add    eax, ebx
  inc    edi
  dec    ecx
  cmp   ecx ,0             長度
  jnz    @1
  lea    ebx,[ebp+42cf59]
  cmp   [ebp+42d1a8] ,eax     比較校驗和是否相當
  jnz   error
利用prodump抓取的影像檔案的校驗和,與原來的肯定要不同



程式執行時edi=需要計算的程式碼地址,ecx=1c000,相當於下面的說明語句
for(cl=0x1c000;cl=0;cl--)
{
sum+=[EDI]^CL;
edi++;
}
if (sum<>CorrectSum)
error;
 

 


飛葉流楓  

下面引用由pll6212003/06/22 01:24am 發表的內容:
十、不明之處
程式碼如下
mov  eax, [fs:word 30]            不明
=====================
此程式碼可以用於反某些偵錯程式,當有偵錯程式和沒有偵錯程式的時候內容是不同的

...




上面所說的並非是檢測程式擁有者,而是Anti Dump,其彙編指令如下
       push    fs:[30h]
       pop     eax
       TEST    EAX, EAX
       JS      _win9x     ; 判斷作業系統的型別
  _iswinnt:
       MOV     EAX, [EAX+0Ch]
       MOV     EAX, [EAX+0Ch]
       MOV     DWORD PTR [EAX+20h], 1000h ; change proc size=1000h
       JMP     _over
  _win9x:
       PUSH    0
       CALL    GetModuleHandle
       TEST    EDX, EDX
       JNS     _over                  
       CMP     DWORD PTR [EDX+8], -1
       JNE     _over                
       MOV     EDX, [EDX+4]          
       MOV     DWORD PTR [EDX+50h], 1000h ; change proc size=1000h
在經過上面的指令後,我們DUMP出來的程式就只有1000h大小了.

 

swift  
必須提出一點,我最早釋出幻影2.3x破解版的時候,就指出了目的不是為了讓大家用它來免費加密自己的程式,而更重要的是破除國內很多人對d.boy加密工具的迷信、盲目崇拜和畏懼。

我在win2k sp3下除錯dbpe 2.33,和樓主的分析結果有些出入,這裡提出來供參考。

樓主提出程式大量的程式碼是一段一段解碼後執行,解碼一段,執行一段,記憶體中不出現完全解碼的檔案。而根據我的分析結果,dbpe的殼的部分雖然多次透過呼叫VirtualAlloc申請一段記憶體,但是其最重要的也是最長的一段程式碼,包括把捆綁的註冊介面釋放、註冊碼讀取以後的判斷,對被加密的主程式的解碼以及跳到真實OEP的這些東東都是在原地解碼並且一次性rep movsb過去的。

至於花指令,我認為它的主要目的是為了對抗現有的靜態分析工具,以及動態跟蹤的時候,斷到某處以後讓你難以找到它前面執行過的指令是什麼。對於前者,只要稍微調整一下靜態分析的引擎就可以越過這個障礙。對後者,解決的辦法可能就困難一些,因為現在大多數的除錯工具對back trace的支援都很有限。



下面引用由newlaos2003/06/21 03:46pm 發表的內容:
高手出招了。
不過想來也是必然,因為國內有越來越多的軟體作者使用幻影加密(swift的功勞),那麼軟體解密總不能沒飯吃吧。
自然就會有人去研究、去討論,其結果也是可想而知了。
世上沒有無堅不摧的矛,也沒有 ...



 

相關文章