前言
Dnguard是通过Hook JIT编译器,跳转到HVMRun64.dll里面的RunHVM函数,通过还原IL代码来对IL代码进行重新编辑,然后导入到JIT进行正规化的编译。这样就可以避免一些中低端的破解,本篇来看下这个过程.
概括
1.举例
比如以下代码:
static void Main(string[] args)
{
Console.ReadLine();
Console.WriteLine("Call Main");
}
经过Dnguard加密之后他变成了
[NullableContext(1)]
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Main(string[] args)
{
throw new Exception("Error, DNGuard Runtime library not loaded!");
}
它变成了这种代码之后,无法通过修改MSIL这种简单的方法来破解或者篡改程序集了,从而修改结果。
2.加密
经过Dnguard加密的.Net DLL里面生成了高达几十个方法,这些方法对于混淆托管DLL以及JIT的编译流程起了作用。它自己生成了另外两个非托管DLL(实质部分方法也被托管调用)HVMRun64.dll和HVMRuntm.dll,前者用于64位,后者32位。其中有几个比较重要的函数分别为:
<Module>虚拟模块的cotr
ZXYDNGuarder模块的Startup
ZXYDNGuarder模块的CheckRuntime64
ZXYDNGuarder模块的RunHVM
.ctor里面调用虚拟机修改程序的入口Startup运行,然后里面调用CheckRuntime64运行RunHVM函数hook JIT。
其中RunHVM把.Net JIT的compileMethod函数修改为HVMRun64.dll里面不知名的函数进行MSIL还原,也就是把加密的MSIL还原成正确的MSIL。
Dnguard保护程序入口的代码逆向如下:
void Startup()
{
bool ZYXDNGuarder.a;
if(a!=0)
{
return;
}
try
{
bool l=ZYXDNGuarder.RunHVM();
bool ZYXDNGuarder.a;
}
catch(Exception ex)
{
try
{
int A=ZYXDNGuarder.a;
int B= System.IntPtr.get_Size();
if(a<=b)
{
ZYXDNGuarder.CheckRuntime64();
try
{
ZYXDNGuarder.$MD$F();
ZYXDNGuarder.a;
}
catch
{
string str="*=Load DNGuard Runtime library failed, runtime lib";
System.Exception ex =new System.Exception();
throw;
}
}
catch
{
}
}
}
它主要的Hook JIT代码是在RunHVM函数里面,这个函数在HVMRun64.dll里面,而这个DLL是个汇编非托管,行数高达153万多行。后面再看看。