株式会社Ninjastars
セキュリティエンジニア研修生:鶴田
今回は弊社のサービス内容をより多くの方に理解していただくことを目的として、リバースエンジニアリング( 以下RE )を、実際に初心者である私の視点から解説いたします!
・著作権者の許諾
著作権者
@kakira9618
この度記事を書くにあたり、特別に著作権者の許諾を得てリバースエンジニアリングを行っています。
著作権者の許諾なく、今回のような行為は絶対に行わないでください。
電子計算機損壊等業務妨害罪
私電磁的記録不正作出・同供用
不正指令電磁的記録作成罪
著作権法違反
不正競争防止法違反
等の法律に違反し、犯罪行為となる可能性があります。
1. 事前の準備
必要なソフト
Ghidra
Stirling
TORI( 今回REする対象となるゲーム )
※TORIはWindows環境でのみ動作します。
そうでない環境の方は、仮想マシンなどでセットアップして下さい。
↓TORIのダウンロードはこちらから↓
https://drive.google.com/drive/folders/1CGy28IQGGVov76nOL60WVbvh48a7jfFB
※この記事は初心者向けのため、なるべく挫折しないように画像を多めに用意したので、ボリュームが多く見えますが、15分前後でゲームがリバーシングできちゃうので、記事の長さに騙されず取り組んでいただけると幸いです(・ω・;)
2. TORIのスコアを書き換えてみよう!
TORIをダウンロードできたら、実際に起動して遊んでみましょう(^ω^)
しばらく遊んだ後に、他のファイルを調べてみましょう。
するとscore.txtというテキストファイルが見つかると思います。
開いて中身を見てみると、4つの整数が確認できます。
私はゲームで38点獲得し、リザルト画面で2位だったので、このscore.txtは点数を記録するテキストファイルと見てよさそうです。
一番上にある大きな整数は、今はスルーしておきましょう。
では、このスコアを書き換えてみましょう。
試しに1位のスコアを9999に書き換えます。( 648→9999 )
そして再びminigame.exeを起動してください。
すると、TORIが起動しなくなるはずです。
どうやら、このゲームはスコアを改竄するとゲーム自体が起動しなくなるようです。
( スコアを書き換える前の数値に戻すと、正常に起動します。)
スコアの書き換えを検知すること、そしてscore.txtの一番上にあった謎の数を考慮すると、おそらくハッシュ関数のようなものを使ってスコア改竄を検知していると予想できますね!
ここからゲームをリバースエンジニアリングしていきましょう。
3.Ghidraを使って解析
それではGhidraを開いてください。
Ghidraの導入・開き方は、↓別記事↓を参照してください。
Ghidraが起動し、この画面が出たら、
1)CodeBrowserの起動。
File->New Project->Next->Project Nameを入力->ドラゴンのアイコンをクリックでCodeBrowserが起動します。
↑この手順に従ってCodeBrowserを起動してください。
CodeBrowserが起動できたでしょうか?(´・ω・`)
では、TORIごとminigame.exeをGhidraにドラッグ&ドロップしてください。
するとこのような画面が現れるはずです。
この画面も、デフォルトのままOKをクリックしてください。
重要なのは次の画面です。
Analyze( 分析 )するかしないかGhidraが尋ねてくるので、Yesを選択してください。
Analyze中は、画面右下の分析状況を示すプログレスバーが表示されます。
なかなか時間がかかる(数分)ので、気長に待ちましょう(´・ω・`)
Analyzeが終わったところで、一旦休憩です(; ・`ω・´)
さて、ここからリバースエンジニアリングを始めるわけですが、手がかりが何もありません。
そこで、GhidraにはFor Stringsという、現在解析しているプログラムから、文字に変換できるものを抜き出して表示してくれる機能があります。
( CTFでよく使われるstringsコマンドとほぼ同じものと見てよいでしょう。 )
早速For Stringsを使って何か手がかりを探ってみましょう!
それでは、画面上のSearchタブ→For Stringsをクリックしてください。
↓↓↓ 少し分かりづらい部分にあるので、画像を参照してください ↓↓↓
クリックした後の画面では、何もいじらずにSearchを選択して進んでください。
そして、出てきたウィンドウ下部にある" Filter "の部分に、抜き出したい文字列を入力し検索する訳ですが、ここで一旦立ち止まって考えてみましょう( ・`ω・´)
現在、解析するプログラムから文字列を抜き出そうとしている訳ですが、何を抜き出せばいいのか分かりませんね(´・ω・`)
そこで、TORIの特徴を振り返って考えてみましょう。
TORIはスコアの改竄を検知する機能や、スコアを記憶してランキングとして表示する機能がありました。
ということは、スコアをどこかで読み込む必要があるということが分かります。
そう、もうお分かりですね!
以前書き換えたテキストファイル、" score.txt "をTORIは読み込んでいるはずなので、score.txtを抜き出して解析を進めていけば、何かヒントが見つかるかもしれません!
( 勘の良い方はお気づきかもしれませんが、改竄を検知している部分を発見することにも繋がりますね! )
というわけで、Filterの部分に" score.txt "と入力して、該当した部分をダブルクリックし、再びGhidraの解析画面へ戻ってください!
( score.txtのアドレスやタイプの情報が表示されています )
For StringsのFilter機能を使って、score.txtを使っている部分へ移動すると、↓のような画面になると思います。
またもや意味不明な画面(´;ω;`)
ですが、今重要なのは1ヶ所だけです!(; ・`ω・´)
ここで注目してほしいのは、右側の" XREF[3] "と書かれている部分です。
これは、score.txtが参照されている部分を意味します。[3]は3ヶ所で呼ばれている、ということですね。
これらのうち、どれかが改竄検知の部分で参照されているということになるのですが、今回は1番上の" FUN_00401080:004010f3 "が正解です(・ω・;)
( IDAのJump to xref to operandという機能と同じです。 )
それでは、" FUN_00401080:004010f3 "をクリックしてください。
すると次の画面が表示されるはずです。
無事、score.txtが呼ばれているアドレス" 004010f3 "にジャンプすることができました。
それでは、004010f3の行が青くハイライトされている状態で、画面上部にある" Display Function Graph "というボタンをクリックしてください。
すると・・・
これは、Ghidraがプログラムの分岐を視覚的に表示してくれる機能です。
黄色で点滅している部分に、該当するアドレスがあるとGhidraが教えてくれているので、スクロールで拡大してください。
( 初見私はここで詰まりました(・ω・;) トラックパッドを使っている方は、それで拡大してください )
拡大していくと、↓の画面のように、アセンブリが書かれた画面に到達できたはずです。
この表を見ると、何か気づく点はありませんか?(´-ω-`)???
そうです、call命令で同じ関数が4回呼ばれていますね。
( fopen関数の後に、fgets関数が4回呼ばれています! )
score.txtを使って、同じ処理を4回・・・・
そういえば、score.txtに書かれていた整数も4つでしたね(゚ω゚)!
というわけで、この部分は「score.txtから1行ずつ数値を読み出して何らかの処理をしている」 と仮説を立ててみます。
そして、最後の分岐を見てください!
JZ命令( 直前のCMP命令の2つのオペランドが等しいかどうか )で分岐していますね。
スコアを読み込んで、何らかの処理を施した後に分岐・・・
つまりこれは、ゲームを起動させるか否かを決定していると考えてもいいでしょう!!(; ・`ω・´)
ということは、この分岐をどうにかすれば、スコアを改竄した状態でTORIが起動することになりますね(´^ω^`)
というわけで、Ghidra上での最後の作業になりますが、Display Function Graphを閉じて元の画面へ戻ってください。
このJZ命令をバイナリで表した"0F 84 CB 02 00 00"を控えた後は、Ghidraを終了して構いません(´・ω・`)
ここまで長らくお疲れ様でした(´・ω・`)
ここまで、Ghidraを使った解析が終了し、プログラム中のJZ命令をどうにかすればよいということが分かりました。(´・ω・`)
次はStirlingというツールで、実際にプログラムをほんの少し書き換えます。
4. Stirlingを使ってプログラムの挙動を変える
では、Stirlingを起動し、またminigame.exeをドラッグ&ドロップしてください。
すると、TORIがバイナリデータとして表示されます。
先ほど控えた、"0F 84 CB 02 00 00"の場所を検索しましょう。
画面上の「検索・移動タブ」から「検索」を選択してください。
そして、検索データの欄に、jz命令の機械語を入れて次検索を実行しましょう!
該当する部分が黒くハイライトされているはずです。
では、84の部分をクリックし、そのまま85と入力してください。
(0F 84はjz命令、 0F 85はjnz命令を表します。 jnzはnot jzあるいは !jz のようなものです。)
84の部分を85に書き換えたら、画面左上のフロッピーマークで上書き保存し、Stirlingを終了してください。
Stirlingを使ったプログラムの書き換え、お疲れ様でした(´・ω・`)
これにてTORIへの全てのリバースエンジニアリングは終了です!(´^ω^`)
5.そして・・・!!
慣れないリバースエンジニアリングの作業、お疲れ様でした。
ではscore.txtを書き換えていることを確認して、TORIを起動してみましょう。
上記の手順が正しく行われていれば、スコアが改竄されているのにも関わらずTORIを起動させることができるはずです!
そして。。。
ゲームが起動しているのにも関わらず、ランキングのスコアが改竄されています!
おめでとうございます!リバースエンジニアリング成功です!(^ω^)
6.最後に
いかがでしたか?
今回は、スコアの改竄を検知するゲームをリバースエンジニアリングする、というテーマでした。
このようにゲームに不正改竄検知システムを実装しても、そのシステム自体が改竄され無効化されるというジレンマが存在します。
また最近は今回のように実行ファイル自体を改竄したアプリケーションが海外のサイト経由で配布されてしまっているという現状が存在します。
ゲームをどのようにしてセキュアな状態に持っていくか、このシリーズでは考察していきたいと思います。
『もっと楽しく安全なゲームの世界を作る』
上記が弊社の企業理念であり、目指すところであります。
7.備考
現在、弊社ではスマートフォン向けのソーシャルゲームを中心としたセキュリティ脆弱性診断やリバースエンジニアリング対策等のサービスを提供しております。
注意事項
本レポートに記載されている内容を許可されていないソフトウェアで行うと、場合によっては犯罪行為となる可能性があります。そのため、記事の内容を試す際には許可されたソフトウェアに対してのみ実施するようにしてください。
本レポートについて
お問い合せ
E-mail:saito@ninjastars-net.com
株式会社Ninjastars
セキュリティエンジニア研修生
鶴田龍之介