【问题标题】:Recovery of local names in .Net在 .Net 中恢复本地名称
【发布时间】:2014-02-26 00:36:36
【问题描述】:

所以问题是:为什么反编译器不恢复局部变量的名称?我认为反编译器会删除有关本地名称的所有信息,并简单地使用 ldarg_0 等。这就是为什么这段代码:

    private static int Foo()
    {
        int locA = Console.ReadKey().KeyChar;
        int b = Console.ReadKey().KeyChar;
        int c = Console.ReadKey().KeyChar;
        return locA*b * c;
    }

被反编译成这个:

private static int Foo() // from .Net reflector 8.2
{
    int keyChar = Console.ReadKey().KeyChar;
    int num2 = Console.ReadKey().KeyChar;
    int num3 = Console.ReadKey().KeyChar;
    return ((keyChar * num2) * num3);
}

直到今天,我发现了一个反编译器 ILSpy,它就这样反编译它:

// ConsoleApplication101.Program

private static int Foo()
{
    int locA = (int)Console.ReadKey().KeyChar;
    int b = (int)Console.ReadKey().KeyChar;
    int c = (int)Console.ReadKey().KeyChar;
    return locA * b * c;
}

原来的代码 - 在这里! (我知道,我禁止编译器优化我的代码,但我不在乎)

问题是:为什么所有使用的反编译器(reflector、dotPeek 等)在编译器在 exe 中提供时都没有显示这些非常重要的信息!

.method private hidebysig static int32  Foo() cil managed
{
  // Размер кода:       56 (0x38)
  .maxstack  2
  .locals init ([0] int32 locA,
           [1] int32 b,
           [2] int32 c,
           [3] int32 CS$1$0000,
           [4] valuetype [mscorlib]System.ConsoleKeyInfo CS$0$0001)
  IL_0000:  nop
  IL_0001:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0006:  stloc.s    CS$0$0001
  IL_0008:  ldloca.s   CS$0$0001
  IL_000a:  call       instance char [mscorlib]System.ConsoleKeyInfo::get_KeyChar()
  IL_000f:  stloc.0
  IL_0010:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0015:  stloc.s    CS$0$0001
  IL_0017:  ldloca.s   CS$0$0001
  IL_0019:  call       instance char [mscorlib]System.ConsoleKeyInfo::get_KeyChar()
  IL_001e:  stloc.1
  IL_001f:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0024:  stloc.s    CS$0$0001
  IL_0026:  ldloca.s   CS$0$0001
  IL_0028:  call       instance char [mscorlib]System.ConsoleKeyInfo::get_KeyChar()
  IL_002d:  stloc.2
  IL_002e:  ldloc.0
  IL_002f:  ldloc.1
  IL_0030:  mul
  IL_0031:  ldloc.2
  IL_0032:  mul
  IL_0033:  stloc.3
  IL_0034:  br.s       IL_0036
  IL_0036:  ldloc.3
  IL_0037:  ret
} // end of method Program::Foo

【问题讨论】:

  • 也许其中一个使用了 .PDB 文件而一个没有?
  • 因为反编译器使用官方api访问元数据,IMetaDataImport和朋友。哪个不提供此信息。就像反射没有一样。 Ildasm 不同,可能是在 api 可用之前编写的。维护起来一定很痛苦。

标签: c# .net reflection reverse-engineering disassembly


【解决方案1】:

您的观察/假设不正确。该元数据不是 exe 的一部分。 ILSpy 和 ildasm 只能显示原始变量名称,因为这些程序读取可用的 pdb 文件。

编译后你会得到两个文件:一个exe文件和一个pdb文件。 pdb 文件包含元数据(如变量名、行号)。如果您使用能够读取附带的 pdb 文件的工具打开 exe,您会得到与原始源文件更匹配的反编译结果。

要验证您的身份,您可以将 pdb 文件重命名为不同的扩展名,然后在 ildasm 或 ilpsy 中打开 exe。
ildasm 的结果是:

// Code size       56 (0x38)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1,
           int32 V_2,
           int32 V_3,
           valuetype [mscorlib]System.ConsoleKeyInfo V_4)

存在 pdb 文件:

 // Code size       56 (0x38)
  .maxstack  2
  .locals init ([0] int32 locA,
           [1] int32 b,
           [2] int32 c,
           [3] int32 CS$1$0000,
           [4] valuetype [mscorlib]System.ConsoleKeyInfo CS$0$0001)

您可以看到差异。从 pdb 文件中读取本地名称。

要验证您的 EXE 是否可以找到 pdb,您可以使用 DUMPBIN 命令:

dumpbin /pdbPATH:VERBOSE ConsoleApplication1.exe

它将像这样呈现输出:

文件 ConsoleApplication1.exe 的转储

文件类型:可执行图像
PDB 文件“C:...\ConsoleApplication1.pdb”已检查。 (未找到文件)
PDB 文件位于 'c:...\obj\x86\Debug\ConsoleApplication1.pdb'

John Robbin (Wintellect) PDB Files: What Every Developer Must Know

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    • 2011-09-24
    • 1970-01-01
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多