#include "stdafx.h"
#include <tchar.h>
#include <CorHdr.h>
#include "corinfo.h"
#include "corjit.h"
#include "DisasMSIL.h"
HINSTANCE hInstance;
extern "C" __declspec(dllexport) void HookJIT();
VOID DisplayMethodAndCalls(ICorJitInfo *comp,
CORINFO_METHOD_INFO *info);
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD dwReason,
LPVOID lpReserved
)
{
hInstance = (HINSTANCE) hModule;
HookJIT();
return TRUE;
}
//
// Hook JIT's compileMethod
//
BOOL bHooked = FALSE;
ULONG_PTR *(__stdcall *p_getJit)();
typedef int (__stdcall *compileMethod_def)(ULONG_PTR classthis, ICorJitInfo *comp,
CORINFO_METHOD_INFO *info, unsigned flags,
BYTE **nativeEntry, ULONG *nativeSizeOfCode);
struct JIT
{
compileMethod_def compileMethod;
};
compileMethod_def compileMethod;
int __stdcall my_compileMethod(ULONG_PTR classthis, ICorJitInfo *comp,
CORINFO_METHOD_INFO *info, unsigned flags,
BYTE **nativeEntry, ULONG *nativeSizeOfCode);
extern "C" __declspec(dllexport) void HookJIT()
{
if (bHooked) return;
LoadLibrary(_T("mscoree.dll"));
HMODULE hJitMod = LoadLibrary(_T("mscorjit.dll"));
if (!hJitMod)
return;
p_getJit = (ULONG_PTR *(__stdcall *)()) GetProcAddress(hJitMod, "getJit");
if (p_getJit)
{
JIT *pJit = (JIT *) *((ULONG_PTR *) p_getJit());
if (pJit)
{
DWORD OldProtect;
VirtualProtect(pJit, sizeof (ULONG_PTR), PAGE_READWRITE, &OldProtect);
compileMethod = pJit->compileMethod;
pJit->compileMethod = &my_compileMethod;
VirtualProtect(pJit, sizeof (ULONG_PTR), OldProtect, &OldProtect);
bHooked = TRUE;
}
}
}
//
// hooked compileMethod
//
/*__declspec (naked) */
int __stdcall my_compileMethod(ULONG_PTR classthis, ICorJitInfo *comp,
CORINFO_METHOD_INFO *info, unsigned flags,
BYTE **nativeEntry, ULONG *nativeSizeOfCode)
{
// in case somebody hooks us (x86 only)
#ifdef _M_IX86
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
#endif
// call original method
// I'm not using the naked + jmp approach to avoid x64 incompatibilities
int nRet = compileMethod(classthis, comp, info, flags, nativeEntry, nativeSizeOfCode);
//
// Displays the current method and its calls
//
DisplayMethodAndCalls(comp, info);
return nRet;
}
VOID DisplayMethodAndCalls(ICorJitInfo *comp,
CORINFO_METHOD_INFO *info)
{
const char *szMethodName = NULL;
const char *szClassName = NULL;
szMethodName = comp->getMethodName(info->ftn, &szClassName);
char CurMethod[200];
sprintf_s(CurMethod, 200, "%s::%s", szClassName, szMethodName);
char Calls[0x1000];
strcpy_s(Calls, 0x1000, "Methods called:\r\n\r\n");
//
// retrieve calls
//
#define MAX_INSTR 100
ILOPCODE_STRUCT ilopar[MAX_INSTR];
DISASMSIL_OFFSET CodeBase = 0;
BYTE *pCur = info->ILCode;
UINT nSize = info->ILCodeSize;
UINT nDisasmedInstr;
while (DisasMSIL(pCur, nSize, CodeBase, ilopar, MAX_INSTR,
&nDisasmedInstr))
{
//
// check the instructions for calls
//
for (UINT x = 0; x < nDisasmedInstr; x++)
{
if (info->ILCode[ilopar[x].Offset] == ILOPCODE_CALL)
{
DWORD dwToken = *((DWORD *) &info->ILCode[ilopar[x].Offset + 1]);
CORINFO_METHOD_HANDLE hCallHandle =
comp->findMethod(info->scope, dwToken, info->ftn);
szMethodName = comp->getMethodName(hCallHandle, &szClassName);
strcat_s(Calls, 0x1000, szClassName);
strcat_s(Calls, 0x1000, "::");
strcat_s(Calls, 0x1000, szMethodName);
strcat_s(Calls, 0x1000, "\r\n");
}
}
//
// end loop?
//
if (nDisasmedInstr < MAX_INSTR) break;
//
// next instructions
//
DISASMSIL_OFFSET next = ilopar[nDisasmedInstr - 1].Offset - CodeBase;
next += ilopar[nDisasmedInstr - 1].Size;
pCur += next;
nSize -= next;
CodeBase += next;
}
//
// Show MessageBox
//
MessageBoxA(0, Calls, CurMethod, MB_ICONINFORMATION);
}