←[第1章] | [第3章]→

# 2 関数リファレンス

## 2.1 ファイル構成

DSプロテクトのライブラリのファイル構成は以下の通りです。

AMProtect.h | 検出関数プロトタイプを記述したヘッダーファイル。
AMProtectRa.a | 検出関数ライブラリ。 プロジェクトの「Libraries」に追加して使用できますが、可能であるならば、メモリ上の生存期間の短いオーバーレイモジュールへの組み込みを推奨します。

## 2.2 AM_Is(Not)MagiconA*

## 構文

`#include "AMProtect.h"
// 検出された時に真を返し、指定した関数を実行する関数
u32 AM_IsMagiconA1( void(*func)() );
u32 AM_IsMagiconA2( void(*func)() );
u32 AM_IsMagiconA3( void(*func)() );
// 検出されなかった時に真を返し、指定した関数を実行する関数
u32 AM_IsNotMagiconA1( void(*func)() );
u32 AM_IsNotMagiconA2( void(*func)() );
u32 AM_IsNotMagiconA3( void(*func)() );
（これらの関数はFINALROM版ではマクロになります。DEBUG,RELEASE版では関数となります。）
`

## 引数

void(*func)() | 検出された（されなかった）時に実行したい void(*func)() 型の関数アドレスを指定します。 指定した関数の実行後には、元の処理に復帰します。 NULLを指定すると、そのまま検出の有無を意味する値が返ります。 引数にはNULLを指定することができますが、強度を得るために何らかの関数を指定することを推奨します。

## 返り値

検出結果として、u32 型の真(0以外)、偽(0)のいずれかを返します。

## 説明

マジコン・エミュレータといった、ニンテンドーDS実機以外での動作を検出する関数です。対応マジコン・エミュレータ、公式開発環境への対応については 1.2.1 検出確認済みマジコン、1.2.2 検出確認済みエミュレータ を参考にしてください。

プロテクトを使用する際は、１つのプログラム内で必ず３種類の関数をセットで使用する必要があります。

`1) AM_IsMagiconA1() または AM_IsNotMagiconA1() // マジコン全般・一部エミュレータ検出関数
この関数の内部では LockID を使用しています。
2) AM_IsMagiconA2() または AM_IsNotMagiconA2() // エミュレータ検出関数
3) AM_IsMagiconA3() または AM_IsNotMagiconA3() // 実際には検出を行わないダミー関数
`

全ての関数グループはスレッドセーフではありません。

AM_IsMagiconA*() を呼び出した場合は、検出された時に引数に指定された関数が実行され、真の値が返ります。検出されなかった時には引数に指定された関数は実行されず、偽の値が返ります。

AM_IsNotMagiconA*() を呼び出した場合は、検出されなかった時に引数に指定された関数が実行され、真の値が返ります。検出失敗時には引数に指定された関数は実行されず、偽の値が返ります。

それぞれの検出関数には、検出された時、または検出されなかった時に実行する void(*func)() 型の関数アドレスを指定することができます。ここに指定された関数の実行後、処理が戻ります。

## 使い方

プログラム内での呼び出しの順番は自由ですが、容易に破られることのないよう、以下のルールを遵守するようにしてください。

1. 検出処理を組み込み際には、関数名称サフィックスが A1, A2, A3 であるものをそれぞれ１回ずつ呼び出すようにしてください（これを１セットと呼称する）
2. １セットにおける A1, A2, A3 それぞれの検出処理は、動作テストを容易にするため、同一のものを使用することを推奨します。
3. AM_IsMagiconA1, AM_IsNotMagiconA1 のように表裏となる関数の併用を推奨します（AM_IsMagiconA1,A2,A3 だけ、AM_IsNotMagiconA1,A2,A3 だけの使用は推奨しません）。
4. ３種類の関数を一つにまとめて１つの関数にするようなラップ関数型の実装は、強度面で非常に問題があるため、絶対に行わないようにしてください。
5. 弊社提供関数は、可能であればオーバーレイモジュールにインクルードし、オーバーレイモジュールから呼び出すことを推奨します。

## 注意

アプリ側で、OS_GetLockID() 関数を呼び出して OS_LOCK_ID_ERROR が返る状態で、検出関数 AM_IsMagiconA1, AM_IsNotMagiconA1 のいずれかを呼び出した場合、ビルドオプションによって挙動が異なります。

ビルドオプション | 動作環境 | 実行時の挙動
--- | --- | ---
DEBUG | 正規品 | フリーズ
デバッガ（IS-NITRO-DEBUGGER） | 停止・ログ表示　(AMProtect.h:91 Panic:lock ID get error.)
マジコン | フリーズ
RELEASE | 正規品 | フリーズ
デバッガ（IS-NITRO-DEBUGGER） | 停止・ログ表示　(AMProtect.h:91 Panic:lock ID get error.)
マジコン | フリーズ
FINALROM | 正規品 | 正規判定
デバッガ（IS-NITRO-DEBUGGER） | 不正判定
マジコン | 不正判定

## サンプル

このサンプルは、3 反映方法のガイドライン を参考にした一例です。各自プログラムに沿った実装方法を考案してください。

以下にオーバーレイモジュールを用いた使用例を挙げます。3.5.5 バグ誘発型プロテクトを参考にした実装です。

> `//
> // マジコン検出処理を組み込んだ通常処理関数
> //
> // 効果：不正利用時のみ、この関数を通過する度に
> // 　　　512KBのメモリリークが発生する
> // 　　　メモリリークが累積するとフリーズする
> // 　　　ゲーム中何度も通過する処理（画面切り替えなど）に組み込む
> //
> u32 HogehogeFunc(void)
> {
> // （中略）
> char *pTemp = NULL;
> // （中略）
> // オーバーレイでライブラリを含むモジュールを呼び出す
> FS_LoadOverlay(MI_PROCESSOR_ARM9, FS_OVERLAY_ID(OVERLAY_PROTECT));
> if (AM_IsMagiconA1(NULL)) {
> if (NULL == pTemp) {
> pTemp = new char[0x80000];
> }
> }
> // （中略）
> if (AM_IsMagiconA2(NULL)) {
> if (NULL == pTemp) {
> pTemp = new char[0x80000];
> }
> }
> // （中略）
> if (AM_IsMagiconA3(NULL)) {
> if (NULL == pTemp) {
> pTemp = new char[0x80000];
> }
> }
> // オーバーレイとして読み出したライブラリをアンロード
> FS_UnloadOverlay(MI_PROCESSOR_ARM9, FS_OVERLAY_ID(OVERLAY_PROTECT));
> // （中略）
> }
> `

以下は3.5.2 メニュー型プロテクトを参考にした実装です。

> `// 正常な初期化を実施する関数
> void Init(void)
> {
> gStateA = new gStateA;
> gStateB = new gStateB;
> gStateC = new gStateC;
> }
> // 不正な初期化を実施する関数
> void InitDummy(void)
> {
> gStateA = new gStateA;
> gStateB = new gStateB_Dummy; // 不正な初期化
> gStateC = new gStateC;
> }
> // （中略）
> //
> // マジコン検出処理を組み込んだ初期化関数
> //
> // 効果：不正利用時のみ、誤った初期化を実施する。
> // 　　　ここではクラスの初期化を行っているが、
> // 　　　オーバーレイ切り替えでも同様の効果が得られる。
> //
> u32 FoofooInitFunc(void)
> {
> // （中略）
> if (!AM_IsNotMagiconA1(Init)) {
> InitDummy();
> }
> AM_IsMagiconA2(InitDummy);
> AM_IsMagiconA3(InitDummy);
> // （中略）
> }
> `

## サンプル（悪例）

以下に示すような実装は、使い方 4. のラップ関数に相当する実装であるため、決して採用しないようにしてください。

> `// ※※※※※ 採用禁止 ※※※※※
> //
> // マジコン検出関数
> //
> // ３種類の検出関数を一まとめにするラップ関数型実装のため、
> // 実際にこの方法を用いるべきではない。
> //
> u32 isMagiconPresent(void)
> {
> u32 r;
> r += AM_IsMagiconA1(NULL);
> r += AM_IsMagiconA2(NULL);
> r += AM_IsMagiconA3(NULL);
> return r;
> }
> // （中略）
> // マジコン検出結果を格納するフラグ
> bool gIsMagiconFlag = false;
> // （中略）
> //
> // マジコン検出処理を組み込んだ通常処理関数
> //
> u32 HogeFunc(void)
> {
> // （中略）
> // マジコン検出関数を呼び出し、
> // 検出結果格納フラグに検出結果を格納する
> if (isMagiconPresent()) {
> gIsMagiconFlag = true;
> }
> // （中略）
> }
> // ※※※※※ 採用禁止 ※※※※※
> `

←[第1章] | [第3章]→