导入用于在 C# 中分配虚拟内存的 kernel32 函数?

Importing kernel32 functions for allocating virtual memory in C#?

我的硬盘上有几个 DLL 文件。我服务器上的一个进程包含重要的文件数据,我想通过在进程内分配虚拟内存来记录这些数据。我没有那个过程的源代码,所以我需要采取更多的极端措施。我想让它启动 DLL 主函数。外部内存的分配需要用C#写,因为我想用在WPF中

如何用C#在另一个进程中执行自己的源代码?

为了在进程中执行您自己的源代码,您需要为进程虚拟分配内存,并将您的 DLL 路径写入您分配的内存地址。您将使用该 DLL 路径通过 kernel32.dll LoadLibraryW 中的导出函数将您的 dll 弹射到进程中。


windows 平台上的每个进程都有专用于该进程的指定内存大小。原因之一是出于安全考虑,一个进程不能向其他进程读取或写入数据。所以为了能够 write/inject 你的 DLL 你需要打开一个 HANDLE。如果从 kernel32.dll 导入 OpenProcess 函数,则可以执行此操作。这简要意味着您正在使用 windows api。以下是如何在 C#

中导入 kernel32 DLL
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(
  uint dwDesiredAccess, 
  int  bInheritHandle, 
  uint dwProcessId
);

You can find the full documentation of the windows api in the holy bible

现在,您想使用 OpenProcess 函数为您从中获得句柄的进程分配内存。使用VirtualAllocEx函数,参考MSDN

How hath thou allocated thou memory?

LPVOID WINAPI VirtualAllocEx(
  _In_     HANDLE hProcess,
  _In_opt_ LPVOID lpAddress,
  _In_     SIZE_T dwSize,
  _In_     DWORD  flAllocationType,
  _In_     DWORD  flProtect
);

正如我们所见,它有 5 个参数。您之前收集的 HANDLE object。我们不会使用的可选参数。如果将 DLL 转换为字节数组,则可以获得 DLL 的大小。内存分配的类型,我们想要保留和提交分配,所以使用 (0x1000 | 0x2000) 并最后保护我们将写入的已分配内存 0x40.

步骤 1 分配内存 ✓
STEP 2 写入DLL路径
步骤 3 使用 LoadLibraryW

第二步涉及到使用WriteProcessMemory简单的将dll路径写入内存。将字符串转换为字节数组

byte[] bytes = Encoding.ASCII.GetBytes(DllPath);

像这样在您使用 windows api 函数 WriteProcessMemory 分配的内存中写入该字节数组。

WriteProcessMemory(processHandle, allocatedMemory, bytes, (uint)bytes.Length, 0)

步骤 1 分配内存 ✓
STEP 2 写入DLL路径✓
步骤 3 使用 LoadLibraryW

如果您不知道导出的函数是什么,那么解释起来会有点棘手,请尝试给您一个抽象的理解。

创建应用程序时,您需要导入 windows 提供的 DLL 才能使用某些功能。例如,您想要在您的应用程序中发送一个 HTTP 请求。即使你不知道你需要加载 windows ws2.dll (windows socket) 库。 windows OS 提供了一个方便的函数,可以从字面上加载一个名为 LoadLibraryW 的库。我在哪里可以找到这个奇妙的功能?好吧,不用担心 child,kernel32.dll 可以满足您的需求。您需要做的就是找到指向 LoadLibraryW 函数的指针。再次强调,相信 MSDN,它会给你回报。

FARPROC WINAPI GetProcAddress(
  _In_ HMODULE hModule,
  _In_ LPCSTR  lpProcName
);

HMODULE WINAPI GetModuleHandle(
  _In_opt_ LPCTSTR lpModuleName
);

您可以阅读文档了解更多信息。简单地说,这会在 kernel32.dll 中找到您的 LoadLibraryW 函数,因为它是一个导出函数。

IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");

步骤 1 分配内存 ✓
STEP 2 写入DLL路径✓
第 3 步使用 LoadLibraryW ✓

在您的进程中启动一个远程线程,它将简单地执行您的加载库代码

CreateRemoteThread(hndProc, (IntPtr)null, (IntPtr)null, lpLLAddress, lpAddress, 0, (IntPtr)null)

之后,只需关闭该进程的句柄,您的 dll 就会在该进程中“注入”。无论如何,如果您仍然没有弄清楚或者只是想要一个 class 来为您完成这里是一些源代码

DLLinjector

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace dllInjectExample
{
    public enum DllInjectionResult
    {
        DllNotFound,
        GameProcessNotFound,
        InjectionFailed,
        Success
    }

    public static class DllInjector
    {
        static readonly IntPtr INTPTR_ZERO = (IntPtr)0;

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

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

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

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

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

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

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

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

            uint _procId = 0;

            Process[] _procs = Process.GetProcesses();
            for (int i = 0; i < _procs.Length; i++)
            {
                if (_procs[i].ProcessName == sProcName)
                {
                    _procId = (uint)_procs[i].Id;
                    break;
                }
            }

            if (_procId == 0)
            {
                return DllInjectionResult.GameProcessNotFound;
            }

            if (!bInject(_procId, sDllPath))
            {
                return DllInjectionResult.InjectionFailed;
            }

            return DllInjectionResult.Success;
        }

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

            if (hndProc == INTPTR_ZERO)
            {
                return false;
            }

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

            if (lpAddress == INTPTR_ZERO)
            {
                return false;
            }

            byte[] bytes = Encoding.ASCII.GetBytes(sDllPath);

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

            IntPtr lpLLAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");

            if (lpLLAddress == INTPTR_ZERO)
            {
                return false;
            }

            if (CreateRemoteThread(hndProc, (IntPtr)null, INTPTR_ZERO, lpLLAddress, lpAddress, 0, (IntPtr)null) == INTPTR_ZERO)
            {
                return false;
            }

            CloseHandle(hndProc);

            return true;
        }
    }
}

注入到 csgo 的示例,因为我不知道为什么要注入 dll?

if (Process.GetProcessesByName("csgo").Count() == 0)
            {
                Process Proc = new Process();
                ProcessStartInfo startInfo = new ProcessStartInfo(@"D:\Application\Steam\Steam.exe");

                Proc.StartInfo = startInfo;
                Proc.StartInfo.Arguments = "-applaunch 730";
                Proc.StartInfo.UseShellExecute = false;
                Proc.StartInfo.CreateNoWindow = false;
                Proc.Start();
                Thread.Sleep(15000);
            }

            while (Process.GetProcessesByName("csgo").Count() == 0)
            {

            }

            var something = DllInjector.Inject("csgo", @"C:\Visual Studio 2015\Projects\XGame\Debug\XGamedll.dll");