新版の3gx(Luma3DS v10以降で読み込める3gx)にはなんとデフォルトではシンボル情報が埋め込まれています。
シンボル情報とは?
簡単に言うと、関数や変数の名前、アドレスなどの情報です。
何ができる?
シンボル情報を読み取るGhidraなどのリバースエンジニアリングツールの拡張プラグインを適当に作れば3gxを逆コンパイル出来ちゃうんですよ…(何もしなくても出来るっちゃできますが、シンボル名がわからないのでかなり見にくいです。)
構造
3gxヘッダ
struct _3gx_Header
{
u64 magic;
u32 version;
u32 reserved;
_3gx_Infos infos;
_3gx_Executable executable ;
_3gx_Targets targets;
_3gx_Symtable symtable;
};
(https://gitlab.com/thepixellizeross/3gxtool/-/blob/master/includes/3gx.hpp より)
シンボル情報のオフセットや数はヘッダのsymtableにあります。
シンボル情報ヘッダ
struct _3gx_Symtable
{
u32 nbSymbols;
u32 symbolsOffset;
u32 nameTableOffset;
};
(https://gitlab.com/thepixellizeross/3gxtool/-/blob/master/includes/3gx.hpp より)
nbSymbols: シンボル数
symbolsOffset: シンボル情報のオフセット
nameTableOffset: シンボル名の集合体のオフセット
シンボル情報の構造体
struct _3gx_Symbol
{
u32 address;
u16 size;
u16 flags;
u32 nameOffset;
};
(https://gitlab.com/thepixellizeross/3gxtool/-/blob/master/includes/3gx.hpp より)
address: メモリ上でのアドレス
size: サイズ
flag: フラグ(bit0: data, bit1: func, bit2: thumb, bit3: altname)
nameOffset: nameTableOffsetからのオフセット
意外と単純な構造ですね。
実際に作ってみた
Ghidraのプラグインを作ってみました。シンボル情報を読み取って指定のアドレスにシンボル名の関数を作る簡単なものです。少し前にGhidraのプラグインを作ったことあるのでササッと作れました。
自分の3gxで試してみると…
なんと出来ちゃいました…
と言っても完全な訳ではない
逆コンパイル結果が完全と言う訳ではないので、あくまで参考程度に…って感じです。
対策
3gxにシンボル情報埋め込みたくないよって人は、Makefileの3gxtoolのオプションに-dを追加しましょう。