protected string CompareOneAndTwo() { int a = 1; int b = 2; if (a < b) { return "Number 1 is less than 2"; } else { return "Number 1 is greater than 2 (O_o)"; } }
// Type type=this.GetType(); MethodInfo methodInfo=type.GetMethod("CompareOneAndTwo", BindingFlags.NonPublic|BindingFlags.Instance); // , , // , , JIT // , JIT- :) RuntimeHelpers.PrepareMethod(methodInfo.MethodHandle); // IL- byte[] ilCodes=methodInfo.GetMethodBody().GetILAsByteArray(); // // for (int i=0; i<ilCodes.Length; i++) { if (ilCodes[i]==OpCodes.Bge_S.Value) { // Bge_S Blt_S ilCodes[i]=(byte)OpCodes.Blt_S.Value; } } // IL- InjectionHelper.UpdateILCodes(methodInfo, ilCodes);
public static class InjectionHelper { // Load the unmanaged injection.dll, the initlaization happens in a background thread // you can check if the initialization is completed by GetStatus() public static void Initialize() // Unload the unmanaged injection.dll public static void Uninitialize() // Update the IL Code of a Method. public static void UpdateILCodes(MethodInfo method, byte[] ilCodes) // The method returns until the initialization is completed public static Status WaitForIntializationCompletion() // Query the current status of the unmanaged dll, returns immediately. public static Status GetStatus() }
File name | Description |
Injection32.dll | Unmanaged dll performing our task (x86 version) |
Injection64.dll | Unmanaged dll performing our task (version x64) |
EasyHook32.dll | x86 EasyHook DLL (http://easyhook.codeplex.com/) (using Injection32.dll) |
EasyHook64.dll | X64 EasyHook DLL (http://easyhook.codeplex.com/) (used by Injection64.dll) |
x86 / * | Windows Debug Tool for x86 |
x64 / * | Windows Debug Tool for x64 |
PDB_symbols / * | PDB files. They can be removed, but this will slow initialization. |
CorJitResult compileMethod(ICorJitInfo * pJitInfo, CORINFO_METHOD_INFO * pMethodInfo, UINT nFlags, LPBYTE * pEntryAddress, ULONG * pSizeOfCode);
// ICorJitCompiler interface from JIT dll class ICorJitCompiler { public: typedef CorJitResult (__stdcall ICorJitCompiler::*PFN_compileMethod)(ICorJitInfo * pJitInfo, CORINFO_METHOD_INFO * pMethodInfo, UINT nFlags, LPBYTE * pEntryAddress, ULONG * pSizeOfCode); CorJitResult compileMethod(ICorJitInfo * pJitInfo, CORINFO_METHOD_INFO * pMethodInfo, UINT nFlags, LPBYTE * pEntryAddress, ULONG * pSizeOfCode) { return (this->*s_pfnComplieMethod)( pJitInfo, pMethodInfo, nFlags, pEntryAddress, pSizeOfCode); } private: static PFN_compileMethod s_pfnComplieMethod; }; // LPVOID pAddr = tPdbHelper.GetJitCompileMethodAddress(); LPVOID* pDest = (LPVOID*)&ICorJitCompiler::s_pfnComplieMethod; *pDest = pAddr; // compileMethod CorJitResult __stdcall CInjection::compileMethod(ICorJitInfo * pJitInfo , CORINFO_METHOD_INFO * pCorMethodInfo , UINT nFlags , LPBYTE * pEntryAddress , ULONG * pSizeOfCode ) { ICorJitCompiler * pCorJitCompiler = (ICorJitCompiler *)this; // TO DO: IL- CorJitResult result = pCorJitCompiler->compileMethod( pJitInfo, pCorMethodInfo, nFlags, pEntryAddress, pSizeOfCode); return result; } // JIT- NTSTATUS ntStatus = LhInstallHook( (PVOID&)ICorJitCompiler::s_pfnComplieMethod , &(PVOID&)CInjection::compileMethod , NULL , &s_hHookCompileMethod );
void MethodDesc::Reset() { CONTRACTL { THROWS; GC_NOTRIGGER; } CONTRACTL_END // , . // _ASSERTE(IsEnCMethod() || // IsDynamicMethod() || GetLoaderModule()->IsReflection()); // ClearFlagsOnUpdate(); if (HasPrecode()) { GetPrecode()->Reset(); } else { // Reflection- _ASSERTE(GetLoaderModule()->IsReflection()); InterlockedUpdateFlags2(enum_flag2_HasStableEntryPoint | enum_flag2_HasPrecode, FALSE); *GetAddrOfSlotUnchecked() = GetTemporaryEntryPoint(); } _ASSERTE(!HasNativeCode()); }
class MethodDesc { typedef void (MethodDesc::*PFN_Reset)(void); typedef BOOL (MethodDesc::*PFN_IsGenericMethodDefinition)(void); typedef ULONG (MethodDesc::*PFN_GetNumGenericMethodArgs)(void); typedef MethodDesc * (MethodDesc::*PFN_StripMethodInstantiation)(void); typedef BOOL (MethodDesc::*PFN_HasClassOrMethodInstantiation)(void); typedef BOOL (MethodDesc::*PFN_ContainsGenericVariables)(void); typedef MethodDesc * (MethodDesc::*PFN_GetWrappedMethodDesc)(void); typedef AppDomain * (MethodDesc::*PFN_GetDomain)(void); typedef Module * (MethodDesc::*PFN_GetLoaderModule)(void); public: void Reset(void) { (this->*s_pfnReset)(); } BOOL IsGenericMethodDefinition(void) { return (this->*s_pfnIsGenericMethodDefinition)(); } ULONG GetNumGenericMethodArgs(void) { return (this->*s_pfnGetNumGenericMethodArgs)(); } MethodDesc * StripMethodInstantiation(void) { return (this->*s_pfnStripMethodInstantiation)(); } BOOL HasClassOrMethodInstantiation(void) { return (this->*s_pfnHasClassOrMethodInstantiation)(); } BOOL ContainsGenericVariables(void) { return (this->*s_pfnContainsGenericVariables)(); } MethodDesc * GetWrappedMethodDesc(void) { return (this->*s_pfnGetWrappedMethodDesc)(); } AppDomain * GetDomain(void) { return (this->*s_pfnGetDomain)(); } Module * GetLoaderModule(void) { return (this->*s_pfnGetLoaderModule)(); } private: static PFN_Reset s_pfnReset; static PFN_IsGenericMethodDefinition s_pfnIsGenericMethodDefinition; static PFN_GetNumGenericMethodArgs s_pfnGetNumGenericMethodArgs; static PFN_StripMethodInstantiation s_pfnStripMethodInstantiation; static PFN_HasClassOrMethodInstantiation s_pfnHasClassOrMethodInstantiation; static PFN_ContainsGenericVariables s_pfnContainsGenericVariables; static PFN_GetWrappedMethodDesc s_pfnGetWrappedMethodDesc; static PFN_GetDomain s_pfnGetDomain; static PFN_GetLoaderModule s_pfnGetLoaderModule; };
MethodDesc * pMethodDesc = (MethodDesc*)pMethodHandle; pMethodDesc->Reset();
// structure to store the IL code for replacement typedef struct _ILCodeBuffer { LPBYTE pBuffer; DWORD dwSize; } ILCodeBuffer, *LPILCodeBuffer; // method to be called by managed code BOOL CInjection::StartUpdateILCodes( MethodTable * pMethodTable , CORINFO_METHOD_HANDLE pMethodHandle , mdMethodDef md , LPBYTE pBuffer , DWORD dwSize ) { MethodDesc * pMethodDesc = (MethodDesc*)pMethodHandle; // reset this MethodDesc pMethodDesc->Reset(); ILCodeBuffer tILCodeBuffer; tILCodeBuffer.pBuffer = pBuffer; tILCodeBuffer.dwSize = dwSize; tILCodeBuffer.bIsGeneric = FALSE; // save the IL code for the method s_mpILBuffers.insert( std::pair< CORINFO_METHOD_HANDLE, ILCodeBuffer>( pMethodHandle, tILCodeBuffer) ); return TRUE; }
CorJitResult __stdcall CInjection::compileMethod(ICorJitInfo * pJitInfo , CORINFO_METHOD_INFO * pCorMethodInfo , UINT nFlags , LPBYTE * pEntryAddress , ULONG * pSizeOfCode ) { ICorJitCompiler * pCorJitCompiler = (ICorJitCompiler *)this; LPBYTE pOriginalILCode = pCorMethodInfo->ILCode; unsigned int nOriginalSize = pCorMethodInfo->ILCodeSize; ILCodeBuffer tILCodeBuffer = {0}; MethodDesc * pMethodDesc = (MethodDesc*)pCorMethodInfo->ftn; // find the method to be replaced std::map< CORINFO_METHOD_HANDLE, ILCodeBuffer>::iterator iter = s_mpILBuffers.find((CORINFO_METHOD_HANDLE)pMethodDesc); if( iter != s_mpILBuffers.end() ) { tILCodeBuffer = iter->second; pCorMethodInfo->ILCode = tILCodeBuffer.pBuffer; pCorMethodInfo->ILCodeSize = tILCodeBuffer.dwSize; } CorJitResult result = pCorJitCompiler->compileMethod( pJitInfo, pCorMethodInfo, nFlags, pEntryAddress, pSizeOfCode); return result; }
string GenericMethodToBeReplaced<T, K>(T t, K k)
LoadedMethodDescIterator MDIter(ADIter.GetDomain(), pModule, methodId); while(MDIter.Next()) { MethodDesc * pMD = MDIter.Current(); if (pMD) { _ASSERTE(pMD->IsIL()); pMD->SetRVA(rva); } }
class LoadedMethodDescIterator { private: BYTE dummy[10240]; };
// .Net 2.0 & 4.0 LoadedMethodDescIterator(AppDomain * pAppDomain, Module *pModule, mdMethodDef md) BOOL LoadedMethodDescIterator::Next(void) // .Net 4.5 LoadedMethodDescIterator(AppDomain * pAppDomain, Module *pModule, mdMethodDef md,enum AssemblyIterationMode mode) BOOL LoadedMethodDescIterator::Next(CollectibleAssemblyHolder<DomainAssembly *> *)
// detect the version of CLR BOOL DetermineDotNetVersion(void) { WCHAR wszPath[MAX_PATH] = {0}; ::GetModuleFileNameW( g_hClrModule, wszPath, MAX_PATH); CStringW strPath(wszPath); int nIndex = strPath.ReverseFind('\\'); if( nIndex <= 0 ) return FALSE; nIndex++; CStringW strFilename = strPath.Mid( nIndex, strPath.GetLength() - nIndex); if( strFilename.CompareNoCase(L"mscorwks.dll") == 0 ) { g_tDotNetVersion = DotNetVersion_20; return TRUE; } if( strFilename.CompareNoCase(L"clr.dll") == 0 ) { DWORD dwHandle = NULL; UINT nSize = 0; LPBYTE lpBuffer = NULL; BYTE szTempBuf[2048] = {0}; DWORD dwSize = GetFileVersionInfoSizeW( wszPath, &dwHandle); if (dwSize != NULL) { LPVOID pData = szTempBuf; if (GetFileVersionInfo( wszPath, dwHandle, dwSize, pData)) { if (VerQueryValueW( pData, L"\\",(VOID FAR* FAR*)&lpBuffer,&nSize)) { if (nSize) { VS_FIXEDFILEINFO * pVerInfo = (VS_FIXEDFILEINFO *)lpBuffer; if (pVerInfo->dwSignature == 0xfeef04bd) { int nMajor = HIWORD(pVerInfo->dwFileVersionMS); int nMinor = LOWORD(pVerInfo->dwFileVersionMS); int nBuildMajor = HIWORD(pVerInfo->dwFileVersionLS); int nBuildMinor = LOWORD(pVerInfo->dwFileVersionLS); if( nMajor == 4 && nMinor == 0 && nBuildMajor == 30319 ) { if( nBuildMinor < 10000 ) g_tDotNetVersion = DotNetVersion_40; else g_tDotNetVersion = DotNetVersion_45; return TRUE; } } } } } return FALSE; } } return FALSE; }
enum AssemblyIterationMode { AssemblyIterationMode_Default = 0 }; class LoadedMethodDescIterator { typedef void (LoadedMethodDescIterator::*PFN_LoadedMethodDescIteratorConstructor)(AppDomain * pAppDomain, Module *pModule, mdMethodDef md); typedef void (LoadedMethodDescIterator::*PFN_LoadedMethodDescIteratorConstructor_v45)(AppDomain * pAppDomain, Module *pModule, mdMethodDef md, AssemblyIterationMode mode); typedef void (LoadedMethodDescIterator::*PFN_Start)(AppDomain * pAppDomain, Module *pModule, mdMethodDef md); typedef BOOL (LoadedMethodDescIterator::*PFN_Next_v4)(LPVOID pParam); typedef BOOL (LoadedMethodDescIterator::*PFN_Next_v2)(void); typedef MethodDesc* (LoadedMethodDescIterator::*PFN_Current)(void); public: LoadedMethodDescIterator(AppDomain * pAppDomain, Module *pModule, mdMethodDef md) { memset( dummy, 0, sizeof(dummy)); memset( dummy2, 0, sizeof(dummy2)); if( s_pfnConstructor ) (this->*s_pfnConstructor)( pAppDomain, pModule, md); if( s_pfnConstructor_v45 ) (this->*s_pfnConstructor_v45)( pAppDomain, pModule, md, AssemblyIterationMode_Default); } void Start(AppDomain * pAppDomain, Module *pModule, mdMethodDef md) { (this->*s_pfnStart)( pAppDomain, pModule, md); } BOOL Next() { if( s_pfnNext_v4 ) return (this->*s_pfnNext_v4)(dummy2); if( s_pfnNext_v2 ) return (this->*s_pfnNext_v2)(); return FALSE; } MethodDesc* Current() { return (this->*s_pfnCurrent)(); } private: // we don't know the exact size of LoadedMethodDescIterator, so add enough memory here BYTE dummy[10240]; // class CollectibleAssemblyHolder<class DomainAssembly *> parameter for Next() in .Net4.0 and above BYTE dummy2[10240]; // constructor for .Net2.0 & .Net 4.0 static PFN_LoadedMethodDescIteratorConstructor s_pfnConstructor; // constructor for .Net4.5 static PFN_LoadedMethodDescIteratorConstructor_v45 s_pfnConstructor_v45; static PFN_Start s_pfnStart; static PFN_Next_v4 s_pfnNext_v4; static PFN_Next_v2 s_pfnNext_v2; static PFN_Current s_pfnCurrent; public: static void MatchAddress(PSYMBOL_INFOW pSymbolInfo) { LPVOID* pDest = NULL; if( wcscmp( L"LoadedMethodDescIterator::LoadedMethodDescIterator", pSymbolInfo->Name) == 0 ) { switch(g_tDotNetVersion) { case DotNetVersion_20: case DotNetVersion_40: pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnConstructor); break; case DotNetVersion_45: pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnConstructor_v45); break; default: ATLASSERT(FALSE); return; } } else if( wcscmp( L"LoadedMethodDescIterator::Next", pSymbolInfo->Name) == 0 ) { switch(g_tDotNetVersion) { case DotNetVersion_20: pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnNext_v2); break; case DotNetVersion_40: case DotNetVersion_45: pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnNext_v4); break; default: ATLASSERT(FALSE); return; } } else if( wcscmp( L"LoadedMethodDescIterator::Start", pSymbolInfo->Name) == 0 ) pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnStart); else if( wcscmp( L"LoadedMethodDescIterator::Current", pSymbolInfo->Name) == 0 ) pDest = (LPVOID*)&(LoadedMethodDescIterator::s_pfnCurrent); if( pDest ) *pDest = (LPVOID)pSymbolInfo->Address; } };
Module * pModule = pMethodDesc->GetLoaderModule(); AppDomain * pAppDomain = pMethodDesc->GetDomain(); if( pModule ) { LoadedMethodDescIterator * pLoadedMethodDescIter = new LoadedMethodDescIterator( pAppDomain, pModule, md); while(pLoadedMethodDescIter->Next()) { MethodDesc * pMD = pLoadedMethodDescIter->Current(); if( pMD ) pMD->Reset(); } delete pLoadedMethodDescIter; }
Source: https://habr.com/ru/post/154419/
All Articles