C# 为远程进程外部调用FreeLibraryAndExitThread

C# 为远程进程外部调用FreeLibraryAndExitThread,c#,winapi,pinvoke,C#,Winapi,Pinvoke,我尝试在另一个进程中使用CreateRemoteThread在外部调用FreeLibraryAndExitThread,以便可以通过LoadLibrary卸载从外部加载的模块 我知道CreateRemoteThread接受1个参数,如果需要多个参数,可以为其提供多个参数的结构 如果您尝试了以下未卸载模块的操作。事实上,它似乎什么也没做 注意我已经删除了所有的错误检查,以保持这篇文章的简单和简短 [DllImport("kernel32.dll", SetLastError = true)] in

我尝试在另一个进程中使用CreateRemoteThread在外部调用FreeLibraryAndExitThread,以便可以通过LoadLibrary卸载从外部加载的模块

我知道CreateRemoteThread接受1个参数,如果需要多个参数,可以为其提供多个参数的结构

如果您尝试了以下未卸载模块的操作。事实上,它似乎什么也没做

注意我已经删除了所有的错误检查,以保持这篇文章的简单和简短

[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);
没有一个pinvoke调用实际失败,我可以看到字节正在写入内存,但在创建远程线程之后似乎什么也没有发生——在我的实际代码中,我调用WaitForSingleObject,线程也毫无问题地完成了它的任务

有人能指出我做错了什么,以及我如何解决这个问题,以便在远程进程中从外部调用FreeLibraryAndExitThread吗


值得一提的是,我可以用这个方法使用FreeLibrary——它可以很好地移动结构,因为它只需要1个参数,但我特别需要为我需要卸载的模块使用FreeLibrary和ExitThread,这就是我不使用更简单的FreeLibrary的原因。

正式来说,这就是我们所需要的

CreateRemoteThreadhProcess,0,0,PTHREAD\u START\u RoutineFreeLibrary和ExitThread,hmod,0,0

其中hmod是远程进程中模块的地址。FreeLibraryAndExitThread的地址可以从当前进程内核32获取!FreeLibraryAndExitThread-直到在所有进程中在相同的基址加载kernel32.dll

在具体情况下取2个参数没有问题。调用-CreateRemoteThreadhProcess,0,0,PTHREAD\u START\u ROUTINEFreeLibraryAndExitThread,hmod,0,0的结果是,FreeLibraryAndExitThread将通过stdcall WINAPI调用约定,使用单参数-hmod进行调用。第二个参数dwExitCode在本例中是未定义的,但它不起任何作用-线程的任何返回代码都可以。系统无法解释此值。而且因为这个具体的api永远不会返回-不同的参数计数也不会起作用


另一个问题是,对于什么,远程进程中的哪个感测卸载模块。如果模块真的要卸载,FreeLibrary只调用递减模块加载计数,因此,在调用过程中,模块并不总是被卸载,在此之后,远程进程调用卸载模块的代码中的一些代码-认为不需要解释在这种情况下是什么

您必须传递到要卸载的模块的CreateRemoteThread地址,而不是remoteAddress。远程进程不需要任何VirtualAllocEx。为什么?我正试图卸载远程进程中的一个模块。FreeLibraryAndExitThread接受2个参数,与FreeLibrary不同,因此需要分配内存并将参数写入远程进程。我不能用一个变量同时传递参数2。不,你错了。您不需要在远程进程中进行任何分配。第二个参数未定义。不管怎样,它都将是线程的退出代码。因此,您可以像只需1个参数一样调用此api。只需传递您想要卸载的模块的地址,我已经尝试过了,进程在远程线程完成后终止。模块似乎也被卸载了,但理想情况下,我希望进程不会崩溃,但如果您卸载了由进程代码使用的模块,那么它当然会崩溃,如果调用卸载模块的代码。你为什么要这么做?您尝试卸载的dll是什么?您需要使用调试器来查看发生了什么。但在远程进程中正式调用FreeLibraryAndExitThread非常简单。您需要CreateRemoteThreadhProcess,0,0,FreeLibraryAndExitThread,hmod,0,0,其中hmod是要卸载的模块的地址。在远程进程中不需要任何内存分配。该api采用2个参数-在具体情况下没有问题。我们只能通过一个,一切都会好的
DECLSPEC_NORETURN
VOID
WINAPI
FreeLibraryAndExitThread(
    _In_ HMODULE hLibModule,
    _In_ DWORD dwExitCode
    );