从外部调用FreeLibraryAndExitThread进行远程处理

时间:2019-01-16 09:02:16

标签: c# winapi pinvoke

我试图在另一个进程中(使用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个参数),但是我特别需要对需要卸载的模块使用FreeLibraryAndExitThread,这就是为什么不使用更简单的FreeLibrary。

1 个答案:

答案 0 :(得分:0)

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

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的{​​{1}} l(stdcal)调用约定来调用WINAPI。在这种情况下,第二个参数hmod将是未定义的,但它没有任何作用-线程的任何返回码都可以。系统不解释该值。而且由于此具体的api永远不会返回-参数计数不同也不会发挥作用。

另一个问题-在远程过程中,什么感测卸载模块。并且如果确实要卸载模块(dwExitCode调用只会减少模块的加载计数,那么在此调用期间模块不会总是被卸载),然后在此过程中,卸载模块的远程进程调用代码中的某些代码-认为不需要解释在这种情况下是什么