轉一點starforce的資料 (9千字)

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

前兩天玩仙劍II被這個東東給折磨得夠嗆,找點資料也難。前面還有一篇是俄文的呢,鬱悶。終於在smth上找了一些關於sf的資料,轉過來。
******************************

對 Star-Force 的研究 (Cossacks)
作者 ASMax ,郵件地址 asmax@imail.ru
譯者 kxn@SMTH, 郵件地址 kxn@btamail.net.cn
原文 URL : http://www.reversing.net/articles/122001/sf-cossacks.htm

譯者說明:
原文是俄文,本文系譯者參考機器翻譯到英文的結果和自己對脫殼的理解翻譯而成,由於
譯者並沒有條件去試驗文章中的內容,錯誤在所難免,請各位不吝賜教,轉載時請保留原
作者和譯者資訊,謝謝。

××××××××

2000 年終最值得紀念的恐怕就是 Cossacks : The European wars --第一個使用
Star-Force 保護系統遊戲的推出了。Star-Force的出現給程式研究者帶來了很多新的問
題,現在是給這些問題一個答案的時候了。



Star-Force是怎樣的保護?
    這個保護系統最強的主要是以下幾點:它的核心是一個虛擬碼的直譯器,虛擬碼
大大複雜了對Star-Force的研究工作;一部分匯入函式(imported function)
的程式碼是從系統庫中複製出來並進行修改過的;一部分程式程式碼只有在執行時
候才解密出來。除了這些,保護中還大量的應用了下面這些手段:檢測某些記憶體段的CRC
校驗和,經常性地將除錯暫存器DRx清零,利用RDTSC指令來控制解碼不同塊程式碼的時刻(
譯者注:這句不是很明白,此句是對照兩種不同的英文機器譯本硬譯出的),最後一塊
程式碼的解碼甚至是透過截獲int0在 ring0 中進行的。關於這個保護的詳細情況我大致就
介紹這麼多,因為我們將另闢蹊徑,使這些保護方法中的大多數在我們面前根本起不了
作用。



Dump

    在這個版本中Dump還是一件很簡單的事情,在protect.dll中跳轉到原始入口點
之前大致是這樣的程式碼:
        push 64h
        MOV of eax, [Kernel32!Sleep ]
        call eax
        ret
    因此我們設一個 bpx Sleep,啟動遊戲,在斷點處停下來,跟進 ret 指令,然
後用PEditor之類就可以dump了。




恢復import

    Star-Force所使用的import保護技術是我所見過的保護程式中最強的一種。在傳
統的保護中一般最後都是跳轉到真正的函式入口處,或者跳轉到真正函式入口幾條指令之
後的地方。在Star-Force中,所有從kernel32.dll user32.dll advapi32.dll
中import的函式程式碼都整個被複製到保護程式碼的記憶體中了(除了push,pop,jxx 指令),拷
貝過來的程式碼按照下面的規則進行了修改:

        1:  ?????? 改成 nop 和 jmp short $2 (譯者注:這裡沒有一個軟體可以正確
翻譯出原來的程式碼,大家猜猜是什麼呢?)

        2:      push 12345678h 修改成
                MOV eax, 12345678h
                xchg eax, [esp]
        3:      push esi 修改成
                xchg eax, esi
                push eax
                xchg eax, esi
        4:      pop esi 修改成
                MOV esi, eax
                pop eax
                xchg eax, esi
        5: 兩位元組的 jcc 程式碼被修改成 6 位元組的相應程式碼 (譯者注:
          即 0F 開頭的相對跳轉程式碼)
        6: 兩位元組的 push 00h 修改成 5 位元組的版本

    import 函式入口的長跳轉 jmp X 修改成 jmp $+5 ,在首次執行到入口時,X指向
的程式碼進行將windows庫函式程式碼複製和修改的一系列工作,並將 jmp 指令指向修改後
的程式碼。(譯者注:原文說得不是很清楚,這一段是按照自己的理解翻譯的,可能有誤)
不過就這個遊戲來說,被保護的函式只有11個,因此我決定用手動恢復它們(在我後來對
遊戲Venom的研究中解決了這個問題):把程式碼手動轉換回原始的形式,用sice在記憶體中
搜尋入口前10個位元組左右相同的庫函式。找出的函式結果按照在保護程式碼的記憶體中位置排
列如下:
ReadFile, GetUserNameA,  FindNextFileA, WriteFile, VirtualFree, GetFileType,
VirtualAlloc, CreateFileA, DeleteFileA, FindClose, MessageBoxA
將所有import都手動恢復以後,我們就使用一個我常用的工具 ImportList by Boris來重
建 IT。我們把它放進 dump 裡面,這部分的工作就完成了。

恢復 _DllDispatch 的程式碼

        還沒有看暈?那我們進行下一步工作。在我們 dump 出來的程式碼中大約有20多處
(!)呼叫了 _DllDispatch  --  protect.dll中唯一的匯出函式。呼叫它的程式碼大概看
起來是這樣的:

        push ID
        call _DllDispatch

    其中 ID 這個引數決定了哪一段程式碼需要被解碼並執行,ID = 0 的情況是將主
程式解碼出來。值得注意的是,解碼出來的程式碼仍然包含著對 _DllDispatch 的呼叫。但
是這個 _DllDispatch是用前面提到過的虛擬碼引擎執行的虛擬碼。怎麼辦呢?自己跟蹤
每一個呼叫直到跳轉到實際的程式碼?(譯者注:自己的理解)你如果願意試可以自己去
試,不過我將提供一種更有趣的方法,一次性自動獲得所有被保護的程式碼。為了做到這
一點就需要自己寫點程式了。

    首先我們知道一旦被執行過一次,需要的程式碼就以解密的形式存在記憶體中了,怎麼
捕捉到這一時刻呢?很簡單,每個這樣的函式多少都會執行到原來的程式碼中,因此我們
可以截獲對_DllDispatch的呼叫,在將控制權交給protect.dll之前,把原始碼段統統
清成0CCh,這樣從解碼出來的程式碼跳轉出來到任何地方都會觸發中斷,我們截獲int 3
就可以處理之。 更進一步的,我們從ring0的堆疊中找到ring3的堆疊標誌,然後就可以
很快找到解碼出來的程式碼了。



對實現的一些說明


    為了方便處理類似的遊戲,我建議將我們的deprotect.dll 加入到程式的import中
,它就可以截獲protect.dll的入口了,不過這時程式的程式碼還沒有被解碼出來,只有一
個指向protect.dll中的入口呼叫。我們把它修改一下,使得當protect.dll將程式碼段解
碼之後將控制權返回給我們的dll, 接下來我們搜尋遊戲的程式碼,就可以找到很多對
_DllDispatch的呼叫,以及它們對應的ID,把ID都存到一個檔案裡面以避免出現重複的。
然後我們挨個用這些ID呼叫_DllDispatch,在 int 3 的處理函式里面將控制權正確的交
給我們的搜尋-恢復函式。我們需要在解碼出的程式碼中繼續搜尋對 _DllDispatch的呼叫
以得到全部程式碼。當然還得把呼叫這一次DllDispatch的程式碼修改成直接呼叫解密程式碼。
因此搜尋需要進行兩遍,一遍在原來的程式碼中,另一遍在解密後的程式碼中。


    全部工作做完以後,我們得到了兩個檔案,一個是text.bin,這是程式程式碼段中
的程式碼,另一個是code.bin,這是經_DllDispatch解密出的程式碼,需要手動加到dump中
去。整個EXE檔案組裝完畢後, protect.dll 就沒用了,可以刪掉。
最後的一點修正

    啟動解密後的遊戲試驗一下,結果很令人失望:金錢狂漲到無限多,任務說明不
顯示,TCP/IP聯網對戰時選擇地圖後不生成地圖。前兩個問題好像是檔名的問題,
把可執行檔案改成 dmcr.exe 就正常了,最後一個錯誤原因是對某一個_DllDispatch的
恢復時出錯,大約是這個_DllDispatch中沒有跳到其他的程式碼,就沒有被我們的程式捕
捉到(譯者注:這裡大概是一個沒有呼叫任何其他函式的函式),導致最後生成的程式碼
裡面有一個錯誤的呼叫。這樣的函式是我們研究的一個盲點,不過就這個例子來說很好
解決,手動跟蹤了一下,看出這個函式的地址(譯者注:在解碼記憶體區域中的偏移量)
是0A3Ch,手動修改一下呼叫,把5個nop改成對這裡的呼叫就可以了。
現在所有的問題都解決了,Star-Force完全被搞定了。

源程式
        deprotect.asm (7K) 源程式,使用 TASM5.0 編譯成 DLL
        deprotect.dll (8K) 編譯好的DLL檔案
注意:這個DLL只適用於文中提到的遊戲。

(譯者注:上面兩個程式的URL如下
http://www.reversing.net/articles/122001/deprotect.asm
http://www.reversing.net/articles/122001/deprotect.dll


總結
        Star-Force是一種很有意思的保護系統。不要怕在對它的研究上費時間,這是值
得的。我希望這篇文章對你的研究有所幫助,如果你有任何的問題請給我來信,我會很樂
於回覆的。
ASMax
asmax@imail.ru





發信人: kxn (沒錢的事情我是不幹的), 信區: Hacker
標  題: 一些對Star-Force的個人看法以及補充
發信站: BBS 水木清華站 (Fri Nov 29 10:42:21 2002), 站內


從翻譯的文章中可以看出,Star-Force 的保護確實非常優秀,幾個關鍵創意都是
頭一次提出:

1: 使用偽碼解釋引擎來使得對程式碼演算法的分析基本不可能
    像 VB 和 installshield 那樣的虛擬碼程式一直都是破解的一個難題,
    但是 VB 和 is 因為能弄到相應的虛擬碼生成器, 分析起來方便不少。
    對於 Star-Force 這樣搞不到生成器的,希望就更渺茫了

2: 首次大範圍應用對彙編程式碼的反向分析
    Star-Force 一定是有一個比較強的程式碼反向分析引擎的,首先
    在它獨特的 Import 保護方式裡面需要對 windows 庫函式程式碼進行修改
    程式必須能正確的分析出所有的跳轉指令進行修改,才能使得 windows
    庫函式可以在其他的記憶體位置執行,其次 _DllDispatch 生成出來的
    程式碼,明顯是對原 EXE 分析以後,把整個函式摳出來了,而且需要
    修改原函式里面的一些跳轉指令取址指令等以保證能夠正常執行

3: 非常特別的 import 保護方式
    透過將 windows 庫函式程式碼複製到另外的地方執行,就完全從原理上
    廢掉了 imprec 和 revirgin 這類工具

  4: 那個詭異的 DllDispatch
    只能這麼說,這個設計實在是太變態了,弓雖口阿


  Star-Force 自己對這些手段看來也是比較有自信的,因此可執行檔案的
其他部分,比如資料段,資源段等,統統沒有加密,連程式的 OEP 都沒有隱藏
加密過的程式 EP 和 OEP 數值一樣,還有可執行檔案各段的實際長度
在普通的殼裡面, 這些數值都是要極力隱藏的。


從 Star-Force 的保護方式可以看出,將來的軟體保護將越來越趨向對原有程式碼
進行自動修改,而不是像以前加個殼完事,而且還不要求軟體廠商做任何的適應



發信人: kxn (貧僧法號一坨大師), 信區: Hacker
標  題: Re: [翻譯]對 Star-Force 的研究 (Cossacks)
發信站: BBS 水木清華站 (Wed Feb 12 13:54:37 2003), 轉信


還有點其他資訊, 有的來源是同作者的另一篇文章, 有的來源是自己瞎看的
一起貼上來算了, 另一篇文章懶得翻譯了, 辛辛苦苦翻譯一堆, 轉的人果然
還是把前面的話刪掉 :(

ASMax 另一片文章裡面的介紹了一個新版本的 SF, 主要內容就是兩點,

1: 新版本 SF 程式碼使用了 INT1 和 INT3 , 不僅使得跟蹤不便, 還使得原來的
  用 0xCC 填充程式碼段來恢復 __DllDispatch 的辦法失效了

  ASMax 的應對方法如下:

  在 deprotect.dll 的 DLLMain 裡面加上恢復 INT3 和 INT1 的程式碼, 方便跟蹤.

  DllDispatch 的恢復思路跟以前一樣, 不過這次改成用 0xFF 填充, 攔截
  INT6 (非法指令)

2: import 的快速恢復,
  把自己的 kernel32.dll user32.dll advapi32.dll 修改,使得 API 入口程式碼大致像

  CreateFileA :
  push  77e56724  ; 原來的 CreateFileA 入口
  retn

  這樣 StarForce 複製過來的程式碼就變成

  mov eax, 77e56724
  xchg eax,[esp]
  ret

  一下就得到 import 的入口了


關於新的 SF 3.0

  SF3 的 import 直接用 imprec  auto search 不到了, 不過還是可以 dump
  出來, 反編譯一下就看出 iat 在哪裡,

  Dlldispatch 的程式碼 SF3 用了一個很簡單也是很有效的辦法來保護
  以前 SF 的 Dlldispatch 是直接把程式碼解出來到程式碼段的, 因此以前 SF
  保護的可執行其程式碼 section 是空的, rawsize = 0 , vsize != 0
  現在 SF 把程式碼段預先填充內容, 解出來的資料和原來處的資料做運算後才是
  正確的程式碼, 這樣 0xCC 和 0xFF 大法都不能用了. so .....

相關文章