←[第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つのプログラム内で必ず3種類の関数をセットで使用する必要があります。

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 であるものをそれぞれ1回ずつ呼び出すようにしてください(これを1セットと呼称する)
  2. 1セットにおける A1, A2, A3 それぞれの検出処理は、動作テストを容易にするため、同一のものを使用することを推奨します。
  3. AM_IsMagiconA1, AM_IsNotMagiconA1 のように表裏となる関数の併用を推奨します(AM_IsMagiconA1,A2,A3 だけ、AM_IsNotMagiconA1,A2,A3 だけの使用は推奨しません)。
  4. 3種類の関数を一つにまとめて1つの関数にするようなラップ関数型の実装は、強度面で非常に問題があるため、絶対に行わないようにしてください。
  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. のラップ関数に相当する実装であるため、決して採用しないようにしてください。

// ※※※※※ 採用禁止 ※※※※※

//
// マジコン検出関数
//
// 3種類の検出関数を一まとめにするラップ関数型実装のため、
// 実際にこの方法を用いるべきではない。
//
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章]→