R2R的原理是在DLL里面添加一个Native Header项,此项包含了:
1.编译器标识符(CompilerIdentifier)
2.导入方法段(ImportSections)
3.运行时方法(RuntimeFunctions)
4.方法入口点(MethodDefEntryPoints)
5.异常信息(ExceptionInfo)
6.调试信息(DebugInfo)
7.延迟加载方法调用块(DelayLoadMethodCallThunks)
等等总共高达18项信息,由于这些东西过于复杂此处只列出其中的前面几个。构成了NH。.
可以看到RuntimeFunctions是运行时方法,要获取到它的索引,则必须首先获取到方法入口点(MethodDefEntryPoints)。
方法入口点是在方法: ReadyToRunInfo::Initialize 里面获取。
Module::Initialize---->
ReadyToRunInfo::Initialize--->
new(pMemory)ReadyToRunInfo---->
m_methodDefEntryPoints=NativeArray(&m_nativeReader,pEntryPointsDir>VirtualAddress)
NativeArray里面:
NativeArray(PTR_NativeReader pReader, uint offset)
: _pReader(pReader)
{
uint val;
_baseOffset = pReader->DecodeUnsigned(offset, &val);
_nElements = (val >> 2);
_entryIndexSize = (val & 3);
}
此后
bool TryGetAt(uint index, uint * pOffset)
{
if (index >= _nElements)
return false;
uint offset;
if (_entryIndexSize == 0)
{
offset = _pReader->ReadUInt8(_baseOffset + (index / _blockSize));
}
else if (_entryIndexSize == 1)
{
offset = _pReader->ReadUInt16(_baseOffset + 2 * (index / _blockSize));
}
else
{
offset = _pReader->ReadUInt32(_baseOffset + 4 * (index / _blockSize));
}
offset += _baseOffset;
for (uint bit = _blockSize >> 1; bit > 0; bit >>= 1)
{
uint val;
uint offset2 = _pReader->DecodeUnsigned(offset, &val);
if (index & bit)
{
if ((val & 2) != 0)
{
offset = offset + (val >> 2);
continue;
}
}
else
{
if ((val & 1) != 0)
{
offset = offset2;
continue;
}
}
// Not found
if ((val & 3) == 0)
{
// Matching special leaf node?
if ((val >> 2) == (index & (_blockSize - 1)))
{
offset = offset2;
break;
}
}
return false;
}
*pOffset = offset;
return true;
}
};
offset = m_nativeReader.DecodeUnsigned(offset, &id);
if (id & 1)
{
id >>= 2;
}
else
{
id >>= 1;
}
pEntryPoint = dac_cast<TADDR>(GetImage()->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
大致的结果就是这样