public void Inject(InjectableProcess process, string dllPath, string typeName, string methodName) { bool x86 = !process.Is64Bit; var clrVersion = GetClrVersion(); var bindToRuntimeAddr = GetCorBindToRuntimeExAddress(process.Pid, process.FullHandle, x86); var callStub = CreateCallStub(process.FullHandle, dllPath, typeName, methodName, null, bindToRuntimeAddr, x86, clrVersion); var hThread = CodeInjectionUtils.RunRemoteCode(process.FullHandle, callStub, x86); Console.WriteLine("Thread handle: " + hThread.ToInt32().ToString("X8")); }
private static IntPtr GetCorBindToRuntimeExAddress(uint pid, IntPtr hProc, bool x86) { var mods = NativeHelper.GetModules(pid); var mod = mods.SingleOrDefault(x => x.moduleName.Equals("mscoree.dll", StringComparison.InvariantCultureIgnoreCase)); if (mod == default) { throw new Exception("Couldn't find MSCOREE.DLL, arch mismatch?"); } int fnAddr = CodeInjectionUtils.GetExportAddress(hProc, mod.baseAddress, "CorBindToRuntimeEx", x86); return(mod.baseAddress + fnAddr); }
private static IReadOnlyList <Instruction> CreateCallStub(IntPtr hProc, string asmPath, string typeFullName, string methodName, string?args, IntPtr fnAddr, bool x86, string clrVersion) { const string buildFlavor = "wks"; // WorkStation var ppv = alloc(IntPtr.Size); var riid = allocBytes(iidIclrRuntimeHost.ToByteArray()); var rcslid = allocBytes(clsidClrRuntimeHost.ToByteArray()); var pwszBuildFlavor = allocString(buildFlavor); var pwszVersion = allocString(clrVersion); var pReturnValue = alloc(4); var pwzArgument = allocString(args); var pwzMethodName = allocString(methodName); var pwzTypeName = allocString(typeFullName); var pwzAssemblyPath = allocString(asmPath); var c = new Assembler(x86 ? 32 : 64); void AddCallReg(Register r, params object[] callArgs) => CodeInjectionUtils.AddCallStub(c, r, callArgs, x86); void AddCallPtr(IntPtr fn, params object[] callArgs) => CodeInjectionUtils.AddCallStub(c, fn, callArgs, x86); if (x86) { // call CorBindToRuntimeEx AddCallPtr(fnAddr, pwszVersion, pwszBuildFlavor, (byte)0, rcslid, riid, ppv); // call ICLRRuntimeHost::Start c.mov(edx, __[ppv.ToInt32()]); c.mov(eax, __[edx]); c.mov(eax, __[eax + 0x0C]); AddCallReg(eax, edx); // call ICLRRuntimeHost::ExecuteInDefaultAppDomain c.mov(edx, __[ppv.ToInt32()]); c.mov(eax, __[edx]); c.mov(eax, __[eax + 0x2C]); AddCallReg(eax, edx, pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument, pReturnValue); c.ret(); } else { const int maxStackIndex = 3; const int stackOffset = 0x20; c.sub(rsp, stackOffset + maxStackIndex * 8); // call CorBindToRuntimeEx AddCallPtr(fnAddr, pwszVersion, pwszBuildFlavor, 0, rcslid, riid, ppv); // call pClrHost->Start(); c.mov(rcx, ppv.ToInt64()); c.mov(rcx, __[rcx]); c.mov(rax, __[rcx]); c.mov(rdx, __[rax + 0x18]); AddCallReg(rdx, rcx); // call pClrHost->ExecuteInDefaultAppDomain() c.mov(rcx, ppv.ToInt64()); c.mov(rcx, __[rcx]); c.mov(rax, __[rcx]); c.mov(rax, __[rax + 0x58]); AddCallReg(rax, rcx, pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument, pReturnValue); c.add(rsp, stackOffset + maxStackIndex * 8); c.ret(); } return(c.Instructions); IntPtr alloc(int size, int protection = 0x04) => Native.VirtualAllocEx(hProc, IntPtr.Zero, (uint)size, 0x1000, protection); void writeBytes(IntPtr address, byte[] b) => Native.WriteProcessMemory(hProc, address, b, (uint)b.Length, out _); void writeString(IntPtr address, string str) => writeBytes(address, new UnicodeEncoding().GetBytes(str)); IntPtr allocString(string?str) { if (str is null) { return(IntPtr.Zero); } IntPtr pString = alloc(str.Length * 2 + 2); writeString(pString, str); return(pString); } IntPtr allocBytes(byte[] buffer) { IntPtr pBuffer = alloc(buffer.Length); writeBytes(pBuffer, buffer); return(pBuffer); } }