[Hack] コード移植方法 with GHIDRA

GHIDRAとは

NSAが開発した逆アセンブラツールです。

しかも無料というのだから、これまたすごいの一言です。

IDA Proはものすごく便利なツールですが、ライセンス料が高いので導入のハードルがかなり高いです。

このサイトでダウンロードできるのでまずはGHIDRAを入手しましょう。

IDA ProでできることのほとんどがGHIDRAでできます。

プログラミングに最適なキーボードのご紹介

コーディングはとにかくキーボードを叩く作業なので、疲れにくいキーボードは必須です。

HHKBのような静電容量式のキーボード欲しいんだけど、今のキーボードなかなか壊れてくれません。

ところで、ぼくがメインで使っているFFKB67MRL/EBがいつの間にか生産終了しててキレてます。

NSO to ELF

NSOはそのままではGHIDRAでひらけないのでELFに変換する必要があります。

GHIDRAに対応したLoaderがリリースされました!もうこの作業は不要です!!

64bitにしか対応していませんが、nx2elfというツールが変換に対応しているのでそれをビルドしたものを公開してあります。

ドラッグアンドドロップすれば変換してくれます。

JDK

GHIDRAの実行にはJDK(JAVA)が必要なので、公式サイトからインストールしましょう。

JDK

jdk-11.0.2_windows-x64_bin.exeをダウンロードします。

32bit版が提供されていないので、32bitOSではGHIDRAは動作しないかも?

インストールが終わったらJavaのパスを通します。

環境変数
C:\Program Files\Java\jdk-11.0.3\bin

環境変数に追加するパスはインストールしたJDKのバージョンによって異なります。

わからない場合はドライブC内の “ProgramFiles\Java” から確認してください。

これをしないとGHIDRAが起動しません。

GHIDRAの使い方

いくつかのパートに分けてGHIDRAの使い方を解説していきたいと思います。

GHIDRAを展開した状態

Loaderの導入

GHIDRAでのNSOの分析を便利にしてくれるプラグインが公開されていたので紹介します。

  • GHIDRAを起動してFile -> Install Extensionを選択
  • 右側の+ボタンを押して、ダウンロードしたzipファイルを直接指定

GHIDRAの再起動が要求されると思うので、再起動しましょう。

ELFの分析

ghidraRun.batを起動します。

まずは実行ファイルであるELFを分析します。

同意書

I Agree(同意)をクリックして先に進みます。

起動するとプロジェクトを作成するように指示されます。

プロジェクト名は適当に決めてしまいましょう。

FileからImport Fileを選択して、復号済みのバイナリファイル(.elf)を選択します。

ファイル選択画面
ELFファイル選択画面

ELFってExecutable and Linking Formatの略だったんですね。

インポート結果が表示されます。

「分析済みではないので分析しますか?」というダイアログが表示されるのでYesを選択します。

分析オプション

とりあえずデフォルトでチェックが入っているものだけにしました。

Analyzeをクリックすると分析が始まります。

分析中

右下の表示で分析中なことがわかります。

分析のスピードは使用しているマシンのCPUのスペックに依存します。

i7 6700Kで実行したところ約20分ほどかかりました。

IPSwitchのコードについて

まず、コードの意味について理解しなければいけないので「コードとは何か」というところからかいつまんで解説します。

分かる人はスルーしていただいて結構です。

IPSwitchのコード(というかほとんどすべてのコードは)はアドレス部と命令部に分かれています。

そして、各コードは「指定されたアドレスの本来の命令を、指定された命令に上書きせよ」という意味を持ちます。

アドレスとか命令とかがよくわからない人のためにわかりやすく説明すると、例えば “「お金」と言えば100円引き出せる貯金箱” があったとします。

そして、コードを用いてボタンを押したときの挙動が「100円引き出す」ではなく「10000円引き出す」に変えることを考えます。

それをIPswitch形式でコードを書くと以下のようになります。

擬似コード

// Money
@enabled
Desk 10000yen

つまり、100円というところを10000円に上書きしてしまうわけです。

今(ver4.3.1)ではその貯金箱は机の上にあるので「お金」と話しかけれ(コードを実行すれ)ばちゃんと10000円が引き出せます。

ところが部屋の模様替え(バージョンアップデート)をしたので、貯金箱はタンスの上に移動させられてしまいました。

ここでさっきと同じようにコードを実行しようとすると、机の上に既に貯金箱はないにも関わらず、お金を引き出そうと何度も話しかける事になってしまいます。

これでは思ったとおりの動作(お金の引き出し)ができないのは明らかですよね?

今からやる移植という作業は「マイナーアップデートだから模様替えをしたといってもそんなに位置は変わってないはず(別の部屋に移動させられたわけではない)だから、前回貯金箱があった場所付近を探して新しい貯金箱の位置を見つけよう」ということになります。

書きたいコード

// Money
@enabled
???? 10000yen

コードでいえば上のコードの?に当てはまるアドレスを見つければよいということになります。

ざっくり書いてみたのですが、どうでしょう?

コードの移植

移植に関して言えば基本的に命令部は弄る必要がないので、正しいアドレスの位置さえ指定してあげれば良いことになります。

移植元と移植先の両方のELFを分析している必要があります。

[4.3.1]
// Invisible
@enabled
023E1074 6666F63A

このコードの意味するところはアドレス “023E1074” の値を “6666F63A” に上書きしなさいということになります。

注意点

GHIDRAのアドレスは何故かIPSwitchのものと比べて0x00100000だけズレています。

なので、InvisibleのコードのアドレスはGHIDRAではズレを考慮して “24E1074” を調べなければいけません。

以下、アドレスを表記する際は断りがない限りGHIDRA表記(0x100000)ズレたものを記載します。

移植元のバイナリ参照

移植元のELFの分析が終了したらNavigationからGo Toを選択してアドレスを入力します。

InvisibleのアドレスはGHIDRAでは “24E1074” なのでそれを入力します。

24E1074付近へのジャンプ

ジャンプできたらBytesから付近のバイナリを調べます。

これは4.5.1のバイナリです

4.3.1でコードのアドレス付近のHEXを確認すると以下のような情報がわかります。

[4.3.1]
024E1070  6E 12 83 3B 66 66 A6 3F  00 00 00 80 66 A8 3B 3F
024E1080  09 98 C4 3E EC 51 78 3F  00 00 00 3D 48 E1 AA C0

このバイナリはしっかりとメモしておきましょう。

さてここで思い出していただきたいのはInvisibleのコードは、

アドレス “24E1074” の値を “6666F63A” に変更せよ

という命令だったということです。

そして、いまHEXを直接確認することで、

アドレス “23E1074(24E1074)” の “6666A63F” という値を “6666F63A” に変更せよ

というコードだとわかったことになります。

つまり、変更元である “66 66 A6 3F” を移植先のELFで探せば良いわけです。。

移植先のバイナリ検索

4.3.1から4.5.1の移植であればマイナーアップデートなので適当に “24E1074” 付近でバイナリ検索をかければ見つかります。

まずは “24E1074” 付近にジャンプしましょう。

ジャンプすると以下のような画面になるはずです。

4.5.1のアドレス0x024E1074

ここからバイナリサーチを行います。

SearchからMemoryを選んで以下のウィンドウを開きます。

検索したい命令 “66 66A6 3F” を入力したらNextを押します。

Search Allを押してしまうと、ELFの最初から検索を始めてしまうのでせっかく目的付近のアドレスに移動した意味がなくなってしまいます。

するとアドレス “2547b80” でヒットしました。

ただ、検索したバイナリが “66 66A6 3F” と比較的短いものなので、たまたま別のコードと一致してしまっただけの可能性があります。

本当に本来探しているべきアドレスなのかどうかチェックするには、付近のバイナリと比較するのが良いでしょう。

[4.3.1]
024E1070  6E 12 83 3B 66 66 A6 3F  00 00 00 80 66 A8 3B 3F
024E1080  09 98 C4 3E EC 51 78 3F  00 00 00 3D 48 E1 AA C0

[4.5.1]
02547B80  66 66 A6 3F 00 00 00 80  66 A8 3B 3F 09 98 C4 3E
02547B90  EC 51 78 3F 00 00 00 3D  48 E1 AA C0 1F 85 EB BE

比較すると全く同じバイナリが続いていることがわかります。

おそらくこれが正しいアドレスなので、IPSwitchに実装しましょう。

他のコード

全部自分が移植してしまっても勉強にならないので、残りについては宿題ということで。

[4.3.1]
// Infinity Ink
@disabled
02340ADE 75622C20635370656369616C00537562
02340AE0 496E6B5F53617665202C4D61696E496E
023406F8 6B5F53617665202C496E6B5265636F76

// Weak Gravity
@disabled
023E0DE4 0A2D2D3D

重力変更コードはめっちゃ簡単に移植できます。

IPSwitch

GHIDRAのアドレスは先述したように “0x00100000” だけズレているので、それを加味してコードを書きます。

// Invisible
@disabled
02447B80 6666F63A

あれ、これだけ?

nsobidの検索方法などは以下の記事を参考にしてください。

実行してみた

実行の仕方については割愛します。

ver4.5.1です

どうやら、ここのイカちゃんは消えないようですね。

広場のイカちゃんはみんな消えてしまっています。

無事、4.5.1に移植できました。

おまけ

簡単にみなさんが疑問に思っていそうなことに答えていきます。

プログラミングってどうやって勉強した?

独学です。

書店にいくと山ほどプログラミング関係の本が売っていますが、正直言って買うだけ無駄です。

プログラミングというのはすぐにトレンドが変化するので、一年前の本なんて全く役に立ちません。

特にSwiftはコーディング規則の変化が激しく、本に載っているサンプルプログラムはまず100%最新のSwiftで動作しません。

インターネットのほうがよっぽど便利です。

ただ、C言語の本だけは一冊読みました。どの本だったか忘れちゃったんですけれど…

おすすめの本は?

プログラミングとは全く関係ないけれど、この本はオススメです。

情報理論的な下限とか、符号化や暗号化について学べます。

個人的にはエントロピーのあたりの話が面白かったですね。

英語なので難しいと言えば難しいんですが、この本はめちゃくちゃ役に立ちます。

値段も結構するので、英語に抵抗がなくてアルゴリズムに興味がある人はどうぞ。

と思っていたら、割高ですが日本語版もありました。

コード教えて

教えないゾ☆

ここのDiscordサーバでDeveloperになればいくつかのコードは公開しているので見れます。

ただし、Developerになるには現Developer一名以上の推薦が必要なので誰かと仲良くなって紹介してもらってください。

シェアする

『[Hack] コード移植方法 with GHIDRA』へのコメント

  1. 名前:らみあ 投稿日:2019/04/09(火) 10:43:03 ID:421e7db67 返信

    アドレス “24E1074” の値を “66 66 F6 3A” に変更せよ

    という命令だったということです。

    と書いてありますが、なんで、そうなるのでしょうか?
    すみません…あまり知識がないもので…

    • 名前:me 投稿日:2019/04/09(火) 11:13:09 ID:1d068e850

      素朴な疑問なのですが、IPSwitchで記述されているコードがゲームにどのようにして影響を与えるかご理解いただけているでしょうか?
      ここの理解が不十分だと、まずここから説明しなくてはいけませんので。

    • 名前:らみあ 投稿日:2019/04/09(火) 16:05:46 ID:421e7db67

      それは理解出来ました。

    • 名前:me 投稿日:2019/04/09(火) 18:09:19 ID:bc165b243

      では以下のIPSwitchのコードについて考えます。
      [4.3.1]
      // Invisible
      @enabled
      024E1074 6666F63A

      これは「アドレス24E1074にある(本来は6666A63Fという)値を6666F63Aに上書きする」という意味なのもご理解頂けるでしょうか?
      ※本来の値はバイナリで調べないとわかりません

  2. 名前: 投稿日:2019/04/17(水) 12:20:38 ID:7b95dcb0a 返信

    >>1 自分から質問しておいて結局放置って常識無さすぎだろ

    管理人もこんな奴に答えてあげる必要なんてないよ
    コードの意味が分かってない時点でこのブログ見てる意味が分からん

    • 名前:me 投稿日:2019/04/17(水) 15:58:11 ID:2626a8344

      おっしゃられるとおりです。
      お返事お待ちしていたのですが、なかなか返ってこないのでここで一旦締め切らせていただこうと思います。

    • 名前:haru 投稿日:2019/04/28(日) 09:46:31 ID:9f3174227

      やってみます。返信ありがとうございます!

    • 名前:me 投稿日:2019/04/28(日) 10:19:38 ID:4f103d687

      またわからないことがあればどうぞ。
      NSOの取り出し方については記事にしていないので、近いうちにまとめようと思います。

  3. 名前:haru 投稿日:2019/04/27(土) 19:30:01 ID:043029ea3 返信

    NSOとはなんですか?

    • 名前:me 投稿日:2019/04/27(土) 23:16:55 ID:cd38afb23

      ここでNSOについて簡単に解説しているのでどうぞ。

      NSOをELFに変換して分析しよう
      NSOとは Nintendo Switchの実行ファイルのこと、詳しくはwikiを参照。 ここを見ることでゲームの...
    • 名前:haru 投稿日:2019/04/28(日) 07:47:15 ID:9f3174227

      NSOの取り出し方について詳しく教えてもらえませんか?

    • 名前:me 投稿日:2019/04/28(日) 08:54:56 ID:4f103d687

      簡単に手順を説明すると以下のようになります。

      1. HACGUIを使ってアップデータをNSPないしはNCAでダンプします。
      2. title.keyがあればhactoolでNCAを展開できます。
      3. 展開したexefsフォルダ内にmainがあります
      4. mainはNSO形式なのでELFに変換します。

    • 名前:haru 投稿日:2019/04/29(月) 09:45:43 ID:40ef3fc09

      アップデータでないとだめですか?

    • 名前:me 投稿日:2019/04/29(月) 16:03:12 ID:eee171002

      アップデータでないと1.0.0のNSOを解析することしかできないので、それでは意味がありません。