如何从IL指令生成C#代码

3

我正在尝试使用dnlib库从IL指令生成c#代码。

我要生成的代码是这样的:

private string GetIp()
{
    return new WebClient().DownloadString("https://api.myip.com/");
}

我的代码:

Type webclientType = typeof(System.Net.WebClient);

ConstructorInfo constructor = webclientType.GetConstructors()[0];

MethodInfo methodInfo = webclientType.GetMethod("DownloadString", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, System.Reflection.CallingConventions.Any, new Type[] { typeof(string) }, null);

MethodDefUser m = new MethodDefUser("GetIp", MethodSig.CreateInstance(module.CorLibTypes.String), MethodImplAttributes.IL, MethodAttributes.Static | MethodAttributes.HideBySig)
{
    Body = new CilBody()
};

m.Body.Instructions.Add(new Instruction(OpCodes.Newobj, constructor));
m.Body.Instructions.Add(new Instruction(OpCodes.Ldstr, "https://api.myip.com/"));
m.Body.Instructions.Add(new Instruction(OpCodes.Callvirt, methodInfo));
m.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));

当我试图将模块保存到磁盘时,出现了错误(无效的指令操作数)。

目前,我的代码正在生成这些指令:

newobj - Void .ctor()
ldstr - https://api.myip.com/
callvirt - System.String DownloadString(System.String)
ret - 

当它们应该是这样的:
newobj - System.Void System.Net.WebClient::.ctor()
ldstr - https://api.myip.com/
callvirt - System.String System.Net.WebClient::DownloadString(System.String)
ret -

我尝试替换webclientType变量的constructor,但没有成功,也没有在网上找到任何信息。


什么是 MethodDefUser?什么是 MethodSig?什么是 module?请发布一个 [mcve],以便我们能够正确地帮助您。 - Lasse V. Karlsen
另外,“生成C#代码”具体是什么意思?请解释一下这是什么意思,因为你的问题似乎是关于使某些IL发射正常工作,而不是关于生成C#代码。 - Lasse V. Karlsen
@LasseV.Karlsen MethodDefUser 用于定义一个方法,然后您可以使用 CIL 指令添加功能,并最终将其写入 .net 文件。 - Milton Cardoso
1个回答

2

在尝试一些东西时,我发现需要使用具有.NET模块加载的主对象(来自dnlib)(ModuleDefMD)。

因此,我这样做:

m.Body.Instructions.Add(new Instruction(OpCodes.Newobj, module.Import(typeof(System.Net.WebClient).GetConstructors()[0])));
m.Body.Instructions.Add(new Instruction(OpCodes.Ldstr, "https://api.myip.com/"));
m.Body.Instructions.Add(new Instruction(OpCodes.Callvirt, module.Import(typeof(System.Net.WebClient).GetMethod("DownloadString", new Type[] { typeof(string) }))));
m.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));

module是我加载.NET文件的主要对象:

ModuleDefMD module = ModuleDefMD.Load(TxtFilepath.Text);

现在,这将生成以下C#代码:

static string GetIp()
{
    return new WebClient().DownloadString("https://api.myip.com/");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接