【问题标题】:DLL injection CreateRemoteThread not working on some clients (.NET)DLL 注入 CreateRemoteThread 在某些客户端 (.NET) 上不起作用
【发布时间】:2016-04-20 17:20:16
【问题描述】:

我在 .NET 中创建了一个启动器,它启动单人游戏并将 DLL 注入其中。 它可以在我自己的机器和其他几台机器上运行,但在某些人的计算机上它似乎神秘地失败了。我不知道可能是什么原因,也不能直接调试它,因为它对我有用。也许你们中的一些人遇到了同样的问题,或者知道可能出了什么问题。

这是启动器的注入代码(.NET Framework 4.5.2,目标平台:Any CPU [首选32bit]):

    static void StartProcess()
    {
        ProcessStartInfo psi = new ProcessStartInfo();
        psi.UseShellExecute = false;
        psi.WorkingDirectory = Path.GetFullPath("..");
        psi.EnvironmentVariables.Add("GUCProject", projectName);
        psi.FileName = Path.GetFullPath("..\\Gothic2.exe");
        Process process = Process.Start(psi);

        string dllPath = Path.GetFullPath("UntoldChapters\\" + projectName + "\\NetInject.dll");

        //dll injection
        if (LoadLibary(process, dllPath) == IntPtr.Zero)
        {
            throw new Exception(Marshal.GetLastWin32Error().ToString());
        }
    }

    [Flags]
    public enum AllocationType
    {
        Commit = 0x1000,
        Reserve = 0x2000,
        Decommit = 0x4000,
        Release = 0x8000,
        Reset = 0x80000,
        Physical = 0x400000,
        TopDown = 0x100000,
        WriteWatch = 0x200000,
        LargePages = 0x20000000
    }

    [Flags]
    public enum MemoryProtection : uint
    {
        Execute = 0x10,
        ExecuteRead = 0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        NoAccess = 0x01,
        ReadOnly = 0x02,
        ReadWrite = 0x04,
        WriteCopy = 0x08,
        GuardModifierflag = 0x100,
        NoCacheModifierflag = 0x200,
        WriteCombineModifierflag = 0x400
    }

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

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, UInt32 nSize, out UInt32 lpNumberOfBytesWritten);

    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

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

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

    public static IntPtr LoadLibary(Process process, String dll)
    {
        if (process == null || String.IsNullOrWhiteSpace(dll))
            return IntPtr.Zero;

        byte[] dllb = Encoding.ASCII.GetBytes(dll);
        if (dllb == null || dllb.Length == 0)
            return IntPtr.Zero;

        //Alloc
        uint len = (uint)dllb.Length + 1;
        IntPtr dllbPtr = VirtualAllocEx(process.Handle, IntPtr.Zero, len, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ReadWrite);
        if (dllbPtr == IntPtr.Zero)
        {
            throw new Exception(Marshal.GetLastWin32Error().ToString());
        }

        //Write dll name
        uint tmp = 0;
        bool b = WriteProcessMemory(process.Handle, dllbPtr, dllb, (uint)dllb.Length, out tmp);
        if (!b)
        {
            throw new Exception(Marshal.GetLastWin32Error().ToString());
        }

        IntPtr moduleHandle = GetModuleHandle("kernel32.dll");
        if (moduleHandle == IntPtr.Zero)
        {
            throw new Exception(Marshal.GetLastWin32Error().ToString());
        }

        IntPtr loadlib = GetProcAddress(moduleHandle, "LoadLibraryA");
        if (loadlib == IntPtr.Zero)
        {
            throw new Exception(Marshal.GetLastWin32Error().ToString());
        }

        return CreateRemoteThread(process.Handle, IntPtr.Zero, 0, loadlib, dllbPtr, 0, out tmp);
    }

没有显示错误消息/向无法正常工作的人抛出异常,所有指针、句柄和路径看起来都很好,但注入的“NetInject.dll”的 DLLMain 没有被调用。

(目标平台 Windows 8.1,工具集 VS2015 (v140),多字节字符集,不支持 CLR)

int WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
    // this is just the testing code for the people for which it doesn't work. It doesn't even get till here.
    MessageBoxW(NULL, L"Injected!", L"Error!", MB_ICONWARNING | MB_OK | MB_DEFBUTTON2);
    return true;
}
  • Launcher 始终以管理权限启动。
  • 操作系统似乎不是问题,因为它在某些情况下可以正常工作并出现故障 具有相同操作系统的人。 (工作在Win8.1 64Bit,Win7 Professional 64 位、Win7 企业版 64 位、Win7 家庭高级版 64 位) (不适用于 Win7 Professional 64Bit、Win 10 64Bit)
  • 关闭防病毒软件对他们也不起作用(无论如何,我与有问题的测试人员之一拥有相同的防病毒软件)。
  • 在发布模式下编译。

提前谢谢你。

【问题讨论】:

  • 这只是一个猜测,但请尝试在 Process.Start 之后执行 WaitForInputIdle()。
  • 试过了,没有任何改变。不过谢谢。

标签: c# .net dll code-injection


【解决方案1】:

Dynamic-Link Library Best Practices (Windows)。在“一般最佳实践”中,它说“你永远不应该”......来自 DllMain 的“调用 User32.dll 或 Gdi32.dll 中的函数”。 MessageBox 在 User32.dll 中。即使您使用 MessageBox 作为测试,您也需要确保遵守一般最佳实践。

是的,我知道一般最佳实践非常有限。当我第一次发现它时,我对此感到惊讶。

【讨论】:

  • 我不知道,谢谢。但这并不能解决问题。 :p
  • 尝试使用 ofstream 而不是 MessageBox,但没有成功。 :(
  • 我们不能确定 ofstream 在 DllMain 中是否有效。从Download the Windows Driver Kit (WDK) and WinDbg – Windows 10 Hardware Dev Center 获取 WinDbg。您可以使用OutputDebugStgring,WinDbg 会收到消息。
  • 我非常感谢您提供帮助的奉献精神,并将查看 WDK。然而,我可能已经找到了错误的根源,这不是(直接)在发布的代码中,而只是一些丢失/错误的可再发行库。显然,“msvcp140.dll”和“vcruntime140.dll”都需要作为它们的 32 位版本提供,而其中一位测试人员并非如此(启动的进程是 32 位应用程序)。 (我会等待另一位测试人员的反馈,如果成功,我会发布“官方”答案。)
  • OutputDebugString 可以与 any Windows 调试器一起使用。 Visual Studio 将在其 Output 窗格中显示该字符串。无需下载安装WinDbg。
猜你喜欢
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-19
  • 2018-10-26
  • 2011-09-28
  • 1970-01-01
相关资源
最近更新 更多