Goバイナリ解析メモ
はじめに
前回の記事ではC, PythonそしてRustで「Hello World!」を表示するだけのプログラムをコンパイル等を行なって実行ファイルへ変換したものの解析を行いましたが、先日の某LTの懇親会にてGo言語で実装したものを解析してみたら面白いのではないかと意見をいただいたため、今回の検証を行いました。なお、今回も最適化を無効化した32bitバイナリを対象としています。
検証メモ
以下は検証を行なった際のメモとなります。
Stirling
* Cバイナリに比べてやはりサイズが大きくなっている、ヘッダーとヘッダーとボディー感のNULL領域以外は相似していない
* 先頭付近に「Go Build」と言う文字列が存在する
* 途中から可読文字列が現れ始める(expやesiなど)
-> この周辺になんらかの処理が埋まってる?
* 一部下毒文字列ではない文字列を挟んだ後にintやboolなどの型名らしき文字列が出現
* 後半に進むに従ってGoの関数と思われる名称が多く現れる
* io.Writer, Sync.PoolなどのGoの要素がいくつか確認できる
-> 内部でGoの関数定義を行なっている?
* 「kernel32.dll」などのDLLファイルの名称が含まれている
-> 内部でバイナリに変換する際に利用?
* Cで利用される関数名が存在する
-> 独自で関数を持っている?
* Goソース、Goライブラリを列挙した部分がある
-> コンパイル時に必要?
-> 1.5以降のGoではGoとアセンブリで実装されていると言う仕様から、その線が高い
vxPEViewer
* ヘッダーに特に変わった点は無し
* ImportLibraryでは「winmm」「ws2_32」「kernel32」がインポートされている
* Stirlingを用いた解析時に現れたCの関数と同じ関数がインポートされている
* 直接関係のない関数を読み込んでいる点はRustと同じように思える
-> Goソース内でimportしたGoライブラリで利用されている関数で利用されているもの?
* なぜかWriteConsoleWはあるもののWriteConsoleAが読み込まれていない(他の関数ではどちらも読み込まれている)
Ollydbg, x32dbg
* これまで同様初期化処理と思われるコードからjmpする
* WriteFile, WriteConsoleにBPを仕掛けるもののそのまま通常終了している点から、別の関数を利用 or 独自の処理を行なっている?
* 今までのように特定のDLLの関数を直接呼び出さずに外部関数を呼び出す総合的なcall命令が存在する
-> 実質一つの命令で様々な命令を再現できる
-> 上記の関数にBPを仕掛けても効果がなかったことも頷ける
このcall命令が文字列を表示する関数を呼び出しているようで、同時にeaxに関数のアドレスを渡すことで様々な関数を呼び出すことのできる命令でもある
このように、eaxに関数のアドレスを渡すことで呼び出していました。
先ほどのcall命令の内部へ入ると上記のようになっており、eaxに与えるアドレスによって呼び出す関数が変わっていることがわかります。
最後に、このcall命令が最終的な文字列表示を行う処理でありWriteConsoleWを呼び出していることがわかります。
まとめ
今回の検証は、今まで行ってきたどのバイナリよりも複雑なものでありWriteConsole関数にBPを仕掛けるだけではうまくいかないと言うこともありかなり苦戦しました。特に、関数名や処理名をデバッガ側でアシストされなかったのが一番の難点だったと思います。
しかし、関数アドレスを渡すことで呼び出しを行う処理の攻略は自バイナリで主要処理を保持していたりパッカーまではいかなくとも難読化を行われているようなバイナリを解析する練習としては非常に良い経験になったと思います。
今回もおそらく本来の仕様とは異なる点が多くあるかと思うでの意見等頂ければ嬉しいです。