Reflector如何反编译代码?

时间:2014-01-21 22:30:38

标签: .net cil reflection.emit il reflector

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

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

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

这让我想到了。我在Reflector中打开了Reflector.exe,但是他们的代码大多数(并非全部)都被混淆了。

2 个答案:

答案 0 :(得分:7)

一般来说,反编译器通过查看IL并构造语义上等同于IL的源代码来工作。这不能总是产生orignal源代码,因为IL丢弃了一些高级信息(尽管没有机器代码那么多),并且因为通常会有几段代码编译到同一个IL。例如,foreach循环等同于某种while循环(首先设置枚举器,然后循环直到枚举器耗尽,并在每一步推进枚举器)。< / p>

答案 1 :(得分:3)

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

当与习语识别相结合,并且一个模式被称为“派生的图形序列”时,可以从包含汇编语言(或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循环是一个不错的选择。

然而,这是额外的工作。反编译器编写者必须开始说“我想添加一堆启发式试图检测每个循环”。

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

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

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

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