gpt4 book ai didi

.net - 将 .NET COM Interop 程序集与其托管进程断开

转载 作者:行者123 更新时间:2023-12-02 05:54:44 25 4
gpt4 key购买 nike

当 ActiveXObject 托管在 Windows 桌面/边栏小工具中时,该 ActiveXObject 会被缓存,并且它的 DLL 文件会被锁定(意味着它无法移动、删除或重命名)。问题是这样的;当该小工具随后关闭时,DLL 仍被 Windows 边栏锁定并且无法删除。这会导致一个严重的问题,即无法在旧版本小工具的基础上安装新版本的小工具,在删除小工具的过程中会失败,且不会出现任何错误消息。

这对于用户来说不是很友好,因此我正在寻找一种在小工具卸载事件期间以某种方式“切断”与 ActiveX 控件的联系的方法。我希望有人能告诉我这是否可行,如果可行,请给我一些关于如何实现它的想法。

仅供引用,Windows 边栏小工具实际上只是 Internet Explorer 服务器窗口,因此可以安全地假设 IE 表现出相同的行为。

编辑: Unlocker似乎做了我需要做的事情,那么我如何在 .NET 中以编程方式实现同​​样的事情?

最佳答案

好吧,这是一个相当复杂的问题。我以前见过这种行为,我不熟悉 Windows 桌面/侧边栏小工具,因为我不使用它。不过,我设法想出了三种可能的攻击方法

<强>1。 Handle来自 TechNet

这不是我的主意,there is another StackOverflow thread就推荐这个方法。但我对这是否有效持怀疑态度。文件锁(该实用程序处理的内容)和“加载库”锁之间存在差异,我认为这就是您在使用 ActiveX 时遇到的问题。

我稍微修改了该线程的代码,他们使用 Process.Kill() 来释放锁,我认为最好使用handle.exe来释放锁。

public struct LockInfo
{
public int PID;
public string Handle;

public LockInfo(int pid, string handle)
{
this.PID = pid;
this.Handle = handle;
}
}

static List<LockInfo> getLockingInfo(string fileName)
{
List<LockInfo> lockingProcesses = new List<LockInfo>();

Process tool = new Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = fileName;
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();

// I;m not so hot with regex, so a bit of regex and a bit of manual splitting
string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(\s+)\b(\S+:)";
foreach (Match match in Regex.Matches(outputTool, matchPattern))
{
string[] temp = match.Value.Replace(":", "").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (temp.Length == 2)
{
lockingProcesses.Add(new LockInfo(int.Parse(temp[0].Trim()), temp[1].Trim()));
}
}
return lockingProcesses.Count > 0 ? lockingProcesses : null;
}

static bool closeFileHandle(List<LockInfo> lockingInfo)
{
if ((lockingInfo == null) || (lockingInfo.Count == 0))
{
throw new ArgumentException("lockingProcesses cannot be null or empty");
}

bool fileClosed = true;

foreach (LockInfo lockInfo in lockingInfo)
{
Process tool = new Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = string.Format("-c {0} -y -p {1}", lockInfo.Handle, lockInfo.PID.ToString());
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
if (outputTool.IndexOf("Handle closed") == -1)
{
fileClosed = false;
}
}
return fileClosed;
}

public static void Main()
{
//Path to locked file, make sure the full path is in quotes
string fileName = "\"" + @"C:\Your_Path\To_The\ActiveX.ocx" + "\"";
List<LockInfo> lockInfo = getLockingInfo(fileName);
if ((lockInfo != null) && (lockInfo.Count > 0))
{
closeFileHandle(lockInfo);
}
}

...

<小时/>

<强>2。 Win32 风格

互联网上没有太多关于此的信息,而且似乎需要一些未记录的 API 调用才能顺利完成此任务。

这些 C++ 示例可能会有所帮助。

不幸的是我无法让它无缝地工作。我已经使用 MS Word 中加载的 ActiveX 测试了此方法。然后我尝试解锁ActiveX,它不是很稳定,经常导致word崩溃。我想我没有正确破译上述程序所需的 C++ war 创伤。

连同 CreateRemoteThread in C# 的这个例子我确实将这段代码放在一起。

public struct ProcessInfo
{
public Process Process;
public ProcessModule Module;

public ProcessInfo(Process process, ProcessModule module)
{
this.Process = process;
this.Module = module;
}
}

private static List<ProcessInfo> getProcessInfo(string fileName, bool partialMatch)
{
List<ProcessInfo> myProcesses = new List<ProcessInfo>();

Process[] runningProcesses = Process.GetProcesses();
int i = 0;
for (i = 0; i < runningProcesses.Length; i++)
{
Process currentProcess = runningProcesses[i];
try
{
if (!currentProcess.HasExited)
{
try
{
ProcessModuleCollection modules = currentProcess.Modules;
int j = 0;
for (j = 0; j < modules.Count; j++)
{
if (partialMatch)
{
if ((modules[j].FileName.ToLower().IndexOf(fileName.ToLower()) != -1))
{
myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
break;
}
}
else
{
if ((modules[j].FileName.ToLower().CompareTo(fileName.ToLower()) == 0))
{
myProcesses.Add(new ProcessInfo(currentProcess, modules[j]));
break;
}
}
}
}
catch (NotSupportedException)
{
// You are attempting to access the Modules property for a process that is running on a remote computer.
// This property is available only for processes that are running on the local computer.
}
catch (InvalidOperationException)
{
// The process Id is not available.
}
catch (Win32Exception)
{
// You are attempting to access the Modules property for either the system process or the idle process.
// These processes do not have modules.
}
}
}
catch (InvalidOperationException)
{
// There is no process associated with the object.
}
catch (Win32Exception)
{
// The exit code for the process could not be retrieved.
}
catch (NotSupportedException)
{
// You are trying to access the HasExited property for a process that is running on a remote computer.
// This property is available only for processes that are running on the local computer.

}
}
return myProcesses.Count > 0 ? myProcesses : null;
}

private static void forceRemoteCloseHandle(ProcessInfo processInfo)
{
// Open remote process for write
IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

// Get the handle to CloseHandle in kernel32.dll
IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
IntPtr hCloseHandle = NativeMethods.GetProcAddress(hKernel32, "CloseHandle");
uint temp = 0;

// Create the remote thread and point it to CloseHandle
IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hCloseHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

// Wait for thread to end
NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

//Closes the remote thread handle
NativeMethods.CloseHandle(hCreateRemoteThread);

//Free up the kernel32.dll
if (hKernel32 != null)
NativeMethods.FreeLibrary(hKernel32);

//Close the process handle
NativeMethods.CloseHandle(hProcess);
}

private static void forceRemoteFreeLibrary(ProcessInfo processInfo)
{
// Open remote process for write
IntPtr hProcess = NativeMethods.OpenProcess(NativeMethods.PROCESS_CREATE_THREAD | NativeMethods.PROCESS_VM_OPERATION |
NativeMethods.PROCESS_VM_WRITE | NativeMethods.PROCESS_VM_READ, false, processInfo.Process.Id);

// Get the handle to FreeLibrary in kernel32.dll
IntPtr hKernel32 = NativeMethods.LoadLibrary("kernel32.dll");
IntPtr hFreeHandle = NativeMethods.GetProcAddress(hKernel32, "FreeLibrary");

// Create the remote thread and point it to FreeLibrary
uint temp = 0;
IntPtr hCreateRemoteThread = NativeMethods.CreateRemoteThread((IntPtr)hProcess, (IntPtr)0, 0, hFreeHandle, (IntPtr)processInfo.Module.BaseAddress, 0, out temp);

// Wait for thread to end
NativeMethods.WaitForSingleObject(hCreateRemoteThread, 2000);

//Closes the remote thread handle
NativeMethods.CloseHandle(hCreateRemoteThread);

//Free up the kernel32.dll
if (hKernel32 != null)
NativeMethods.FreeLibrary(hKernel32);

// Close the process handle
NativeMethods.CloseHandle(hProcess);
}

public static void Main()
{
string strFile = @"C:\Program Files\Microsoft Office\OFFICE11\MSCAL.OCX";
List<ProcessInfo> lockingProcesses = getProcessInfo(strFile, false);

foreach (ProcessInfo processInfo in lockingProcesses)
{
forceRemoteCloseHandle(processInfo);
// OR
forceRemoteFreeLibrary(processInfo);
}

// OR
foreach (ProcessInfo procInfo in lockingProcesses)
{
procInfo.Process.Kill();
}

}

internal static class NativeMethods
{
internal const int PROCESS_TERMINATE = 0x0001;
internal const int PROCESS_CREATE_THREAD = 0x0002;
internal const int PROCESS_VM_OPERATION = 0x0008;
internal const int PROCESS_VM_READ = 0x0010;
internal const int PROCESS_VM_WRITE = 0x0020;

internal const int PROCESS_QUERY_INFORMATION = 0x0400;

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
internal static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);

[DllImport("kernel32", SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);


[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool FreeLibrary(IntPtr hModule);

[DllImport("kernel32")]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId);

[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
internal static extern int CloseHandle(IntPtr hPass);
}

...

<小时/>

<强>3。只需使用 Unlocker

这是我最好的推荐。来自 technet 的句柄无法处理加载的 dll/ocx 锁(根据我的测试)。 Win32 很困惑并且没有文档。

Unlocker 提供命令行访问,因此您可以按照与handle.exe 完全相同的方式调用它。只是搞怪一个/?在命令提示符下执行unlocker.exe 后即可查看开关。

还有一个portable version of Unlocker available 这样您就可以将其捆绑到您的部署中,而无需强制最终用户安装该应用程序。

如果所有其他方法都失败,您可以联系 Unlocker 的作者,从他的自述文件中查看此内容。

Licensing

If you are interested in redistributing Unlocker, either in original or modified form, or wish to use Unlocker source code in a product, please send e-mail to ccollomb@yahoo.com with details.

...

<小时/>

<强>4。使用 Process Hacker 共享库

我刚刚发现了这个出色的工具:Process Hacker它是用 100% C# 代码编写的(尽管它在底层确实通过 P/Invoke 使用了很多 WinAPI 函数)。

最好的一点是:它是开源的(LGPL),并提供了两个开发人员可以在其解决方案中引用的库:ProcessHacker.Common ProcessHacker.Native。

我下载了源代码,只是警告一句,这是一个相当大的解决方案,因此可能需要一些时间才能弄清楚到底什么/如何使用它。

它使用我在选项 2 中谈到的未记录的 API 函数 (ntdll.dl),并且可以执行 Unlocker 可以执行的所有操作,甚至更多。

关于.net - 将 .NET COM Interop 程序集与其托管进程断开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1492869/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com