.net軟件反編譯筆記

在軟件的破解及源碼獲取及從新編譯的道路上會遇到一些問題,書此備查。框架

大名鼎鼎的Reflector以及開源的ILSPY都是.NET程序集的反編譯利器,可是它們不能爲你作所有的工做。ide

0x01:工具

遇到反編譯所得源碼裏面調用類的屬性時多出set_Name或者get_Name之類的說明程序集引用沒有加載徹底,性能

由於反編譯工具在沒有元數據的狀況下沒法判斷這丫的究竟是個方法仍是個屬性。flex

有時候反編譯獲得的源碼裏的-1實際上多是某個數的最大值,由於反編譯時沒有加載依賴的程序集,工具將相似int.MaxValue等值變成了-1。優化

因此將依賴項加載完是一個好的習慣,Reflector在反編譯時找不到依賴會提示你手動選擇,你能夠手動選擇或者忽略(點取消就是忽略),而ILSPY不會提示。spa

 

0x02:code

Reflector新版支持C#6的特性,會把一些屬性賦值反編譯爲Lumbda表達式,而實際該項目可能不是C#6的項目,形成沒法經過編譯器檢查。orm

解決辦法是生成程序集的源碼以前從主界面工具欄那個下拉列表選擇合適的.NET框架版本。blog

 

0x03:

一些WPF強名稱應用程序會因爲資源文件也是強名稱引用致使反編譯爲項目後跑不起來。

或許從新簽名而後替換資源引用的公鑰能夠解決此問題但我沒有試過。

 

0x04:

在反編譯MVC Web項目時,控制器類和預編譯視圖裏(若是發佈時啓用的了話)會出現不少相似這樣的類

    [CompilerGenerated]
        private static class <Index>o__SiteContainer19
        {
            public static CallSite<Func<CallSite, object, string, object>> <>p__Site1a;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site1b;

            public static CallSite<Func<CallSite, object, DateTime, object>> <>p__Site1c;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site1d;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site1e;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site1f;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site20;

            public static CallSite<Func<CallSite, object, string, object>> <>p__Site21;
        }

 

這些代碼是編譯器爲優化性能生成的靜態類及靜態屬性。參考源碼後你會發現,這些代碼簡單的仍是比較容易還原的,複雜的你就留着吧。

個人作法是幹掉[CompilerGenerated]特性,批量替換類名<Index>o__SiteContainer19爲o__SiteContainer19,而後替換屬性中的<>爲空字符串。

 

0x05:

有時候咱們並不須要源碼,只是須要修改某個值或一處代碼。因此咱們須要的是Reflexil,固然還有更厲害的mono.cecil和dnlib,這是我知道的最牛逼的三個項目。

我的喜歡用ILSPY看源碼,而後用mono.cecil改程序。

但是修改後發現並不能運行,由於開發商使用了程序集強名稱。因此我通常會使用mono.cecil作以下操做來幹掉幹掉公鑰簽名

         var asmdef = AssemblyDefinition.ReadAssembly(dll.FullName);
                if (asmdef.Name.PublicKey != null && asmdef.Name.PublicKey.Any())
                {
                    asmdef.Name.PublicKey = new byte[0];
                    asmdef.Name.PublicKeyToken = new byte[0];
                    asmdef.Name.Attributes = AssemblyAttributes.SideBySideCompatible;
                    asmdef.MainModule.Attributes &= ~ModuleAttributes.StrongNameSigned;
         }

 

但是修改後發現並不能運行,由於開發商使用了強名稱的InternalsVisibleTo特性,因此我通常會使用mono.cecil作以下操做來幹掉InternalsVisibleToAttribute值裏面的公鑰

 
         #region//0x02 幹掉InternalsVisibleToAttribute值裏面的公鑰
                var internalsVisibleToAttrs = asmdef.CustomAttributes.Where(x => x.AttributeType.Name == "InternalsVisibleToAttribute").ToList();foreach (CustomAttribute item in internalsVisibleToAttrs)
                {
                    var argsctor = item.ConstructorArguments.Single();
                    var commaIndex = argsctor.Value.ToString().IndexOf(",");
                    if (argsctor.Value != null && commaIndex != -1) //format is "AsmName,PublicKey=..."
                    {
                        var newValue = item.ConstructorArguments[0].Value.ToString().Substring(0, commaIndex);//format is "AsmName"
                        item.ConstructorArguments[0] = new CustomAttributeArgument(argsctor.Type, newValue);
                        var index = asmdef.CustomAttributes.IndexOf(item);
                        asmdef.CustomAttributes.RemoveAt(index);
                        asmdef.CustomAttributes.Insert(index, item);
                    }
                }

但是修改後發現並不能運行,由於開發商使用了程序集強名稱致使編譯引用的也是強名稱的程序集,因此我通常會使用以下操做來幹掉引用定義裏面的公鑰

         
         //這裏假設引用的該產品的程序集都是SupperApp.*.dll格式的
         var
asmRefs = asmdef.MainModule.AssemblyReferences .Where(x => x.FullName.StartsWith("SupperApp", StringComparison.OrdinalIgnoreCase) && x.PublicKeyToken != null && x.PublicKeyToken.Any()) .ToList();foreach (var item in asmRefs) { item.PublicKeyToken = new byte[0]; }

 

以上操做後把變動寫入該軟件就能夠順利運行了。

 

0x06:

固然有些加了殼的,通常狀況須要找到對應的脫殼工具。若是隻是修改關鍵邏輯經過關鍵詞查找應該能找到蛛絲馬跡,但前提是要能看到源碼。

對於既沒有工具能脫殼也沒有工具能看源碼的能夠求助C++反彙編高手。

相關文章
相關標籤/搜索