一.引言
好久没更新博客了...最近研究了一下MIMEFILTER拦截JS脚本,为什么要研究这个问题,想必看到这篇文章的你懂的... :D网上关于这个话题的资料太少了,我知道研究的辛苦,所以帖出来,希望我走过的弯路化作经验,能够帮助到需要的朋友。
二.关于MIME FILTER
MIME的英文全称是"Multipurpose Internet Mail Extensions" 多功能Internet 邮件扩充服务,它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器。MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。MEMIFILTER是微软用来支持研发者扩展IE浏览器功能的一套机制,微软原文为:Asynchronous pluggable protocols enable developers to create pluggable protocol handlers, MIME filters, and namespace handlers that work with Microsoft Internet Explorer 4.0 and later and aURL moniker.由此可见,MIMEFILTERS是异步可插拔协议的一种应用方式。
异步可插拔协议提供三种方式实现URI到类的映射(我的翻译部标准,就引用MSDN原文了):
- Permanently registering an asynchronous pluggable protocol handler in the registry. The handler is used for any URIs with the specified scheme (such ashttp,ftp, and so on).
- Temporarily registering a pluggable namespace handler. The handler is used for any URLs with a particular protocol scheme.
- Permanently or temporarily registering a MIME filter. The handler manipulates the data stream it receives and returns a data stream for any resources of the specified MIME type.
其中第三种就是永久或临时地注册一个MIME filter,处理例程对接收到的特定的MIME filter类型的数据流进行处理后然后返回处理后的数据流。因此关于MIME filter总共有两种类型,一种是永久注册,一种是临时注册。
永久注册的MIME filter必须在注册表的HKEY_CLASSES_ROOT\PROTOCOLS\Filter\<mime_filter>位置注册;
临时注册MIME filter则使用IInternetSession接口注册。
IE所支持的MIME类型可查看http://msdn.microsoft.com/en-us/library/ms775147(v=vs.85).aspx,JS并不在其中,可事实上,IE是支持JS过滤的。
JavaScript的MIME 类型有三种:
- text/javascript
- application/javascript
- application/x-javascript
怎样创建一个MIMEFILTER工程可参考微软提供的实例:http://support.microsoft.com/kb/260840。
三. 实现JS拦截和修改
因为JS的MIME类型有三种,如果想注册为永久型的话,则需要写三次注册表,可通过修改RGS文件实现。例如添加
NoRemove PROTOCOLS
{
NoRemove Filter
{
ForceRemove 'text/javascript' = s 'JSMimeFilter MIME Filter Sample'
{
val CLSID = s '{53B95211-7D77-11D2-9F80-00104B107C96}'
}
}
}
就实现了'text/javascript'类型的永久注册(CLSID的值需修改为你自己创建的插件的CLSID值)。但是我发现如果我永久注册三种类型,调试的时候是拦截不到的。我自己的思路是在RGS里注册text/html类型,然后在临时注册三种JS的MIME类型。
拦截步骤:
1. 修改RGS文件
NoRemove PROTOCOLS
{
NoRemove Filter
{
ForceRemove 'text/html' = s 'HTMLMimeFilter MIME Filter Sample'
{
val CLSID = s '{53B95211-7D77-11D2-9F80-00104B107C96}'
}
}
}
2. 在新建的过滤类中添加2个成员:
IInternetSession* m_pSession;
IClassFactory* m_pFactory;
在构造函数中临时注册三种JS MIME类型:
HRESULT hr = CoGetClassObject(CLSID_HttpContentFilterPP, CLSCTX_SERVER, NULL, IID_IClassFactory, (void**)&m_pFactory);
if(hr==S_OK)
{
if(CoInternetGetSession(0, &m_pSession, 0)==S_OK)
{
//临时注册其它三种类型
hr = m_pSession->RegisterMimeFilter(m_pFactory, CLSID_HttpContentFilterPP, L"application/javascript");
hr = m_pSession->RegisterMimeFilter(m_pFactory, CLSID_HttpContentFilterPP, L"application/x-javascript");
hr = m_pSession->RegisterMimeFilter(m_pFactory, CLSID_HttpContentFilterPP, L"text/javascript");
}
}
当用户访问某个网页的时候,最先到达MIME类型是text/html,这样就会引发PP构造函数,从而实现了JS的MIME类型注册,这样后面的JS就会被拦截。
3. 在Start函数中实现类型判别:
if (!wcscmp(szUrl, CONTENT_TYPE_TEXT_JS))
{
m_js_type = TEXT_JS;
}
else if (!wcscmp(szUrl, CONTENT_TYPE_JS))
{
m_js_type = JS;
}
else if (!wcscmp(szUrl, CONTENT_TYPE_X_JS))
{
m_js_type = X_JS;
}
m_js_type是我定义的一个枚举成员变量。
4. 在过滤处理函数中实现过滤:
if(m_js_type != NONE)
{
//过滤处理
//...
CString S = pbuff;
_ASSERTE(m_pHTMLBuffer);
int c = 0;
/*while(c!=g_KeyWordsOrgin.GetCount())
{
CString s = g_KeyWordsOrgin[c];
S.Replace(s, g_KeyWordsReplace[c]);
c++;
}*/
CString s_or("aaaaaaaaa;");
CString s_or2("bbbbbbbbb;");
int len = S.GetLength();
if (S.Find(s_or)!=-1)
{
CString s_re("aaaaaaaaa; alert('a');");
if(S.Replace(s_or, s_re))
{
ATLTRACE(_T("aaaaaaaaa replaced success!"));
}
}
else if(S.Find(s_or2)!=-1)
{
CString s_re2("bbbbbbbbb; alert('b');");
if(S.Replace(s_or2, s_re2))
{
ATLTRACE(_T("bbbbbbbbb replaced success!"));
}
}
memcpy(pbuff, S.GetBuffer(0), S.GetLength());
pbuff[S.GetLength()] = 0;
S.ReleaseBuffer();
//...
}
四. 实验结果
以某某站点为例,测试结果如下:
五. 总结
上面的步骤是在微软提供的例子的基础上修改的,经过测试,成功地拦截到了JS脚本,并实现了JS脚本内容的修改。在实验中发现,IE下载到的JS脚本文件并没有修改掉,只是读取到内存中的脚本内容发生了变化,读者可查看IE缓存文件夹的响应脚本文件验证下。还有个问题就是同一个网页中,某些JS脚本拦截不到,过滤器的功能不够稳定,具体的原因可能是由于某些JS没有content-type标签,导致IE在探查JS类型的时候误判。具体可参考http://msdn.microsoft.com/en-us/library/ms775147(v=vs.85).aspx中关于MIME类型的探查算法。文章中若有错误恳请读者不吝文墨,批评斧正。谢谢!
下面是我搜到的关于MEMIFILTER的一些站点:
http://msdn.microsoft.com/en-us/library/aa767916(VS.85).aspx
http://msdn.microsoft.com/en-us/library/ms775148(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms775147(v=vs.85).aspx
http://support.microsoft.com/kb/260840
http://blog.youkuaiyun.com/lion_wing/article/details/839134
http://www.pudn.com/downloads74/sourcecode/windows/internet/detail271630.html
http://www.vckbase.com/index.php/wv/1145
http://www.qingfengju.com/article.asp?id=68