我該如何去解決在反射運行時生成的類的IL代碼,以便我可以將它保存到磁盤?如果可能的話。我無法控制生成這些類的代碼片段。如何從加載的程序集中提取IL類代碼並保存到磁盤?
最後,我想從磁盤此IL代碼加載到另一個組件。
我知道我可以連載/ deserialise類,但我想純粹使用IL代碼。我並沒有對安全問題產生影響。
運行單2.10.1
我該如何去解決在反射運行時生成的類的IL代碼,以便我可以將它保存到磁盤?如果可能的話。我無法控制生成這些類的代碼片段。如何從加載的程序集中提取IL類代碼並保存到磁盤?
最後,我想從磁盤此IL代碼加載到另一個組件。
我知道我可以連載/ deserialise類,但我想純粹使用IL代碼。我並沒有對安全問題產生影響。
運行單2.10.1
或更好的是,使用Mono.Cecil。
這將讓你得到的各條指令,甚至操縱他們和拆卸他們(與mono decompiler addition)。
請注意,反編譯器是一個正在進行的工作(上次我檢查它並沒有完全支持lambda表達式和Visual Basic異常塊),但是您可以非常容易地在C#中擁有相當反編譯的輸出,只要您不需要碰到這些邊界條件。此後,工作也取得了進展。
單塞西爾一般咱們你寫的IL到一個新的組件,以及,這如果你喜歡流血的邊緣玩,你可以隨後加載到你的應用程序域。
更新我恍然嘗試此。不幸的是我覺得我發現你遇到了什麼問題。事實證明,除非程序集碰巧寫出了可以加載它的地方,否則似乎無法獲取生成類型的IL字節。
我認爲你可以通過反射獲取位(因爲類支持所需的方法),但是相關方法在調用時會引發異常The invoked member is not supported in a dynamic module.
。你可以用下面的代碼試試這個,但總之我想這意味着它不會發生的,除非你想f*ck with 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");
}
}
}
不幸的是,因爲Mono.Cecil缺少官方文檔,我找不到一個例子可以讓我將代表特定類的IL代碼保存到文件中。它是否允許您將IL代碼注入當前的應用程序域? – 2011-04-02 16:15:28
Mono的回購包含[cecil-roundtrip.cs](https://github.com/mono/cecil/blob/master/tools/cecil-roundtrip.cs),我想這應該是非常全面的開始的事情,我會看到是否可以敲一點樣品 – sehe 2011-04-02 20:28:18
更新壞消息對不起:)還有一個建議,但我不確定我會去那裏 – sehe 2011-04-03 00:16:21
如果你想要的是IL您User
類,你已經擁有了它。它在你編譯的dll中。
從您的其他程序集,您可以load the dll與User
類動態和use it通過反射。
UPDATE:
如果你有什麼是Reflection.Emit
創建動態類,你有一個AssemblyBuilder
,你可以用它來save it到磁盤。
如果您的動態類型是使用Mono.Cecil
創建的,則您的AssemblyDefinition
可以使用myAssemblyDefinition.Write("MyAssembly.dll")
(在Mono.Cecil 0.9中)保存到磁盤。
這是錯誤的,代碼=數據。 – 2011-04-02 16:24:18
漢斯評論說,IL不會包含用戶名和密碼。即使序列化對於用戶名和密碼來說也不是好主意。可能通過解釋你的實際問題,你可以幫助社區提出更好的解決方案和答案。 – 2011-04-02 16:38:07
@Sanjeevakumar這完全是一個例子。我說我想「用運行時計算值填充它的屬性」。我不認爲IL代碼包含數據,我的意思是我想創建一個我剛剛注入的類的實例,並使用反射來修改值。總的來說,我希望能夠提取可能包含任何數量的屬性,字段和方法的任何對象的IL代碼。 – 2011-04-02 16:51:58