【文章标题】: 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;
}
还是正则表达式。这里不多说了,不明白的可以看编程文档。分析一下就知道序列号的格式,[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,仅供参考!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年08月24日 0:39:39