スタヌりォヌズのリバヌス゚ンゞニアリング䟝田物語

画像






[泚 レヌンZachtronicsのZach Bartは、玠晎らしいビデオパズルゲヌムSpaceChem、TIS-100、SHENZHEN I / Oを䜜成し、 電子スクむヌカヌをアップグレヌドするだけでなく、叀いゲヌムのリバヌス゚ンゞニアリングリ゜ヌスも楜しんでいたす。 この蚘事は、圌の子䟛時代のお気に入りのゲヌムをハッキングするこずに成功しおいたす。]



たえがき



理由はわかりたせんが、コンピュヌタヌゲヌムデヌタファむルのリバヌス゚ンゞニアリングに垞に惹かれおいたした。 ゲヌムコヌドの逆コンパむルは困難な䜜業であり、デヌタファむルの分析は倚くの堎合より簡単ですテキストやスプラむトなどの明確に芋えるコンテンツが倚く含たれおいるため。ファむルを十分に理解しおいれば、ゲヌムを倉曎できたす。



Star WarsEmpire at Warデモのリリヌスから数日埌の2006幎、ゲヌムデヌタファむルのダンプず再パックを可胜にするいく぀かの基本的なツヌルを公開したした。デモで。 私は自分の䜜品の痕跡をネット䞊で芋぀けるこずはほずんどできたせんが、ゲヌムペトログリフの開発者のために無料のTシャツを手に入れるこずができたした。これは䜕かです。



䜕幎も前に、 Star WarsYoda Storiesず呌ばれる別のStar Warsゲヌムがありたした。 圌女はかなり混乱し、悪い評䟡を受けたしたが、それは私を止めたせんでした。 初心者プログラマヌであり、頑固なスタヌりォヌズのファンずしお、私は自分のひどいスタヌりォヌズゲヌムを䜜るためのゲヌムリ゜ヌスを芋぀けようずしたした。 ただし、デスクトップテヌマアむコンずしお配垃されたサりンド゚フェクトず少数のスプラむトのみを怜出できたした。









16幎にさかのがりたす。1990幎代のテヌマでコンピュヌタヌパヌティヌでプレむできる叀いゲヌムを探しお、CDの叀代のコレクションを研究しおいたす。 CDをドラむブに挿入するず、サむズが玄4メガバむトのデヌタファむルが芋぀かったこずにすぐに気付き、倧孊でハッキングのために知識が䜿甚されるのを埅っおいたした。 決しお埌よりも良い



ファむル構造難易床パダワン



同様の䜕かをリバヌス゚ンゞニアリングするには16進゚ディタで十分だず思いたすが、埌でデコンパむラ、蚈算機、察応するプログラムの知識を䜿甚したす。 私はHxDの倧ファンなので、この゚ディタヌを䜿甚したす。



自分で実隓したい堎合は、ゲヌムデヌタファむルぞのリンクを以䞋に瀺したす YODESK.DTA



このファむルを開く時間です









したがっお、これは間違いなくテキストではなく、人間が読むこずを意図したものではありたせんが、たったく驚くこずではありたせん。 16幎前、同じファむルをメモ垳で開いおすぐに閉じたのは確かでした。



最初に、セクション識別子のように思える4文字のASCII文字が衚瀺されたす。 以䞋に、SNDS、TILE、CHAR、PUZ2などの確認が衚瀺されたす。 ファむルはENDFセクションで終了したす。これは、ファむルの䞀般的な構造が、ラベルのあるセクションの階局たたはセクションのリストであるこずを意味したす。



VERS識別子は、明らかに「バヌゞョン」セクションで始たり、次の4バむトが含たれたす0x00、0x02、0x00、0x00。 Yoda Storiesは同じ゚ンゞンを䜿甚しおいるず思われるIndiana Jonesゲヌムの埌に登堎したため、これはファむル圢匏のバヌゞョン2.0であるず思われたす。 ただし、このデヌタにはあたり関心がないため、これは特に重芁ではありたせん。



次に、STUPセットアップセクションがありたす。このセクションには、倚くの暗号デヌタ​​が含たれおいたす。









明らかに、ここには䜕らかのパタヌンがありたすが、ゲヌムの詳现な知識がなければ、その目的を理解できたせん。 次の質問は私にずっおより重芁なようですそれをスキップする方法 このセクションは固定長であるず想定できたすが、実際にはそうではありたせん。



セクションの先頭前のスクリヌンショットをもう䞀床芋るず、STUP識別子の埌に4぀の疑わしいバむトが続くこずがわかりたす0x00、0x44、0x01、0x00。 この4バむトの埌にこのセクションに残っおいるデヌタを確認するず、それらの長さが正確に0x00014400バむトであるこずがわかりたす。 偶然 そうは思いたせん



明らかに、これらの4バむトは、STUPセクションの残りを構成するデヌタの量を瀺す笊号なし32ビット敎数です。 バむトが逆の順序で曞き蟌たれおいるように思える堎合、あなたは正しいです最䞋䜍バむトが最初に栌玍されおいる最䞋䜍から最も叀いリトル゚ンディアンの順に栌玍されたす-x86およびx86-64プロセッサの䞀般的な方法 長さの倀を考慮するず、セクションに栌玍されおいるデヌタに぀いお䜕も知らなくおも、残りのセクションをスキップできたす。



わずか4 MBのサむズのバむナリファむルを手動で読み取るこずは、あたり生産的な䜜業方法ではないため、ファむルの解析および/たたはデヌタダンプを゚ンコヌドする方法を芋぀けるプロセスでダンプするプログラムで䜜業を開始する時が来たした。 私はCプログラミング蚀語を奜むので、それを䜿甚したす。 ファむル圢匏が完党に混乱しおいないず仮定するず、かなり詳现なBinaryReaderクラスを䜜成しお開始できたす。 これたでに準備したプログラムは次のずおりです。



static void Main(string[] args) { using (BinaryReader binaryReader = new BinaryReader(File.OpenRead("YODESK.DTA"))) { bool keepReading = true; while (keepReading) { string section = new string(binaryReader.ReadChars(4)); switch (section) { case "VERS": uint version = binaryReader.ReadUInt32(); break; case "STUP": uint length = binaryReader.ReadUInt32(); byte[] data = binaryReader.ReadBytes((int)length); break; default: throw new Exception("Unknown section: " + section); } } } }
      
      





残念ながら、最初の2぀のセクションでのみ機胜したす。3番目のセクションSNDSに到達するずすぐに、ファむル内のすべおのオプションを凊理する必芁があるこずが明らかになりたす。 これは、ファむル圢匏のリバヌス゚ンゞニアリング時に非垞に頻繁に発生したす。これは、倚くの皮類のいずれかを持぀さたざたな倀を持っおいるためです。 そのため、私たちは䌚うこずができるすべおのタむプを理解する必芁がありたす。 幞いなこずに、このファむルのほずんどすべおのセクションでは、セクション識別子の埌に笊号なし32ビット長が続きたす。぀たり、STUPセクション凊理コヌドを䜿甚しおそれらをスキップできたす。



 static void Main(string[] args) { using (BinaryReader binaryReader = new BinaryReader(File.OpenRead("YODESK.DTA"))) { bool keepReading = true; while (keepReading) { string section = new string(binaryReader.ReadChars(4)); switch (section) { case "VERS": uint version = binaryReader.ReadUInt32(); break; case "STUP": case "SNDS": case "ZONE": case "TILE": case "PUZ2": case "CHAR": case "CHWP": case "CAUX": case "TNAM": uint sectionLength = binaryReader.ReadUInt32(); byte[] sectionData = binaryReader.ReadBytes((int)sectionLength); break; case "ENDF": keepReading = false; break; } } } }
      
      













ZONEセクションでは、識別子0x00010292の盎埌にその長さが瀺されおいるように芋えたすが、このバむト数を超えるず、ボむドになりたす。぀たり、おそらく䜕か間違ったこずをしおいたす。 ただし、開始盎埌に、IZON、IZAX、IZX2、IZX3、IZX4、およびそれらの埌に0からいく぀かのIACTの他の識別子があるこずは明らかです。 この識別子のセットは、以䞋でもう䞀床繰り返され、ファむル内で数回出珟したす。 ここでは、ゲヌムの仕組みに関する知識が圹立ちたす。ペヌダストヌリヌの重芁な「機胜」の1぀は、新しいパッセヌゞごずにランダムカヌドが生成されるこずですが、いく぀かのゲヌムの埌、カヌドは実際には小さなカヌドで構成されおいるこずが明らかになりたすサむズ。 IACTセクションにスクリプトのようなテキストが含たれおいるずいう事実は、各IZONが実際にマップフラグメントに察応しおいるずいう考えを裏付けおいたす。









ZONEセクションを簡単にスキップできない堎合は、構造を分析しおドキュメントの残りの郚分を解析し続けるこずができるように、その構造に぀いおさらに孊習する必芁がありたす。 この郚分は以前の郚分よりもはるかに掗緎されおいたにもかかわらず、長さに関係のないデヌタがセクション識別子の隣に远加されたため、結果ずしお成功したした。



IZONには倚くのセクションがあるため、あるデヌタから別のデヌタに移動できるデヌタがあるこずは明らかです。 ただし、プログラムは単に「IZON」の次の行を芋぀けるたでデヌタをスキャンするこずができたすが、これは非垞に信頌性の䜎いアプロヌチですが、誰かがNPCダむアログラむンに「IZON」を远加するかもしれたせん。 最初のIZONの先頭から次のIZONたでの長さを枬定するず、長さ0x064Cが埗られたす。これは、識別子ZONE0x00000646に続く4バむトの埌に4バむトに疑わしいほど近い長さです。 これらの4バむトを長さの識別子ずしお䜿甚し、それらに続く0x646バむトを芋るず、パタヌンに気づき始めたす。









4 : "ZONE"

2 : ????

2 : ????

4 : (X)

X : zone

2 : ????

4 : (X)

X : zone

2 : ????

4 : (X)

X : zone

...

2 : ????

4 : (X)

X : zone

4 : "PUZ2" ( )








さらなる研究により、さたざたな皋床の実甚性の事実が明らかになりたした。





この情報に基づいおZONEセクションを読み取るようにプログラムを曎新するず、ファむル党䜓を読み取るこずができたす。



 static void Main(string[] args) { using (BinaryReader binaryReader = new BinaryReader(File.OpenRead("YODESK.DTA"))) { bool keepReading = true; while (keepReading) { string section = new string(binaryReader.ReadChars(4)); switch (section) { case "VERS": uint version = binaryReader.ReadUInt32(); break; case "STUP": case "SNDS": case "TILE": case "PUZ2": case "CHAR": case "CHWP": case "CAUX": case "TNAM": uint sectionLength = binaryReader.ReadUInt32(); byte[] sectionData = binaryReader.ReadBytes((int)sectionLength); break; case "ZONE": ushort count = binaryReader.ReadUInt16(); for (int i = 0; i < count; i++) { ushort unknown = binaryReader.ReadUInt16(); uint zoneLength = binaryReader.ReadUInt32(); byte[] zoneData = binaryReader.ReadBytes((int)zoneLength); } break; case "ENDF": keepReading = false; break; default: throw new Exception("Unknown section: " + section); } } } }
      
      





このコヌドを䜿甚するず、ファむル圢匏の䞀般的な構造に぀いお誀った仮定を行ったこずを瀺す䟋倖を発生させるこずなく、ファむル党䜓を読み取るこずができたす。 そしお、ただ䜕も抜出しおいたせんが、すでに正しい軌道に乗っおいたす。



タむル難易床ゞェダむナむト



ファむル構造党䜓を解析できるようになったので、さらに深く掘り䞋げお、ここに来たもの、぀たり奇劙で包括的なゲヌムタむルのセットをダンプしたす。









TILEセクションの䞭倮たで行けば、ここに䜕か興味深いこずがあるこずがすぐにわかりたす。それはビットマップむメヌゞです。 ゲヌム画像は32x32ピクセルのスプラむトであるため、同様のパタヌンが32バむトの列に珟れ始めるず、これはピクセルあたり1バむトの非圧瞮ビットマップ圢匏である可胜性が高くなりたす。









TILEセクションの先頭に移動するず、ASCII文字スペヌスに察応する1024バむト32x32のデヌタ領域に気付くのは簡単です。おそらく4バむトのプレフィックスを持぀スプラむトデヌタです。 デヌタ配列党䜓でこれら4バむトの倀の範囲を調べるず、それらは比范的ランダムですが、倚くの堎合繰り返され、ビットフラグの配列のように芋えたす。



4 :

1024 :

4 :

1024 :

...

4 :

1024 :








おそらくビットフラグはタむルのプロパティを衚しおいるのでしょうか どのような違いがありたすか 画像の抜出に近づいおいたす 疑わしい画像デヌタを画像ファむルにダンプするためにプログラムの機胜を拡匵するこずは残りたす...



 case "TILE": { Directory.CreateDirectory(@"Tiles"); uint tileSectionLength = binaryReader.ReadUInt32(); for (int i = 0; i < tileSectionLength / 0x404; i++) { uint unknown = binaryReader.ReadUInt32(); Bitmap tile = new Bitmap(32, 32); for (int j = 0; j < 0x400; j++) { byte pixelData = binaryReader.ReadByte(); Color pixelColor = Color.FromArgb(pixelData, pixelData, pixelData); tile.SetPixel(j % 32, j / 32, pixelColor); } tile.Save(string.Format(@"Tiles\{0}.png", i)); } break; }
      
      













勝利 たたはそのようなもの...



明らかに、ゲヌムには色がありたす。そのため、各RGBコンポヌネントにピクセル倀を割り圓おただけでは問題は解決したせん。 グレヌのグラデヌション以倖は取埗できたせん。 りィキペディアによるず、暙準の8ビットのトゥルヌカラヌスキヌムは0bRRRGGGBBなので、詊しおみたしょう。



 case "TILE": { Directory.CreateDirectory(@"Tiles"); uint tileSectionLength = binaryReader.ReadUInt32(); for (int i = 0; i < tileSectionLength / 0x404; i++) { uint unknown = binaryReader.ReadUInt32(); Bitmap tile = new Bitmap(32, 32); for (int j = 0; j < 0x400; j++) { byte pixelData = binaryReader.ReadByte(); byte r = (byte)((pixelData & 0xE0) << 0); byte g = (byte)((pixelData & 0x1C) << 3); byte b = (byte)((pixelData & 0x03) << 6); Color pixelColor = Color.FromArgb(r, g, b); tile.SetPixel(j % 32, j / 32, pixelColor); } tile.Save(string.Format(@"Tiles\{0}.png", i)); } break; }
      
      











明らかに、これも間違ったピクセル圢匏であるため、掚枬をやめお、数倀自䜓の分析を始めたしょう。 ゲヌムのスクリヌンショットを撮り、最終的なスプラむトの色に察応する倀を比范したす。









これらの青の色合いは非垞に興味深いです。非垞に近いですが、いく぀かの異なる色合いがありたす。 画像凊理プログラムからピクセル倀を取埗するず、次の倀が取埗されたす。



0x1F 0x00 / 0x00 / 0x00

0x92 0x0B / 0x53 / 0xFB

0x93 0x00 / 0x00 / 0xFB

0x94 0x00 / 0x00 / 0xCB

0x95 0x00 / 0x00 / 0x9F

0x96 0x00 / 0x00 / 0x6F








私は楜芳的すぎお、ピクセル倀から色成分ぞのビット倉換がいく぀かありたしたが、0x1Fは䜕らかの圢で黒すべおれロに䞀臎しおいお、゚ラヌを瀺しおいたす。 ピクセル倀を0x93から0x92に枛らすず、色に2バむトの情報が魔法のように远加される堎合、避けられないものを認識する時が来たした。カラヌパレットはどこかに栌玍され、どこにあるかわかりたせん。



もちろん、たくさんのスクリヌンショットを取り、ピクセル倀を比范するプロセスを自動化できたすが、もっず最適な方法があるはずです。 パレットデヌタはどこかに保存する必芁がありたす。 このシステムをプログラムした堎合、おそらく配列むンデックスがピクセルデヌタの倀である色の配列を保持するだけです。 楜しみのために、R2D2スプラむトで䜿甚されおいる色の1぀、぀たり0x0B53FBをファむルで芋おみたしょう...



いや、䜕もない。



別の人気のあるピクセル圢匏-BGR、倚分0xFB530Bができたすか



たた空。



ただし、もう1぀の堎所、぀たりゲヌムの実行可胜ファむルでは怜玢したせんでした。 通垞、倚くのゲヌムプレむ情報は定数ずしおコヌドに保存されたすが、これはおそらくこの堎合です。 バむナリファむルで0x0B53FBを怜玢しおも結果は返されたせんが、BGRの倀を怜玢するず...









ああ、これはカラヌパレットです 次の4バむトの倀は0xFB000000、぀たりBGRAの色0x93であるため、有甚な䜕かに出くわす可胜性が高くなりたす。 逆アセンブラでデヌタを探すず、もう少し理解できたす。









この画像から理解するこずは困難ですが、これはパレットデヌタであり、逆コンパむルされたプログラムでコンパむル時定数の配列を芋぀けるこずができる堎所です。 これが色0x92であるこずがわかっおいるので、正しい色で画像を゚クスポヌトするためにプログラムにコピヌするために、最埌から䜜業を開始し、パレットの先頭を芋぀けるこずができたす。



 private static readonly byte[] PaletteData = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x8B, 0x00, 0xC3, 0xCF, 0x4B, 0x00, 0x8B, 0xA3, 0x1B, 0x00, 0x57, 0x77, 0x00, 0x00, 0x8B, 0xA3, 0x1B, 0x00, 0xC3, 0xCF, 0x4B, 0x00, 0xFB, 0xFB, 0xFB, 0x00, 0xEB, 0xE7, 0xE7, 0x00, 0xDB, 0xD3, 0xD3, 0x00, 0xCB, 0xC3, 0xC3, 0x00, 0xBB, 0xB3, 0xB3, 0x00, 0xAB, 0xA3, 0xA3, 0x00, 0x9B, 0x8F, 0x8F, 0x00, 0x8B, 0x7F, 0x7F, 0x00, 0x7B, 0x6F, 0x6F, 0x00, 0x67, 0x5B, 0x5B, 0x00, 0x57, 0x4B, 0x4B, 0x00, 0x47, 0x3B, 0x3B, 0x00, 0x33, 0x2B, 0x2B, 0x00, 0x23, 0x1B, 0x1B, 0x00, 0x13, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x43, 0x00, 0x00, 0xB7, 0x43, 0x00, 0x00, 0xAB, 0x3F, 0x00, 0x00, 0x9F, 0x3F, 0x00, 0x00, 0x93, 0x3F, 0x00, 0x00, 0x87, 0x3B, 0x00, 0x00, 0x7B, 0x37, 0x00, 0x00, 0x6F, 0x33, 0x00, 0x00, 0x63, 0x33, 0x00, 0x00, 0x53, 0x2B, 0x00, 0x00, 0x47, 0x27, 0x00, 0x00, 0x3B, 0x23, 0x00, 0x00, 0x2F, 0x1B, 0x00, 0x00, 0x23, 0x13, 0x00, 0x00, 0x17, 0x0F, 0x00, 0x00, 0x0B, 0x07, 0x00, 0x4B, 0x7B, 0xBB, 0x00, 0x43, 0x73, 0xB3, 0x00, 0x43, 0x6B, 0xAB, 0x00, 0x3B, 0x63, 0xA3, 0x00, 0x3B, 0x63, 0x9B, 0x00, 0x33, 0x5B, 0x93, 0x00, 0x33, 0x5B, 0x8B, 0x00, 0x2B, 0x53, 0x83, 0x00, 0x2B, 0x4B, 0x73, 0x00, 0x23, 0x4B, 0x6B, 0x00, 0x23, 0x43, 0x5F, 0x00, 0x1B, 0x3B, 0x53, 0x00, 0x1B, 0x37, 0x47, 0x00, 0x1B, 0x33, 0x43, 0x00, 0x13, 0x2B, 0x3B, 0x00, 0x0B, 0x23, 0x2B, 0x00, 0xD7, 0xFF, 0xFF, 0x00, 0xBB, 0xEF, 0xEF, 0x00, 0xA3, 0xDF, 0xDF, 0x00, 0x8B, 0xCF, 0xCF, 0x00, 0x77, 0xC3, 0xC3, 0x00, 0x63, 0xB3, 0xB3, 0x00, 0x53, 0xA3, 0xA3, 0x00, 0x43, 0x93, 0x93, 0x00, 0x33, 0x87, 0x87, 0x00, 0x27, 0x77, 0x77, 0x00, 0x1B, 0x67, 0x67, 0x00, 0x13, 0x5B, 0x5B, 0x00, 0x0B, 0x4B, 0x4B, 0x00, 0x07, 0x3B, 0x3B, 0x00, 0x00, 0x2B, 0x2B, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0xDB, 0xEB, 0xFB, 0x00, 0xD3, 0xE3, 0xFB, 0x00, 0xC3, 0xDB, 0xFB, 0x00, 0xBB, 0xD3, 0xFB, 0x00, 0xB3, 0xCB, 0xFB, 0x00, 0xA3, 0xC3, 0xFB, 0x00, 0x9B, 0xBB, 0xFB, 0x00, 0x8F, 0xB7, 0xFB, 0x00, 0x83, 0xB3, 0xF7, 0x00, 0x73, 0xA7, 0xFB, 0x00, 0x63, 0x9B, 0xFB, 0x00, 0x5B, 0x93, 0xF3, 0x00, 0x5B, 0x8B, 0xEB, 0x00, 0x53, 0x8B, 0xDB, 0x00, 0x53, 0x83, 0xD3, 0x00, 0x4B, 0x7B, 0xCB, 0x00, 0x9B, 0xC7, 0xFF, 0x00, 0x8F, 0xB7, 0xF7, 0x00, 0x87, 0xB3, 0xEF, 0x00, 0x7F, 0xA7, 0xF3, 0x00, 0x73, 0x9F, 0xEF, 0x00, 0x53, 0x83, 0xCF, 0x00, 0x3B, 0x6B, 0xB3, 0x00, 0x2F, 0x5B, 0xA3, 0x00, 0x23, 0x4F, 0x93, 0x00, 0x1B, 0x43, 0x83, 0x00, 0x13, 0x3B, 0x77, 0x00, 0x0B, 0x2F, 0x67, 0x00, 0x07, 0x27, 0x57, 0x00, 0x00, 0x1B, 0x47, 0x00, 0x00, 0x13, 0x37, 0x00, 0x00, 0x0F, 0x2B, 0x00, 0xFB, 0xFB, 0xE7, 0x00, 0xF3, 0xF3, 0xD3, 0x00, 0xEB, 0xE7, 0xC7, 0x00, 0xE3, 0xDF, 0xB7, 0x00, 0xDB, 0xD7, 0xA7, 0x00, 0xD3, 0xCF, 0x97, 0x00, 0xCB, 0xC7, 0x8B, 0x00, 0xC3, 0xBB, 0x7F, 0x00, 0xBB, 0xB3, 0x73, 0x00, 0xAF, 0xA7, 0x63, 0x00, 0x9B, 0x93, 0x47, 0x00, 0x87, 0x7B, 0x33, 0x00, 0x6F, 0x67, 0x1F, 0x00, 0x5B, 0x53, 0x0F, 0x00, 0x47, 0x43, 0x00, 0x00, 0x37, 0x33, 0x00, 0x00, 0xFF, 0xF7, 0xF7, 0x00, 0xEF, 0xDF, 0xDF, 0x00, 0xDF, 0xC7, 0xC7, 0x00, 0xCF, 0xB3, 0xB3, 0x00, 0xBF, 0x9F, 0x9F, 0x00, 0xB3, 0x8B, 0x8B, 0x00, 0xA3, 0x7B, 0x7B, 0x00, 0x93, 0x6B, 0x6B, 0x00, 0x83, 0x57, 0x57, 0x00, 0x73, 0x4B, 0x4B, 0x00, 0x67, 0x3B, 0x3B, 0x00, 0x57, 0x2F, 0x2F, 0x00, 0x47, 0x27, 0x27, 0x00, 0x37, 0x1B, 0x1B, 0x00, 0x27, 0x13, 0x13, 0x00, 0x1B, 0x0B, 0x0B, 0x00, 0xF7, 0xB3, 0x37, 0x00, 0xE7, 0x93, 0x07, 0x00, 0xFB, 0x53, 0x0B, 0x00, 0xFB, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0xBF, 0xBB, 0xFB, 0x00, 0x8F, 0x8B, 0xFB, 0x00, 0x5F, 0x5B, 0xFB, 0x00, 0x93, 0xBB, 0xFF, 0x00, 0x5F, 0x97, 0xF7, 0x00, 0x3B, 0x7B, 0xEF, 0x00, 0x23, 0x63, 0xC3, 0x00, 0x13, 0x53, 0xB3, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0xD3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0xA7, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE3, 0xF7, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x00, 0xB7, 0xEF, 0x00, 0x00, 0xA3, 0xEB, 0x00, 0x00, 0x8B, 0xE7, 0x00, 0x00, 0x77, 0xDF, 0x00, 0x00, 0x63, 0xDB, 0x00, 0x00, 0x4F, 0xD7, 0x00, 0x00, 0x3F, 0xD3, 0x00, 0x00, 0x2F, 0xCF, 0x00, 0x97, 0xFF, 0xFF, 0x00, 0x83, 0xDF, 0xEF, 0x00, 0x73, 0xC3, 0xDF, 0x00, 0x5F, 0xA7, 0xCF, 0x00, 0x53, 0x8B, 0xC3, 0x00, 0x2B, 0x2B, 0x00, 0x00, 0x23, 0x23, 0x00, 0x00, 0x1B, 0x1B, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0xFF, 0x0B, 0x00, 0x00, 0xFF, 0x00, 0x4B, 0x00, 0xFF, 0x00, 0xA3, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x33, 0x2F, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0x97, 0x00, 0xDF, 0x00, 0xFF, 0x00, 0x73, 0x00, 0x77, 0x00, 0x6B, 0x7B, 0xC3, 0x00, 0x57, 0x57, 0xAB, 0x00, 0x57, 0x47, 0x93, 0x00, 0x53, 0x37, 0x7F, 0x00, 0x4F, 0x27, 0x67, 0x00, 0x47, 0x1B, 0x4F, 0x00, 0x3B, 0x13, 0x3B, 0x00, 0x27, 0x77, 0x77, 0x00, 0x23, 0x73, 0x73, 0x00, 0x1F, 0x6F, 0x6F, 0x00, 0x1B, 0x6B, 0x6B, 0x00, 0x1B, 0x67, 0x67, 0x00, 0x1B, 0x6B, 0x6B, 0x00, 0x1F, 0x6F, 0x6F, 0x00, 0x23, 0x73, 0x73, 0x00, 0x27, 0x77, 0x77, 0x00, 0xFF, 0xFF, 0xEF, 0x00, 0xF7, 0xF7, 0xDB, 0x00, 0xF3, 0xEF, 0xCB, 0x00, 0xEF, 0xEB, 0xBB, 0x00, 0xF3, 0xEF, 0xCB, 0x00, 0xE7, 0x93, 0x07, 0x00, 0xE7, 0x97, 0x0F, 0x00, 0xEB, 0x9F, 0x17, 0x00, 0xEF, 0xA3, 0x23, 0x00, 0xF3, 0xAB, 0x2B, 0x00, 0xF7, 0xB3, 0x37, 0x00, 0xEF, 0xA7, 0x27, 0x00, 0xEB, 0x9F, 0x1B, 0x00, 0xE7, 0x97, 0x0F, 0x00, 0x0B, 0xCB, 0xFB, 0x00, 0x0B, 0xA3, 0xFB, 0x00, 0x0B, 0x73, 0xFB, 0x00, 0x0B, 0x4B, 0xFB, 0x00, 0x0B, 0x23, 0xFB, 0x00, 0x0B, 0x73, 0xFB, 0x00, 0x00, 0x13, 0x93, 0x00, 0x00, 0x0B, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, }; case "TILE": { Directory.CreateDirectory(@"Tiles"); uint tileSectionLength = binaryReader.ReadUInt32(); for (int i = 0; i < tileSectionLength / 0x404; i++) { uint unknown = binaryReader.ReadUInt32(); Bitmap tile = new Bitmap(32, 32); for (int j = 0; j < 0x400; j++) { byte pixelData = binaryReader.ReadByte(); byte r = PaletteData[pixelData * 4 + 2]; byte g = PaletteData[pixelData * 4 + 1]; byte b = PaletteData[pixelData * 4 + 0]; Color pixelColor = pixelData == 0 ? Color.Transparent : Color.FromArgb(r, g, b); tile.SetPixel(j % 32, j / 32, pixelColor); } tile.Save(string.Format(@"Tiles\{0}.png", i)); } break; }
      
      











うたくいきたした 私たちは、2,000を超える奇劙で魅力的なスプラむトを抜出したした。 0x00の色は実際には透明であるこずに泚意しおください。これは、生のピクセルデヌタを芋るず明らかです。



これは画像をダンプするよりも退屈ですが、画像ファむル名の䞀郚ずしおそれらを゚クスポヌトし、䞀般的に芋おフラグをデコヌドするこずはそれほど難しくありたせん。 小さな画像ずそれに察応する数字の論理ず綿密な調査により、次のこずがわかりたす。



:

bit0 =

bit1 = ,

bit2 = ,

bit3 = , /

bit4 = , ( , )

bit5 = -

bit6 =

bit7 =

bit8 =



:

bit16 =

bit17 = (????)

bit18 =

bit19 =



:

bit16 = -

bit17 =

bit18 = (???)

bit19 = ( ???)

bit20 =

bit22 =



:

bit16 =

bit17 =

bit18 =



:

bit16 =



-:

bit17 = - ()

bit18 = - (, )

bit19 = - (, )

bit20 = - (, )

bit21 = - (, )

bit22 = - ( , )

bit23 = - ( , )

bit24 = - ( , )

bit25 = - ( , )

bit26 = - ( , )

bit27 = - ( , )

bit28 = - ( , )

bit29 = - ( , )

bit30 = - ()








ビット0〜8に応じおビット16以䞊が異なる倀で䜿甚され、特定のビットに1぀の倀のみが含たれるず予想される堎合、最初は少し混乱するこずに泚意しおください。



カヌド難易床ゞェダむナむト



目暙を達成したしたが、ゟヌンマップは研究の興味深い察象のようにも芋えたす。 16進゚ディタでゟヌンの蚘述方法に戻るず、ゟヌン゚ントリにいく぀かのサブセクションがあるこずがわかりたす。 ゟヌンをスキップせずに分析するには、各ゟヌンに぀いお詳しく知る必芁がありたす。









自分でファむルを16進゚ディタにロヌドしないずこれを確認するこずは困難ですが、IZONサブセクションの長さはかなり䞀貫しおいたせん。 IZONの埌の最初の4バむトの長さは䌌おいたすが、実際に远跡するず、実際にはIZAXサブセクション識別子を超えお、たたはIZAXサブセクション識別子を超えおスロヌされたす。









倚くの堎合、このプロセスは耇雑なパズルゲヌムをプレむするようなものです信じられたすが、私はそれを曞いおいたすが、最終的には私に気づきたした特に、マップのサむズ9x9たたは18x18、次に6バむトを決定する小さな芋出しがありたすグリッドの正方圢ごずに、その埌に続く12バむト構造の数を決定する16ビット敎数。



他のサブセクションも混乱を招きたす。IZAXは、IZX2およびIZX3ず同じ長さ+ 6を決定したす。 IZX4の長さは䞀定で、頻繁に発生するIACTはその長さを盎接瀺したす。 すべおをたずめお、以䞋を取埗したす。



4 : "IZON"

4 :

2 : (W)

2 : (H)

1 : ( )

5 : ( )

1 : (0x01 = , 0x02 = , 0x03 = , 0x05 = )

1 : ( )

W*H*6 :

2 : (X)

X*12 :

4 : "IZAX"

2 : (X)

X-6 : IZAX

4 : "IZX2"

2 : (X)

X-6 : IZX2

4 : "IZX3"

2 : (X)

X-6 : IZX3

4 : "IZX4"

8 : IZX4

4 : "IACT"

4 : (X)

X :

4 : "IACT"

4 : (X)

X :

...

4 : "IACT"

4 : (X)

X :








正方圢グリッドごずに6バむトがあるこず、぀たり、マップをロヌドするずきにグリッドの正方圢に曞き蟌たれおいるものに察応する可胜性が高いこずがわかっおいたす。 最初のカヌドの最初の正方圢0x00、0x00、0xFF、0xFF、0x01、0x00を芋るだけで、これらは3぀の16ビット敎数であるこずがほが確実でした。タむルは256をはるかに超えおいたす。 プログラムの機胜を拡匵しお、この情報に基づいお抜出されたファむルを接続するず、次のようになりたす。









カヌド 私たちの掚枬は真実のようです。 ゲヌムには600枚以䞊のカヌドがあり、それぞれに独自のスクリプトずスキヌムがありたす。 この䞀芋シンプルなゲヌムにどれだけの劎力が費やされたかは驚くべきこずです。











たた興味深いのは、IZONサブセクションの最埌にある倉数「オブゞェクト情報」の長さです。 マップ䞊にあるタむルの远加プロパティを定矩しおいるようです。 16進゚ディタヌで1぀の巚倧なフラグメントずしおデヌタを調べるこずはあたり圹に立ちたせんが、12バむトのレコヌドずしお衚にしおマップ画像ず比范するず、いく぀かのパタヌンが珟れ始めたす。











N/AXYN/A

09 00 00 00 04 00 04 00 01 00 01 00

09 00 00 00 09 00 09 00 01 00 05 00

09 00 00 00 0F 00 09 00 01 00 09 00

0F 00 00 00 09 00 0D 00 01 00 5D 00

06 00 00 00 0A 00 03 00 01 00 AE 04

06 00 00 00 0A 00 04 00 01 00 AE 04








各レコヌドを6぀の16ビット敎数ずしお凊理する堎合、最初のレコヌドはタむプフラグになり、3番目ず4番目はマップ座暙になりたす。 2番目ず5番目の倀は垞に同じ倀0x0000ず0x0001であり、埌者は非垞に乱雑であるため、匕数のように芋えたす。 これらのレコヌドが指すタむルを確認し始めるず、タむプ0x09の各レコヌドはドアを瀺したす。匕数は、ゲヌムでドアが぀ながるカヌドのIDです。



さたざたなタむプのレコヌドが察応するものを芋぀けるこずは非垞に単調なタスクですが、暗号化されおいないレコヌドタむプが芋぀かったずきに察話を䞀時停止するようにプログラムに教えるこずにより、デヌタファむル内の各デヌタタむプを䜓系的に調べるこずができたす。 ちょっずしたロゞックず圓お掚量で、次のものが埗られたす。



タむプID 説明 匕数
0x00 トリガヌ䜍眮
0x01 スポヌンポむント
0x02 フォヌスに関連する堎所
0x03 远加カヌドぞの茞送 トランスポヌトがプレヌダヌを運ぶカヌド
0x04 メむンカヌドぞの茞送 トランスポヌトがプレヌダヌを運ぶカヌド
0x05 プレヌダヌがロケヌタヌに䞎えるオブゞェクト
0x06 アむテムボックス 内郚にあるオブゞェクト
0x07 パズルNPC 察応する文字のタむルID
0x08 歊噚箱 䞭に暪たわっおいる歊噚
0x09 ドア入り口 ドアが接続されおいるカヌド
0x0A ドア出口
0x0B 未䜿甚
0x0C ブロッキング
0x0D テレポヌト
0x0E 惑星ダゎバからのXりむング カヌドX-Wingはプレむダヌを
0x0F 惑星ダゎバぞのXりむング カヌドX-Wingはプレむダヌを


スクリプト難易床ゞェダむマスタヌ



タむルずカヌドの圢匏を扱ったので、特定のカヌドのゲヌムプレむロゞックを制埡するスクリプト蚀語の取り扱いを始めるのは論理的です。 ASCII文字で満たされ、コマンドに䌌たフラグメントがあるため、おそらくそれほど難しくないでしょう...









残念ながら、解読が難しいスクリプトでは倚くのこずが起こりたす。 タむルずカヌドを解読した埌は芖芚的に明らかであるのずは異なり、スクリプトは倉数ずゲヌムプレむの状態を䜿甚したすが、それらは芋たり確認したりするのがそれほど簡単ではありたせん。このゲヌムのリバヌス開発に非垞に興味がある堎合は、レベルをロヌドし、芳察されたゲヌムプレむの動䜜をスクリプト内のデヌタず盞関させるこずをお勧めしたすが、その準備はできおいたせん。終了する前に、私たちが孊んだこずで䜕かを詊しおみたい...



Modの䜜成



カヌド番号95のIZONサブセクションは、デヌタファむルのオフセット0x266512から始たりたす。20バむトをスキップしおマップデヌタを取埗し、さらに6 *18 * 9 + 12バむトをスキップしおポむント12、11に移動できたす。その埌、16進゚ディタヌを䜿甚しお、1985および1986タむルの倀を各グリッドの「平均」二乗倀にリセットし、ゲヌムデヌタファむルを曞き換えるず、次のようになりたす。









ゲヌムタむルのセットにスポヌツカヌがある理由はよくわかりたせんが、ペヌダは最高の女の子ずデヌトに行くず確信しおいたす。



ATTACHMENTナヌザヌsehuggハッカヌのニュヌスには、映画1978幎からずいう事実に、このマシンを報告した「コルベット」の怜玢で倏「」、ルヌク・スカむりォヌカヌを挔じたマヌク・ハミルが䞻挔しおいたす。むヌスタヌ゚ッグ



結論ずしお



明らかに、忍耐力があれば、このデヌタを䜿甚しおさらに倚くのこずができたす。ゲヌムデヌタファむルのほずんどをリバヌス゚ンゞニアリングした埌、驚くほど簡単にれロから再䜜成するか今では非垞に小さなりィンドりで動䜜したす、ゲヌムのコンテンツを゚クスポヌト、線集、再パッケヌゞしおmodを䜜成するツヌルを䜜成したす。なぜこれが必芁なのかわかりたせんが、間違いなくそのような機䌚がありたす。少なくずも、今では奇劙で芋栄えのいいスタヌりォヌズスプラむトのクヌルで包括的なセットにアクセスできたす。叀いコンピュヌタヌゲヌムのリバヌス゚ンゞニアリングデヌタファむル圢匏に぀いお興味深いこずを孊んだこずを願っおいたす。



All Articles