CLR内核随记(1)

CLR内核随记(1)

 

把平时看到的一些东西记下来,没准以后用的上。

 

本文利用调试跟踪CLR中接口virtual方法的定位。为什么呢?好玩儿而已。

 

这是在某壳挂钩JIT的代码,有些东西还是很有意思(总是觉得这些壳作者知道很多CLR的内部结构,估计微软对他们部分开源了):

.text:10002A4C                 mov     eax, [ebp+ICorJitInfo]
.text:10002A4F                 mov     ecx, [eax+4]

//此时ecxà.text:79E97C14 const CEEJitInfo::`vbtable'{for `ICorJitInfo'},第一个双字是什么?第一个双字指向

.text:79E97B14                 dd offset [thunk]:CEEInfo::getHelperName`vtordisp{4294967292,52}' (CorInfoHelpFunc)

 

到这里,来看看CEEJitInfo::’vbtable’在内存中的表示:

79E97C14 >FC FF FF FF 34 00 00 00 3C 00 00 00 44 00 00 00

79E97C24  4C 00 00 00 54 00 00 00 5C 00 00 00 64 00 00 00

79E97C34  6C 00 00 00 74 00 00 00 80 00 00 00 FC FF FF FF

 

其实这些值是在编译时确定的,因为CLR本身部分用C++写成,也就是C++中的vtable在编译时确定,mscorwks.dll中的代码如下:

.text:79E97C14 const CEEJitInfo::`vbtable'{for `ICorJitInfo'} dd 0FFFFFFFCh, 34h, 3Ch, 44h, 4Ch, 54h, 5Ch, 64h, 6Ch

.text:79E97C14                 dd 74h, 80h

 

FCFFFFFFwhat?谁知道,也许是一个vtable的开始标志,因为在第三行最后又见到一个同样的双字。计算两个FCFFFFFF之间的双字值,可以先猜测这个vtable含有10个方法。不过sscli中对应的代码却多出了一两个方法,这里暂且不管,下面主要看怎么定位这些vtable的。

 

.text:10002A52                 mov     edx, [ecx+4]
.text:10002A55                 mov     eax, [ebp+ICorJitInfo]
.text:10002A58                 mov     ecx, [eax+4]
.text:10002A5B                 mov     eax, [ecx+4]
.text:10002A5E                 mov     ecx, [ebp+ICorJitInfo]
.text:10002A61                 lea     eax, [ecx+eax+4]
.text:10002A65                 mov     ecx, [ebp+ICorJitInfo]
.text:10002A68                 mov     edx, [ecx+edx+4]

 

lea eax这句执行完后,eax指向内存如下

0013EA18  78 7B E9 79 00 00 00 00 4C 7B E9 79 00 00 00 00 

0013EA28  A8 7A E9 79 00 00 00 00 84 7A E9 79 00 00 00 00

 

总觉得后面那句mov edx,[ecx+edx+4]重复了,直接mov edx,[eax]不就可以了吗?这时[eax]的值是79E97B78指向什么?它指向了下面一个方法:.text:79E97B78 const CEEJitInfo::`vftable'{for `ICorMethodInfo'} dd offset [thunk]:CEEInfo::getMethodName`vtordisp{4294967292,52}' (CORINFO_METHOD_STRUCT_ *,char const * *)

 

也就是说,在ICorJitInfo vtable表里有getMethodName方法。可sscli的代码中并没有getMethodName方法啊。如果说,vtable是按顺序生成的,那么eax+ecx+4这个指令代表getMethodName方法排名应该还较靠前,而sscli中的代码为。

 

 

class ICorJitInfo : public virtual ICorDynamicInfo
{
public:
    // return memory manager that the JIT can use to allocate a regular memory
    virtual IEEMemoryManager* __stdcall getMemoryManager() = 0;

 

    // get a block of memory for the code, readonly data, and read-write data
    virtual void __stdcall allocMem (

}

 

这时,我们想到了继承。ICorJitInfo继承了ICorDynamicInfo,于是来到后者的代码处:


class ICorDynamicInfo : public virtual ICorStaticInfo

 

这里,ICorDynamicInfo中仍然没有getMethodName的方法,于是再次顺着继承走下去:

 


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第一个继承的就是ICorMethodInfo,终于,我们找到了getMethodName方法:

class ICorMethodInfo
{
public:
    
// this function is for debugging only.  It returns the method name

    
// and if 'moduleName' is non-null, it sets it to something that will
    
// says which method (a class name, or a module name)
    virtual const char* __stdcall getMethodName (
            CORINFO_METHOD_HANDLE       ftn,        
/* IN */
            const char                **moduleName  
/* OUT */
            ) = 0;

    
// this function is for debugging only.  It returns a value that
    
// is will always be the same for a given method.  It is used
    
// to implement the 'jitRange' functionality
    virtual unsigned __stdcall getMethodHash (
            CORINFO_METHOD_HANDLE       ftn         
/* IN */
            ) = 0;

 

 

到这里,一个简单的virtual方法定位才算跟完。其实,这和CLR已经没有多大关系了,更多的是C++编译器的工作,它是怎么分配类和虚方法的内存空间,当然,还要结合在运行时的动态填充。

 

CLR中提供了多少个这种vtable呢?至少有以下这么多:

.text:79E977EC                 mov     dword ptr [esi+4], offset const CEEJitInfo::`vbtable'{for `CEEInfo'}
.text:79E977F3                 mov     
dword ptr [esi+10h], offset
 const CEEJitInfo::`vbtable'{for `ICorJitInfo'}
.text:79E977FA                 mov     
dword ptr [esi+88h], offset
 const CEEInfo::`vbtable'{for `ICorStaticInfo'}
.text:79E97804                 mov     
dword ptr [esi+94h], offset
 const CEEJitInfo::`vbtable'{for `ICorDynamicInfo'}
.text:79E9780E                 mov     
dword ptr [esi+44h], offset
 const ICorStaticInfo::`vftable'{for `ICorMethodInfo'}
.text:79E97815                 mov     
dword ptr [esi+4Ch], offset
 const ICorModuleInfo::`vftable'
.text:79E9781C                 mov     
dword ptr [esi+54h], offset
 const ICorCompileInfo::`vftable'{for `ICorClassInfo'}
.text:79E97823                 mov     
dword ptr [esi+5Ch], offset
 const ICorJitInfo::`vftable'{for `ICorFieldInfo'}
.text:79E9782A                 mov     
dword ptr [esi+64h], offset
 const ICorDebugInfo::`vftable'
.text:79E97831                 mov     
dword ptr [esi+6Ch], offset
 const ICorCompileInfo::`vftable'{for `ICorArgInfo'}
.text:79E97838                 mov     
dword ptr [esi+74h], offset const CHashTableAndData<CNewDataNoThrow>::`vftable'

 

回到文章最初的ICorJitInfo,那个表中第一个值是0x34,最终定位到getMethodName,第二个0x3C又指向什么方法呢?你自己跟一下吧,呵呵。

 

下次,会真正跟一些CLR内部的东西,那些被标记上for internal use的玩意儿。以上分析基于xp sp2 +.net framework 2.0 简体中文版。

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值