C# プログラムを暗号化して隠す方法?

C# プログラムを暗号化して隠す方法?

LiteDBを使って自分のプログラムを暗号化する方法を紹介し、LiteDBについて簡単に説明します。

最終更新 2023/08/15 20:23
tokengo
読了目安 4 分
カテゴリ
.NET
タグ
.NET C#

以下では、LiteDB を使用してプログラムを暗号化する方法を紹介し、LiteDB の概要を説明します。

LiteDB

LiteDB は軽量な組み込みデータベースで、C# で記述されており、.NET プラットフォームに対応しています。シンプルで使いやすいデータベースソリューションを提供し、さまざまなアプリケーションで利用できます。

LiteDB は単一のファイルをデータベースストレージとして使用し、このファイルはディスク上またはメモリ内に配置できます。NoSQL データベースと同様のドキュメントストレージモデルをサポートし、各ドキュメントは JSON 形式のオブジェクトです。つまり、事前にスキーマを定義することなく、任意の型のデータを保存および取得できます。

LiteDB は、挿入、更新、削除、クエリを含むさまざまなデータベース操作を実行するためのシンプルな API セットを提供します。また、トランザクションをサポートしており、データの一貫性と整合性を確保できます。

さらに、LiteDB はインデックス、全文検索、ファイルストレージといった高度な機能も提供します。インデックスはクエリを高速化し、全文検索はテキストデータ内のキーワード検索を可能にし、ファイルストレージはファイルをデータベース内に直接保存できます。

LiteDB の利点には、使いやすさ、軽量性、高速性、組み込み可能性があります。コードベースは非常に小さく、アプリケーションに簡単に統合できます。また、クロスプラットフォーム対応であり、Windows、Linux、Mac などのオペレーティングシステムで動作します。

要約すると、LiteDB はさまざまなアプリケーションに適したシンプルで使いやすい組み込みデータベースです。データベース操作用のシンプルな API セットを提供し、いくつかの高度な機能もサポートしています。軽量なデータベースソリューションが必要な場合は、LiteDB の使用を検討してください。

暗号化によるパッケージング

LiteDB.Service という WebApi プロジェクトを作成します。

右クリックして発行:

LiteDB.Launch というコンソールプロジェクトを作成します。

EntryPointDiscoverer.cs はエントリポイントメソッドを検索するためのものです。

internal class EntryPointDiscoverer
{
    public static MethodInfo FindStaticEntryMethod(Assembly assembly, string? entryPointFullTypeName = null)
    {
        var candidates = new List<MethodInfo>();

        if (!string.IsNullOrWhiteSpace(entryPointFullTypeName))
        {
            var typeInfo = assembly.GetType(entryPointFullTypeName, false, false)?.GetTypeInfo();
            if (typeInfo == null)
            {
                throw new InvalidProgramException($"Could not find '{entryPointFullTypeName}' specified for Main method. See <StartupObject> project property.");
            }
            FindMainMethodCandidates(typeInfo, candidates);
        }
        else
        {
            foreach (var type in assembly
                         .DefinedTypes
                         .Where(t => t.IsClass)
                         .Where(t => t.GetCustomAttribute<CompilerGeneratedAttribute>() is null))
            {
                FindMainMethodCandidates(type, candidates);
            }
        }

        string MainMethodFullName()
        {
            return string.IsNullOrWhiteSpace(entryPointFullTypeName) ? "Main" : $"{entryPointFullTypeName}.Main";
        }

        if (candidates.Count > 1)
        {
            throw new AmbiguousMatchException(
                $"Ambiguous entry point. Found multiple static functions named '{MainMethodFullName()}'. Could not identify which method is the main entry point for this function.");
        }

        if (candidates.Count == 0)
        {
            throw new InvalidProgramException(
                $"Could not find a static entry point '{MainMethodFullName()}'.");
        }

        return candidates[0];
    }

    private static void FindMainMethodCandidates(TypeInfo type, List<MethodInfo> candidates)
    {
        foreach (var method in type
                     .GetMethods(BindingFlags.Static |
                                 BindingFlags.Public |
                                 BindingFlags.NonPublic)
                     .Where(m =>
                         string.Equals("Main", m.Name, StringComparison.OrdinalIgnoreCase)))
        {
            if (method.ReturnType == typeof(void)
                || method.ReturnType == typeof(int)
                || method.ReturnType == typeof(Task)
                || method.ReturnType == typeof(Task<int>))
            {
                candidates.Add(method);
            }
        }
    }
}

次に、Program.cs ファイルを開きます。注意:SaveDb の引数は、自身のプロジェクトのパッケージパスに変更してください。

// 指定されたプログラムをパッケージ化するために使用。
SaveDb(@"E:\Project\LiteDB-Application\LiteDB.Service\bin\Release\net7.0\publish");

// db を開く
var db = new LiteDatabase("Launch.db");

// テーブルを開く
var files = db.GetCollection<FileAssembly>("files");

// 見つからないアセンブリの処理を引き継ぐ
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
    try
    {
        var name = eventArgs.Name.Split(",")[0];
        if (!name.EndsWith(".dll"))
        {
            name += ".dll";
        }

        var file = files.FindOne(x => x.Name == name);

        return file != null ? Assembly.Load(file.Bytes) : default;
    }
    catch (Exception)
    {
        return default;
    }
};

// プログラムを起動
StartServer("LiteDB.Service", new string[] { });

Console.ReadKey();

void StartServer(string assemblyName, string[] args)
{
    var value = files!.FindOne(x => x.Name == assemblyName + ".dll");
    var assembly = Assembly.Load(value!.Bytes);

    var entryPoint = EntryPointDiscoverer.FindStaticEntryMethod(assembly);

    try
    {
        var parameters = entryPoint.GetParameters();
        if (parameters.Length != 0)
        {
            var parameterValues = parameters.Select(p =>
                    p.ParameterType.IsValueType ? Activator.CreateInstance(p.ParameterType) : null)
                .ToArray();
            entryPoint.Invoke(null, parameterValues);
        }
        else
        {
            entryPoint.Invoke(null, null);
        }
    }
    catch (Exception e)
    {

    }
}


// 指定されたディレクトリ以下のすべてのファイルとサブディレクトリをスキャンし、LiteDB データベースに保存する。
void SaveDb(string path)
{
    var files = ScanDirectory(path);
    using var db = new LiteDatabase("Launch.db");
    var col = db.GetCollection<FileAssembly>("files");
    col.InsertBulk(files);
}

// 指定されたディレクトリ以下のすべてのファイルとサブディレクトリをスキャンし、コレクションを返すメソッド。
List<FileAssembly> ScanDirectory(string path)
{
    var files = new List<FileAssembly>();
    var dir = new DirectoryInfo(path);
    var fileInfos = dir.GetFiles("*", SearchOption.AllDirectories);
    foreach (var fileInfo in fileInfos)
    {
        var file = new FileAssembly
        {
            Name = fileInfo.Name,
            Bytes = File.ReadAllBytes(fileInfo.FullName)
        };
        files.Add(file);
    }

    return files;
}

class FileAssembly
{
    /// <summary>
    /// ファイル名
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// ファイルの内容
    /// </summary>
    public byte[] Bytes { get; set; }
}

LiteDB.Launch プロジェクトファイルをクリックし、LiteDB の依存関係を追加し、SDK を Microsoft.NET.Sdk.Web に変更します。

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="LiteDB" Version="5.0.17" />
    </ItemGroup>

</Project>

プロジェクトを起動する前に、まず LiteDB.Service を発行してください。次に、SaveDb の引数を発行ディレクトリに変更します(すべてのファイルが自動的にスキャンされ、LiteDB ファイルにパッケージ化されます)。

その後、プロジェクトを起動します。

LiteDB.Launch を起動すると、StartServer メソッド内で作成された LiteDB ファイルから指定された起動アセンブリが検索されます。

次に、AppDomain.CurrentDomain.AssemblyResolve で、起動アセンブリに不足しているアセンブリがドメインに読み込まれます。

AppDomain.CurrentDomain.AssemblyResolve は、依存関係が見つからない場合に発生するイベントです。

LiteDB に保存する際に、保存内容を暗号化できます。その後、AppDomain.CurrentDomain.AssemblyResolve がトリガーされたときに、LiteDB から読み込むファイルの内容を復号化します。

おわりに

token さんの共有によるものです。

QQ 技術交流グループ:737776595

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2026/04/22

各OSバージョンの.NETサポート状況(250707更新)

仮想マシンとテストマシンを使用して、各OSバージョンの.NETサポート状況を確認します。OSインストール後、対応するランタイムをインストールし、Stardustエージェントを実行できることを確認します(合格条件)。

続きを読む
同じカテゴリ / 同じタグ 2026/02/07

AOTの使用経験のまとめ

プロジェクト作成当初から、新機能を追加したり新しい構文を使用したりした場合には、すぐにAOT公開テストを実施するという良い習慣を身につけるべきです。

続きを読む