2024年12月7日土曜日

おバカ人狼Feignの解析(2)

 さて、パッチ形式でのデータ取りは出来たものの、Feignに手を入れないで動かすのもやってみたい。どこから手をつければいいのかな。

と、その前にFeignはオンラインゲームです。どうやって動作検証を行うのでしょうか。Among Usの場合はローカルネットワークだけで動くモードがあります。こちらは抜け道を使うと一個のPCでフルの15人まで動かすことだって可能です。

でもFeignはオンラインにつなぐしかありません。二つのPCでSteam2アカウント使えばゲームの流れはつかめます。が、吊り=ゲーム終了となってしまうためまだ足りません。もう少し多様なシチュエーションを作るには最低あと二つ。てことでスマホとタブレットを持ってきて4アカ。ギリギリです。

さて、Feignのメモリを覗きこむ。そのためにはWin32APIのReadProcessMemoryを使用する必要があります。プロセスのハンドルとかはC#のProcess周りで取ることが出来そう。

では、これらを使ってどこを読めばいいのか?本格的にFeignの解析が必要です。

Unityで作られたゲームはIL2CPPという技術でコードの難読化も兼ねてネイティブコードに変換されています。Il2CppDumperとかIl2CppInspectorというツールで解析が出来るようです。

が、どちらも本家のアップデートが止まっています。試しにFeignに使ってみると対応しないVersionですとのこと。Forkをいくつか見てると更新が続いてるのがある、試してみると・・いけた。

入手した情報からアドレスの割り出しをしていく。見た感じstaticオブジェクトのポインタがわかって、staticのフィールド、インスタンスのフィールドのオフセットがわかったので順々にたどればいいのね。LobbyManagerはstaticクラスだったのでここから辿って辿っていくとusersは取れそう・・・。取れた。

GameControllerは動的に生成されてるので、インスタンスを誰か保持していないかな、と探すと同じく動的に生成されるクラスしか保持していない。あれ?詰んだ臭くない?

よく考えなおしてみよう。staticのオブジェクトも生成される場所はヒープのはずだからその周辺に確保されるはず。メモリサーチでクラス情報を保持しているオブジェクトらしきものを列挙してみる・・・。複数出てくる。

真のオブジェクトはplayers、deadPlayersというListを持っているはずだから、そのオフセットにListを持つものに絞ると・・・まだ複数ある。ゲームごとにオブジェクトを作成して破棄しきれていないらしい。あちこちで保持しあってるからGC効かないんだろうな。

こうなってくると、ゲーム開始直前のロビー人数とplayersが等しく、deadPlayersが0のゲームを現在のゲームと決め撃つしかなく、それで何とか取れたっぽい。

playersは生きているプレイヤー、deadPlayersは死んでいるプレイヤーに違いないから、これで生死を判定しようかな。あれ?両方に名前があるプレイヤーがいるぞ。もしかしてキルされたらplayersからdeadPlayersに移すけど、蘇生されたらdeadPlayersはそのままにplayersに再追加してる?そういう仮定で検出すると、あってるぽい。

てことでメモリ監視方式も完成。手動/メモリ監視/Mod経由の3通り全部乗せが出来ました。テストプレイで代替問題ないことを確認して数日後。

本体アップデートが来ました。こうなってくるとアドレスも変わってるだろうし、パッチもそのまま当たるかわからないし。いやぁ、アプデに追従するのは大変だなぁって実感しました。ある程度需要はあるだろうし、公開してもいいんだけどね。

おバカ人狼Feignの解析(1)

 久しぶりになんか書いてみる。

時々友人とおバカ人狼と言われるFeignをやってます。

人狼系ゲームをDiscord VCでプレイするとき、どうしても必要になるのがミュート作業。夜時間はスピーカーミュート、死亡した場合はミュートが定番です。もちろん、手動でやってもいいんですがスマホでやってる人は下手するとゲームが落ちてしまいます。

最初に考えたのが、手動ミュートボット。PCで二窓出来る人が代表して昼時間/夜時間の切り替え、死亡処理をボタンポチポチしてする方法。

C#でDiscord.Netを使ったり、サーバーで動かすためにpythonに移植したり。これでも十分便利なんですが、やっぱ操作ミスとか忘れがたまにあるので何とか自動化したい。

二パターン考えました。

・BepinExを使ってパッチを当てる。(AmongUsなどのModと同じ)
・Feignのメモリを覗き見る。(AmongUsCaptureやBetterCrewLinkと同じ)

まぁAmong UsでもModを作ってるし、パッチを当てるほうが早いかなと思いBepinExを導入。

BepinExが変換したDLLを読むことでクラス情報が一覧できます。

どのような処理をしているかは簡単にはわからないのですが、今回は動作を変更するためではなく状態を読み取るのが目的なのでとにかくクラス名、メソッド名、フィールド・プロパティ名から動作を推測していきます。

まず、ゲームロビーとゲーム自体の制御をする部分があるはず。ロビーについてはLobbyManagerというそれらしいものを発見。usersというListも発見し明らかにこれでメンバーが取れそうです。

メンバー変更のタイミングもOn~joinやら~Leave~やらがあるのでLogとってみたり、デバッガアタッチして見たりで大丈夫そうなことを確認。

じゃあ、ゲーム進行はというとこれまたGameControllerというそのままの物を発見。stateというフィールドがありここでゲーム状態を保持してそう。メソッドにもProcessStateChangeというものがありLogを出してみるとここでstate移行してるのも間違いない。

ってな感じで解析を進めていきました。

この情報をBotアプリに転送すればオートミュートの出来上がり!

・・・ただ、Modのインストールからしないといけないのはめんどくさいし、アプリ一個で済む形を作ってみたい。自分がいない時に誰かに貸せるようにしたいしね。

でも、そこからが結構大変でした・・・。

2021年12月12日日曜日

Among Us 管理ツール少しいじりました。

 前回のMod管理ツール、Reactorを使ってるMODには対応できていなかったので
複数DLLがある場合を仮定してフォルダ管理する形式に変更してみた。

あと、AutoMuteUsやBetter-CrewLinkを使うことを想定して、そちらも同時に
立ち上げられるようにしてみた。

ついでになんとなく.NET5に移行。
単一実行ファイルにできるとか、Zip解凍にアップデートが来ているとかで。


よくあるエンジニアが適当に作ったUIです。

こんなショートカットをまずウインドウにドロップ。
するとSteamなら
Epicなら
となるはず。
Steamの場合はもうひと手順必要で

で表示されるフォルダを開いて
をウィンドウにドロップすると上二つがそろう。
ここでTheOtherRolesなり、Town Of MossなりのModのZipファイルを取ってきて
ウインドウにドロップ。
するとAmong UsフォルダにMod本体以外を展開してリストにModが追加される。

これ以降はDLL本体だけでも大丈夫なんですが、Town Of MossはReactor.DLLが必要なのでZipで登録するほうが楽ですね。

ここまですればMOD無しならVanilla、MODなら好きなMODを選択してゲーム開始を押せば
DLL本体を自動で消したりコピーしたりでAmong Usが起動します。

下二つはDiscode連携するAmongMuteUs用のキャプチャツールや近アモ用のBetter-ClewLinkを同様に登録できます。
チェックを入れると本体起動前にそれらを起動できるので便利かなと。

というのを使ってみたい人っているんですかね?

2021年12月6日月曜日

Among Us MOD管理ツール

 久しぶりにツール作ってます。

Among Us面白いですよね。色んな配信者の方見てるうちに自分でもやってみようと。

今はMODを入れて遊ぶのが特に流行っていますが、そのMODの中にとある推し配信者の方が作ったスキンが入ってるものがありまして。

でもMODない人と遊ぶには外したり、また違うMOD入れたり・・・。
ちょっとめんどくさいなと思って管理ツール作成中です。


ほんとに簡単なツールなんですが、アモアスの起動ショートカットとアモアス本体フォルダを最初に登録します。
Steamだと両方登録しないとだめですが、Epicだと起動ショートカットだけで両方登録されます。

下の表にMODをドロップするとModを管理して選択が出来るようになります。
Zipをドロップするとアモアス本体フォルダに展開するので、まだMOD入れたことない人は最初はZipからですね。
それ以降はDLLだけドロップでOKです。
DLLはMOD名+バージョンにリネームして管理します。

下の表で素の状態でプレイしたいときはVanillaを選ぶとDLLなしで、MODは入れたいものを選択するとDLLをコピーしてゲーム開始になります。

ただ、まだThe Other Role系しか確認してないんですよね。
なぜか最近MOD入れると起動して認識はするんだけどゲーム開始できないので確認できたとも言えないんですよね。
あと結構ファイルいじるので公開するのは怖いんですよね。
どうしようかな?


2019年12月7日土曜日

OVMFのバグ

今ちょっといろいろあってUEFIアプリを書いてます。
検証をQEMU上で行ってるんですが、なぜかプログラムを実行するたびに使用可能メモリが減っていきます。
実機でテストすると全く起きない。
どこまで削ったら起きなくなるのか突き詰めていったら、見つかりました。
TestString()という、画面表示できる文字列か検証するAPI。
これを呼ぶとメモリが減っていきました。

で、QEMU用のUEFIっていうのはオープンソースのOVMFっていう実装を使ってます。
なのでソースみりゃわかるかなと。

ダウンロードしてきてGREPかけて・・・多分これ。

EFI_STATUS
EFIAPI
GraphicsConsoleConOutTestString (
  IN  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
  IN  CHAR16                           *WString
  )
{
  EFI_STATUS            Status;
  UINT16                Count;

  EFI_IMAGE_OUTPUT      *Blt;

  Blt   = NULL;
  Count = 0;

  while (WString[Count] != 0) {
    Status = mHiiFont->GetGlyph (
                         mHiiFont,
                         WString[Count],
                         NULL,
                         &Blt,
                         NULL
                         );
    if (Blt != NULL) {
      FreePool (Blt);
      Blt = NULL;
    }
    Count++;

    if (EFI_ERROR (Status)) {
      return EFI_UNSUPPORTED;
    }
  }

  return EFI_SUCCESS;
}
Bltをfreeしてるってことは内部でメモリ割り当ててるのね。
これは怪しいのでGetGryphの実装を探してみると、たぶんこれ

EFI_STATUS
EFIAPI
HiiGetGlyph (
  IN  CONST EFI_HII_FONT_PROTOCOL    *This,
  IN  CHAR16                         Char,
  IN  CONST EFI_FONT_DISPLAY_INFO    *StringInfo,
  OUT EFI_IMAGE_OUTPUT               **Blt,
  OUT UINTN                          *Baseline OPTIONAL
  )
{
~中略~
  *Blt = Image;
~後略
Imageが実体ね。これを探してみると

  Image = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
  if (Image == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto Exit;
  }
  Image->Width   = Cell.Width;
  Image->Height  = Cell.Height;

  if (Image->Width * Image->Height > 0) {
    Image->Image.Bitmap = AllocateZeroPool (Image->Width * Image->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
    if (Image->Image.Bitmap == NULL) {
      FreePool (Image);
      Status = EFI_OUT_OF_RESOURCES;
      goto Exit;
    }

はい。Imageは構造体で、Bitmapという要素にもメモリ割り当ててるね。
ってことでBltだけfreeするのはアウトですね。
とりあえずTestStringを呼ばなきゃいいんだけど、UEFIの実装ってまちまちでフォントも入ってるかテストしてみなきゃわからないんですよねー。
実際に"|”と”}”が実装されていない環境もありました。"{"はあるのにw。

これ直してビルドすればいいんだけど、環境整えるのがめんどくさいw
誰か直してくれないかなぁ?

2019年11月30日土曜日

ケ〇マス?

久々の投稿です。すっかり忘れてたというか

作ったのはちょっと前ですが・・・。
テレビのクイズ番組で人気のコーナー。
アプリ作ってくれるところ募集とかなんとか言っました。
いいお題ではあるな、と思ったのでものは試しに作ってみた。
4,5時間はかかったかな。

PC更新したばかりなのでまずUnity入れなおして、使い方を思い出して・・・まだよくわかんない。

とりあえず問題の管理だよなぁ。単純に盤面を記録して、正解の読み方、間違った読み方のデータを並べ解けばいいのかな?
ってことでこんな感じ。

巴,祇,藺,草
危,険,案,蹴
医,眩,家,木
剣,園,山,計
基,軸,子,通
薬,奈,馬,鞠
巴,ともえ
巴奈馬,パナマ
祇園,ぎおん
藺草,いぐさ
草木,くさき
危険,きけん
案山子,かかし
蹴鞠,けまり
医薬,いやく
家計,かけい
基軸,きじく
剣,つるぎ
眩,めまい
木通,あけび

誤読データ準備するのがしんどいぞ・・・

2018年3月21日水曜日

2月勝率

気づいたらもう3月も終盤。
また更新忘れてました。

最近のニュースであれば、とうとう星14武器を手に入れました。
パルチザンでした・・・。



とりあえず、頑張って強化もしたしせっかくなのでメインで使っていきたいと思います。

で、バトルアリーナですが相変わらず・・・

特に2月終盤にはバーチャロンコラボで武器種チェンジが入ったんですが初日の混乱で勝ちを稼いだ以外は負け続き。3月序盤まであったんですが結局勝ちきれなかったです。
ライドスラッシャー、面白かったけどなー。使いきれませんでした。

3月はまた武器チェンジでさらに変化があったけど、それはまた別の話、ということで・・・。