windows 表单的权限是否少于控制台应用程序?
Do windows forms have fewer permissions than console applications?
我创建了一个库,可以使用多种方法将 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 上有它以及如何使用它的说明。
进程正在崩溃,因为您为内存调用了 VirtualFreeEx
,您在内存中存储了 dll 的名称 (dllMemoryPointer
)。当 LoadLibrary
开始使用此内存时,它可能已经无效。 APC - 这是 异步 过程调用,所以你无法知道,在你调用 VirtualFreeEx
的地方,是 LoadLibrary
已经执行或正在执行,甚至还没有开始。
关于权限 - 当然没有。如果您没有权限 - 您只会使打开的进程或进程中的线程失败。结果什么都不会发生。你在目标进程中崩溃,反之亦然确认你有权限。
还需要了解,在您向其注入 APC 后,并非进程中的所有线程都处于可警报状态。所以有可能,尽管 APC 将成功排队 - 它永远不会被调用。将它注入进程中的所有线程,希望其中至少有一个以错误的方式处于可警报状态。起初可能不是,其次 - 一些工作线程可能根本不是为调用 LoadLibrary
设计的 - 比如说线程可以没有激活上下文,不连接到 csrss,可能是其他原因。所有这些也会产生崩溃或未定义的效果。最后,这根本没有效率。
通过 QueueUserAPC
的注入在您创建进程本身(处于挂起状态)并在恢复之前将 apc 注入初始进程线程时很有用。这将是可行的(直到),因为进程中的新线程总是从 LdrInitializeThunk
(他初始化进程 and/or 调用加载 dll 代码)开始在用户模式下执行,并且总是在跳转到真正的入口点之前(在所有现有 windows 版本中)调用 ZwTestAlert
。正是在这一点上,您的 APC 调用将被执行。但严格来说这也不是 100% 正确的方法,因为我们使用 LoadLibrary[W/A]
作为 APC 入口点。但是如果 APC 执行得太早,当 kernel32.dll
尚未映射到进程或尚未初始化时会怎样?显然是那场车祸。显然 windows 绝不能是这种情况(apc 将在进程完全初始化后调用,加载所有静态 dll,就在调用 exe 入口点之前)。但可能某些驱动程序会通过 APC 调用注入自身代码以进行处理(比如映射 kernel32.dll 事件)并强制 APC此时执行。结果只有 100% 可靠的方法在这里使用 ZwQueueApcThread
到 shellcode,它将只调用 ntdll api,通过 LdrLoadDll
加载 dll 并且 dll 本身仅从 静态导入ntdll.dll
我创建了一个库,可以使用多种方法将 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 上有它以及如何使用它的说明。
进程正在崩溃,因为您为内存调用了 VirtualFreeEx
,您在内存中存储了 dll 的名称 (dllMemoryPointer
)。当 LoadLibrary
开始使用此内存时,它可能已经无效。 APC - 这是 异步 过程调用,所以你无法知道,在你调用 VirtualFreeEx
的地方,是 LoadLibrary
已经执行或正在执行,甚至还没有开始。
关于权限 - 当然没有。如果您没有权限 - 您只会使打开的进程或进程中的线程失败。结果什么都不会发生。你在目标进程中崩溃,反之亦然确认你有权限。
还需要了解,在您向其注入 APC 后,并非进程中的所有线程都处于可警报状态。所以有可能,尽管 APC 将成功排队 - 它永远不会被调用。将它注入进程中的所有线程,希望其中至少有一个以错误的方式处于可警报状态。起初可能不是,其次 - 一些工作线程可能根本不是为调用 LoadLibrary
设计的 - 比如说线程可以没有激活上下文,不连接到 csrss,可能是其他原因。所有这些也会产生崩溃或未定义的效果。最后,这根本没有效率。
通过 QueueUserAPC
的注入在您创建进程本身(处于挂起状态)并在恢复之前将 apc 注入初始进程线程时很有用。这将是可行的(直到),因为进程中的新线程总是从 LdrInitializeThunk
(他初始化进程 and/or 调用加载 dll 代码)开始在用户模式下执行,并且总是在跳转到真正的入口点之前(在所有现有 windows 版本中)调用 ZwTestAlert
。正是在这一点上,您的 APC 调用将被执行。但严格来说这也不是 100% 正确的方法,因为我们使用 LoadLibrary[W/A]
作为 APC 入口点。但是如果 APC 执行得太早,当 kernel32.dll
尚未映射到进程或尚未初始化时会怎样?显然是那场车祸。显然 windows 绝不能是这种情况(apc 将在进程完全初始化后调用,加载所有静态 dll,就在调用 exe 入口点之前)。但可能某些驱动程序会通过 APC 调用注入自身代码以进行处理(比如映射 kernel32.dll 事件)并强制 APC此时执行。结果只有 100% 可靠的方法在这里使用 ZwQueueApcThread
到 shellcode,它将只调用 ntdll api,通过 LdrLoadDll
加载 dll 并且 dll 本身仅从 静态导入ntdll.dll