/// <summary> /// Injects a dll into a process by creating a remote thread on LoadLibrary. /// </summary> /// <param name="_hProcess">Handle to the process into which dll will be injected.</param> /// <param name="_szDllPath">Full path of the dll that will be injected.</param> /// <returns>Returns the base address of the injected dll on success, zero on failure.</returns> public static IntPtr InjectDllCreateThread(IntPtr _hProcess, string _szDllPath) { if (_hProcess == IntPtr.Zero) { throw new ArgumentNullException("_hProcess"); } if (_szDllPath.Length == 0) { throw new ArgumentNullException("_szDllPath"); } if (!_szDllPath.Contains("\\")) { _szDllPath = Path.GetFullPath(_szDllPath); } if (!File.Exists(_szDllPath)) { throw new ArgumentException("DLL not found.", "_szDllPath"); } var dwBaseAddress = IntPtr.Zero; IntPtr lpLoadLibrary; IntPtr lpDll; IntPtr hThread, threadId; var hKernel32 = OnyxNative.GetModuleHandle(_hProcess, "kernel32.dll"); lpLoadLibrary = (IntPtr)(hKernel32.ToInt64() + OnyxNative.GetExportedFunctionRVA(OnyxNative.GetModuleFileNameEx(_hProcess, hKernel32), "LoadLibraryW").ToInt64()); if (lpLoadLibrary != IntPtr.Zero) { lpDll = OnyxMemory.AllocateMemory(_hProcess); if (lpDll != IntPtr.Zero) { if (OnyxMemory.Write(_hProcess, lpDll, _szDllPath)) { //wait for thread handle to have signaled state hThread = OnyxNative.CreateRemoteThread( _hProcess, IntPtr.Zero, 0, lpLoadLibrary, lpDll, ThreadFlags.THREAD_EXECUTE_IMMEDIATELY, out threadId); //wait for thread handle to have signaled state //exit code will be equal to the base address of the dll if (OnyxNative.WaitForSingleObject(hThread, 5000) == WaitValues.WAIT_OBJECT_0) { OnyxNative.GetExitCodeThread(hThread, out dwBaseAddress); if (dwBaseAddress == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } OnyxNative.CloseHandle(hThread); } OnyxMemory.FreeMemory(_hProcess, lpDll); } } return(dwBaseAddress); }
//ExecuteInDefaultAppDomain(_processId, Path.GetDirectoryName(Application.ExecutablePath) + "\\" + DLLName, "Onyx.DomainManager.EntryPoint", "Main", ""); /// <summary> /// Loads CLR and target assembly into process address space /// </summary> /// <param name="_processId">Target process</param> /// <param name="_assemblyPath">Target assembly</param> /// <param name="_typeName">Type that contains method, that will be executed</param> /// <param name="_methodName">Method, that will be executed upon load</param> /// <param name="_args">Arguments, that will be passed to method</param> public static void InjectAndExecuteInDefaultAppDomain(Int32 _processId, String _assemblyPath, String _typeName, String _methodName, String _args) { if (_assemblyPath == null) { throw new ArgumentNullException(nameof(_assemblyPath)); } if (_typeName == null) { throw new ArgumentNullException(nameof(_typeName)); } if (_methodName == null) { throw new ArgumentNullException(nameof(_methodName)); } Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Injecting assembly '{0}'({1}.{2}, args '{3}') into process {4}...", _assemblyPath, _typeName, _methodName, _args ?? "null", _processId); var is64BitProcess = OnyxNative.Is64bitProcess(_processId); var clrDllPath = is64BitProcess ? MSCOREE_DLL_NAME_64 : MSCOREE_DLL_NAME_32; try { using (var onyx = new Onyx(_processId)) { // проверяем, не загружена ли уже CLR var hRemoteClr = OnyxNative.GetModuleHandle(onyx.Memory.OpenedProcess, MSCOREE_DLL_NAME); if (hRemoteClr != IntPtr.Zero) { Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] MSCOREE.dll({1}) is already exists in process {0}...", _processId, clrDllPath); } else { Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Loading MSCOREE.dll({1}) into process {0}...", _processId, clrDllPath); InjectDllCreateThread(onyx.Memory.OpenedProcess, clrDllPath); hRemoteClr = OnyxNative.GetModuleHandle(onyx.Memory.OpenedProcess, MSCOREE_DLL_NAME); if (hRemoteClr == IntPtr.Zero) { throw new ApplicationException(String.Format("Could not load dll '{0}' into process {1}", clrDllPath, _processId)); } } Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] MSCOREE.dll({1}) handle - 0x{0:X8}", hRemoteClr.ToInt64(), clrDllPath); var clrModuleName = OnyxNative.GetModuleFileNameEx(onyx.Memory.OpenedProcess, hRemoteClr); var bindToRuntimeFuncRva = OnyxNative.GetExportedFunctionRVA(clrModuleName, "CorBindToRuntimeEx"); var lpCorBindToRuntimeEx = (IntPtr)(hRemoteClr.ToInt64() + bindToRuntimeFuncRva.ToInt64()); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] CorBindToRuntimeEx ptr -> 0x{0:X8}", lpCorBindToRuntimeEx.ToInt64()); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Allocating code caves..."); var lpCLSID_CLRRuntimeHost = onyx.Memory.AllocateMemory((uint)(CLSID_CLRRuntimeHost.Length * 4)); var lpIID_ICLRRuntimeHost = onyx.Memory.AllocateMemory((uint)IID_ICLRRuntimeHost.Length); var lpClrHost = onyx.Memory.AllocateMemory(0x4); var lpdwRet = onyx.Memory.AllocateMemory(0x4); var lpCodeCave = onyx.Memory.AllocateMemory(0x256); var lpAssemblyPath = onyx.Memory.AllocateMemory((uint)_assemblyPath.Length + 1); var lpTypeName = onyx.Memory.AllocateMemory((uint)_typeName.Length + 1); var lpMethodName = onyx.Memory.AllocateMemory((uint)_methodName.Length + 1); var lpArgs = onyx.Memory.AllocateMemory((uint)_args.Length + 1); var lpBuildFlavor = onyx.Memory.AllocateMemory((uint)BuildFlavor.Length * 2 + 2); var lpFrameworkVersion = onyx.Memory.AllocateMemory((uint)FrameworkVersion.Length * 2 + 1); onyx.Memory.Write(lpBuildFlavor, BuildFlavor); onyx.Memory.Write(lpAssemblyPath, _assemblyPath); onyx.Memory.Write(lpTypeName, _typeName); onyx.Memory.Write(lpMethodName, _methodName); onyx.Memory.Write(lpArgs, _args); onyx.Memory.Write(lpCLSID_CLRRuntimeHost, CLSID_CLRRuntimeHost); onyx.Memory.Write(lpIID_ICLRRuntimeHost, IID_ICLRRuntimeHost); onyx.Memory.Write(lpFrameworkVersion, FrameworkVersion); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Preparing ASM code..."); var fasm = new RemoteFasm(); fasm.AddLine("use32"); fasm.AddLine("push {0}", lpClrHost.ToInt64()); fasm.AddLine("push {0}", lpIID_ICLRRuntimeHost.ToInt64()); fasm.AddLine("push {0}", lpCLSID_CLRRuntimeHost.ToInt64()); fasm.AddLine("push 0"); fasm.AddLine("push {0}", lpBuildFlavor.ToInt64()); fasm.AddLine("push {0}", lpFrameworkVersion.ToInt64()); fasm.AddLine("mov eax, {0}", lpCorBindToRuntimeEx.ToInt64()); fasm.AddLine("call eax"); // CorBindToRuntimeEx () fasm.AddLine("mov eax, [{0}]", lpClrHost.ToInt64()); fasm.AddLine("mov ecx, [eax]"); fasm.AddLine("mov edx, [ecx+0xC]"); fasm.AddLine("push eax"); fasm.AddLine("call edx"); // ClrHost () fasm.AddLine("push {0}", lpdwRet.ToInt64()); fasm.AddLine("push {0}", lpArgs.ToInt64()); fasm.AddLine("push {0}", lpMethodName.ToInt64()); fasm.AddLine("push {0}", lpTypeName.ToInt64()); fasm.AddLine("push {0}", lpAssemblyPath.ToInt64()); fasm.AddLine("mov eax, [{0}]", lpClrHost.ToInt64()); fasm.AddLine("mov ecx, [eax]"); fasm.AddLine("push eax"); fasm.AddLine("mov eax, [ecx+0x2C]"); fasm.AddLine("call eax"); fasm.AddLine("retn"); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Injecting and executing ASM code..."); fasm.InjectAndExecute(onyx.Memory.OpenedProcess, lpCodeCave); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Disposing code caves..."); onyx.Memory.FreeMemory(lpCLSID_CLRRuntimeHost); onyx.Memory.FreeMemory(lpIID_ICLRRuntimeHost); onyx.Memory.FreeMemory(lpClrHost); onyx.Memory.FreeMemory(lpdwRet); onyx.Memory.FreeMemory(lpCodeCave); onyx.Memory.FreeMemory(lpAssemblyPath); onyx.Memory.FreeMemory(lpTypeName); onyx.Memory.FreeMemory(lpMethodName); onyx.Memory.FreeMemory(lpArgs); onyx.Memory.FreeMemory(lpBuildFlavor); onyx.Memory.FreeMemory(lpFrameworkVersion); Logger.InfoFormat("[InjectAndExecuteInDefaultAppDomain] Assembly sussessfully injected"); } } catch (Exception ex) { throw new ApplicationException(String.Format("Could not inject assembly '{0}'({1}.{2}, args '{3}') into process {4}", _assemblyPath, _typeName, _methodName, _args ?? "null", _processId), ex); } }