private static void InitializeManaged() { void * clrModuleHandle; StringBuilder stringBuilder; byte[] clrFile; if (_isManagedInitialized) { return; } switch (Environment.Version.Major) { case 2: _pIsDebuggerAttached = (byte *)typeof(Debugger).GetMethod("IsDebuggerAttached", BindingFlags.NonPublic | BindingFlags.Static).MethodHandle.GetFunctionPointer(); // 和.NET 4.x不一样,这个Debugger.IsAttached的get属性调用了IsDebuggerAttached(),而不是直通CLR内部。 clrModuleHandle = GetModuleHandle("mscorwks.dll"); break; case 4: _pIsDebuggerAttached = (byte *)typeof(Debugger).GetMethod("get_IsAttached").MethodHandle.GetFunctionPointer(); // Debugger.IsAttached的get属性是一个有[MethodImpl(MethodImplOptions.InternalCall)]特性的方法,意思是实现在CLR内部,而且没有任何stub,直接指向CLR内部。 // 通过x64dbg调试,可以知道Debugger.get_IsAttached()对应clr!DebugDebugger::IsDebuggerAttached()。 clrModuleHandle = GetModuleHandle("clr.dll"); break; default: throw new NotSupportedException(); } _isDebuggerAttached = (IsDebuggerAttachedDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)_pIsDebuggerAttached, typeof(IsDebuggerAttachedDelegate)); if (clrModuleHandle == null) { throw new InvalidOperationException(); } stringBuilder = new StringBuilder((int)MAX_PATH); if (!GetModuleFileName(clrModuleHandle, stringBuilder, MAX_PATH)) { throw new InvalidOperationException(); } clrFile = File.ReadAllBytes(stringBuilder.ToString()); // 读取CLR模块文件内容 fixed(byte *pPEImage = clrFile) { PEInfo peInfo; uint isDebuggerAttachedRva; uint isDebuggerAttachedFoa; byte * pCodeStart; byte * pCodeCurrent; ldasm_data ldasmData; bool is64Bit; byte[] opcodes; peInfo = new PEInfo(pPEImage); isDebuggerAttachedRva = (uint)(_pIsDebuggerAttached - (byte *)clrModuleHandle); isDebuggerAttachedFoa = peInfo.ToFOA(isDebuggerAttachedRva); pCodeStart = pPEImage + isDebuggerAttachedFoa; pCodeCurrent = pCodeStart; is64Bit = sizeof(void *) == 8; opcodes = new byte[0x200]; // 分配远大于实际函数大小的内存 while (true) { uint length; length = Ldasm.ldasm(pCodeCurrent, &ldasmData, is64Bit); if ((ldasmData.flags & Ldasm.F_INVALID) != 0) { throw new NotSupportedException(); } CopyOpcode(&ldasmData, pCodeCurrent, opcodes, (uint)(pCodeCurrent - pCodeStart)); if (*pCodeCurrent == 0xC3) { // 找到了第一个ret指令 pCodeCurrent += length; break; } pCodeCurrent += length; } // 复制Opcode直到出现第一个ret _isDebuggerAttachedLength = (uint)(pCodeCurrent - pCodeStart); fixed(byte *pOpcodes = opcodes) _isDebuggerAttachedCrc32 = DynamicCrc32.Compute(pOpcodes, _isDebuggerAttachedLength); } _isManagedInitialized = true; }