【问题标题】:How does Reflector decompile code?Reflector 如何反编译代码?
【发布时间】:2014-01-21 22:30:37
【问题描述】:

Red Gate Ant Profiler 或 Reflector 等工具如何将 IL 转换为 C# 或 VB.NET 代码?

我最近注意到 Red Gate Ant Profiler 生成的源代码与最初编写的源代码不同。

它生成了一个while 循环,而我使用了foreach

这让我想到了。我在 Reflector 中打开了 Reflector.exe 本身,但它们的代码大部分(不是全部)都被混淆了。

【问题讨论】:

  • 为了满足你的好奇心,ILSpy 是开源的
  • 谢谢,史蒂夫。我有它在我的待办事项清单上,除此之外还有许多其他事情要通过其中一些源代码,包括 ILSpy 和 dotPeek。这是我找到的列表:stackoverflow.com/questions/2425973/…

标签: .net cil reflection.emit il reflector


【解决方案1】:

反编译器通常通过查看 IL 并构建在语义上与 IL 等效的源代码来工作。这不能总是产生原始源代码,因为 IL 丢弃了一些高级信息(尽管不如机器代码那么多),而且通常有几段代码可以编译成同一个 IL。例如,foreach 循环相当于某种while 循环(先设置一个枚举器,然后循环直到枚举器用尽,然后每一步都推进枚举器)。

【讨论】:

    【解决方案2】:

    实现反编译的一种常用技术是使用称为“区间分析”的方法来识别循环的范围。

    当与成语识别和称为“图的派生序列”的模式结合使用时,可以从包含汇编语言(或 MSIL)的控制流图开始,然后迭代地简化它,直到您拥有一个 AST(抽象语法树)节点表示程序(或方法)的“源级别”视图。给定 AST,生成源代码就很简单了:然后您就可以漂亮地打印生成的 AST。

    以下是更多信息的链接:

    http://en.wikipedia.org/wiki/Interval_(graph_theory)

    http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.50.8004&rep=rep1&type=pdf

    通常,原始源代码和反编译的源代码之间永远不会完全保真。

    foreach 循环的控制流图类似于 while 循环的控制流图。这主要是因为下面的代码:

    foreach (var x in xs) {
        //body
    }
    

    实际上是语法糖:

    var enumerator = xs.GetEnumerator()
    try {
        while (enumerator.MoveNext()) {
            var x = xs.Current;
            //body
        }
    }
    finally {
        enumerator.dispose();
    }
    

    即foreach循环基本翻译成while循环,然后while循环编译成MSIL。

    为了让反编译器产生一个 for-each 循环,它必须添加特殊支持来尝试猜测 while 循环何时实际上是一个 foreach 循环。任何这样的逻辑都不会是完美的(上面的 while 循环和 foreach 循环都应该产生相同(或非常相似)的 MSIL 代码)。

    在某些情况下它会匹配您编写的源代码,而在其他情况下则不会。

    您可能已经编写了一个 for-each 循环,因此从可用性的角度来看,在 for-each 循环和 while 循环方面犯错是一个不错的选择。

    但是,这是额外的工作。反编译器编写者必须开始说“我想添加一堆启发式方法来尝试检测 for-each 循环”。

    最后,有很多事情会阻碍反编译。例如,“break”和“continue”语句的存在确实会使事情复杂化。某些类型的嵌套也是如此(switch 语句中的循环,反之亦然)。它们都可能导致 CFG 循环具有多个入口点和多个出口点。这增加了生成可读源代码的难度。

    通常处理这些情况的唯一方法是使用启发式方法。这些启发式方法有时会“做错事”。

    此外,即使是很小的事情,例如用于循环边界的特定表达式,也会破坏习语识别。有时编译器会引入临时变量(源代码中不存在)。这可能需要额外的习语检查,或者更高级的技术,例如数据流分析(实时变量分析、定义-使用链等)。

    总结:反编译很难,而且永远不会完美。此外,我确信实施者必须考虑权衡。例如,投资检测 for-each 循环是否有意义,还是应该花时间反编译 lambda 和推断 LINQ 查询?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      • 2014-05-29
      相关资源
      最近更新 更多