0

実行時にリフレクションによって生成されるクラスの IL コードを抽出して、ディスクに保存するにはどうすればよいですか? できれば。これらのクラスを生成するコードを制御することはできません。

最終的に、この IL コードをディスクから別のアセンブリにロードしたいと考えています。

クラスをシリアライズ/デシリアライズできることはわかっていますが、純粋に IL コードを使用したいと考えています。私はセキュリティへの影響については気にしていません。

Mono 2.10.1 の実行

4

2 に答える 2

1

またはさらに良いことに、Mono.Cecil を使用します。

個々の命令を取得し、それらを操作して逆アセンブルすることもできます ( mono decompiler の追加を使用)。

逆コンパイラは進行中の作業であることに注意してください (前回チェックしたときは、ラムダ式と Visual Basic 例外ブロックを完全にはサポートしていませんでした)、これらの境界条件に達しない限り、C# で非常に簡単にかなり逆コンパイルされた出力を得ることができます。 . また、そこから作業が進みました。

一般に、Mono Cecil では、IL を新しいアセンブリに書き込むこともできます。その後、ブリーディング エッジで遊んでみたい場合は、後でアプリケーション ドメインに読み込むことができます。

更新これを試してみました。残念ながら、あなたが遭遇した問題を見つけたと思います。アセンブリがたまたまロードできる場所に書き出されない限り、生成された型の IL バイトを取得する方法はないようです。

リフレクションを介してビットを取得できると思いましたが (クラスは必要なメソッドをサポートしているため)、関連するメソッドThe invoked member is not supported in a dynamic module.は呼び出し時に例外を発生させるだけです。以下のコードでこれを試すことができますが、要するに、あなたMarshal::GetFunctionPointerForDelegate(). 命令をバイナリ ダンプし、IL オペコードとして手動で逆アセンブルする必要があります。ドラゴンがいます。

コードスニペット:

using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Reflection.Emit;
using System.Reflection;

namespace REFLECT
{
    class Program
    {
        private static Type EmitType()
        {
            var dyn = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Emitted"), AssemblyBuilderAccess.RunAndSave);
            var mod = dyn.DefineDynamicModule("Emitted", "Emitted.dll");
            var typ = mod.DefineType("EmittedNS.EmittedType", System.Reflection.TypeAttributes.Public);
            var mth = typ.DefineMethod("SuperSecretEncryption", System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.Static, typeof(String), new [] {typeof(String)});

            var il = mth.GetILGenerator();
            il.EmitWriteLine("Emit was here");
            il.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);    
            il.Emit(System.Reflection.Emit.OpCodes.Ret);
            var result = typ.CreateType();
            dyn.Save("Emitted.dll");
            return result;
        }

        private static Type TestEmit()
        {
            var result = EmitType();
            var instance = Activator.CreateInstance(result);
            var encrypted = instance.GetType().GetMethod("SuperSecretEncryption").Invoke(null, new [] { "Hello world" });
            Console.WriteLine(encrypted); // This works happily, print "Emit was here" first

            return result;
        }

        public static void Main (string[] args)
        {
            Type emitted = TestEmit();

              // CRASH HERE: even if the assembly was actually for SaveAndRun _and_ it 
              // has actually been saved, there seems to be no way to get at the image
              // directly:
            var ass = AssemblyFactory.GetAssembly(emitted.Assembly.GetFiles(false)[0]);

              // the rest was intended as mockup on how to isolate the interesting bits
              // but I didn't get much chance to test that :)
            var types = ass.Modules.Cast<ModuleDefinition>().SelectMany(m => m.Types.Cast<TypeDefinition>()).ToList();
            var typ = types.FirstOrDefault(t => t.Name == emitted.Name);

            var operands = typ.Methods.Cast<MethodDefinition>()
                .SelectMany(m => m.Body.Instructions.Cast<Instruction>())
                .Select(i => i.Operand);

            var requiredTypes = operands.OfType<TypeReference>()
                .Concat(operands.OfType<MethodReference>().Select(mr => mr.DeclaringType))
                .Select(tr => tr.Resolve()).OfType<TypeDefinition>()
                .Distinct();
            var requiredAssemblies = requiredTypes
                .Select(tr => tr.Module).OfType<ModuleDefinition>()
                .Select(md => md.Assembly.Name as AssemblyNameReference);

            foreach (var t in types.Except(requiredTypes))
                ass.MainModule.Types.Remove(t);

            foreach (var unused in ass.MainModule
                     .AssemblyReferences.Cast<AssemblyNameReference>().ToList()
                     .Except(requiredAssemblies))
                ass.MainModule.AssemblyReferences.Remove(unused);

            AssemblyFactory.SaveAssembly(ass, "/tmp/TestCecil.dll");
        }
    }
}
于 2011-04-02T16:02:23.517 に答える
0

クラスのILだけが必要な場合は、Userすでに持っています。それはあなたがそれをコンパイルしたdllにあります。

他のアセンブリから、クラスを含むdllUser動的にロードし、リフレクションを通じて使用できます。

更新

で作成された動的クラスがあるReflection.Emit場合は、AssemblyBuilderそれを使用してディスクに保存できます。

代わりに動的タイプがで作成されたMono.Cecil場合は、(Mono.Cecil 0.9で)AssemblyDefinitionディスクに保存できるものがあります。myAssemblyDefinition.Write("MyAssembly.dll")

于 2011-04-02T15:49:27.477 に答える