Я создал библиотеку для внедрения файлов DLL в процессы, используя различные методы.Я тестирую это с графическим интерфейсом, используя Windows Forms.
Все методы работают должным образом, кроме случаев использования QueueUserAPC.Когда я пытаюсь использовать этот метод, процесс, в который я внедряю DLL-библиотеку, дает сбой.
Я создал базовое консольное приложение для тестирования этого метода вне формы Windows, и оно работало, как предполагалось, без сбоя процесса.Кроме того, моя проверка ошибок говорит мне, что DLL вводится без каких-либо ошибок при использовании метода QueueUserAPC из формы Windows, однако процесс все равно падает.
У меня такое ощущение, что причина сбоя процесса прииспользование формы 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 Method
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 Form / Console
var injector = new Injector();
if(Injector.QueueUserAPC(dllPath, processName))
{
MessageBox.Show("No error was raised");
}
Я предполагаю, что у Windows Forms меньше разрешений, чем у консольных приложений иесли это так, как я могу настроить свою форму Windows, чтобы я не столкнулся с проблемой сбоя процесса при попытке использовать QueueUserAPC.
Если вы хотите проверить библиотеку, она у меня установлена на Github с инструкциями по его использованию.