1996年のクエストのフォント分析と翻訳-私は口がなく、私は叫ぶ必要があります

すべてに良い!


Harlan Ellisonによる同名の小説に基づいゲームI Have No Mouth、I Must Screamは、これまでで最も暗いクエストの1つです。 抑圧的な雰囲気は、否定されるまで手放しません。

近い将来。 3つの超大国、アメリカ、ロシア、中国は、それぞれライバルを凌surしようと努力し、戦争を行うためのスーパーコンピューターを作成しました。 しかし、彼らは誤算しました。 単一の全体で団結し、自分自身をAMと呼び、3つのスーパーコンピューターが、人々から与えられた力を使用して、地球の表面から人類を一掃しました。 コンピューターはたった5人しか生きていません。彼らは無限の拷問のおもちゃの役目を果たします。

前回は8ビットフォントについて説明しましたが、今回は1ビットフォントを解析することができました。
どちらのタイプのフォントも暗号化も圧縮もされていないため、タスクが大幅に簡素化されています。

ツール:IDA、 dosbox +デバッガー 、winhex、 GBS

KDPV
画像

問題は、ファイルの中からフォントを見つけることです。
明らかに、FONTSのように、ファイルやフォルダーはありません;サイズが75.5 MBのscream.resリソースファイルがあります。
dosboxのフィルターでプロセスモニター(FileMonなど)を使用して、ファイルアクセス順序、オフセット、およびサイズのテーブルをコンパイルしました。
まず、GBSを使用して.resファイルを調べ、scream.resのブロックを呼び出された順序で台無しにし始めました。フォントイメージを保存する場所を見つけました。
画像


彼自身のフォントを破り、Arialからは幅と位置合わせを調整しなかったようですが、ゲームを翻訳できるという確信があり、文字コードはcp1251に対応していました。
文字を描画するために、Excelは問題なく動作します。


画像

後に彼らは素晴らしいリンクを促し、SCUMMVMの仲間がゲームを取り上げ、 マニュアルがあります

フォントは1ビットです。つまり、1ピクセルで8ピクセルを指定できます。 数バイトが行を形成します。 複数の行が高さを形成し、メモリ内のブロック(高さ*行の長さ)バイトまたは解像度の長方形(高さX(行* 8))を取得します。
視覚的にはメモリ内およびゲーム内では次のように見えます(緑と赤のストライプはバイトを示しています):
画像
画像

ゲームは小さなR3フォントとインタラクティブなR1を使用します。
各フォントの構造
ヘッダー-1286バイトで構成されます
ITE_FONTHEADER、6バイト
INT16、c_height-最大文字高さ、
INT16 c_width-最大文字幅、パラメーターは完全に不要、
INT16 row_length-フォントイメージの行の長さ(バイト単位)、

次に、256バイト、インデックスの配列、cp1251に相当するインデックス自体(Ayaaa-これらはインデックス192〜255)。
INT16インデックス[256]-文字イメージの開始バイト数。

次に、256バイト、文字幅の配列:
BYTE幅[256]-ピクセル単位の文字の幅は、0から無限までの妥当な範囲内の任意の値にできます。 まあ、255まで:)

次に、256バイトのフラグ。 一連の実験から理解した限りでは、左マージンをピクセル単位で設定します。
BYTEフラグ[256]不明な文字フラグ(0または1)

次に256バイト-描画する文字のピクセル数を追跡します。 0から無限大までの左から右へのカウントダウン。 バイトに。
バイト追跡[256]-追跡

ヘッダーに続くのは、データブロック(row_length * c_height)バイト長です。

シリーズの始まりにアクセスするための式:
font_data +(row_length * y)、
ここで、font_dataはフォントデータの先頭へのポインターで、yは行番号です。

各文字は((width [index]-1)/ 8)+ 1バイトを取ります。


このデータの後、フォーラムアーティストは、ダイアログのような美しいフォントを作成しました。 オリジナルでは、すべての種類のアイコンとウムラウトは、オリジナルとロシア語のフォントに合わせて十分なバイトを確保していました。 結局、結局、1バイトも残っていたので、それを無効にしました。 BMPからブロックをコピーするためのプログラムを作成しました。ロシア語のフォントはゲームブロック内に連続して描画されていました。
出力は、cp1251の文字、アイコン、数字、英語とロシア語の文字のセットを受け取りました。


2番目のフォントを開始しました。


ここで、妨害が起こりました。 元のブロックには、スペースが非常にわずかしかありませんでした。つまり、14の愚かな文字を提案されたセットから除外できましたが、これはロシア語の66文字には明らかに不十分でした。

最初に、ゲームが行の高さとバイトのバッファーを初期化すると考えて、行のバイト数で再生しようとしました。 次のブロックが次のフォントであることがwinhexで確認されましたが、ゲーム内のどこでも使用されていません。 ブロックをゼロにし、行の長さを増やしましたが、同じ文字セットを受け取りましたが、シフトがありました。 データバッファのサイズが別の場所に書き込まれていることが判明しました。
シリーズの長さは変更せずに、インデックスで遊んでみました。
私はどの事業にも成功せず、ごみは山に登りました。 しかし、判明したのは、リソースファイルの最後にオフセットとブロックサイズのテーブルがあることを忘れてしまったことです。それを試してみる必要があり、パッチなしですべてが機能します。

その後、DOSヘッダーを破棄してLEファイルを削除する方法がわかりにくくなりました。このファイルをIDAに入れると、32ビットLEファイルとして認識されます。 ファイルをwinhexで開き、「*** NULL assignment detected」という行を見つけ、MZに移動して、先頭をMZにカットしました。
ありがとうcracklab。

次に、別の問題が発生しました。dosboxのアドレス(180:200c61のように見える)とIDAのアドレス(cseg01:0001AC1Fのように見える)を照合してコードの実行場所を確認し、分析する方法です。 SCUMMVM Webサイトには、かなり愚かなオプションがあり、動作しますが、非常に遅いです。 IDAのコードを調べて、すぐにdosboxの力でそれをトレースできるようになるとき、私はまだIDADOSを待っています。 しかし、今のところ... IDAで、dosboxデバッガーに表示されるものの約10バイトのシーケンスを検索します。
このゲームの公式は次のとおりです。
dosboxのアドレスは1DFFFE h = IDAのアドレスです。

この時点で、フォントブロックの先頭の正確な変位とそのサイズがわかりました。 私は簡単な検索でIDAでこれらの番号を検索し始めましたが、何も見つかりませんでした。
次に、dosboxで、デバッガーは割り込みを設定して読み取りポインターを配置します(int 21h、ah = 42h、LSEEK)。 CX:DXを呼び出す前に、ポインターを移動する量の値(CX * 65536)+ DXが必要です。

何度かジャンプした後、ゲームから2つのフォントを読み取るための2つの連続した呼び出しを見つけました。使用されているものだけです。
DXには必要な数がありました。 少し巻き戻して、次のようなフォント初期化ブロックを見つけました。
mov eax、6(最終的にmov eax、3にパッチが適用されます)
InitFontを呼び出す
mov eax、8
InitFontを呼び出す

ブロック内-これは5番目と7番目のフォントです。 異なる数字で遊んだ後、ゲームで未使用のフォントがどのように見えるかを見ました。
画像
画像
画像
画像

フォントブロックのサイズを調べ、そこで最大のフォントブロックを選択し、実行可能ファイルにパッチを適用し、BMPにロシア語の文字をインポートさせました(bmp 256色の場合、1バイトは1ピクセルに等しく、バイトからビットへのキャストは2番目です)、インデックスを修正し、追跡しました、幅、行の長さ、1単位の高さの増加により、上下の文字がマージされず、最終的に最終フォントが取得されます。
保存された元の文字、数字、文字、ヨーを含む多くのロシア文字が追加されました。
画像

Source: https://habr.com/ru/post/J194988/


All Articles