保護技法
このセクションでは、JSDefender で使用される保護技法について学習できます。
ブール リテラルの置き換え
この技法は、true
と false
のブール リテラル値を、等価だがやや複雑な式に置き換えるものです。
コンソールのクローキング
この保護技法では、保護されたコードが console
オブジェクトのメソッド(console.log
、console.info
など)を呼び出すときに、その保護されたコードがコンソールで情報を表示できないようにします。重要:この変換は console
関連メソッドの呼び出しをコードから削除するわけではなく、それらのメソッドを抑制するだけです。
定数引数の難読化
この技法は、関数の引数に含まれる整数リテラルを、JSDefender Runtime に宣言された特別な保護条件を使用する条件式に置き換えるものです。次の関数呼び出しがあるとします。
displayNumbers(1, 10);
上記のコードは、この保護技法により、次のような保護されたバージョンに置き換えられます。
displayNumbers(Ecrt.wr(123) ? 1 : 3, Ecrt.wr(14) ? 7: 10);
日付ロック
この保護技法は、現在の日付が特定の期間に含まれるかどうかをテストするコードを保護対象ソースに差し込むものです。含まれる場合は、コードが正常に実行されます。含まれない場合は、コードが日付テスト フェーズの直後に中断します。
debugger ステートメントの削除
この保護技法は、コードから JavaScript の debugger
ステートメントを削除するものです。
開発者ツールのブロック
この保護技法は JSDefender Runtime にコードを追加します。これによって開発者ツール パネルがブラウザーで開かれているかどうかを検出します。ブラウザーで開かれている場合は、保護スクリプトがプログラムをブレークポイントで連続的にストップさせ、ハッカーがデバッグできないようにします。プログラムを実行し続けるためには、ハッカー(攻撃者)が開発者ツール パネルを閉じる必要があります。事前に設定されているストップの回数に達すると、JSDefender Runtime はコードの無効化を宣言します。
式シーケンスの難読化
この保護技法は、コード内の隣接する式ステートメントを収集し、それらを 1 つの式シーケンスとして結合するものです。
元のコード:
(function x() {
y = 3;
z = 4;
return y*z;
})()
難読化されたコード:
(function x() {
return y=3, z=4, y*z;
})()
制御フローの保護
この技法は、コード内の制御フローのステートメント(if
ステートメントとループ)を分析し、それらを 1 つの有限オートマトンに変換します。この難読化は、特に if
ステートメントとループが入れ子になっている場合に、コードの制御フローを分析し難くします。変換時、エンジンはフェイクの条件コードを差し込むことができます。
関数宣言の並べ替え
この保護技法は、ソース コードから関数宣言を収集し、それらを宣言のスコープ内で散在させます。
グローバル オブジェクトの非表示
window
、navigator
、Object
、String
、setTimeout
、その他多くの頻繁に使用されるグローバル オブジェクトや関数は、コードのリバースエンジニアリングに有用なヒントを与えます。グローバル オブジェクトを非表示にするという保護技法では、これらのオブジェクトの間接参照を使用し、保護されたオブジェクト内で表示しないようにします。攻撃者が見る内容は、グローバル オブジェクトの識別子ではなく、改変された意味のない名前です。
整数リテラルの置き換え
この技法は、整数リテラルを同じ値となる式に置き換えるものです。置き換えでは 10 進、8 進、16 進のリテラルの組み合わせが使用されるため、元の値は検出できません。この置き換え(変換)を適用する整数の範囲を設定できます。また、その他すべての整数リテラルを変換する基数(2 、10、16、8)を設定することもできます。
ローカル宣言名の改変
この技法はローカル宣言の識別子(変数、関数、クラスなど)の名前を変更します。いくつかの名前改変方法から選択できます。JSDefender は、新しく作成された名前が既存の名前と競合しないように管理します。また、グローバル宣言名(保護済みコードの外部で宣言されている識別子)は変更されません。
プロパティの間接参照
JSDefender は、プロパティに直接的にアクセスする式を、プロパティに(インデックスまたは計算により)間接的にアクセスする式に変更します。例を見てみましょう。
var x = {
get: function() {
return x.myProp;
}
}
上記コードは、保護すると、次のようになります。
var x={
["get"]: function(){
return x["myProp"];
}
}
プロパティの散在化
オブジェクト リテラル式の割り当てを複数の代入ステートメントに変換することで、それらの割り当てを判読し難くします。
元のコード:
let x = {
w: 1,
z: { x: 3, y: 4},
q: "hello"
}
プロパティ散在化後のコード:
let IcwE = {};
IcWE.w = 1;
IcwE.z = {};
IcwE.z.x = 3;
IcwE.z.y = 4;
IcwE.q = "hello";
let x = IcwE
文字列リテラルの抽出
JSDefender はコードから文字列リテラルを抽出し、それらをエンコードした形で定数変数に割り当てます。次に、元の文字列リテラルは対応する変数の参照に置き換えられます。例を見てみましょう。
var greet = "hello";
var planet = "world";
上記コードは、保護すると、次のようになります。
const kK1K=IcZK.xb("{v\x7F\x7F|");
const E7TK=IcZK.xb("d|a\x7Fw");
var greet=kK1K;
var planet=E7TK;
自己防御型の保護
この技法は関数宣言、関数式、オブジェクトおよびクラスのメソッド宣言を 1 つの保護用関数としてラップするものです。この関数は、その本文(したがって元の関数のような構文)の改ざんを検出します。関数の本文に 1 つのスペースや 1 つの改行文字を挿入するだけでも、その関数が正常に実行されなくなります。
このような改ざんを検出する保護は、実行時のコストが高くつきます。この保護は、コード内で一度しか実行されない関数や即時関数に対しては非常に安価ですが、頻繁に呼び出される関数に対してはコストが高くつきます。
この保護を有効にした場合、JSDefender は、一度実行されたものとして認識された即時関数にのみこの保護を適用します。
変数のグループ化による保護
この技法は変数の宣言と初期化を分割し、宣言部を宣言のスコープの最後の部分に移動します。例を見てみましょう。
var a = 234,
b = 123;
displayNumbers(a, b);
// ... 数百行のコード
変数のグループ化の適用後:
a = 234;
b = 123;
displayNumbers(a, b);
// ... 数百行
var a, b;