Welcome

首页 / 软件开发 / .NET编程技术 / .Net程序集基于方法的保护原理(HookJIT篇)

.Net程序集基于方法的保护原理(HookJIT篇)2012-02-11 博客园 RZH引言

DOTNET程序集的保护由混淆、整体加密、基于方法保护到参与伪IL指令本地化,逐步由纯.NET领域走向传统WIN32加密领域。相应,解密的主体工作也由过去的 IL代码分析走向了ASM代码分析。我们留恋过去的“开源盛世”,但不得不正视现实。基于方法的保护是这一过渡中关键的一环,可见的实例代码太少了,本文将通过手动实践学习它的基本原理。

JIT及相关内容简介

JIT Compiler(Just-in-time Compiler) 即时编译。.net中当一个方法第一次被调用时,虚拟机会调用JIT来编译生成本地代码。也就是说.net的即时编译是基于每个方法的,它的具体实现由MSCORJIT.DLL提供。当方法第一次被调用时,调用方从MethodTable中读取指向一个代码块的地址,也就是方法的描述(MethodDesc),然后调用这个块,块接着调用JIT。当JIT完成了编译后,将改变MethodTable,使其直接指向已经被JIT编译过的代码,也就是说无论代码是否被JIT编译,对方法的调用都是通过调用MethodTable中方法地址来实现的。

这正是我们要关注的两个地方,MSCORJIT.DLL中的编译函数CILJit::compileMethod以及PE格式文件中的MethodTable。MethodTable以后再提及,先让我们看看JIT的方法调用流程:

1.MSCORJIT.DLL只提供了唯一一个导出函数getJit(),它返回一个虚表指针,而这个虚表的第一项就是CILJit::compileMethod函数指针。

2.CILJit::compileMethod函数不做任何工作,直接调用了jitNativeCode方法。而jitNativeCode则会调用Compiler::compCompile完成实质工作。

3.需要注意的是这和SSCLI并不完全相同,但上述方法中使用的接口和结构SSCLI已经给出:corinfo.h 和 corjit.h,挂勾时需要它们。

下面我们来看看getJit()方法在MSCORJIT.DLL和SSCLI中的实现,因为我们要调用getJit()得到CILJit::compileMethod函数指针,并通过替换它完成我们的挂勾,这是个稳妥的方法,不需要根据不同操作系统和运行时版本去找内存地址,加密程序需要稳定:

MSCORJIT中:

int *__cdecl getJit()
{
int *result; // eax@1
result = (int *)dword_790B7260;
if ( !dword_790B7260 )
{
result = &dword_790B7268;
dword_790B7268 = (int)&CILJit___vftable_;
dword_790B7260 = (int)&dword_790B7268;
}
return result;
}