おそらく、ソフトウェア保護は常に私のお気に入りのトピックの1つです。 私は、プログラムのライセンスに関する複雑で独創的なチェックを思いつき、熱心に実装しました。 私は常に、防御を破るために、ハッカーはプログラムで使用される最大限の技術を研究しなければならないという原則を堅持しました。 キー検証アルゴリズムを中断したい場合は、スレッドの同期について考えさせてください。 彼が私のアルゴリズムに干渉したい場合、COMリンクのカウントの問題を研究させてください。 キーデータを保存する方法を理解することに決めた場合、メモリ内でのイメージのビットマップの表現方法について考えさせてください。
はい、C ++はこの点でほぼ理想的な言語でした。 しかし、時代は変わり、古いテクノロジーは去り、新しい、より生産的で便利なテクノロジーが代わりに来ています。 そこで、私たちのチームは.NETに切り替えました。 しかし、開発の単純さとデバッグの利便性と引き換えに、ソフトウェアの逆コンパイルの単純さも加えられました。 これで、ハッカーはライセンスの制限を回避できるだけでなく、リフレクターに送るだけでプログラムのほぼ完全なソースを入手できました。
もちろん、この問題の解決策として、多くの異なる難読化ツールが市場に導入されました。 しかし、不思議なことに、それらのほとんどは、価格方針(一部の最小ライセンスでさえ、ソフトウェアのコストを数回超えました)とアルゴリズムの「インテリジェンス」の両方で一度に私を失望させました。 そのため、いくつかの難読化ツールの後、単純なWinFormsアプリケーションでさえクラッシュすることがありました。 WPFに関しては、排他的なものに対する長くて長い黒のシャーマニズムがなければ、中規模のプログラムを起動することは原則として不可能でした。
これにより、問題の理解と、上記の問題を最小限に抑える製品を作成するという明確な願望が形成されました。 そして、SaaS難読化ツールと.NETコードプロテクターAppFuscator.comが登場しました
セキュリティアルゴリズム
名前の変更
クラスとそのメンバーの難読化。ジェネリック、継承、オーバーロード仮想メソッド、難読化の標準属性を完全にサポートしています。
さまざまな命名オプションが利用可能です:英語の文字、英語の文字、パラメーターの種類、印刷不可能な文字、その他多数の種類によるオーバーロード。
アセンブリのマージ
分析と逆コンパイルを複雑にするために、複数のソース保護アセンブリを1つの最終に結合します。
現在のバージョンでは、埋め込みアセンブリはWPFリソースを含まないアセンブリである必要があります。
分解
クラス構造の手続き型表現への分解は、プログラムをオブジェクト指向形式(リバースエンジニアリングが簡単)から手続き型スタイルに移行するというアイデアに基づいた独自の開発であり、メタデータに格納されているすべての利用可能な情報を最大限破壊します(ただし、ガベージコレクターの完全な効率を維持します) 。
もう少しお話しします 次のクラス構造を持つアセンブリがあるとします。
分解後、次のように表示されます。
スクリーンショットで強調表示されているメソッドは、以前のMainForm_Load(フォーム読み込みハンドラー)です。 今では、他のすべてのコードと同様に、グローバル名前空間で、それが属するクラスの外側にあります(任意のメソッドがクラスに属するC#とは異なり、通常のグローバル関数の宣言はILで許可されます)。
フォーム自体(現在のクラスb)には、メソッドDisposeのみが残っています。 これは仮想関数のオーバーロードであるため、我慢できません。
ご覧のとおり、読み取りの複雑さは時々増加し、攻撃者がどのメソッドが以前に属しているかを把握することは非常に困難です。 この場合、クラスは(失われた型を持つ)データフィールドと残りの仮想関数のみを含む空のラッパーに変わります。
外部メソッド呼び出しの非表示
外部メソッドの呼び出しの隠蔽-外部アセンブリからのメソッドの明示的な呼び出しの置換(共通言語ランタイムへの呼び出しを含む)、アンマネージポインターによる暗黙的なアクセス。
小さな例。 それは:
public void ShowMessage(string text) { MessageBox.Show(text); }
次のようになりました:
// <Module> public static void a(object obj, string text) { object arg_0C_0 = calli(System.Int32(System.String), text, gb); }
文字列暗号化
独自のアルゴリズムに基づいた文字列の暗号化。 自動デコーダーの潜在的な開発者の生活を明確に複雑にするために、コンテキストに応じて、保護されたプログラムで動的変数が形成されます。
反射解析
リフレクションメカニズムへの呼び出しの分析-リフレクションへの呼び出しを追跡するアルゴリズムのセット。
プログラムの次のバージョンをアセンブルした後、次のステージが始まる-難読化ツールの周りをタンバリンで踊るのは、私はいつもそれを好まなかった。 したがって、当社の製品は、通信を自動的に追跡し、プログラムコードの名前を調整するようにトレーニングされたアナライザーを提供します。 複雑な構造を解析し、最終的なソリューションを選択するためのかなり強力なロジックを備えています。 もちろん、可能性のあるすべてのケースを自動的に閉じることはできませんが、開発者の生活は大幅に楽になります。
次の2つのクラスがあるとします。
class ClassA { string GetText() { return "A"; } public int smallField; } class ClassB { string GetText() { return "B"; } }
次のコード例を検討してください。
public void HabraTestFirst(int x) { Type work = null; string method = "gettext"; if (x == 0) work = typeof(ClassA); // ClassA else { string name = "HabraCode.ClassB, HabraCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; work = Type.GetType(name, true); // ClassB } // GetText HabraReflectionCall(work, method); } public void HabraReflectionCall(Type target, string method) { var call = target.GetMethod(method, BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance); var obj = Activator.CreateInstance(target); call.Invoke(obj, null); MessageBox.Show(string.Format("HabraReflection call: {0}.{1}", obj.ToString(), call.Name)); }
この例では、入力に渡される数値パラメーターに応じて、メソッドはClassAクラスまたはClassBのいずれかで呼び出されます。 同時に、これらのクラスには、継承とインターフェイスの間の接続がありません。
簡単なプログラムをコンパイルします。
var reflector = new Reflector(); reflector.HabraTestFirst(0); reflector.HabraTestFirst(1);
開始して出来上がり:
ご覧のとおり、難読化中に両方のクラスと両方のメソッドの名前が変更されましたが、プログラムはそれらの間の関係を識別し、Reflection呼び出しの名前へのリンクを更新できました。
さらに興味深い例では、Reflectionを介してアクセスするだけでなく、列挙体を介して目的のフィールドを検索します。
public void HabraTestSecond() { FieldInfo result = null; var anyobj = new ClassA().GetType(); foreach (var it in anyobj.GetFields()) { if (it.Name == "smallField") // smallField result = it; } if (result == null) throw new InvalidOperationException(); MessageBox.Show("HabraReflection field: " + result.ToString()); }
起動時に、プログラムは正直に教えてくれます:
どのように機能しますか? 特徴的な構造を見ただけで、Reflectionから取得したフィールドを一覧表示することですべてが簡単になり、アナライザーはILコード内の要求された名前を適合および更新することができました。
もちろん、このアプローチは常に機能するとは限りません。設計がより多段階である場合や、たとえば外部ファイルから目的のメソッドの名前が取得される場合、インテリジェントアナライザーは正直に敗北を認めます。
ソースコードはこちらからダウンロードできます 。
WPF分析
Windows Presentation Foundationからアクセスされるタイプ、メソッド、およびフィールドを難読化から自動的に除外します。 このプログラムは、アセンブリ内のコンパイル済みXAMLリソースを逆コンパイルおよび分析します。 複雑なコンストラクト(PropertyPathなど)を含むWPF構文拡張を完全にサポートします。
このため、WPFで記述されたプログラムでは、名前を変更する必要があるもののみが名前変更されます。
難読化後のプログラムの典型的な例:
(クリックして拡大)
なぜSaaSなのか?
それは簡単です-数千ドルで優れたボックス化された難読化ツールを購入し、その更新の購入に常に支払うのではなく(結局、.NETプラットフォームテクノロジーは非常に急速に開発されています)、オンライン難読化サービスにアクセスできます。 その後、個人的に必要な仕事の分だけ支払います。 月に一度バージョンをリリース-これに対してのみ支払います。
価格設定はまだ始まったばかりですが、条件はおいしいと自信を持って言えます。 さらに、無料版が利用可能になり、その機能は現在利用可能なすべての無料の難読化ツールを上回ります。
安全ですか?
データの保護は非常に重要です。
何よりもまず、プログラムのソースコードをサーバーに送信する必要はありません。 既にコンパイル済みのアセンブリのみを送信します。フォームは、保護の問題に対処せず、難読化しない場合に、ユーザー(およびユーザーだけでなく)が表示する形式で送信します。 他の情報は必要ありません。
難読化のプロセス全体が専用サーバーで実行されます。専用サーバーへのアクセスは、チームの少数のユーザーのみが利用できます。 もちろん、私たちはソフトウェアの最新バージョンを使用し、定期的なアップデートを作成しています。 さらに、難読化モジュールとユーザーと対話するためのWebフロントエンドは物理的に別々のサーバーに配置され、システムのセキュリティとスケーラビリティが向上します。
当社は法人であり、当社のサービスおよびNDAの使用に関する契約など、必要なすべての文書を提供する準備ができています。
これで、サービスがベータモードで起動され、すべての機能を完全に無料でテストできます。