随着微软在.NET 3.5 SP1中正式推出Entity Framework,很多数据访问提供者开始支持这一新框架。本文涉及到的 Devart MyDirect.NET 就是目前MySql数据库领域支持EF的数据访问组件(MySql Connector据说要等本月底才推出支持EF的新版本)。MyDirect.NET对EF提供了很好的支持,不过免费版只能试用1个月。以下从技术角度阐述如何绕开其验证,仅供学习研究之用。
1、寻找验证相关的入口函数:
当到期时,异常信息和调用堆栈如下:
----> CoreLab.MySql.MySqlException : Sorry, your trial period has expired.
--MySqlException
at CoreLab.MySql.MySqlConnection.Open()
在打开MySqlConnection出错,用Reflector分析CoreLab.MySql.dll看一下代码:
Code
License license = a
随着微软在.NET 3.5 SP1中正式推出Entity Framework,很多数据访问提供者开始支持这一新框架。本文涉及到的 Devart MyDirect.NET 就是目前MySql数据库领域支持EF的数据访问组件(MySql Connector据说要等本月底才推出支持EF的新版本)。MyDirect.NET对EF提供了很好的支持,不过免费版只能试用1个月。以下从技术角度阐述如何绕开其验证,仅供学习研究之用。
1、寻找验证相关的入口函数:
当到期时,异常信息和调用堆栈如下:
----> CoreLab.MySql.MySqlException : Sorry, your trial period has expired.
--MySqlException
at CoreLab.MySql.MySqlConnection.Open()
在打开MySqlConnection出错,用Reflector分析CoreLab.MySql.dll看一下代码:
Code
License license = ac.a().GetLicense(LicenseManager.CurrentContext, typeof(MySqlConnection), this, false);
u u = license as u;
if ((u != null) && (u.b() != null))
{
throw new MySqlException(-1, u.b());
}
可以看到,ac这个类实现LicenseProvider用于产生License,而u这个类继承License对象,同时保存更具体的认证信息。
由于混淆过,我们无从知道u这个类每个字段的含义(a,b,c,d,e,f),这个时候我们需要人为执行一下GetLicense,看里面到底包含什么数据:
Code
Type licenseType = typeof(LicenseProvider);
Assembly coreLabMySql = typeof(CoreLab.MySql.MySqlConnection).Assembly;
Type t = coreLabMySql.GetType("CoreLab.Common.ac");
Type u = coreLabMySql.GetType("CoreLab.Common.u");
// 创建ac对象
var aMethod = t.GetMethod("a", BindingFlags.Static | BindingFlags.Public);
var ac = aMethod.Invoke(null, new object[] { });
// 模拟调用GetLicense
MySqlConnection conn = new MySqlConnection();
var getLicense = t.GetMethod("GetLicense");
var license = getLicense.Invoke(ac, new object[] { LicenseManager.CurrentContext, typeof(MySqlConnection), conn, false });
// 查看返回的license
var uLicense = Convert.ChangeType(license, u);
调试的时候我们可以看到,u.a包含了LicenseString, u.c则包含了认证失败的错误信息,u.e=3,这个貌似是返回码。
我们把系统时间调前,看一下未到期的时候,产生的license是什么样子:
u.a=LicenseString, u.c=null, u.e=0
2、产生可以使用的License
Code
public class MyLicenseProvider : LicenseProvider
{
public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions)
{
Assembly coreLabMySql = typeof(CoreLab.MySql.MySqlConnection).GetType().Assembly;
Type uType = coreLabMySql.GetType("CoreLab.Common.u");
object u = Activator.CreateInstance(uType, "Here is license string", null, false, 0, null);
return u as License;
}
}
自己运行一下,OK,可以产生一个正常的license
3、修改DLL
首先,将上述MyLicenseProvider编译成一个DLL,我们需要得到上述代码的IL:
ilasm MyLicenseProvider.dll /out=MyLicenseProvider.il
找到 GetLicense 方法:
Code
// Code size 82 (0x52)
.maxstack 4
.locals init ([0] class [mscorlib]System.Reflection.Assembly coreLabMySql,
[1] class [mscorlib]System.Type uType,
[2] object u,
[3] class [System]System.ComponentModel.License CS$1$0000,
[4] object[] CS$0$0001)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_0007: callvirt instance class [mscorlib]System.Reflection.Assembly [mscorlib]System.Type::get_Assembly()
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: ldstr "CoreLab.Common.u"
IL_0013: callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string)
IL_0018: stloc.1
IL_0019: ldloc.1
IL_001a: ldc.i4.5
IL_001b: newarr [mscorlib]System.Object
IL_0020: stloc.s CS$0$0001
IL_0022: ldloc.s CS$0$0001
IL_0024: ldc.i4.0
IL_0025: ldstr "here is license string"
+ "k0WXphh/g4KEcX"
IL_002a: stelem.ref
IL_002b: ldloc.s CS$0$0001
IL_002d: ldc.i4.2
IL_002e: ldc.i4.0
IL_002f: box [mscorlib]System.Boolean
IL_0034: stelem.ref
IL_0035: ldloc.s CS$0$0001
IL_0037: ldc.i4.3
IL_0038: ldc.i4.0
IL_0039: box [mscorlib]System.Int32
IL_003e: stelem.ref
IL_003f: ldloc.s CS$0$0001
IL_0041: call object [mscorlib]System.Activator::CreateInstance(class [mscorlib]System.Type,
object[])
IL_0046: stloc.2
IL_0047: ldloc.2
IL_0048: isinst [System]System.ComponentModel.License
IL_004d: stloc.3
IL_004e: br.s IL_0050
IL_0050: ldloc.3
IL_0051: ret
接下来我们要反汇编 CoreLab.MySql.dll
运行 ildasm CoreLab.MySql.dll /out=source.il
这时出现提示信息 "Protected Module",无法反汇编。这是因为这个动态库增加了SuppressIldasmAttribute属性,从而ildasm不允许反汇编。我们可以很容易制造一个hack过的ildasm.exe版本,方法如下:
用二进制编辑器(如WinHex)打开C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\ildasm.exe
查找SuppressIldasmAttribute,将其修改为任意字符串,保存。
现在重新执行ildasm CoreLab.MySql.dll /out=source.il,得到CoreLab.MySql的il代码,查找以下代码:
Code
.method public hidebysig virtual instance class [System]System.ComponentModel.License
a(class [System]System.ComponentModel.LicenseContext A_0,
class [mscorlib]System.Type A_1,
object A_2,
bool A_3) cil managed
用我们之前得到的MyLicenseProvider里面的il代码替换a()方法,注意保留第一行的.override [System]System.ComponentModel.LicenseProvider::GetLicense
我们在重新编译il之前,还有一些工作要做,其中最重要的就是产生强名称签名。没有强名称签名,这个修改过的dll是无法工作的。
4、产生和修改强名称
首先产生一对key:
sn -k key.snk
然后从中提取公钥
sn -p key.snk public.key
然后显示PublicKeyToken
sn -t public.key
这个时候会显示Public key token is a603cb3085449c2c
这个public key token要记下来,我们下面要用到
这里需要说明一下CoreLab.MySql.dll和CoreLab.MySql.Entity.dll的关系。
从名称上可以看出,CoreLab.MySql.Entity.dll用于支持Entity Framework,所以其必然会引用强名称版本的CoreLab.MySql.dll,通过Reflector查看Reference可以验证我们的猜想。按照我们的思路,修改CoreLab.MySql.dll的验证部分代码,然后用我们产生的新的key去签名,为了支持EF,有必要同时产生一个配套的修改版CoreLab.MySql.Entity.dll。
回头看CoreLab.MySql.dll,我们使用EF也好,使用ADO.NET也好,其Data Provider都是指向CoreLab.MySql。通过反射可知,这些功能都是由 CoreLab.MySql.MySqlDirectFactory工厂来支持的,这个类实现了接口DbProviderFactory和IServiceProvider,前者用于支持ADO.NET Data Provider,后者用于支持Entity Framework。我们看到MySqlDirectFactory里有如下方法签名:private object a(Type A_0); 这个方法便实现了IServiceProvider.GetService(Type serviceType)方法。在它的实现里,可以看到如下代码:
Code
Type type = (a == null) ? Type.GetType("CoreLab.MySql.Entity.MySqlEntityProviderServices, CoreLab.MySql.Entity, Version=4.85.35.0, Culture=neutral, PublicKeyToken=09af7300eec23701", false) : a.GetType();
if (type == null)
{
Assembly assembly = Assembly.Load("CoreLab.MySql.Entity, Version=4.85.35.0, Culture=neutral, PublicKeyToken=09af7300eec23701");
if (assembly != null)
{
type = assembly.GetType("CoreLab.MySql.Entity.MySqlEntityProviderServices");
}
}
把这里的PublicKeyToken=09af7300eec23701替换成我们刚才自己产生的KeyToken, a603cb3085449c2c。
好了,现在可以重新编译 CoreLab.MySql.dll 了,运行以下命令:
ilasm source.il /dll /key=key.snk /out=CoreLab.MySql.dll
接下来我们修改CoreLab.MySql.Entity.dll对CoreLab.MySql.dll的引用。
1) 反汇编IL
ildasm CoreLab.MySql.Entity.dll /out=entity_source.il
2) 查找 .assembly extern CoreLab.MySql
将publickeytoken改成上面产生的新key,每个字节用空格隔开
3) 重新编译
ilasm entity_source.il /dll /key=key.snk /out=CoreLab.MySql.Entity.dll
对DLL和强名称的修改完成后,我们可以重新注册这些DLL并且使用了。
5、注册GAC
gacutil /i CoreLab.MySql.dll
gacutil /i CoreLab.MySql.Entity.dll
如果打开C:\Windows\Assembly,我们现在应该可以看到两个版本的DLL,一个是原始版,一个是修改版
6、最后一步,修改machine.config使用修改版Data Provider.
编辑 C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config
找到以下这一段配置:
<add name="MyDirect .NET" invariant="CoreLab.MySql" description="CoreLab MyDirect .NET"
type="CoreLab.MySql.MySqlDirectFactory, CoreLab.MySql, Version=4.85.35.0, Culture=neutral, PublicKeyToken=09af7300eec23701" />
将PublicKeyToken改成我们的key
大功告成~!