【发布时间】:2018-10-20 03:29:29
【问题描述】:
我创建了一个库,可以使用多种方法将 DLL 文件注入进程。我正在使用 Windows 窗体使用 GUI 对其进行测试。
所有方法都按预期工作,但使用 QueueUserAPC 时除外。当我尝试使用此方法时,我将 DLL 注入的进程崩溃了。
我创建了一个基本的控制台应用程序来在 Windows 窗体之外测试此方法,它按预期工作而没有进程崩溃。此外,我的错误检查告诉我,当使用 Windows 窗体中的 QueueUserAPC 方法时,DLL 正在注入没有任何错误,但是,该进程仍然崩溃。
我感觉在使用 Windows 窗体时进程崩溃的原因与 QueueUserAPC 方法的代码以及更多关于 Windows 窗体的权限无关。但是,我可能是错的,所以我将包含以下方法的代码。
pinvoke
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessPrivileges dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, MemoryAllocation flAllocationType, MemoryProtection flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, IntPtr dwData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern void CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern void VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, MemoryAllocation dwFreeType);
public enum MemoryAllocation
{
Commit = 0x1000,
Reserve = 0x2000,
Release = 0x8000,
AllAccess = Commit | Reserve
}
public enum MemoryProtection
{
PageReadWrite = 0x04,
PageExecuteReadWrite = 0x40
}
public enum ThreadAccess
{
SuspendResume = 0x02,
GetContext = 0x08,
SetContext = 0x010,
AllAccess = SuspendResume | GetContext | SetContext
}
QueueUserAPC 方法
public static class MQueueUserAPC
{
public static bool Inject(string dllPath, string processName)
{
// Get the pointer to load library
var loadLibraryPointer = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (loadLibraryPointer == IntPtr.Zero)
{
return false;
}
// Get the handle of the specified process
var processId = Process.GetProcessesByName(processName)[0].Id;
var processHandle = OpenProcess(ProcessPrivileges.AllAccess, false, processId);
if (processHandle == IntPtr.Zero)
{
return false;
}
// Allocate memory for the dll name
var dllNameSize = dllPath.Length + 1;
var dllMemoryPointer = VirtualAllocEx(processHandle, IntPtr.Zero, (uint) dllNameSize, MemoryAllocation.AllAccess, MemoryProtection.PageReadWrite);
if (dllMemoryPointer == IntPtr.Zero)
{
return false;
}
// Write the dll name into memory
var dllBytes = Encoding.Default.GetBytes(dllPath);
if (!WriteProcessMemory(processHandle, dllMemoryPointer, dllBytes, (uint) dllNameSize, 0))
{
return false;
}
// Call QueueUserAPC on each thread
foreach (var thread in Process.GetProcessesByName(processName)[0].Threads.Cast<ProcessThread>())
{
var threadId = thread.Id;
// Get the threads handle
var threadHandle = OpenThread(ThreadAccess.SetContext, false, (uint) threadId);
// Add a user-mode APC to the APC queue of the thread
QueueUserAPC(loadLibraryPointer, threadHandle, dllMemoryPointer);
// Close the handle to the thread
CloseHandle(threadHandle);
}
// Close the previously opened handle
CloseHandle(processHandle);
// Free the previously allocated memory
VirtualFreeEx(processHandle, dllMemoryPointer, dllNameSize, MemoryAllocation.Release);
return true;
}
}
我如何在 Windows 窗体/控制台应用程序中使用它
var injector = new Injector();
if(Injector.QueueUserAPC(dllPath, processName))
{
MessageBox.Show("No error was raised");
}
我想我要问的是 Windows 窗体的权限是否比控制台应用程序少,如果是这样,我该如何配置我的 Windows 窗体,以便在尝试使用 QueueUserAPC 时不会遇到进程崩溃的问题。
如果您想测试这个库,我在 Github 上提供了如何使用它的说明。
【问题讨论】:
-
不应该有,除非您的防病毒软件在沙盒中运行您的应用程序。您可以通过使用提升的权限运行应用程序来测试权限问题。最简单的方法是在管理员权限下重新启动 Visual Studio,或者您可以编译然后右键单击 .exe 并“以管理员身份运行”。
-
在管理员下运行会产生同样的问题。我想权限不是这里的问题。您对为什么它可以在控制台应用程序而不是 Windows 窗体应用程序中工作有任何想法吗?
-
进入
QueueUserAPC调用,它在哪一行中断? -
它不会中断任何东西。返回 True 并显示 MessageBox,但是,2 - 3 秒后(正在注入的)进程崩溃。我将完全相同的代码复制到控制台应用程序和新的 Windows 窗体应用程序中,它在控制台应用程序中运行良好,但在 Windows 窗体应用程序中运行良好。
-
应用程序崩溃时报告的错误(在应用程序错误日志中)是什么?
标签: c# winforms winapi pinvoke