←[第1章] | [第3章]→ |
DSプロテクトのライブラリのファイル構成は以下の通りです。
AMProtect.h | 検出関数プロトタイプを記述したヘッダーファイル。 |
AMProtectRa.a |
検出関数ライブラリ。 プロジェクトの「Libraries」に追加して使用できますが、可能であるならば、メモリ上の生存期間の短いオーバーレイモジュールへの組み込みを推奨します。 |
#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)() 型の関数アドレスを指定することができます。ここに指定された関数の実行後、処理が戻ります。
プログラム内での呼び出しの順番は自由ですが、容易に破られることのないよう、以下のルールを遵守するようにしてください。
アプリ側で、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章]→ |