実行ファイルの暗号化

.NET(というかIL)の場合、逆コンパイルで中身がまる見えになり、商用アプリだとそこが嫌われることがあります。ぶっちゃけ、x86ネイティブコードなら問題ないか?と言えば、全然そんなことないのですが、ILがあまりに手軽なのが駄目なんでしょうね。あと、難読化ツールは試したことがないので、どの程度効果があるのか分かってませんです。(^^;

全くのノーガードが気になる場合、気休めにライブラリ(DLL)を暗号化して、実行時に復号するのはどうでしょうか?
暗号化プログラム

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

class Program
{
    static void Main(string args)
    {
        // 引数で渡されたファイルを暗号化し、
        // .crypt(暗号化済みファイル)と.key(キーファイル)を作成する
        if (args.Length == 0)
            return;

        string original = args[0];
        RijndaelManaged rj = new RijndaelManaged();
        byte key;
        byte IV;

        rj.GenerateKey();
        rj.GenerateIV();

        key = rj.Key;
        IV = rj.IV;

        ICryptoTransform encryptor = rj.CreateEncryptor(key, IV);

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

        byte toEncript = File.ReadAllBytes(original);
        csEncrypt.Write(toEncript, 0, toEncript.Length);
        csEncrypt.FlushFinalBlock();

        // 暗号化したDLLは元の名前+.cryptにする
        File.WriteAllBytes(original + ".crypt", msEncrypt.ToArray());
        // KeyとIVを元の名前+.keyファイルとして保存する
        using (BinaryWriter bw = new BinaryWriter(File.Create(original + ".key")))
        {
            bw.Write(key.Length);
            bw.Write(key);
            bw.Write(IV.Length);
            bw.Write(IV);            
        }
    }
}

暗号化したいDLLを引数に渡すと

  • xxx.dll.crypt
  • xxx.dll.key

の2つのファイルが出来ます。xxx.dllを使いたいプログラムにこの暗号化したファイル(xxx.dll.crypt)を埋め込みます。で、実行時に埋め込みリソースから読み込んで復号すればいいです。例えば、こんな感じ。

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Resources;
using System.Security.Cryptography;
using System.Reflection;

class Program
{
    static void Main(string args)
    {
        if (args.Length == 0)
            return;

        int n;
        string keyfile = args[0];
        byte key;
        byte IV;

        using (BinaryReader br = new BinaryReader(File.OpenRead(keyfile)))
        {
            n = br.ReadInt32();
            key = br.ReadBytes(n);
            n = br.ReadInt32();
            IV = br.ReadBytes(n);
        }

        Assembly asm = Assembly.GetEntryAssembly();
        Stream stm = asm.GetManifestResourceStream("ConsoleApplication2.ClassLibrary1.dll.crypt");

        // 復号
        RijndaelManaged rj = new RijndaelManaged();
        ICryptoTransform decryptor = rj.CreateDecryptor(key, IV);
        CryptoStream csDecrpt = new CryptoStream(stm, decryptor, CryptoStreamMode.Read);
        byte dll = new byte[stm.Length];
        csDecrpt.Read(dll, 0, dll.Length);

        asm = Assembly.Load(dll);
        object o = asm.CreateInstance("Calc");
        Console.WriteLine (o.GetType().GetMethod("Add").Invoke(o, new object[] {10, 20}));
    }
}

/* 結果
 0.5
 */

正しいキーファイルがないとILコードが全然でたらめなので実行不可能です。凄い人なら簡単に破るのかも知れませんが、私程度の実力なら諦めるでしょう。(^^;

メソッドがAddなのに割り算を行っているのは意図的です。名前のまんまだと結果が分かってしまってつまんないし。