7

In my situation i want to load a custom .net assembly into a running .net process's domain, for example Windows Explorer, What i have tried already is just injecting the assembly to explorer.exe but that doesn't seem to work for no obvious reason.

Injector Code:

public class CodeInjector
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int CloseHandle(IntPtr hObject);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr GetModuleHandle(string lpModuleName);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress,
        IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);

    private static CodeInjector _instance;

    public static CodeInjector GetInstance
    {
        get { return _instance ?? (_instance = new CodeInjector()); }
    }

    public InjectionResult Inject(string sProcName, string sDllPath)
    {
        if (!File.Exists(sDllPath))
        {
            return InjectionResult.DllNotFound;
        }

        var procs = Process.GetProcesses();
        var procId = (from t in procs where t.ProcessName == sProcName select (uint)t.Id).FirstOrDefault();

        if (procId == 0)
        {
            return InjectionResult.ProcessNotFound;
        }

        if (!Inject(procId, sDllPath))
        {
            return InjectionResult.InjectionFailed;
        }

        return InjectionResult.InjectionSucceed;
    }

    private static bool Inject(uint pToBeInjected, string sDllPath)
    {
        var hndProc = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, pToBeInjected);

        if (hndProc == IntPtr.Zero)
        {
            return false;
        }

        var lpLlAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");

        if (lpLlAddress == IntPtr.Zero)
        {
            return false;
        }

        var lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (IntPtr)sDllPath.Length, (0x1000 | 0x2000), 0X40);

        if (lpAddress == IntPtr.Zero)
        {
            return false;
        }

        var bytes = Encoding.ASCII.GetBytes(sDllPath);

        if (WriteProcessMemory(hndProc, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
        {
            return false;
        }

        if (CreateRemoteThread(hndProc, (IntPtr)null, IntPtr.Zero, lpLlAddress, lpAddress, 0, (IntPtr)null) == IntPtr.Zero)
        {
            return false;
        }

        CloseHandle(hndProc);

        return true;
    }
}
Daniel Eugen
  • 2,712
  • 8
  • 33
  • 56
  • 1
    How do you verify that assembly didn't inject? Do you sent the same assembly in `sDllPath` variable? Does that assembly locate in the same folder as executable of injected process? btw, Explorer isn't .Net process, so it might not have running CLR inside. Other way in that case is to inject own C++ assembly and create new AppDomain and run assembly in injected process – Sergey Litvinov Jul 11 '15 at 20:40
  • @SergeyLitvinov Is there a good way to load my .net assembly into Explorer ?, i have tried every single way i can find without luck. And i use procexplorer to see if my assembly is loaded into target process. – Daniel Eugen Jul 11 '15 at 20:44

1 Answers1

8

As another option you can use existing library - ManagedInjector - https://github.com/cplotts/snoopwpf/tree/master/ManagedInjector . There is a tool snoopwpf that can show details of any WPF process, and it uses process injection for that. I used it some time ago and it worked well.

You need to build it, add to your project as reference and call like this:

Injector.Launch(someProcess.MainWindowHandle, 
                  typeof(Loader).Assembly.Location, 
                  typeof(Loader).FullName, 
                  "Inject");

Loader is name of type that will be loaded into process and Inject is a static method that will be executed. In my case i had:

public class Loader
{

    public static void Inject()
    {
          // i did CBT Hook on main window here 
          // and also displayed sample message box for debugging purposes
          MessageBox.Show("Hello from another process");
    }
}

That ManagedInjector is written in Managed C++ code. Basically it hooks own unmanaged C++ method as MessageHookProc and it will start specified assembly after injection and run specified method. It should work fine for both managed and unmanaged programs. In my case i used it for unmanaged program.

UPDATE

I tested it locally and it successfully injects my message box into explorer process under Windows 8.1 x64. I compiled ManagedInjector64-4.0 and my sample console project also has x64 in platform selection. Here is my working code:

class Program
{
    static void Main(string[] args)
    {
        var proc = Process.GetProcessesByName("explorer").FirstOrDefault();
        Injector.Launch(proc.MainWindowHandle, typeof(Loader).Assembly.Location, typeof(Loader).FullName, "Inject");
    }
}

public class Loader
{
    public static void Inject()
    {
        MessageBox.Show("Hello");
        Task.Run(() =>
        {
            Thread.Sleep(3000);
            MessageBox.Show("Hello again");
            Thread.Sleep(5000);
            MessageBox.Show("Hello again again");
        });
    }
}
Sergey Litvinov
  • 7,408
  • 5
  • 46
  • 67
  • It keeps throwing FileLoadException, even without calling the Inject Method.. any help because your solution seems interesting. – Daniel Eugen Jul 11 '15 at 21:52
  • I had an error in Injector usage. The second parameter should point to assembly location, so probably it just couldn't load it. I've updated answer and added working sample. – Sergey Litvinov Jul 11 '15 at 22:30
  • Sorry but i can't build the Injector project i keep getting `Error 5 error LNK2022: metadata operation failed (80131195) : Custom attributes are not consistent: (0x0c000089).` – Daniel Eugen Jul 11 '15 at 22:50
  • You can install Snoop WPF tool that uses it - https://snoopwpf.codeplex.com/ and then get this library from folder where you installed it. – Sergey Litvinov Jul 11 '15 at 22:53
  • Already tried that but i keep getting `An unhandled exception of type 'System.IO.FileLoadException' occurred in Unknown Module.` every time my c# application starts... it a .net 3.5 c# console app – Daniel Eugen Jul 11 '15 at 23:13
  • Additional information: Unverifiable code failed policy check. (Exception from HRESULT: 0x80131402) – Daniel Eugen Jul 11 '15 at 23:22
  • Is there any details for `FileLoadException`? it should say assembly\file name. `Unverifiable code failed policy check` do you run it As Administrator? it may require more permissions that typical process – Sergey Litvinov Jul 12 '15 at 16:11