为远程进程在外部调用 FreeLibraryAndExitThread
Calling FreeLibraryAndExitThread externally for a remote process
我要尝试在另一个进程中从外部调用 FreeLibraryAndExitThread(使用 CreateRemoteThread),以便我可以卸载通过 LoadLibrary 从外部加载的模块。
我知道虽然 CreateRemoteThread 有 1 个参数,但如果您需要多个参数,您可以为它提供一个包含多个参数的结构。
如果尝试了以下没有卸载模块。事实上它似乎什么也没做。
请注意,我删除了所有错误检查以保持post简单和简短
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr moduleHandle, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr VirtualAllocEx(IntPtr processHandle, IntPtr baseAddress, int size, int allocationType, int protection);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool WriteProcessMemory(IntPtr processHandle, IntPtr baseAddress, byte[] buffer, int size, int bytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateRemoteThread(IntPtr processHandle, IntPtr threadAttributes, int stackSize, IntPtr startAddress, IntPtr parameter, int creationFlags, int threadId);
private struct FreeLibraryAndExitThreadParameters
{
internal IntPtr ModuleAddress;
internal int ExitCode;
}
var process = Process.GetProcessesByName("notepad")[0];
var freeLibraryAndExitThreadAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibraryAndExitThread");
// Get an instance of the module - dllName is the name of the module I am trying to unload
var module = process.Modules.Cast<ProcessModule>().SingleOrDefault(m => string.Equals(m.ModuleName, dllName, StringComparison.OrdinalIgnoreCase));
var freeLibraryAndExitThreadParameters = new FreeLibraryAndExitThreadParameters { ModuleAddress = module.BaseAddress, ExitCode = 0 };
// This code turns the struct into a byte array
var structureSize = Marshal.SizeOf(freeLibraryAndExitThreadParameters);
var structureBytes = new byte[structureSize];
var buffer = Marshal.AllocHGlobal(structureSize);
Marshal.StructureToPtr(freeLibraryAndExitThreadParameters, buffer, true);
Marshal.Copy(buffer, structureBytes, 0, structureSize);
Marshal.FreeHGlobal(buffer);
// Allocate memory in the remote process with commit and reserve allocation type and PageExecuteReadWrite permissions
var remoteAddress = VirtualAllocEx(process.Handle, IntPtr.Zero, structureSize, 0x01000 | 0x02000, 0x040);
// Write the structure into the remote process
WriteProcessMemory(process.Handle, remoteAddress, buffer, structureSize, 0);
// Finally call CreateRemoteThread to execute the function in the remote process
CreateRemoteThread(process.Handle, IntPtr.Zero, 0, freeLibraryAndExitThreadAddress, remoteAddress, 0, 0);
None 的 pinvoke 调用实际上失败了,我可以看到字节正在写入内存,但在创建远程线程后似乎什么也没有发生——在我的实际代码中,我调用了 WaitForSingleObject 和线程也可以毫无问题地完成任务。
有人可以指出我做错了什么以及如何解决这个问题,以便我可以在远程进程中从外部调用 FreeLibraryAndExitThread 吗?
可能值得一提的是,我可以通过这种方法使用 FreeLibrary - 它工作正常(删除结构,因为它只需要一个参数)但我特别需要为我需要卸载的模块使用 FreeLibraryAndExitThread,这就是为什么我没有使用更简单的 FreeLibrary。
正式来说,这就是我们需要的一切
CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0)
其中 hmod
是远程进程中模块的地址。 FreeLibraryAndExitThread
的地址可以从当前进程 kernel32!FreeLibraryAndExitThread
获取 - 直到 kernel32.dll
在所有进程中加载到相同的基地址。
那个
DECLSPEC_NORETURN
VOID
WINAPI
FreeLibraryAndExitThread(
_In_ HMODULE hLibModule,
_In_ DWORD dwExitCode
);
具体情况下取2个参数没问题。作为调用的结果 - CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0)
FreeLibraryAndExitThread
将通过具有单个参数的 stdcal
l (WINAPI
) 调用约定调用 - hmod
。第二个参数 dwExitCode
在这种情况下将是未定义的,但它不会发挥任何作用 - 线程的任何 return 代码都可以。系统不解释这个值。并且因为这个具体的 api 从来没有 return - 参数数量的不同也不起作用。
另一个问题 - 什么,在远程进程中感知卸载模块。并且如果模块真的会被卸载(FreeLibrary
调用只会减少模块加载计数,因此在此调用期间模块并不总是会被卸载)并且在此之后远程进程中的一些代码卸载模块的调用代码 - 认为不需要解释在这种情况下是什么
我要尝试在另一个进程中从外部调用 FreeLibraryAndExitThread(使用 CreateRemoteThread),以便我可以卸载通过 LoadLibrary 从外部加载的模块。
我知道虽然 CreateRemoteThread 有 1 个参数,但如果您需要多个参数,您可以为它提供一个包含多个参数的结构。
如果尝试了以下没有卸载模块。事实上它似乎什么也没做。
请注意,我删除了所有错误检查以保持post简单和简短
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetModuleHandle(string moduleName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr moduleHandle, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr VirtualAllocEx(IntPtr processHandle, IntPtr baseAddress, int size, int allocationType, int protection);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool WriteProcessMemory(IntPtr processHandle, IntPtr baseAddress, byte[] buffer, int size, int bytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateRemoteThread(IntPtr processHandle, IntPtr threadAttributes, int stackSize, IntPtr startAddress, IntPtr parameter, int creationFlags, int threadId);
private struct FreeLibraryAndExitThreadParameters
{
internal IntPtr ModuleAddress;
internal int ExitCode;
}
var process = Process.GetProcessesByName("notepad")[0];
var freeLibraryAndExitThreadAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "FreeLibraryAndExitThread");
// Get an instance of the module - dllName is the name of the module I am trying to unload
var module = process.Modules.Cast<ProcessModule>().SingleOrDefault(m => string.Equals(m.ModuleName, dllName, StringComparison.OrdinalIgnoreCase));
var freeLibraryAndExitThreadParameters = new FreeLibraryAndExitThreadParameters { ModuleAddress = module.BaseAddress, ExitCode = 0 };
// This code turns the struct into a byte array
var structureSize = Marshal.SizeOf(freeLibraryAndExitThreadParameters);
var structureBytes = new byte[structureSize];
var buffer = Marshal.AllocHGlobal(structureSize);
Marshal.StructureToPtr(freeLibraryAndExitThreadParameters, buffer, true);
Marshal.Copy(buffer, structureBytes, 0, structureSize);
Marshal.FreeHGlobal(buffer);
// Allocate memory in the remote process with commit and reserve allocation type and PageExecuteReadWrite permissions
var remoteAddress = VirtualAllocEx(process.Handle, IntPtr.Zero, structureSize, 0x01000 | 0x02000, 0x040);
// Write the structure into the remote process
WriteProcessMemory(process.Handle, remoteAddress, buffer, structureSize, 0);
// Finally call CreateRemoteThread to execute the function in the remote process
CreateRemoteThread(process.Handle, IntPtr.Zero, 0, freeLibraryAndExitThreadAddress, remoteAddress, 0, 0);
None 的 pinvoke 调用实际上失败了,我可以看到字节正在写入内存,但在创建远程线程后似乎什么也没有发生——在我的实际代码中,我调用了 WaitForSingleObject 和线程也可以毫无问题地完成任务。
有人可以指出我做错了什么以及如何解决这个问题,以便我可以在远程进程中从外部调用 FreeLibraryAndExitThread 吗?
可能值得一提的是,我可以通过这种方法使用 FreeLibrary - 它工作正常(删除结构,因为它只需要一个参数)但我特别需要为我需要卸载的模块使用 FreeLibraryAndExitThread,这就是为什么我没有使用更简单的 FreeLibrary。
正式来说,这就是我们需要的一切
CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0)
其中 hmod
是远程进程中模块的地址。 FreeLibraryAndExitThread
的地址可以从当前进程 kernel32!FreeLibraryAndExitThread
获取 - 直到 kernel32.dll
在所有进程中加载到相同的基地址。
那个
DECLSPEC_NORETURN
VOID
WINAPI
FreeLibraryAndExitThread(
_In_ HMODULE hLibModule,
_In_ DWORD dwExitCode
);
具体情况下取2个参数没问题。作为调用的结果 - CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)FreeLibraryAndExitThread, hmod, 0, 0)
FreeLibraryAndExitThread
将通过具有单个参数的 stdcal
l (WINAPI
) 调用约定调用 - hmod
。第二个参数 dwExitCode
在这种情况下将是未定义的,但它不会发挥任何作用 - 线程的任何 return 代码都可以。系统不解释这个值。并且因为这个具体的 api 从来没有 return - 参数数量的不同也不起作用。
另一个问题 - 什么,在远程进程中感知卸载模块。并且如果模块真的会被卸载(FreeLibrary
调用只会减少模块加载计数,因此在此调用期间模块并不总是会被卸载)并且在此之后远程进程中的一些代码卸载模块的调用代码 - 认为不需要解释在这种情况下是什么