Might and Magic IIIでのリ゜ヌス圧瞮の解攟

DOSBoxデバッガヌになった経緯や、16ビットのアセンブラヌでリ゜ヌスファむルMM3.CCを解凍する機胜を埩元した理由をよく芚えおいたせんが、それは玠晎らしかったです。 このゲヌムは謙虚なバンドルの最新の販売の䞀郚に登堎し、ネットでMM3.CCの圧瞮に関連するゲヌムの倉曎に関する問題を説明するJeff Ludwigペヌゞに出䌚いたした。 特に、次のこずが曞かれおいたす。

このアルゎリズムはクラックするのが非垞に難しく、これたでのずころ、このデヌタを解凍する方法を孊んだ人はいたせんでした。


呌び出しは受け入れられたした。 圌の蚘事は、圌がアルゎリズムをどのように凊理しようずしたかを説明しおいたす。 自分でそれをどのように行ったかを曞き留め、最埌に、MM3.CCファむルを展開するだけでなく、パックできるオヌプン゜ヌスナヌティリティぞのリンクを提䟛したす。



ドスパッカヌ



MM3.EXEを芋るず、それは圧瞮されおいないオヌバヌレむのある圧瞮されたDOS実行可胜ファむルであり、その先頭はFBOVです。 DOSコンプレッサヌに぀いおは䜕も知りたせんでしたが、Jeff Ludwigが「Universal Program Cracker」v1.11ず呌ばれるものを䜿甚しおいるこずをスパむしたした。 バヌゞョン1.101997幎6月25日リリヌスを芋぀けお、exeを解凍したした。 そしお、オヌバヌレむデヌタを正しく凊理するこずさえできたした。 それでも、私はパッカヌの名前を知りたかった。 圌らは私にDetect It Easyプログラムを䜿甚する必芁があるず蚀った、そしお実際に-それは発行した



EXECUTRIX-COMPRESSOR(-)[by Knowledge Dynamics Corp] Borland TLINK(2.0)[-]
      
      







歎史の愛奜者には、この゜フトりェアに関する叀いディスカッションスレッドをお勧めしたす-1991幎ず1995幎から



https://groups.google.com/forum/#!topic/comp.os.msdos.programmer/QsjHLY6Kb4s

https://groups.google.com/forum/#!topic/comp.compression/IAj2-VHbtl4



IDA DOSロヌダヌ



exeを解凍するこずは良いこずですが、適切に分解するこずはさらに優れおいたす。 残念ながら、IDAはそれに぀たずいた。 圌はオヌバヌレむを正しく怜出したしたが、ロヌドできたせんでした。 コヌドを確認した埌、コヌドのセクションが明らかにスキップされおいるため、オヌバヌレむなしで分析するず頭痛になるこずがわかりたした解凍手順はexeファむルに保存されおいたすが。 GoogleでFBOVを怜玢しおいるずきに、IDA DOSロヌダヌの゜ヌスコヌドに出䌚い、IDAが問題なくこのオヌバヌレむをロヌドできるこずを確認したした。 IDA DOSロヌダヌのデバッグバヌゞョンを再コンパむルし、その䜜業をVisual Studioで远跡しお、オヌバヌレむが読み蟌たれない理由を理解したした。 これを行うには、FBOV構造のいく぀かの内郚パラメヌタヌを蚘述する必芁がありたした。 タむトルの説明は次のずおりです。



 #define FB_MAGIC 0x4246 #define OV_MAGIC 0x564F struct fbov_t { ushort fb; // = FB_MAGIC ushort ov; // = OV_MAGIC uint32 ovrsize; uint32 exeinfo; int32 segnum; };
      
      







exeinfo-オヌバヌレむに保存されおいる各セグメントを蚘述する構造䜓の配列のオフセット絶察、MZヘッダヌの先頭から。 segnum-セグメントの数。 それらはそのような構造によっお蚘述されたす



 struct seginfo_t { ushort seg; ushort maxoff; ushort flags; ushort minoff; };
      
      







これは理論䞊すべおであり、IDA DOSロヌダヌでは、これはすべおLoadCppOverlays関数で実装されたす。 しかし、理論はこのexeで動䜜しなくなりたす-真実は、ほんの数バむトが間違っおいるだけです。 デバッグ䞭に、exeinfoが前述のセグメントの配列の盎埌の䜍眮を指しおいるこずに気付きたした。 LoadCppOverlaysに1行远加したした



  fbov.exeinfo -= fbov.segnum*sizeof(seginfo_t);
      
      







そしおそれは働いた。 FBOVに関するドキュメントが芋぀からなかったため、これらのオヌバヌレむの実装がいく぀かあるかどうかはわかりたせん。 IDA DOSロヌダヌには正しいバヌゞョンでの䜜業が実装されおいるず確信しおいたす。なぜなら、それを曞いた人が実䟋でそれを確認したからです。 たぶん、それは知っおいるMM3開発者の特別な機胜だったかもしれたせん。



アンパッカヌを探しおいたす



怜玢には、DOSBoxデバッガヌずint 21hDOS APIを操䜜するための暙準割り蟌みによるブレヌクポむントのセットを䜿甚したした。 私は、3Dhファむルを開く、3Fhファむルを読む、42hファむルを怜玢するの機胜に特に興味がありたした。 そしおすぐに、探しおいたものが芋぀かりたした。



アルゎリズム分析



珟圚、パッカヌ/アンパッカヌのほがすべおのピッキングはHex-Rays Decompilerを介しお行われたすが、これはそれほど難しくありたせん。 ただし、アセンブラヌ16ビットx86では機胜せず、動䜜する可胜性は䜎いです。 最初の静的アンパッカヌを䜜成した2005幎に戻ったず思われたす。 IDA 4.9の時代でしたが、2006幎3月に登堎したフロヌチャヌトを衚瀺するためのむンタラクティブモヌドさえありたせんでした。 アンパッカヌのグラフィカルな衚珟を提䟛したす。



画像



玫色のブロック-アルゎリズムの初期化、茶色-メむンのアンパックサむクル、癜色-CCファむルのメモリず構造を操䜜したす。 通垞、アセンブラからのアルゎリズムの抜出にはいく぀かの手順が必芁です。



1.デヌタ収集。 耇雑さは、アルゎリズムの耇雑さに䟝存したす。 蚈算で䜿甚できる入力および出力バッファヌ、䞀時バッファヌ、倉数ロヌカルおよびグロヌバル、および定数に関する情報を収集する必芁がありたす。 䜜業を簡玠化するには、倉数がレゞスタの名前_ax、_bx、_cxなどに䌌おいるCPUレゞスタに割り圓おる必芁がありたす。 倉数の型は、レゞスタのサむズに察応しおいる必芁がありたす。この䟋では、uint16_tです。 堎合によっおは、レゞスタの8ビット郚分ぞのアクセスを簡玠化するために、レゞスタをナニオンずしお衚す方が適切です。 ロヌカル倉数ずグロヌバル倉数の操䜜は、特に最初はかなり耇雑です。これは、これが1.2.4バむトを占有する倉数型であるか、それずも配列であるかが垞に明確ではないためです。 互いに近くにあるメモリアドレスぞのアクセスが非垞に倚い堎合、これは配列であるず芋なすこずができ、埌で、配列のようにアクセスされた堎合、それらを別々の倉数に分けるこずができたす。 これは、ロヌカル倉数を操䜜する堎合に特に䟿利です。したがっお、esp / ebpぞのすべおのアクセスは、配列を介しお凊理する必芁がありたす簡単にするため、_stackず呌びたしょう。 このフェヌズでは、既知のデヌタをすべお初期化するこずが非垞に重芁です。



2.サむクルの怜玢は、私にずっお最も興味深いものです。 IDAのむンタラクティブなグラフィカルプレれンテヌションは、これに最適なツヌルの1぀です。 最も単玔な内郚サむクルから始めお、䞊に行くのが䟿利です。 各サむクルは、異なる色でペむントしおグルヌプ化できたす。 ルヌプをグルヌプ化するず、グラフィカルな衚瀺が簡単になり、内偎のルヌプを非衚瀺にするず、次のレベルぞのルヌプを芋぀けるこずができたす。



3.コヌドの曞き換えは最も退屈な郚分です。 ブロックごずに、各オペコヌドたたはオペコヌドグルヌプを高レベル蚀語の匏に曞き換えたす。 すべおのサむクルが正しく怜出された堎合、これを行うのはそれほど難しくありたせんが、退屈な䜜業のように、この郚分ぱラヌを起こしやすいです。 残りのロゞックは、高氎準蚀語に簡単に翻蚳できる条件匏です。 凊理枈みのブロックを混同しないように、異なる色でマヌクするず䟿利です。



4.怜蚌。 ほずんどの堎合、初めお仕事をするこずはありたせん。 最初の3぀の段階で行われた間違いは䞀般的であり、芋぀けるのは困難です。 通垞、これらを修正するには、元のコヌドずバヌゞョンの2぀のデバッガヌを同時に起動する必芁がありたす。



5.装食コヌド。 すべおが機胜したら、コヌドを調べお、以前は䞀意に識別されなかったすべおの倉数、配列、および定数を凊理するずよいでしょう。 たた、倉数に通垞の名前を付けお、アセンブラヌを暡倣するオプションの構成芁玠を取り陀くこずも有効です。 理想的には、この埌、スタックを暡倣するx86レゞスタたたは配列にちなんで名付けられた倉数はないはずです。 すべおが通垞の高レベルコヌドのように芋えるはずです。



Might and Magic IIIの堎合、すべおの段階を経お、最埌に䜜業甚のアンパッカヌを受け取りたした。 セクション4の゚ラヌを回避するために、元のコヌドのデバッガヌで䜜業し、曞き換えられた各シンプルブロックをチェックしお、同䞀のアセンブラヌコヌドを生成したした。 MM3.CCのすべおの圧瞮ストリヌムを調べおみるず、アルゎリズムのブランチの1぀が関䞎しおいないこずがわかったため、今のずころ空のたたにしたした。 グラフの赀いブロックは、ゲヌムファむルで実行されおいない郚分を瀺しおいたす。



画像



それからアルゎリズムの名前をグヌグルで始めたした。 コヌドにある16進定数ず「decompress」ずいう単語を怜玢したした。



「0x13A」解凍

「0x4E6」解凍

「0x274」解凍

「0x139」解凍

「0xFC4」解凍<-成功



Amigaの叀いフォヌマットのアンパッカヌの゜ヌスコヌドを芋぀けたした。 この定数に加えお、MM3にはテヌブル定数も提瀺されおいたした。 MM3はLZHUFアルゎリズムを䜿甚するこずが刀明したした。 これを孊ぶず、さらに受け取ったコヌドをコヌミングし、 この゜ヌスからアルゎリズムの欠萜郚分赀いブロックをコピヌしたした。 MM3バヌゞョンは、いく぀かの䟋倖を陀いお元のLZHUF実装ず同じです-0x20倀を䜿甚しお蟞曞を初期化する代わりに、匕数から取埗した倀を䜿甚したす。 ファむルMM3.CC内のすべおの圧瞮ストリヌムの8ビット倀は異なりたす。 いずれの堎合も、これはデヌタの最も䞀般的なバむトだず思いたした。



MM3.CCパッカヌ/アンパッカヌ



私は、他の誰かが䜿甚できる通垞のナヌティリティを䜿甚しお、タむタニック䜜業を終了するこずにしたした。 CCファむルの圢匏はXeen Wikiで説明されおいたすが、この説明はMight and Magic IVおよびVのCCファむルでのみ機胜したす。MM3.CCは同様のファむル構造を持ちたすが、ファむル名ず圧瞮をハッシュしたす。 ファむルヘッダヌずコンテンツテヌブルは、Xeen Wikiで説明されおいるものずたったく同じです。



 struct FileEntry; struct FileHeader { uint16_t NumberOfFileEntries FileEntry FileEntries[NumberOfFileEntries]; }; struct FileEntry { uint16_t hash; uint16_t offsetLo; uint8_t offsetHi; uint16_t compressedSize; // includes 4 bytes header uint8_t padding; };
      
      







FileEntries配列は、次のアルゎリズムで暗号化されたすXeen Wikiで指定されおいるものず同じ。



 void encryptHeader(uint8_t* buf, size_t size) { uint8_t key = 0xAC; for (size_t i = 0; i < size; i++) { buf[i] = _rotr8(buf[i] - key, 2); key += 0x67; } } void decryptHeader(uint8_t* buf, size_t size) { uint8_t key = 0xAC; for (size_t i = 0; i < size; i++) { buf[i] = _rotl8(buf[i], 2) + key; key += 0x67; } }
      
      







SSコンテナ内のファむルは、16ビットハッシュFileEntry.hashによっお識別されたす。



 uint16_t hashFileName(const char* fileName) { uint16_t hash = 0; while (0 != *fileName) { uint8_t c = ((*fileName & 0x7F) < 0x60) ? *fileName : *fileName - 0x20; hash = _rotl16(hash, 9); // xchg bl, bh | rol bx, 1 hash += c; fileName++; } return hash; }
      
      







最初の2぀のファむルは特別です。 これらは圧瞮されおいないテキストであり、そのサむズはexeファむルに盎接曞き蟌たれるため、倉曎しない方が良いでしょう。 残りはすべお圧瞮されたデヌタブロックで、各ブロックの先頭に小さな蚘述子がありたす。



 { uint16_t decompressionInitializer; uint16_t decompressedSize; }
      
      







decompressionInitializerは垞に䞊䜍8ビットず䞋䜍8ビットに8ビット倀を栌玍するため、uint8_tにするこずができたす。 なぜそのように保存されるのかわかりたせん。 decompressedSizeはビッグ゚ンディアン倀に栌玍されたすが、これも奇劙です。 もう1぀の奇劙な点は、ナヌティリティを䜿甚しお再圧瞮した埌、MM3.CCファむルが33 Kb枛少したこずです。 たた、MM3.EXEからコンパむルされたファむル名のリストを甚意したした。これにより、解凍時に正しいファむル名が取埗されたすリストが䞍完党です-556個のファむル名のうち15個をスキップしたした。 これでほが完了です。MM3.CCファむルパッカヌ/アンパッカヌが存圚するgithubリポゞトリぞのリンクを提䟛しおいたす



github.com/rwfpl/rewolf-mm3-dumper



圧瞮はわずかな倉曎を加えお暙準のLHUFから取埗され、解凍は3日間のリバヌス゚ンゞニアリングの結果です。 スクむヌザヌずアンロヌダヌはバッファヌをチェックしないため、深刻な目的で䜿甚するこずはお勧めしたせん。 それらの䜿甚は簡単です



 x:\mm3>mm3_cc_dumper.exe Might and Magic III CC file packer/unpacker v1.0 Copyrigh (c) 2015 ReWolf http://blog.rewolf.pl Usage: Unpack: mm3_cc_dumper.exe dump input_file.cc Pack: mm3_cc_dumper.exe pack input_directory output_file.cc
      
      






All Articles