我想挂钩一个CLR方法,在我的情况下,我试图挂钩AppDomain->加载(byte [])。
我尝试了几个我可以找到钩住自编类方法的例子,但它们似乎都不适用于CLR方法。所以我试着坚持使用AppDomain :: CurrentDomain对象的vtable钩子,这似乎在理论上起作用。 但是,每当它调用我的方法时,它会在某处崩溃并且WinDBG会显示以下错误:
ExceptionCode: c0000005 (Access violation)
Attempt to execute non-executable address 000000d801020200
Stack:
00000000001aece0 000007fe927e20da cppclihook!DomainBoundILStubClass.IL_STUB_ReversePInvoke+0x8a
00000000001aee10 000007fe927e1a28 cppclihook!_Module_.main+0x48
00000000001aef20 000007fe927e1988 cppclihook!DomainBoundILStubClass.IL_STUB_PInvoke+0x68
我通过简单地调用AppDomain->加载并检查vs中生成的反汇编代码得到了vtable偏移量,可以在这里看到:
当前代码:
public delegate Reflection::Assembly^ CurrentDomain_LoadDelegate_Hook(AppDomain^ thisptr, array<uint8_t>^ data);
public delegate Reflection::Assembly^ CurrentDomain_LoadDelegate(array<uint8_t>^ data);
Reflection::Assembly^ (__clrcall* CurrentDomain_Load)(AppDomain^ thisptr, array<uint8_t>^ data);
Reflection::Assembly^ __clrcall CurrentDomain_Load_Hook(AppDomain^ thisptr, array<uint8_t>^ data)
{
System::Windows::Forms::MessageBox::Show("Hooked");
// calls jmp <clr.AssemblyNative::LoadImage>
return CurrentDomain_Load(thisptr, data);
}
void HookDomain(AppDomain^ domain)
{
auto fp = gcnew CurrentDomain_LoadDelegate_Hook(CurrentDomain_Load_Hook);
RuntimeHelpers::PrepareMethod(fp->Method->MethodHandle);
auto gch = GCHandle::Alloc(fp);
auto ip = Marshal::GetFunctionPointerForDelegate(fp);
auto hookAddr = (uintptr_t)ip.ToPointer();
// auto orig = gcnew CurrentDomain_LoadDelegate(domain, &AppDomain::Load);
// RuntimeHelpers::PrepareMethod(orig->Method->MethodHandle);
auto domainPtrHandle = System::Runtime::InteropServices::GCHandle::Alloc(domain);
auto domainIntPtr = System::Runtime::InteropServices::GCHandle::ToIntPtr(domainPtrHandle);
auto domainPtr = *(uintptr_t*)domainIntPtr.ToPointer();
auto vtableAddr = *(uintptr_t***)domainPtr;
auto funcAddr = vtableAddr[12];
DWORD protect;
VirtualProtect(funcAddr, sizeof(uintptr_t), PAGE_EXECUTE_READWRITE, &protect);
// save orig addr
// CurrentDomain_Load = ?
*funcAddr = hookAddr;
VirtualProtect(funcAddr, sizeof(uintptr_t), protect, &protect);
}
int main(int argc, char** argv)
{
HookDomain(AppDomain::CurrentDomain);
try
{
array<uint8_t>^ arr = gcnew array<uint8_t>(256);
System::AppDomain::CurrentDomain->Load(arr);
}
catch(Exception^) {}
return 0;
}
我实际上检查了原始Load方法中发生了什么,它似乎没有做任何特别的事情:
当我从vtable调用中跟踪我的hook方法时,它在调用无效指针时崩溃:
我还尝试为本机DLL提供AppDomain指针并挂钩到一个简单调用原始地址的本机函数。 因为它只生成一个JMP [original_load],我希望它可以工作,但它会在NET调用中的某个地方崩溃。
我错过了什么,或者我做错了什么? 希望任何人都可以帮助我。