逆向工程第007篇:跨越CM4驗證機制的鴻溝(下)

來源:互聯網
上載者:User

標籤:cm4   反組譯碼   註冊機   薑曄   逆向   

一、前言

        本文是逆向分析CM4系列的最後一篇,我會將該遊戲的序號驗證機制分析完畢,進而編寫出註冊碼產生器。

 

二、分析第二個驗證迴圈

        延續上一篇文章的內容,來到如下代碼處:


圖1

        上述代碼並沒有特別需要注意的地方,只是知道了接下來的迴圈需要執行4次。下面就是重要的驗證部分:


圖2

        這是註冊碼中第二組四個字元的產生代碼,主要是利用[ebp+var_20]進行運算,將結果作為字串的位移值,從而得到註冊碼。回顧一下,這裡的[ebp+var_20]是之前運算所得到的餘數,可見這個遊戲的驗證過程中的取餘運算還是比較多的。接下來的兩段代碼,與圖2代碼較為類似:


圖3


圖4

        上述兩段代碼在取餘並擷取相應字元的同時,還更改了[ebp+var_20]、[ebp+var_2C]與[ebp+var_38]中的值,用於接下來的運算,由於比較簡單,這裡就不再贅述。

        至此,CM4的註冊碼驗證機制徹底分析完畢,那麼接下來就可以開始註冊碼產生器的編寫了。

 

三、編寫註冊碼產生器        結合之前的分析,我們很容易就可以編寫出註冊機。但是要注意,我們在產生註冊碼的時候,是需要利用“cm4.epe”這個檔案的,需要將二者放置在同一目錄,讓註冊機程式便於讀取“密碼本”中的內容以進行運算,代碼如下:

#include<stdio.h>#include<windows.h>//////////////////////////////////////////////////////////////// GetNum函數用於計算cm4.epe檔案中相應位移值處的DWORD大小的// 十六進位數值,用於接下來的運算,該函數有一個參數var,儲存// 有位移值//////////////////////////////////////////////////////////////DWORD GetNum( DWORD dwOffset ){    HANDLE hFile = NULL;DWORD dwSigNum = 0;         // 用於儲存位於位移位置的DWORD位元組的內容DWORD dwNum = 0;            // 恒為0,用作ReadFile的參數// 開啟名為cm4.epe的檔案,該檔案與本程式應處於同一目錄下hFile = CreateFile("cm4.epe",               GENERIC_READ,   0,   NULL,   OPEN_EXISTING,   FILE_ATTRIBUTE_NORMAL,   NULL                      );// 如果檔案開啟失敗,則提示出錯資訊並退出if (hFile == INVALID_HANDLE_VALUE){         printf("Could not open cm4.epe\n");          return 0;}    // 設定檔案指標到指定的位置SetFilePointer(hFile, dwOffset, 0, FILE_BEGIN);// 讀取起始於檔案指標位置的十六進位代碼,讀取長度為4個位元組(DWORD)ReadFile(hFile, &dwSigNum, sizeof(DWORD), &dwNum, NULL);    CloseHandle(hFile);return dwSigNum;}int main(){    int a, b, c;             // 用於控制迴圈次數int i, j, m, n;          // 用於儲存第一組驗證碼的四個ASCII碼值int count = 10;          // 用於儲存產生的註冊碼的組數int tmp[4];              // 用於臨時儲存前四位驗證碼的ASCII碼減去0x30或0x37後的值int temp;                // 用於儲存臨時的運算結果int edx;                 // 用於儲存運算的餘數DWORD Num;               // 用於儲存位於cm4.epe相應位移處的十六進位代碼DWORD var_9C = 0x800000; // 這是一個固定的值,作為之後驗證中的除數DWORD var_14;            // 用於儲存第一迴圈演算法最終運算的結果DWORD var_20 = 0;DWORD var_2C = 0;DWORD var_38 = 0;        // 這三個變數用於儲存第二迴圈演算法中的運算結果char Reg[4][4] = { "0" };// 這個二維數組儲存最終得出的註冊碼char letter[37] = { "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" };// 字母表,用於產生註冊碼//////////////////////////////////////////////////////////////// 這裡是註冊碼演算法的第一處驗證迴圈,這裡通過四重迴圈,來不斷// 驗證各種不同的ASCII碼值的組合,也就是從0000到ZZZZ,從而產生// 第一組的驗證碼(4個字元)//////////////////////////////////////////////////////////////// 此處迴圈產生第一組驗證碼的第一個字元for ( i = 48; i <= 90; i++ ){    if( i >= 58 && i <= 64 ) continue;// 如果註冊碼是數字,則減去48if( i >= 48 && i <= 57 ){    tmp[0] = i - 48;}// 如果註冊碼是大寫字母,則減去55else{tmp[0] = i - 55;}// 此處迴圈產生第一組驗證碼的第二個字元for ( j = 48; j <= 90; j++ ){    if( j >= 58 && j <= 64 ) continue;// 如果註冊碼是數字,則減去48if( j >= 48 && j <= 57 ){    tmp[1] = j - 48;}// 如果註冊碼是大寫字母,則減去55else{    tmp[1] = j - 55;}// 此處迴圈產生第一組驗證碼的第三個字元for ( m = 48; m <= 90; m++ ){    if( m >= 58 && m <= 64 ) continue;// 如果註冊碼是數字,則減去48    if( m >= 48 && m <= 57 ){        tmp[2] = m - 48;}    // 如果註冊碼是大寫字母,則減去55    else{        tmp[2] = m - 55;}// 此處迴圈產生第一組驗證碼的第四個字元for ( n = 48; n <= 90; n++ ){    if( n >= 58 && n <= 64 ) continue; // 如果註冊碼是數字,則減去48        if( n >= 48 && n <= 57 ){            tmp[3] = n - 48;}        // 如果註冊碼是大寫字母,則減去55        else{            tmp[3] = n - 55;}    var_14 = 0;// 按照演算法進行運算for( a = 3; a >= 0; a-- ){    var_14 *= 36;                        var_14 += tmp[a];}if (var_14 % 36 != 0 ){                            // loc_4132CB                        Num = GetNum(var_14);                        var_20 = Num % var_9C;temp = var_20;temp %= 36;if ( temp == 0 ){    continue;}else{    // loc_41330F                            Num = GetNum(var_20);                            var_2C = Num % var_9C;temp = var_2C;temp %= 36;if ( temp == 0 ){        continue;}    else{    // loc_413353                                Num = GetNum(var_2C);                                var_38 = Num % var_9C;temp = var_38;temp %= 36;    if ( temp == 0 ){            continue;}        else{// 第一組(前四個)註冊碼驗證完畢並賦值Reg[0][0] = i;Reg[0][1] = j;Reg[0][2] = m;Reg[0][3] = n;//////////////////////////////////////////////////////////////// 這裡是註冊碼演算法的第二處驗證迴圈,這裡通過之前運算的結果,// 經過運算得到餘數(edx),作為letter[]字母表的位移,從而產生// 註冊碼字元//////////////////////////////////////////////////////////////                                    // loc_4133C5,第二處迴圈演算法for( b = 0; b < 4; b++ ){    c = 1;edx = var_20 % 36;Reg[c][b] = letter[edx];c += 1;    temp = var_20 / 36;var_20 = temp;edx = var_2C % 36;Reg[c][b] = letter[edx];c += 1;temp = var_2C / 36;var_2C = temp;edx = var_38 % 36;Reg[c][b] = letter[edx];temp = var_38 / 36;var_38 = temp;}// 輸出已經運算完畢的註冊碼for ( a = 0; a <= 3; a++){    for( b = 0; b <= 3; b++ ){    printf("%c", Reg[a][b]);    }if(a != 3){    printf("-");}}printf("\n");}}}count--;}if ( count == 0 ){    getchar();return 0;}}}}}return 0;}

        結合之前的分析,代碼並不難理解,只是各種驗證與迴圈比較多。這裡我只在乎實現,而不考慮代碼的最佳化等問題。

 

四、程式測試        這裡我先產生10個註冊碼。由於後三組註冊碼字元是嚴格取決於第一組註冊碼字元的取值的,而第一組註冊碼字元的取值範圍是在0000到FFFF之間,那麼我這裡產生的10個註冊碼其實也就所有註冊碼中的前十個,運行結果如下:


圖5 所產生的前10個註冊碼

        為了測試這些註冊碼,我們無需重新安裝遊戲,因為遊戲在安裝時會在註冊表中建立相應的鍵值,用於儲存註冊碼,而遊戲每次啟動又會查詢註冊表擷取該註冊碼,所以我們只需修改該鍵值即可:


圖6

        我不可能驗證所有註冊碼,但是驗證這十個,結果是可行的,那麼可以認為上面的程式是可行的,這裡不再贅述。

 

五、後記        這三篇關於CM4逆向分析的文章,可以說是我到目前為止寫作時間跨度最長的了。本系列的上篇,我是在研究完FIFA07與《仙劍奇俠傳》之後就打算寫作的,大概是在今年6月中旬的時候。那時寫了個初稿,也就是通過“爆破”的方式來繞過驗證機制,想繼續寫註冊機的編寫部分,無奈水平有限,一直拖到現在才完成。這大半年的時間也是我的知識水平增長最快的半年,要不然我依舊不能分析出CM4的驗證機制。這三篇文章的中篇和下篇,是利用了一個多星期的時間突擊完成的,這段時間每天只有很少的時間用於分析,而且分析過程中也走了非常多的彎路,也正是因為這些彎路,我才能夠在文章中始終展示出一片坦途。因為是第一次分析註冊碼驗證機制,沒有經驗,耗時也比較長。但是我的收穫卻是巨大的。我也希望各位讀者也能夠從這些文章中有所收穫,多多練習,多多思考,不斷嘗試,將自己所學,真正運用於自己的身邊以及自己的工作中。

逆向工程第007篇:跨越CM4驗證機制的鴻溝(下)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.