CLR方法挂钩

时间:2017-09-15 20:47:39

标签: .net c++-cli hook clr

我想挂钩一个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偏移量,可以在这里看到:

disassembly of AppDomain->Load call

当前代码:

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方法中发生了什么,它似乎没有做任何特别的事情:

AppDomain->Load call Call of Load call

当我从vtable调用中跟踪我的hook方法时,它在调用无效指针时崩溃:

invalid RBX

我还尝试为本机DLL提供AppDomain指针并挂钩到一个简单调用原始地址的本机函数。 因为它只生成一个JMP [original_load],我希望它可以工作,但它会在NET调用中的某个地方崩溃。

我错过了什么,或者我做错了什么? 希望任何人都可以帮助我。

0 个答案:

没有答案