闲来无事,随便写点,老话题了,高手略过。
    compileMethod方法在各类.NET内核的文章中出现频率相当高,因为它是JIT引擎工作的关键函数。其原型如下(参考sscli代码):

代码:
CorJitResult __stdcall FJitCompiler::compileMethod (
            ICorJitInfo*               compHnd,            /* IN */
            CORINFO_METHOD_INFO*        info,               /* IN */
            unsigned                flags,              /* IN */
            BYTE **                 entryAddress,       /* OUT */
            ULONG  *                nativeSizeOfCode    /* OUT */
            )
    一般的用法是通过该函数的第二个参数COFINFO_METHOD_INFO取得代码的IL和大小。但其实还可以更加深入,注意第一个传入参数很有意思,指向了ICorJitInfo接口。该接口定义如下:
代码:
/*********************************************************************************
 * a ICorJitInfo is the main interface that the JIT uses to call back to the EE and
 *   get information
 *********************************************************************************/
class ICorJitInfo : public virtual ICorDynamicInfo
{//省略}
    这说明ICorJitInfo继承了ICorDynamicInfo接口。而后者的定义如下:
代码:
/*****************************************************************************
 * ICorDynamicInfo contains EE interface methods which return values that may
 * change from invocation to invocation.  They cannot be embedded in persisted
 * data; they must be requeried each time the EE is run.
 *****************************************************************************/

class ICorDynamicInfo : public virtual ICorStaticInfo
{//省略}
    这说明ICorDynamicInfo又继承了ICorStaticInfo。接着来,继续看ICorStaticInfo的代码:

代码:
/*****************************************************************************
 * ICorStaticInfo contains EE interface methods which return values that are
 * constant from invocation to invocation.  Thus they may be embedded in
 * persisted information like statically generated code. (This is of course
 * assuming that all code versions are identical each time.)
 *****************************************************************************/
class ICorStaticInfo : public virtual ICorMethodInfo, public virtual ICorModuleInfo,
                       public virtual ICorClassInfo,  public virtual ICorFieldInfo,
                       public virtual ICorDebugInfo,  public virtual ICorArgInfo,
                       public virtual ICorLinkInfo,   public virtual ICorErrorInfo
    这一次牛了,ICorStaticInfo继承了8个接口的方法,其中第一个为ICorMethodInfo。该接口定义了许多与方法相关的函数,如果能调用它,在hook中是非常爽的。那可不可以调用呢?当然可以,compileMethod的第一个参数就是我们需要的。
    比如我们需要取得当前hook方法的方法名,可以调用ICorMethodInfo中的如下方法:
代码:
    virtual const char* __stdcall getMethodName (
            CORINFO_METHOD_HANDLE       ftn,        /* IN */
            const char                **moduleName  /* OUT */
            ) = 0;
    这里需要传入CORINFO_METHOD_HANDLE这个参数,该参数是.NET内核中表示方法的核心结构,在sscli中也未公开。不过它的值是可以取得的,从compileMethod第二个参数CORINFO_METHOD_INFO结构的第一项中便可以取得:
代码:
struct CORINFO_METHOD_INFO
{
    CORINFO_METHOD_HANDLE       ftn;
    CORINFO_MODULE_HANDLE       scope;    
    BYTE *                      ILCode;
    unsigned                    ILCodeSize;
    unsigned short              maxStack;
    unsigned short              EHcount;
    CorInfoOptions              options;
    CORINFO_SIG_INFO            args;
    CORINFO_SIG_INFO            locals;
};
    同样,在调用ICorModuleInfor接口中的许多方法时,也需要传入CORINFO_MODULE_HANDLE作为参数,同样可以从CORINFO_METHOD_INFO结构中获得该值。比如调用findClass函数,以取得CORINFO_CLASS_HANDLE,定义如下:
代码:
    virtual CORINFO_CLASS_HANDLE __stdcall findClass (
            CORINFO_MODULE_HANDLE       module,     /* IN  */
            unsigned                    metaTOK,    /* IN  */
            CORINFO_CONTEXT_HANDLE      context,    /* IN  */
            CorInfoTokenKind            tokenKind = CORINFO_TOKENKIND_Default /* IN  */
            ) = 0;
    其中出现了CORINFO_CONTEXT_HANDLE。该结构也非常容易取得,具体参考sscli,就不详述了。
    具体在VS中编程时,可以添加corinfo.h和corjit.h,并在同一目录下添加corhdr.h,便可顺利编译通过。
    最后还有一个问题,sscli毕竟是早期框架了,还是精简版,现在还能直接使用吗?不妨分析一下。随便运行一个.NET程序,用WinDbg调试并中断在compileMethod处,查看ICorJitInfo值所指的内存:
代码:
0012ea38 79f10654 mscorwks!CEEJitInfo::`vbtable'
0012ea3c 00174d18 
0012ea40 00997850 
0012ea44 00107210 
0012ea48 00000000 
0012ea4c 0018a610 
0012ea50 00000000 
0012ea54 00000000 
0012ea58 00000000 
0012ea5c 0012ea40 
0012ea60 00000000 
0012ea64 00000000 
0012ea68 00000000 
0012ea6c 79f105b8 mscorwks!CEEJitInfo::`vftable'
0012ea70 00000000 
0012ea74 79f10584 mscorwks!CEEJitInfo::`vftable'
0012ea78 00000000 
0012ea7c 79f104e0 mscorwks!CEEJitInfo::`vftable'
0012ea80 00000000 
0012ea84 79f104bc mscorwks!CEEJitInfo::`vftable'
0012ea88 00000000 
0012ea8c 79f104a4 mscorwks!CEEJitInfo::`vftable'
0012ea90 00000000 
0012ea94 79f10498 mscorwks!CEEJitInfo::`vftable'
0012ea98 00000000 
0012ea9c 79f10494 mscorwks!CEEJitInfo::`vftable'
...//下略
    这里又涉及到VC编译器对类的vftable和vbtable在内存中的布局问题了,最先两项是类自身定义的虚方法表和虚基址表,相关资料请自己查阅。我们跟进vftable:
代码:
79f10624 79f106ac mscorwks!CEEJitInfo::getMemoryManager
79f10628 79f11d82 mscorwks!CEEJitInfo::allocMem
79f1062c 79f11f39 mscorwks!CEEJitInfo::allocGCInfo
79f10630 7a12b8cb mscorwks!CEEJitInfo::getEHInfo
79f10634 7a12b6cf mscorwks!CEEJitInfo::yieldExecution
79f10638 79f16373 mscorwks!CEEJitInfo::setEHcount
79f1063c 79f16491 mscorwks!CEEJitInfo::setEHinfo
79f10640 7a12ed41 mscorwks!CEEJitInfo::logMsg
79f10644 7a27ffcc mscorwks!ZapperModule::doAssert
79f10648 7a12eeb6 mscorwks!CEEJitInfo::allocBBProfileBuffer
79f1064c 7a2c2fa1 mscorwks!MDInternalRO::ConvertTextSigToComSig
79f10650 79f0efee mscorwks!CEEJitInfo::isVerifyOnly
79f10654 fffffffc 
      这些地址在静态编译时就已经确定了,因此如果用IDA反编译mscorwks.dll,同样会得到这些值。这便是最新的.NET框架内核中ICorJitInfo定义的方法。和sscli对比下(在corjit.h文件中),完全一样!(也可以再对比其它关键接口的方法,应该也是一样,我没有详细对比了。)
    这样,我们就得到如下的结论:.NET内核框架从2.0开始,内核变化不大,包括sscli的内核代码,这些可以从内部函数的定义看出来;通过hook compileMethod,可以得到ICorJitInfo等关键接口,并调用其中的许多内部方法;具体编写时,可以在VS中引入sscli的corinfo.h、corjit.h和corhdr.h等文件,之后便可以直接调用。因此,通过compileMethod,我们可以做的事很多很多,远不限于仅获得某个方法的IL。
    个人观点,若有错误,欢迎指正!