反编译 IEnumerator

Posted

技术标签:

【中文标题】反编译 IEnumerator【英文标题】:Decompiling IEnumerators 【发布时间】:2016-12-08 13:41:12 【问题描述】:

出于好奇,我决定尝试反编译我的项目代码。我获取了 Assembly .dll 文件并使用 ILSpy 对其进行了反编译。它似乎工作正常,除了IEnumerator<> 方法。

IEnumerator sP()

        for (int i = 0; i < maxEnemies; i++)
        
            var p = Porczaks[Random.Range(0, Porczaks.Length)];
            Instantiate(p, new Vector3(Random.Range(245, 360), 16.8f, Random.Range(292, 366)), Quaternion.Euler(0f, Random.Range(0f, 359f), 0f));
            yield return new WaitForEndOfFrame();
        

... 例如被解码成这样:

[DebuggerHidden]
private IEnumerator sP()

    WaveManager.<sP>c__Iterator7 <sP>c__Iterator = new WaveManager.<sP>c__Iterator7();
    <sP>c__Iterator.<>f__this = this;
    return <sP>c__Iterator;

有什么方法可以准确反编译那个IEnumerator

编辑:我使用 dotPeek 反编译器反编译了同一个程序集,它创建了更多代码。虽然我仍然不确定变量是否可以在 .net 中具有这样的名称:

// Method sP with token 060000AB
[/*Attribute with token 0C000051*/DebuggerHidden]
private IEnumerator sP()

    WaveManager.\u003CsP\u003Ec__Iterator7 sPCIterator7 = new WaveManager.\u003CsP\u003Ec__Iterator7();
    sPCIterator7.\u003C\u003Ef__this = this;
    return (IEnumerator) sPCIterator7;


// Type <sP>c__Iterator7 with token 02000031
[/*Attribute with token 0C000026*/CompilerGenerated]
private sealed class \u003CsP\u003Ec__Iterator7 : IEnumerator<object>, IEnumerator, IDisposable

    // Field <i>__0 with token 040000C7
    internal int \u003Ci\u003E__0;
    // Field <p>__1 with token 040000C8
    internal GameObject \u003Cp\u003E__1;
    // Field $PC with token 040000C9
    internal int \u0024PC;
    // Field $current with token 040000CA
    internal object \u0024current;
    // Field <>f__this with token 040000CB
    internal WaveManager \u003C\u003Ef__this;

    // Property System.Collections.Generic.IEnumerator<object>.Current with token 17000017
    object IEnumerator<object>.System\u002ECollections\u002EGeneric\u002EIEnumerator\u003Cobject\u003E\u002ECurrent
    
      // Method System.Collections.Generic.IEnumerator<object>.get_Current with token 060000EA
      [/*Attribute with token 0C00006E*/DebuggerHidden] get
      
        return this.\u0024current;
      
    

    // Property System.Collections.IEnumerator.Current with token 17000018
    object IEnumerator.Current
    
      // Method System.Collections.IEnumerator.get_Current with token 060000EB
      [/*Attribute with token 0C00006F*/DebuggerHidden] get
      
        return this.\u0024current;
      
    

    // Method .ctor with token 060000E9
    public \u003CsP\u003Ec__Iterator7()
    
      base.\u002Ector();
    

    // Method MoveNext with token 060000EC
    public bool MoveNext()
    
      uint num = (uint) this.\u0024PC;
      this.\u0024PC = -1;
      switch (num)
      
        case 0:
          this.\u003Ci\u003E__0 = 0;
          break;
        case 1:
          this.\u003Ci\u003E__0 = this.\u003Ci\u003E__0 + 1;
          break;
        default:
          return false;
      
      if (this.\u003Ci\u003E__0 < this.\u003C\u003Ef__this.maxEnemies)
      
        this.\u003Cp\u003E__1 = this.\u003C\u003Ef__this.Porczaks[UnityEngine.Random.Range(0, this.\u003C\u003Ef__this.Porczaks.Length)];
        UnityEngine.Object.Instantiate((UnityEngine.Object) this.\u003Cp\u003E__1, new Vector3((float) UnityEngine.Random.Range(245, 360), 16.8f, (float) UnityEngine.Random.Range(292, 366)), Quaternion.Euler(0.0f, UnityEngine.Random.Range(0.0f, 359f), 0.0f));
        this.\u0024current = (object) new WaitForEndOfFrame();
        this.\u0024PC = 1;
        return true;
      
      this.\u0024PC = -1;
      goto default;
    

    // Method Dispose with token 060000ED
    [/*Attribute with token 0C000070*/DebuggerHidden]
    public void Dispose()
    
      this.\u0024PC = -1;
    

    // Method Reset with token 060000EE
    [/*Attribute with token 0C000071*/DebuggerHidden]
    public void Reset()
    
      throw new NotSupportedException();
    

似乎 dotPeek 没有正确处理 &lt;&gt;,但是这段代码值得吗?

【问题讨论】:

这确实看起来像编译器会生成的。 话虽如此,JetBrains dotPeek 似乎在这方面做得更好。 我已经检查了 dotPeek,当在代码中禁用显示标记时,它看起来与 ILSpy 中的代码几乎相同,但启用它会变得非常混乱。我在第一篇文章中发布了代码。这有什么意义吗?如果我只是将名称从 &lt;i&gt;__+@!# 更改为正常名称,它会起作用吗? 如果您将奇怪的名称更改为有效的 C#,它应该可以正常工作。它只是一个状态机。当我早些时候测试它时,dotPeek 完全反编译 - 但我确实使用了一个更简单的代码示例。 不过有一个大问题。我希望能够直接在 dotPeek 中更改所有这些名称,因为当我将代码保存为 VS 项目时,它似乎跳过了所有这些 &lt;&gt;_enumerator 类,所以我必须直接从 dotPeek 代码查看器中复制它们,然后手动对所有 unicode 字符、声明和名称以及基本上整个接口实现进行像素化。我在我的代码中为一个IEnumerators 做了它,但无法测试它,因为如果我想编译 dll,还有 6 到 7 个要做。是否有任何 dP 扩展可以让我直接从它完成大部分工作? 【参考方案1】:

您确实看到了编译器生成的用于替换 yield return 语句的样板代码。是的,它确实是一个状态机。

通常反编译器应该能够识别编译器生成的样板代码并将其替换为正确的 C# 语句。然而,这种识别是通过模式匹配完成的,即样板代码应该以一种非常具体的方式进行结构化。如果编译器产生等效代码但结构不同(例如,由于编译器升级、优化等),则反编译器无法匹配模式并识别 yield 语句。

您应该做的是向反编译器团队提交错误报告,以便解决此问题,而您不必手动重命名。您是否在该程序集上尝试过 JustDecompile?它也失败了吗?如果是这样,您可以在 Telerik 论坛上发布此内容,我们会处理的。

顺便说一句,您使用的是什么编译器?

【讨论】:

以上是关于反编译 IEnumerator的主要内容,如果未能解决你的问题,请参考以下文章

反编译和反汇编有啥区别?

java反编译器怎么用?

如何反编译esriaddin文件

class文件反编译后,怎么编译回去!

EXE文件反编译成源码

eclipse怎样进行反编译?