新版3gxにシンボル情報埋め込まれてる件

新版の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を追加しましょう。

CTRPFの関数まとめ OSD.hpp(Screenクラス)編

CTRPF関数まとめ第3回です。
今回はOSD.hpp編です。

目次

OSD.hppには何がある?

OSD.hppには、Screenクラスと、OSDクラスがあります。今回紹介するのはScreenクラスです。
Screenクラスには、画面に描画したりするための関数があります。

使い方

Screen::GetFramebuffer

指定した画面の座標のフレームバッファポインタを取得します。
引数:(X座標, Y座標, 右目のフレームバッファ(通常はfalse))
戻り値: フレームバッファのポインタ(u8 *)

void screenTest(const Screen &screen) {
    // 座標(0, 0)の左目のフレームバッファを取得
    u8 *leftFb = screen.GetFramebuffer(0, 0);

    // 座標(0, 0)の右目のフレームバッファを取得(上画面のみ)
    u8 *rightFb = screen.GetFramebuffer(0, 0, true);
}
Screen::DrawPixel

画面に1px × 1pxの点を描画します。 複数組み合わせることで画像を描画できます。
引数:(X座標, Y座標, 色)
戻り値: なし

void screenTest(const Screen &screen) {
    // 座標(0, 0)に点を描画
    screen.DrawPixel(0, 0, Color::White);
}
Screen::DrawRect

画面に長方形を描画します。
引数:(X座標, Y座標, 横の長さ, 縦の長さ, 色)
戻り値: なし

void screenTest(const Screen &screen) {
    // 画像に100×200の長方形を描画
    screen.DrawRect(0, 0, 100, 200, Color::White);
}
Screen::Draw

画面に文字を描画します。ASCII文字(半角英数字,記号等)のみ対応です。
引数:(文字, X座標, Y座標, 文字の色, 背景の色)
戻り値: Y座標に+10した値(u32)

void screenTest(const Screen &screen) {

    screen.Draw("Hello", 0, 0, Color::White, Color::Black);

    // 色を指定しなくてもOK(通常は文字が白、背景が黒)
    screen.Draw("Hello", 0, 10);
}
Screen::DrawSysfont

画面に文字を描画します。日本語や全角文字も描画できます。
引数:(文字, X座標, Y座標, 文字の色)
戻り値: Y座標に+16した値(u32)

void screenTest(const Screen &screen) {

    screen.DrawSysfont("日本語表示", 0, 0, Color::Blue);

    // 色を指定しなくてもOK(通常は白色)
    screen.DrawSysfont("てきとー256", 0, 20);
}
Screen::ReadPixel

指定した画面の座標に描画されている色を取得します。
引数:(X座標, Y座標, 色(参照渡し), 右目のフレームバッファ(通常はfalse))
戻り値: なし

void screenTest(const Screen &screen) {
    Color color;

    // color変数に座標(0, 0)の色を格納する
    screen.ReadPixel(0, 0, color);

    // 右目のフレームバッファ
    screen.ReadPixel(0, 0, color, true);
}
Screen::Fade (CTRPF v0.7.1より追加)

画面の色を薄くします。
引数:(強度(0〜1))
戻り値: なし

void screenTest(const Screen &screen) {
    // 強度はfloatで指定可能
    screen.Fade(0.5);
}

思ったよりこのシリーズ続いてて驚いてる。
読んでくださりありがとうございました。

CTRPF関数まとめ Utils.hpp編

CTRPF関数まとめのUtils.hpp編です。

Utilsクラスには、便利な関数がたくさんあります。


目次:

Utils::Format

☆文字列をフォーマットします。

  • 引数: Utils::Format(const char* 文字列, ...)
  • 戻り値: std::string フォーマットされた文字列

使い方:

Utils::Format("Tekito_%d", 256); // Tekito_256

書式はprintf関数等と同じです。

Utils::ToHex

☆数値を16進数の文字列にします。

  • 引数:Utils::ToHex(u32 値)
  • 戻り値: std::string 0埋めされた16進数の8桁文字列(大文字)

使用例:

Utils::ToHex(65535); // 0000FFFF

Utils::Format("%08X", 65535)でも同様のことができます。

Utils::ToString

☆数値を文字列にします。

  • 引数:Utils::ToString(float 値, int 小数以下の値の数(指定しない場合は2))
  • 戻り値: std::string 文字列の数値

使用例:

Utils::ToString(256); // "256"
Utils::ToString(123.45); // "123.45"
Utils::ToString(99.99999, 1); // "99.9"

Utils::Random

☆ランダムな値を取得します。

  • 引数:無し
  • 戻り値: 0 〜 4294967295までのランダムな値

使用例:

Utils::Random() // 874879
Utils::Random() // 998723636
Utils::Random() // 12

Utils::Random

☆ Utils::Randomのオーバーロードです。
最小、最大値を指定し、その範囲の中からランダムな値を取得します。

  • 引数:Utils::Random(u32 最小値, u32 最大値)
  • 戻り値: 最小 〜 最大までのランダムな値

使用例:

Utils::Random(0, 10); // 0 〜 10までのランダムな値

Utils::FilePicker

☆SD内のファイルを選択するメニューを開きます。

  • 引数:Utils::FilePicker(std::string& 選択されたファイル名が出力される変数, std::string& 拡張子(指定しない場合は拡張子を限定しない))
  • 戻り値: 0: ファイルが選択された。 -1: ユーザーによって閉じられた。

使用例:

std::string out;
Utils::FilePicker(out); // メニューが開く

Utils::DirectoryPicker

☆SD内のフォルダを選択するメニューを開きます。

  • 引数:Utils::DirectoryPicker(std::string& 選択されたファイル名が出力される変数)
  • 戻り値: 0: ファイルが選択された。 -1: ユーザーによって閉じられた。

使用例:

std::string out;
Utils::DirectoryPicker(out); // メニューが開く

Utils::OpenInHexEditor (CTRPF v0.6.0より追加)

☆指定したアドレスをHexEditorで開きます。

  • 引数:Utils::OpenInHexEditor(u32 開くアドレス, HexEditorView HexEditorのメニュー(指定しない場合はByte。詳しくは下に書いておきます。))
  • 戻り値: HexEditorが閉じられたアドレス

使用例:

Utils::OpenInHexEditor(0x8000000); // アドレス0x8000000をHexEditorで開く
Utils::OpenInHexEditor(0x300000, HexEditorView::Dissasembler); // アドレス0x300000をHexEditorのDissasemblerで開く

HexEditorView

enum class HexEditorView
{
    Byte = 0,
    Integer = 1,
    Disassembler = 2
};

こんな感じでした。
またいつか。

Luma3DSのビルド方法(作り方)

日本語のLuma3DSの作成方法の記事が1つも無いので、作り方を軽く紹介します。今回はv9.1をビルドしていきます。

※この記事では、devkitProとPythonがインストールされていることを前提として説明していくので、まだインストールしていない方はまずこの2つをインストールしてください。

※11月18日追記
gitをインストールしないとfirmtoolがインストール出来ないので、gitも先にインストールしておいて下さい。

ビルドするために必要なもの

ビルドするために必要なものは以下の通りです。

Python
・devkitARM
・libctru
・makerom
・firmtool
・armips
・Git ※11月18日追記

必要なものをダウンロード/インストール

Luma3DSのソース

ここから Luma3DS-v9.1.zipをダウンロードし、展開してください。

libctru

libctruは、最新のバージョンじゃビルドできないので、ここから v1.5.0のものをダウンロードしてください。
ダウンロードしたものを展開し、中にある、includeフォルダ、libフォルダ、default_icon.pngを、C:\devkitPro\libctru\の中に配置してください。元々入っていたlibフォルダやincludeフォルダは消してください。
libctruはこれで完了です。

makerom

ここから makerom-v0.17-win_x86_64.zipをダウンロードし展開してください。展開して出てきたmakerom.exeをC:\devkitPro\tools\bin\の中に入れてください。(C:\devkitPro\tools\bin\のパスを通していない場合、パスを通してください。)
makeromはこれで完了です。

firmtool

ターミナルで、

pip install -U git+https://github.com/TuxSH/firmtool.git

と打ってください。
firmtoolはこれで完了です。

armips

ここから armips-v0.11.0-windows-x86.7zをダウンロードし、展開して、出てきたarmips.exeを、上でダウンロードしたLuma3DSのソースがある場所に貼り付けてください。
armipsはこれで完了です。

ビルドする

Luma3DSのソースの、Makefileがあるところでターミナルを開き、

make clean

と打って、終わるまで待ってください。
終わったら、

make

と打ってください。
少し長いですが、全て終わったらoutフォルダの中にboot.firmがあると思います。
これでLuma3DSのビルドは終了です。お疲れ様でした。

あとは好きにソースを弄ってビルドしてください。2回目以降は、"make clean"は必要ありません。

わからないことがあればコメントかTwitterでお願いします。

Twitter

CTRPF関数まとめ File.hpp編

CTRPFの関数について少し解説していこうと思います。いつまで続くかな?
間違いがあるかもしれませんが、ご了承ください。

目次:

Fileクラスとは?

Fileクラスにはファイルを操作する関数があります。(ファイル作成、削除、書き込み、読み込み etc...)
普通はファイルクラスはあまり使わないと思いますが、便利な機能がたくさんあるCTRPFを作りたい時には欠かせませんね!!!!!!!!!!!!!!!!!!!!!!!!!

Fileクラスの使い方

File::Create

ファイルを新規作成します。
戻り値: OPResult
使用例:

File::Create("file.txt"); //プラグインと同じフォルダに"file.txt"を作成する。
File::Create("../file.txt"); //プラグインがあるパスの1つ前のフォルダに"file.txt"を作成する。

File::Rename

ファイルの名前を変更します。
戻り値: OPResult
使用例:

File::Rename("file.txt", "file2.txt") //file.txtの名前を、"file2.txt"に変更する。

File::Exists

ファイルの存在確認をします。
戻り値: ファイルが存在したら1が返ってくる。存在しなかったら0が返ってくる。
使用例:

if(File::Exists("file.txt")) //プラグインと同じフォルダに"file.txt"があった場合

File::Open

ファイルを開きます。
戻り値: OPResult
使用例:

File file;
File::Open(file,"file.txt");//file.txtを開く

File::Close

ファイルを閉じます。
戻り値: OPResult
使用例:

File file;
File::Open(file,"file.txt");//file.txtを開く
file.Close();//file.txtを閉じる

File::Read

ファイルの中身を読みます。
戻り値: OPResult
使用例:

//あらかじめ、file.binに0xffffffffを書き込んでおく
File file;
u32 buf;
File::Open(file,"file.bin");//file.binを開く
file.Read((void*)&buf, sizeof(u32));//bufにfile.binの内容をu32のサイズ(4byte)分読み込む
file.Close();//file.binを閉じる
//buf = ffffffff;

File::Write

ファイルに書き込みます。
戻り値: OPResult
使用例:

File file;
u32 data = 0xffffffff;
File::Open(file,"file.bin");//file.binを開く
file.Write((void*)&data, sizeof(u32));//dataの内容をにfile.binに書き込む
file.Flush(); //後ほど説明
file.Close();//file.binを閉じる

File::WriteLine

ファイルに文字列を書き込みます。
自動で改行が追加されます。
戻り値: OPResult
使用例:

File file;
File::Open(file,"file.txt");//file.txtを開く
file.WriteLine("Hello World!");//flle.txtに"Hello World!"と書き込まれる。
file.Flush(); //後ほど説明
file.Close();//file.txtを閉じる

File::Seek

ファイルポインタの位置を変更します。
戻り値: OPResult
使用例:

//あらかじめ、file.binに、バイナリデータ 11 22 33 44と書いておく
File file;
u8 buf;
File::Open(file,"file.bin");
file.Seek(1);//ファイルポインタを1つ動かす
file.Read((void*)&buf,sizeof(u8));//bufには0x22が入れられる。
file.Close();

File::Tell

ファイルポインタの現在位置を取得します。
戻り値: u64 ファイルポインタの位置
使用例:

File file;
File::Open(file,"file.bin");
file.Seek(1);//ファイルポインタを1つ動かす
u64 fp = file.Tell(); // 上の行でポインタを1つ動かしたので、fp=1になる
file.Close();

File::Rewind

ファイルポインタの位置をファイルの最初の位置にする。
戻り値: なし
使用例:

File file;
File::Open(file,"file.bin");
file.Seek(1);//ファイルポインタを1つ動かす
file.Rewind(); //ファイルポインタを最初の位置にする
u64 fp = file.Tell(); //上の行でRewindしたため、0が返ってくる
file.Close();

File::Flush

ファイルを保存する。
File::Writeだけだと、実際にファイルに保存されないので、この関数で、実際にファイルを保存させる。(File::Create/Removeの場合は不要、WriteやWriteLineを使用した場合のみ)
戻り値: OPResult
使用例:

File file;
File::Open(file,"file.txt");
file.WriteLine("Hello");
file.Flush(); //保存する
file.Close();

File::GetSize

ファイルのサイズを取得する。
戻り値: u64 ファイルサイズ
使用例:

File file;
File::Open(file,"file.bin");
u64 size = file.GetSize();//ファイルサイズを取得
file.Close();

File::SetPriority

知らん

File::Dump

アドレスの値をダンプします
戻り値: OPResult
使用例:

File file;
File::Open(file,"file.bin");
file.Dump(0x100000,4);//0x100000のアドレスの値を4byte分ダンプ
file.Flush(); //保存
file.Close();

File::Inject

Dumpと逆のことをします。
ファイルの内容をメモリに書き込みます。
戻り値: OPResult
使用例:

//あらかじめ、file.binにバイナリデータ ff ff ff ffと書いておく
File file;
File::Open(file,"file.bin");
file.Inject(0x100000,4);//0x100000の値が0xffffffffになる
file.Close();

File::IsOpen

ファイルが開かれているか確認します。
戻り値: bool
使用例:

File file;
File::Open(file,"file.bin");
if(file.IsOpen())//ファイルがちゃんと開かれていたら
    OSD::Notify("File is Opening");
file.Close();

File::GetFullName

ファイルパスを取得します。
戻り値: std::string ファイルパス
使用例:

File file;
File::Open(file,"file.bin");
std::string name = file.GetFullName();//"/luma/plugins/0004000000155100/file.bin"が返ってくる
file.Close();

File::GetName

ファイル名を取得します。
戻り値: std::string ファイル名
使用例:

File file;
File::Open(file,"file.bin");
std::string name = file.GetName();//"file.bin"が返ってくる
file.Close();

File::GetExtension

ファイルの拡張子を取得します。
戻り値: std::string 拡張子
使用例:

File file;
File::Open(file,"file.bin");
std::string ets = file.GetExtension();//"bin"が返ってくる
file.Close();

File::File

コンストラク
File::Open以外の開き方
戻り値: なし
使用例:

File file1("file.bin"); // 1

File file2; 
File::Open(file2,"file.bin");//2

//1と2は同じ

終わりに

疲れた。
次回は無いかも。