0

好的,这是一个 100 万美元的小问题。我正在开发一个应用程序来检查您的任何浏览器当前是否正在运行 Flash 应用程序。这是我的核心本机实现:

// Using CreateToolhelp32Snapshot allows to list all the modules loaded by a specific process.
internal static Boolean ProcessContainsModule(Process process, String moduleMask)
{
    IntPtr snapshotHandle;

    if (Environment.Is64BitProcess)
        snapshotHandle = CreateToolhelp32Snapshot((SnapshotFlags.Module | SnapshotFlags.Module32), (UInt32)process.Id);
    else
        snapshotHandle = CreateToolhelp32Snapshot(SnapshotFlags.Module, (UInt32)process.Id);

    if (snapshotHandle == IntPtr.Zero)
        return false;

    Boolean result = false;

    ModuleEntry entry = new ModuleEntry();
    entry.Size = ModuleEntry.SizeOf;

    if (Module32First(snapshotHandle, ref entry))
    {
        do
        {
            if (entry.ModuleName.FitsMask(moduleMask))
            {
                result = true;
                break;
            }

            entry = new ModuleEntry();
            entry.Size = ModuleEntry.SizeOf;
        }
        while (Module32Next(snapshotHandle, ref entry));
    }

    CloseHandle(snapshotHandle);

    return result;
}

// This is a simple wildcard matching implementation.
public static Boolean FitsMask(this String value, String mask)
{
    Regex regex;

    if (!s_MaskRegexes.TryGetValue(mask, out regex))
        s_MaskRegexes[mask] = regex = new Regex(String.Concat('^', Regex.Escape(mask.Replace(".", "__DOT__").Replace("*", "__STAR__").Replace("?", "__QM__")).Replace("__DOT__", "[.]").Replace("__STAR__", ".*").Replace("__QM__", "."), '$'), RegexOptions.IgnoreCase);

    return regex.IsMatch(value);
}

现在,Process Explorer在我的流程探索中非常有用。

用 Chrome 检测这个非常简单:

if ((process.ProcessName == "chrome") && NativeMethods.ProcessContainsModule(process, "PepFlashPlayer.dll"))

用 Firefox 检测这个也很简单:

if ((process.ProcessName.StartsWith("FlashPlayerPlugin")) && NativeMethods.ProcessContainsModule(process, "NPSWF32*"))

与往常一样,当您查看 Internet Explorer 时,一切都会发生变化。有关如何使用 Microsoft 的浏览器检测到这一点的任何线索?

4

2 回答 2

1

好的,我找到了:

if ((process.ProcessName == "iexplore") && NativeMethods.ProcessContainsModule(process, "Flash32*"))
于 2013-05-16T18:58:42.737 回答
0

我已经修改了 Zarathos 的代码以使其实际可编译,并添加了一些个人风格。

tl;dr:这适用于 Firefox,有时适用于 Chrome,完全不适用于 IE

首先,这是基本代码:

using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Diagnostics;

#region pinvoke.net boilerplate

[Flags]
private enum SnapshotFlags : uint
{
    HeapList = 0x00000001,
    Process = 0x00000002,
    Thread = 0x00000004,
    Module = 0x00000008,
    Module32 = 0x00000010,
    Inherit = 0x80000000,
    All = 0x0000001F,
    NoHeaps = 0x40000000
}

private struct MODULEENTRY32
{
    private const int MAX_PATH = 255;
    internal uint dwSize;   
    internal uint th32ModuleID;
    internal uint th32ProcessID;
    internal uint GlblcntUsage;
    internal uint ProccntUsage;
    internal IntPtr modBaseAddr;
    internal uint modBaseSize;
    internal IntPtr hModule;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
    internal string szModule;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 5)]
    internal string szExePath;
}

[DllImport("kernel32", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern IntPtr CreateToolhelp32Snapshot([In]UInt32 dwFlags, [In]UInt32 th32ProcessID);

[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle([In] IntPtr hObject);

[DllImport("kernel32.dll")]
static extern bool Module32First(IntPtr hSnapshot, ref MODULEENTRY32 lpme);

[DllImport("kernel32.dll")]
static extern bool Module32Next(IntPtr hSnapshot, ref MODULEENTRY32 lpme);

#endregion

static bool ProcessContainsModule(Process process, string searchTerm)
{
    bool result = false;

    //get handle to process
    IntPtr snapshotHandle = Environment.Is64BitProcess ?
        CreateToolhelp32Snapshot((UInt32)(SnapshotFlags.Module | SnapshotFlags.Module32), (UInt32)process.Id) :
        CreateToolhelp32Snapshot((UInt32)SnapshotFlags.Module, (UInt32)process.Id);
    if (snapshotHandle == IntPtr.Zero)
    {
        return result;
    }

    //walk the module list
    try
    {
        MODULEENTRY32 entry = new MODULEENTRY32() { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) };

        if (Module32First(snapshotHandle, ref entry))
        {
            do
            {
                if (entry.szModule.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    result = true;
                    break;
                }

                entry = new MODULEENTRY32() { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) };
            }
            while (Module32Next(snapshotHandle, ref entry));
        }

        return result;
    }
    finally
    {
        CloseHandle(snapshotHandle);
    }
}

你可以像这样使用它:

static bool IsFlashLoadedInFirefox()
{
    return Process.GetProcessesByName("plugin-container").Any(x => ProcessContainsModule(x, "NPSWF"));
}

static bool IsFlashLoadedInInternetExplorer()
{
    //This doesn't work. For some reason can't get modules from child processes
    return Process.GetProcessesByName("iexplore").Any(x => ProcessContainsModule(x, "Flash32"));
}

static bool IsFlashLoadedInChrome()
{
    //Doesn't work reliably. See description.
    return Process.GetProcessesByName("chrome").Any(x => ProcessContainsModule(x, "pepflashplayer"));
}

如评论中所述,似乎只有 Firefox 可以可靠地工作。在 IE (IE11) 的情况下,Module32First()由于某种原因失败。在 Chrome 的情况下,事情变得更有趣了:

  • 如果新标签页导航到 youtube.com 或任何 YouTube 视频,则代码有效
  • 但是,如果将新选项卡导航到 YouTube 上的播放列表,代码将失败,因为 pepFlashPlayer.dll 不在进程的模块列表中(使用 ProcessExplorer 检查)。此外,如果您继续导航到其他非播放列表 YouTube 视频,它仍然不会显示。

请注意,这种检查进程加载的 DLL 的方法非常脆弱,如果任何浏览器决定更改它们加载的 DLL 或它的加载方式,那么代码就会中断。

参考:

  1. http://pinvoke.net/default.aspx/kernel32.createtoolhelp32snapshot
  2. http://pinvoke.net/default.aspx/kernel32/Module32First.html
  3. http://pinvoke.net/default.aspx/kernel32/Module32Next.html
于 2015-02-27T22:24:49.600 回答