怎样写一个与Windows10 IE11兼容的标准BHO?

怎样写一个与Windows10 IE11兼容的标准BHO

 

 

 

环境:Windows10 x6410240 IE11x86环境类似)

作者:magictong

日期:2015/11/11

 

 

概述

其实Windows8刚出来的时候写过一篇关于BHO怎么与Win8 x86IE11(增强保护模式开启)兼容的文章(传送门:http://blog.csdn.net/magictong/article/details/21280243),本文主要讨论的问题是Windows10 x86 &x64(是的x64也包含了)下BHOIE11(增强保护模式开启)兼容的问题。

其方法和思路跟Windows8下是类似的,但是修改了一些实现方法,修复了之前那篇文章里面的bug,并且针对x64做了一些必要的处理,本文后面说到的系统和一些贴图都是来之于Windows10x6410240版本(不再赘述)。

 

 

现象


看到这篇文章的人,上面这个图应该见过吧,网上很多的文章对于这个问题的解决方法是将IE的增强安全功能关掉,以解决此不兼容问题。当然对于第三方的插件来说,譬如网购插件,支付插件,这可能是唯一的方法,但是作为一个开发者,我们应该更多的思考怎么从技术上解决此问题,微软既然有此提示,说明也是有方法解决的。

 

 

第一步:兼容x64系统

其实如果是优先兼容x86系统,兼容x64系统是可以放到最后讲的,但是因为我们以x64系统为例讲,而且兼容x64系统的操作很简单,因此提到最前面说了。

其实秘密就是你要准备两个BHO组件(别问我是怎么知道的,反正就是这样o(_)o ),一个是x86下使用的(32位模块),一个是x64下使用的(64位模块),二者使用的CLSIDIIDLIBID都要完全一样,简单点处理就是可以把原始代码分x86平台和x64平台编译出两个模块来,然后分别注册,不用担心CLSID会冲突,在x64系统下,32位的COM组件的注册表在HKEY_CLASSES_ROOT\Wow6432Node\CLSID下面,x64COM组件注册表才在HKEY_CLASSES_ROOT \CLSID下。

另外需要说明的是,如果你的IE没有开增强保护模式,那么你可以根据需要只准备一个BHO模块,也就没有本文说得要解决的这些问题了。

 

 

第二步:兼容增强保护模式

x86下,兼容IE的增量保护模式,比较关键的一点是告诉系统(或者IE),BHO的实现对象(COM对象)是增强保护模式兼容的,也就是[2]里面提到的要将BHOCLSID注册为一个特殊的组件类型库,也就是CATID_AppContainerCompatible类型库,类型库的概念,经常做COM开发的肯定清楚了,或者以前做过ActiveX开发也应该知道,为了和网页的安全性兼容,常把ActiveX控件注册到系统的某些安全类型库中去,否则有些网页下面JS可能调用不了这个ActiveX控件。

[2]里面注册类型库的方式提到了动静两种方式,静态这种方式经验证是肯定可以的,但是有一个很不好的地方就是如果是Windows8以下的系统,因为没有这个类型库,直接注册失败导致整个BHO注册失败,这就无法接受了,除非你确定你的BHO只会在Windows8以上的系统注册。而动态的注册的方式(使用ICatRegister接口的RegisterClassImplCategories方法注册{59FB2056-D625-48D0-A944-1A85B5AB2640}类型库),我发现有bug,接口方法调用成功了,但是实际上没注册上,导致还是提升增强保护模式不兼容,后来仔细对比了一下动态注册和静态注册的注册表,发现动态注册的情况下,Implemented Categories下写了一串为0GUID进去,也不知道是Windows10bug还是什么情况,后来发现Windows8.1下面也有类似问题。


 

而静态的方法则可以正确的写入类型库信息。


 

动态注册的方式以前在Windows8下面使用确信可以成功,这个问题可以调试下到底是什么问题,不过既然知道最终的结果是写这个地方的注册表,我们自己来写注册表也是一样的,注意判断下系统是Windows8以上才进行该操作,代码如下(DllRegisterServer里面):

           // 声明EPM兼容

           //

           WCHAR szClsGuid[64] = {0};

           if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))

               break;

 

           CAtlString strAppContainerCompatibleRegPath;

           strAppContainerCompatibleRegPath.Format(

               L"CLSID\\%s\\Implemented Categories\\{59FB2056-D625-48D0-A944-1A85B5AB2640}",szClsGuid);

           

           CRegKey RegKey;

           if (ERROR_SUCCESS != RegKey.Create(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerCompatibleRegPath))

               break;

 

反注册时,记得删除写入的注册表。

           //

           // 删除EPM兼容

           //

           WCHAR szClsGuid[64] = {0};

           if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))

               break;

 

           CAtlString strAppContainerRegPath;

           strAppContainerRegPath.Format(L"CLSID\\%s", szClsGuid);

 

           CRegKey RegKey;

           if (ERROR_SUCCESS != RegKey.Open(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerRegPath))

               break;

 

           if (ERROR_SUCCESS != RegKey.RecurseDeleteKey(L"ImplementedCategories"))

               break;

 

 

第三步:兼容AppContainer完整性权限

做完第二步的事情之后,启动IE,出现了熟悉的启用,不启用提示条,果断启用,再看“管理加载项”里面状态已经是“已启用”了,但是感觉BHO的功能没生效,什么情况?


 

查看了IE进程的模块加载情况,发现BHO的模块并没有被加载,咦,又被微软忽悠了?调试了下发现,IE是有加载我们的BHO的动作的,但是加载失败了!深入调试发现,原来是因为IE在增强保护模式下时,进程的完整性权限是AppContainer,这种进程只能加载具有ALL APPLICATIONPACKAGES用户组的文件,好吧,注册的时候也给加上吧(Tips:测试时,可以手动添加下先,试试是否成功)!最终代码如下(注:有些代码太长,没有贴出):

//DllRegisterServer - Adds entries to the system registry

STDAPIDllRegisterServer(void)

{

   // registers object, typelib and all interfaces in typelib

   HRESULT hr = _AtlModule.DllRegisterServer();

 

   if (Util::IsWindows8OrGreater())

   {

       // >= Windows 8

       do

       {

           //

           // 添加Appcontainer权限

           //

           TCHAR szModuleName[2 * MAX_PATH + 1] = _T(""); 

           DWORD dwLen = ::GetModuleFileNameW(G_hModSelf, szModuleName, 2 * MAX_PATH);

           if (dwLen < 2 * MAX_PATH)

           {

               TSWIN8AR::AddAllApplicationPackagesGroupToFile(szModuleName);

           }

 

           //

           // 声明EPM兼容

           //

           WCHAR szClsGuid[64] = {0};

           if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))

               break;

 

           CAtlString strAppContainerCompatibleRegPath;

           strAppContainerCompatibleRegPath.Format(

               L"CLSID\\%s\\ImplementedCategories\\{59FB2056-D625-48D0-A944-1A85B5AB2640}", szClsGuid);

           

           CRegKey RegKey;

           if (ERROR_SUCCESS != RegKey.Create(HKEY_CLASSES_ROOT, (LPCTSTR)strAppContainerCompatibleRegPath))

               break;

 

       } while (0);

   }

 

         returnhr;

}

 

//DllUnregisterServer - Removes entries from the system registry

STDAPIDllUnregisterServer(void)

{

   if (Util::IsWindows8OrGreater())

   {

        //>= Windows 8

       do

       {

           //

           // 删除EPM兼容

           //

           WCHAR szClsGuid[64] = {0};

           if (!::StringFromGUID2(CLSID_CBHOInjectJsPlugin, szClsGuid, 64))

               break;

 

           CAtlString strAppContainerRegPath;

           strAppContainerRegPath.Format(L"CLSID\\%s", szClsGuid);

 

           CRegKey RegKey;

           if (ERROR_SUCCESS != RegKey.Open(HKEY_CLASSES_ROOT,(LPCTSTR)strAppContainerRegPath))

               break;

 

           if (ERROR_SUCCESS != RegKey.RecurseDeleteKey(L"ImplementedCategories"))

               break;

       } while (0);

   }

 

   HRESULT hr = _AtlModule.DllUnregisterServer();

         returnhr;

}

 

再看看效果,终于加载进来了。


 

 

注意

(1) 注册程序需要是管理员权限启动,否则注册会失败(除非你把UAC彻底关掉了)。

(2) 如果你的BHO组件放在一些特殊的目录,譬如系统目录,Program Files目录等等,因为这些目录本身处于ALL APPLICATIONPACKAGES用户组,那么拷贝过去的时候会自动继承,导致可能没有出现AppContainer兼容的问题。

(3) 完整代码下载:http://download.csdn.net/detail/magictong/9273691

 

 

参考文档

[1] UnderstandingEnhanced Protected Mode http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx

 

[2] 怎样写一个与Win8 IE11兼容的标准BHO http://blog.csdn.net/magictong/article/details/21280243

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值