【收山之作】用yourdiary为例 学习KRKR2 XP3加密静态分析
? ?以前我談過,?第1章?KRKR游戲系統漢化說明
? 我覺得問題在于很多商業KRKR系統都是加密過的數據,今天作為收山之文,談下XP3加密分析和封包算法
? 今天我們分析的游戲是《yourdiary》,也是前久漢化組來求破解的游戲。
 
加密VS解密
不管KRKR還是.net 還是JAVA,以及android,其加密解密方法基本差不多,就是HOOK相應函數或者提供相應接口就OK。
無外乎解密存在兩種方法
1、動態HOOK 然后內存DUMP
2、靜態分析
舉例:
1、動態HOOK?xp3dumer
 
2、靜態分析 ?Crass
 
JAVA 靜態解密可以參考鄙人做的java?Class文件解密大師發布和說明
 
對于大家來說動態HOOK簡單實用,因為不需要考慮什么加密算法,直接內存DUMP
對于程序猿來說,顯然靜態分析,逆向其算法更能提高水平。
 
所以說本文需要程序設計基礎非大眾讀物。
 
? 我們用Crass解包直接解包,提示CRC錯誤。
??
青子私服c06a(大)-mono.tlg: crc校驗失敗(0x90d63725), 應該是0xe1eb5d2b. 青子私服c06a(大).tlg: crc校驗失敗(0x2a395798), 應該是0x9ff1bbbe. 青子私服c06a(近)-mono.tlg: crc校驗失敗(0xab6e8767), 應該是0x70439e0e. 青子私服c06a(近).tlg: crc校驗失敗(0xac8ab284), 應該是0x346e11f5. 黒幕.tlg: crc校驗失敗(0xc41caf48), 應該是0x9014486f. data.xp3: 成功提取1286 / 1286 個資源文件? 怎么回事,CRC錯誤可能就是1、文件損壞了 2、加密了
? 顯然游戲可以正常運行,否定1。
? 用UE打開XP3,分析下看不出規律,現在只能從代碼入手。
??
打開plugin目錄有個yourdiary.tpm
這個就是加密DLL
用反匯編器打開看看
發現有兩個導出函數
V2Link
 V2Unlink
 
 
注意:KRKR分早期版本和2.22以后版本,其導出函數不一樣,大家要注意.不過大家遇到KRKR都不很老,所以本文基本可以通吃。
 
這里需要大家有KRKR封包加密插件編寫的經驗才能跟到關鍵加密代碼段
至于加密插件的使用方法請參照水螅大大的教程,這里不再贅述。
 
 我直接跟進關鍵加密代碼段:
 .text:10001000
 .text:10001000 ; Segment type: Pure code
 .text:10001000 ; Segment permissions: Read/Execute
 .text:10001000 _text ? ? ? ? ? segment para public 'CODE' use32
 .text:10001000 ? ? ? ? ? ? ? ? assume cs:_text
 .text:10001000 ? ? ? ? ? ? ? ? ;org 10001000h
 .text:10001000 ? ? ? ? ? ? ? ? assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
 .text:10001000
 .text:10001000 loc_10001000: ? ? ? ? ? ? ? ? ? ? ? ? ? ; DATA XREF: V2Link:loc_10001078o
 .text:10001000 ? ? ? ? ? ? ? ? push ? ?esi
 .text:10001001 ? ? ? ? ? ? ? ? mov ? ? esi, [esp+8]
 .text:10001005 ? ? ? ? ? ? ? ? cmp ? ? dword ptr [esi], 18h
 .text:10001008 ? ? ? ? ? ? ? ? jz ? ? ?short loc_1000102C
 .text:1000100A ? ? ? ? ? ? ? ? mov ? ? eax, dword_1000C2CC
 .text:1000100F ? ? ? ? ? ? ? ? test ? ?eax, eax
 .text:10001011 ? ? ? ? ? ? ? ? jnz ? ? short loc_10001025
 .text:10001013 ? ? ? ? ? ? ? ? push ? ?offset aVoidTvpthrowex ; "void ::TVPThrowExceptionMessage(const t"...
 .text:10001018 ? ? ? ? ? ? ? ? call ? ?sub_100010C0
 .text:1000101D ? ? ? ? ? ? ? ? add ? ? esp, 4
 .text:10001020 ? ? ? ? ? ? ? ? mov ? ? dword_1000C2CC, eax
 .text:10001025
 .text:10001025 loc_10001025: ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: .text:10001011j
 .text:10001025 ? ? ? ? ? ? ? ? push ? ?offset aIncompatibleTt ; "Incompatible tTVPXP3ExtractionFilterInf"...
 .text:1000102A ? ? ? ? ? ? ? ? call ? ?eax ; dword_1000C2CC
 .text:1000102C
 .text:1000102C loc_1000102C: ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: .text:10001008j
 .text:1000102C ? ? ? ? ? ? ? ? xor ? ? eax, eax
 .text:1000102E ? ? ? ? ? ? ? ? cmp ? ? [esi+10h], eax
 .text:10001031 ? ? ? ? ? ? ? ? jbe ? ? short loc_1000104B
 .text:10001033
 .text:10001033 loc_10001033: ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: .text:10001049j
 .text:10001033 ? ? ? ? ? ? ? ? mov ? ? ecx, [esi+0Ch]
 .text:10001036 ? ? ? ? ? ? ? ? mov ? ? dl, [ecx+eax]
 .text:10001039 ? ? ? ? ? ? ? ? xor ? ? dl, [esi+14h]
 .text:1000103C ? ? ? ? ? ? ? ? add ? ? ecx, eax
 .text:1000103E ? ? ? ? ? ? ? ? xor ? ? dl, 0CDh
 .text:10001041 ? ? ? ? ? ? ? ? add ? ? eax, 1
 .text:10001044 ? ? ? ? ? ? ? ? mov ? ? [ecx], dl
 .text:10001046 ? ? ? ? ? ? ? ? cmp ? ? eax, [esi+10h]
 .text:10001049 ? ? ? ? ? ? ? ? jb ? ? ?short loc_10001033
 .text:1000104B
 .text:1000104B loc_1000104B: ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: .text:10001031j
 .text:1000104B ? ? ? ? ? ? ? ? pop ? ? esi
 .text:1000104C ? ? ? ? ? ? ? ? retn ? ?4
 .text:1000104C ; ---------------------------------------------------------------------------
 .text:1000104F ? ? ? ? ? ? ? ? align 10h
 .text:10001050 ; Exported entry ? 1. V2Link
 
 
要看懂上面匯編對于新手是很難的,因為計算機不懂什么叫類,什么叫對象,什么叫結構體。
所有的這些概念在編譯之后都不復存在。
數據解密最難也在于此,比如[esi+0Ch]那是啥玩意,是數組?還是結構體?還是對象?
就像在漆黑的屋子里面抓到一大團毛絨絨的東西,是啥,是兔子還是貓?
 
好在解密插件是開源的
大家可以打開KRKR源代碼\2.26\kirikiri2\src\plugins\win32\xp3filter\xp3dec 目錄下的 main.cpp
可以看到
//--------------------------------------------------------------------------- void TVP_tTVPXP3ArchiveExtractionFilter_CONVENTIONTVPXP3ArchiveExtractionFilter(tTVPXP3ExtractionFilterInfo *info) {// TVPXP3ArchiveExtractionFilter 関數は本體側から呼び出される// コールバック関數です。// 引數を一つ取り、それは tTVPXP3ExtractionFilterInfo 構造體へのポインタ// です。// TVPXP3ArchiveExtractionFilter は、後述の V2Link 関數內で// TVPSetXP3ArchiveExtractionFilter により設定されます。// ここでは単純に、xp3enc.dll のサンプルで作成された XP3 アーカイブを// 復號すべく、データをすべて FileHash の最下位バイトで XOR// することにします。// この関數は複數のスレッドから同時に呼び出される可能性があるので// 注意してください。/*tTVPXP3ExtractionFilterInfo のメンバは以下の通り* SizeOfSelf : 自分自身の構造體のサイズ* Offset : "Buffer" メンバが指し示すデータが、* : アーカイブに格納されているそのファイルの先頭からの* : どのオフセット位置からのものか、を表す* Buffer : データ本體* BufferSize : "Buffer" メンバの指し示すデータのサイズ(バイト単位)* FileHash : ファイルの暗號化解除狀態でのファイル內容の32bitハッシュ*/// 一応構造體のサイズをチェックするif(info->SizeOfSelf != sizeof(tTVPXP3ExtractionFilterInfo)){// 構造體のサイズが違う場合はここでエラーにした方がよいTVPThrowExceptionMessage(TJS_W("Incompatible tTVPXP3ExtractionFilterInfo size"));// TVPThrowExceptionMessage は例外メッセージを投げる関數// この関數は戻らない ( もっと呼び出し元をさかのぼった位置で// 例外が補足されるため )}// 復號tjs_uint i;for(i = 0; i < info->BufferSize; i++)((unsigned char *)info->Buffer)[i] ^= info->FileHash; } //------------我們可以看到上面的匯編就是上面這個官方實例的修改版,
但要知道[esi+0Ch]是啥,還得研究官方源代碼,所有KRKR解密依賴于tTVPXP3ExtractionFilterInfo這個結構,顯然解密代碼就是結構體操作。
下面請大家復習下C語言知識:
| 類型標識符 | 類型說明 | 長度 ?? (字節) | 范圍 | 備注 | 
| char | 字符型 | 1 | -128 ~ 127 | -27?~ (27?-1) | 
| unsigned char | 無符字符型 | 1 | 0 ~ 255 | 0 ~ (28?-1) | 
| short int | 短整型 | 2 | -32768 ~ 32767 | 2-15?~ (215?- 1) | 
| unsigned short int | 無符短整型 | 2 | 0 ~ 65535 | 0 ~ (216?- 1) | 
| int | 整型 | 4 | -2147483648 ~ 2147483647 | -231?~ (231?- 1) | 
| unsigned int | 無符整型 | 4 | 0 ~ 4294967295 | 0 ~ (232-1) | 
| float | 實型(單精度) | 4 | 1.18*10-38?~ 3.40*1038 | 7位有效位 | 
| double | 實型(雙精度) | 8 | 2.23*10-308?~ 1.79*10308 | 15位有效位 | 
| long double | 實型(長雙精度) | 10 | 3.37*10-4932?~ 1.18*104932 | 19位有效位 | 
上面這張表是一般VC 32位程序類型的資料。大家特別注意下長度,你看int 占用4字節,不過不同編譯器和平臺不一樣,數據類型的字節數應該是由CPU決定的,但是實際上主要由編譯器決定。
顯然一個類似下面這樣結構體:
struct Student {int name;int sex;int age;int addr; }; /*然后定義一個Student 類型的 student變量*/ struct Student student;
student這樣的結構體占用4×4=16字節
內存分布一般為:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15?
name ? sex ? ? ?age ? ? ? ? ? addr
下面我們看看tTVPXP3ExtractionFilterInfo結構如下:大小和內存位置我已經標注給大家(KRKR源代碼\2.26\kirikiri2\src\plugins\win32\tp_stub.cpp文件中)
struct tTVPXP3ExtractionFilterInfo {const tjs_uint SizeOfSelf; // structure size of tTVPXP3ExtractionFilterInfo itself 4個字節 0-3const tjs_uint64 Offset; // offset of the buffer data in uncompressed stream position 8個字節 4-11void * Buffer; // target data buffer 4個字節 12-15const tjs_uint BufferSize; // buffer size in bytes pointed by "Buffer" 16-19const tjs_uint32 FileHash; // hash value of the file (since inteface v2)tTVPXP3ExtractionFilterInfo(tjs_uint64 offset, void *buffer,tjs_uint buffersize, tjs_uint32 filehash) :Offset(offset), Buffer(buffer), BufferSize(buffersize),FileHash(filehash),SizeOfSelf(sizeof(tTVPXP3ExtractionFilterInfo)) {;} };有了這些東西,我們去搞匯編就易如反掌了
上面加密算法偽代碼應該這樣:
取出[esi+0Ch]里的數據,即Buffer[i]
異或xor ?[esi+14h] 即?FileHash
異或xor?0CDh
 
 
好了解密算法這樣寫就OK了:
//--------------------------------------------------------------------------- void TVP_tTVPXP3ArchiveExtractionFilter_CONVENTIONTVPXP3ArchiveExtractionFilter(tTVPXP3ExtractionFilterInfo *info) {// TVPXP3ArchiveExtractionFilter 函數是會從吉里吉里本體調用的回調函數。// 能得到的參數只有一個,就是對 tTVPXP3ExtractionFilterInfo 結構體的指針。// TVPXP3ArchiveExtractionFilter 需要在后述的 V2Link 函數內使用// 吉里吉里本體的 TVPSetXP3ArchiveExtractionFilter 函數設定。// 這個樣例只是純粹的對 xp3enc.dll 樣例代碼加密的 XP3 文件包解密// 將所有的數據以 FileHash 的最后一個字節作異或(XOR)運算// 請注意,這個函數有可能在多個線程中被調用。/*tTVPXP3ExtractionFilterInfo 的成員如下* SizeOfSelf : 結構體自身的大小* Offset : "Buffer" 成員所指向的數據偏離這個文件頭部的偏移值* Buffer : 數據本體* BufferSize : "Buffer" 成員所指向的數據的大小(字節單位)* FileHash : 解密后文件內容的32位 Hash (散列)值*/// 檢查結構體的大小if(info->SizeOfSelf != sizeof(tTVPXP3ExtractionFilterInfo)){// 當結構體的大小錯誤,則最好投出異常TVPThrowExceptionMessage(TJS_W("Incompatible tTVPXP3ExtractionFilterInfo size"));// TVPThrowExceptionMessage 是用于投出異常的函數// 本函數不會返回。}// yourdiary 解密代碼 by大師♂羅莊 // ext:10001033 loc_10001033: ; CODE XREF: .text:10001049j //.text:10001033 mov ecx, [esi+0Ch] //Buffer[i] //.text:10001036 mov dl, [ecx+eax]//Buffer[i] //.text:10001039 xor dl, [esi+14h] //FileHash //.text:1000103C add ecx, eax //.text:1000103E xor dl, 0CDh //.text:10001041 add eax, 1 //.text:10001044 mov [ecx], dl //.text:10001046 cmp eax, [esi+10h]//循環比較BufferSize //.text:10001049 jb short loc_10001033 //.text:1000104B //.text:1000104B loc_1000104B: ; CODE XREF: .text:10001031j //.text:1000104B pop esi //.text:1000104C retn 4 //.text:1000104C ; --------------------------------------------------------------------------- //.text:1000104F align 10htjs_uint i;for(i = 0; i < info->BufferSize; i++){unsigned char v4 =((unsigned char *)info->Buffer)[i] ;unsigned char v5 =info->FileHash^ (v4);unsigned char result ;result = v5 ^ 0xCD;((unsigned char *)info->Buffer)[i] =result;} } //---------------------------------------------------------------------------編譯生成*.dll 然后改成*.tmp
可以覆蓋游戲*.tmp試試,但最好別這樣,最好用Crass 帶tmp參數進行測試,發現沒有錯誤能解包。
好了課程就這樣,下課。
 
 
總結
以上是生活随笔為你收集整理的【收山之作】用yourdiary为例 学习KRKR2 XP3加密静态分析的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Swagger2 @ApiImplici
- 下一篇: 常见算法复习整理1
