/// <summary> /// Injects a dll into a process by hijacking the given thread and redirecting it to LoadLibrary. /// </summary> /// <param name="hProcess">Handle to process into which dll will be injected.</param> /// <param name="hThread">Handle to thread that will be hijacked.</param> /// <param name="szDllPath">Full path to the dll to be injected.</param> /// <returns>Returns the base address of the injected dll on success, zero on failure.</returns> public static uint InjectDllRedirectThread(IntPtr hProcess, IntPtr hThread, string szDllPath) { const uint INITIAL_EXIT_CODE = 0xFFFFFFFF; if (hProcess == IntPtr.Zero) { throw new ArgumentNullException("hProcess"); } if (hThread == IntPtr.Zero) { throw new ArgumentNullException("hThread"); } if (szDllPath.Length == 0) { throw new ArgumentNullException("szDllPath"); } if (!szDllPath.Contains("\\")) { szDllPath = System.IO.Path.GetFullPath(szDllPath); } if (!System.IO.File.Exists(szDllPath)) { throw new ArgumentException("DLL not found.", "szDllPath"); } uint dwBaseAddress = RETURN_ERROR; uint lpLoadLibrary, lpAsmStub; CONTEXT ctx; StringBuilder AssemblyStub = new StringBuilder(); ManagedFasm fasm = new ManagedFasm(hProcess); lpLoadLibrary = (uint)Imports.GetProcAddress(Imports.GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (lpLoadLibrary == 0) { return(RETURN_ERROR); } lpAsmStub = SMemory.AllocateMemory(hProcess); if (lpAsmStub == 0) { return(RETURN_ERROR); } if (SThread.SuspendThread(hThread) != uint.MaxValue) { ctx = SThread.GetThreadContext(hThread, CONTEXT_FLAGS.CONTEXT_CONTROL); if (ctx.Eip > 0) { try { //located at lpAsmStub+0, where we can monitor LoadLibrary's exit code. fasm.AddLine("lpExitCode dd 0x{0:X}", INITIAL_EXIT_CODE); //lpAsmStub+4, where the actual code part starts fasm.AddLine("push 0x{0:X}", ctx.Eip); fasm.AddLine("pushad"); fasm.AddLine("push szDllPath"); fasm.AddLine("call 0x{0:X}", lpLoadLibrary); fasm.AddLine("mov [lpExitCode], eax"); fasm.AddLine("popad"); fasm.AddLine("retn"); //dll path fasm.AddLine("szDllPath db \'{0}\',0", szDllPath); fasm.Inject(lpAsmStub); } catch { SMemory.FreeMemory(hProcess, lpAsmStub); SThread.ResumeThread(hThread); return(RETURN_ERROR); } ctx.ContextFlags = CONTEXT_FLAGS.CONTEXT_CONTROL; ctx.Eip = lpAsmStub + 4; //skip over lpExitCode data if (SThread.SetThreadContext(hThread, ctx)) { if (SThread.ResumeThread(hThread) != uint.MaxValue) { for (int i = 0; i < 400; i++) { System.Threading.Thread.Sleep(5); if ((dwBaseAddress = SMemory.ReadUInt(hProcess, lpAsmStub)) != INITIAL_EXIT_CODE) { break; } } } } } } if (fasm != null) { fasm.Dispose(); fasm = null; } SMemory.FreeMemory(hProcess, lpAsmStub); return(dwBaseAddress); }
/// <summary> /// Suspends execution of a thread. /// </summary> /// <param name="hThread">Handle to the thread to be suspended.</param> /// <returns>Returns true on success, false on failure.</returns> public bool SuspendThread(IntPtr hThread) { return((SThread.SuspendThread(hThread) == uint.MaxValue) ? false : true); }