我在C#中有以下代码
// test.Program
private static void Main()
{
int x = 5;
int y = 100;
Console.WriteLine(y + ", " + x);
}
Run Code Online (Sandbox Code Playgroud)
而且我正在阅读IL代码,我之前从未编写过程序集,所以我问我每行的功能是否正确.
.method private hidebysig static
void Main () cil managed
{
// Method begins at RVA 0x2058
// Code size 33 (0x21)
.maxstack 3 // maximum stack in this method is 3
.entrypoint // method is initial entry point
.locals init ( // reserves memory for x and y variables
[0] int32 x, // x variable is …Run Code Online (Sandbox Code Playgroud) 我最近一直在挖掘IL,我注意到了C#编译器的一些奇怪的行为.以下方法是一个非常简单且可验证的应用程序,它将立即退出,退出代码为1:
static int Main(string[] args)
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)
当我使用Visual Studio Community 2015编译它时,会生成以下IL代码(添加注释):
.method private hidebysig static int32 Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init ([0] int32 V_0) // Local variable init
IL_0000: nop // Do nothing
IL_0001: ldc.i4.1 // Push '1' to stack
IL_0002: stloc.0 // Pop stack to local variable 0
IL_0003: br.s IL_0005 // Jump to next instruction
IL_0005: ldloc.0 // Load local variable 0 onto stack
IL_0006: ret // Return
}
Run Code Online (Sandbox Code Playgroud)
如果我要手写这个方法,看起来使用以下IL可以获得相同的结果:
.method …Run Code Online (Sandbox Code Playgroud) 有没有办法以编程方式获取ildasm.exe/ilasm.exe可执行文件的FileInfo/Path?我正在尝试反编译并重新编译一个dll/exe文件后对其进行一些修改(我猜测PostSharp会做类似的事情,在编译后改变IL).
我发现了一篇博文,指出:
var pfDir = Environment.GetFolderPath(Environment.SpecialFolders.ProgramFiles));
var sdkDir = Path.Combine(pfDir, @"Microsoft SDKs\Windows\v6.0A\bin");
...
Run Code Online (Sandbox Code Playgroud)
但是,当我运行此代码时,目录不存在(主要是因为我的SDK版本是7.1),所以在我的本地机器上正确的路径是@"Microsoft SDKs\Windows\v7.1\bin".我怎样才能确保我能找到ildasm.exe?
同样,我发现了另一篇关于如何访问ilasm.exe的博文:
string windows = Environment.GetFolderPath(Environment.SpecialFolder.System);
string fwork = Path.Combine(windows, @"..\Microsoft.NET\Framework\v2.0.50727");
...
Run Code Online (Sandbox Code Playgroud)
虽然这有效,但我注意到我有Framework和Framework64,而在Framework本身中我拥有v4.0.30319的所有版本(与Framework64相同).那么,我怎么知道使用哪一个?它应该基于我正在瞄准的.NET Framework版本吗?
摘要:
所以,我有一个用C#2.0编写的第三方.dll需要强类型,我无法访问源代码.我找到了几篇关于如何反汇编.dll并用强命名密钥文件重新组装它的文章.
我遇到的问题是VS2010将其重新编译为.NET 4.0 .dll而不是2.0 .dll(我们的应用程序当前所在的版本).我不能在我的项目中包含"new"dll,因为它给我一个运行时错误:"此程序集由比当前加载的运行时更新的运行时构建,无法加载." 如果我没有签署该DLL,我会得到"程序集不是强类型".错误.
有没有办法在2.0框架中使用VS2010 ilasm.exe重新编译这个.dll?
是否有.net-core的ILDASM/ILASM等价物?
具体来说,我正在寻找在Linux上运行的东西(因此为什么是.net-core).
我在尝试使用 Visual Studio 命令提示符(反)组装 dll 时遇到了困难,看起来不像我在 microsoft page 中看到的那么简单。
我正在以这些方式使用 ildasm:
ildasm myLibrary.dll output:MyLibrary.il
Run Code Online (Sandbox Code Playgroud)
我得到:无法打开“MyLibrary.il”进行输出。
我也试过完整路径:
ildasm directory\myLibrary.dll output:directory\MyLibrary.il
Run Code Online (Sandbox Code Playgroud)
我得到:指定的多个输入文件
使用 ildasm GUI 实际上有效,但是当我使用 ilasm 时:
ilasm myLibrary.il /dll
Run Code Online (Sandbox Code Playgroud)
我得到:无法打开 'myLibrary.il',当我使用完整路径时,我得到了同样的错误。
这里有什么问题?
我在项目中使用了一些未签名的库.因为我的应用程序是强签名的,所以库也必须如此.
我用以下方式签署这些库:
"%PROGRAMFILES%\Microsoft SDKs\Windows\v7.1\Bin\ildasm.exe" /nobar /all /out=library.il library.dll
"%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\ilasm.exe" /dll /key=MyKey.snk library.il
Run Code Online (Sandbox Code Playgroud)
问题是任何元数据(例如版本号)都会在现在签名的DLL中丢失.这是一个问题,因为现在库之间的某些依赖关系被破坏了.如何保留版本号而不需要实际编译这些库的源代码?
UPDATE
它实际上是一个显示此问题的特定DLL,我发现它是使用ILMerge构建的.也许这就是问题所在.需要明确的是:ILMerge生成的DLL确实具有正确的元数据,只有在反汇编和重组后,元数据才会消失.
更新2
我在Reflector中打开了DLL,看起来至少版本号仍在那里.我一直在使用Windows资源管理器中的文件属性对话框/详细信息选项卡进行检查.所以我认为这是缺少的清单.
我有一个.il文件,我可以编译没有任何问题.我可以强烈地命名它,所以没有任何问题.但是我无法像我期望的那样通过属性设置文件版本.使用ilasm时如何设置程序集的FileVersion?
如果我往返一次,我总会得到一个.res文件,它只包含不可读的二进制数据.这个res文件里面有什么,可以编辑吗?
代码不起作用
.assembly myAssembly
{
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = { string('1.2.3.4') }
Run Code Online (Sandbox Code Playgroud) 我最近一直在编写MSIL并用ilasm编译它,当时我注意到方法确实需要一个ret指令从方法结束返回; 例如,我应该写这样的代码:
.method static void Main()
{
.entrypoint
ldstr "Hello World!"
call void [mscorlib]System.Console::WriteLine(string)
ret //I am returning properly
}
Run Code Online (Sandbox Code Playgroud)
但是,如果省略ret,代码仍会运行并输出"Hello World!" 完美.起初我认为这可能是入口点方法特有的,但是ilasm很高兴地编译这个代码既没有警告也没有错误:
.assembly Program{}
.assembly extern mscorlib{}
.method static void Main()
{
.entrypoint
ldstr "Hello World!"
call void [mscorlib]System.Console::WriteLine(string)
ldstr "Foo returned: {0}!"
call int32 Foo()
box int32
call void [mscorlib]System.Console::WriteLine(string, object)
}
.method static int32 Foo()
{
ldstr "Hello from Foo!"
call void [mscorlib]System.Console::WriteLine(string)
ldstr "GoodBye!"
call void [mscorlib]System.Console::WriteLine(string)
ldc.i4 42
}
Run Code Online (Sandbox Code Playgroud)
请注意,Main()和Foo()都没有return语句.Foo()甚至有一个返回值!编译并运行此代码时,我得到以下输出:
你好,世界!来自Foo的你好!再见!Foo回归:42!
该程序也正常终止.然后我想也许ilasm是自动插入ret语句,但是在用ildasm查看程序之后,这些方法与上面的代码相同,即没有返回.
奇怪的是,当我试图用DotPeek反编译该方法时,它拒绝用两个方法体替换 …
我查看了ILDASMstruct FooStruct中的C# ,并看到了以下内容:

ILDASM 此处显示两个不同的声明:
.class value public.class public(前窗)开头我想知道哪种语法(如果不是两种)是声明值类型的正确语法?修饰符是value严格必需的、可选的还是语法错误?