標 題: 【原創】ANTS Profiler(for .net)的分析、調試及破解
作 者: tankaiha
時 間: 2006-08-24,11:33:35
鏈 接: http://bbs.pediy.com/showthread.php?t=30953
【文章標題】: ANTS Profiler(for .net)的分析、調試及破解
【文章作者】: tankaiha
【作者首頁】: vxer.cn
【軟體名稱】: ANTS Profiler
【】: 自己搜尋下載
【保護方式】: 混淆+強命名+RSA
【使用工具】: Reflector,Pebrowse,snremove,UltraEdit
【操作平台】: .Net v1.1
【作者聲明】: 第一次用破文產生器,8錯!
--------------------------------------------------------------------------------
【詳細過程】
ANTS Profiler的主要功能如下:
" Code profile .NET applications
" Profile application memory use
" Profile both .NET desktop applications and ASP.NET web applications
" Optimize your code
不廢話了,直接來過程。
先運行一下,提示14天試用期,輸入序號。如果輸入錯誤的序號則提示Please enter a valid serial number"。用Reflector開啟試試,運氣好,發現軟體混淆強度較弱(只有少部分使用了不可列印字元),再查發現有強命名。
目錄下有兩個檔案很可疑,RedGate.Licensing.Client.dll和RedGate.Licensing.Helper.dll(發現這兩個檔案一是看目錄下的檔案名稱,二是調試時會發現有這兩個模組,見下節)。同樣,用Reflector載入。搜尋字串"valid serial",很容易就來到了判斷序號的地方。(暈,關鍵的東東不混淆,而且敏感字串以明文出現,好久沒遇到這麼爽的.Net程式了。)
代碼:
try { string text1 = this.?.Text.ToUpper().Trim(); if (text1 == "I NEED MORE TIME") { if (this.?.?()) { this.?((?.?) 6); return; } MessageBox.Show("Your trial could not be extended", "Trial extension failure", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } this.?.SerialNumber = this.?.Text; } catch (?) { MessageBox.Show("Please enter a valid serial number", "Invalid serial number", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; }
雖然有不少不可列印字元,但並不影響分析。從代碼中看出輸入錯誤的序號會拋出異常。下面是找序號的計算代碼。(這裡還有個字串"I NEED MORE TIME",這是延長試用期的,結合註冊表可以不破解直接無限使用,已經發過文章了。)
找序號的比較代碼有兩種方法,一種是在PeBrowse中下斷,動態調試找到地方,當時我用的這個方法,這裡只簡單的說一下。用PeBrowse載入(對於含有不可列印字元的程式,ildasm後的原始碼往往不能用ilasm再編譯,用WinDbg不方便,還是直接調試方便),在相應的dll處對所有的方法下斷(因為暫時不知道是哪個方法計算序號),見,紅色圈中的就是前文提到的可疑dll。不再多說了,大家自已試,因為這個程式靜態完全可以跟出來。
第二是Reflector中直接分析。注意這句:
this.?.SerialNumber = this.?.Text;
點擊"SericalNumber",來到它的定義處
代碼:
public string SerialNumber { get { return this.?; } set { value = value.Trim(); if (!Licence.?(value, this.?)) { throw new ?(); } this.? = value; } }
這裡明顯調用的是set。代碼的意義非常明顯,如果License判斷序號是錯的,就throw一個異常,這正好被剛才的catch捕捉到,顯示invalid serial的視窗。那我們點擊Licence.XX(某不可見字元,呵呵),終於,找到了:
代碼:
private static bool ?(string text5, int num1) { text5 = text5.ToUpper().Trim(); Regex regex1 = new Regex(@"[A-Z]{2}-[0-9A-Z]{1}-[0-9A-Z]{1}-/d{5}-[0-9A-F]{4}"); Regex regex2 = new Regex(@"/d{3}-/d{3}-/d{6}-[0-9A-F]{4}"); if (regex1.IsMatch(text5)) { string text1 = text5.Substring(0, 12); string text2 = string.Format("{0:X4}", Licence.?(text1)); if (!text5.EndsWith(text2)) { return false; } } else { if (!regex2.IsMatch(text5)) { return false; } string text3 = text5.Substring(0, 14); string text4 = string.Format("{0:X4}", Licence.?(text3)); if (!text5.EndsWith(text4)) { return false; } if (Convert.ToInt32(text5.Substring(0, 3)) != num1) { return false; } } return true; }
還是Regex。這裡不多說了,不明白的可以看編程文檔。分析一下就知道序號的格式,[A-Z]{2}-[0-9A-Z]{1}-[0-9A-Z]{1}-/d{5}-[0-9A-F]{4},而且前14位計算的值等於末尾4位。這裡給出一個,以便我們繼續分析:AA-0-0-12345-5C3B。
輸入序號後,可以繼續了,發現原來還要啟用,不然還是試用14天。選擇用Email啟用(網路啟用不好搞),然後會讓你輸入啟用的代碼。隨便輸入一些,提示"The activation response is not in the correct format"。就以這為關鍵詞搜,來到這裡。
代碼:
private bool ?(XmlDocument document1, ref Licence.? ?Ref1) { XmlNodeList list1 = document1.GetElementsByTagName("data"); XmlNodeList list2 = document1.GetElementsByTagName("signature"); if ((list1.Count != 1) || (list2.Count != 1)) { ?Ref1.? = "The activation response is not in the correct format"; return false; } string text1 = list1[0].OuterXml; string text2 = list2[0].InnerXml; if (text2.Length != 0) { ?Ref1.? = "The activation response does not contain a digital signature"; return false; } RSACryptoServiceProvider provider1 = new RSACryptoServiceProvider(); string text3 = "<RSAKeyValue><Modulus>zLizNmLUd4VlIWee1GXgn/KxEwcghPASQ+NUzZhbY2fTGzpW64T6yEOdHlIbhX1DX6yAz2gMZKfnpQL2aFqxh5ACFV9dONSTzuQzkqeXwFEARsMxGP3eTQSWMpwVhEcraSn1zOqMb3CRDeQpgasq0lv4HRFhbwalOifKarjEL/8=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; provider1.FromXmlString(text3); byte[] buffer1 = Convert.FromBase64String(text2); byte[] buffer2 = Encoding.UTF8.GetBytes(text1); if (provider1.VerifyData(buffer2, new SHA1Managed(), buffer1)) { ?Ref1.? = "The activation response contains an incorrect digital signature"; return false; } ?Ref1.? = false;
暈,有RSA,我功力不行,只能爆破了。不過這裡爆破範圍和爆破點的選擇還是很有技巧的,詳見下文。大概分析一下代碼,看來啟用資訊是XML格式,大至如下:
<activationresponse>
<data>
XXXX
</data>
<signature>
YYYY
</signature>
</activationresponse>
而且YYYY必須的字元數必須是4的倍數,為啥?因為Convert.FromBase64String(text2),不信你可以試試。我們就按上面的樣式輸入,又有新提示:The activation response does not match the registration properties。看來這裡還不是最終驗證的地方,還得找。
這裡有個使用Reflector的小技巧,操作見圖:先分析這個方法被哪些別的方法使用了,又使用了哪些別的方法。
這裡我們找被使用的關係,然後點Go To Member,來到下面的代碼處。這裡才是關鍵呵。
代碼:
private bool ?(XmlDocument document1) { Licence.? ?1 = new Licence.?(); if (!this.?(document1, ref ?1)) { throw new ?(?1.?); } if (((?1.? != this.?) || (?1.? != this.?)) || (?1.? != this.?)) { throw new ?("The activation response does not match the registration properties"); } if (!?1.?) { if (?1.? != this.?) { throw new ?("The activation response does not match the registration properties"); } if (Licence.?(?1.?, this.?)) { this.? = true; return true; } throw new ?("The activation response is for a different machine"); } if (?1.? != this.?) { throw new ?("The activation response is for a different session"); } this.?(true); return false; }
我們要在這裡進行爆破,但怎麼個爆破法呢?注意,該段代碼中只有一個正確的返回點,就是
this.? = true;
return true;
我們的方法是讓第一句Licence.? ?1 = new Licence.?();執行完後,不進行任何判斷,直接執行上面的兩句代碼。對了,前面還有一處,就是RSA判斷處的provider1.VerifyData也要改掉,這樣才能進行到下面。
修改方法,在結合ILDASM的反組譯碼代碼,在UltraEdit中定位。
第一處:
IL_00a4: /* 2D | 0E */ brtrue.s IL_00b4
將2D改為2C(brfalse.s)。物理位移在0x3118h處。
第二處:
IL_0000: /* 73 | (06)00003B */ newobj instance void RedGate.Licensing.Client.Licence/*02000008*//'?'/*02000009*/::.ctor() /* 0600003B */
IL_0005: /* 0A | */ stloc.0
在物理位移的0x2cb4處。緊接著這兩句修改。原檔案為
00002cbah: 02 03 12 00 28 29 00 00 ; ....()..
改為
00002cbah: 02 17 7D 38 00 00 04 17 ; ..}8....
即MSIL代碼
ldarg.0
ldc.i4.1
stfld bool RedGate.Licensing.Client.Licence::'?'
ret
儲存修改,運行。按格式輸入註冊碼和啟用資訊,顯示啟用成功,不再提示有使用時間了。序號產生器偶就不寫了,很簡單的演算法。不知道什麼時候才能搞定RSA。
附件裡是patch過的RedGate.Licensing.Client.DLL,僅供參考!