.NET§1の難読化ツール(および難読化解除ツール)

(これは難読化ツールのレビューの続きです。 ここから始めてください



1.難読化ツール。



1.1。 方法論



アセンブリと名前空間の組み合わせ(Assembly Merge、Namespace Flatten)

この手法だけでも、攻撃者を1分間遅らせることはありませんが、さらに絡まる場合に非常に役立ちます。 なぜなら 結果のアセンブリに含まれるクラスが多いほど、詳細な分析なしに必要なものを見つけるのが難しくなります。

繰り返しますが、コードを盗もうとすると、攻撃者は複数のライブラリプロジェクトと1つのプログラムではなく、すべてのクラスが1つのフォルダー(および1つの名前空間)にある1つのプロジェクトのみを受け取ります。



アセンブリを結合するには、 ilmergeユーティリティまたは難読化機能に組み込まれた機能を使用できます。 通常、名前空間はクラス名の難読化中に結合されます(そのため、異なる名前空間の同じ名前のクラスと衝突することはありません)。



クラス、メソッドなどの名前変更

このアプローチは、ほぼすべての敬意を払う難読化ツールに実装されています。 攻撃者がライセンスの原因となるクラスをすばやく検索するために使用できるすべての「ヒント」は削除されます。コードが「盗まれた」場合、アプリケーションロジック、クラスの作成理由と作成方法、メソッドの呼び出しを理解するのは非常に困難になります。



現時点で最も人気のあるオプションは、印刷できない文字(または儽。凍::儽のような「中国語」)に名前を変更することです。 これにより、リフレクター内のアセンブリの表示が少し複雑になりますが、難読化解除ツールには影響しません。

さらに、欠点から、エンドユーザーに発生した可能性のある例外に関する読みにくいメッセージを受け取ります。Unicodeエンコーディングではないテキストを送信すると、解析することは事実上不可能になります。



同様のオプションは、短いが印刷された識別子(a、b、c、.... aa、ab、ac ...)を使用することです。 難読化解除プログラムの場合、このオプションは前のオプションと完全に類似していますが、示されている欠点はありません。



ネーミングの3番目のバリエーション-高レベル言語キーワード(C#またはVB.net)の使用、またはこの言語の無効な識別子(たとえば?難読化解除ツールによって使用され、出力は未コンパイルのテキストになります...



元の名前の意味を確実に隠す「愚かな」オプションがまだたくさんありますが、なぜそんなに長くするのでしょうか?





興味深い、さらに混乱を招くアプローチは、難読化前に異なる名前を持ち、どのような方法でも接続されていなかった同じ名前の多数のオーバーロードメソッドを作成することです。

また、.netを使用すると、オーバーラップしたメソッドの名前とは異なる名前のオーバーライドメソッドを作成できます。 これは、攻撃者を混乱させるだけでなく、難読化解除プログラムに不要な要件を追加します。





クラスの内容を変更する

一部の難読化ツールは、複数のクラスを1つに結合したり、通常のクラスからネストされたクラスを作成したりできます。 しかし、このような難読化は、結果のプログラムでエラーを引き起こすことが多く、ほとんど使用されません。



難読化制御フロー

この時点で、コード内の命令の順序が変わり、命令自体も変わります。 おそらく、最も興味深く、最も物議をかもしている段階です。

この手法を使用すると、大部分の高レベル言語逆コンパイラーを誤解させる(場合によっては完全に混乱させる)ことができます。 コード盗難に非常によく対抗します。 また、クラッカーとkeygenの作成者を混乱させます。

コインの裏側は、パフォーマンスが低下する場合があります。 プログラムのコースを混乱させるほど、時間がかかります。 これは、例外の使用に特に当てはまります。

ほとんどの場合、メソッドコードはブロックに分割され、これらのブロックはランダムに混合され、無条件ジャンプ(brおよびbr.s命令)を使用して「接着」されます。 例として:

L_0034: br.s L_003a

L_0036: nop

L_0037: br.s L_0041

L_0039: nop

L_003a: callvirt instance void [ Aaa ] Xxx . Yyy :: Zzz ()

L_003f: br.s L_0036

L_0041: nop








メソッドが非常に短く、「ミックス」してもうまく機能しない場合があります。この場合、一部の難読化ツールは次の指示への移行を提供します。

L_0008: br.s L_000a

L_000a: ldarg.0








遷移命令とその目的の間に、デバッガーに陥る、または単に無効な命令など、あらゆる種類のでたらめが挿入されることが非常に多くあります。

L_0000: br.s L_0003

L_0002: break

L_0003: ldarg.0








一部の難読化ツールは、遷移命令(元の命令と挿入された命令の両方)を、一定のロードとスイッチへの切り替えに置き換えます:

L_0000: br.s L_0023

L_0002: ldloc num3

L_0006: switch (L_005b, L_0068, L_00ce, L_00af, L_0047 , L_007b)

...

...

...

L_003c: ldc.i4 4

L_0041: stloc num3

L_0045: br.s L_0002








この例では、オフセットL_0045“ in girlhood”の命令がbr L_0047であったことは明らかです。以前の方法を考慮すると、これは通常nopです;)



「移行から移行」に遭遇する場合があります。



プログラムの1つで、6(6)のこのような遷移のチェーンを見ました;)



興味深いアプローチは、常に真(または不正確)な式に条件付きジャンプを使用することです。

最も簡単な例:

L_0014: ldc.i4.1

L_0015: brtrue.s L_002e








同じことですが、少しわかりにくいです:

L_0014: ldc.i4.1

L_0015: stloc.0

L_0016: br.s L_001c

L_0018: nop

L_0019: ldarg.1

L_001a: br.s L_002e

L_001c: ldloc.0

L_001d: brtrue.s L_0018








別のオプション:

if (5 < (5 - 6)) {

// IL-,

}




ILの形式では、次のようになります。

L_0000: ldc.i4.5

L_0001: dup

L_0002: dup

L_0003: ldc.i4.6

L_0004: sub

L_0005: blt L_0001








いくつかの指示の単純な混合、例えば:

L_0000: ldc.i4 4

L_0005: stloc num

L_0009: ldstr "\u5f03"

L_000e: ldloc num




コンパイラは、ローカル変数に値を書き込む必要があるが、スタックから値を削除する必要がない場合、stloc X、ldloc Xの形式のコードを生成することがあります。 難読化ツールの場合、この変数(num)は人為的に追加され、これら2つの命令を除いてどこでも使用されません。



最も難しいメソッドの1つは、常にtry — catchブロック内で例外をスローすることです。 このアプローチは、めったに使用されません。 不適切に使用すると、パフォーマンスが劇的に低下し、アプリケーションロジックが混乱する可能性があります。 多くのスペースを占有するため、スクリーンショットは提供しません。



私は最も人気のある方法をリストしているようです。他に何か知っているなら、コメントで知らせてください。



無効なIL

ここではすべてが非常に簡単です。 決して実行されないコードのセクションには、標準に記述されていないオペコードが挿入されます(つまり、無効な命令)。

リフレクターには、次のようなものが表示されます。



または、ILに切り替えた場合:



この手法は、初心者の「ハッキング」を阻止します。 しかし、回避することは難しくありません(これらのオペコードは単純にnopに置き換えられます)。



行の非表示

これは難読化解除者によって「文字列暗号化」と呼ばれますが、私はそれを暗号化と呼ぶことを敢えてしません。

通常、これは定数のXORタイプのある種の「子」暗号化アルゴリズムによって行われます。

public static string Decode( string str, int num)

{

int length = str.Length;

char [] chArray = str.ToCharArray();

while (--length >= 0)

chArray[length] = ( char )(chArray[length] ^ num);

return new string (chArray);

}









文字列が1つに結合されてから、Substringメソッドが呼び出される場合があります。 リソースに文字列が隠れている場合があります。



いずれにせよ、「暗号化」はいくつかの引数、通常は文字列および/または数字を持つ静的メソッドとして提示されます。 暗号化アルゴリズムは使用されません。これは非常に論理的です。ここで実際の暗号化を使用すると、プログラムは恥知らずに遅くなります。

この方法は、「無効なシリアル番号」などの文字列やその他のメッセージテキストをコードで検索する初心者のクラッカーを節約します。



特定の逆コンパイラの属性とバグ

最も一般的な属性は[ SuppressIldasm ]です。これは、Microsoftの公式の逆コンパイラildasmであるこのアセンブリで動作しないよう「丁寧に要求」します。 また、リフレクターおよび市販の逆コンパイラーに固有の属性があります。



バグとして、逆コンパイラの純粋に技術的な欠陥を見つけることができます(たとえば、リフレクターは命令ldfld string儽に該当します。スタックの状態。ただし、グラフに従ってではなく、線形にメソッドに従って進み、最後のretステートメントの後に無限ループが挿入されるメソッドに喜んで該当します。 Reflexilプラグインに対して、それ自体に切り替える命令は「役立つ」。



その他の方法

文字列を非表示にするのに非常によく似たアプローチを思いつくことがありますが、それはリソースのためです。

難読化ツールの1つは、「V-Spot Elimination」(非常に誇りに思っています)-BCLクラスのプロキシクラスの作成も提供します。これにより、分析が遅くなり、逆コンパイルによって得られたコードが少し損なわれます。

管理された.netコードへの管理の変換も使用されます。 つまり すべてが管理されていないマークで再構築されます。 ドメイン内のほぼすべての機能は保持されますが、コードはリフレクターから見えません。







コメントと追加をしてくれたExaktusに感謝します。

次はパート1.2です。 難読化ツールの概要

継続する...

*すべてのソースコードがMSVSとワードパッドで強調表示されました;)



All Articles