DataFit V7.0.36註冊過程的分析 (9千字)

看雪資料發表於2001-11-09

軟體簡介:DataFit是一個科學與工程工具,用來對資料進行繪圖、迴歸分析和統計分析。軟體已內建上百個數學模型,並可由使用者自己設定數學模型,對於初學者和專家來說,該軟體都是一個高效率的易於使用的曲線擬合和分析的工具。(本人在10多年前上大學時就對曲線擬合情有獨鍾,使用了一下該軟體,對它的曲線擬合真是印象很深,簡單說就是傻瓜也能把一組複雜的資料擬合出很好的結果――儘管有的曲線擬合得非常好,但又讓我覺得擬合的非常沒有道理)
下載地址:http://www.oakdaleengr.com/download.htm
分析工具:IDA Pro 4.15,SmartCheck 6.60
前言:要想獲得這個軟體的註冊碼相對來說,需要費一番功夫的。去年曾經用SoftICE和SmartCheck追過,追了半天追不出來,最後只好採用暴破的形式使之成為註冊版,很醜。今年經過對幾個VB程式的註冊碼的分析,信心大增,於是又開始跟這個軟體搏鬥,不過還好,終於解決了。這個軟體的註冊碼的生成確實經過該公司軟體設計人員的考慮,因此雖然最後仍然是透過STRCMP這個函式進行比較的,但由於是透過對註冊碼進行變換之後的比較,因此透過中斷STRCMP獲得字串來進行註冊肯定是不行的(即非明碼比較),只有瞭解了該軟體註冊碼的計算過程,才能夠獲得註冊碼,其中的關鍵就是註冊碼的變換過程。不過由於有IDA Pro和SmartCheck這兩個利器,同時該軟體並沒有採取不可逆演算法,這個程式註冊碼的計算還是分析出來的。

分析過程:啟動SmartCheck,選擇開啟datafit.exe,執行後會顯示評估版(EVALUATION COPY)對話方塊,按“繼續”按鈕後進入主程式。選擇Help選單下的Enter license命令,會彈出Enter license對話方塊,讓你輸入許可號,經過分析知道,這裡最好輸入16個字母,大小寫無關,如:ABCDEFGHIJKLMNOP(為什麼輸入這樣的字串,摸索出來的嘛,一般來說,分析註冊過程要避免輸入這種字串,但這個軟體是個例外,輸入這種字串後,可以很清楚地知道字串變換後各自的位置,這樣可以在SmartCheck中就可以清楚看出字串的變換過程,減少在IDA中透過觀察反彙編結果來分析程式的過程),輸入後軟體直接退出該對話方塊,不會顯示什麼“註冊碼不正確”之類的容易被人利用的資訊,不過沒關係。退出DataFit,軟體又會顯示評估版對話方塊,單擊“Exit Datafit”按鈕退出。現在,SmartCheck已經把整個執行Datafit的過程忠實地記錄下來了,結合IDA分析吧。

在SmartCheck中找到Parentfrm_Unload,移動滑鼠向下不遠就是註冊碼的變換過程了。

流程:Parentfrm_Unload
:007DABF3          call    sub_51E9C0  ;退出是儲存設定
:007DABF8          cmp    word_952108, bx
:007DABFF          jz      short loc_7DAC29
:007DAC01          call    sub_56E5C0  ;註冊碼的變換及比較過程,call見下面
:007DAC06          mov    eax, dword_952104
:007DAC0B          mov    ecx, dword_952100
:007DAC11          push    eax
:007DAC12          push    ecx
:007DAC13          call    ds:__vbaStrCmp  ;字串比較

註冊碼的變換及比較過程
:0056E5C0          push    esi
:0056E5C1          mov    esi, ds:__vbaStrCopy
:0056E5C7          mov    edx, offset dword_455228  ;值為1ah
:0056E5CC          mov    ecx, offset dword_952100
:0056E5D1          call    esi ; __vbaStrCopy
:0056E5D3          mov    edx, offset dword_455228
:0056E5D8          mov    ecx, offset dword_952104
:0056E5DD          call    esi ; __vbaStrCopy
:0056E5DF          mov    eax, dword_9520FC
:0056E5E4          push    eax
:0056E5E5          call    sub_94B400  ;註冊碼的變換過程
:0056E5EA          mov    esi, ds:__vbaStrMove
:0056E5F0          mov    edx, eax
:0056E5F2          mov    ecx, offset dword_952104
:0056E5F7          call    esi ; __vbaStrMove
:0056E5F9          push    offset dword_952104
:0056E5FE          call    sub_5A0E90  ;註冊碼的比較過程
:0056E603          mov    edx, eax
:0056E605          mov    ecx, offset dword_952100
:0056E60A          call    esi ; __vbaStrMove
:0056E60C          pop    esi
:0056E60D          retn

註冊碼的變換過程:
:0094B463          call    sub_94A600  ;獲得註冊碼字串的長度並用Mid函式檢測字元
:0094B475          mov    edx, [ebp+var_20]
:0094B478          push    edx
:0094B479          call    sub_94A810  ;變換1
:0094B496          mov    eax, [ebp+var_20]
:0094B499          push    eax
:0094B49A          call    sub_94AD90  ;變換2
:0094B4B2          mov    edx, [ebp+var_20]
:0094B4B5          push    edx
:0094B4B6          call    sub_94AA70  ;變換3
:0094B4C2          mov    eax, [ebp+var_20]
:0094B4C5          push    eax
:0094B4C6          call    sub_94AF30  ;變換4
:0094B4D2          mov    ecx, [ebp+var_20]
:0094B4D5          push    ecx
:0094B4D6          call    sub_94A810  ;變換5

註冊碼的變換過程:
變換1:透過Mid函式取字元,先取偶數位字元放到前面,然後奇數位字元放到後面
      結果:ABCDEFGHIJKLMNOP ====> BDFHJLNPACEGIKMO

變換2:字串左邊3個放到最後,然後轉為小寫
      結果:BDFHJLNPACEGIKMO ====> hjlnpacegikmobdf

變換3:用Mid函式每次取1個字元,令該字元的ASCII值-61h,如果該值大於19h,則結果為0h,否則用下表變換:
新字元:abcdefghijklmnopqrstuvwxyz 或 新字元:lesiaxkcpgnmvrzfbhjuqdoywt
原字元:eqhvbpjrdsgalkwiuncztmyfxo    原字元:abcdefghijklmnopqrstuvwxyz
      結果:hjlnpacegikmobdf ====> cgmrflsakpnvzeix

變換4:用Mid函式每次取1個字元,令該字元的ASCII值-0ch,如果結果不小於61h則不變,如果小於則加上1ah
      結果:cgmrflsakpnvzeix ====> quaftzgoydbjnswl

變換5:同變換1
      結果:quaftzgoydbjnswl ====> ufzodjslqatgybnw
經過上面5步變換後的字串就是要比較的字串

比較過程:call 5A0E90
:005A0F9E          mov    [ebp+var_64], 0FFFFFFFFh  ;-1
:005A0FB1          call    ds:rtcRandomNext          ;Rnd(-1)
:005A0FC4          mov    word ptr [ebp+var_64], 0Ah ;10
:005A0FD1          call    ds:rtcRandomize            ;Randomize(10)
:005A0FEC          mov    eax, 12Ch                  ;300
:005A0FF1          cmp    word ptr [ebp+var_2C], ax  ;是否進行了300次
:005A0FF5          jg      loc_5A1126                ;是則轉
:005A1009          mov    esi, 1
:005A100E          mov    eax, 10h                  ;16
:005A1013          cmp    si, ax                    ;是否進行了16次
:005A1016          jg      loc_5A10F4                ;是則轉而比較變換字串與新“隨機”生成的是否相同
:005A102E          call    ds:rtcRandomNext          ;取隨機數
:005A1034          fstp    [ebp+var_260]              ;放到[ebp+var_260]中
:005A103A          mov    eax, 7Ah
:005A103F          mov    cx, ax
:005A1042          mov    eax, 61h
:005A1047          sub    cx, ax
:005A104A          jo      loc_5A234B
:005A1050          add    cx, 1                      ;7ah-61h+1=1ah
:005A105A          movsx  edx, cx
:005A105D          mov    [ebp+var_288], edx
:005A1063          fild    [ebp+var_288]
:005A1069          fstp    [ebp+var_28C]
:005A106F          fld    [ebp+var_28C]
:005A1075          fmul    [ebp+var_260]              ;1ah*隨機數
:005A107B          movsx  eax, ax                    ;eax=61h
:005A107E          mov    [ebp+var_290], eax
:005A1084          fild    [ebp+var_290]
:005A108A          fstp    [ebp+var_294]
:005A1090          fadd    [ebp+var_294]              ;61h+1ah*隨機數
:005A10A0          call    ds:__vbaR8IntI2            ;取整
:005A10B9          call    ds:rtcBstrFromAnsi        ;根據ASCII值取相應的字元,即VB的chr函式
:005A10CF          lea    ecx, [ebp+var_3C]
:005A10D2          call    ebx ; __vbaStrMove        ;放到[ebp+var_3C]
:005A10DD          mov    eax, 1
:005A10E2          add    ax, si                    ;計數器加1
:005A10EB          mov    esi, eax
:005A10ED          xor    edi, edi
:005A10EF          jmp    loc_5A100E                ;取下一個字元
:005A10F4          mov    eax, [ebp+arg_0]
:005A10F7          mov    ecx, [eax]
:005A10F9          push    ecx
:005A10FA          mov    edx, [ebp+var_3C]
:005A10FD          push    edx
:005A10FE          call    ds:__vbaStrCmp            ;字串比較
:005A1104          test    eax, eax
:005A1106          jz      short loc_5A111F          ;相等則轉(註冊碼正確)
:005A1108          mov    eax, 1
:005A110D          add    ax, word ptr [ebp+var_2C]  ;計數器加1
:005A1117          mov    [ebp+var_2C], eax
:005A111A          jmp    loc_5A0FEC                ;取下一組(共300組)

上面的過程用VB表示就是:
Rnd(-1):Randomize(10)
for i=1 to 300:Rand_Code=""
    for j=1 to 16:Rand_Code=Rand_Code+Chr(int(&H61+Rnd*&H1A)):next j
    if Rand_Code="ufzodjslqatgybnw" then
        註冊碼正確:exit sub
    endif
next i

應該注意:上面雖然是隨機生成的300個註冊碼,但由於固定了隨機種子,因此300個註冊碼也是固定的,但不知不同機器的隨機種子值是否相同,從我測試的來看,各機器間的隨機種子值是相同的,因此註冊碼應是通用的。不過有5個肯定是通用的,原因見下面:
從5A1130-5A1EE4將變換字串分別與下面5組固定字串進行比較,如果相同則註冊碼正確:
(1) acllkakiojgoymjg (2) cpnikjlaepkvccfo (3)qhkxakuwdkzuaaol (4) lvzlpckxgecgeunm (5) mflkssoltlajgjmp
如果與上面的均不相同則生成下列字串:"areaunder"(語句5A1F10-5A2074)並返回
如果註冊碼正確則[ebp+var_44]=-1,否則=0

註冊碼的反推:
設Regcode為最終參與比較的字串(看上面,共305個),Regcode1為反推出的註冊碼
說明:註冊碼的長度為16且均是字母,這裡反推出的註冊碼為小寫的,實際輸入時大小寫無關。
步驟1:for i=1 to 8:Regcode1=Regcode1+mid(Regcode,i+8,1)+mid(Regcode,i,1)
步驟2:for i=1 to 16
if asc(mid(Regcode1,i,1)) <=&H6E then
  mid(Regcode,i,1)=chr(asc(mid(Regcode1,i,1))+&HC)
else
  mid(Regcode,i,1)=chr(asc(mid(Regcode1,i,1))+&HC-&H1A)
end if
步驟3:for i= to 16
  mid(Regcode1,i,1)=mid("eqhvbpjrdsgalkwiuncztmyfxo",(Asc(mid(Regcode,i,1))-&H60),1)
步驟4:Regcode=Right(Regcode1,3)+Left(Regcode1,13)
步驟5:Regcode1="":for i=1 to 8:Regcode1=Regcode1+mid(Regcode,i+8,1)+mid(Regcode,i,1)

註冊器已做成,5個通用的註冊碼中的一個為:OFRETLWUYWWQMQNY,透過隨機種子生成的300個註冊碼中的一個為:CKVVZSTQYVKKJXQB,如果大家下載了這個軟體,請測試並報告一下後面的隨機生成的註冊碼是否可以註冊成功,如果成功則說明那300個隨機生成的註冊碼也是通用的。

補充說明:我分析的這個版本是V7.0.36,目前該網站提供的版本是V7.1.44,我下載回來分析了一下,註冊過程一點沒變,上面的註冊分析過程同樣適用於新的版本。
另外,登錄檔中H.L.M\Software\Oakdale Engineering\DataFit\Version\desckey值表示的是軟體第一次執行的時間,跟序列號無關,註冊成功後,會建立一個License的鍵值,即正確的註冊碼字串。

相關文章