【问题标题】:Overriding IE settings when embedding a WebBrowser control using IE9使用 IE9 嵌入 WebBrowser 控件时覆盖 IE 设置
【发布时间】:2023-03-10 20:55:02
【问题描述】:

我有一个应用程序(用 MFC 用 C++ 编写,但我认为这并不特别相关),它嵌入了 Internet Explorer ActiveX WebBrowser 控件,用于显示一些 HTML 页面。一项要求始终是使用应用程序的字体名称和大小设置作为 HTML 的默认设置,而不是 Internet Explorer 的默认设置。

为此,应用程序实现了 IDocHostUIHandler2 COM 接口,并将其传递给 WebBrowser 控件。这会导致控件调用应用程序的GetOptionKeyPath 实现,这使应用程序可以设置WebBrowser 控件从中获取其设置的注册表位置。借助 Sysinternals 的工具来查看 IE 使用哪些键来查找字体名称和大小,这足以满足我的需要。

然而,Internet Explorer 9 的出现让人大吃一惊:在我测试过的所有安装了 IE9 的机器上,WebBrowser 控件都使用自己的设置,而忽略了应用程序中的注册表位置。使用调试器进行测试表明 WebBrowser 控件从不调用提供的 GetOptionKeyPath。

更多实验表明 IE9 WebBrowser 控件正在调用类似(但不相同)GetOverrideKeyPath 方法:据称这提供了一种覆盖 IE 设置的方法,如果在注册表的相关部分。不幸的是,这有两个问题:1) 这不是我想要的,2) IE9 在转到 IE 默认注册表设置之前并不总是检查 GetOverrideKeyPath 注册表位置。

查看GetOptionKeyPath MSDN page 有一些类似的投诉,但没有解决方案。有没有人找到一个干净的方法来说服 WebBrowser 控件恢复到实际调用 GetOptionKeyPath 的 IE9 之前的行为?

【问题讨论】:

  • 这里在 IE9 中有一个回归。目前正在将其视为服务(补丁)过程的一部分。

标签: windows com internet-explorer-9 webbrowser-control


【解决方案1】:

我想出了一个技巧来解决这个问题,但我应该警告你:它并不漂亮。如果您很容易被冒犯,请立即停止阅读...

由于似乎没有办法让 IE9 使用 IDocHostUIHandler::GetOptionKeyPath() 方法,我使用 SysInternals 的工具查看哪些 IE9 DLL 访问了注册表的相关部分以加载 IE9 设置。这揭示了唯一的罪魁祸首是“mshtml.dll”和“iertutil.dll”,它们都调用了 RegOpenKeyExW()。

然后计划是在初始化 WebBrowser 控件之前加载这些 DLL,并对它们进行修补,以便将调用重定向到我的代码,在那里我可以使用 dbghelp.dll 对我打开的注册表项撒谎。因此,首先,在初始化 WebBrowser 控件之前:

if (theApp.GetIEVersion() >= 9.0)
{
  HMODULE advadi = ::LoadLibrary("advapi32.dll");
  HMODULE mshtml = ::LoadLibrary("mshtml.dll");
  HookApiFunction(mshtml,advadi,"advapi32.dll","RegOpenKeyExW",(PROC)HookRegOpenKeyExW);
  HMODULE iertutil = ::LoadLibrary("iertutil.dll");
  HookApiFunction(iertutil,advadi,"advapi32.dll","RegOpenKeyExW",(PROC)HookRegOpenKeyExW);
}

现在,执行扫描 DLL 导入地址表和修补请求的函数的邪恶工作的代码(省略了错误处理以减小代码大小):

void HookApiFunction(HMODULE callingDll, HMODULE calledDll, const char* calledDllName, const char* functionName, PROC newFunction)
{
  // Get the pointer to the 'real' function
  PROC realFunction = ::GetProcAddress(calledDll,functionName);

  // Get the import section of the DLL, using dbghelp.dll's ImageDirectoryEntryToData()
  ULONG sz;
  PIMAGE_IMPORT_DESCRIPTOR import = (PIMAGE_IMPORT_DESCRIPTOR)
    ImageDirectoryEntryToData(callingDll,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&sz);

  // Find the import section matching the named DLL
  while (import->Name)
  {
    PSTR dllName = (PSTR)((PBYTE)callingDll + import->Name);
    {
      if (stricmp(dllName,calledDllName) == 0)
       break;
    }
    import++;
  }
  if (import->Name == NULL)
    return;

  // Scan the IAT for this DLL
  PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((PBYTE)callingDll + import->FirstThunk);
  while (thunk->u1.Function)
  {
    PROC* function = (PROC*)&(thunk->u1.Function);
    if (*function == realFunction)
    {
      // Make the function pointer writable and hook the function
      MEMORY_BASIC_INFORMATION mbi;
      ::VirtualQuery(function,&mbi,sizeof mbi);
      if (::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect))
      {
        *function = newFunction;
        DWORD protect;
        ::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&protect);
        return;
      }
    }
    thunk++;
  }

最后,我修补了 DLL 以在我的代码中调用的函数,代替 RegOpenKeyExW():

LONG WINAPI HookRegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
{
  static const wchar_t* ieKey = L"Software\\Microsoft\\Internet Explorer";

  // Never redirect any of the FeatureControl settings
  if (wcsstr(lpSubKey,L"FeatureControl") != NULL)
    return ::RegOpenKeyExW(hKey,lpSubKey,ulOptions,samDesired,phkResult);

  if (wcsnicmp(lpSubKey,ieKey,wcslen(ieKey)) == 0)
  {
    // Redirect the IE settings to our registry key
    CStringW newSubKey(m_registryPath);
    newSubKey.Append(lpSubKey+wcslen(ieKey));
    return ::RegOpenKeyExW(hKey,newSubKey,ulOptions,samDesired,phkResult);
 }
 else
   return ::RegOpenKeyExW(hKey,lpSubKey,ulOptions,samDesired,phkResult);
}

令人惊讶的是,这个可怕的 hack 确实有效。但是,微软,如果你在听,请在 IE10 中正确修复这个问题。

【讨论】:

  • 这个问题在 IE 10 中修复了吗?另外,这样的 dll 钩子不会在防病毒软件中引起警报吗?这个钩子是附加到 UI 线程应用程序拥有还是整个操作系统?
  • 我没有尝试过 IE10,也没有看到任何由于这种技术而导致的反病毒攻击。它只会影响当前进程,因为它所做的只是修补进程空间中的 IAT。
  • 为什么不覆盖 FeatureControl 设置?这些也会弄乱您的浏览器控制。
  • 我尝试在 Win8.1/IE11 上使用类似的东西,但我得到的 DLL 名称如 api-ms-win-downlevel-advapi32-l1-1-0.dll 而不是 advapi32.dll。我可能会尝试识别存根库,但是这个 hack 已经过火了!甚至尝试这样做的原因是也无法让 GetOptionKeyPath 在此环境中工作(它被调用但 reg 条目仍然来自默认位置,无论出于何种原因)。
猜你喜欢
  • 2014-10-15
  • 2011-10-13
  • 1970-01-01
  • 2011-07-28
  • 2023-03-03
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
  • 2015-07-16
相关资源
最近更新 更多