<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【轉(zhuǎn)自看雪】從reflector實(shí)現(xiàn)看.net的混淆與反混淆技術(shù)

      標(biāo) 題: 從reflector實(shí)現(xiàn)看.net的混淆與反混淆技術(shù)【原創(chuàng)】
      作 者: dreaman
      時(shí) 間: 2006-12-31,13:07
      鏈 接: http://bbs.pediy.com/showthread.php?t=37217

      【文章標(biāo)題】: 從reflector實(shí)現(xiàn)看.net的混淆與反混淆技術(shù)
      【文章作者】: dreaman
      【作者郵箱】: dreaman_163@163.com
      【作者主頁】: http://dreaman.haolinju.net
      【軟件名稱】: reflector 4.2.50.0
      【軟件大小】: 850KB
      【下載地址】: http://www.aisto.com/roeder/dotnet/
      【加殼方式】: 
      【保護(hù)方式】: 多種混淆+加密壓縮主功能文件內(nèi)嵌到框架程序資源段
      【編寫語言】: 未知
      【使用工具】: reflector,vs.net 2005,自編反名稱混淆工具與反編譯工具
      【操作平臺(tái)】: winxp , .net 2.0
      【軟件介紹】: .net 程序反編譯工具,差不多無人不知了吧。
      【作者聲明】: 主要是出于學(xué)習(xí)目的,別無他意:)


      一直想利用C#或C++這類語言的編譯優(yōu)化功能來反.net程序的流程混淆,做過一些簡(jiǎn)單的試驗(yàn),這個(gè)思路是可行的
      ,但是目前的反編譯工具reflector,dis#,spices.net對(duì)做了流程混淆的程序都不能正常反編譯,不得已我只好嘗
      試自己寫一個(gè)將IL反編譯成高級(jí)語言語法的工具,我的目標(biāo)與前面的反編譯工具不太一樣,主要在于將混淆過的IL
      代碼反成等價(jià)的僅僅語法上可編譯的高級(jí)語言結(jié)構(gòu)(不使用if,while,do-while,for,for-each等高級(jí)語言構(gòu)造,而
      是使用goto語句,再經(jīng)由高級(jí)語言編譯器優(yōu)化編譯后,再用前述工具才可以看到使用這些構(gòu)造的便于人看的代碼)
      ,我主要針對(duì)reflector采用的混淆方式來進(jìn)行開發(fā),因此本文主要講述的混淆方式都來自reflector。

      一、reflector的保護(hù)
      1、名稱混淆
      reflector使用不可見名作名稱混淆,用它自己看的話都是框框。

      2、主功能文件隱藏,字節(jié)碼直接裝入內(nèi)存使用
      reflector能夠十分容易的查找多個(gè)文件間的交叉引用,但當(dāng)我們用reflector來看reflector.exe的交叉引用時(shí)卻發(fā)
      現(xiàn)主要接口都沒有對(duì)應(yīng)實(shí)現(xiàn),后來反編譯后調(diào)試時(shí)才發(fā)現(xiàn),reflector.exe其實(shí)只是個(gè)框架,主要是定義了reflector
      的接口,另外是啟動(dòng)代碼部分,接口的實(shí)現(xiàn)差不多都在另一個(gè)文件里。
      在編譯后調(diào)試還發(fā)現(xiàn)另一個(gè)保護(hù),就是reflector.exe的關(guān)鍵函數(shù)都加了屬性[DebuggerHidden],這樣在使用vs.net
      調(diào)試跟蹤時(shí)會(huì)直接跳過這些函數(shù),無法跟蹤到函數(shù)內(nèi),當(dāng)然這種保護(hù)很弱,注釋掉就可以了。

      下面我們來看一下reflector啟動(dòng)的過程,首先是程序入口點(diǎn)函數(shù):
      [STAThread, DebuggerHidden]  <--這里加了屬性,如果不去掉,程序就沒法調(diào)試,直接運(yùn)行起來了,呵呵。
      public static void Main()
      {
            
      if (!T_x2.M_x1())
            
      {
                  MessageBox.Show(a(
      "\ucf95\uf797\uef99\ubc9b\ufd9d\uc19f\ucca1\ucaa3\uc9a5\udca7\u8aa9\uc0ab\ucfad\uc5af\udcb1\ud7b3\udeb5\u98b7\uceb9\ud4bb\ud7bd\ub3bf\ue2c1\ua5c3\ub6c5\ub8c7\ua6c9\ua5cb\uadcd\ub1cf\ua6d1\ubdd3\ub9d5\ub6d7\ufad9\ubadb\uacdd\u8fdf\u8fe1\uc4e3\u87e5\uc8e7\u84e9\u89eb\u9aed\u87ef\u9df1\u86f3\u9df5\ud8f7\u89f9\u94fb\u9ffd\u72ff\u6701\u2a03\u2605\u5807\u6609\u690b\u6f0d\u630f\u7711\u3413\u6215\u6a17\u6319\u3c1b\u6c1d\u551f\u4c21\u4a23\u4f25\u4627\u4d29\u0c2b\u472d\u442f\u1231\u5233\u4435\u5737\u5739\u1c3b\u5f3d\u603f\u2e41\u2b43\u2545\u2947\u2649\u6c4b\u2a4d\u394f\u2051\u3153\u3555\u2c57\u3559\u2e5b\u275d\u4e5f"9), typeof(T_x2).Assembly.Location, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }

            
      else
            
      {
                  T_x2 _x1 
      = new T_x2(null);
                  
      try
                  
      {
                        _x1.M_x6();
                  }

                  
      finally
                  
      {
                  }

            }

      }


      Main中的if語句調(diào)用的T_x2::M_x1函數(shù)的內(nèi)容:
      [return: MarshalAs(UnmanagedType.U1)]
      private static bool M_x1()
      {
            
      try
            
      {
                  
      new PermissionSet(PermissionState.Unrestricted).Demand();
            }

            
      catch (SecurityException)
            
      {
                  
      return false;
            }

            
      return true;
      }


      這個(gè)是檢查權(quán)限的,如果通不過就提示說不要從網(wǎng)絡(luò)共享里啟動(dòng)程序。彈出消息使用全局函數(shù)a解密,這個(gè)函數(shù)我們后面再說。
      安全檢查通過后會(huì)構(gòu)造T_x2類實(shí)例,構(gòu)造內(nèi)容:
      [DebuggerHidden]  <--又是不讓調(diào)試!
      public T_x2(IWindowManager A_0)
      {
            
      this.M_x1(A_0);
      }


      調(diào)了M_x1(IWindowManager):
      [DebuggerHidden]  <--又是不讓調(diào)試!
      private void M_x1(IWindowManager A_0)
      {
            
      string text1 = T_x4.M_x2();
            
      object obj1 = Activator.CreateInstance(T_x3.F_x1.GetType(text1, true), new object[] { A_0 });
            
      this.F_x1 = (IServiceProvider) obj1;
      }


      這個(gè)函數(shù)時(shí)創(chuàng)建了一個(gè)對(duì)象,比較關(guān)鍵了,它的第一行使用了T_x4.M_x2():
      internal static string M_x2()
      {
            
      return a("\uc390\uf692\uf394\ufb96\ufc98\uf89a\ue99c\uf09e\ud3a0\u8da2\ue4a4\ud7a6\ud9a8\uc7aa\uc4ac\uccae\ud0b0\uc7b2\udcb4\ud8b6\ud7b8\u95ba\ufcbc\ucfbe\ub1c0\uafc2\uacc4\ua4c6\ua8c8\ubfca\ua4cc\ua0ce\ubfd0\u9ed2\ub4d4\ub9d6\ub8d8\ubcda\ub8dc\uadde"4);
      }

      原來只是取一個(gè)字符串,跟到解密函數(shù)里看一下,是"Reflector.Application.ApplicationManager",這個(gè)名字有點(diǎn)意思了,reflector.exe
      里并不包含Reflector.Application名空間,也沒有ApplicationManager這個(gè)類。
      M_x1(IWindowManager)在取出上面的字符串后就用T_x3.F_x1.GetType來取對(duì)應(yīng)此名字的類型了,T_x3.F_x1這個(gè)字段的類型是

      internal static Assembly F_x1;

      它的初化化在靜態(tài)構(gòu)造里:
      static T_x3()
      {
            T_x3.F_x1 
      = typeof(T_x2).Assembly;
      }


      用的Assembly是T_x2所屬的Assembly,其它只是用標(biāo)準(zhǔn).net的功能而已,也就是說到這里T_x2的Assembly里已經(jīng)有Reflector.Application.ApplicationManager
      這個(gè)Type了!回頭再看一下從入口點(diǎn)過來的代碼,好象沒有別的代碼了,有點(diǎn)怪?呵呵,reflector利用了類的靜態(tài)構(gòu)造來做實(shí)際工作了,前面的過程中一共
      涉及3個(gè)類T_x2,T_x3,T_x4,T_x2沒有靜態(tài)構(gòu)造,T_x3的上面剛看了,就剩下T_x4了,我們來瞧一下:
      [DebuggerHidden]  <--汗,又來了!!!
      static T_x4()
      {
            
      byte[] buffer1 = T_x4.M_x1();
            SymmetricAlgorithm algorithm1 
      = new TripleDESCryptoServiceProvider();
            
      string text2 = a("\udc94\ub096\uf498\ubb9a\uee9c\uf09e\ud3a0\ud1a2\udca4\u87a6\udda8\uc4aa\u8dac\udcae\ud4b0\ud6b2\u95b4\uceb6\ud6b8\uceba\u9dbc\udebe\ub3c0\ua6c2\ue5c4\ua3c6\ua6c8\ua2ca\ua3cc\ua8ce\uf1d0\ua7d2\ubdd4\ubed6\uaad8\ufbda\uaedc\ubede\u85e0\uc3e2\u86e4\u95e6\u88e8\u88ea\u86ec\u86ee\u9ff0\u94f2\ud5f4\u92f6\u81f8\u9efa\u8ffc\u9cfe\u6800\u7002\u6004\u2906\u2908\u5b0a\u610c\u6a0e\u7010\u6012\u7014\u3716\u6a18\u7e1a\u731c\u7b1e\u0120\u4e22\u4024\u0726\u4828\u452a\u0d2c\u6a2e\u5c30\u5232\u5c34\u5b36\u1938\u5a3a\u493c\u1f3e\u6640\u3142\u2a44\u2246\u2d48\u2e4a\u3f4c\u0f4e\u3050\u3a52\u2654\u2356\u3658\u755a\u3e5c\u305e\u0c60\u4462\u4564\u1466\u0668\u4b6a\u1a6c\u0a6e\u5170\u1072\u1474\u1976\u5978\u187a\u157c\u1e7e\uf580\ua382\ue484\ue586\ue688\ufe8a\uf98c\uaf8e\uf090\ub392\uf894\uf896\ueb98\ufe9a\ubd9c\uf29e\uc4a0\uc2a2\ucba4\ucea6\uc7a8\uccaa\ucbac\udaae\uddb0\u93b2\uc6b4\ud8b6\ud5b8\uceba\uc9bc\ud6be\uaec0\uadc2\uebc4\ue7c6\u80c8\uecca\ua0cc\uefce\ub2d0\ua6d2\ua7d4\ubed6\ub6d8\uaeda\uaedc\uffde\u96e0\u8be2\u9ce4\uc7e6\u90e8\u84ea\u98ec\ucfee\u90f0\u81f2\u90f4\ud7f6\u9df8\u94fa\u94fc\u91fe\u6600\u2302\u7104\u6f06\u6008\u780a\u230c\u2f0e\u4510\u7b12\u7014\u6516\u7c18\u3b1a\u701c\u6a1e\u5220\u5722\u0524\u4526\u4c28\u0b2a\u4c2c\u0f2e\u5c30\u5c32\u4734\u5236\u1938\u4b3a\u4f3c\u503e\u2540\u3642\u2644\u3346\u2048\u3d4a\u284c\u6f4e\u2650\u3252\u2c54\u7756\u2d58\u345a\u7d5c\u325e`\u0862d\u4766\u1068\u046a\u186c\u4f6e\u1970\u1272\u0574\u0776x\u557a"8);
            
      byte[] buffer3 = Encoding.ASCII.GetBytes(text2);
            
      byte[] buffer2 = new MD5CryptoServiceProvider().ComputeHash(buffer3);
            algorithm1.Key 
      = buffer2;
            algorithm1.Mode 
      = CipherMode.ECB;
            
      int num1 = buffer1.Length;
            buffer1 
      = algorithm1.CreateDecryptor().TransformFinalBlock(buffer1, 0, num1);
            T_x1 _x1 
      = new T_x1(new MemoryStream(buffer1));
            _x1.M_x8();
            T_x7 _x2 
      = (T_x7) _x1.M_x6();
            ResolveEventHandler handler1 
      = new ResolveEventHandler(T_x4.M_x1);
            AppDomain.CurrentDomain.AssemblyResolve 
      += handler1;
            
      string text1 = a("\ud994\uf896\uf898\uff9a"8);  //這個(gè)字符串解出來是Load
            Type[] typeArray1 = new Type[1];
            Type type1 
      = typeof(byte[]);
            typeArray1[
      0= type1;
            
      object[] objArray1 = new object[] { _x2.M_x1() };
            
      object obj1 = typeof(T_x3).GetFields(BindingFlags.NonPublic | BindingFlags.Static)[0].FieldType.GetMethod(text1, typeArray1).Invoke(null, objArray1);
            
      typeof(T_x3).GetFields(BindingFlags.NonPublic | BindingFlags.Static)[0].SetValue(null, obj1);
      }


      呵呵,看到有關(guān)加密的東東了,TripleDES、MD5!在解密之前調(diào)了T_x4.M_x1:
      private static byte[] M_x1()
      {
            
      byte[] buffer2 = null;
            
      string text2 = typeof(T_x2).Module.FullyQualifiedName;
            FileStream stream1 
      = File.OpenRead(text2);
            
      try
            
      {
                  BinaryReader reader1 
      = new BinaryReader(stream1);
                  BinaryReader reader2 
      = reader1;
                  
      try
                  
      {
                        T_x4.T_x2 _x1 
      = new T_x4.T_x2(reader1);
                        T_x4.T_x2 _x6 
      = _x1;
                        
      ushort num5 = _x1.M_x20();
                        T_x4.T_x5 _x3 
      = new T_x4.T_x5(reader1, num5);
                        T_x4.T_x5 _x5 
      = _x3;
                        
      string text1 = a("\ub895\uea97\ue999\uee9b\ufd9d"9); //這個(gè)字符串解出來是.rsrc
                        T_x4.T_x6 _x2 = _x3.M_x1(text1);
                        T_x4.T_x6 _x4 
      = _x2;
                        
      uint num4 = _x2.M_x2();
                        
      int num3 = _x1.M_x7().M_x5();
                        reader1.BaseStream.Position 
      = num3 + num4;
                        
      int num2 = reader1.ReadInt32();
                        
      int num6 = num2;
                        
      byte[] buffer1 = reader1.ReadBytes(num2);
                        
      byte[] buffer3 = buffer1;
                        
      return buffer1;
                  }

                  
      finally
                  
      {
                        
      int num1 = 2;
                        
      if (reader2 != null)
                        
      {
                              num1 
      = 1;
                              num1 
      = 0;
                        }

                  }

            }

            
      finally
            
      {
            }

            
      return buffer2;
      }


      可以看到是讀reflector.exe的.rsrc段,原來reflector.exe把它的關(guān)鍵代碼放在框架程序里了。接著看T_x4的靜態(tài)構(gòu)造,
      先解密了一個(gè)字符串:

      "I'm sorry to see you are doing this sad cracking exercise. Please send me an Email at 'roeder@aisto.com' 
      so we can chat about a more meaningful solution. I'm curious why you are doing this. There must be a more 
      productive way to make you happy." 
       
      汗了,原來是讓偶不要研究他的程序了。
      reflector用了這段話的md5 hash值作TripleDES的密鑰,有點(diǎn)搞笑了。解密完之后是一段可能是驗(yàn)證與解壓的過程(沒細(xì)看),
      完了開始裝入,最后兩句話的本意是
      T_x3.F_x1=Assembly.Load(byte[]);
      故意用了一段基于reflection api的寫法,迷惑人!到這時(shí)也才發(fā)現(xiàn)原來T_x3的靜態(tài)構(gòu)造里對(duì)T_x3.F_x1的初始化居然也
      是用來迷惑人的,reflector的作者真的是別具匠心了。

      現(xiàn)在回到M_x1(IWindowManager):
      [DebuggerHidden]  
      private void M_x1(IWindowManager A_0)
      {
            
      string text1 = T_x4.M_x2();
            
      object obj1 = Activator.CreateInstance(T_x3.F_x1.GetType(text1, true), new object[] { A_0 });
            
      this.F_x1 = (IServiceProvider) obj1;
      }


      本意是:

      object obj=Activator.CreateInstance(assembly.GetType("Reflector.Application.ApplicationManager"),new object[]{null}); 
      this.F_x1 = (IServiceProvider)obj;
      到這里,真正的功能代碼已經(jīng)裝入了,并且已經(jīng)實(shí)例化了一個(gè)ApplicationManager對(duì)象,現(xiàn)在回到reflector.exe的入口
      函數(shù)了:
      [STAThread, DebuggerHidden]
      public static void Main()
      {
            
      if (!T_x2.M_x1())
            
      {
                  MessageBox.Show(a(
      "\ucf95\uf797\uef99\ubc9b\ufd9d\uc19f\ucca1\ucaa3\uc9a5\udca7\u8aa9\uc0ab\ucfad\uc5af\udcb1\ud7b3\udeb5\u98b7\uceb9\ud4bb\ud7bd\ub3bf\ue2c1\ua5c3\ub6c5\ub8c7\ua6c9\ua5cb\uadcd\ub1cf\ua6d1\ubdd3\ub9d5\ub6d7\ufad9\ubadb\uacdd\u8fdf\u8fe1\uc4e3\u87e5\uc8e7\u84e9\u89eb\u9aed\u87ef\u9df1\u86f3\u9df5\ud8f7\u89f9\u94fb\u9ffd\u72ff\u6701\u2a03\u2605\u5807\u6609\u690b\u6f0d\u630f\u7711\u3413\u6215\u6a17\u6319\u3c1b\u6c1d\u551f\u4c21\u4a23\u4f25\u4627\u4d29\u0c2b\u472d\u442f\u1231\u5233\u4435\u5737\u5739\u1c3b\u5f3d\u603f\u2e41\u2b43\u2545\u2947\u2649\u6c4b\u2a4d\u394f\u2051\u3153\u3555\u2c57\u3559\u2e5b\u275d\u4e5f"9), typeof(T_x2).Assembly.Location, MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }

            
      else
            
      {
                  T_x2 _x1 
      = new T_x2(null);
                  
      try
                  
      {
                        _x1.M_x6();
                  }

                  
      finally
                  
      {
                  }

            }

      }


      在try塊內(nèi)調(diào)_x1.M_x6():

      public void M_x6()
      {
            IServiceProvider provider1 
      = this.F_x1;
            
      if (provider1 != null)
            
      {
                  
      string text1 = a("\uc899\ue99b\uf09d"13); //這個(gè)字符串解出來是Run
                  provider1.GetType().GetMethod(text1).Invoke(this.F_x1, null);
            }

      }


      又是一段reflection api的寫法,本意是:

      ((IServiceProvider)(
      this.F_x1)).Run();

      其實(shí)這才是程序真正的入口!
      3、流程混淆及結(jié)構(gòu)類混淆技術(shù)
      reflector在混淆上用的花樣實(shí)在太多,這個(gè)在下一部分說了。

      4、獲取真正功能實(shí)現(xiàn)文件
      主要是改兩個(gè)地方,一個(gè)是讀文件的地方,一個(gè)是解密后:
      1)將T_x4.M_x1()里的FileStream stream1 = File.OpenRead(text2);改為
      FileStream stream1 = File.OpenRead("d:\\reflector.exe");//假設(shè)原始的reflector.exe放在這個(gè)地方
      2)在T_x4的靜態(tài)構(gòu)造里object[] objArray1 = new object[] { _x2.M_x1() };后面加上
      byte[] data=objArray1[0] as byte[];
      FileStream fs = new FileStream("d:\\reflector.application.dll", FileMode.Create, FileAccess.Write);
      fs.Write(data,0,data.Length);
      fs.Close();

      之后執(zhí)行到fs.Close();后,我們就得到reflector.application.dll,這個(gè)文件大小是1756KB,在它的托管資源部分還嵌了
      一個(gè)可執(zhí)行文件reflector.install.exe

      二、reflector用到的混淆技術(shù)
      我覺得可以將reflector用到的混淆技術(shù)除名稱混淆外分為兩類,一類是防止反編譯的混淆,另一類是防止重編譯的混淆
      (一)防止反編譯的混淆(數(shù)據(jù)流或控制流混淆)
      1、無用條件跳轉(zhuǎn)或永真條件跳轉(zhuǎn)
            L_000f: ldc.i4.0 
            L_0010: dup 
            L_0011: ldc.i4.1 
            L_0012: blt.s L_0047
      上面這段代碼的條件跳轉(zhuǎn)是if(0<1)goto L_0047;這是永遠(yuǎn)成立的跳轉(zhuǎn),等價(jià)于一條goto語句,與之對(duì)應(yīng),還有一類條件跳
      轉(zhuǎn)是永遠(yuǎn)不成立的跳轉(zhuǎn),就是可以刪除的跳轉(zhuǎn)。

      2、塊間來回跳轉(zhuǎn)
      這應(yīng)該就是流程混淆的最初形態(tài)了,簡(jiǎn)單說就是將順序執(zhí)行的指令序列分為若干塊,然后打亂順序,再用goto將這些塊連接
      為原來的執(zhí)行順序。

      --附帶說一下,1與2這兩種情形都是可以經(jīng)過編譯優(yōu)化處理的。

      3、用switch作跳轉(zhuǎn)
      用switch作跳轉(zhuǎn)是比較有意思的,這里用一段C#說明,比用IL應(yīng)該更清楚:
      int v=0;
        
      goto IL_01;
      IL_01:
        
      switch(v)
        
      {
          
      case 0:goto IL_02;
          
      case 1:goto IL_03;
          
      case 2:goto IL_04;
          
      case 3:goto IL_05;
          
      default:goto IL_06;
        }

      IL_02:
        做實(shí)際工作
        v
      =1;
        
      goto IL_01;
      IL_03:
        做實(shí)際工作
        v
      =2;
        
      goto IL_01;
      IL_04:
        做實(shí)際工作
        v
      =3;
        
      goto IL_01;
      IL_05:
        做實(shí)際工作
        v
      =4;
        
      goto IL_01;
      IL_06:
        做實(shí)際工作
        
      return
      上面這段代碼實(shí)際上是順序執(zhí)行的,這段代碼如果用C#編譯,IL_02到IL_06的代碼會(huì)嵌到switch里面各個(gè)標(biāo)簽處,也就是說
      編譯器將這些goto連接起來了,但這種優(yōu)化卻不能實(shí)現(xiàn)反混淆,這個(gè)switch的所有跳轉(zhuǎn)其實(shí)都是編譯時(shí)能計(jì)算的
        v=1;
        goto IL_01;
      這樣模式的句子實(shí)際上就是無條件跳轉(zhuǎn)goto IL_03,真正原始的代碼就是去掉上面的v變量定義,switch語句、所有對(duì)v的賦值
      以及所有g(shù)oto語句后剩下的代碼。

      4、catch塊跳往try塊
        try
        {
      IL_0001:
        ...
        }
        catch(Exception)
        {
        ...
        leave.s IL_0001
        }
      這樣的可能算不上混淆,不過直接反編譯為C#或C++時(shí)這樣的跳轉(zhuǎn)是不合法的,在高級(jí)語言中g(shù)oto只能跳轉(zhuǎn)同一塊或者是外層塊
      ,而不能跳到嵌入塊或其它塊中。此外,有多層try-catch時(shí)在塊間跳轉(zhuǎn)在IL級(jí)也是合法的,這種混淆會(huì)成為反混淆的難題。(
      手工反應(yīng)該不難,應(yīng)該主要難在自動(dòng)處理上,特別是使用了filter與fault塊的情況)

      5、用堆棧儲(chǔ)存值
      這種方式對(duì)付目前的反編譯軟件是最有效的,這里我們看一下reflector用來解密字符串的函數(shù),函數(shù)IL指令后面的//注釋開始的
      代碼是按IL指令序列反出來的C#代碼,()包括的內(nèi)容是執(zhí)行完IL指令后的堆棧內(nèi)容,右邊是棧頂,我們用這種方式模擬反編譯的
      過程,因?yàn)镮L指令是基于堆棧計(jì)算的,函數(shù)的數(shù)據(jù)流主要反映在堆棧中,而高級(jí)語言是基于變量與表達(dá)式的,將堆棧計(jì)算還原到
      到變量與表達(dá)式就是反編譯了。
      .method privatescope hidebysig static string a(string A_0_1, int32 A_1_2) cil managed
      {
            .maxstack 
      8
            .locals init (
                  [
      0char[] loc0,
                  [
      1] int32 loc1,
                  [
      2] int32 loc2,
                  [
      3] unsigned int8 loc3,
                  [
      4] unsigned int8 loc4)
            L_0000: ldarg.
      0 
            L_0001: callvirt instance 
      char[] string::ToCharArray()
            L_0006: stloc.
      0         //loc0=A_0_1.ToCharArray();
            L_0007: ldc.i4 832044172
            L_000c: ldarg.
      1 
            L_000d: add 
            L_000e: stloc.
      1        //loc1=832044172+A_1_2;
            L_000f: ldc.i4.0         (0)
            L_0010: br.s L_0045
      -----------------------------------------------------------------------------------------------------------------------      
            L_0012: dup 
            L_0013: stloc.
      2        //loc2=stack_top;      
            L_0014: ldloc.0         
            L_0015: ldloc.
      2 
            L_0016: ldloc.
      0      
            L_0017: ldloc.
      2 
            L_0018: ldelem.i2       (
      0,loc0,loc2,loc0[loc2])
            L_0019: dup         (
      0,loc0,loc2,loc0[loc2],loc0[loc2])
            L_001a: ldc.i4 
      255  
            L_001f: and             (
      0,loc0,loc2,loc0[loc2],loc0[loc2] & 255)
            L_0020: ldloc.
      1     
            L_0021: dup         (
      0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1,loc1)
            L_0022: ldc.i4.
      1     
            L_0023: add             (
      0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1,loc1+1)
            L_0024: stloc.
      1         (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1)    
                  
      //loc1=loc1+1
                  
            L_0025: xor         
            L_0026: conv.u1 
            L_0027: stloc.
      3         (0,loc0,loc2,loc0[loc2])
                  
      //loc3=(loc0[loc2] & 255) ^ loc1  
                  
      //這里的loc1不是上面+1后的loc1,而應(yīng)該是+1操作前的loc1
            
            L_0028: dup 
            L_0029: ldc.i4.
      8     
            L_002a: shr         (
      0,loc0,loc2,loc0[loc2],loc0[loc2] >> 8)
            L_002b: ldloc.
      1     
            L_002c: dup         (
      0,loc0,loc2,loc0[loc2],loc0[loc2] >> 8,loc1,loc1)
            L_002d: ldc.i4.
      1     
            L_002e: add         (
      0,loc0,loc2,loc0[loc2],loc0[loc2] >> 8,loc1,loc1+1)
            L_002f: stloc.
      1         (0,loc0,loc2,loc0[loc2],loc0[loc2] >> 8,loc1)
                  
      //loc1=loc1+1
            
            L_0030: xor             
            L_0031: conv.u1 
            L_0032: stloc.s num4      (
      0,loc0,loc2,loc0[loc2])   
                  
      //loc4=(loc0[loc2] >> 8) ^ loc1     
                  
      //這里的loc1不是上面+1后的loc1,而應(yīng)該是+1操作前的loc1

            L_0034: pop         (
      0,loc0,loc2)
            L_0035: ldloc.s num4      (
      0,loc0,loc2,loc4)
            L_0037: ldloc.
      3 
            L_0038: stloc.s num4      (
      0,loc0,loc2,loc4)    
                  
      //loc4=loc3      
            L_003a: stloc.3         (0,loc0,loc2)
                  
      //loc3=loc4 
                  
      //這里的loc4是棧中保存的原來的loc4,并不是上一語句改變過其值的loc4
            
            L_003b: ldloc.s num4    
            L_003d: ldc.i4.
      8 
            L_003e: shl         (
      0,loc0,loc2,loc4 << 8)
            L_003f: ldloc.
      3         (0,loc0,loc2,loc4 << 8,loc3)
            L_0040: or         (
      0,loc0,loc2,((loc4 << 8| loc3))
            L_0041: conv.u2         
            L_0042: stelem.i2       (
      0)        
                  
      //loc0[loc2]=((loc4 << 8) | loc3)
            L_0043: ldc.i4.1         
      ----------------------------------------------------------------------------------------------------------------------------------------------
            L_0044: add                                                 (
      0 + 1)
            L_0045: dup         (
      0,0)        第二次執(zhí)行的堆棧內(nèi)容:(1,1)
            L_0046: ldloc.
      0         (0,0,loc0)      第二次執(zhí)行的堆棧內(nèi)容:(1,1,loc0)
            L_0047: ldlen         (
      0,0,len(loc0))      第二次執(zhí)行的堆棧內(nèi)容:(1,1,len(loc0))
            L_0048: conv.i4         
            L_0049: blt.s L_0012      (
      0)        第二次執(zhí)行的堆棧內(nèi)容:(1)
                  
      //if(0<len(loc0)) goto L_0012;            //if(1<len(loc0)) goto L_0012
      ----------------------------------------------------------------------------------------------------------------------------------------------
            L_004b: pop             
            L_004c: ldloc.
      0                                             
            L_004d: newobj instance 
      void string::.ctor(char[])          
            L_0052: call 
      string string::Intern(string)                  
            L_0057: ret         
      //return String.Intern(new string(loc0))                                        return string.Intern(new String(loc0))
      }

      上面代碼中有二類導(dǎo)致反編譯失效的情形:
      1)、觀察我們用括號(hào)列出的堆棧分析,可以看到在L_0012到L_0042指令,堆棧一直不為空,有一個(gè)值在整個(gè)塊中從未出過堆棧,此值在L_0044時(shí)執(zhí)行+1操作,仍然不
      出棧,直到L_0049跳轉(zhuǎn)回L_0012,可以看到這是一個(gè)循環(huán),從函數(shù)入口跳到L_0044開始執(zhí)行,之后每次循環(huán)棧底的值被加1,此值同時(shí)用作循環(huán)條件。如果我們簡(jiǎn)單
      按照注釋部分生成C#代碼,則此循環(huán)被忘記了(因?yàn)檠h(huán)變量是用棧作的)。

      2)、L_0023、L_002e兩處對(duì)棧頂值執(zhí)行+1操作,此時(shí)棧中保存著對(duì)應(yīng)變量的兩份值,稍后棧頂值再次賦給原變量,原變量值改變,但棧中仍保存了一份此變量被必變
      前的值;這種情況還有一處出現(xiàn),L_0038處對(duì)變量loc4賦值,賦值后棧中仍保存著原來的loc4值,緊接著對(duì)loc3賦值時(shí)使用了。也就是說,棧在操作中起到了臨時(shí)變量
      的作用。我們來看與L_0023處堆棧操作相關(guān)的反編譯:
        loc1=loc1+1;
        loc4=(loc0[loc2] >> 8) ^ loc1
      這樣結(jié)果就不正確了,考慮到棧起到臨時(shí)變量的作用,實(shí)際上可以寫成:
        temp1=loc1;
        loc1=temp1+1;
        loc4=(loc0[loc2] >> 8) ^ temp1;
      這樣三句就與原IL程序等價(jià)了。我們?cè)倏匆幌翷_0038處的反編譯:
        loc4=loc3;
        loc3=loc4;
      這也是不正確的,考慮棧的臨時(shí)變量作用,寫成:
        temp2=loc4;
        loc4=loc3;
        loc3=temp2;
      這樣就正確了。
      大家可以用dis#,spices.net分別反一下reflector的這個(gè)函數(shù),看看他們的反編譯能力。(reflector比較狡猾,它只要發(fā)現(xiàn)堆棧有問題就說可以是混淆代碼,不給反
      了,呵呵)

      (二)防止重編譯的混淆(結(jié)構(gòu)混淆)
      這種混淆我把它稱為結(jié)構(gòu)混淆,就是通過使用高級(jí)語言沒有對(duì)應(yīng)實(shí)現(xiàn)的語法結(jié)構(gòu)來混淆,使得反編譯后的程序無法通過編譯,一般的反編譯程序是不會(huì)考慮這個(gè)問題
      的,因?yàn)樗鼈兺ǔ2皇菫榱俗尨蠹抑匦戮幾g的,呵呵。
      1、使用filter,fault的異常塊,在C#中沒有對(duì)應(yīng)構(gòu)造,C++中對(duì)應(yīng)也不太明確。

      2、引用與非引用參數(shù)在C++中是不區(qū)分的,不過C#與.net里是區(qū)分的,如
      ref class A
      {
        void Test(int i);
        void Test(int% i);
      };
      這樣的定義雖然可以通過編譯,但是卻不能被調(diào)用
      A^ a=gcnew A();
      a->Test(1);
      編譯時(shí)會(huì)說無法決定使用哪個(gè)重載。

      3、外層類與嵌入類同名,這在C#與C++中都是不允許的,如
      class A
      {
        Class A
        {
        }
      }
      這樣的定義是不合法的。
      4、類的完全限定名不能恰好是另一個(gè)類的完全限定名的后綴,這在定義時(shí)不會(huì)出錯(cuò),但在引用時(shí)往往引起錯(cuò)誤,如
      Class A
      {
      }
      Class B
      {
        Class A
        {
        }
      }
      這里的A成為了B.A的后綴,如果在類B中定義一個(gè)A的實(shí)例變量,不使用完全限定名的情況下有時(shí)會(huì)引起混淆,這種情
      況只出現(xiàn)在沒有名空間包含的全局類與這樣類的嵌入類之間,所以有一個(gè)簡(jiǎn)單辦法解決,就是為所有全局類指定一個(gè)
      名空間,比如Root(dis#就是這么干的,相信它是考慮到這一點(diǎn)了),這樣上面的類變成Root.A與Root.B.A,不再是
      后綴了。
      5、引用assembly與被引用assembly類型重名,reflector.exe與reflector.application.dll在名稱混淆后就有這種情
      況,因?yàn)樗鼈冞@此類實(shí)際上互不相干,在運(yùn)行時(shí)不會(huì)倒致問題,但是反編譯時(shí)如果我們對(duì)這些混淆成相同名稱的類還
      是采用相同的名稱,那么編譯reflector.exe能過去,因?yàn)樗灰胷eflector.application.dll(它使用動(dòng)態(tài)裝入),
      但是編譯reflector.application.dll則不行,因?yàn)樗们罢撸褂美锩娑x的接口,雖然那些接口定義與它不
      沖突,但因?yàn)橐玫牟幌喔傻念惻c它有沖突,會(huì)倒致編譯失敗,因?yàn)檫@種沖突只出現(xiàn)互不相干的類之間,所以可以為
      某一方指定一個(gè)不同的名空間。
      6、改變?cè)L問許可,訪問許可看起來像是編譯時(shí)檢查的東西,混淆時(shí)如果將某些方法改為私有,似乎并不會(huì)影響調(diào)用它
      的方法的執(zhí)行,但是編譯時(shí)這是錯(cuò)誤的。(事實(shí)上我們用reflection api調(diào)用方法時(shí)就不受訪問許可的限制,呵呵)
      7、重載換名,就是方法重載使用.override指示一個(gè)不同的名稱,C#對(duì)此沒有支持,mc++對(duì)此也不支持,只在較新的
      c++/cli中有支持。
      8、父類或?qū)崿F(xiàn)接口名與特性名稱相同,這在C++使用類外函數(shù)實(shí)現(xiàn)語法時(shí)會(huì)無法編譯(因?yàn)镃++不像C#會(huì)自動(dòng)解決交叉
      引用,而.net程序的交叉引用泛濫,類外函數(shù)實(shí)現(xiàn)是反編譯大工程時(shí)的必然先擇),C#中倒無此問題。

      三、針對(duì)這些混淆的反編譯
      1、目標(biāo)高級(jí)語言的選擇
      目標(biāo)語言的選擇主要考慮前面提到的結(jié)構(gòu)混淆的問題,因?yàn)橹剌d換名C#完全不支持,而其它情形的混淆均可以通過修改
      讓C++通過編譯,C++在語法結(jié)構(gòu)的豐富性勝過C#,另一方面,比較了一下C#與C++的編譯優(yōu)化,雖然二者在處理流程混淆
      的無用跳轉(zhuǎn)與來回跳轉(zhuǎn)都很有效,但C#在處理變量使用優(yōu)化時(shí)明顯不如C++,優(yōu)化選項(xiàng)也不C++豐富。綜合這兩點(diǎn),C++
      是較好的選擇,不過C++語言不夠動(dòng)態(tài),vs.net的調(diào)試與源代碼編輯方面都不如C#,只可惜魚與熊掌不能兼得。

      2、反混淆的關(guān)鍵點(diǎn)
      在前面介紹混淆方式時(shí)大多已經(jīng)提到了反混淆的方法,這里著重提一下針對(duì)switch混淆的反混淆與利用堆棧混淆的反混淆
      ,其它混淆一般不影響反編譯結(jié)果的正確性,可以利用C++的優(yōu)化編譯處理,利用異常的混淆在reflector中用得較簡(jiǎn)單,
      所以我也沒有深入探索。
      1)反編譯與反混淆的基礎(chǔ)
      這里說的基礎(chǔ)是在編譯原理之類書藉在講到編譯優(yōu)化時(shí)要說的東東,就是要建立程序流圖,因?yàn)閷⒒跅5腎L反編譯成基于
      變量與表達(dá)式的高級(jí)語言關(guān)鍵在于保證數(shù)據(jù)流的正確性,而數(shù)據(jù)流是在控制流的框架內(nèi)維持的,所以我們首先需要為每個(gè)
      函數(shù)建立其程序流圖,流圖的每個(gè)結(jié)點(diǎn)就是一個(gè)基本塊,基本塊內(nèi)我們只要按前面說堆棧混淆時(shí)的那種堆棧分析方法來生成
      表達(dá)式即可(相當(dāng)于解釋執(zhí)行IL),在基本塊與基本塊之間則需要考慮塊間暫存在堆棧中的數(shù)據(jù)的一致性問題。
      事實(shí)上,程序流圖的建立還用于像來回跳轉(zhuǎn)這種優(yōu)化以及識(shí)別分支與循環(huán)結(jié)構(gòu)這種高級(jí)語言結(jié)構(gòu)上,不過這些都有現(xiàn)成工具
      來做,我就沒有重復(fù)做這些事了。

      2)用switch作跳轉(zhuǎn)的反混淆
      還是拿前面講混淆時(shí)的例子,反混淆的辦法就是分析每個(gè)switch語句的判斷表達(dá)式與switch塊的入口點(diǎn),然后在每個(gè)跳往
      switch塊入口的跳轉(zhuǎn)時(shí)計(jì)算switch判斷表達(dá)式的值,將跳轉(zhuǎn)目標(biāo)直接用對(duì)應(yīng)switch分支目標(biāo)代替,這樣C++編譯器就能優(yōu)化
      掉switch了(因?yàn)檫@樣處理后switch塊就是一個(gè)空架子了),前面的例子這樣處理的結(jié)果如下:
      int v=0;
        
      goto IL_01;  改為switch(0)的分支目標(biāo)-->goto IL_02;
      IL_01:
        
      switch(v)
        
      {
          
      case 0:goto IL_02;
          
      case 1:goto IL_03;
          
      case 2:goto IL_04;
          
      case 3:goto IL_05;
          
      default:goto IL_06;
        }

      IL_02:
        做實(shí)際工作
        v
      =1;
        
      goto IL_01;  改為switch(1)的分支目標(biāo)-->goto IL_03;
      IL_03:
        做實(shí)際工作
        v
      =2;
        
      goto IL_01;  改為switch(2)的分支目標(biāo)-->goto IL_04;
      IL_04:
        做實(shí)際工作
        v
      =3;
        
      goto IL_01;  改為switch(3)的分支目標(biāo)-->goto IL_05;
      IL_05:
        做實(shí)際工作
        v
      =4;
        
      goto IL_01;  改為switch(default)的分支目標(biāo)-->goto IL_06;
      IL_06:
        做實(shí)際工作
        
      return
      3)用堆棧儲(chǔ)存值的混淆的反混淆
      前面說的時(shí)候已經(jīng)提到了基本辦法,就是引入臨時(shí)變量,相當(dāng)于為堆棧中暫存的值命名。這里說一下引入臨時(shí)變量的幾種情形:
      1、變量值更新倒致原變量值需要臨時(shí)變量記錄
      在編譯優(yōu)化中處理基本塊時(shí)一般使用一種稱為DAG的結(jié)構(gòu)來描述,在構(gòu)造DAG的過程中如果一個(gè)結(jié)點(diǎn)被指定給某一個(gè)變量時(shí),此變
      量需要與先前關(guān)聯(lián)的結(jié)點(diǎn)斷開,我們這里所處理的情形與此類似,只需要跟蹤變量的賦值,也就是stloc,starg語句即可,當(dāng)執(zhí)
      行賦值語句時(shí),我們檢查當(dāng)前堆棧中是否有引用該變量的值存在,如果有,則對(duì)原引用賦一個(gè)昨時(shí)變量。還是以先前堆棧混淆的
      代碼為例:
      L_0020: ldloc.1     
      L_0021: dup         (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1,loc1)
      L_0022: ldc.i4.1   
      L_0023: add             (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1,loc1+1)
      L_0024: stloc.1        (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,loc1)    
                //loc1=loc1+1
      在L_0024時(shí),我們要對(duì)loc1賦值,此時(shí)棧頂值引用了原loc1,所以我們需要對(duì)原loc1引入一個(gè)臨時(shí)變量temp1,不過temp1這個(gè)變
      量生成C#的地方要放到該值進(jìn)棧的那條IL語句也就是L_0020上,也就是說記錄變?yōu)?
      L_0020: ldloc.1       //temp1=loc1
      L_0021: dup         (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,temp1,temp1)
      L_0022: ldc.i4.1   
      L_0023: add             (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,temp1,temp1+1)
      L_0024: stloc.1        (0,loc0,loc2,loc0[loc2],loc0[loc2] & 255,temp1)    
                //loc1=temp1+1
      這樣生成的C#代碼序列為:
      temp1=loc1;
      loc1=temp1+1;
      因?yàn)闂V杏涗浀氖莟emp1,對(duì)loc1的賦值不會(huì)影響棧中值的使用。

      2、過程調(diào)用返回值需要使用臨時(shí)變量暫存
      過程調(diào)用有可能改變當(dāng)前函數(shù)的上下文,也就是說過程調(diào)用語句的順序可能是不能改變的,不過我們用堆棧分析IL指令時(shí),棧中的
      值是用產(chǎn)生該值的表達(dá)式表示的(除非該表達(dá)式值賦給了臨時(shí)變量),對(duì)于過程調(diào)用的返回值,在棧中是用過程調(diào)用表示的,僅當(dāng)
      值出棧時(shí)才會(huì)生成C#語句,由于棧的后進(jìn)先出特性,將過程調(diào)用表達(dá)式放在棧中就有可能改變語句的順序。
      如果能夠進(jìn)行全程序優(yōu)化,過程調(diào)用的影響是可以確切知道的,但不做這種優(yōu)化的話,我們需要保證調(diào)用語句的執(zhí)行順序,此時(shí)就
      需要為返回值的調(diào)用引入臨時(shí)變量。

      3、數(shù)組訪問、指針需要引入臨時(shí)變量
      如果數(shù)組元素與指針指向的值進(jìn)棧后再被修改,則與1中所說變量被修改情形是一樣的,需要對(duì)棧中記錄的原值引入臨時(shí)變量。

      4、塊間利用堆棧傳值需要為棧中變量引入臨時(shí)變量名
      前面說的1、2、3都是基本塊內(nèi)的處理辦法,除了塊內(nèi)有用堆棧混淆外,塊間也會(huì)有這樣的混淆:
      IL_0041:            ldstr        L"\xDA8E\xE290\xF692\xF194\xB796\xDB98\xE29A"
      IL_0046:            ldloc        V_1
      IL_004a:            call        System::String
      ^ undefined_type::a(System::String^,System::Int32)
      IL_004f:            br.s        IL_007f
      -----------------------------------------------------------------------------------------------------------------------------------------------------------
      IL_0051:            ldstr        L
      "\xDA8E\xE290\xF692\xF194\xB796\xD098\xF59A\xBD9C\xB89E"
      IL_0056:            ldloc        V_1
      IL_005a:            call        System::String
      ^ undefined_type::a(System::String^,System::Int32)
      IL_005f:            ldarg.
      0
      IL_0060:            ldfld        Reflector::CodeModel::IAssembly
      ^ Root::T_x32::T_x1 F_x2
      IL_0065:            callvirt        System::String
      ^ Reflector::CodeModel::IAssemblyReference::get_Name()
      IL_006a:            ldstr        L
      "\xA88E\xB190\xD192\xEC94"
      IL_006f:            ldloc        V_1
      IL_0073:            call        System::String
      ^ undefined_type::a(System::String^,System::Int32)
      IL_0078:            call        System::String
      ^ System::String::Concat(System::String^,System::String^,System::String^)
      IL_007d:            br.s        IL_007f
      -----------------------------------------------------------------------------------------------------------------------------------------------------------
      IL_007f:            call        
      void System::Windows::Forms::TreeNode::set_Text(System::String^)
      IL_0084:            ldarg.
      0
      IL_0085:            call        System::Windows::Forms::TreeNodeCollection
      ^ System::Windows::Forms::TreeNode::get_Nodes()
      IL_008a:            newobj        
      void Root::T_x32::T_x14::.ctor()
      IL_008f:            callvirt        System::Int32 System::Windows::Forms::TreeNodeCollection::Add(System::Windows::Forms::TreeNode
      ^)
      IL_0094:            pop
      IL_0095:            ret
      上面這段代碼由三個(gè)基本塊組成,第一塊與第二塊為第三塊的前導(dǎo),我們看到第一塊與第二塊執(zhí)行結(jié)束時(shí)最后一次函數(shù)調(diào)用的返回值在堆棧中并未出棧,在第三塊
      開始的調(diào)用直接使用了棧中傳入的參數(shù)(高級(jí)語言基于變量與表達(dá)式的語法是不會(huì)產(chǎn)生這種情況的)。
      當(dāng)我們反編譯這段代碼時(shí),反編譯到第三塊時(shí),函數(shù)調(diào)用的參數(shù)用哪個(gè)呢?它有兩個(gè)前導(dǎo)塊,各自通過堆棧傳入一個(gè)值,程序的原意是根據(jù)條件不同使用不同的參數(shù)
      ,如果我們用高級(jí)語言這樣的功能,我們會(huì)寫成:
      string s;
      if(...)
      {
        s=xxCall1();
      }
      else
      {
        s=xxCall2();
      }
      xxCall3(s);

      也就是說,我們使用一個(gè)局部變量來統(tǒng)一兩個(gè)分支的返回值,然后用這個(gè)變量作參數(shù)調(diào)用xxCall3。這樣一類比就比較清楚了,仍然是需要引入臨時(shí)變量,
      只不過這次不只是引入臨時(shí)變量,還需要兩個(gè)分支塊的臨時(shí)變量是同一個(gè)變量。
      上面的是一個(gè)分支結(jié)構(gòu)的例子,其實(shí)塊間傳值還有一種情形發(fā)生在循環(huán)時(shí)(從這個(gè)角度看,循環(huán)其實(shí)是可以歸入分支結(jié)構(gòu)的),這里的一個(gè)例子是我們
      前面用來說明堆棧存值混淆的refelctor的字符串解密函數(shù),在循環(huán)的全過程中棧中有個(gè)值一直未出棧,L_0049->L_0012,前者是一個(gè)基本塊的結(jié)束,后者是
      一個(gè)基本塊的開始,所以棧中的值也是在基本塊間傳遞的,按照前面的方法,我們也需要為它引入一個(gè)臨時(shí)變量,這個(gè)變量便是循環(huán)變量了。

      最后我貼出我寫的反混淆反編譯程序?qū)ψ址饷芎瘮?shù)反出來的代碼(相對(duì)原始的代碼,呵呵)與經(jīng)過C++優(yōu)化編譯后再用refelctor看到的代碼,大家有興趣可以仔細(xì)看
      一下,這里面有關(guān)于堆棧混淆與反混淆的主要信息。
      反混淆反編譯的結(jié)果:
      System::String^ a(System::String^ A_0,System::Int32 A_1)
      {
        
      //temp variables , should be optimized by C++/cli compiler.
        array<System::Char>^ Temp_0 = nullptr;
        System::Int32 Temp_1 
      = 0;
        System::Int32 Temp_2 
      = 0;
        System::Int32 Temp_3 
      = 0;
        System::Byte Temp_4 
      = 0;
        System::String
      ^ Temp_5 = nullptr;
        System::String
      ^ Temp_6 = nullptr;
        System::Int32 Temp_7 
      = 0;
        System::Int32 Temp_8 
      = 0;
        System::Int32 Temp_9 
      = 0;
        
      //local variables.
        array<System::Char>^ V_0 = nullptr;
        System::Int32 V_1 
      = 0;
        System::Int32 V_2 
      = 0;
        System::Byte V_3 
      = 0;
        System::Byte V_4 
      = 0;
        
      //method body ------- 
        IL_0000:                                                                        //ldarg.0
        IL_0001:            Temp_0=A_0->ToCharArray();                                  //callvirt        array<System::Char>^ System::String::ToCharArray()
        IL_0006:            V_0=Temp_0;                                                 //stloc.0
        IL_0007:                                                                        //ldc.i4        0x3197fc8c
        IL_000c:                                                                        //ldarg.1
        IL_000d:                                                                        //add
        IL_000e:            V_1=(832044172 + A_1);                                      //stloc.1
        IL_000f:                                                                        //ldc.i4.0
        IL_0010:                                                                        //dup
        IL_0011:                                                                        //ldc.i4.1
        IL_0012:            Temp_8=0;goto IL_0047;                                      //blt.s        IL_0047
        IL_0014:                                                                        //dup
        IL_0015:            Temp_9=Temp_8;                                              //stloc.2
        IL_0016:                                                                        //ldloc.0
        IL_0017:                                                                        //ldloc.2
        IL_0018:                                                                        //ldloc.0
        IL_0019:                                                                        //ldloc.2
        IL_001a:                                                                        //ldelem.i2
        IL_001b:                                                                        //dup
        IL_001c:                                                                        //ldc.i4        0xff
        IL_0021:                                                                        //and
        IL_0022:            Temp_2=V_1;                                                 //ldloc.1
        IL_0023:                                                                        //dup
        IL_0024:                                                                        //ldc.i4.1
        IL_0025:                                                                        //add
        IL_0026:            Temp_3=(Temp_2 + 1);                                        //stloc.1
        IL_0027:                                                                        //xor
        IL_0028:                                                                        //conv.u1
        IL_0029:            V_3=safe_cast<System::Byte>(((V_0[Temp_9] & (System::Char)255^ Temp_2));//stloc.3
        IL_002a:                                                                        //dup
        IL_002b:                                                                        //ldc.i4.8
        IL_002c:                                                                        //shr
        IL_002d:                                                                        //ldloc.1
        IL_002e:                                                                        //dup
        IL_002f:                                                                        //ldc.i4.1
        IL_0030:                                                                        //add
        IL_0031:            V_1=(Temp_3 + 1);                                           //stloc.1
        IL_0032:                                                                        //xor
        IL_0033:                                                                        //conv.u1
        IL_0034:            Temp_4=safe_cast<System::Byte>(((V_0[Temp_9] >> 8^ safe_cast<System::Char>(Temp_3)));//stloc.s        V_4
        IL_0036:                                                                        //pop
        IL_0037:                                                                        //ldloc.s        V_4
        IL_0039:                                                                        //ldloc.3
        IL_003a:            V_4=V_3;                                                    //stloc.s        V_4
        IL_003c:            V_3=Temp_4;                                                 //stloc.3
        IL_003d:                                                                        //ldloc.s        V_4
        IL_003f:                                                                        //ldc.i4.8
        IL_0040:                                                                        //shl
        IL_0041:                                                                        //ldloc.3
        IL_0042:                                                                        //or
        IL_0043:                                                                        //conv.u2
        IL_0044:            V_0[Temp_9]=safe_cast<System::Char>(safe_cast<System::UInt16>(((V_4 << 8| V_3)));//stelem.i2
        IL_0045:                                                                        //ldc.i4.1
        IL_0046:            Temp_8=(Temp_9 + 1);                                        //add
        IL_0047:            /*warning ! semantic stack doesn't empty at joint !;*/      //dup
        IL_0048:                                                                        //ldloc.0
        IL_0049:            Temp_1=V_0->Length;                                         //ldlen
        IL_004a:                                                                        //conv.i4
        IL_004b:            if(Temp_8<Temp_1)goto IL_0014;                              //blt.s        IL_0014
        IL_004d:                                                                        //pop
        IL_004e:                                                                        //ldloc.0
        IL_004f:            Temp_5=gcnew System::String(V_0);                           //newobj        void System::String::.ctor(array<System::Char>^)
        IL_0054:            Temp_6=System::String::Intern(Temp_5);                      //call        System::String^ System::String::Intern(System::String^)
        IL_0059:            return Temp_6;                                              //ret
      }

      經(jīng)過C
      ++優(yōu)化編譯后再用reflector看到的C++/cli代碼:
      String
      ^  a(String^ A_0, int A_1)
      {
            array
      <wchar_t>^ chArray1 = A_0->ToCharArray();
            
      int num2 = (A_1 + 832044172);
            
      int num1 = 0;
            
      if ((0 < chArray1->Length))
            
      {
                  
      do
                  
      {
                        
      int num4 = num2;
                        
      int num3 = (num2 + 1);
                        num2 
      = (num3 + 1);
                        wchar_t ch1 
      = chArray1[num1];
                        chArray1[num1] 
      = ((wchar_t) (((unsigned short) ((((unsigned char) ch1) << 8^ (((unsigned char) num4) << 8))) | ((unsigned short) (((unsigned char) (ch1 >> 8)) ^ ((unsigned char) num3)))));
                        num1
      ++;
                  }

                  
      while((num1 < chArray1->Length));
            }

            
      return String::Intern(gcnew String(chArray1) );
      }

      C#代碼:
      internal static string a(string A_0, int A_1)
      {
            
      char[] chArray1 = A_0.ToCharArray();
            
      int num2 = A_1 + 0x3197fc8c;
            
      int num1 = 0;
            
      if (0 < chArray1.Length)
            
      {
                  
      do
                  
      {
                        
      int num4 = num2;
                        
      int num3 = num2 + 1;
                        num2 
      = num3 + 1;
                        
      char ch1 = chArray1[num1];
                        chArray1[num1] 
      = (char) (((ushort) ((((byte) ch1) << 8^ (((byte) num4) << 8))) | ((ushort) (((byte) (ch1 >> 8)) ^ ((byte) num3))));
                        num1
      ++;
                  }

                  
      while (num1 < chArray1.Length);
            }

            
      return string.Intern(new string(chArray1));
      }

      四、反編譯成高級(jí)語言后...
      反編譯成可編譯的高級(jí)語言的一個(gè)用處是利用高級(jí)語言編譯器的優(yōu)化功能處理混淆,另外還有一個(gè)便是調(diào)試,對(duì)于.net程序,還是在有源碼的情況下用vs.net調(diào)試來得
      直觀,我寫的反編譯工具輸出的源碼是高級(jí)語言與IL對(duì)應(yīng)的,主要是考慮到反編譯如果出錯(cuò),便于人工修改。

      現(xiàn)在的程序還只是個(gè)初步的程序,對(duì)于COM,generic的支持還不行,當(dāng)混淆程序使用了結(jié)構(gòu)混淆時(shí)生成的代碼會(huì)出現(xiàn)編譯錯(cuò)誤,類型轉(zhuǎn)換與推導(dǎo)有時(shí)也會(huì)出錯(cuò),還需要
      人工作一些調(diào)整,就reflector的反編譯來說,reflector.exe反編譯后只有兩處類型轉(zhuǎn)換錯(cuò)誤了,但reflector.application.dll則有數(shù)十處錯(cuò)誤(其中主要的錯(cuò)誤都源
      于引用參數(shù)與非引用參數(shù)的重載混淆所致)。
      最終我重新編譯通過了reflector.exe,reflector.application.dll,但是運(yùn)行時(shí)剛顯示主界面就會(huì)異常退出,跟蹤調(diào)試時(shí)發(fā)現(xiàn)是使用IOleObject::SetClientSite時(shí)出
      錯(cuò)了,現(xiàn)在原因還沒搞清楚,汗。

      附件是我寫的反名稱混淆程序與反編譯程序(均是未加殼未混淆的,用reflector可直接閱讀代碼的)。
      反編譯程序的用法如下:
      1、用ildasm反匯編.net程序并保存成IL文件;
      2、在命令行執(zhí)行反編譯程序test.exe:
        test 目標(biāo)文件.il
      此時(shí)在test.exe所在目錄生成一個(gè)子目錄il2cpp,其下是反編譯出來的c++源文件;
      3、用vs.net 2005新建立一個(gè)C++/cli項(xiàng)目(視目標(biāo)程序是console還是winform選不同類型),若是winform生成后刪除主form文件,將2中生成的文件拷到項(xiàng)目源文件目錄,
      再用“添加現(xiàn)有項(xiàng)”將這些文件添加項(xiàng)目中,并將所有*.cpp文件的預(yù)編譯頭設(shè)為“不使用預(yù)編譯頭”;
      4、在項(xiàng)目主程序cpp文件添加包含頭文件
        #include "global_xref.h"
      在main函數(shù)里調(diào)用原程序?qū)?yīng)的入口函數(shù)調(diào)用;
      5、編譯、改錯(cuò)、再編譯直到通過,呵呵;
      6、發(fā)現(xiàn)問題請(qǐng)發(fā)信息至dreaman_163@163.com,此程序目前還相當(dāng)初級(jí),需要完善。

      --------------------------------------------------------------------------------------------------
      謝謝閱讀,呵呵                
                        2006.12.31

      原文地址:http://bbs.pediy.com/showthread.php?threadid=37217
      posted @ 2007-04-25 10:04  大石頭  閱讀(10296)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产一区二区三区精美视频| 欧美高清精品一区二区| 成人麻豆日韩在无码视频| 亚洲无线看天堂av| 最新国产精品好看的精品| 艳妇乳肉豪妇荡乳xxx| 欧洲人与动牲交α欧美精品| 中文字幕久久人妻熟人妻| 国产黄色一区二区三区四区| 国产欧美日韩精品丝袜高跟鞋| 国产av精品一区二区三区| 少妇爽到呻吟的视频| 国产成人无码A区在线观看视频| 激情综合网激情激情五月天| 2022亚洲男人天堂| 精品一区二区三区不卡| 国产va免费精品观看| 欧美日本国产va高清cabal| 藁城市| 99麻豆久久精品一区二区| 国产精品视频亚洲二区| 久久精品国产亚洲夜色av网站| 久青草视频在线免费观看| 日本不卡不二三区在线看| 日韩av在线不卡一区二区三区| 亚洲欧美人成人综合在线播放| 石原莉奈日韩一区二区三区| av 日韩 人妻 黑人 综合 无码| 国产精品免费看久久久| 国产极品精品自在线不卡| 人妻综合专区第一页| 亚洲欧美牲交| 秋霞电影网| 国产影片AV级毛片特别刺激| 亚洲成av人片在www鸭子| 免费看黄色亚洲一区久久| 蜜桃草视频免费在线观看| 漂亮人妻中文字幕丝袜| 熟女乱一区二区三区四区| 欧美成人精品高清在线播放| 老熟女重囗味hdxx69|