zoukankan      html  css  js  c++  java
  • Reflector: Get the secret inside .NET assemblies.

    Reflector: Get the secret inside .NET assemblies.

    Written by Allen Lee

    用.NET编程的朋友应该都知道ILDASM的大名吧,这里为大家介绍另一个名为Reflector的好东东。为了了解Reflector,我特意写了一个代码片断(这里只给出用C#写的Main方法的代码):

    static void Main(string[] args)
    {
        List
    <string> strList = new List<string>();

        
    if (args.Length != 0)
        
    {
            
    foreach (string arg in args)
            
    {
                
    switch (arg)
                
    {
                    
    case "IL":
                        Console.WriteLine(
    "IL");
                        strList.Add(
    "IL");
                        
    break;
                    
    case "C#":
                        Console.WriteLine(
    "C#");
                        strList.Add(
    "C#");
                        
    break;
                    
    case "VB.NET":
                        Console.WriteLine(
    "VB.NET");
                        strList.Add(
    "VB.NET");
                        
    break;
                    
    case "Delphi":
                        Console.WriteLine(
    "Delphi");
                        strList.Add(
    "Delphi");
                        
    break;
                    
    default:
                        Console.WriteLine(
    "Invalid Option");
                        
    break;
                }

            }

        }

        
    else
        
    {
            Console.WriteLine(
    "No command line args!");
            Console.WriteLine(
    "Press any key to end.");
            Console.ReadLine();
        }


        
    foreach (string str in strList)
            Console.WriteLine(str);
    }

    将上面的代码进行编译,并命名为ReflectorLab.exe。然后我们运行Reflector,一开始它的界面是:

    接着,我们打开菜单:File|Open,找到并选择刚刚编译的程序集,该程序集将会被加入到程序集列表,打开ReflectorLab的树,找到Main(string[]):Void这个方法,右击并选择Disassembler,将会得到下图的反编译代码:

    现在截取反编译后的Main方法完整代码如下:

    private static void Main(string[] args)
    {
        List.Enumerator
    <string> enumerator1;
        List
    <string> list1 = new List<string>();
        
    bool flag1 = args.Length == 0;
        
    if (flag1)
        
    {
            Console.WriteLine(
    "No command line args!");
            Console.WriteLine(
    "Press any key to end.");
            Console.ReadLine();
            
    goto Label_010F;
        }

        
    string[] textArray1 = args;
        
    int num1 = 0;
        
    goto Label_00E0;
    Label_00CC:
        Console.WriteLine(
    "Invalid Option");
    Label_00D9:
        num1
    ++;
    Label_00E0:
        flag1 
    = num1 < textArray1.Length;
        
    if (flag1)
        
    {
            
    string text3 = textArray1[num1];
            
    if (text3 == null)
            
    {
                
    goto Label_00CC;
            }

            
    if (text3 != "IL")
            
    {
                
    if (text3 == "C#")
                
    {
                    Console.WriteLine(
    "C#");
                    list1.Add(
    "C#");
                    
    goto Label_00D9;
                }

                
    if (text3 == "VB.NET")
                
    {
                    Console.WriteLine(
    "VB.NET");
                    list1.Add(
    "VB.NET");
                    
    goto Label_00D9;
                }

                
    if (text3 == "Delphi")
                
    {
                    Console.WriteLine(
    "Delphi");
                    list1.Add(
    "Delphi");
                    
    goto Label_00D9;
                }

                
    goto Label_00CC;
            }

            Console.WriteLine(
    "IL");
            list1.Add(
    "IL");
            
    goto Label_00D9;
        }

    Label_010F:
        enumerator1 
    = list1.GetEnumerator();
        
    try
        
    {
            
    goto Label_0128;
        Label_0119:
            Console.WriteLine(enumerator1.Current);
        Label_0128:
            flag1 
    = enumerator1.MoveNext();
            
    if (flag1)
            
    {
                
    goto Label_0119;
            }

        }

        
    finally
        
    {
            enumerator1.Dispose();
        }

    }

    反编译的代码在功能效果上与原代码是相同的,但是个人认为反编译的代码的风格却不怎么棒,尤其是充满goto语句,乍一看我真的晕了过去。代码把原来的switch条件块换成if条件块,将foreach循环块换成while循环块。我猜这是由于它是从IL那里翻译出来的,而IL就是一门基于堆栈的语言,在IL里面没有流程控制语句,全部使用goto + Label模拟,于是得到这样的结果。

    除此之外,我还发现一些很特别的东西,请留意这一句:text3 = string.IsInterned(text3); 它其实反映了.NET的字符串处理方式是使用了一种叫做字符串驻留(String Interning)的技术,该技术是为了减轻字符串的操作为系统带来的性能损失(详细请参见《Microsoft .NET框架程序设计(修订版)》的262页)。另外我们看到原代码最后的foreach被翻译成一个try...finally块,在try里面实现foreach的功能,然后再finally里面自动为每一个enumerator试着调用IDisposable接口来释放资源,真是想得周到相信对应的IL也会有同样的“设施”,如果你懂IL的话,而你又肯定在这里不需要这样一个finally的话,那么你可以手动优化一下了,呵呵。

    翻译后的代码是有点复杂和混乱,不过,你可以从中窥探.NET的(部分)运行机制(而这种窥探原本是应该使用IL的),并了解到简单的C#代码背后,编译器在默默地为我们作了不少的工作!最后,我们还会惊喜地发现,Reflector不但支持反汇编成C#,还支持IL、VB.NET、Delphi,这下子爽了,我们可以比较并学习这些语言,以前我们用ILDASM来反汇编C#写的程序来学习IL,现在我们可以用Reflector反汇编C#写的程序来学习VB.NET和Delphi啦!当然,由于篇幅的问题,我不可以再往里面灌水(依次加入IL、VB.NET、Delphi反编译的代码)。

    另外,你会发现这些源代码的某些地方,通常是类型名称或者方法名称又或者属性会是一个连接,按下去看看有什么事发生!是不是连接到该东西(类型或者方法或者属性)的.NET基类库的反编译代码上了?

    最后,在文章的结束,我还有一个惊喜给你,就是Reflector本身是一个.NET程序,这意味着它还可以反汇编它自己,不信的话你可以试试看!

    噢,补充一点,当你运行Reflector后,它会在它所在的文件夹会生成一个叫Reflector.cfg的文件,这个不是XML文件,是一种INI格式的配置文件,请留意该文件的[AssemblyLoader]区段,有什么发现了没有?好了,这次的介绍就到此为止,希望你发现更多的东西来跟我分享!

  • 相关阅读:
    2016/10/18 数据库设计三大范式
    2016/10/13 Oracle COALESCE()
    2016/10/13 oracle中的round()
    2016/10/10 数据、数据元素和数据项
    2016/09/29 Maven简介
    2016/09/29 瀑布模型开发和敏捷开发
    python2和python3中的类
    使用JQuery完成页面定时弹出广告
    JQuery入门+js库文件分享
    使用JavaScript完成控制下拉列表左右选择
  • 原文地址:https://www.cnblogs.com/allenlooplee/p/55852.html
Copyright © 2011-2022 走看看