《同級生1》DMM版破解手記之腳本文件解包

《同級生1》DMM版(即Original版)是2007年3月1日由DMM發行的《同級生》復刻版,似乎DMM發佈的elf遊戲都採用了新的系統,加密方式和原來的win版有所不同,使用目前網絡上流行的遊戲文件提取工具(如mlist3等)均無法提取本版本遊戲的文件,於是只能手動逆向調試進行文件提取。按照elf遊戲的一貫做法,腳本文件都被打包在mes.arc文件中。採用調試器OllyDBG v1.10,操作系統爲Windows XP。

關於od的基本使用方法不再贅述,這裏只記錄主要解密過程。

1、啓動調試器,運行AI5WIN.exe,給ReadFile函數下斷點:

然後按F9運行程序,直到ReadFile第一次斷下mes.arc:

此時可以記下句柄號。

2、繼續運行程序,直到直到ReadFile第二次斷下mes.arc,在數據窗口中查看Buffer的地址,並在第一個字節上設置內存訪問斷點:

繼續運行程序直到命中剛纔的內存訪問斷點,此時所在的代碼段就是對mes.arc的文件頭進行解密的代碼,其中包括了被打包的腳本文件的文件名、文件長度和在mes.arc中的偏移量,核心部分如下:

004019FD   .  B3 35         MOV BL,35
……
00401A10   >  309C08 FCFEFF>XOR BYTE PTR DS:[EAX+ECX-104],BL
00401A17   .  83C1 01       ADD ECX,1
00401A1A   .  81F9 00010000 CMP ECX,100
……
00401A22   .  8170 FC 8B5F5>XOR DWORD PTR DS:[EAX-4],A25D5F8B
00401A29   .  8130 69A7FEA9 XOR DWORD PTR DS:[EAX],A9FEA769
……

這一段彙編沒有任何難度,首先是對文件名xor 0x35,最大長度0x100個字節,然後對文件長度xor A25D5F8B,最後對文件偏移xor A9FEA769。至於爲什麼能確定第一個是長度、第二個是偏移,這個只要觀察連續兩個文件的信息就能看出,偏移量的改變比較會小而且是遞增的。

3、繼續運行程序,直到直到ReadFile第三次斷下mes.arc,這次就是讀入具體的腳本文件了,遊戲啓動第一次讀取的文件是start.mes:

在數據窗口中查看Buffer的地址,並在第一個字節上設置內存訪問斷點,運行程序等待斷點命中,此時我們就找到了解密腳本文件的代碼。這段代碼比較複雜,本質上是個解壓縮的算法,我們到下一篇文章中再探討。

在寫解包器的程序時,我們可以直接把這段彙編拿過來用,不必一定改寫成高級語言的形式。在我寫的解包器中,核心解密函數的代碼如下:

DWORD Decode(void* srt, DWORD len, void* dst)
{
    g_bufSrt = srt;
    g_lenRaw = len;
    g_bufDst = dst;

    _asm
    {
        mov ebx, g_bufSrt;
        xor eax, eax;
        push ebp;
        xor ebp, ebp;
        xor esi, esi;
        sub esp, 0x2000;
        mov edi, esp;
        mov ecx, 0x2000;
        rep stos;
    }
    __asm
    {
        cmp g_lenRaw, eax;
        mov edi, 0x0fee;
        je ai5win_0042c404;
        jmp short ai5win_0042c344;
        jmp short ai5win_0042c340;
        lea ecx, dword ptr ds:[ecx];
ai5win_0042c340:
        mov eax, dword ptr ss:[esp+0x10];
ai5win_0042c344:
        shr eax, 0x1;
        test eax, 0x100;
        mov dword ptr ss:[esp+0x10], eax;
        jnz short ai5win_0042c363;
        mov al, byte ptr ds:[esi+ebx];
        movzx eax, al;
        add esi, 0x1;
        or eax, 0x0ff00;
        mov dword ptr ss:[esp+0x10], eax;
ai5win_0042c363:
        test byte ptr ss:[esp+0x10], 0x1;
        je short ai5win_0042c38c;
        mov al, byte ptr ds:[esi+ebx];
        mov edx, g_bufDst;
        movzx eax, al;
        mov byte ptr ss:[esp+edi+0x1c], al;
        mov byte ptr ds:[edx+ebp], al;
        add edi, 0x1;
        add esi, 0x1;
        add ebp, 0x1;
        and edi, 0x0fff;
        jmp short ai5win_0042c3f5;
ai5win_0042c38c:
        mov dl, byte ptr ds:[esi+ebx];
        mov al, byte ptr ds:[esi+ebx+0x1];
        add esi, 0x1;
        movzx ecx, al;
        mov eax, ecx;
        and eax, 0x0f0;
        movzx edx, dl;
        shl eax, 0x4;
        or eax, edx;
        and ecx, 0x0f;
        add esi, 0x1;
        add ecx, 0x2;
        mov dword ptr ss:[esp+0x18], ecx;
        mov edx, 0x0;
        js short ai5win_0042c3f5;
        lea esp, dword ptr ss:[esp];
ai5win_0042c3c0:
        mov ebx, g_bufDst;
        lea ecx, dword ptr ds:[edx+eax];
        and ecx, 0x0fff;
        movzx ecx, byte ptr ss:[esp+ecx+0x1c];
        mov byte ptr ss:[esp+edi+0x1c], cl;
        add edi, 0x1;
        mov byte ptr ds:[ebx+ebp], cl;
        add edx, 0x1;
        add ebp, 0x1;
        and edi, 0x0fff;
        cmp edx, dword ptr ss:[esp+0x18];
        jle short ai5win_0042c3c0;
        mov ebx, dword ptr g_bufSrt;
ai5win_0042c3f5:
        cmp esi, g_lenRaw;
        jnz ai5win_0042c340;
        mov eax, ebp;
ai5win_0042c404:
        mov ecx, dword ptr ss:[esp+0x101c];
    }
    __asm 
    {
        add esp, 0x2000;
        mov g_lenDecode, ebp;
        pop ebp;
    }
    return g_lenDecode;
}

函數參數分別爲解密前數據的地址、長度和解密後數據的地址(要求事先分配好足夠空間),函數返回值爲解密後數據的長度。

在下一篇文章中會解釋這段彙編代碼的原理,以及如何設計封包算法。

 轉載請註明來源及鏈接:未來代碼研究所
 本文鏈接地址:http://blog.atelier39.org/rev_eng/615.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章