加载/注入.net程序集到现有的.net进程中

本文关键字:net 进程 注入 程序集 加载 | 更新日期: 2023-09-27 18:02:11

在我的情况下,我想加载一个自定义。net程序集到一个正在运行的。net进程的域,例如Windows Explorer,我已经尝试过的只是将程序集注入explorer.exe,但这似乎没有明显的原因。

喷射器代码:

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;
    }
}

加载/注入.net程序集到现有的.net进程中

作为另一个选项,您可以使用现有的库- ManagedInjector - https://github.com/cplotts/snoopwpf/tree/master/ManagedInjector。有一个工具snoopwpf可以显示任何WPF进程的细节,它使用进程注入来实现这一点。我前一段时间用过它,它工作得很好。

你需要构建它,添加到你的项目中作为参考,并像这样调用:

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

Loader是将加载到进程中的类型的名称,Inject是将执行的静态方法。在我的例子中,我有:

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");
    }
}

ManagedInjector是用Managed c++代码写的。基本上它钩子自己的非托管的c++方法作为MessageHookProc,它将在注入后启动指定的程序集并运行指定的方法。它应该可以很好地工作于托管和非托管程序。在我的例子中,我用它来管理非托管程序。

我在本地测试了它,它成功地将我的消息框注入Windows 8.1 x64下的资源管理器进程。我编译了ManagedInjector64-4.0,我的示例控制台项目也有x64的平台选择。下面是我的工作代码:

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");
        });
    }
}