ごちゃペディア

はなまるデジタル創作紀行(DTM、TAS、いろいろな技術)

プロセスメモリエディタ「MHS」を利用したメモリ監視・操作

MHSはいわゆるプロセスメモリエディタと呼ばれるもので、ゲームの見えないパラメータを表示させたり、値を書き換えたりすることができます。類似のツールはほかにもありますが、TAS界隈ではよくこのMHSが利用されます*1

日本では同様のツールとして、うさみみハリケーンなどが知られています。噂に聞くところでは検索機能はこちらの方が高度とも聞きますし、可能であれば他のプロセスメモリエディタ、デバッガと組み合わせて利用すると、できることの幅は広がるでしょう。個人的にはMHSの基本のシンプルさがとても好きです。

それでは、導入から簡単な利用までを見てみましょう。

ダウンロードとインストール

MHS Download Page から MHS6.1.rar をダウンロードして展開するだけです。


起動〜対象プロセス選択

メモリ監視対象のプログラム(ゲーム)を起動した状態で MHS.exe を起動します。初回起動時には下記のダイアログが表示されます。

Would you like to personalize this software?
Doing this can allow you to avoid detection by anti-cheat software.


If you do not want to do this now, you can always do it later from the Tools/Modify Self menu. (はい/いいえ)

不正防止つきソフトウェアへの対策として、MHSを改変しますか?」というような内容です。TAS目的の方にはまず不要ですし、Tools/Modify Self メニューから後で改変を実施することもできますので、ここでは「いいえ」を選択して次へ進みます。

メインウィンドウが表示されたら、メニューから File → Open Process を開きます。

現在起動中のプロセスを一覧表示したダイアログが開くので、タイトルや実行ファイル名を参考に、メモリ監視対象のプロセスを選択して、OKを押してください。

これで、MHS でメモリにアクセスする準備ができました。

メモリアドレスを検索する

メモリアドレスを検索するには、Found Addresses ウィンドウにある、虫眼鏡(単一)アイコンのボタンをクリックします(あるいはメニューから Search → Data-Type Search を選択)。

すると、検索のための Data-Type Search ダイアログが表示されます。

まずは、Search グループで基本的な検索条件を指定します。選択肢の意味は下記の表のとおりです。

Data Type バイト数 値の型・範囲
Byte 1 0〜255 の整数
Char 1 -128〜-127 の整数
Short 2 -32768〜-32767 の整数
Unsigned Short 2 0〜65535 の整数
Long 4 -2147483648〜-2147483647 の整数
Unsigned Long 4 0〜4294967295 の整数
64-bit Integer 8 -9223372036854775808〜9223372036854775807 の整数
Unsigned 64-bit Integer 8 0〜18446744073709551615 の整数
Float 4 実数 (単精度浮動小数点数)
Double 8 実数 (倍精度浮動小数点数)
Evalutation Type 説明
Exact Value Value to Find に一致する値を検索する。
Not Equal To Value to Find に一致しない値を検索する。
Range From より大きく、To より小さい値を検索する。
Greater Than Find Values Greater Than よりも大きい値を検索する。
Lower Than Find Values Lower Than よりも小さい値を検索する。
Unknown (不明。指定した型に合う全候補を表示?)

その他の主なポイントは以下のとおりです。

  • デフォルトではマップされたメモリが検索対象に含まれない(エミュレータのメモリアドレスが見つけられない可能性がある)ので、Options の General Search Options から設定画面を開いて、General Search タブで MEM_MAPPED を検索対象とするよう、チェックを付けるとよいかもしれません(ただし検索速度は遅くなります)。
  • Search Range は検索対象とするメモリアドレスの範囲です。おおよそ変更する必要はありません。

OKボタンを押して検索を行うと、Found Addresses の一覧に結果が表示されます。

多くの場合、ここから絞り込み検索を必要とします。Found Addresses ウィンドウにある、虫眼鏡(複数)アイコンのボタンをクリックします(あるいはメニューから Search → Sub Search を選択)。

すると Sub Search ダイアログが表示されます。使い方は先ほどのダイアログと同じなので割愛します。

探しているメモリアドレスが見つかったら、項目を右クリックして Add Selected を選択します。

メインウィンドウで特定のメモリアドレスの値を見ることができるようになりました。


おまけ:ポインタの検索

特定のアドレス領域を指しているポインタを検索する機能があります。メニューから Search → Pointer Search をクリックすると、下図のダイアログが表示されます。

動的に変化するアドレスを追いたいときには、ポインタの検索が必要になります。これを知らなくても MHS は使えますが、使い方が想像できる人は知っているとお得です。

ウォッチの編集、改造コード機能の利用

メインウィンドウにあるメモリアドレス一覧の項目をダブルクリックすると、Modify Address ダイアログが開きます。


  • Description を編集して、説明文を変更できます。
  • Type を変更すると、値のサイズ・型が変更できます。
  • Show as Hex にチェックを入れると、値を16進数で表示できます。

また、Locked のチェックボックスにチェックを付けると、改造コード機能が利用できます。Lock Type の意味は下記のとおりです。

Evalutation Type 説明
Exact 指定値を強制する。
Range 指定した下限値〜上限値の範囲を強制する。
No Lower Than 指定値より小さくならないよう強制する。
No Greater Than 指定値より大きくならないよう強制する。

OKを押すと変更が反映されます。

おまけ:アドレス計算に式を利用する

動的に確保されるメモリ領域はメモリアドレスが不定になるため、ここまでで紹介した方法では、起動後に毎回再検索しなければなりません。MHS にはポインタの参照先を辿って動的にアドレスを指定する方法が用意されています。

Modify Address ダイアログの Normal Address タブを開きます。

中断の Complex Address (Overrides Simple) というチェックボックスにチェックを付けると、下部の入力欄にて、メモリアドレスの表現に式が利用できます。

計算式の仕様は下記のとおりです。

  • 式ではC言語の基本的な演算子が利用可能。
  • 間接参照は [40B0F0] のように角括弧で行う(括弧は入れ子にしても問題ない)。
記述例: [40B0F0] + 0x1536 + ([40B0F4] & 0xff)
おまけ:値を計算式で加工して表示する

Expression Evaluator ウィンドウに式を入力して追加すると、値を計算式で加工して表示することができます。

計算式の仕様は、動的アドレス計算に使用するものと同じです(上記参照)。

メモリウォッチ内容の保存

MHS を終了する前に、メモリウォッチの内容を保存しておきましょう。

ファイルの保存は、メニューから File → Save Selected As を選択して行います。

保存したファイルは次回、File → Open Save File から開くことができます。

まとめ

とりとめのない紹介になりましたが、下記をもってまとめとします。

  • MHS を使えば簡単・強力にメモリの検索・監視・書き換えが行える。
  • 解析技術があれば、動的に変化するアドレスにも柔軟に対応できる。よくわからなければ、メモリアドレスによっては、起動ごとに毎回検索する必要があることに注意すべし。
  • MHS には Script など、まだ紹介されていない興味深い機能が多数ある。

Windows 上で動くゲームの TAS 制作を考えている方の参考になればうれしいです!

*1:多くのエミュレータは RAM Watch 機能を内蔵しているのでプロセスメモリエディタを利用する必要はないのですが、Mupen64 のようにそういった機能を持たないエミュレータに対してはプロセスメモリエディタが利用されます。また、最近では Windows でも Hourglass を利用した TAS 記録が行えるようになったため、Windows 向けゲームに対して TAS 目的で利用する事例も増えると考えられます。

「Hourglass」を利用したWindowsゲームのTAS製作

Hourglass (GitHub)Windows向けゲームのTASを作成するためのツールです。

www.nicovideo.jp

Hourglass が公開されてまもなく、洞窟物語TASStickman TAS などが公開されました。Hourglass が使えるかどうかはゲームによって異なるようですが、今後も作品数は増えていくものと思われます。

本記事では、Hourglass の基本的な使い方を紹介します。

Hourglass はどんなツール?

Hourglass は指定されたゲームを独自に書き換えして起動することで、以下に挙げるような機能を利用可能にします。

  • ムービーの記録・再生(キー記録のみ、マウスなどは執筆時現在未対応)
  • セーブステートの読み込みと保存(どこでもセーブ機能)
  • スローモーション、フレームアドバンス(コマ送り)、早送りなどの実行速度制御
  • ゲーム画面・音声のAVIファイル記録(低速でもコマ落ちしないはず)

ユーザーは何も考えず Hourglass からゲームを起動するだけでよいです。

中には Hourglass で起動を行うと、まったく正常に起動しないゲームや、一部機能がうまく動作しないゲームがあります。外部からアプリケーションに無理やり介入するので安定性の問題は避けられないと思いますが、今後徐々に解消されることを期待したいです。

動作環境に関してですが、開発者からは「XP推奨、Vistaや7でもそれなりに動くけれど十分なサポートはされていません(特に64ビット版)」というふうに言われています。

対応状況

いくつかのゲームでは安定して動作するようですが、同期ずれ(desync)がときどき発生するゲームや、エラーが出て起動できないゲームもあるようです。先駆者がそういった情報を公開していることもあるので、まずは既存の情報を探すと良いでしょう(検索例:東方 hourglass)。

Hourglass のインストール

2016年現在、Hourglass は TASVideos のページ上からダウンロードできます。

Nitsuja 氏が作成した元祖 Hourglass と、改良版の Hourglass Resurrection があるようです。2016年時点ではどちらも「開発途上(開発停滞中)」の様相を見せており、一概にはどちらを利用すべきとも言い難いようです。

インストールは、ダウンロードした圧縮ファイルを任意のディレクトリに展開するだけです。また、アンインストールは展開したファイルをフォルダごと削除するだけです。


使い方

多くの機能は操作感がエミュレータのそれとほぼ一致します。


ムービーの記録と再生

「Game Executable」で起動したいゲームを選んで「Run and Record New Movie」を押せば、ゲームが起動して、動画の記録が始まります。

「Stop Running」を押すとゲームが終了して、動画の記録が停止します(注*1)。

ムービーの再生は、既存ムービーが選ばれた状態で「Run and Play Existing Movie」を押すだけです。

キー設定の変更

「Input」メニューからキー設定を変更することができます。

「Configure Hotkeys」では、Hourglassの機能に割り当てるショートカットキーを編集することができます。デフォルトの設定を把握したいときも、この設定画面を見ればよいです。割り当てを変更したいときは、項目を選択して「Reassign」を押してください。

「Configure Game Input」では、ゲームに送るキーの設定ができます。デフォルト設定から変更することで、カーソルキーの左右の認識を入れ替えたり、特定のキー以外は押してもゲーム側で認識されないように設定したりすることができます。Hourglassの機能キーとゲームの操作キーが重複するような場合、この設定で割り当てを調整するとよいでしょう。


ステートの読み込みと保存

いわゆるどこでもセーブです。ステートの読み込みと保存はショートカットキーで行います(デフォルト設定では、F1〜F10でロード、Shift+F1〜F10でセーブ)。

一度作成したムービーの途中から記録を再開するには、以下の手順を行います(一般的なエミュレータでの操作と同じ)。

  1. ムービーの再生を開始する
  2. 記録を再開したい箇所でステートをセーブする
  3. Hourglass のウィンドウを見て Read+Write モードであることを確認し、先ほどのステートをロードする
  4. 動画を記録する状態になっているので、ここから記録を続ける
フレームアドバンス、速度変更

フレームアドバンスというのはコマ送り機能のことです。

フレームアドバンスはショートカットキーで操作します(デフォルトでは \ キー、スペースキーに割り当て)。フレームアドバンスを行ったあとの停止状態から、通常の速度に戻すには Pause を解除します(デフォルトでは Esc キー、Delete キー、Pause キーに割り当て)。

フレームアドバンスがあれば必要ありませんが、ゲームを50%などの一定の速度でスロー動作させることもできます。

また、Fast-Forward は極力ウェイト類を飛ばして高速に動作させようとします。作成したムービーの確認時などに便利です。

映像・音声のAVIファイル記録

「AVI」メニューで「Capture Video and Audio」を選ぶと、映像と音声がAVIファイルに記録されます。「AVI Capture Disabled」を選ぶと、記録は停止されます。


メモリアドレスの検索と監視

エミュレータに搭載の RAM Watch と RAM Search がありますが未完成気味です。現在のところは、これらの代替として MHS のような外部ビューアを利用することを推奨します。

関連: プロセスメモリエディタ「MHS」を利用したメモリ監視・操作 - ごちゃログ

*1:私が動作を確認したところによると、ゲーム終了後もHourglassを閉じるまではプロセスが残り続けていました。Windows XP 32bitでは起きない問題なのかもしれませんが、多重起動防止ロジックがあるゲームがこれにより起動できなくなることがあるので注意が必要です。ゲームを終了後は一旦Hourglassを閉じるのが確実です。

古い Snes9xで使うライブラリのビルド方法 (zlib, libpng)

2011 年時点の Snes9x 向けの zlib と libpng のビルド手順です。2019 年現在は公式ビルドガイドに沿っていればこういったことを考える必要はありません。

本体のビルドについては、Snes9x のソースコードをコンパイルするをご覧ください。

使用するツールとライブラリ

スタティックライブラリをビルドします。DLLであれば些細なバージョン違いでのエラーは発生しないと思うので、手間なく継続的に開発できるようにするには、DLLとリンクする方が良いかもしれません。

本記事では Snes9x 向けのライブラリをビルドするので、文字コード(MBCS/Unicode 両サポート)周りで通常のビルドとは異なる手順を必要とします。

コンパイル手順

前準備
  1. zlib と libpng のソースコードをダウンロードして展開する
  2. libpng/projects/vstudio/zlib.props を開いて、ZLibSrcDir を修正する(相対指定は zlib.vcxproj からの相対位置になる)
  3. zlib/contrib/masmx86/bld_ml32.bat を開いて、ml のオプションに /safeseh を追加する(/safeseh 追加の参考
  4. 修正したらソリューション vstudio.sln を開いて、デフォルト設定のビルドが成功することを確認する
Win32 ビルド

*** 最適化及びデバッグオプションの統一

[Debug Library] [Release Library] のオプションを、zlib, libpng についてそれぞれ変更する。

  • 最適化オプションを Snes9x と揃える([ランタイム オプション])
  • [C/C++]-[デバッグ情報の形式] を Snes9x と揃える
  • [全般]-[ターゲット名] を出力したいファイル名に設定する
  • [全般]-[文字セット] を [マルチバイト文字セットを使用する] あるいは [設定なし] にする
  • [C/C++]-[出力ファイル]-[プログラム データベース ファイルの名前] をなど出力したいファイル名に設定する(コンパイル後のリネーム厳禁)(例: $(OutDir)$(TargetName).pdb)。

*** zlib コンパイルの修正

  • 「error LNK2001: unresolved external symbol _gzclose」への対策を行う
    • zlib プロジェクトに gzclose.c, gzlib.c, gzread.c, gzwrite.c を追加する
    • [C/C++]-[プリプロセッサ]-[プリプロセッサの定義] から Z_SOLO を削除する
    • [C/C++]-[全般]-[警告をエラーとして扱う] を「いいえ」に設定する

以上を設定後、libpng プロジェクトをリビルドする。

x64 ビルド

Win32 ビルドの構成を複製するので、ビルド設定を完了後に実施してください。

  • メニュー [ビルド]-[構成マネージャー] を開いて、Win32 構成を元に x64 構成を新規作成する
  • 出力ファイル名を適宜変更する

以上を設定後、libpng プロジェクトをリビルドする。

Unicode ビルド

Cランタイム関数の呼び出しをUnicode版に差し替えることで、Unicode サポートを実現します。

  • [全般]-[文字セット] を [Unicode 文字セットを使用する]に設定する
  • snes9x/win32 ディレクトリの _tfwopen.cpp を zlib, libpng プロジェクトに追加する
  • snes9x/win32 ディレクトリの _tfwopen.h をインクルードパス上に配置する
  • [C/C++]-[詳細設定]-[必ず使用されるインクルード ファイル] に _tfwopen.h を追加する
  • [プリコンパイル済みヘッダー] を使用しない設定に変更する
その他

ライブラリのビルド以外における留意事項です。

  • libpng/scripts/pnglibconf.h.prebuilt を pnglibconf.h にリネームして snes9x の所定ディレクトリに配置する

古い Snes9x のソースコードをコンパイルする

以下はとても古い時代に書かれた記事です。最新の Snes9x は CI で自動ビルドされています。バイナリがほしいだけなら自分でビルドする必要もありません。それでも自分でビルドしたい方は公式なビルドガイドを参照してください。この記事を執筆した当時と比べてずっと簡単です。

当時のコード向けのビルド済みの依存ライブラリファイルをおいておきます。

続きを読む