C# dll注入不加载dll
C# dll injection not loading dll
我知道在 Whosebug 上有几个类似的问题,但是 none 解决了我的问题。
所以我正在为低级进程间操作编写一个 c# 框架,包括 dll 注入功能。
在调用我的注入器之前,我已经使用具有 PROCESS_ALL_ACCESS
权限的 OpenProcess()
附加到目标进程(在本例中为 notepad++.exe)。
以下是我的注入器代码(我知道由于所有调试打印,可读性受到很大影响):
public void Inject(string dllName, bool printDebugInfo)
{
// Check if we are attached to the process.
target.Assertions.AssertProcessAttached();
target.Assertions.AssertInjectionPermissions();
// searching for the address of LoadLibraryA and storing it in a pointer
IntPtr kernel32Handle = WinAPI.GetModuleHandle("kernel32.dll");
if (kernel32Handle == IntPtr.Zero)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Could not get handle of kernel32.dll: was NULL.");
}
UIntPtr loadLibraryAddr = WinAPI.GetProcAddress(kernel32Handle, "LoadLibraryA");
if (loadLibraryAddr == UIntPtr.Zero)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Could not get address of LoadLibraryA: was NULL.");
}
HelperMethods.Debug("LoadLibraryA is at 0x" + loadLibraryAddr.ToUInt64().ToString("x"), printDebugInfo);
// alocating some memory on the target process - enough to store the name of the dll
// and storing its address in a pointer
uint size = (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char)));
IntPtr allocMemAddress = WinAPI.VirtualAllocEx(target.Handle, IntPtr.Zero, size, (uint)Permissions.MemoryPermission.MEM_COMMIT | (uint)Permissions.MemoryPermission.MEM_RESERVE, (uint)Permissions.MemoryPermission.PAGE_READWRITE);
HelperMethods.Debug("Allocated memory at 0x" + allocMemAddress.ToInt64().ToString("x"), printDebugInfo);
int bytesWritten = 0;
// writing the name of the dll there
byte[] buffer = new byte[size];
byte[] bytes = Encoding.ASCII.GetBytes(dllName);
Array.Copy(bytes, 0, buffer, 0, bytes.Length);
buffer[buffer.Length - 1] = 0;
bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt64(), buffer, size, ref bytesWritten);
if (success)
{
HelperMethods.Debug("Successfully wrote \"" + dllName + "\" to 0x" + allocMemAddress.ToInt64().ToString("x"), printDebugInfo);
}
else
{
HelperMethods.Debug("FAILED to write dll name!", printDebugInfo);
}
// creating a thread that will call LoadLibraryA with allocMemAddress as argument
HelperMethods.Debug("Injecting dll ...", printDebugInfo);
IntPtr threadHandle = WinAPI.CreateRemoteThread(target.Handle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, out IntPtr threadId);
HelperMethods.Debug("CreateRemoteThread returned the following handle: 0x" + threadHandle.ToInt32().ToString("x"), printDebugInfo);
uint errCode = WinAPI.GetLastError();
if (threadHandle == IntPtr.Zero)
{
throw new Win32Exception((int)errCode, "Encountered error " + errCode.ToString() + " (0x" + errCode.ToString("x") + ") - FATAL: CreateRemoteThread returned NULL pointer as handle.");
}
Console.WriteLine("CreateRemoteThread threw errorCode 0x" + errCode.ToString("x"));
Console.WriteLine("Currently the following modules are LOADED:");
ProcessModuleCollection processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
uint waitExitCode = WinAPI.WaitForSingleObject(threadHandle, 10 * 1000);
HelperMethods.Debug("Waiting for thread to exit ...", printDebugInfo);
HelperMethods.Debug("WaitForSingleObject returned 0x" + waitExitCode.ToString("x"), printDebugInfo);
Thread.Sleep(1000);
Console.WriteLine("Currently the following modules are LOADED:");
processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
success = WinAPI.GetExitCodeThread(threadHandle, out uint exitCode);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Non-zero exit code of GetExitCodeThread.");
}
Console.WriteLine("Currently the following modules are LOADED:");
processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
HelperMethods.Debug("Remote thread returned 0x" + exitCode.ToString("x"), printDebugInfo);
success = WinAPI.CloseHandle(threadHandle);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Failed calling CloseHandle on 0x" + threadHandle.ToInt64().ToString("x") + ".");
}
HelperMethods.Debug("Called CloseHandle on 0x" + threadHandle.ToInt64().ToString("x") + ".", printDebugInfo);
success = WinAPI.VirtualFreeEx(target.Handle, allocMemAddress, 0, 0x8000);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Failed calling VirtualFreeEx on 0x" + allocMemAddress.ToInt64().ToString("x") + ".");
}
HelperMethods.Debug("Released all previously allocated resources!", printDebugInfo);
}
所有 WinAPI 函数都按照 Microsoft 官方文档的指定调用(经过三次检查)。
我调用我的代码如下
Target target = Target.CreateFromName("notepad++");
target.Attach(Permissions.ProcessPermission.PROCESS_ALL_ACCESS);
target.Injector.Inject(@"L:\Programming\C\test\newdll.dll",true);
Target
class 的完整源代码在 GitHub 但不应该与这个问题相关。
这里最有趣的可能是 newdll.dll
,它是用本机 C 编写的,如下所示:
#include<Windows.h>
#include<stdbool.h>
__declspec(dllexport) bool WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
return true;
}
这段代码显然没有做太多事情,但是从 DllMain 中生成类似消息框的东西显然被认为是 "bad" 我就这样离开了。但是,如果注入有效,dll 将列在 Process.Modules
中(实际上不是)。
然而,当 运行 我的代码时,我从所有调试打印中得到以下输出:
LoadLibraryA is at 0x778f60b0
Allocated memory at 0x9c0000
Successfully wrote "L:\Programming\C\test\newdll.dll" to 0x9c0000
Injecting dll ...
CreateRemoteThread returned the following handle: 0x22c
CreateRemoteThread threw errorCode 0x0
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Waiting for thread to exit ...
WaitForSingleObject returned 0x0
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Remote thread returned 0x0
Called CloseHandle on 0x22c.
Released all previously allocated resources!
Press any key to continue . . .
可以看出,没有错误代码或任何迹象表明注入确实出错了,除了 newdll.dll
从未加载过,因为它没有显示在 [= 中的加载模块中18=]。
所以我的代码有什么问题?
快速概览:我遵循以下程序:
OpenProcess()
与 PROCESS_ALL_ACCESS
GetModuleHandle("kernel32.dll")
GetProcAddress(kernel32Handle, "LoadLibraryA")
VirtualAllocEx(...)
和 WriteProcessMemory()
写我的 dll 名称和路径。
CreateRemoteThread()
加载dll
WaitForSingleObject()
等待dll加载
- 释放之前分配的所有资源
正如正确指出的那样,此注入技术仅在从 32 位进程注入 --> 32 位进程或从 64 位进程 --> 64 位进程注入时有效。我正在将我的代码编译为 64 位可执行文件,试图将我的 dll 注入 32 位记事本++.exe。
我还必须调整 WriteProcessMemory
调用以符合 32 位内存 space。所以从 bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt64(), buffer, size, ref bytesWritten);
更改为 bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt32(), buffer, size, ref bytesWritten);
就成功了。
我知道在 Whosebug 上有几个类似的问题,但是 none 解决了我的问题。
所以我正在为低级进程间操作编写一个 c# 框架,包括 dll 注入功能。
在调用我的注入器之前,我已经使用具有 PROCESS_ALL_ACCESS
权限的 OpenProcess()
附加到目标进程(在本例中为 notepad++.exe)。
以下是我的注入器代码(我知道由于所有调试打印,可读性受到很大影响):
public void Inject(string dllName, bool printDebugInfo)
{
// Check if we are attached to the process.
target.Assertions.AssertProcessAttached();
target.Assertions.AssertInjectionPermissions();
// searching for the address of LoadLibraryA and storing it in a pointer
IntPtr kernel32Handle = WinAPI.GetModuleHandle("kernel32.dll");
if (kernel32Handle == IntPtr.Zero)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Could not get handle of kernel32.dll: was NULL.");
}
UIntPtr loadLibraryAddr = WinAPI.GetProcAddress(kernel32Handle, "LoadLibraryA");
if (loadLibraryAddr == UIntPtr.Zero)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Could not get address of LoadLibraryA: was NULL.");
}
HelperMethods.Debug("LoadLibraryA is at 0x" + loadLibraryAddr.ToUInt64().ToString("x"), printDebugInfo);
// alocating some memory on the target process - enough to store the name of the dll
// and storing its address in a pointer
uint size = (uint)((dllName.Length + 1) * Marshal.SizeOf(typeof(char)));
IntPtr allocMemAddress = WinAPI.VirtualAllocEx(target.Handle, IntPtr.Zero, size, (uint)Permissions.MemoryPermission.MEM_COMMIT | (uint)Permissions.MemoryPermission.MEM_RESERVE, (uint)Permissions.MemoryPermission.PAGE_READWRITE);
HelperMethods.Debug("Allocated memory at 0x" + allocMemAddress.ToInt64().ToString("x"), printDebugInfo);
int bytesWritten = 0;
// writing the name of the dll there
byte[] buffer = new byte[size];
byte[] bytes = Encoding.ASCII.GetBytes(dllName);
Array.Copy(bytes, 0, buffer, 0, bytes.Length);
buffer[buffer.Length - 1] = 0;
bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt64(), buffer, size, ref bytesWritten);
if (success)
{
HelperMethods.Debug("Successfully wrote \"" + dllName + "\" to 0x" + allocMemAddress.ToInt64().ToString("x"), printDebugInfo);
}
else
{
HelperMethods.Debug("FAILED to write dll name!", printDebugInfo);
}
// creating a thread that will call LoadLibraryA with allocMemAddress as argument
HelperMethods.Debug("Injecting dll ...", printDebugInfo);
IntPtr threadHandle = WinAPI.CreateRemoteThread(target.Handle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, out IntPtr threadId);
HelperMethods.Debug("CreateRemoteThread returned the following handle: 0x" + threadHandle.ToInt32().ToString("x"), printDebugInfo);
uint errCode = WinAPI.GetLastError();
if (threadHandle == IntPtr.Zero)
{
throw new Win32Exception((int)errCode, "Encountered error " + errCode.ToString() + " (0x" + errCode.ToString("x") + ") - FATAL: CreateRemoteThread returned NULL pointer as handle.");
}
Console.WriteLine("CreateRemoteThread threw errorCode 0x" + errCode.ToString("x"));
Console.WriteLine("Currently the following modules are LOADED:");
ProcessModuleCollection processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
uint waitExitCode = WinAPI.WaitForSingleObject(threadHandle, 10 * 1000);
HelperMethods.Debug("Waiting for thread to exit ...", printDebugInfo);
HelperMethods.Debug("WaitForSingleObject returned 0x" + waitExitCode.ToString("x"), printDebugInfo);
Thread.Sleep(1000);
Console.WriteLine("Currently the following modules are LOADED:");
processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
success = WinAPI.GetExitCodeThread(threadHandle, out uint exitCode);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Non-zero exit code of GetExitCodeThread.");
}
Console.WriteLine("Currently the following modules are LOADED:");
processModules = target.Process.Modules;
foreach (ProcessModule module in processModules)
{
Console.WriteLine(" - " + module.FileName);
}
HelperMethods.Debug("Remote thread returned 0x" + exitCode.ToString("x"), printDebugInfo);
success = WinAPI.CloseHandle(threadHandle);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Failed calling CloseHandle on 0x" + threadHandle.ToInt64().ToString("x") + ".");
}
HelperMethods.Debug("Called CloseHandle on 0x" + threadHandle.ToInt64().ToString("x") + ".", printDebugInfo);
success = WinAPI.VirtualFreeEx(target.Handle, allocMemAddress, 0, 0x8000);
if (!success)
{
uint errorCode = WinAPI.GetLastError();
throw new Win32Exception((int)errorCode, "Encountered error " + errorCode.ToString() + " (0x" + errorCode.ToString("x") + ") - FATAL: Failed calling VirtualFreeEx on 0x" + allocMemAddress.ToInt64().ToString("x") + ".");
}
HelperMethods.Debug("Released all previously allocated resources!", printDebugInfo);
}
所有 WinAPI 函数都按照 Microsoft 官方文档的指定调用(经过三次检查)。
我调用我的代码如下
Target target = Target.CreateFromName("notepad++");
target.Attach(Permissions.ProcessPermission.PROCESS_ALL_ACCESS);
target.Injector.Inject(@"L:\Programming\C\test\newdll.dll",true);
Target
class 的完整源代码在 GitHub 但不应该与这个问题相关。
这里最有趣的可能是 newdll.dll
,它是用本机 C 编写的,如下所示:
#include<Windows.h>
#include<stdbool.h>
__declspec(dllexport) bool WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
break;
}
case DLL_PROCESS_DETACH:
{
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
case DLL_THREAD_DETACH:
{
break;
}
}
return true;
}
这段代码显然没有做太多事情,但是从 DllMain 中生成类似消息框的东西显然被认为是 "bad" 我就这样离开了。但是,如果注入有效,dll 将列在 Process.Modules
中(实际上不是)。
然而,当 运行 我的代码时,我从所有调试打印中得到以下输出:
LoadLibraryA is at 0x778f60b0
Allocated memory at 0x9c0000
Successfully wrote "L:\Programming\C\test\newdll.dll" to 0x9c0000
Injecting dll ...
CreateRemoteThread returned the following handle: 0x22c
CreateRemoteThread threw errorCode 0x0
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Waiting for thread to exit ...
WaitForSingleObject returned 0x0
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Currently the following modules are LOADED:
- J:\TOOLS\Notepad++\notepad++.exe
- C:\Windows\SYSTEM32\ntdll.dll
- C:\Windows\SYSTEM32\wow64.dll
- C:\Windows\SYSTEM32\wow64win.dll
- C:\Windows\SYSTEM32\wow64cpu.dll
Remote thread returned 0x0
Called CloseHandle on 0x22c.
Released all previously allocated resources!
Press any key to continue . . .
可以看出,没有错误代码或任何迹象表明注入确实出错了,除了 newdll.dll
从未加载过,因为它没有显示在 [= 中的加载模块中18=]。
所以我的代码有什么问题?
快速概览:我遵循以下程序:
OpenProcess()
与PROCESS_ALL_ACCESS
GetModuleHandle("kernel32.dll")
GetProcAddress(kernel32Handle, "LoadLibraryA")
VirtualAllocEx(...)
和WriteProcessMemory()
写我的 dll 名称和路径。CreateRemoteThread()
加载dllWaitForSingleObject()
等待dll加载- 释放之前分配的所有资源
正如正确指出的那样,此注入技术仅在从 32 位进程注入 --> 32 位进程或从 64 位进程 --> 64 位进程注入时有效。我正在将我的代码编译为 64 位可执行文件,试图将我的 dll 注入 32 位记事本++.exe。
我还必须调整 WriteProcessMemory
调用以符合 32 位内存 space。所以从 bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt64(), buffer, size, ref bytesWritten);
更改为 bool success = WinAPI.WriteProcessMemory((uint)target.Handle, allocMemAddress.ToInt32(), buffer, size, ref bytesWritten);
就成功了。