同學翻譯的一篇FlexLm文章 (9千字)

看雪資料發表於2003-03-31

UGFLEX――傳奇在繼續
作者:macilaci  翻譯:上官振寧
需要的工具
Debugger (SICE, OllyDbg--非常棒的東東),Wadsm或者IDA,Flexlm SDK 7.2或者更高版本(非必須),一些最近的資訊(從Pilgrim, Nolan Blender或其他的地方得到)。
目標位置(對付得東東是個CAD軟體,叫做Solidedge。)
http://www.ugsolutions.com
http://www.solid-edge.com
正文
經過最初的嗅聽之後,發現了讀取license檔案(selicense.dat)的DLL。也許我們並沒有建立License檔案,所以License Key也沒有,它是這樣的:
FEATURE SOLIDEDGECLASSIC sedemon 11.0 permanent uncounted \
    123456789ABC HOSTID=ANY ISSUER="I don't know"
我們的ugflex.dll被jutil.dll替換。還有個MAP檔案,格式如下:
Address        Publics by Value              Rva+Base    Lib:Object
0001:00000010  _JSetVACallback@4              5a001010 f    auto.obj
0001:00000040  ?IsAutomationEnabled@@YAHXZ    5a001040 f    auto.obj
0001:00000050  ?IsLicenceValidForAutomation@@YAHXZ 5a001050 auto.obj

為了與idasym.exe檔案一起使用這個MAP檔案,將Rva+Base還有Lib:Object列刪除。然
後將建立的sym檔案與symbol loader一起使用(設斷點易如反掌,接著往下看就明白了)

由經驗得知,實際上對於License的檢查是在LC_CHECKOUT進行的(摘自flexlm手冊)

lc_checkout()
SYNTAX  status = lc_checkout( job ,feature ,version ,num_lic ,flag ,code , dup_group )
說明:查出一個或多個具體的feature(不好翻譯,姑且用e文)。如果呼叫lc_checkout()的程式存在,那麼check出的license將返回供另一使用者使用。
    如果將上面函式中的flag設定成LM_CO_WAIT,那麼這個程式將等待,一直到達到這個feature需要的license數目。License檔案的版本必須等於或高於lc_checkout呼叫中的version引數。
    If the license file is counted, that is, if the number of users specified on the FEATURE line is non-zero, lc_checkout() will request the license from alicense server. If the number of users on the FEATURE line is uncounted, it will grant permission based on the contents of the license file onlyŠhostid,version, expiration date, etc.(感覺沒什麼用,沒翻譯)

在5a04cf70 處的_lc_checkout是設斷點的好地方!找到了FEATURE名後,就可以按照上面的格式建立自己的license檔案了^_^。為了保證正確性,給出所有的FEATURE名:SOLIDEDGECLASSIC, SOLIDEDGEADVANCEDPAR, SOLIDEDGEXPRESROUTE, SOLIDEDGEFEATURERECO, SOLIDEDGEXPAND3D,
SEWEBPUBLISHER, SOLIDEDGEHANDBOOK, SOLIDEDGEMANAGER(note:有些feature如expand3d要在別的可執行程式中採用的到,以後再說^_^)
再來看l_good_lic_key函式。_lc_checkout命中三次而_l_good_lic_key只有一次。挺敗吧?下面是程式片斷:
5A04DA6C loc_5A04DA6C:              ;CODE XREF _lm_start_real+343j
5A04DA6C                mov    edx, [ebp+arg_14]
5A04DA6F                push    edx            ; vendorcode 結構(這次有所改進-加密了)
5A04DA70                mov    eax, [ebp+var_20]
5A04DA73                push    eax
5A04DA74                mov    ecx, [ebp+arg_0]    ;我們的license information
5A04DA77                push    ecx
5A04DA78                call    _l_good_lic_key    ;檢查license
5A04DA7D                add    esp, 0Ch
5A04DA80                test    eax, eax
5A04DA82                jnz    short loc_5A04DA89    ;這個你應該很熟悉了吧:-)

如果執行part.exe而沒有反應,可能是應為你沒有執行seiges.exe。part.exe中有些反debug的程式碼的部分。執行seiges.exe並將eax置成非零,將得到status=OK.但是僅僅有patch並不能讓人滿意,所以我們接著往下看^_^

5A04E995                add    edx, 54h
.
.
5A04E99C                push    eax
5A04E99D                call    _l_extract_date
.
.
5A04E9B1                push    ecx            ;我們的vendorcode structure
5A04E9B2                mov    edx, [ebp+var_CC]
5A04E9B8                push    edx          ;feature(特徵名)
5A04E9B9                mov    eax, [ebp+arg_4]
5A04E9BC                push    eax
5A04E9BD                mov    ecx, [ebp+arg_0]
5A04E9C0                push    ecx
5A04E9C1                call    _l_ckout_crypt

跟蹤上面的程式碼我們發現_l_ckout_crypt做了一些重要的工作。這裡只改變了seed的值而沒有改變key的值。由於key的值沒有改變,我們姑且認為他們已經被解密了,但seed的值仍然隱藏著!繼續追蹤,_real_crypt出現了(敗了,這麼個敗名字)
5A050B44                mov    eax, [ebp+arg_0]
5A050B47                push    eax
5A050B48                call    _real_crypt   
5A050B4D                add    esp, 10h

下面是_real_crypt的程式碼片斷:

.
.
5A050ECB                push    ecx
5A050ECC                call    _l_getattr              ;取得license attributes
.
.
5A05106A                push    eax
5A05106B                call    _l_good_bin_date        ; date
.
.
5A0510DA                mov    edx, [ebp+arg_0]
5A0510DD                push    edx
5A0510DE                call    _move_in_hostid    ; 從license檔案裡獲取hostid
.
.
5A051456                push    offset aDup_group ; "DUP_GROUP" ;DUP_GROUP=UHD意味著可能的分組為(DUP_USER|DUP_HOST|DUP_DISPLAY),
所以對於使用者在一臺主機上,另外的對於feature的使用不會銷燬另外的licenses. (看不太懂哦:(  )

5A05145B                mov    eax, [ebp+arg_4]
5A05145E                mov    ecx, [eax+94h]
5A051464                push    ecx
5A051465                call    _addi            ;把這個加到license中
.
.
5A051855                push    ecx
5A051856                call    _l_ckout_string_key            ;這個怎樣?
5A05185B                add    esp, 18h

_l_ckout_string_key值得注意!
5A052902 _l_ckout_string_key proc near          ; CODE XREF: _real_crypt+AD1p


5A052902                push    ebp
5A052903                mov    ebp, esp
5A052905                sub    esp, 1E4h
.
.
.
5A053755              call      _our_encrypt2            5A05375A                add    esp, 4
5A05375D                jmp    short loc_5A05376C
5A05375F ; ΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖ
5A05375F
5A05375F loc_5A05375F:          ; CODE XREF: _l_ckout_string_key+E43j
5A05375F                                        ; _l_ckout_string_key+E4Cj
5A05375F                push    offset byte_5A0C5820
5A053764                call    _our_encrypt        ;the second encrypt
.
.
.
5A05384B                mov    ecx, [ebp+var_188]
5A053851                add    ecx, 1
5A053854                mov    [ebp+var_188], ecx
5A05385A
5A05385A loc_5A05385A:          ; CODE XREF: _l_ckout_string_key+F47j
5A05385A                mov    edx, [ebp+var_188]
5A053860                cmp    edx, [ebp+var_18C]
5A053866                jge    loc_5A0539E0
5A05386C                mov    eax, [ebp+var_188]
5A053872                mov    cl, [ebp+eax*2+var_168]
5A053879                mov    [ebp+var_1CC], cl
5A05387F                call    ds:__p___mb_cur_max
5A053885                cmp    dword ptr [eax], 1
.
.
.
5A0539CB                xor    eax, eax
5A0539CD                mov    al, byte_5A0C5820[edx]              ; 最終 - 比較license
5A0539D3                cmp    ecx, eax
5A0539D5                jz      short loc_5A0539DB              ;比較下一個byte
5A0539D7                xor    eax, eax                  ;錯誤的key
5A0539D9                jmp    short loc_5A053A01             
5A0539DB ; ΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖΖ
5A0539DB
5A0539DB loc_5A0539DB:        ; CODE XREF: _l_ckout_string_key+10D3j
5A0539DB                jmp    loc_5A05384B        ;loop back

上面的迴圈與版本7中的有些類似(現在是7.2)。5A0C5820是產生真正的key的地方!這裡有必要說明一下key的產生:如果沒有license key,我們的license(格式正確)是混亂的,兩者好像是透過addi function函式聯絡到一起的。所以現在程式的任務就是計算vendorseed,並在4個vendorkey的幫助下同混亂的license混合(可能是做某種運算^_^)。上面說得工作將在5A0C5820處完成。在5A0C5820處bpm,我們得到:

.
.
5A053334                mov    byte_5A0C5820[ecx], al    ;here we go
5A05333A                jmp    short loc_5A0532F9
5A05333C loc_5A05333C:          ; CODE XREF: _l_ckout_string_key+A0Dj
5A05333C                cmp    [ebp+var_188], 0

從5A05333C處開始追蹤,我們發現了計算seed的程式碼:

5A0533EA                xor    eax, ebx        ;計算正確的seed
5A0533EC                push    eax            ;入棧
5A0533ED                call    sub_5A053AD3
5A0533F2                add    esp, 4
5A0533F5                mov    [ebp+seed_one], eax
5A0533FB                mov    edx, [ebp+seed_one]
5A053401                and    edx, 0FFh
.
.
5A0534C9                add    eax, 1
5A0534CC                mov    [ebp+var_10], eax
5A0534CF                mov    [ebp+seed_one], 3D4DA1D6h  ;隱藏seed
.
.
5A053548                push    eax    ;第二個seed入棧
5A053549                call    sub_5A053AD3
5A05354E                add    esp, 4
5A053551                mov    [ebp+seed_two], eax
5A053557                mov    edx, [ebp+seed_two]
.
.
5A053628                mov    [ebp+var_10], eax
5A05362B                mov    [ebp+seed_two], 3D4DA1D6h  ;隱藏5A053635                jmp    loc_5A053735

將seed隱藏能很好的防止記憶體dump工具將seed解出來。解seed的過程只能在特定位置並且是執行時才可以!

總結:
LC_CHECKOUT ---
        |
        |
        _l_good_lic_key― /*加密的keys*/
                  |
                  |
                  _l_ckout_crypt---/*解密的keys*/
                            |
                            |
                            _real_crypt---
                                  |
                                |
                        _l_ckout_string_key---
                        |
                        |
                5A0533EA  /*計算第一個seed*/
                        |
                        |
                5A053547  /*計算第二個seed*/
                        |
                        |
                5A0539DB <-
                        |
                        |
                5A0539CD---  /*license比較*/
現在我們可以修改lm_code.h並且編譯lmcrypt。使用3D4DA1D6h這樣的位元組模式,我們在AddInlm.dll中找類似的位置。其實我們只需要LC_CHECKOUT作為feature名。使用其他的模式能得到相應的位置(對於沒有flexlm SDK的朋友來說,比較有用):
jutil.dll          AddInlm.dll        Selicwiz.exe
5A0533EC        046CAEDC         00428C6C
.
5A0539CD        046CB4BD         0042924D

The origin of the above code is the object lm_ckout.obj winthin the lmgr.lib library.(大體意思是上面的程式碼從那裡來的)

                                             |
                                             |
                                             5A0533EA  /*計算第一個seed*/
                                             |
                                             5A053547  /*計算第二個seed*/
                                             |
                                             5A0539DB <-                                                   
                                                 |      |
                                                  5A0539CD---  /*license比較*/
                                             |
                                            --
翻譯得不好,大蝦莫笑:P

相關文章