[原创]破解WebUI.NET Framework验证原理
发表于:
2005-8-17 14:18
10648
[原创]破解WebUI.NET Framework验证原理
破解WebUI.NET Framework验证原理
【软件名称】:WebGrid.NET Version 4.0
【软件类别】:国外软件
【整理时间】:2005-08-17
【下载地址】:http://www.evget.com/view/viewProductInfo.asp?productId=89&tabIndex=0
【软件简介】:显示与操作标准数据,允许您的用户自由地对数据进行操作,使用简单,并能有效节约您的开发时间,WebGrid.NET企业版针对基于Asp.net的Grid控件上,在执行上设置了新的标准,用户接口和效果,允许用户像使用类似于windows的用户一样方便地操作基于web环境的Webgrid,此工业版本是唯一的装备有众多强大内置功能和高级核心架构(比如OnTheFly?数据处理),丰富的包括WebCombo.NET?的编辑控件以及日历控件,全球化支持(包括中文简体,繁体支持),表格输出,以及其他更多的内容
典型客户
・ Energie NB Power Corp.
・ Microsoft Corporation.
・ Intel Corp.
・ Dell Corp.
・ BellSouth Corp.
・ DollarGeneral Corporation.
・ General Electric Corporation.
・ Siemens GmBH, Germany.
・ Inco Limited, Canada.
・ TempWorks, USA.
【保护方式】:License
【保护软件】:XenoCode
【编译语言】:ASP.NET
【调试环境】:WinXP、.NET Framework 1.1、Reflector、ildasm、sn、ultraedit
【破解日期】:2005-08-17
【破解目的】:研究.NET程序的破解流程
【作者声明】:初学Crack,只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
听说WebGrid.NET 4.0采用了另外的加密技术,于是下载下来想见识一下,结果非常失望。除了把验证部分转移到了Framework的通用框架内以外,没有发现有什么改进的,加密水平还后退回WebCombo.NET的水平去了。
先是利用流程反混淆技术,把一堆函数反混淆出来,过程没有什么新意,参看以前我写的《揭开.NET程序保护的秘密》和《破解WebCombo.NET Version 2.0》,用ildasm反编译成il后修改转跳流程,然后用ilasm重新编译回去即可,唯一遇到一点点麻烦的是ilasm居然不认那个混淆后的resource。这也没关系,我们只是要分析验证原理,暂时不把resource编进去就是了。虽然是用XenoCode混淆的,可是连变量名字都没有处理过,非常容易就找到这两个函数
<ISNet.WebUI.ISNetControl>private void CheckLicense()
{
string text2 = "" ;
string text3 = "" ;
RegistryKey key3 = this .GetIntersoftRegKey(); // HKLM\Software\Intersoft Solutions
text2 = this .Product.ProductName; // 具体的软件产品会重载此field
text3 = this .Product.VersionNumber; // 具体的软件产品会重载此field
if (key3 != null)
{
RegistryKey key1 = key3.OpenSubKey(text2);//从注册表读键值
if (key1 != null)
{
RegistryKey key2 = key1.OpenSubKey(text3);
if (key2 != null)
{
string text1 = key2.GetValue("SID" ) as string ; //注册码
if ((text1 != "" ) && (text1 != null))
{
if (this .MatchSN(this .Product.dk, text1)) //关键,如果爆破只要nop掉这里即可
{
this .LicenseType = LicType.Full;
}
else if (this .MatchSN(this .Product.dr, text1))
{
this .LicenseType = LicType.RuntimeOnly;
}
else
{
text1 = this .ReadWebConfigValue("RuntimeLicenseKey" );
if ((text1 != null) && this .MatchSN(this .Product.dr, text1))
{
this .LicenseType = LicType.RuntimeOnly;
}
}
}
}
}
}
}private bool MatchSN(byte[] ?, string ?)//比较序列号的核心call
{
byte[] buffer1 = Encoding.ASCII.GetBytes(?);
bool flag1 = false ;
bool flag2 = false ;
bool flag3 = false ;
int num1 = 0;
byte[] buffer2 = ?;
int num4 = 0;
Label_001B:
if (num4 < buffer2.Length) //实际是循环:for(num4=0;num4<buffer2.Length;num4++)
{
byte num2 = buffer2[num4];//读入num2和num3进行比较
byte num3 = 0;
try
{
num3 = (byte) buffer1.GetValue(num1);
}
catch
{
flag3 = true ;
goto Label_014B;
}
if (num2 != 0xbc)//下面一大段是核心判断,后面解释
{
if (num2 == 190)
{
if ((num3 >= 0x41) && (num3 <= 0x4b))
{
goto Label_0054;
}
flag3 = true ;
}
else
{
if (num2 == 0xb8)
{
flag2 = true ;
goto Label_005A;
}
if (num2 != 0x4a)
{
if (num2 != 0x7e)
{
if (num2 != 90)
{
if (num2 == 0x42)
{
if ((num3 >= 0x30) && (num3 <= 0x35))
{
goto Label_0054;
}
flag3 = true ;
}
else
{
if (num2 != 0x80)
{
if (!flag2)
{
flag3 = true ;
goto Label_014B;
}
if (num3 != (num2 / 2))
{
flag3 = true ;
goto Label_014B;
}
flag2 = false ;
goto Label_0054;
}
if ((num3 >= 0x36) && (num3 <= 0x39))
{
goto Label_0054;
}
flag3 = true ;
}
}
else
{
if (num3 == (num2 / 2))
{
goto Label_0054;
}
flag3 = true ;
}
}
else
{
if ((num3 >= 0x41) && (num3 <= 90))
{
goto Label_0054;
}
flag3 = true ;
}
}
else
{
if ((num3 >= 0x30) && (num3 <= 0x39))
{
goto Label_0054;
}
flag3 = true ;
}
}
}
else
{
if ((num3 >= 0x4c) && (num3 <= 90))
{
goto Label_0054;
}
flag3 = true ;
}
}
goto Label_014B;
Label_0054:
num1++;
Label_005A: //实际是循环:for(num4=0;num4<buffer2.Length;num4++)
num4++;
goto Label_001B;
Label_014B:
if (!flag3)
{
flag1 = true ;
}
return flag1;
} 看起来有点眼花,实际是因为Reflector对switch语句的支持不太好造成的。按照里面的逻辑列一张表就清楚了:
num2 num3
190 [0x41,0x4b]
0xbc [0x4c,90]
0xb8 flag2 = true ,当前num3不变(num2在这里的作用是一个额外的转义字符)
0x42 [0x30,0x35]
90 45
0x7e [0x41,90]
0x4a [0x30,0x39]
0x80 [0x36,0x39]default : flag2 == true && num3 == num2 / 2, flag2 = false
再看看Product.dk是在哪里初始化的,用Callee graph查到WebGrid.NET当中
<ISNet.WebUI.WebGrid.WebGrid>
.method family hidebysig specialname virtual instance [ISNet.WebUI]ISNet.WebUI.ProductInfo get_Product() cil managed
{
// Code Size: 292 byte(s)
…
L_006b: ldc.i4.s 16
L_006d: newarr unsigned int8
L_0072: dup
L_0073: ldtoken ?/? ?::?
L_0078: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray([mscorlib]System.Array, [mscorlib]System.RuntimeFieldHandle)
L_007d: stfld unsigned int8[] [ISNet.WebUI]ISNet.WebUI.ProductInfo::dk
}
找那串乱码的定义
.field assembly static ?/? ? = ((BC 42 4A 4A 42 5A 42 BC BE 7E 5A 7E BC BE BE BC))
对照上面的表,就可以手动构造一个sn了。如0x4c, 0x30, 0x30, 0x30, 0x30, 45, 0x30, 0x4c, 0x41, 0x41, 45, 0x41, 0x4c, 0x41, 0x41, 0x4c,即N0000-0NAA-ANAAN。Keygen也不难写,甚至可以写一个WebUI Framework产品万能注册机,直接从exe里面读取这串东西,呵呵。这里就省略了。
想不明白WebUI Framework的注册码验证算法为什么不再用Remotesoft Protector了。莫非出现版权问题?不过这对偶等穷人是好事。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!