吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|www.pyclye.live

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 6883|回復: 98
上一主題 下一主題

[原創] 某國外音視頻轉換軟件之注冊算法、加密算法分析及逆向注冊機實現

  [復制鏈接]
跳轉到指定樓層
樓主
solly 發表于 2019-12-27 17:58 回帖獎勵
本帖最后由 solly 于 2019-12-29 01:59 編輯

這篇帖子是對一個國外的音頻軟件的注冊加密算法進行分析和逆向過程記錄,分成三個部分:
1、注冊碼的校驗碼。
這是在輸入用戶名和注冊碼時進行的校驗,包括注冊碼格式校驗和CRC校驗。
2、注冊碼加密驗證。
這是一個重啟后進行的驗證,在軟件每次啟動時都會驗證。(這一部分跟貼寫在后面)。
3、注冊算法分析和逆向注冊機。
這一部分還原出軟件的算法代碼,再進行代碼化簡,分析出算法,并編寫注冊機。(這一部分也是分開跟帖在后面)


軟件名稱為 B_o_i_l_s_o_f_t  A_u_d_i_o  Converter(加點下劃線脫敏,防止過敏反應),這個公司有好多個音視頻相關轉換、分切和合并等的工具軟件,
好象注冊算法和注冊碼格式都差不多,只是加解密的密碼不一樣,當然也不一定正確,因為我也沒有驗證其它程序的算法,只是看了一下密碼。
補充:已驗證該公司的視頻轉換軟件的算法也是一樣的,只是密碼不一樣,見后面跟貼中的已更新了的注冊機的代碼中的注釋

一、注冊碼的校驗碼。


還是按正常逆向步驟一步步來,先看看文件信息。如下圖所示:


由 Microaoft VC 9.0 編譯,沒有加殼,這是一個好消息,不用脫殼了。

再“Scan /t"成 VC8了,沒什么影響。


怎么找注冊函數入口就不説了,我們先看看其導入表信息,用 Stud_PE 查看:

Stud_PE 也顯示沒有殼。

可以看到,這是一個基于 QT4 框架開發的軟件,QT4是什么就不説了,反正就是一個 MFC 類似的開發框架,跨平臺UI套件。


重點在下面:


可以看到,這里導入了一個 "trreg_bl.dll" 的庫,其實,這個就是注冊碼算法庫,注冊驗證的相關函數都在這里,省去大把時間找注冊代碼,直接在其導出函數下斷就可以了,這里沒有導出函數名,是用的序號。
下面用 IDA 打開這個動態庫反編譯,就可以看到其所有導出函數了,如下圖所示:


其中所選中的那一行函數:TRRegKeyInstall_BL,就是輸入并保存注冊碼的函數,并對注冊碼進行格式檢查和CRC校驗。


首先,我們用 OD 載入該軟件,因為是QT 架構,入口代碼首先一個調用進入QT進行初始化,如下圖所示,已經到了QT的入口代碼了:


可以看到后面有一個調用 QtCore4.qWinMain 調用,這個調用是初始化QT的環境,放大看看:

再往下走,如下圖所示:

進入程序入口,我們 F7 進入此函數,可以看到如下代碼,如下圖所示:


這就是調用程序入口,要顯示應用的UI了,我們不看這些了,先 F9 進入程序看看,如下圖所示:

右上角,有一個”Register“ 按鈕,這是注冊用的。先看看 "About",如下所示:

顯示”unregistered“,未注冊。

點”Register“,進行注冊,彈出如下所示注冊界面:

隨便輸入注冊假碼數據,點”OK“,會彈出如下消息框:

表示注冊碼無效。


下面進入正題,進行注冊碼算法的跟蹤,我們先到 trreg_bl.dll 中下斷點,先找到其導出函數:

”右鍵“-->”查找“-->”所有模塊中的名稱“,顯示如下界面:

找到我們需要的 "TRRegKeyInstall_BL",如上圖所示,雙擊進入函數,如下圖所示:

在函數內下一個斷點,如上圖所示位置。再回到軟件,重新回到軟件的注冊界面點”OK”,馬上就會來到我們下的斷點處,如下圖所示:

在 0x(nnnn)113E call 0x(nnnn)1FF0 處,就是注冊碼校驗的調用。(注,nnnn 表示值不固定,dll 重定位后,高2字節可能會有變化,每次重進軟件都可能不一樣

按 F7 進入該函數,該函數先對用戶名進行檢查,檢查用戶名是否為空,不為空則計算用戶名的長度,如下圖所示:


再往下走,就是注冊碼的格式檢查了,如下圖所示:


再次按 F7 進入該函數,來到如下位置:

這里調用 call 0x(nnnn)15A0,對注冊碼以“-”號進行切分,分成7段,不是7段就退出了,返回到上一級函數:

這里又對注冊碼進行長度驗證,長度應為 0x34 個字符,不是也會退出。這里説明一下,C++ 的 string 內存中的存貯格式,結構如下:
[C] 純文本查看 復制代碼
struct string {
    void * ptr;
    union {
        char * str_ptr;
        char[16] str_buff;
    }
   long length;
   long maxLength;
};

當字符串長度小于16字符時,存于結構中的 str_buff 中,當長度大于 0x0F 時,則 str_buff 前4字節保存的是字符串的地址,也就是保存的 str_ptr 指針了。
length 保存在是字符串的長度,maxLength 是可保存字符串的最大長度。
第1個成員 void * ptr 沒搞清楚,一般是一個地址,不過好象也沒什么用,有時為 0。


長度檢查失敗再往上返回,如下圖所示:

當 al==0時,表示格式檢查失敗。
下面我們來看看,對注冊碼進行切分并檢查的函數 call 0x(nnnn)15A0,如下圖所示,我們F9返回界面,重新點“OK”再次進入注冊函數,來到下面位置:

可以看到,注冊碼是由“-”分隔成多個部分的。按 F7 進入 call 0x(nnnn)2B90,如下圖所示:


在注冊碼中,循環查找“-”符號,我們手動在輸入的注冊碼“78787878”中間改一位為“-“,如上圖 OD 數據區所示,跟蹤代碼運行情況。
具體代碼如下:
[Asm] 純文本查看 復制代碼
78612BC3    8BF3                mov     esi, ebx                      ; esi ===> 注冊碼
78612BC5    3BF7                cmp     esi, edi
78612BC7    73 26               jnb     short 78612BEF
78612BC9    8DA424 00000000     lea     esp, dword ptr [esp]          ; 在SN中查找 "-" 字符
78612BD0    8B4424 1C           mov     eax, dword ptr [esp+1C]
78612BD4    0FBE0E              movsx   ecx, byte ptr [esi]           ; ecx == sn[i]
78612BD7    8B5424 18           mov     edx, dword ptr [esp+18]
78612BDB    50                  push    eax                           ; 1
78612BDC    51                  push    ecx                           ; sn[i] == 0x37
78612BDD    52                  push    edx                           ; '-'
78612BDE    E8 8DFE0000         call    78622A70                      ; _memchr(),檢查注冊碼字符串是否含有"-"
78612BE3    83C4 0C             add     esp, 0C
78612BE6    85C0                test    eax, eax
78612BE8    75 0F               jnz     short 78612BF9                ; 找到"-"則跳轉
78612BEA    46                  inc     esi                           ; sn++, sn[i], i++
78612BEB    3BF7                cmp     esi, edi
78612BED  ^ 72 E1               jb      short 78612BD0                ; 循環查找


如果找到”-“號,則跳轉處理,如下圖所示:

找到“-”號就返回其所在位置索引值,并從函數返回。

這時還是對注冊碼進行切分,截取”-“號后面的內容再進行檢查。

如下圖所示,這個 call 0x(nnnn)2B90,就是對字符串進行切分處理的函數。

在剩下的字符串,再手動改一位為”-“,驗證是否會再次切分。如下圖 OD 的數據區所示。


返回值不為-1時,表示找到”-“,繼續下一輪查找和切分。如下所示:


切分完后,返回到上一級函數,如下圖所示:

因為我們改了兩次”-“,字符分成了 3 段,eax == 0x03 了,但還是不夠7段。
我們  F9 運行,重新返回界面,輸入符合要求的 7 段式注冊碼,如下圖所示:

再次”OK“,一路來到下圖所示位置:


可以看到,這次 eax == 0x00000007 了,后面的 cmp eax, 7 的檢查也會成功了,分段數正確后,來到下面一個循環處:

這里對切分出來的每一段進行格式檢查,前6段是一樣的檢查,第7段另外檢查,如下圖所示,檢查1~6段。

來到下圖所示位置,又是一個長度檢查:

需要8位長度,上面 OD 數據區顯示,我們前面輸入的不對,只有5個字符長度,再次 F9 繼續回到界面,輸入新的注冊碼:

再一次”OK“,來到各段格式檢查處:

由上圖可見,在 OD 數據區顯示的字符串中,顯示長度為 0x08 了,字符串格式見前面的 struct string 的説明。
長度檢查完后,再進行字符范圍檢查,保證每段字符串都可以轉化成 16 進制數,如下圖所示:

上圖中 call 0x(nnnn)1700 就是對字符范圍進行檢查。如果都沒問題,則繼續檢查下一段:

最后,當前6段都檢查完成后,就單獨對第7段進行檢查,如下圖所示:

進入第7段檢查,如下圖所示:

可以看到,這里要求的長度是4個字節,我們輸入的是8個字符,所以還得重新來一次,F9 后再次修改注冊碼:

按”OK“繼續,來到前面的位置,如下圖所示:


如上圖所示,SN 第7段的長度為 4 了,這一次終于完美達成其對注冊碼分段格式的要求了。繼續 F8 往下走,退出循環,來到下面位置:

這里一個調用 call 0x(nnnn)2AB0,是對剛才切分成7段的注冊碼重新進行連接,生成一個新字符,這個字符串就不含”-“號了,執行調用后如下圖所示:


上圖中的 OD 數據區顯示了這個字符串的結構,因為長度為 0x34,大于 0x10,結構內只保存了字符串的地址:0x02C91F80,最大長度是 0x3F,實際長度是 0x34。
跟隨上面的地址,可以看到這個字符串的內容,如下圖所示:

繼續 F8 向下走,來到如下圖所示位置:

這里的調用是釋放7個子分段的字符串了,切分及合并就完成了,退出函數,返回上一級。

這里對合并的字符串進行長度檢查,長度必須為 0x34,否則就是無效的注冊碼。
檢查長度合法后,跳轉到下一步,進行注冊碼的有效性檢查,如下圖所示:

首先,調用 call 0x(nnnn)3B60 將注冊碼轉換成 16 進制數據,如下圖所示:

上圖中 OD 數據區顯示的是已經轉換好了的數據。
接下來是對用戶名的處理了,如下圖所示:

通過分析,這是通過查表方式,對用戶名進行 CRC 校驗碼的計算,如上圖所示,OD 數據區是 CRC 的數據表。
對名字計算CRC后,還有一段對 NULL 字符串進行 CRC 計算的代碼,猜測是該算法對機構名之類的進行 CRC 驗證,但該軟件沒有用到。
接下來,對注冊碼進行奇偶的一個檢查,如下圖所示:

當索引號是奇數,進行累加,為偶數則進行異或,結果分別存于 BL 和 DL,是一個分開的8位校驗。
接下來,把剛才計算生成2個字節,組成一個雙字(word),同時取一個軟件內置的常量字符串的頭兩個字節,對這個結果進行XOR計算,再將結果與用戶名的CRC值XOR計算,如下圖所示:

上面的計算結果再與前面的 CRC 值異或,結果為存于 DX,如下圖所示:

上面生成的結果,與輸入的注冊碼的最后2字節(SN 第7段轉換后16進制數)進行比較,如下圖所示:

如果相等,則表示成功,不相等則注冊碼無效。
按 F9 退出,返回界面修改注冊碼,如下圖所示:

再次點”OK“,來到前面退出的位置,如下圖所示:


這一次是相等的了。格式驗證過程就結束了。
這個7段式注冊碼第7段校驗碼的生成和校驗的具體代碼如下:
[Asm] 純文本查看 復制代碼
78612067     8B4424 18              mov     eax, dword ptr [esp+18]                 ; SN, 去掉“-”的注冊碼
7861206B     BF 10000000            mov     edi, 10
78612070     397C24 2C              cmp     dword ptr [esp+2C], edi                 ; 檢查最大長度不小于16
78612074     73 04                  jnb     short 7861207A
78612076     8D4424 18              lea     eax, dword ptr [esp+18]
7861207A     6A 1A                  push    1A                                      ; 26 個字節,長度
7861207C     8D4C24 34              lea     ecx, dword ptr [esp+34]                 ; ecx: endptr ===> null
78612080     E8 DB1A0000            call    78613B60                                ; strtol(sn, length), 將SN按字節轉換成16進制字節數據
78612085     83C4 04                add     esp, 4
78612088     8BD6                   mov     edx, esi                                ; edx ===> name
7861208A     85F6                   test    esi, esi
7861208C     74 21                  je      short 786120AF
7861208E     8A0E                   mov     cl, byte ptr [esi]                      ; cl = name[i]
78612090     33C0                   xor     eax, eax                                ; long crc = 0
78612092     84C9                   test    cl, cl
78612094     74 17                  je      short 786120AD
78612096     0FB6C9                 movzx   ecx, cl                                 ; (uint)name[i]
78612099     0FB6F0                 movzx   esi, al                                 ; (uint)(crc & 0xFF)
7861209C     33CE                   xor     ecx, esi                                ; long idx = name[i] ^ (crc &0xFF)
7861209E     33048D 78346378        xor     eax, dword ptr [ecx*4+78633478]         ; crc ^= crc_table[idx]
786120A5     8A4A 01                mov     cl, byte ptr [edx+1]                    ; name[i+1]
786120A8     42                     inc     edx                                     ; name++, i++
786120A9     84C9                   test    cl, cl
786120AB   ^ 75 E9                  jnz     short 78612096
786120AD     8BF0                   mov     esi, eax                                ; eax == 0x9B64C2B0
786120AF     33C0                   xor     eax, eax
786120B1     8BD3                   mov     edx, ebx                                ; ebx == 0,  參數3
786120B3     85DB                   test    ebx, ebx
786120B5     74 20                  je      short 786120D7
786120B7     8A0B                   mov     cl, byte ptr [ebx]                      ; 另:機構名?暫無用
786120B9     84C9                   test    cl, cl
786120BB     74 1A                  je      short 786120D7
786120BD     8D49 00                lea     ecx, dword ptr [ecx]
786120C0     0FB6C9                 movzx   ecx, cl
786120C3     0FB6D8                 movzx   ebx, al
786120C6     33CB                   xor     ecx, ebx
786120C8     33048D 78346378        xor     eax, dword ptr [ecx*4+78633478]
786120CF     8A4A 01                mov     cl, byte ptr [edx+1]
786120D2     42                     inc     edx
786120D3     84C9                   test    cl, cl
786120D5   ^ 75 E9                  jnz     short 786120C0
786120D7     03F0                   add     esi, eax                                ; 兩組CRC值相加
786120D9     33C0                   xor     eax, eax                                ; int i = 0
786120DB     32D2                   xor     dl, dl                                  ; char ch1 = 0
786120DD     8D4C24 30              lea     ecx, dword ptr [esp+30]                 ; ecx ===> sn_int
786120E1     32DB                   xor     bl, bl                                  ; char ch2 = 0;
786120E3     A8 01                  test    al, 1
786120E5     74 04                  je      short 786120EB
786120E7     0219                   add     bl, byte ptr [ecx]                      ; al 為奇, ch2 += sn_char[i]
786120E9     EB 02                  jmp     short 786120ED
786120EB     3211                   xor     dl, byte ptr [ecx]                      ; al 為偶,ch1 ^= sn_char[i]
786120ED     40                     inc     eax                                     ; i++
786120EE     41                     inc     ecx                                     ; sn_int ++
786120EF     83F8 18                cmp     eax, 18                                 ; 對SN前 24 個字符進行校驗
786120F2   ^ 72 EF                  jb      short 786120E3
786120F4     0FB60D E7716378        movzx   ecx, byte ptr [786371E7]                ; key2[1]
786120FB     66:0FB6D2              movzx   dx, dl                                  ; ch1
786120FF     66:0FB6C3              movzx   ax, bl                                  ; ch2
78612103     66:C1E2 08             shl     dx, 8
78612107     66:0BD0                or      dx, ax                                  ; short sn_check1 = (ch1<<8) + ch2
7861210A     66:0FB605 E6716378     movzx   ax, byte ptr [786371E6]                 ; key2[0]
78612112     66:C1E1 08             shl     cx, 8
78612116     66:0BC8                or      cx, ax                                  ; short sn_check2 = (key2[1]<<8) + key2[0]
78612119     66:33D1                xor     dx, cx                                  ; short check = sn_check1 ^ sn_check2
7861211C     66:33D6                xor     dx, si                                  ; check = check ^ name_crc
7861211F     0FB7C2                 movzx   eax, dx                                 ; eax == check == 0x894D
78612122     884424 10              mov     byte ptr [esp+10], al
78612126     C1E8 08                shr     eax, 8
78612129     884424 11              mov     byte ptr [esp+11], al                   ; 轉換成 short 類型
7861212D     0FB74C24 10            movzx   ecx, word ptr [esp+10]
78612132     66:3B4C24 48           cmp     cx, word ptr [esp+48]                   ; check 值與 SN 最后4位比較
78612137     74 2B                  je      short 78612164                          ; 相等則表示成功


上面對比成功后,直接 F9 運行,會彈出如下消息框:

這只是表示注冊碼的格式檢查全部通過了,注冊碼正確性檢查需要在重啟后進行。
如果要對這個檢查進行破解,進行如下操作,來到下面位置:

修改最上面那一條指令,如下圖所示,修改后的指令為紅色:

這樣就可以破解掉格式檢查。
都成功后,我們退出 DLL 中的函數,來到主程序,看看是在那里調用的這個 trreg_bl 函數,如下圖所示:

就是在這個位置調用的。
=================================================
太長了,注冊分析和注冊機,放在跟帖內寫。先到這里吧。。。。

免費評分

參與人數 33吾愛幣 +39 熱心值 +32 收起 理由
我為52pojie狂 + 1 + 1 [email protected]!
月六點年一倍 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
擼冰花 + 1 + 1 熱心回復!
bugof52pj + 1 + 1 [email protected]!
Booneey + 1 熱心回復!
獨行風云 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
小豆丁 + 1 + 1 我很贊同!
ofo + 3 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
Bascter_Main + 1 用心討論,共獲提升!
loxohc + 1 + 1 太秀了兄弟
小小學生 + 1 + 1 太秀了哥們。贊一個
wapjphl + 1 + 1 用心討論,共獲提升!
smile1110 + 3 + 1 [email protected]!
gaosld + 1 + 1 用心討論,共獲提升!
UniqueLegend + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
無聞無問 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
朱朱你墮落了 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
dazhuangzhuang + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
wu0o0pj + 1 + 1 秀!
Higher-Stark + 1 + 1 用心討論,共獲提升!
wzlyq + 1 + 1 熱心回復!
zhangbaida + 3 + 1 鼓勵轉貼優秀軟件安全工具和文檔!
zhangyazhou + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
生有涯知無涯 + 1 我很贊同!
wtujoxk + 2 + 1 大神真的秀,這操作膜拜了!
iamcjsyr + 1 + 1 用心討論,共獲提升!
笙若 + 2 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
lxwen + 1 + 1 熱心回復!
xlnetwork + 1 熱心回復!
fqr2009 + 1 + 1 [email protected]!
sighout + 1 + 1 [email protected]!
FleTime + 1 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
Gentlewang + 3 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!

查看全部評分

本帖被以下淘專輯推薦:

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

推薦
 樓主| solly 發表于 2019-12-27 17:59 <

三、算法逆向和注冊機實現

本帖最后由 solly 于 2020-1-9 01:07 編輯

(注:跟貼順序有時會變化,這是第三部分,如果順序顯示不對,可先看第二部分再看這一部分)
前面兩部分,對加密進行了分析,這部分對注冊算法進行逆向分析。因為加密共有5個過程,其中4個比較簡單,很容易逆向出來,這4個就不詳説了。


現在看看,最關鍵的一段加密,其代碼如下所示:
[Asm] 純文本查看 復制代碼
786139A0     51                   push    ecx
786139A1     0FB64E 03            movzx   ecx, byte ptr [esi+3]
786139A5     0FB646 02            movzx   eax, byte ptr [esi+2]
786139A9     0FB656 01            movzx   edx, byte ptr [esi+1]
786139AD     C1E1 08              shl     ecx, 8
786139B0     0BC8                 or      ecx, eax
786139B2     0FB606               movzx   eax, byte ptr [esi]
786139B5     C1E1 08              shl     ecx, 8
786139B8     0BCA                 or      ecx, edx
786139BA     0FB656 06            movzx   edx, byte ptr [esi+6]
786139BE     C1E1 08              shl     ecx, 8
786139C1     0BC8                 or      ecx, eax                                 ; ecx == sn_part1
786139C3     0FB646 07            movzx   eax, byte ptr [esi+7]
786139C7     C1E0 08              shl     eax, 8
786139CA     0BC2                 or      eax, edx
786139CC     0FB656 05            movzx   edx, byte ptr [esi+5]
786139D0     C1E0 08              shl     eax, 8
786139D3     0BC2                 or      eax, edx
786139D5     0FB656 04            movzx   edx, byte ptr [esi+4]
786139D9     53                   push    ebx
786139DA     55                   push    ebp
786139DB     C1E0 08              shl     eax, 8
786139DE     57                   push    edi
786139DF     0BC2                 or      eax, edx                                 ; eax == sn_part2
786139E1     BF 20000000          mov     edi, 20                                  ; int n = 0x20;
786139E6     BA 2037EFC6          mov     edx, C6EF3720                            ; key = 0xC6EF3720
786139EB     4F                   dec     edi                                      ; n--
786139EC     897C24 0C            mov     dword ptr [esp+C], edi                   ; n
786139F0     8BD9                 mov     ebx, ecx                                 ; sn11 = sn_part1;
786139F2     335C24 1C            xor     ebx, dword ptr [esp+1C]                  ; sn11 = sn_part1 ^ key3;
786139F6     8BF9                 mov     edi, ecx                                 ; sn12 = sn_part1;
786139F8     035C24 20            add     ebx, dword ptr [esp+20]                  ; sn11 = sn11 + key4;
786139FC     C1EF 05              shr     edi, 5                                   ; sn12 >>= 5;
786139FF     33FA                 xor     edi, edx                                 ; sn12 ^= key;
78613A01     03DF                 add     ebx, edi                                 ; sn11 += sn12;
78613A03     8BE9                 mov     ebp, ecx                                 ; sn13 = sn_part1;
78613A05     C1E5 04              shl     ebp, 4                                   ; sn13 <<= 4;
78613A08     03EB                 add     ebp, ebx                                 ; sn13 += sn11;
78613A0A     2BC5                 sub     eax, ebp                                 ; sn_part2 -= sn13;
78613A0C     8BD8                 mov     ebx, eax
78613A0E     335C24 14            xor     ebx, dword ptr [esp+14]                  ; sn11 = sn_part2 ^ key1;
78613A12     8BF8                 mov     edi, eax                                 ; sn12 = sn_part2;
78613A14     035C24 18            add     ebx, dword ptr [esp+18]                  ; sn11 = sn11 + key2;
78613A18     C1EF 05              shr     edi, 5                                   ; sn12 >>= 5;
78613A1B     33FA                 xor     edi, edx                                 ; sn12 ^= key;
78613A1D     8BE8                 mov     ebp, eax                                 ; sn13 = sn_part2;
78613A1F     03DF                 add     ebx, edi                                 ; sn11 += sn12;
78613A21     8B7C24 0C            mov     edi, dword ptr [esp+C]                   ; n
78613A25     C1E5 04              shl     ebp, 4                                   ; sn13 <<= 4;
78613A28     03EB                 add     ebp, ebx                                 ; sn13 += sn11;
78613A2A     2BCD                 sub     ecx, ebp                                 ; sn_part1 -= sn13;
78613A2C     81C2 4786C861        add     edx, 61C88647                            ; key += 0x61C88647;
78613A32     85FF                 test    edi, edi
78613A34   ^ 77 B5                ja      short 786139EB                           ; 循環執行32次
78613A36     33FF                 xor     edi, edi                                 ; 0
78613A38     0BC7                 or      eax, edi                                 ; sn_part2 = 0x4C22825B
78613A3A     33D2                 xor     edx, edx                                 ; 0
78613A3C     0BD1                 or      edx, ecx                                 ; sn_part1 = 0x4F16BACE
78613A3E     8BCA                 mov     ecx, edx                                 ; sn_part1 = 0x4F16BACE
78613A40     8BF8                 mov     edi, eax                                 ; sn_part2 = 0x4C22825B
78613A42     0FACF9 08            shrd    ecx, edi, 8                              ; save to sn_int, edi最低8bits移到ecx的最高8bits
78613A46     884E 01              mov     byte ptr [esi+1], cl                     ; save
78613A49     C1EF 08              shr     edi, 8
78613A4C     8BCA                 mov     ecx, edx
78613A4E     8BF8                 mov     edi, eax
78613A50     0FACF9 10            shrd    ecx, edi, 10
78613A54     884E 02              mov     byte ptr [esi+2], cl                     ; save
78613A57     8816                 mov     byte ptr [esi], dl                       ; save
78613A59     8BC8                 mov     ecx, eax
78613A5B     0FACCA 18            shrd    edx, ecx, 18
78613A5F     C1E9 18              shr     ecx, 18
78613A62     8856 03              mov     byte ptr [esi+3], dl                     ; save
78613A65     8BD0                 mov     edx, eax
78613A67     C1EF 10              shr     edi, 10
78613A6A     8BC8                 mov     ecx, eax
78613A6C     5F                   pop     edi
78613A6D     8856 04              mov     byte ptr [esi+4], dl                     ; save
78613A70     C1E9 08              shr     ecx, 8
78613A73     C1EA 10              shr     edx, 10
78613A76     C1E8 18              shr     eax, 18
78613A79     5D                   pop     ebp
78613A7A     884E 05              mov     byte ptr [esi+5], cl                     ; save
78613A7D     8856 06              mov     byte ptr [esi+6], dl                     ; save
78613A80     8846 07              mov     byte ptr [esi+7], al                     ; save
78613A83     5B                   pop     ebx
78613A84     59                   pop     ecx
78613A85     C3                   retn

先轉換成 C 代碼:
[C++] 純文本查看 復制代碼
//// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
        ULONG sn11, sn12, sn13;
        //// 取注冊碼 
        ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
        ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
        
        ULONG key = 0xC6EF3720;
        
        for(int i=0; i<32; i++) {
                sn11 = sn_part1 ^ key3;
                sn11 += key4;
                
                sn12 = sn_part1 >> 5;
                sn12 ^= key;
                
                sn11 += sn12;
                
                sn13 = sn_part1 << 4;
                sn13 += sn11;
                
                sn_part2 -= sn13;
                
                /////
                sn11 = sn_part2 ^ key1;
                sn11 += key2;
                
                sn12 = sn_part2 >> 5;
                sn12 ^= key;
                
                sn11 += sn12;
                
                sn13 = sn_part2 << 4;
                sn13 += sn11;
                
                sn_part1 -= sn13;
                
                key += 0x61C88647;
        }
        //// sn_part1= 0x4F16BACE, sn_part2 = 4C22825B, key = 0x00000000
        *(ULONG *)&sn_int[0] = sn_part1;
        *(ULONG *)&sn_int[4] = sn_part2;
        printSN(6); 
        
        return 0;
}



對代碼進行優化一下,如下所示:
[C++] 純文本查看 復制代碼
//// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
        ULONG sn11, sn12, sn13;
        //// 取注冊碼
        ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
        ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
        
        ULONG key = 0xC6EF3720;
        
        for(int i=0; i<32; i++) {
                sn11 = (sn_part1 ^ key3) + key4;
                sn12 = (sn_part1 >> 5) ^ key;
                sn13 = (sn_part1 << 4);

                sn_part2 -= (sn11 + sn12 + sn13);
                
                /////
                sn11 = (sn_part2 ^ key1) + key2;
                sn12 = (sn_part2 >> 5) ^ key;
                sn13 = (sn_part2 << 4);
                
                sn_part1 -= (sn11 + sn12 + sn13);
                
                key += 0x61C88647;
        }

        *(ULONG *)&sn_int[0] = sn_part1;
        *(ULONG *)&sn_int[4] = sn_part2;
        printSN(3); 
        
        return 0;
}



可以看到,是用一個64位密碼(兩組32位),再加另一個32位key(計算的密碼,每輪都不一樣)(其實是IV),分別對一段SN(32位數據)加密,同時,SN兩段數據還交叉進行加密。
一眼也看不出是什么加密方法,上網查資料,看看哪個算法有32輪加密,直到看到一個 DES 加密的框圖,如下所示:

可以看到,這里也會將64位明文,分成兩個32位交叉加密,是不是很象前面的加密代碼,不過 DES 一般只進行 16 輪加密,而這里用了 32 輪,比標準的多一倍,并且也沒有對明文和密文進行置換,因此,對 DES 加密過程也進行了簡化。
因此,可以看成是對標準 DES 算法的一種變形,那解密算法自然也是 DES 解密算法的變形,經過對標準 DES 算法的基本了解和查閱了一些資料,終于逆向出解密算法如下:
[Asm] 純文本查看 復制代碼
//// step2_2() like DES_Decrypt()
int step2_2(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
        ULONG sn11, sn12, sn13;
        //// 取注冊碼 
        ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
        ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
        
        ULONG IV = 0x00000000; //init IV

        for(int i=0; i<32; i++) {

                IV -= 0x61C88647;
                
                /////
                sn11 = (sn_part2 ^ key1) + key2;
                sn12 = (sn_part2 >> 5) ^ IV;
                sn13 = (sn_part2 << 4);

                sn_part1 += (sn11 + sn12 + sn13);
                
                /////
                sn11 = (sn_part1 ^ key3) + key4;
                sn12 = (sn_part1 >> 5) ^ IV;
                sn13 = (sn_part1 << 4);
                
                sn_part2 += (sn11 + sn12 + sn13);
        }

        *(ULONG *)&sn_int[0] = sn_part1;
        *(ULONG *)&sn_int[4] = sn_part2;
        //printSN(3); 
        
        return 0;
}

與加密算法很相似,只是順序反過來,包括那個計算的密碼也是順序反過來。
完整的注冊機代碼如下,包括了注冊碼的加密過程(從輸入的假碼到完成加密)和逆向解密過程(在加密后的假碼中的將正確的用戶名CRC值替換原值,并解密返回到可用的注冊碼SN 0),便于了解SN在加密、解密過程的變化:
[C++] 純文本查看 復制代碼
#include <iostream>
#include "crc_table.h"

typedef unsigned char  UCHAR;
typedef unsigned short UWORD;
typedef unsigned long  ULONG;
typedef unsigned long long UINT64;

/*
// Video Joiner 
UCHAR KEY0[] = {0xC6, 0x99};
UCHAR KEY1[] = {0xB2, 0xB5, 0xA9, 0xB7, 0x97, 0xA3, 0xD0, 0xE6, 
                0x9D, 0x8B, 0xA1, 0xD2, 0x63, 0xB7, 0x96, 0xDD};
char KEY2[] = "Q2JmTzS8fIKsNQBI8itv01Yir6Is4846";
char KEY3[] = "ncYEVD34az43";   
*/

/*
// Video Splitter
UCHAR KEY0[] = {0x6A, 0xA2};
UCHAR KEY1[] = {0x99, 0xA8, 0x9B, 0x8E, 0x89, 0xD8, 0x7E, 0x93, 
                0x9E, 0xC0, 0xE1, 0x78, 0x8E, 0x7D, 0xA8, 0xC9};
char KEY2[] = "0HCw296HPiAWxg9v5lGQ4rA13Ejg52I8";
char KEY3[] = "Q7H4I53CngYt";   
*/

/*
/// Video Converter
UCHAR KEY0[] = {0x68, 0x8B};
UCHAR KEY1[] = {0x96, 0xD4, 0x67, 0xAE, 0x8E, 0x82, 0x7A, 0xAB,
                0x84, 0xDD, 0xBC, 0xEB, 0x90, 0x75, 0xCA, 0x6C};
char KEY2[] = "11s8hYyw9QW74U1Gw5893241o65rncsW";
char KEY3[] = "841a036f5vDr";   
*/

///*
/// Audio Converter
UCHAR KEY0[] = {0xBD, 0x88};
UCHAR KEY1[] = {0xAD, 0xD9, 0xDF, 0xA4, 0x9E, 0xB1, 0xA2, 0x9A, 
                0x86, 0x9A, 0x8F, 0xC0, 0x6A, 0xB6, 0xA4, 0x9B};
char KEY2[] = "W9K85WVnk9BlCqM8f43rSwZ6T3748b44";
char KEY3[] = "7Kb3xboI268I";  
//*/

//unsigned long KEY4=0;
//unsigned long KEY5=0;
//unsigned long KEY6=0;

void printSN(int theTimes);

long getCRC(char * buff);
unsigned short getSNCheck(char * sn_char);
long getKeyCheck1(char * key, char * sn_int);
long getKeyCheck2(unsigned long key, char * keyStr);

long getKey2Check1(char * key, char * sn_int);
long getKey2Check2(unsigned long key, char * sn_int);

long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int);

long getSNCheck2(char * sn_int);

long getNameCheck(char * name);

int keyTransform1(char * keyStr, ULONG * key_trans);

//// application algorithm
int getAlgorithm(char * name);

//// calculate serial number
int getSN(char * name); 

//// test sn: 11111111-22222222-33333333-44444444-55555555-66666666-7777 
char sn_char_test[] = {0x11, 0x11, 0x11, 0x11, 
                       0x22, 0x22, 0x22, 0x22, 
                       0x33, 0x33, 0x33, 0x33, 
                       0x44, 0x44, 0x44, 0x44, 
                       0x55, 0x55, 0x55, 0x55, 
                       0x66, 0x66, 0x66, 0x66, 
                       0x77, 0x77}; ////check
//char sn_char_test[] = {0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52, 0x52, 0x52, 
//                       0x52, 0x52}; ////check

int main(int argc, char** argv) {
    
    char name[] = "solly"; /// modify name here
    //char name[] = "52pojie.cn"; /// modify name here
    
    printf("User Name: %s\n", name);

    ///// calculate
    printf("\n============================ start calculate =============================\n");
    ////
    int a = getAlgorithm(name);
    
    //// get successfal flag value
    printf("\n============================ show check value ============================\n");
    long name_check = getNameCheck(name);
    
    printf("Name check: 0x%08X\n", name_check);
    
    UWORD key = (UWORD) name_check;
    UWORD sn_key = * (UWORD *)&sn_char_test[18];  /// sn_int[19]sn_int[18]
    
    printf("key valid flag: 0x%04X, key calculated flag: 0x%04X\n", key, sn_key); 
    
    ///// reverse
    printf("\n======================== start reverse calculate =========================\n");
    ////
    int b = getSN(name);

    return 0;
}

void printSN(int theTimes) {
    int n = 26; 
    printf("SN %d:  ", theTimes);
    for(int i=0; i<n; i++) {
        if((i>0) && (i % 4 == 0)) {
            printf("-");
        }
        printf("%02X", (unsigned char)sn_char_test[ i ]);
    }
    printf("\n");
}

//// registration algorithm
int getAlgorithm(char * name) {
    ////
    printSN(0); /// 顯示注冊碼 
    ////
    long nameCRC = getCRC(name);
    ///printf("Name check: 0x%08X\n", nameCRC);

    long organCRC = getCRC(NULL); //// 目前沒有用到,為空 

    short snCHK = getSNCheck(sn_char_test);

    unsigned short sn_check = (short)(nameCRC + organCRC) ^ snCHK;
    
    ///printf(" SN CHECK: 0x%04X\n", sn_check);

    sn_char_test[24] = (unsigned char)(sn_check);
    sn_char_test[25] = (unsigned char)(sn_check>>8);
    
    //// 下面進行注冊碼處理 
    
    printSN(1); /// 顯示注冊碼 

    long keyCheck = getKeyCheck1(KEY2, sn_char_test);
    
    printSN(2); /// 顯示注冊碼 

    getKey2Check1(KEY3, sn_char_test);
    
    //printSN(3); /// 顯示注冊碼 
    
    ////
    long sn_check2 = getSNCheck2(sn_char_test);

    printSN(5); /// 顯示注冊碼 
    
    return 0;    
} 

long getCRC(char * buff) {
    long crc = 0;
    if(buff == NULL) {
        return 0;
    }
    while(*buff != '\0') {
        crc ^= crc_table[(unsigned int)((*buff) ^ (unsigned char)crc)];
        buff++;
    }
    
    return crc;
}

unsigned short getSNCheck(char * sn_char) {
    unsigned char ch_even = 0;
    unsigned char ch_odd  = 0;
    unsigned short sn_check = 0;
    
    if(sn_char == NULL) {
        return 0;
    }

    for(int i=0; i<24; i++) {
        if(i % 2) {
            ch_odd += sn_char[ i ];
        } else {
            ch_even ^= sn_char[ i ];
        }
    }

    sn_check = (ch_even<<8) + ch_odd;
    sn_check ^= ((UWORD)KEY3[1]<<8) + (UWORD)KEY3[0];
    
    return sn_check;
}

/// Key1: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
/// return: 
/// chk1: 0xE88F784B
/// chk2: 0x7319B02E
long getKeyCheck2(unsigned long key, char * keyStr) {
    unsigned char ch = 0;
    unsigned long ch1 = 0;
    unsigned long ch2 = key;

    do {
        ch = (unsigned char)(* keyStr);
        ch1 = ((unsigned long)ch << 8);
        ch2 ^= ch1;
    
        unsigned short i = 0;
        do {
            ch1 = (unsigned char)i ^ ch2;
            ch1 += 0x7034616B; //// "ka4k"
            ch2 = (unsigned char)ch1;
            ch2 &= 0x1F;
            if(ch2 != 0) {
                ch1 = (ch1 >> ch2) + (ch1<<(32-ch2)); /// ROR
            }
            ch2 = ch1 ^ 0x8372A5A7;
            i--; //i += 0xFFFF;
        } while(i);
    
        keyStr ++;
    } while(ch);
    
    return ch2;
}

/// 將SN的6段分別與6個常量進行xor操作 
/// Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
long getKeyCheck1(char * key, char * sn_int) {
    unsigned long ch1 = 0;
    unsigned long chk = 0;
    /// chk1 and chk1 calculated from Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44" 
    //unsigned long chk1[] = {0xE88F784B, 0x20E57D8E, 0xA522A5A6, 0x2C245DBC, 0x712E29E9, 0xB2BAF74F};
    //unsigned long chk2[] = {0x7319B02E, 0x42D2836B, 0x7936349F, 0xD9930AE9, 0x2872B191, 0x5EE814F3};
    unsigned long chk2[6];
    keyTransform1(key, chk2);
    
    //// 以整數方式存取 
    unsigned long * sn = (unsigned long *)&sn_int[0]; 
    
    for(int i=0; i<6; i++) {
        sn[ i ] = sn[ i ]  ^ chk2[ i ];
    }
    
    return 0;//chk1;
}

long getKey2Check1(char * key, char * sn_int) {
    unsigned long ch = 0;
    unsigned long ch1 = 0;
    unsigned long ch2 = 0;
    unsigned long ch3 = 0;
    unsigned long ch4 = 0;
    unsigned long ch5 = 0;
    unsigned long ch6 = 0;
    
    //// 由key2組合成兩個整數 
//  //// 兩整數相加 
    //// char key2[] = "7Kb3xboI268I";  //// 0x33624B37, 0x496F6278, 0x49383632 
//    ch1 = 0x496F6278; // (7-6-5-4)
//    ch3 = 0x49383632; // (11-10-9-8)
    ch1 = *(ULONG *)&KEY3[4]; // (7-6-5-4)
    ch3 = *(ULONG *)&KEY3[8]; // (11-10-9-8)
    ch = ch1 + ch3; //// ch = 0x92A798AA
    long check2 = getKey2Check2(ch, sn_int);
    
    printSN(3); 
    
    //// 由 key0 組合成 4 個整數
    //unsigned long key0[] = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A};
//    ch4 = 0x9BA4B66A; //(17-16-15-14) 
//    ch3 = 0xC08F9A86; //(13-12-11-10)
//    ch2 = 0x9AA2B19E; //(9-8-7-6)
//    ch1 = 0xA4DFD9AD; //(5-4-3-2)
    ch4 = *(ULONG *)&KEY1[12]; //(17-16-15-14) 
    ch3 = *(ULONG *)&KEY1[8]; //(13-12-11-10)
    ch2 = *(ULONG *)&KEY1[4]; //(9-8-7-6)
    ch1 = *(ULONG *)&KEY1[0]; //(5-4-3-2)
    //// 每次同時處理兩段SN 
    unsigned long long * sn_llu = (unsigned long long *)(& sn_int[0]);  
    for(int i=0; i<3; i++) {
        getKey0Check(ch1, ch2, ch3, ch4, (char *)(& sn_llu[ i ]));
    }
    
    printSN(4); 
    
    return 0;
}

ULONG htonl(ULONG l) {
    ULONG tmp = l;
    ULONG nl = (UCHAR)tmp;
    nl <<= 8;
    nl += (UCHAR)(tmp >> 8);
    nl <<= 8;
    nl += (UCHAR)(tmp >> 16);
    nl <<= 8;
    nl += (UCHAR)(tmp >> 24);
    
    return nl;
}

////
// ch1 = 0x496F6278; // key2[](7-6-5-4)
// ch2 = 0x49383632; // key2[](11-10-9-8)
// key = ch1 + ch2; //// ch = 0x92A798AA
long getKey2Check2(unsigned long key, char * sn_int) {
    unsigned short key0 = 0;
    unsigned short key1 = 0;
    unsigned long  key2 = 0;
    unsigned long  key3 = 0;
    unsigned long  ch = 0;
    unsigned long  sn_part = 0;
    
    int n = 6;
    unsigned long sn_origin = 0;
    unsigned long sn_new = 0;
    unsigned long sn_tmp = 0;
    
    ////printf("    key: 0x%08X\n", key);
    
    //unsigned char * sn_ptr = (unsigned char *)&sn_int[2];
    ULONG * sn = (ULONG *)(& sn_int[0]);
    
    for(int i=0; i<n; i++) {
        key -= 0x76BDEFDB;
        //// key 字節順序置換 
        key = htonl(key); //// 調整字節順序 
        //printf("new key: 0x%08X\n", key);
    
        //// 將SN每部分4字節組合成一個整數
        sn_part = sn[ i ];
        sn_tmp = sn_part; //// save temp 
        //printf("sn_Part1: 0x%08X\n", sn_part);
    
        //// 計算 
        sn_part -= key;
        sn_part ^= sn_origin;
        //printf("sn_Part2: 0x%08X\n", sn_part);
    
        //// 保存 
        sn[ i ] = sn_part;
    
        //sn_ptr += 4;  ///// SN 下一段
        //n--;
        sn_origin = sn_tmp;  /// SN 上一段的值,作為下一段的異常參數
    }// while(n>0); 
    
    return 0;
}

//// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
    ULONG sn11, sn12, sn13;
    //// 取注冊碼 
    ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
    ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
    
    ULONG key = 0xC6EF3720;
/* 32 個 key: key[ i ] = key[i-1] + 0x61C88647 
0xC6EF3720, 0x28B7BD67, 0x8A8043AE, 0xEC48C9F5, 
0x4E11503C, 0xAFD9D683, 0x11A25CCA, 0x736AE311, 
0xD5336958, 0x36FBEF9F, 0x98C475E6, 0xFA8CFC2D, 
0x5C558274, 0xBE1E08BB, 0x1FE68F02, 0x81AF1549, 
0xE3779B90, 0x454021D7, 0xA708A81E, 0x08D12E65,
0x6A99B4AC, 0xCC623AF3, 0x2E2AC13A, 0x8FF34781, 
0xF1BBCDC8, 0x5384540F, 0xB54CDA56, 0x1715609D, 
0x78DDE6E4, 0xDAA66D2B, 0x3C6EF372, 0x9E3779B9//, 0x00000000 
*/
    //printf("key: 0x%08X, sn1: 0x%08X, sn2: 0x%08X\n", key, sn_part1, sn_part2);
    //printf("key0key: \n");
    for(int i=0; i<32; i++) {
        sn11 = sn_part1 ^ key3;
        sn11 += key4;
        
        sn12 = sn_part1 >> 5;
        sn12 ^= key;
        
        sn11 += sn12;
        
        sn13 = sn_part1 << 4;
        sn13 += sn11;
        
        sn_part2 -= sn13;
        
        /////
        sn11 = sn_part2 ^ key1;
        sn11 += key2;
        
        sn12 = sn_part2 >> 5;
        sn12 ^= key;
        
        sn11 += sn12;
        
        sn13 = sn_part2 << 4;
        sn13 += sn11;
        
        sn_part1 -= sn13;
        
        key += 0x61C88647;
        //printf("key: 0x%08X, sn1: 0x%08X, sn2: 0x%08X\n", key, sn_part1, sn_part2);
    }
    //printf("\nkey0key: 0x%08X\n", key); /// 最后 key == 0x00000000 
    //// sn_part1= 0x4F16BACE, sn_part2 = 0x4C22825B, key = 0x00000000
    *(ULONG *)&sn_int[0] = sn_part1;
    *(ULONG *)&sn_int[4] = sn_part2;
    //printSN(3); 
    
    return 0;
}

long getSNCheck2(char * sn_int) {
    char low = sn_int[22]; /// 0x4D
    char up  = sn_int[23]; /// 0x5F
    
    //printf("up = 0x%02X, low = 0x%02X\n", up, low);
    
    for(int i=0; i<22; i++) {
        sn_int[ i ] = (sn_int[ i ] - up) ^ low;
    }
    
    return 0;//(up<<8) + low;
}

long getNameCheck(char * name) {
    ULONG check = 0;
    while(*name != '\0') {
        check = check ^ crc_table[(UCHAR)check ^ (UCHAR)(* name)];
        name ++;
    }
    
    return check;
}

/////
/*
SN CRC: 0x894D
SN 0:  11111111  22222222  33333333  44444444  55555555  66666666  7777
SN 1:  11111111  22222222  33333333  44444444  55555555  66666666  4D89
SN 2:  3FA10862  49A1F060  AC07054A  AD4ED79D  C4E4277D  95728E38  4D89
SN 3:  CEBA164F  5B82224C  AB6AFAAC  0A1589E4  E1190CCD  2407D7E7  4D89
SN 3:  CEBA164F  5B82224C  4B43745D  754702AF  E1190CCD  2407D7E7  4D89
SN 3:  CEBA164F  5B82224C  4B43745D  754702AF  F3D8A75B  FE0A4D5F  4D89
SN 3:  CEBA164F  5B82224C  4B43745D  754702AF  F3D8A75B  FE0A4D5F  4D89
SN 4:  2216FABD  B16E8EA0  A1A958B3  5BA5EE1D  D93405B1  D2E64D5F  4D89
Name check: 0x9B64C2B0
key ok: 0xC2B0, key_act: 0xB105
*/ 

//// ==================== start reverse ===========================

//// ready
int step0(char * name, char * sn_int) {
    ULONG name_check = (ULONG)getNameCheck(name);
    
    //// update name_check to valid value
    * (UWORD *)&sn_int[18] = (UWORD)name_check;  /// sn_int[19]sn_int[18]
    
    return name_check;
}

int step1(char * sn_int) {
    char low = sn_int[22]; /// 0x4D
    char hi  = sn_int[23]; /// 0x5F
    
    for(int i=0; i<22; i++) {
        sn_int[ i ] = (sn_int[ i ] ^ low) + hi;
    }
    
    return 0;          
}

// ch1 = 0x496F6278; // key2[](7-6-5-4)
// ch2 = 0x49383632; // key2[](11-10-9-8)
// key = ch1 + ch2; //// ch = 0x92A798AA
// like RC4_Decrypt
int step2_1(ULONG key, char * sn_int) {
    
    ULONG * sn = (ULONG *)(& sn_int[0]);
    
    ULONG sn_origin = 0;
    for(int i=0; i<6; i++) {
        key -= 0x76BDEFDB;
        //// key 字節順序置換 
        key = htonl(key); //// 調整字節順序 

        //// descrypt
        sn[ i ] = (sn[ i ] ^ sn_origin) + key;
    
        sn_origin = sn[ i ];  /// SN 上一段的值,作為下一段的異常參數
    }
    
    return 0;
}

//// step2_2() like DES_Decrypt()
int step2_2(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
    ULONG sn11, sn12, sn13;
    //// 取注冊碼 
    ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
    ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
    
    ULONG IV = 0x00000000; //init IV

    for(int i=0; i<32; i++) {

        IV -= 0x61C88647;
        
        /////
        sn11 = (sn_part2 ^ key1) + key2;
        sn12 = (sn_part2 >> 5) ^ IV;
        sn13 = (sn_part2 << 4);

        sn_part1 += (sn11 + sn12 + sn13);
        
        /////
        sn11 = (sn_part1 ^ key3) + key4;
        sn12 = (sn_part1 >> 5) ^ IV;
        sn13 = (sn_part1 << 4);
        
        sn_part2 += (sn11 + sn12 + sn13);
    }

    *(ULONG *)&sn_int[0] = sn_part1;
    *(ULONG *)&sn_int[4] = sn_part2;
    //printSN(3); 
    
    return 0;
}

///  
int step2(char * sn_int) {
//    ULONG key4 = 0x9BA4B66A; //(17-16-15-14) 
//    ULONG key3 = 0xC08F9A86; //(13-12-11-10)
//    ULONG key2 = 0x9AA2B19E; //(9-8-7-6)
//    ULONG key1 = 0xA4DFD9AD; //(5-4-3-2)
    ULONG key4 = * (ULONG *)&KEY1[12]; 
    ULONG key3 = * (ULONG *)&KEY1[8]; 
    ULONG key2 = * (ULONG *)&KEY1[4]; 
    ULONG key1 = * (ULONG *)&KEY1[0]; 
    //// 64 bits data from sn
    UINT64 * sn_llu = (UINT64 *)(& sn_int[0]);  
    for(int i=0; i<3; i++) {
        step2_2(key1, key2, key3, key4, (char *)(& sn_llu[ i ]));
    }
    printSN(3); 
    
    //// char key2[] = "7Kb3xboI268I";  //// 0x33624B37, 0x496F6278, 0x49383632 
//    ULONG key5 = 0x496F6278; // (7-6-5-4)
//    ULONG key6 = 0x49383632; // (11-10-9-8)
    ULONG key5 = * (ULONG *)&KEY3[4]; // (7-6-5-4)
    ULONG key6 = * (ULONG *)&KEY3[8]; // (11-10-9-8)
    ULONG key = key5 + key6; //// key = 0x92A798AA
    long check2 = step2_1(key, sn_int);
    printSN(2); 
    
    return 0;
}

//// 1: 0xE88F784B, 2: 0x7319B02E
int keyTransform2(ULONG key, char * keyStr) {
    unsigned char ch = 0;
    unsigned long ch1 = 0;
    unsigned long ch2 = key;

    do {
        ch = (unsigned char)(* keyStr);
        ch1 = ((unsigned long)ch << 8);
        ch2 ^= ch1;
    
        unsigned short i = 0;
        do {
            ch1 = (unsigned char)i ^ ch2;
            ch1 += 0x7034616B;
            ch2 = (unsigned char)ch1;
            ch2 &= 0x1F;
            if(ch2 != 0) {
                ch1 = (ch1 >> ch2) + (ch1<<(32-ch2)); /// ROR
            }
            ch2 = ch1 ^ 0x8372A5A7;
            i--; //i += 0xFFFF;
        } while(i);
    
        keyStr ++;
    } while(ch);
    
    return ch2;
}


//// KeyStr: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
int keyTransform1(char * keyStr, ULONG * key_trans) {
    const ULONG k = 0x41363233;
    
    if((keyStr == NULL) || (key_trans == NULL)) {
        return -1;
    }
    
    ULONG ch1 = (ULONG)keyStr[0];
    ULONG ch2 = (ULONG)keyStr[0];
    
    ch1 ^= k;
    ULONG chk1 = keyTransform2(ch1, keyStr); //// key 變換 
    //printf("Key trans chk1: 0x%08X\n", chk1);
    
    ///
    ch2 = (ch2<<8) ^ chk1;
    ULONG chk2 = keyTransform2(ch2, keyStr); //// key 變換 
    //printf("Key trans chk2: 0x%08X\n", chk2);
    
    for(int i=0; i<6; i++) {
        key_trans[i] = chk2;
        //printf("Key trans %d: 0x%08X\n", i, key_trans[i]);

        ULONG n1 = chk2 & 0x1F;
        if(n1 != 0) {
            chk1 = (chk1<<n1) + (chk1>>(32-n1));  /// ROL 
        }
        ULONG n2 = ((chk1 >> 8) & 0x1F);
        chk2 = chk1 ^ chk2;
        if(n2 != 0) {
            chk2 = (chk2 >> n2) + (chk2 << (32-n2)); /// ROR
        }
        chk1 += chk2;
        ////
    }
    
    return chk2;
}

/// 將SN的6段分別與6個常量進行xor操作 
/// Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
int step3(char * key, char * sn_int) {
    /// key transformed from: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44" 
    //ULONG key1[] = {0xE88F784B, 0x20E57D8E, 0xA522A5A6, 0x2C245DBC, 0x712E29E9, 0xB2BAF74F};
    ULONG key_trans[6];// = {0x7319B02E, 0x42D2836B, 0x7936349F, 0xD9930AE9, 0x2872B191, 0x5EE814F3};
    keyTransform1(key, key_trans);
    //// 以整數方式存取
    ULONG * sn = (ULONG *)&sn_int[0]; 
    
    for(int i=0; i<6; i++) {
        sn[ i ] = sn[ i ]  ^ key_trans[ i ];
    }
    
    return 0;//chk1;
}

int step4(char * name, char * sn_int) {
    long nameCRC = getCRC(name);
    long organCRC = getCRC(NULL); //// 目前沒有用到,為空 
    short snCHK = getSNCheck(sn_char_test);
    
    UWORD sn_check = (short)(nameCRC + organCRC) ^ snCHK;
    
    //// update sn_check to valid value
    * (UWORD *)&sn_int[24] = sn_check;  /// sn_int[25]sn_int[24]
    
    return sn_check;
}

int getSN(char * name) {

    step0(name, sn_char_test);    
    
    printSN(5);

    step1(sn_char_test);
    
    printSN(4);
    
    step2(sn_char_test);  /// it has two steps

    //printSN(2);
    
    step3(KEY2, sn_char_test); 

    printSN(1);
    
    step4(name, sn_char_test);    

    //// final sn is valid
    printSN(0);
    
    return 0;    
}


另外,CRC 查表數據頭文件:crc_table.h 如下:
[C++] 純文本查看 復制代碼
//// crc計算的查表數據
#ifndef __crc_table_h__
#define __crc_table_h__

long crc_table[] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
#endif


計算結果如下:
[Shell] 純文本查看 復制代碼
User Name: solly

============================ start calculate =============================
SN 0:  11111111-22222222-33333333-44444444-55555555-66666666-7777
SN 1:  11111111-22222222-33333333-44444444-55555555-66666666-4D89
SN 2:  3FA10862-49A1F060-AC07054A-AD4ED79D-C4E4277D-95728E38-4D89
SN 3:  24B85F92-CE17FE7D-AB6AFAAC-0A1589E4-E1190CCD-2407D7E7-4D89
SN 4:  CEBA164F-5B82224C-4B43745D-754702AF-F3D8A75B-FE0A4D5F-4D89
SN 5:  2216FABD-B16E8EA0-A1A958B3-5BA5EE1D-D93405B1-D2E64D5F-4D89

============================ show check value ============================
Name check: 0x9B64C2B0
key valid flag: 0xC2B0, key calculated flag: 0xB105

======================== start reverse calculate =========================
SN 5:  2216FABD-B16E8EA0-A1A958B3-5BA5EE1D-D934B0C2-D2E64D5F-4D89
SN 4:  CEBA164F-5B82224C-4B43745D-754702AF-F3D85CEE-FE0A4D5F-4D89
SN 3:  24B85F92-CE17FE7D-AB6AFAAC-0A1589E4-BB21717E-494633AD-4D89
SN 2:  3FA10862-49A1F060-AC07054A-AD4ED79D-8EFCF20F-7C495F40-4D89
SN 1:  11111111-22222222-33333333-44444444-1F4D8027-8F5DB71E-4D89
SN 0:  11111111-22222222-33333333-44444444-1F4D8027-8F5DB71E-C42E

--------------------------------
Process exited after 0.1549 seconds with return value 0
請按任意鍵繼續. . .


再來一個:
[Shell] 純文本查看 復制代碼
User Name: 52pojie.cn

============================ start calculate =============================
SN 0:  52525252-52525252-52525252-52525252-52525252-52525252-5252
SN 1:  52525252-52525252-52525252-52525252-52525252-52525252-BDB9
SN 2:  7CE24B21-39D18010-CD66642B-BB58C18B-C3E3207A-A146BA0C-BDB9
SN 3:  61F9A251-9D04CDEE-3AFAEABD-797A12B7-F00E15C6-2F543C15-BDB9
SN 4:  B0A54A27-886F3D22-2E38ED99-1AD46F14-FE96EECF-B184EE74-BDB9
SN 5:  D2DF385D-FA152740-542A97CB-488E154E-64CC94B5-D3FEEE74-BDB9

============================ show check value ============================
Name check: 0x4FDFF252
key valid flag: 0xF252, key calculated flag: 0xB594

======================== start reverse calculate =========================
SN 5:  D2DF385D-FA152740-542A97CB-488E154E-64CC52F2-D3FEEE74-BDB9
SN 4:  B0A54A27-886F3D22-2E38ED99-1AD46F14-FE963090-B184EE74-BDB9
SN 3:  61F9A251-9D04CDEE-3AFAEABD-797A12B7-FBD3B937-99CCFAE2-BDB9
SN 2:  7CE24B21-39D18010-CD66642B-BB58C18B-B818C5E8-D662DDA7-BDB9
SN 1:  52525252-52525252-52525252-52525252-29A9B7C0-257635F9-BDB9
SN 0:  52525252-52525252-52525252-52525252-29A9B7C0-257635F9-0D37

--------------------------------
Process exited after 0.1664 seconds with return value 0
請按任意鍵繼續. . .


上面兩個例子最后輸出的 SN 0 就是正確的注冊碼了。
可以看到,注冊碼的前4段沒什么用,只影響最后的 CRC 校驗值。
分析完畢。。!


免費評分

參與人數 1吾愛幣 +1 熱心值 +1 收起 理由
netCheney + 1 + 1 用心討論,共獲提升!

查看全部評分

推薦
 樓主| solly 發表于 2019-12-27 17:58 <

二、注冊算法分析

本帖最后由 solly 于 2020-1-9 01:12 編輯

注:跟貼順序有時會變化,這是第二部分
前面寫的是注冊碼格式的校驗分析,下面進行注冊碼有效性校驗分析,這個校驗是軟件啟動時進行的,也就是重啟校驗。


我們用 OD 重新載入軟件,F9 運行,OD 直接斷了下來,原來我們在格式檢查時下的斷點還有效,因為重啟后還進行了格式檢查,我們退出格式檢查函數,來到下圖所示位置:

上圖中 call 0x(nnnn)1FF0就檢查注冊碼格式并保存注冊碼的調用,我們就是斷在了這個函數里面,現在我們禁用所有前面在函數內下的斷點,如上圖所示,在調用外下一個新斷點即可。
最下面的 call 0x(nnnn)1770也是格式檢查。


按 F8 往下執行,如下圖所示,對注冊碼字符串進行格式轉換,前面已經分析過了:

上圖的重點是調用 call 0x(nnnn)1390,我們按 F7 進入該函數,如下圖所示:

這里就開始進入注冊碼加解密階段了,上圖中可以看到一個字符串,這個就是一個密碼串,后面需要用到,如下所示:
[Asm] 純文本查看 復制代碼
;密碼字符串
786371C2  57 39 4B 38 35 57 56 6E 6B 39 42 6C 43 71 4D 38  W9K85WVnk9BlCqM8
786371D2  66 34 33 72 53 77 5A 36 54 33 37 34 38 62 34 34  f43rSwZ6T3748b44

在調用 call 0x(nnnn)3AD0 后面,是對另一個常量字符串進行一系列變換。這個字符串為:
[Asm] 純文本查看 復制代碼
;另一個密碼字符串
786371E6  37 4B 62 33 78 62 6F 49 32 36 38 49              7Kb3xboI268I


下面是本函數的具體代碼:
[Asm] 純文本查看 復制代碼
78611390     83EC 0C              sub     esp, 0C
78611393     53                   push    ebx
78611394     55                   push    ebp
78611395     56                   push    esi
78611396     57                   push    edi
78611397     B8 C2716378          mov     eax, 786371C2                            ; ASCII "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
7861139C     E8 2F270000          call    78613AD0                                 ; SN加密, key1
786113A1     0FB615 ED716378      movzx   edx, byte ptr [786371ED]                 ; 7Kb3xboI268I[7]
786113A8     0FB605 EC716378      movzx   eax, byte ptr [786371EC]                 ; 7Kb3xboI268I[6]
786113AF     0FB60D EB716378      movzx   ecx, byte ptr [786371EB]                 ; 7Kb3xboI268I[5]
786113B6     C1E2 08              shl     edx, 8
786113B9     0BD0                 or      edx, eax
786113BB     0FB605 EA716378      movzx   eax, byte ptr [786371EA]                 ; 7Kb3xboI268I[4]
786113C2     C1E2 08              shl     edx, 8
786113C5     0BD1                 or      edx, ecx
786113C7     0FB60D F1716378      movzx   ecx, byte ptr [786371F1]                 ; 7Kb3xboI268I[11]
786113CE     C1E2 08              shl     edx, 8
786113D1     0BD0                 or      edx, eax                                 ; edx = 0x496F6278
786113D3     0FB605 F0716378      movzx   eax, byte ptr [786371F0]                 ; 7Kb3xboI268I[10]
786113DA     C1E1 08              shl     ecx, 8
786113DD     0BC8                 or      ecx, eax
786113DF     0FB605 EF716378      movzx   eax, byte ptr [786371EF]                 ; 7Kb3xboI268I[9]
786113E6     C1E1 08              shl     ecx, 8
786113E9     0BC8                 or      ecx, eax
786113EB     0FB605 EE716378      movzx   eax, byte ptr [786371EE]                 ; 7Kb3xboI268I[8]
786113F2     C1E1 08              shl     ecx, 8
786113F5     0BC8                 or      ecx, eax                                 ; ecx = 0x49383632
786113F7     03D1                 add     edx, ecx                                 ; edx = 0x92A798AA
786113F9     E8 02250000          call    78613900                                 ; 再次加密 SN, key2
786113FE     0FB63D C1716378      movzx   edi, byte ptr [786371C1]                 ; 0x9B[17], ch1
78611405     0FB60D C0716378      movzx   ecx, byte ptr [786371C0]                 ; 0xA4[16], ch2
7861140C     0FB615 BF716378      movzx   edx, byte ptr [786371BF]                 ; 0xB6[15], ch3
78611413     0FB61D BD716378      movzx   ebx, byte ptr [786371BD]                 ; 0xC0[13], ch4
7861141A     0FB605 BE716378      movzx   eax, byte ptr [786371BE]                 ; 0x6A[14], ch5
78611421     0FB62D B9716378      movzx   ebp, byte ptr [786371B9]                 ; 0x9A[9],  ch6
78611428     C1E7 08              shl     edi, 8
7861142B     0BF9                 or      edi, ecx
7861142D     0FB60D BC716378      movzx   ecx, byte ptr [786371BC]                 ; 0x8F[12]
78611434     C1E3 08              shl     ebx, 8
78611437     0BD9                 or      ebx, ecx
78611439     0FB60D B8716378      movzx   ecx, byte ptr [786371B8]                 ; 0xA2[8]
78611440     C1E7 08              shl     edi, 8
78611443     0BFA                 or      edi, edx
78611445     0FB615 BB716378      movzx   edx, byte ptr [786371BB]                 ; 0X9A[11]
7861144C     C1E5 08              shl     ebp, 8
7861144F     C1E3 08              shl     ebx, 8
78611452     0BE9                 or      ebp, ecx
78611454     0FB60D B4716378      movzx   ecx, byte ptr [786371B4]                 ; 0xDF[4]
7861145B     C1E7 08              shl     edi, 8
7861145E     0BF8                 or      edi, eax                                 ; edi = 0x9BA4B66A
78611460     0FB605 BA716378      movzx   eax, byte ptr [786371BA]                 ; 0x86[10]
78611467     0BDA                 or      ebx, edx
78611469     0FB615 B7716378      movzx   edx, byte ptr [786371B7]                 ; 0xB1[7]
78611470     C1E5 08              shl     ebp, 8
78611473     C1E3 08              shl     ebx, 8
78611476     0BD8                 or      ebx, eax                                 ; ebx = 0xC08F9A86
78611478     0FB605 B6716378      movzx   eax, byte ptr [786371B6]                 ; 0x9E[6]
7861147F     0BEA                 or      ebp, edx
78611481     0FB615 B3716378      movzx   edx, byte ptr [786371B3]                 ; 0xD9[3]
78611488     C1E5 08              shl     ebp, 8
7861148B     0BE8                 or      ebp, eax                                 ; ebp = 0x9AA2B19E
7861148D     0FB605 B5716378      movzx   eax, byte ptr [786371B5]                 ; 0xA4[5]
78611494     C1E0 08              shl     eax, 8
78611497     0BC1                 or      eax, ecx
78611499     0FB60D B2716378      movzx   ecx, byte ptr [786371B2]                 ; 0xAD[2]
786114A0     C1E0 08              shl     eax, 8
786114A3     0BC2                 or      eax, edx
786114A5     C1E0 08              shl     eax, 8
786114A8     0BC1                 or      eax, ecx
786114AA     894424 18            mov     dword ptr [esp+18], eax                  ; eax = 0xA4DFD9AD
786114AE     BE 54906378          mov     esi, 78639054                            ; sn_ptr ===> sn_int[]
786114B3     C74424 14 03000000   mov     dword ptr [esp+14], 3                    ; int n = 3
786114BB     EB 07                jmp     short 786114C4
786114BD     8D49 00              lea     ecx, dword ptr [ecx]                     ; 無用
786114C0     8B4424 18            mov     eax, dword ptr [esp+18]                  ; eax = 0xA4DFD9AD
786114C4     57                   push    edi                                      ; 0x9BA4B66A
786114C5     53                   push    ebx                                      ; 0xC08F9A86
786114C6     55                   push    ebp                                      ; 0x9AA2B19E
786114C7     50                   push    eax                                      ; 0xA4DFD9AD
786114C8     E8 D3240000          call    786139A0                                 ; 第三次SN加密處理,循環處理3次。key0
786114CD     8B4424 24            mov     eax, dword ptr [esp+24]                  ; n
786114D1     48                   dec     eax                                      ; n--
786114D2     83C4 10              add     esp, 10
786114D5     83C6 08              add     esi, 8                                   ; sn_ptr += 8, 指向下一個2段SN
786114D8     894424 14            mov     dword ptr [esp+14], eax                  ; n
786114DC     85C0                 test    eax, eax
786114DE   ^ 75 E0                jnz     short 786114C0
786114E0     8A0D 6A906378        mov     cl, byte ptr [7863906A]                  ; sn_int[22]
786114E6     8A15 6B906378        mov     dl, byte ptr [7863906B]                  ; sn_int[23]
786114EC     B8 54906378          mov     eax, 78639054                            ; eax === sn_int[]
786114F1     8A18                 mov     bl, byte ptr [eax]                       ; ch = sn_int[0]
786114F3     2ADA                 sub     bl, dl
786114F5     32D9                 xor     bl, cl
786114F7     8818                 mov     byte ptr [eax], bl                       ; sn[0] = (sn[0] - CRC[1])^CRC[0]
786114F9     40                   inc     eax
786114FA     3D 6A906378          cmp     eax, 7863906A
786114FF   ^ 72 F0                jb      short 786114F1                           ; 循環22次,sn[0]~sn[21]
78611501     5F                   pop     edi
78611502     5E                   pop     esi
78611503     5D                   pop     ebp
78611504     5B                   pop     ebx
78611505     83C4 0C              add     esp, 0C
78611508     C3                   retn

可以看到,這是一個加密函數總入口。
我們先看看 call 0x(nnnn)3AD0 加密函數,如下圖所示:


如上圖所示,該函數又兩次調用另一個函數 call 0x(nnnn)3A90,進入該函數看看,如下圖所示:


這個函數對密碼進行了一些轉換操作。


返回上一級函數,看看函數后面,如下圖所示:


就是循環6次,對注冊碼前6段進行加密運算,循環體靠后面的代碼也是對密碼進行轉換運算,看起來比較復雜,但有一大段代碼是用將4字節轉換成整數,再將加密后的整數轉換成4字節數據保存。
具體代碼如下:
[Asm] 純文本查看 復制代碼
; SN 加密
78613AD0     53                   push    ebx
78613AD1     55                   push    ebp
78613AD2     8BD8                 mov     ebx, eax                                 ; ebx ===> keyStr
78613AD4     0FB62B               movzx   ebp, byte ptr [ebx]                      ; W9K85WVnk9BlCqM8f43rSwZ6T3748b44
78613AD7     56                   push    esi
78613AD8     8BCD                 mov     ecx, ebp                                 ; ch = (* keyStr)
78613ADA     57                   push    edi
78613ADB     81F1 33323641        xor     ecx, 41363233
78613AE1     BF 06000000          mov     edi, 6                                   ; n=6, 注冊碼前6個部分
78613AE6     E8 A5FFFFFF          call    78613A90                                 ; chk1 = func(ch, keyStr);
78613AEB     8BF0                 mov     esi, eax                                 ; esi == chk1
78613AED     8BCD                 mov     ecx, ebp                                 ; ch = (* keyStr)
78613AEF     C1E1 08              shl     ecx, 8                                   ; ch <<= 8
78613AF2     33CE                 xor     ecx, esi                                 ; ch ^= chk
78613AF4     8BC3                 mov     eax, ebx                                 ; eax ===> keyStr
78613AF6     E8 95FFFFFF          call    78613A90                                 ; chk2 = func(ch, keyStr);
78613AFB     BA 56906378          mov     edx, 78639056                            ; ptr = &sn_int[2];
78613B00     0FB64A 01            movzx   ecx, byte ptr [edx+1]                    ; ch1 = * (ptr + 1)
78613B04     0FB61A               movzx   ebx, byte ptr [edx]                      ; ch2 = * ptr
78613B07     C1E1 08              shl     ecx, 8
78613B0A     0BCB                 or      ecx, ebx                                 ; ch1 = (ch1<<8) + ch2;
78613B0C     0FB65A FF            movzx   ebx, byte ptr [edx-1]                    ; ch2 = (* (ptr-1));
78613B10     C1E1 08              shl     ecx, 8
78613B13     0BCB                 or      ecx, ebx                                 ; ch1 = (ch1<<8) + ch2;
78613B15     0FB65A FE            movzx   ebx, byte ptr [edx-2]                    ; ch2 = (* (ptr-2));
78613B19     C1E1 08              shl     ecx, 8
78613B1C     0BCB                 or      ecx, ebx                                 ; ch1 = (ch1<<8) + ch2;
78613B1E     33C8                 xor     ecx, eax                                 ; chk = ch1 ^ chk2;
78613B20     8BD9                 mov     ebx, ecx                                 ; chk[1] = 0x6208A13F
78613B22     C1EB 08              shr     ebx, 8                                   ; chk >>= 8;
78613B25     884A FE              mov     byte ptr [edx-2], cl
78613B28     885A FF              mov     byte ptr [edx-1], bl
78613B2B     8BD9                 mov     ebx, ecx
78613B2D     C1E9 18              shr     ecx, 18
78613B30     884A 01              mov     byte ptr [edx+1], cl
78613B33     C1EB 10              shr     ebx, 10
78613B36     0FB6C8               movzx   ecx, al                                  ; ch = ((unsigned char)chk2)
78613B39     83E1 1F              and     ecx, 1F                                  ; ch = chk2 & 0x1F;
78613B3C     881A                 mov     byte ptr [edx], bl
78613B3E     83C2 04              add     edx, 4                                   ; ptr += 4, 指向SN下一部分
78613B41     D3C6                 rol     esi, cl                                  ; chk1 = (chk1<<ch) + (chk1>>(32-ch));
78613B43     8BCE                 mov     ecx, esi                                 ; ch1 = chk1;
78613B45     C1E9 08              shr     ecx, 8                                   ; ch1 >>= 8;
78613B48     8BDE                 mov     ebx, esi                                 ; ch2 = chk1;
78613B4A     33D8                 xor     ebx, eax                                 ; ch2 ^= chk2;
78613B4C     83E1 1F              and     ecx, 1F                                  ; ch1 &= 0x1F;
78613B4F     D3CB                 ror     ebx, cl                                  ; ch2 = (ch2 >> ch1) + (ch2 << (32-ch1));
78613B51     8BC3                 mov     eax, ebx                                 ; chk2 = ch2;
78613B53     03F0                 add     esi, eax                                 ; chk1 += chk2;
78613B55     83EF 01              sub     edi, 1                                   ; i--
78613B58   ^ 75 A6                jnz     short 78613B00
78613B5A     5F                   pop     edi
78613B5B     5E                   pop     esi
78613B5C     5D                   pop     ebp
78613B5D     5B                   pop     ebx
78613B5E     C3                   retn

內部函數如下:
[Asm] 純文本查看 復制代碼
; 子過程:
78613A90     53                   push    ebx
78613A91     56                   push    esi
78613A92     8BF0                 mov     esi, eax                                 ; int ch2=ecx;
78613A94     33DB                 xor     ebx, ebx                                 ; i=0
78613A96     8A06                 mov     al, byte ptr [esi]                       ; al = (* keyStr)
78613A98     0FB6D0               movzx   edx, al                                  ; ch1 = (unsigned)(* keyStr);
78613A9B     C1E2 08              shl     edx, 8                                   ; ch1 <<= 8;
78613A9E     33CA                 xor     ecx, edx                                 ; ch2 ^= ch1;
78613AA0     0FB6D3               movzx   edx, bl
78613AA3     33D1                 xor     edx, ecx                                 ; ch1 = (unsigned)i ^ ch2;
78613AA5     81C2 6B613470        add     edx, 7034616B                            ; ch1 += 0x7034616B;
78613AAB     0FB6CA               movzx   ecx, dl                                  ; ch2 = (unsigned char)ch1;
78613AAE     83E1 1F              and     ecx, 1F                                  ; ch2 &= 0x1F;
78613AB1     D3CA                 ror     edx, cl                                  ; ch1 = (ch1 >> ch2) + (ch1<<(32-ch2));
78613AB3     81C3 FFFF0000        add     ebx, 0FFFF                               ; i--; //i += 0xFFFF
78613AB9     81F2 A7A57283        xor     edx, 8372A5A7                            ; ch1 ^= 0x8372A5A7
78613ABF     8BCA                 mov     ecx, edx                                 ; ch2 = ch1;
78613AC1     66:85DB              test    bx, bx
78613AC4   ^ 75 DA                jnz     short 78613AA0
78613AC6     46                   inc     esi                                      ; keyStr ++
78613AC7     84C0                 test    al, al
78613AC9   ^ 75 CB                jnz     short 78613A96
78613ACB     5E                   pop     esi
78613ACC     8BC1                 mov     eax, ecx
78613ACE     5B                   pop     ebx
78613ACF     C3                   retn

上面是用索引對密碼串進行密碼轉換運算。
從上面的函數返回后,如下圖所示,執行前面函數后面的密碼轉換代碼:

這一段轉換代碼就是將常量字符串“7Kb3xboI268I”后8個字符,組成2個4字節的整數,然后相加,存于 edx,作為后面 call 0x(nnnn)3900的參數。
下面進入函數 call 0x(nnnn)3900,如下圖所示:

這個函數里又有大段的代碼將4字節組合成一個整數,然后再將整數分拆成4字節保存。前面一截代碼是對密碼進行一些變換。
接下來函數進行加密運算,最后面又是分拆保存,如下圖所示:


加密指令代碼就是上圖中間幾條指令(0xnnnn3966~0xnnnn396C),主要是相減和異或運算等。
下面是上面加密操作的函數代碼:
[Asm] 純文本查看 復制代碼
; 加密函數
78613900     53                   push    ebx                                      ; 再次對序列號進行處理
78613901     55                   push    ebp
78613902     56                   push    esi
78613903     57                   push    edi
78613904     BD 06000000          mov     ebp, 6                                   ; int n = 6
78613909     33F6                 xor     esi, esi                                 ; unsigned long sn_origin=0
7861390B     B9 56906378          mov     ecx, 78639056                            ; ecx==>SN_int[2]
78613910     81EA DBEFBD76        sub     edx, 76BDEFDB                            ; key -= 0x76BDEFDB, 1BE9A8CF = 92A798AA-76BDEFDB
78613916     66:0FB6FA            movzx   di, dl                                   ; key1 = (unsigned char)key;
7861391A     8BC2                 mov     eax, edx
7861391C     C1E8 10              shr     eax, 10                                  ; key2 = key >> 0x10;
7861391F     66:C1E7 08           shl     di, 8                                    ; key1 <<= 8;
78613923     C1EA 08              shr     edx, 8                                   ; key >>= 8;
78613926     0FB7FF               movzx   edi, di                                  ; key3 = (unsigned long)key1;
78613929     0FB6D2               movzx   edx, dl                                  ; key = (unsigned char)key;
7861392C     0BFA                 or      edi, edx                                 ; key3 += key;
7861392E     8BD0                 mov     edx, eax                                 ; key = key2;
78613930     66:0FB6C0            movzx   ax, al                                   ; key0 = (unsigned char)key2;
78613934     66:C1E0 08           shl     ax, 8                                    ; key0 <<= 8;
78613938     C1EA 08              shr     edx, 8                                   ; key >>= 8;
7861393B     C1E7 10              shl     edi, 10                                  ; key3 <<= 0x10;
7861393E     0FB6D2               movzx   edx, dl                                  ; key = (unsigned char)key;
78613941     0BFA                 or      edi, edx                                 ; key3 += key;
78613943     0FB7D0               movzx   edx, ax                                  ; key = (unsigned long)key0;
78613946     0FB641 01            movzx   eax, byte ptr [ecx+1]                    ; *(sn_int+1)
7861394A     0BD7                 or      edx, edi                                 ; key += key3; // 0xCFA8E91B
7861394C     0FB639               movzx   edi, byte ptr [ecx]                      ; *(sn_int)
7861394F     C1E0 08              shl     eax, 8
78613952     0BC7                 or      eax, edi
78613954     0FB679 FF            movzx   edi, byte ptr [ecx-1]                    ; *(sn_int-1)
78613958     C1E0 08              shl     eax, 8
7861395B     0BC7                 or      eax, edi
7861395D     0FB679 FE            movzx   edi, byte ptr [ecx-2]                    ; *(sn_int-2)
78613961     C1E0 08              shl     eax, 8
78613964     0BC7                 or      eax, edi                                 ; eax == sn_part
78613966     8BF8                 mov     edi, eax                                 ; sn_tmp = sn_part;
78613968     2BC2                 sub     eax, edx                                 ; sn_part -= key;
7861396A     33C6                 xor     eax, esi                                 ; sn_part ^= sn_origin;
7861396C     8BD8                 mov     ebx, eax                                 ; sn_new = sn_part; ///925FB824
7861396E     C1EB 08              shr     ebx, 8
78613971     8859 FF              mov     byte ptr [ecx-1], bl                     ; save
78613974     8BD8                 mov     ebx, eax
78613976     8841 FE              mov     byte ptr [ecx-2], al                     ; save
78613979     C1EB 10              shr     ebx, 10
7861397C     C1E8 18              shr     eax, 18
7861397F     8819                 mov     byte ptr [ecx], bl                       ; save
78613981     8841 01              mov     byte ptr [ecx+1], al                     ; save
78613984     83C1 04              add     ecx, 4                                   ; sn_ptr += 4; /// 下一部分
78613987     83ED 01              sub     ebp, 1                                   ; n --
7861398A     8BF7                 mov     esi, edi                                 ; sn_origin = sn_tmp
7861398C   ^ 75 82                jnz     short 78613910
7861398E     5F                   pop     edi
7861398F     5E                   pop     esi
78613990     5D                   pop     ebp
78613991     5B                   pop     ebx
78613992     C3                   retn

從上面函數返回后,又對另一組常量數組進行變換,形成4個整數,數組如下:
[Asm] 純文本查看 復制代碼
; 數組數據
786371B0  BD 88 AD D9 DF A4 9E B1 A2 9A 86 9A 8F C0 6A B6 A4 9B   


代碼如下所示:
[Asm] 純文本查看 復制代碼
786113FE     0FB63D C1716378      movzx   edi, byte ptr [786371C1]                 ; 0x9B[17], ch1
78611405     0FB60D C0716378      movzx   ecx, byte ptr [786371C0]                 ; 0xA4[16], ch2
7861140C     0FB615 BF716378      movzx   edx, byte ptr [786371BF]                 ; 0xB6[15], ch3
78611413     0FB61D BD716378      movzx   ebx, byte ptr [786371BD]                 ; 0xC0[13], ch4
7861141A     0FB605 BE716378      movzx   eax, byte ptr [786371BE]                 ; 0x6A[14], ch5
78611421     0FB62D B9716378      movzx   ebp, byte ptr [786371B9]                 ; 0x9A[9],  ch6
78611428     C1E7 08              shl     edi, 8
7861142B     0BF9                 or      edi, ecx
7861142D     0FB60D BC716378      movzx   ecx, byte ptr [786371BC]                 ; 0x8F[12]
78611434     C1E3 08              shl     ebx, 8
78611437     0BD9                 or      ebx, ecx
78611439     0FB60D B8716378      movzx   ecx, byte ptr [786371B8]                 ; 0xA2[8]
78611440     C1E7 08              shl     edi, 8
78611443     0BFA                 or      edi, edx
78611445     0FB615 BB716378      movzx   edx, byte ptr [786371BB]                 ; 0X9A[11]
7861144C     C1E5 08              shl     ebp, 8
7861144F     C1E3 08              shl     ebx, 8
78611452     0BE9                 or      ebp, ecx
78611454     0FB60D B4716378      movzx   ecx, byte ptr [786371B4]                 ; 0xDF[4]
7861145B     C1E7 08              shl     edi, 8
7861145E     0BF8                 or      edi, eax                                 ; edi = 0x9BA4B66A
78611460     0FB605 BA716378      movzx   eax, byte ptr [786371BA]                 ; 0x86[10]
78611467     0BDA                 or      ebx, edx
78611469     0FB615 B7716378      movzx   edx, byte ptr [786371B7]                 ; 0xB1[7]
78611470     C1E5 08              shl     ebp, 8
78611473     C1E3 08              shl     ebx, 8
78611476     0BD8                 or      ebx, eax                                 ; ebx = 0xC08F9A86
78611478     0FB605 B6716378      movzx   eax, byte ptr [786371B6]                 ; 0x9E[6]
7861147F     0BEA                 or      ebp, edx
78611481     0FB615 B3716378      movzx   edx, byte ptr [786371B3]                 ; 0xD9[3]
78611488     C1E5 08              shl     ebp, 8
7861148B     0BE8                 or      ebp, eax                                 ; ebp = 0x9AA2B19E
7861148D     0FB605 B5716378      movzx   eax, byte ptr [786371B5]                 ; 0xA4[5]
78611494     C1E0 08              shl     eax, 8
78611497     0BC1                 or      eax, ecx
78611499     0FB60D B2716378      movzx   ecx, byte ptr [786371B2]                 ; 0xAD[2]
786114A0     C1E0 08              shl     eax, 8
786114A3     0BC2                 or      eax, edx
786114A5     C1E0 08              shl     eax, 8
786114A8     0BC1                 or      eax, ecx
786114AA     894424 18            mov     dword ptr [esp+18], eax                  ; eax = 0xA4DFD9AD
786114AE     BE 54906378          mov     esi, 78639054                            ; sn_ptr ===> sn_int[]
786114B3     C74424 14 03000000   mov     dword ptr [esp+14], 3                    ; int n = 3
786114BB     EB 07                jmp     short 786114C4
786114BD     8D49 00              lea     ecx, dword ptr [ecx]                     ; 無用
786114C0     8B4424 18            mov     eax, dword ptr [esp+18]                  ; eax = 0xA4DFD9AD
786114C4     57                   push    edi                                      ; 0x9BA4B66A
786114C5     53                   push    ebx                                      ; 0xC08F9A86
786114C6     55                   push    ebp                                      ; 0x9AA2B19E
786114C7     50                   push    eax                                      ; 0xA4DFD9AD
786114C8     E8 D3240000          call    786139A0                                 ; 第三次SN加密處理,循環處理3次。

可見,這4個整作為函數 call 0x(nnnn)39A0 的參數,這幾個參數也是密碼,對 SN 進行處理,我們看看這個函數:

函數前面沒什么看的,又是字節轉換整數?春竺娴募用,如下圖所示:


這里同時取SN的兩段(共64bits),同時進行加密。并且每次重復32輪計算,才得到加密的密文?梢钥吹,這里的2段SN會交叉加密。


上面加密的代碼如下:
[Asm] 純文本查看 復制代碼
786139A0     51                   push    ecx
786139A1     0FB64E 03            movzx   ecx, byte ptr [esi+3]
786139A5     0FB646 02            movzx   eax, byte ptr [esi+2]
786139A9     0FB656 01            movzx   edx, byte ptr [esi+1]
786139AD     C1E1 08              shl     ecx, 8
786139B0     0BC8                 or      ecx, eax
786139B2     0FB606               movzx   eax, byte ptr [esi]
786139B5     C1E1 08              shl     ecx, 8
786139B8     0BCA                 or      ecx, edx
786139BA     0FB656 06            movzx   edx, byte ptr [esi+6]
786139BE     C1E1 08              shl     ecx, 8
786139C1     0BC8                 or      ecx, eax                                 ; ecx == sn_part1,32位SN數據
786139C3     0FB646 07            movzx   eax, byte ptr [esi+7]
786139C7     C1E0 08              shl     eax, 8
786139CA     0BC2                 or      eax, edx
786139CC     0FB656 05            movzx   edx, byte ptr [esi+5]
786139D0     C1E0 08              shl     eax, 8
786139D3     0BC2                 or      eax, edx
786139D5     0FB656 04            movzx   edx, byte ptr [esi+4]
786139D9     53                   push    ebx
786139DA     55                   push    ebp
786139DB     C1E0 08              shl     eax, 8
786139DE     57                   push    edi
786139DF     0BC2                 or      eax, edx                                 ; eax == sn_part2,另外32位SN數據
786139E1     BF 20000000          mov     edi, 20                                  ; int n = 0x20;  // 循環次數,32次
786139E6     BA 2037EFC6          mov     edx, C6EF3720                            ; key = 0xC6EF3720
786139EB     4F                   dec     edi                                      ; n--
786139EC     897C24 0C            mov     dword ptr [esp+C], edi                   ; n
786139F0     8BD9                 mov     ebx, ecx                                 ; sn11 = sn_part1;
786139F2     335C24 1C            xor     ebx, dword ptr [esp+1C]                  ; sn11 = sn_part1 ^ key3;
786139F6     8BF9                 mov     edi, ecx                                 ; sn12 = sn_part1;
786139F8     035C24 20            add     ebx, dword ptr [esp+20]                  ; sn11 = sn11 + key4;
786139FC     C1EF 05              shr     edi, 5                                   ; sn12 >>= 5;
786139FF     33FA                 xor     edi, edx                                 ; sn12 ^= key;
78613A01     03DF                 add     ebx, edi                                 ; sn11 += sn12;
78613A03     8BE9                 mov     ebp, ecx                                 ; sn13 = sn_part1;
78613A05     C1E5 04              shl     ebp, 4                                   ; sn13 <<= 4;
78613A08     03EB                 add     ebp, ebx                                 ; sn13 += sn11;
78613A0A     2BC5                 sub     eax, ebp                                 ; sn_part2 -= sn13;
78613A0C     8BD8                 mov     ebx, eax
78613A0E     335C24 14            xor     ebx, dword ptr [esp+14]                  ; sn11 = sn_part2 ^ key1;
78613A12     8BF8                 mov     edi, eax                                 ; sn12 = sn_part2;
78613A14     035C24 18            add     ebx, dword ptr [esp+18]                  ; sn11 = sn11 + key2;
78613A18     C1EF 05              shr     edi, 5                                   ; sn12 >>= 5;
78613A1B     33FA                 xor     edi, edx                                 ; sn12 ^= key;
78613A1D     8BE8                 mov     ebp, eax                                 ; sn13 = sn_part2;
78613A1F     03DF                 add     ebx, edi                                 ; sn11 += sn12;
78613A21     8B7C24 0C            mov     edi, dword ptr [esp+C]                   ; n
78613A25     C1E5 04              shl     ebp, 4                                   ; sn13 <<= 4;
78613A28     03EB                 add     ebp, ebx                                 ; sn13 += sn11;
78613A2A     2BCD                 sub     ecx, ebp                                 ; sn_part1 -= sn13;
78613A2C     81C2 4786C861        add     edx, 61C88647                            ; key += 0x61C88647;
78613A32     85FF                 test    edi, edi
78613A34   ^ 77 B5                ja      short 786139EB                           ; 循環執行32次
78613A36     33FF                 xor     edi, edi                                 ; 0
78613A38     0BC7                 or      eax, edi                                 ; sn_part2 = 0x4C22825B
78613A3A     33D2                 xor     edx, edx                                 ; 0
78613A3C     0BD1                 or      edx, ecx                                 ; sn_part1 = 0x4F16BACE
78613A3E     8BCA                 mov     ecx, edx                                 ; sn_part1 = 0x4F16BACE
78613A40     8BF8                 mov     edi, eax                                 ; sn_part2 = 0x4C22825B
78613A42     0FACF9 08            shrd    ecx, edi, 8                              ; save to sn_int, edi最低8bits移到ecx的最高8bits
78613A46     884E 01              mov     byte ptr [esi+1], cl                     ; save
78613A49     C1EF 08              shr     edi, 8
78613A4C     8BCA                 mov     ecx, edx
78613A4E     8BF8                 mov     edi, eax
78613A50     0FACF9 10            shrd    ecx, edi, 10
78613A54     884E 02              mov     byte ptr [esi+2], cl                     ; save
78613A57     8816                 mov     byte ptr [esi], dl                       ; save
78613A59     8BC8                 mov     ecx, eax
78613A5B     0FACCA 18            shrd    edx, ecx, 18
78613A5F     C1E9 18              shr     ecx, 18
78613A62     8856 03              mov     byte ptr [esi+3], dl                     ; save
78613A65     8BD0                 mov     edx, eax
78613A67     C1EF 10              shr     edi, 10
78613A6A     8BC8                 mov     ecx, eax
78613A6C     5F                   pop     edi
78613A6D     8856 04              mov     byte ptr [esi+4], dl                     ; save
78613A70     C1E9 08              shr     ecx, 8
78613A73     C1EA 10              shr     edx, 10
78613A76     C1E8 18              shr     eax, 18
78613A79     5D                   pop     ebp
78613A7A     884E 05              mov     byte ptr [esi+5], cl                     ; save
78613A7D     8856 06              mov     byte ptr [esi+6], dl                     ; save
78613A80     8846 07              mov     byte ptr [esi+7], al                     ; save
78613A83     5B                   pop     ebx
78613A84     59                   pop     ecx
78613A85     C3                   retn



這里的加密強度最強,主要加密也就在這里,后面的算法逆向難點也在這段代碼,其它幾次加密都比較好逆向。


退出這個函數后,回到上一級加密函數,如下圖所示:

可以看到,將通過以上多個步驟加密后的SN數據,取出其中的SN[22]、SN[23]兩個字節,并用這兩個字節對注冊碼的前22個字節再進行一次加密(減-異或)。


從上面函數返回后,返回到SN主驗證函數,如下圖所示:

這里又生成一次用戶名的 CRC 值(查表索引生成方式與上一次不同),取其低16位,與前面完成加密后的SN 中的 SN[18]和SN[19]兩個字節組成的雙字進行比較(0xnnnn2612 處),如果相等,則注冊碼有效,否則注冊碼無效。


可以看到,注冊碼中只有2個字節是用來判斷是否注冊成功的標志。只要這兩個字節正確,就可以注冊成功。


我們修改 al == 1后(手動讓注冊成功),退出函數,來到下圖所示位置:

這里是導出函數入口,函數名為:TRRegGetStatus_BL(),再次 F8 返回主程序,如下所示,顯示注冊驗證調用處:

這里有多個對庫函數的調用,按 F9 運行,進入軟件,按”About",顯示關于消息框,如下圖所示:

由于前面手動改成 al==1,所以這里顯示注冊成功了。


好了,加密函數的分析就到這里,下面的代碼是我將加密函數的匯編代碼翻譯成 C 語言代碼,可以原版還原出其算法,計算過程和計算結果都一致,也沒有簡化,與匯編指令有極大的相似度,便于大家對照分析,也是后面進行逆向分析的基礎:
[C++] 純文本查看 復制代碼
#include <iostream>
#include "crc_table.h"

typedef unsigned char  UCHAR;
typedef unsigned short UWORD;
typedef unsigned long  ULONG;

/////////////
unsigned char key0[] = {0xBD, 0x88, 0xAD, 0xD9, 0xDF, 0xA4, 0x9E, 0xB1, 0xA2, 
                        0x9A, 0x86, 0x9A, 0x8F, 0xC0, 0x6A, 0xB6, 0xA4, 0x9B};
//                      0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A
char key1[] = "W9K85WVnk9BlCqM8f43rSwZ6T3748b44";
// 0x384B3957, 0x6E565735, 0x6C42396B, 0x384D7143,
// 0x72333466, 0x365A7753, 0x34373354, 0x34346238
char key2[] = "7Kb3xboI268I";  //// 0x33624B37, 0x496F6278, 0x49383632 

//// test sn: 11111111-22222222-33333333-44444444-55555555-66666666-4D89 
char sn_char_test[] = {0x11, 0x11, 0x11, 0x11, 
                       0x22, 0x22, 0x22, 0x22, 
                                       0x33, 0x33, 0x33, 0x33, 
                                       0x44, 0x44, 0x44, 0x44, 
                                       0x55, 0x55, 0x55, 0x55, 
                                       0x66, 0x66, 0x66, 0x66, 
                                       0x77, 0x77}; ////check

void printSN(int theTimes);

long getCRC(char * buff);
unsigned short getSNCheck(char * sn_char);
long getKeyCheck1(char * key, char * sn_int);
long getKeyCheck2(unsigned long key, char * keyStr);

long getKey2Check1(char * key, char * sn_int);
long getKey2Check2(unsigned long key, char * sn_int);

long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int);

long getSNCheck2(char * sn_int);

long getNameCheck(char * name);

int main(int argc, char** argv) {
        
        char name[] = "solly";

        long nameCRC = getCRC(name);
        ///printf("Name check: 0x%08X\n", nameCRC);

        long organCRC = getCRC(NULL); //// 目前沒有用到,為空 

        short snCheck = getSNCheck(sn_char_test);

        unsigned short crc = (short)(nameCRC + organCRC) ^ snCheck;
        
        printf("SN CRC: 0x%04X\n", crc);

        printSN(0); /// 顯示注冊碼 
        
        sn_char_test[24] = (unsigned char)(crc);
        sn_char_test[25] = (unsigned char)(crc>>8);
        
        printSN(1); /// 顯示注冊碼 

        long keyCheck = getKeyCheck1(key1, sn_char_test);
        
        printSN(2); /// 顯示注冊碼 

        getKey2Check1(key2, sn_char_test);
        
        printSN(3); /// 顯示注冊碼 
        
        
        ////
        long sn_check2 = getSNCheck2(sn_char_test);

        printSN(5); /// 顯示注冊碼 
        
        long name_check = getNameCheck(name);
        
        printf("Name check: 0x%08X\n", name_check);
        
        UWORD key = (UWORD) name_check;
        UWORD sn_key = * (UWORD *)&sn_char_test[18];  /// sn_int[19]sn_int[18]
        
        printf("key ok: 0x%04X, key_act: 0x%04X\n", key, sn_key); 

        return 0;
}

void printSN(int theTimes) {
        int n = 26; 
        printf("SN %d:", theTimes);
        for(int i=0; i<n; i++) {
                if(i % 4 == 0) {
                        printf("  ");
                }
                printf("%02X", (unsigned char)sn_char_test[i]);
        }
        printf("\n");
}

long getCRC(char * buff) {
        long crc = 0;
        if(buff == NULL) {
                return 0;
        }
        while(*buff != '\0') {
                crc ^= crc_table[(unsigned int)((*buff) ^ (unsigned char)crc)];
                buff++;
        }
        
        return crc;
}

unsigned short getSNCheck(char * sn_char) {
        unsigned char ch_even = 0;
        unsigned char ch_odd  = 0;
        unsigned short sn_check = 0;
        
        if(sn_char == NULL) {
                return 0;
        }

        for(int i=0; i<24; i++) {
                if(i % 2) {
                        ch_odd += sn_char[i];
                } else {
                        ch_even ^= sn_char[i];
                }
        }

        sn_check = (ch_even<<8) + ch_odd;
        sn_check ^= ((unsigned short)key2[1]<<8) + (unsigned short)key2[0];
        
        return sn_check;
}

/// Key1: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
/// return: E88F784B
long getKeyCheck2(unsigned long key, char * keyStr) {
        unsigned char ch = 0;
        unsigned long ch1 = 0;
        unsigned long ch2 = key;

        do {
                ch = (unsigned char)(* keyStr);
                ch1 = ((unsigned long)ch << 8);
                ch2 ^= ch1;
        
                unsigned short i = 0;
                do {
                        ch1 = (unsigned char)i ^ ch2;
                        ch1 += 0x7034616B;
                        ch2 = (unsigned char)ch1;
                        ch2 &= 0x1F;
                        ch1 = (ch1 >> ch2) + (ch1<<(32-ch2)); /// ROR,用VS編譯時需要判斷 ch1==0 時,不執行這一行。
                        ch2 = ch1 ^ 0x8372A5A7;
                        i--; //i += 0xFFFF;
                } while(i);
        
                keyStr ++;
        } while(ch);
        
        return ch2;
}

/// Key: "W9K85WVnk9BlCqM8f43rSwZ6T3748b44"
long getKeyCheck1(char * key, char * sn_int) {
        unsigned long ch = 0;
        unsigned long ch1 = 0;
        unsigned long ch2 = 0;
        unsigned long chk = 0;
        unsigned long chk1 = 0;
        unsigned long chk2 = 0;
        
        ch = (unsigned long)(* key);
        ch ^= 0x41363233; ///"326A"   //// 41363264
        printf("ch: 0x%08X\n", ch);
        
        ////
        chk1 = getKeyCheck2(ch, key);
        printf("chk1: 0x%08X\n", chk1);
        ch = (unsigned long)(* key);
        ch <<= 8;
        ch ^= chk1;
        chk2 = getKeyCheck2(ch, key);
        printf("chk2: 0x%08X\n\n", chk2);
        
        //// 取 SN 第1部分形成一個整數 
        unsigned char * ptr = (unsigned char *)&sn_int[2];
        
        for(int i=0; i<6; i++) {
                //// 取每部分4字節形成一個整數 
                ch1 = (unsigned long)(* (ptr+1));
                ch2 = (unsigned long)(* (ptr));
                ch1 = (ch1<<8) + ch2;
                ch2 = (unsigned long)(* (ptr-1));
                ch1 = (ch1<<8) + ch2;
                ch2 = (unsigned long)(* (ptr-2));
                ch1 = (ch1<<8) + ch2;
        
                //// xor
                chk = ch1 ^ chk2;
                printf("SN_chk%d: 0x%08X ==> 0x%08X\n", i+1, ch1, chk);
        
                //// 將整數保存回每部分的4字節數據 
                *(ptr-2) = (char)chk;
                chk >>= 8;
                *(ptr-1) = (char)chk;
                chk >>= 8;
                *(ptr)   = (char)chk;
                chk >>= 8;
                *(ptr+1) = (char)chk;
        
                ////
                ptr += 4; /// SN 下一部分 
        
                ch = chk2 & 0x1F;
                //printf("ch: 0x%08X\n", ch);
                chk1 = (chk1<<ch) + (chk1>>(32-ch));  /// ROL,用VS編譯時需要判斷 ch1==0 時,不執行這一行。
                ch1 = chk1;
                ch1 >>= 8;
                ch2 = chk1;
                ch2 ^= chk2;
                ch1 &= 0x1F;
                ch2 = (ch2 >> ch1) + (ch2 << (32-ch1)); /// ROR,用VS編譯時需要判斷 ch1==0 時,不執行這一行。
                chk2 = ch2;
                chk1 += chk2;
                //printf("chk1: 0x%08X, chk2: 0x%08X\n", chk1, chk2);
        }
        
        
        return chk1;
}

long getKey2Check1(char * key, char * sn_int) {
        unsigned long ch = 0;
        unsigned long ch1 = 0;
        unsigned long ch2 = 0;
        unsigned long ch3 = 0;
        unsigned long ch4 = 0;
        unsigned long ch5 = 0;
        unsigned long ch6 = 0;
        
        //// 由key2組合成兩個整數 
        ch1 = key[7];
        ch2 = key[6];
        ch3 = key[5];
        ch1 <<=8;
        ch1 += ch2;
        ch2 = key[4];
        ch1 <<=8;
        ch1 += ch3;
        ch3 = key[11];
        ch1 <<=8;
        ch1 += ch2;     /// ch1 = 0x496F6278 (7-6-5-4)
        ch2 = key[10];
        ch3 <<=8;
        ch3 += ch2;
        ch2 = key[9];
        ch3 <<=8;
        ch3 += ch2;
        ch2 = key[8];
        ch3 <<=8;
        ch3 += ch2;  /// ch3 = 0x49383632 (11-10-9-8)
        
        //// 兩整數相加 
        ch = ch1 + ch3; //// ch = 0x92A798AA
        long check2 = getKey2Check2(ch, sn_int);
        
        //// 由 key0 組合成 4 個整數
        ch1 = (unsigned long)key0[17]; 
        ch2 = (unsigned long)key0[16]; 
        ch3 = (unsigned long)key0[15]; 
        ch4 = (unsigned long)key0[13]; 
        ch5 = (unsigned long)key0[14]; 
        ch6 = (unsigned long)key0[9];
        ch1 <<= 8;
        ch1 += ch2;
        ch2 = (unsigned long)key0[12]; 
        ch4 <<= 8;
        ch4 += ch2;
        ch2 = (unsigned long)key0[8];
        ch1 <<= 8;
        ch1 += ch3;
        ch3 = (unsigned long)key0[11];
        ch6 <<= 8;
        ch4 <<= 8;
        ch6 += ch2;
        ch2 = (unsigned long)key0[4];
        ch1 <<= 8;
        ch1 += ch5;  //// 0x9BA4B66A (17-16-15-14) 
        ch5 = (unsigned long)key0[10];
        ch4 += ch3;
        ch3 = (unsigned long)key0[7];
        ch6 <<= 8;
        ch4 <<= 8;
        ch4 += ch5;  //// 0xC08F9A86 (13-12-11-10)
        ch5 = (unsigned long)key0[6];
        ch6 += ch3;
        ch3 = (unsigned long)key0[3];
        ch6 <<= 8;
        ch6 += ch5;  //// 0x9AA2B19E (9-8-7-6)
        ch5 = (unsigned long)key0[5];
        ch5 <<= 8;
        ch5 += ch2;
        ch2 = (unsigned long)key0[2];
        ch5 <<= 8;
        ch5 += ch3;
        ch5 <<= 8;
        ch5 += ch2;  //// 0xA4DFD9AD (5-4-3-2)
        
        ////
        char * sn_ptr = &sn_int[0];
        for(int i=0; i<3; i++) {
                getKey0Check(ch5, ch6, ch4, ch1, sn_ptr);
                sn_ptr += 8; /// 指向SN的下一個2段 
        }
        ///
         
}

long getKey2Check2(unsigned long key, char * sn_int) {
        unsigned short key0 = 0;
        unsigned short key1 = 0;
        unsigned long  key2 = 0;
        unsigned long  key3 = 0;
        unsigned long  ch = 0;
        unsigned long  sn_part = 0;
        
        int n = 6;
        unsigned long sn_origin = 0;
        unsigned long sn_new = 0;
        unsigned long sn_tmp = 0;
        
        unsigned char * sn_ptr = (unsigned char *)&sn_int[2];
        do {
                key -= 0x76BDEFDB;
                key1 = (unsigned char)key;
                key2 = key >> 0x10;
                key1 <<= 8;
                key >>= 8;
                key3 = (unsigned long)key1;
                key = (unsigned char)key;
                key3 += key;
                key = key2;
                key0 = (unsigned char)key2;
                key0 <<= 8;
                key >>= 8;
                key3 <<= 0x10;
                key = (unsigned char)key;
                key3 += key;
                key = (unsigned long)key0;
                key += key3; //// 0xCFA8E91B
                //printf("     key: 0x%08X\n", key);
        
                //// 將SN每部分4字節組合成一個整數
                ch = (unsigned long)(* (sn_ptr+1));
                sn_part = ch;
                ch =  (unsigned long)(* (sn_ptr));
                sn_part <<= 8;
                sn_part += ch;
                ch =  (unsigned long)(* (sn_ptr-1));
                sn_part <<= 8;
                sn_part += ch;
                ch =  (unsigned long)(* (sn_ptr-2));
                sn_part <<= 8;
                sn_part += ch;  
                sn_tmp = sn_part; //// save temp 
                //printf("sn_Part1: 0x%08X\n", sn_part);
        
                //// 計算 
                sn_part -= key;
                sn_part ^= sn_origin;
                //printf("sn_Part2: 0x%08X\n", sn_part);
        
                //// 保存 
                * (sn_ptr-2) = (char)sn_part;
                sn_part >>= 8;
                * (sn_ptr-1) = (char)sn_part;
                sn_part >>= 8;
                * (sn_ptr)   = (char)sn_part;
                sn_part >>= 8;
                * (sn_ptr+1) = (char)sn_part;
        
                sn_ptr += 4;  ///// SN 下一段
                n--;
                sn_origin = sn_tmp;  /// SN 上一段的值,作為下一段的異常參數
        } while(n>0); 
        
        return 0;
}

//// Keys0 = {0xA4DFD9AD, 0x9AA2B19E, 0xC08F9A86, 0x9BA4B66A}
long getKey0Check(ULONG key1, ULONG key2, ULONG key3, ULONG key4, char * sn_int) {
        ULONG sn11, sn12, sn13;
        //// 取注冊碼 
        ULONG sn_part1 = (ULONG)(*(ULONG *)&sn_int[0]);
        ULONG sn_part2 = (ULONG)(*(ULONG *)&sn_int[4]);
        
        ULONG key = 0xC6EF3720;
        
        for(int i=0; i<32; i++) {
                sn11 = sn_part1 ^ key3;
                sn11 += key4;
                
                sn12 = sn_part1 >> 5;
                sn12 ^= key;
                
                sn11 += sn12;
                
                sn13 = sn_part1 << 4;
                sn13 += sn11;
                
                sn_part2 -= sn13;
                
                /////
                sn11 = sn_part2 ^ key1;
                sn11 += key2;
                
                sn12 = sn_part2 >> 5;
                sn12 ^= key;
                
                sn11 += sn12;
                
                sn13 = sn_part2 << 4;
                sn13 += sn11;
                
                sn_part1 -= sn13;
                
                key += 0x61C88647;
        }
        //// sn_part1= 0x4F16BACE, sn_part2 = 4C22825B, key = 0x00000000
        *(ULONG *)&sn_int[0] = sn_part1;
        *(ULONG *)&sn_int[4] = sn_part2;
        printSN(6); 
        
        return 0;
}

long getSNCheck2(char * sn_int) {
        char low = sn_int[22]; /// 0x4D
        char up  = sn_int[23]; /// 0x5F
        
        printf("up = 0x%02X, low = 0x%02X\n", up, low);
        
        for(int i=0; i<22; i++) {
                sn_int[i] = (sn_int[i] - up) ^ low;
        }
        
        return (up<<8) + low;
}

long getNameCheck(char * name) {
        ULONG check = 0;
        while(*name != '\0') {
                check = check ^ crc_table[(UCHAR)check ^ (UCHAR)(* name)];
                name ++;
        }
        
        return check;
}



第二部分就到這里,后面第三部分是對上面的代碼進行簡化和優化,這樣方便分析其算法,逆向出注冊機代碼。
頭像被屏蔽
4#
YI易 發表于 2019-12-27 18:10
5#
lm180180 發表于 2019-12-27 18:18
感謝分享 辛苦了!
6#
zxinyun 發表于 2019-12-27 18:21
我用這家呢視頻分割合并工具比較多
7#
白曉生 發表于 2019-12-27 18:53
真是高深莫測呀,這回有的耍了,感謝樓主技術分享
8#
水之鏡 發表于 2019-12-27 19:04
看著這個軟件轉換能力還蠻強的 期待試用 哈哈
9#
戰龍在野 發表于 2019-12-27 19:38
分析得很好謝謝提供學習了
10#
無奈123 發表于 2019-12-27 19:54
好多步驟  不容易啊
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:禁止回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2020-1-11 21:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表
腾讯二分彩骗局