ページ作成者:Nex
学校の授業がつまらなかったのでスマホから作成しました。
間違った情報が合ったら修正してください。
アクセス情報
| 項目 | 内容 |
|---|---|
| オンライン | ? |
| 今日のアクセス | ? |
| 昨日のアクセス | ? |
| 総合アクセス | ? |
CTRPluginFramework Action Replayコードタイプ (v0.8.0)
この解説は、CTRPluginFrameworkのソースコードを基に、各コードタイプの機能、引数、そして具体的な使用例を把握することを目的としています。
目次
基本的な概念
CTRPluginFrameworkのARコードエンジンは、いくつかの内部レジスタを持っており、これらを駆使して複雑なチートを実現することが可能です。コードを理解し、作成する上で、これらのレジスタの役割を把握することが非常に重要です。
レジスタの種類
- オフセットレジスタ (Offset Register)*1
- 2つ存在します (オフセット#1, オフセット#2)。
- コード実行開始時に0にリセットされます(非永続*2)。
- 主にメモリアドレスの基準点を保持するために使用します。
- デフォルトでアクティブなのはオフセット#1です。
- データレジスタ (Data Register)
- 2つ存在します (データ#1, データ#2)。
- コード実行開始時に0にリセットされます(非永続)。
- 計算の中間結果や、メモリから読み込んだ値を一時的に保持します。
- デフォルトでアクティブなのはデータ#1です。
- ストレージレジスタ (Storage Register)
- 2つ存在します (ストレージ#1, ストレージ#2)。
- 値が永続*3します。コードの有効・無効を切り替えても値は保持され続けます。
- コードの実行回数をカウントしたり、トグル(ON/OFF切り替え)の状態を保存したりするのに便利です。
- デフォルトでアクティブなのはストレージ#1です。
アクティブレジスタ
コードタイプの説明で単に「オフセット」「データ」と書かれている場合、それは現在アクティブに設定されているレジスタを指します。例えば、オフセット#1がアクティブな状態でオフセットを操作するコードを実行すると、オフセット#1の値が変更されます。アクティブレジスタは `DF`コード で切り替えることができます。
共有メモリページ (Shared Memory Page)*4
CTRPluginFrameworkは、プラグイン用に `0x01E81000` から `0x01E82000` までの4KBのメモリ領域を確保しています。この領域は全てのチートコードから読み書き可能で、コード間で複雑なデータを共有するために利用できます。
コードタイプ一覧
メモリ書き込み (Memory Writes)
基本的なメモリ操作です。指定したアドレスに値を書き込みます。アドレスは `[ベースアドレス + アクティブオフセット]` で計算されます。
- 0XXXXXXX YYYYYYYY - 32bit書き込み
- 説明
- アドレス `XXXXXXX + offset` に32bit値 `YYYYYYYY` を書き込みます。
- 例
// アドレス `0x00400000` に `0x63` (99) を書き込む。 00400000 00000063
- 1XXXXXXX 0000YYYY - 16bit書き込み
- 説明
- アドレス `XXXXXXX + offset` に16bit値 `YYYY` を書き込みます。
- 例
// アドレス `0x00400000` に `0x03E7` (999) を書き込む。 10400000 000003E7
- 2XXXXXXX 000000YY - 8bit書き込み
- 説明
- アドレス `XXXXXXX + offset` に8bit値 `YY` を書き込みます。
- 例
// アドレス `0x00400000` に `0xFF` (255) を書き込む。 20400000 000000FF
条件分岐 (Conditional Codes)
指定した条件が満たされない場合、次の `D0000000 00000000` (end if) または `D2000000 00000000` (full terminator) までのコードブロックをスキップします。
- 32bit条件分岐
コード 条件 3XXXXXXX YYYYYYYY Greater Than (より大きい) 4XXXXXXX YYYYYYYY Less Than (より小さい) 5XXXXXXX YYYYYYYY Equal To (等しい) 6XXXXXXX YYYYYYYY Not Equal To (等しくない)
- 説明
- デフォルトでは、`[XXXXXXX + offset]` から読み込んだ32bit値と、即値 `YYYYYYYY` を比較します。
- 例
// アドレス0x400000の値が10と等しいか? 50400000 0000000A // 等しい場合、アドレス0x400004に1を書き込む 00400004 00000001 // ifブロック終了 D0000000 00000000
- 16bit条件分岐
コード 条件 7XXXXXXX ZZZZYYYY Greater Than (より大きい) 8XXXXXXX ZZZZYYYY Less Than (より小さい) 9XXXXXXX ZZZZYYYY Equal To (等しい) AXXXXXXX ZZZZYYYY Not Equal To (等しくない)
- 説明
- `[XXXXXXX + offset]` から読み込んだ16bit値にビットマスク `~ZZZZ` を適用した結果と、即値 `YYYY` を比較します。
- ZZZZ (マスク)
- *5この値のビットが1になっている部分を無視します。マスクが不要な場合は `0000` にします。
- 例
// アドレス0x400000の値(16bit)が10と等しいか? 90400000 0000000A // 等しい場合、アドレス0x400004に1を書き込む 00400004 00000001 // ifブロック終了 D0000000 00000000
- 条件分岐モードの切り替え (`DF`コード'')
- 説明
- `DF``FFFFFF` XXXXXXXX コードで、条件分岐の比較対象を変更できます。
XXXXXXXX 比較モード `00000000` [アドレス] vs 即値 (デフォルト) `00000001` データレジスタ vs [アドレス] `00000002` 即値 vs データレジスタ `00000003` 即値 vs ストレージレジスタ `00000004` データレジスタ vs ストレージレジスタ
オフセットレジスタ操作 (Offset Codes)
- BXXXXXXX 00000000 - ポインタ*6読み込み
- 説明
- `[XXXXXXX + offset]` から32bit値を読み込み、その値を新しいアクティブオフセットの値として設定します。HPやMPなどのアドレスを保持するポインタをたどるのに非常に便利です。
- D300000Y XXXXXXXX - 即値セット
- 説明
- `Y`が`0`ならオフセット#1に、`1`ならオフセット#2に、即値 `XXXXXXXX` をセットします。
- DC000000 XXXXXXXX - 加算
- 説明
- アクティブオフセットの値に `XXXXXXXX` を加算します。
ループ (Loop Codes)
- C0000000 YYYYYYYY - ループ回数設定 (即値)
- 説明
- 次の `D1` コードまでのブロックを `YYYYYYYY` 回繰り返します。
- C1000000 00000000 - ループ回数設定 (データ#1)
- 説明
- データ#1の値をループ回数として設定します。
- C2000000 00000000 - ループ回数設定 (データ#2)
- 説明
- データ#2の値をループ回数として設定します。
- D1000000 00000000 - ループブロック終端
- 説明
- ループするコードブロックの終わりを示します。
- D0000000 00000001 - ループ中断
- 説明
- 現在のループを抜けます。`if`ブロックの内側で条件付きで使います。
- 例
- アドレス `0x09000000` から10回、4バイトずつ値を書き込む
// データ#1をアクティブに DF000001 00000000 // オフセット#1を0x09000000にセット D3000000 09000000 // データ#1に1をセット D5000000 00000001 // 10回ループ C0000000 0000000A // [offset]にデータ#1の値を書き込み、offset+=4 D6000000 00000000 // ループブロック終了 D1000000 00000000 // コード終了 D2000000 00000000
終端子 (Terminators)
D0000000 00000000 - ifブロック終了
- 説明
- 条件分岐ブロックの終わりを示します。ネスト(入れ子)も可能です。
D2000000 00000000 - フルターミネータ
- 説明
- 全てのブロック (if, loop) を終了させ、待機しているループを実行し、オフセットとデータの両レジスタをクリアします。一つのチートコードの区切りとして機能します。
D2000000 00000001 - コード即時終了
- 説明
- この命令が実行された瞬間に、後続の全てのコードの実行を中止します。エラー処理や、特定の条件を満たした場合にチートを停止させたい場合に使用します。
データレジスタ操作 (Data Register Codes)
| 操作 | コード | 説明 |
|---|---|---|
| 加算 | D4000000 XXXXXXXX | active_data += XXXXXXXX |
| D4000001 XXXXXXXX | data#1 = data#1 + data#2 + XXXXXXXX | |
| D4000002 XXXXXXXX | data#2 = data#2 + data#1 + XXXXXXXX | |
| 即値セット | D500000Y XXXXXXXX | Yで指定したデータレジスタに、即値 XXXXXXXX をセットします。 |
| メモリへ書き込み | D600000Y XXXXXXXX | 32bit |
| [XXXXXXXX + offset] = data *7~offset += 4 | ||
| D700000Y XXXXXXXX | 16bit | |
| [XXXXXXXX + offset] = data ~offset += 2 | ||
| D800000Y XXXXXXXX | 8bit | |
| [XXXXXXXX + offset] = data ~offset += 1 | ||
| メモリから読み込み | D900000Y XXXXXXXX | 32bit |
| data = [XXXXXXXX + offset] | ||
| DA00000Y XXXXXXXX | 16bit | |
| data = [XXXXXXXX + offset] | ||
| DB00000Y XXXXXXXX | 8bit | |
| data = [XXXXXXXX + offset] |
- Y (`D5`~`DB`コード) は、操作対象のデータレジスタを指定します。
- 0: アクティブなデータレジスタ
- 1: データレジスタ#1
- 2: データレジスタ#2
パッチ / データ埋め込み (Patch Code)
- EXXXXXXX YYYYYYYY - パッチコード
- 説明
- 指定したアドレス XXXXXXX に、後続の行に記述された `YYYYYYYY` バイト分のデータをコピー(上書き)します。XXXXXXX にはオフセットレジスタの値が加算されて、最終的な書き込み先アドレスとなります。
- 詳細
EXXXXXXX YYYYYYYY パッチを適用する基準となるアドレスを16進数で指定します。 書き込むデータの総バイト数を16進数で指定します。 - 使用例
- 詳細
- ゲームプログラムの特定の命令を書き換えたり、固定値をメモリに設定したりする場合に使用します。
記述例:
// アドレス 0x00123450 に、4バイトのデータ「0xDEADBEEF」を書き込む
E0123450 00000004
DEADBEEF 00000000
// アドレス 0x00300000 から8バイト分のデータを書き換える
E0300000 00000008
E1A00000 E1A00000 // nop命令を2つ書き込む
入力条件 (Input Codes)
- DD000000 XXXXXXXX - キー入力
- 説明
- `XXXXXXXX` で指定されたキーの組み合わせが押されている場合のみ、後続のコードブロック(次の D0000000 00000000 まで)を実行します。
- 詳細
キーの組み合わせ `(XXXXXXXX)` 押されているかを判定したいキーの値を16進数で指定します。複数のキーを指定する場合は、それぞれの値を足し算(OR)します。(例: L+R = `0x0200` + `0x0100` = `0x0300`) - 使用例
- 詳細
- 特定のボタンを押している間だけチートを有効にしたい場合に使用します。
記述例:
// Lボタンを押している間、所持金を999,999にする
DD000000 00000200
// Lボタンが押されているかチェック00400000 000F423F
// Lボタンが押されていれば、アドレス0x400000に値を書き込むD0000000 00000000
// 条件ブロックの終了
- DE00000Y AAAABBBB - タッチ座標
- 説明
- タッチスクリーンがタッチされており、その座標が指定範囲内にある場合のみ、後続のコードブロックを実行します。
- 詳細
座標軸 `(Y)` 範囲指定 `(AAAABBBB)` `0` = X座標
`1` = Y座標AAAA: 範囲の最大値
BBBB: 範囲の最小値 - 使用例
- 詳細
- 画面の特定の場所をタッチしたときにだけチートを有効にしたい場合に使用します。
記述例:
// 画面の右上(X:220-300, Y:20-100)をタッチしている間、無敵状態にする
// 1. X座標の判定
DE000000 012C00DC
// X座標が 220(DC) ~ 300(12C) の範囲かチェック// 2. Y座標の判定
DE000001 00640014
// Y座標が 20(14) ~ 100(64) の範囲かチェック00500000 00000001
// 条件を満たしていれば、無敵フラグをONにするD0000000 00000000
// Y座標の条件ブロック終了D0000000 00000000
// X座標の条件ブロック終了
浮動小数点モード (Floating Point Mode)
データレジスタの型設定 - DFFFFFE XXXXXXXX
- 説明
- アクティブなデータレジスタの解釈方法(型)を変更します。
- 変換: レジスタ内のビット表現そのものを変換します。例えば、00000010は浮動小数点数の`3.14`を整数の`3`に変換します(小数点以下は切り捨て)。
F1/F2/F3コードの演算モード - F0000001 XXXXXXXX
- 説明
- F1, F2, F3コードの演算を、整数演算か浮動小数点数演算か切り替えます。
XXXXXXXX モード 00000000 整数演算 (デフォルト) 00000001 浮動小数点数演算
レジスタ間操作 (Register Operations - DF)
| 操作 | コード | 説明 |
|---|---|---|
| アクティブレジスタ切替 | DF00000Y 0000000Z | Yで指定した種類のレジスタのうち、Z番を操作対象(アクティブ)に設定します。 |
| 同種レジスタ内コピー (オフセット/データ) | DF00000Y 0001000Z | オフセットレジスタ間、またはデータレジスタ間で値をコピーします。 Y=0: オフセット, Y=1: データ Z=0: #1 → #2 Z=1: #2 → #1 |
| ストレージ → データ | DF000002 0001000Z | ストレージレジスタの値をデータレジスタにコピーします。 Z=0: ストレージ#1 → データ#1 Z=1: ストレージ#2 → データ#2 |
| オフセット → データ | DF000000 0002000Z | オフセットレジスタの値をデータレジスタにコピーします。 Z=0: オフセット#1 → データ#1 Z=1: オフセット#2 → データ#2 |
| データ → オフセット | DF000001 0002000Z | データレジスタの値をオフセットレジスタにコピーします。 Z=0: データ#1 → オフセット#1 Z=1: データ#2 → オフセット#2 |
| データ → ストレージ | DF000002 0002000Z | データレジスタの値をストレージレジスタにコピーします。 Z=0: データ#1 → ストレージ#1 Z=1: データ#2 → ストレージ#2 |
- Y (レジスタ種別):
- 0: オフセットレジスタ
- 1: データレジスタ
- 2: ストレージレジスタ
- Z (レジスタ番号):
- 0: レジスタ #1
- 1: レジスタ #2
算術演算 (Arithmetic Operations)
メモリへの直接演算
:指定したメモリアドレスの値に対して直接、算術演算を行います。
| コード | 操作 |
|---|---|
| F1XXXXXXX YYYYYYYY | [XXXXXXX + offset] += YYYYYYYY |
| F2XXXXXXX YYYYYYYY | [XXXXXXX + offset] *= YYYYYYYY |
| F3XXXXXXX YYYYYYYY | [XXXXXXX + offset] /= YYYYYYYY |
- XXXXXXX: ベースアドレス
- YYYYYYYY: 演算に用いる値
- これらのコードは、F0`000001`コードで浮動小数点数モードに切り替えることが可能です。
データレジスタへの演算
:アクティブなデータレジスタの値に対して演算を行います。
| コード | 操作 | 説明 |
|---|---|---|
| F4000000 YYYYYYYY | data *= YYYYYYYY | 乗算 |
| F5000000 YYYYYYYY | data /= YYYYYYYY | 除算 |
| F6000000 YYYYYYYY | data &= YYYYYYYY | 論理積 (AND) |
| F7000000 YYYYYYYY | ''data | = YYYYYYYY'' | 論理和 (OR) |
| F8000000 YYYYYYYY | data ^= YYYYYYYY | 排他的論理和 (XOR) |
| F9000000 00000000 | data = ~data | ビット反転 (NOT) |
| FA000000 YYYYYYYY | data <<= YYYYYYYY | 左ビットシフト |
| FB000000 YYYYYYYY | data >>= YYYYYYYY | 右ビットシフト |
- dataはアクティブなデータレジスタを指します。
- YYYYYYYY: 演算に用いる値(シフトコードではシフトするビット数)
高度なコードタイプ
- FC000000 YYYYYYYY - メモリコピー (Memcopy)
- 説明
- オフセット#2に設定したアドレスをコピー元(Source)、オフセット#1に設定したアドレスをコピー先(Destination)として、`YYYYYYYY`バイトのデータを高速にコピーします。CPUのメモリ転送機能を直接利用するため、ループ処理で1バイトずつコピーするよりもはるかに高速です。
- 使用シナリオ
- 大規模なデータブロック(アイテムボックス全体、キャラクターのステータスブロックなど)を一度に複製または初期化する場合に有効です。
- バックアップしておいたデータを一瞬で書き戻す、といった使い方も可能です。
- 使用法
- 1. `D3`コードを使用して、オフセット#1にコピー先アドレス、オフセット#2にコピー元アドレスをそれぞれ設定します。
- 2. `FC`コードを実行してコピー処理を行います。
- FDYYYYYY ZZZZZZZZ - フック (Hook)
- 説明
- ゲーム内の特定の命令(フック先)を、強制的に別の命令(ジャンプ命令)に書き換えることで、処理の流れを乗っ取り、後続のカスタムARMアセンブリコード(フックコード)を実行させる、非常に強力なコードタイプです。
- 仕様詳細
- フック先アドレスは、現在アクティブなオフセットレジスタの値が使用されます。
- フックコードは、この`FD`コードの直後に`E0`コードと同様の形式で記述します。
- `YYYYYY`の値(フラグ)によって、フックの挙動を細かく制御できます。
- `0x1`フラグ: このフラグが無い場合、フック先からジャンプした後、元の命令を実行してからフックコードを実行します。このフラグが有る場合、元の命令は実行せず、即座にフックコードを実行します。
- `0x10`フラグ: このフラグが無い場合、フックコードの実行後、`lr`レジスタを使って元の処理フローに戻ります。このフラグが有る場合、`lr`を使わずにフックコードを実行しっぱなしにします(通常は使いません)。
- フックを無効化するには、`FD`の代わりに`FD1`を使い、`ZZZZZZZZ`にフック先アドレスを指定します。
- 使用シナリオ
- 特定の関数が呼び出されたタイミングで独自の処理を実行する(例:レベルアップ時にステータスを最大にする)。
- ダメージ計算処理に割り込み、計算結果を常に0にしてからゲームの処理に戻すことで、無敵状態を実現する。
- 注意点
- このコードタイプを使いこなすには、ARMアセンブリに関する深い知識が必須です。
- フックを解除せずにゲームを終了したり、不正なコードを実行したりすると、ゲームがフリーズする原因になります。
- FE00XXXX YYYYYYYY - メモリ検索 (Memsearch)
- 説明
- 現在アクティブなオフセットを開始アドレスとして、`YYYYYYYY`バイトの範囲内で、後続に記述されたパターンデータを検索します。
- 動作
- パターンが見つかった場合、アクティブオフセットレジスタの値が、パターンが見つかったアドレスに更新されます。
- パターンが見つからなかった場合、このコードは条件分岐の「偽(False)」として扱われ、後続のifブロック(`D0`まで)をスキップします。
- 使用シナリオ
- ゲームの起動毎にアドレスが変わる動的なデータ(プレイヤー情報など)を、特定の固定パターン(プレイヤーIDなど)を手掛かりに検索する。
- 特定のアイテムIDをアイテムボックス内から探し、見つかった場合にその個数を変更する。
- 例
- D3000000 0A000000
FE000002 00000400
001A0000 00000000
DC000000 00000004
D6000000 00000000 // dataレジスタの値(ここでは0)を書き込む
D5000000 00000063 // dataレジスタに99をセットして、次のD6で書き込むという方法もある
D0000000 00000000
- FFXXXXXX YYYYYYYY - 乱数生成
- 説明
- `XXXXXX`(最小値)と`YYYYYYYY`(最大値)の範囲で乱数を生成し、現在アクティブなデータレジスタ (`data`, `data#1`, `data#2`のいずれか) に格納します。
- 使用シナリオ
- 敵からのドロップアイテムをランダムに決定する処理に介入し、レアアイテムを強制的にドロップさせる。
- カジノのルーレットなど、ランダム性が絡むイベントの結果を操作する。
- F0F00000 00000000 - カスタムASMルーチン
- 説明
- 後続に記述されたARMアセンブリコードを、コードが記述されたその場で直接実行します。フックとは異なり、特定のタイミングを待たずに即時実行されるのが特徴です。
- 実行前のレジスタ状態
- r0-r3: 引数・戻り値・一時利用*10
- r4-r9: ポインタレジスタ*11
- `r4`: オフセット#1へのポインタ
- `r5`: オフセット#2へのポインタ
- `r6`: データ#1へのポインタ
- `r7`: データ#2へのポインタ
- `r8`: ストレージ#1へのポインタ
- `r9`: ストレージ#2へのポインタ
- r10: 共有メモリページ (`0x01E81000`) へのポインタ
- r11 (fp): フレームポインタ*12
- r12 (ip): プロシージャコール間スクラッチレジスタ*13
- sp (r13): スタックポインタ*14
- lr (r14): リンクレジスタ*15
- pc (r15): プログラムカウンタ*16
- 注意点
- フック同様、ARMアセンブリの知識が必須であり、非常に高度なコードタイプです。
- レジスタを不用意に書き換えると、ゲームがクラッシュする危険性が非常に高いため、各レジスタの役割を正確に理解する必要があります。
キーパッドコード一覧
`DD`コードで使用します。複数のキーは値を足し合わせる(OR演算*17)ことで表現します。
| 値 | キー | 値 | キー |
|---|---|---|---|
| `0x1` | A | `0x4000` | ZL (New 3DS) |
| `0x2` | B | `0x8000` | ZR (New 3DS) |
| `0x4` | Select | `0x100000` | タッチパッド |
| `0x8` | Start | `0x1000000` | C-Stick 右 |
| `0x10` | 十字キー右 | `0x2000000` | C-Stick 左 |
| `0x20` | 十字キー左 | `0x4000000` | C-Stick 上 |
| `0x40` | 十字キー上 | `0x8000000` | C-Stick 下 |
| `0x80` | 十字キー下 | `0x10000000` | スライドパッド 右 |
| `0x100` | R | `0x20000000` | スライドパッド 左 |
| `0x200` | L | `0x40000000` | スライドパッド 上 |
| `0x400` | X | `0x80000000` | スライドパッド 下 |
| `0x800` | Y |
コメント
自由にコメントして下さい。
- メモリ検索(Memsearch)でどんなチートコードを作れますか? -- 2025-07-27 (日) 18:01:42
- コメントありがとうございます
簡単に言ったら特定のアイテムIDがアイテム所持欄にある場合とか、プレイヤー1~4の中に特定の名前(テスト1)がいた場合にそのテスト1のストーカーチートとか作れます。
プレイヤー1,2,3,4いちいち切り替えず名前指定でできるって言うのが利点ですね。
8100000がプレイヤー1のベースアドレスだとして+0から名前が格納されててx座標が+34、yが+3Cにあってデータ構造が0x100(256)だと仮定した場合
B8100000 00000000
FE000008 00000100
30B930C6 003130C8
D9000001 00000034
D9000002 0000003C
これで名前がテスト1の場合のみData#1にx座標が、Data#2にy座標が格納されます。
FEはifブロックなのでD0でifを抜けれます。 -- Nex 2025-07-27 (日) 23:15:13 - 浮動小数点モード (Floating Point Mode)ってどんな使い方ができますか -- 2025-07-28 (月) 20:55:01
ㅤ-- Nex 2025-07-29 (火) 01:42:20
Floatについて
コメントありがとうございます
浮動小数点モードは、ゲーム内で座標や速度、カメラの角度など、小数で管理されている値を正確に操作したい場合に役立ちます。何故浮動小数点モードが必要か?
例えば、キャラクターのX座標が`123.45`という値だったとします。これはメモリ上では `42F6E666` (16進数) のようなビットパターンで表現されています。
- 整数モードのまま `F1`コードで `1` を足してしまうと、`42F6E666 + 1 = 42F6E667` となり、これは浮動小数点数に直すと `123.45001` のような、意図しない微小な変化にしかなりません。これがいわゆる「F1コードで座標の数値増やしてるのにマップの座標の中心で止まる」現象の原因です。
- 浮動小数点モードを有効にすると、`F1`コードで `1.0` を足す計算(`123.45 + 1.0`)が正しく行われ、結果として座標が `124.45` になります。
具体的な使用例
例1:壁抜けチート(YボタンでZ座標を+1.5する)
:キャラクターのZ座標(高さ)が、ポインタ `0x08100000` の指す先からオフセット `+0x3C` の場所にあるとします。// ポインタを読み込んでオフセットにセット
B08100000 00000000
// Yボタンが押されているかチェック
DD000000 00000800
// F1コードを浮動小数点モードに切り替える
F0000001 00000001
// [オフセット + 0x3C] の値に 1.5 を加算
// 1.5を16進数(float)に変換すると 3FC00000
F100003C 3FC00000
// ifブロック終了
D0000000 00000000
このように、整数では扱えない `1.5` のような半端な値を正確に加算できます。例2:データレジスタを使った座標の微調整
:`DFFFFFE`コードを使うと、データレジスタ自体を浮動小数点数として扱うことができます。// データ#1を浮動小数点モードに設定(整数からの変換も行う)
DFFFFFE 00000011
// データ#1に 0.5 をセット
// 0.5(float) -> 3F000000(hex)
D5000001 3F000000
// データ#1の値を[0x08100034]の座標に加算する
// この例ではD4にアドレス指定はないですが、もしあったらという仮定です
D4000001 08100034
// データ#1を整数モードに戻す
DFFFFFE 00000010
まとめ
- 座標、速度、角度、カメラのズーム率など、ゲーム内の滑らかな動きを実現している値は、ほとんどが浮動小数点数です。
- これらの値を正確に操作するには、F0 や DF コードを使って浮動小数点モードに切り替える必要があります。
- メモリコピーってどんなことできますかね -- 2025-07-31 (木) 12:13:44
- 電波人間等で例えたら確か82XXXXXあたりにパーティメンバー1のデータがあってデータ構造は確か0xFC (電波人間ボックス内の電波人間は0x100)だったので、パーティメンバー1人目のデータ構造の始まりからFCバイト分2人目のデータ構造の始まりにコピーしたらキャラ複製とか楽にできます。
単純なコピーならループでC9,C6,DCみたいにやらずコード短縮になる、のかな。 -- Nex 2025-07-31 (木) 15:59:59 - ボタンを押して一瞬だけ値を書き換えるコードを作りたいのですがどうすればよいでしょうか(長押しで書き換え続けない) -- 2025-08-06 (水) 21:47:53
- ghidraでチートを作成する方法を教えてください。 -- 2025-08-06 (水) 21:52:57
- すみません。資格試験を控えているので返答が遅くなりました。
ㅤ-- Nex 2025-08-07 (木) 00:57:57
Storageを使った1度のみ実行するコード
アクションリプレイコードの解説
DD000000 00000001
DFFFFFFF 00000003
50000000 00000000
00999999 000003E7
D5000001 00000001
DF000002 00020000
D2000000 00000000
コードの概要このコードは、内部に「実行済みフラグ」を持つことで、長押ししても最初の1回しか書き込み処理が実行されないように設計されています。Aボタンが押されると、まずフラグをチェックし、まだ実行されていなければ処理を行い、フラグを立てます。次にAボタンが押されたときは、フラグが立っているため処理がスキップされる、という仕組みです。コードの詳細解説コード 処理内容の解説 平易な解説 DD000000 00000001 キー入力条件
Aボタン(0x1)が押されていなければ、後続のifブロックをスキップします。もし、Aボタンが押されていたら、次の処理へ進みます。 DFFFFFFF 00000003 条件分岐モード変更
次のif文の比較方法を「即値 vs ストレージレジスタ」に変更します。比較のやり方を変えます。(専門的な設定です) 50000000 00000000 32bit一致比較
「0x0 == ストレージレジスタ[0]」を評価します。真でなければifブロックをスキップします。もし、内部の記録場所(フラグ)が0なら、次の処理へ進みます。 00999999 000003E7 32bit書き込み
アドレス「0x00999999」に値「0x000003E7」を書き込みます。目的の値を書き込みます。
(これがコードの本体です)D5000001 00000001 データレジスタ設定
一時的な作業用レジスタに「1」をセットします。内部の記録場所の値を「1」に書き換える準備をします。 DF000002 00020000 レジスタ操作
作業用レジスタの値をストレージレジスタ[0]にコピーします。内部の記録場所(フラグ)の値を「1」に設定します。 D2000000 00000000 フルターミネータ
全てのif文ブロックを終了する。OffsetやDataレジスタはクリアされるが、Storageレジスタは維持されます。「もし~なら」の処理はここまでです。 動作の仕組みこのコードは、ストレージレジスタ#1を「実行済みフラグ」として利用しています。初回Aボタンプレス時 1.Aボタンが押されているので、処理が続行されます。 2.内部の記録場所(ストレージレジスタ)の値は初期状態の0です。 3.「記録場所の値が0か?」というチェックが真(True)になるため、書き込み処理が実行されます。 4.最後に、記録場所の値が1に書き換えられます。 Aボタンを押し続けている間、または2回目以降のプレス時 1.Aボタンが押されているので、処理が続行されます。 2.この時点で、内部の記録場所の値は1になっています。 3.「記録場所の値が0か?」というチェックが偽(False)になるため、書き込み処理はスキップされます。 ㅤ-- Nex 2025-08-07 (木) 01:12:57Ghidraについて
Ghidraを使ったチート作成
解析の大きな流れ
Ghidraを使ったチート作成は、おおよそ以下の流れで進めます。
- 準備: Ghidraをインストールし、解析したいゲームの実行ファイル(.codeセクションなど)を用意します。
- プロジェクト作成: Ghidraで新しいプロジェクトを作り、用意したファイルをインポートします。
- 解析設定: ProcessorとBase Addressを正しく設定します。(ここが最も重要です)
- コード解析: 逆アセンブルされたコードを読み解き、目的の処理を探します。
- デバッガ連携: デバッガで当たりをつけたアドレスをGhidraで詳細に調べます。
- チートコード化: 特定した命令を無効化したり、書き換えたりするアクションリプレイコードを作成します。
Ghidraでの解析手順(詳細)
ファイルをインポートする際、Ghidraはどのような設定で解析するかを尋ねてきます。
項目 設定値 説明 Processor ARM:LE:32:v6 3DSのCPUアーキテクチャに合わせた設定です。
これを正しく選ぶことで、機械語が人間にとって読みやすいアセンブリ言語に正しく変換(逆アセンブル)されます。Base Address 0x100000 3DSの実行ファイルの標準的な開始アドレスです。
これを設定しないと、Ghidra上のアドレスとゲーム内の実際のアドレスがずれてしまい、解析が非常に困難になります。必ず設定してください。これらの設定が完了すると、Ghidraは解析を開始します。
目的のコードを特定する方法
- Ghidraでの静的解析
- `- 文字列検索:` メニューの「Search」→「For Strings...」から、「HP」や「Money」といったゲーム内の文字列を検索し、その文字列が使われている場所から関連する処理を推測します。
- `- 相互参照(X-Refs):` 特定の関数や変数を右クリックし、「Show References to」を選ぶと、その場所を参照している全てのコードを一覧表示できます。これにより、値がどこで読み書きされているかを追跡できます。
- デバッガとの連携(動的解析)
- Ghidraだけでは、「今、どのコードが実行されているか」はわかりません。そこでデバッガの出番です。
- 1. メモリサーチで値を特定: まず、HPなどの値が格納されているメモリアドレスを特定します。
- 2. ウォッチポイントを設定: 3DSのデバッガ(Luma3dsのデバッガ機能など)を使い、特定したアドレスに「書き込みウォッチポイント(Write Watchpoint)」を設定します。
- 3. ゲーム内で値を変動させる: ゲーム内でダメージを受けるなどしてHPを変動させると、ウォッチポイントを設定したアドレスに書き込みが発生した瞬間にゲームが停止します。
- 4. アドレスを特定: ゲームが停止した時点でのプログラムカウンタ(PC)の値をメモします。この値が、まさにHPを書き換えた命令のアドレスです。
- 5. Ghidraで確認: メモしたアドレスをGhidraの「Go To」(Gキー)で検索すると、該当する命令にジャンプできます。右側の「Decompiler」ウィンドウを見れば、C言語に近い形で処理内容を理解することも可能です。
チートコードへの変換例えば、デバッガ連携によって「HPを1にする」という処理が以下の命令だと特定できたとします。
| 002F0C80 | MOV R0, #1 |
この命令を無効化するには、この命令があるアドレス `002F0C80` を、何もしない命令(NOP)で上書きします。
ARMにおけるNOP命令の一例は `MOV R0, R0` で、機械語では `E1A00000` となります。これをアクションリプレイコードにすると、以下のようになります。
002F0C80 E1A00000
- ARMアセンブリの詳しい解説をして欲しいのですが良いでしょうか? -- 2025-08-09 (土) 13:51:31
- ghidraの静的解析が上手くいきません。対象ゲームのcode.binをインストールして設定値を例の通りにしました。その後code.binをダブルクリックしてAnalyze?にYesと答えanalyzeを押すとリストが出てきました。その後search.For Stringsを押して特に設定を変えずにSeacrhを押すとアドレスに余りに抜けが多く目的のアドレスが何処にあるのか全く分からない状況です。 -- 2025-08-11 (月) 14:49:17
- アセンブリは動画で解説してる人がいます。
https://www.youtube.com/watch?v=jTOL1ZkLI6c
gm9で正しく抽出したらcode.binではなく{titleID}.dec.codeになるはずです。exefsに直接入ってるものは圧縮されたものなのでTMD file options...でExtractしましょう -- Nex 2025-08-11 (月) 16:31:45 - {titleID}.dec.codeにして試しましたが、以前と変わらず9996items.{titleID}.dec.code.Minimum5 Align1でした。アドレスがスカスカです。 -- 2025-08-11 (月) 17:39:48