Hook这个东西有时令人又爱又怕,Hook是用来拦截系统某些讯息之用,例如说,我们想让系统不管在什麽地方只要按个Ctl-B便执行NotePad,或许您会使用Form的KeyPreview,设定为True,但在其他Process中按Ctl-B呢?那就没有用,这是就得设一个Keyboard Hook来拦截所有Key in的键;再如:MouseMove的Event只在该Form或Control上有效,如果希望在Form的外面也能得知Mouse Move的讯息,那只好使用Mouse Hook来栏截Mouse的讯息。再如:您想记录方才使用者的所有键盘动作或Mosue动作,以便录巨集,那就使用JournalRecordHook,如果想停止所有Mosue键盘的动作,而放(执行)巨集,那就使用JournalPlayBack Hook;Hook呢,可以是整个系统为范围(Remote Hook),即其他Process的动作您也可以拦截,也可以是LocalHook,它的拦截范围只有Process本身。Remote Hook的Hook Function要在.Dll之中,Local Hook则在.Bas中。在VB如何设定Hook呢?使用SetWindowsHookEx()
Declare Function SetWindowsHookEx Lib “user32″ Alias “SetWindowsHookExA” _
(ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
idHook代表是何种Hook,有以下几种
Public Const WH_CALLWNDPROC = 4
Public Const WH_CALLWNDPROCRET = 12
Public Const WH_CBT = 5
Public Const WH_DEBUG = 9
Public Const WH_FOREGROUNDIDLE = 11
Public Const WH_GETMESSAGE = 3
Public Const WH_HARDWARE = 8
Public Const WH_JOURNALPLAYBACK = 1
Public Const WH_JOURNALRECORD = 0
Public Const WH_KEYBOARD = 2
Public Const WH_MOUSE = 7
Public Const WH_MSGFILTER = (-1)
Public Const WH_SHELL = 10
Public Const WH_SYSMSGFILTER = 6
lpfn代表Hook Function所在的Address,这是一个CallBack Fucnction,当挂上某个Hook时,我们便得定义一个Function来当作某个讯息产生时,来处理它的Function,这个Hook Function有一定的叁数格式
Private Function HookFunc(ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long ) As Long
nCode 代表是什麽请况之下所产生的Hook,随Hook的不同而有不同组的可能值。
wParam lParam 传回值则随Hook的种类和nCode的值之不同而不同。
因这个叁数是一个 Function的Address所以我们固定将Hook Function放在.Bas中,并以AddressOf HookFunc传入。至於Hook Function的名称我们可以任意给定,不一定叫 HookFunc
hmod 代表.DLL的hInstance,如果是Local Hook,该值可以是Null(VB中可传0进去),而如果是Remote Hook,则可以使用GetModuleHandle(”.dll名称”)来传入。
dwThreadId 代表执行这个Hook的ThreadId,如果不设定是那个Thread来做,则传0(所以一般来说,Remote Hook传0进去),而VB的Local Hook一般可传App.ThreadId进去。
值回值 如果SetWindowsHookEx()成功,它会传回一个值,代表目前的Hook的Handle,这个值要记录下来。
因为A程式可以有一个System Hook(Remote Hook),如KeyBoard Hook,而B程式也来设一个Remote的KeyBoard Hook,那麽到底KeyBoard的讯息谁所拦截?答案是,最後的那一个所拦截,也就是说A先做keyboard Hook,而後B才做,那讯息被B拦截,那A呢?就看B的Hook Function如何做。如果B想让A的Hook Function也得这个讯息,那B就得呼叫CallNextHookEx()将这讯息Pass给A,於是产生Hook的一个连线。如果B中不想Pass这讯息给A,那就不要呼叫CallNextHookEx()。
Declare Function CallNextHookEx Lib “user32″ Alias “CallNextHookEx” _
(ByVal hHook As Long, _
ByVal ncode As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
hHook值是SetWindowsHookEx()的传回值,nCode, wParam, lParam则是Hook Procedure中的三个叁数。
最後是将这Hook去除掉,请呼叫UnHookWindowHookEx()
Declare Function UnhookWindowsHookEx Lib “user32″ Alias “UnhookWindowsHookEx” _
(ByVal hHook As Long) As Long
hHook便是SetWindowsHookEx()的传回值。此时,以上例来说,B程式结束Hook,则换A可以直接拦截讯息。
KeyBoard Hook的范例
Hook Function的三个叁数
nCode wParam lParam 传回值
=========== ========================== ============== ================
HC_ACTION 表按键Virtual Key 与WM_KEYDOWN同 若讯息要被处理传0
或 反之传1
HC_NOREMOVE
Public hHook as Long
Public Sub UnHookKBD()
If hnexthookproc <> 0 Then
UnhookWindowsHookEx hHook
hHook = 0
End If
End Sub
Public Function EnableKBDHook()
If hHook <> 0 Then
Exit Function
End If
hhook = SetWindowsHookEx(WH_KEYBOARD, AddressOf _
MyKBHFunc, App.hInstance, App.ThreadId)
End Function
Public Function MyKBHFunc(ByVal iCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
MyKBHfunc = 0 ‘表示要处理这个讯息
If wParam = vbKeySnapshot Then ‘侦测 有没有按到PrintScreen键
MyKBHFunc = 1 ‘在这个Hook便吃掉这个讯息
End If
Call CallNextHookEx(hHook, iCode, wParam, lParam) ‘传给下一个Hook
End Function
至于其他的 Hook的详细资料与nCode,wParam, lParam的意义,请查Win32 Help或Windows 95: A Developer’s Guide (Jeffrey Richter著)(中译本:基峰 李书良译 侯俊杰总监 Windows95程式设计指南)
定制Internet Explorer扩展界面接口
作者:令狐叶
本文仅介绍IE扩展界面接口,不涉及内核级的高级扩展。
本文大部分资料来自MSDN,MSDN中有更详细的资料,本文只是摘要编辑。
MSDN中的基本Shell编程从Shell Programmers Guide开始,
IE Shell编程从Browser Extensions Overview开始。(用索引跳转)
相关资源: 1.本文提及的ATL向导都可在www.CodeTools.com,www.Codeguru.com上的ATL,Shell Programming页下载
要求知识: 基本COM, ATL理解和使用,Shell编程知识。
IE浏览器提供了可编程的对外接口,用于增加自定义的功能的界面接口,自然的,这些接口以COM的形式提供,即:IE定义了一系列的COM接口,你按照它的接口规定实现这些接口,IE运行时调用这些接口,从而完成你的定制界面。另外,有些比较简单的扩展只需增加注册表项就可以实现。
基本的扩展界面接口有这么几种:
1.添加定制菜单项到IE上下文菜单,如NetAnts, FalshGet。
2.添加定制菜单项到<工具>菜单下,如NetAnts, FalshGet,MSN Message Service
3.添加定制按钮到标准工具栏,如NetAnts, FalshGet。
4.添加定制的浏览栏,工具栏。如 历史记录,电台栏。
5.捕获浏览器点击,如NetAnts, FalshGet。
下面分别简述其实现方法:
1 添加定制菜单项到IE上下文菜单(只需添加注册表项,以FlashGet为例)
① 在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\下添加一个子键。
A. 该子键名即显示在上下文菜单上的文字,如<使用网际快车下载(&D)>字样。
B. 该子键的默认值为一个网页文件的路径,如C:\Program Files\FLASHGET\jc_link.htm,该文件中保存了你编写的菜单项命令激发时将执行的操作的脚本程序。脚本将可以利用External.menuArguments 收到当前IE运行状态的参数。如:
C. 如果你要控制定制菜单项的在网页上的显示范围,可以在该子键下添加一个Context二进制值,如
FlashGet的0×00000022,表示在点击图象或锚点(Archor)时才显示定制菜单项。具体的逻辑或位的设置含义如下:
Context 值
默认 0×1
图象 0×2
控件 0×4
表 0×8
被选文字 0×10
锚点 0×20
2.添加定制菜单项到<工具>菜单下 (要求IE5.0)
A. 用Guidgen创建一个GUID,然后用这个GUID为名称在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions 下创建一个子键。
B. 接着在该子键下创建一个名为CLSID的字符串值”{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}”(固定值)
C. 同理,创建名为MenuText的为菜单项显示字串,创建名为MenuStatusBar的为菜单高亮时状态栏显示的帮助字串。另外,如果创建名为MenuCustomize的字串”help”,会将定制的菜单项移到<帮助>主菜单下。
D. 要响应菜单命令有三种实现方式: Exe文件,脚本文件,COM对象。
1. 用Exe文件只需在子键下添加名为Exec的值为Exe文件的路径,如C:\Program Files\NETANTS\NetAnts.exe.
2. 用脚本文件只需添加名为script的值为脚本文件的路径。
3. COM实现最复杂,添加名为ClsidExtension字符串值为你为此扩展所创建的COM的GUID。
而你的COM对象必须实现IOleCommandTarget接口.
IOleCommandTarget是一个在Windows扩展中很常用的接口。我以为,定义接口其实就是定义协作各方在某一具体方面的协作规定,顾名思义,IOleCommandTarget就是规定了一种在OLE Container与其包容对象之间的命令传递的方式。
IOleCommandTarget比较简单,有两个要你实现的方法,Exec用于激发命令,执行你定制的功能,QueryStatus用于传递命令的解释性及状态性描述字符串,同注册表的MenuStatusBar项的功能。从具体的传递的参数来讲,你所实现的COM对象中的每一个菜单或按钮命令都以整数标识存在于一个数组中,该数组有一个唯一的GUID标识,使用时依靠命令的整数标识执行相应的操作。更具体的参数含义请见MSDN。
3.添加定制按钮到标准工具栏
基本注册项同上之菜单,接着你可以
创建ButtonText字符串值为按钮的文本标签。
创建HotIcon字符串值为彩色图标的文件路径
创建Icon字符串值为灰色图标的文件路径
创建Default Visible为是否默认可见,值”YES”,”NO”。
其命令激发机制与上述定制菜单项一致,另外还加进一项打开ExplorerBar功能,将上述2之CLISD项的固定值值改为{E0DD6CAB-2D10-11D2-8F1A-0000F87ABD16}, 在添加BandCLSID字串值为要打开的浏览栏的CLSID,但这样一来菜单的定制就没了。
4.添加定制的浏览栏,工具栏
以上3种定制比较简单,基本上不用实现COM对象,而要定制浏览栏,工具栏就一定要实现含有必要接口的COM对象。
有4种可定制的栏,水平浏览栏,垂直浏览栏,桌面工具栏,IE工具栏,它们的COM实现基本上是一致的,不同之处仅在于它们在注册表中的注册项。除了相同的必要的COM对象类的注册,还要注册它们各自的Component Category(组件分类), Windows或IE根据其所注册的分类决定它们出现的位置,分别注册为:垂直栏 CATID_InfoBand,水平栏 CATID_CommBand, 桌面栏 CATID_DeskBand,工具栏则按另一种注册方式。
在ATL里要实现分类注册是很简单的,使用宏:
BEGIN_CATEGORY_MAP(你的COM类名称)
IMPLEMENTED_CATEGORY(分组GUID,如CATID_InfoBand)
END_CATEGORY_MAP()
对于工具栏则要在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Toolbar下以你实现的COM类的CLSID为名创建一个字符串值,可以手工编写rgs, 如
HKLM
{
NoRemove Software
{
NoRemove Microsoft
{
NoRemove ‘Internet Explorer’
{
NoRemove Toolbar
{
val ‘{758C84FF-78FD-11D5-91A0-B4078A11DF77}’ = b ‘00′
}
}
}
}
}
Band COM实现:
每一个Band对象都要实现三个基本接口IDeskBand, IObjectWithSite, IpersistStream,但不要求实现全部接口方法,而且基本实现是相同的。
其中对IPersistStream的要求最简单,你只要实现基接口IPersist的GetClassID,返回你的Band对象的CLSID即可,其余的直接返回即可。
IObjectWithSite也是一个OLE中常用的接口。Site是位于包容器与被包容对象两个概念之间的一个对象,通过它,包容器能对被包容对象的细节进行控制,而被包容对象则能执行自己的功能,而IObjectWithSite就是连通二者的Site对象接口。以IE工具栏为例,包容器就是IE的那个Rebar, Site代表详细的在Rebar提供的位置信息,Site能获得包容器的信息,然后你的COM对象要与Site打交道,这又是通过IObjectWithSite来通信的。
IobjectWithSite包含两个方法:
SetSite是你的栏窗口与IE连接的最重要的一环,要完成如下工作:
1.事先声明一个IInputObjectSite指针的类变量,通过该变量可获得当前站点的信息,而当你的栏窗口被放置到一新站点时,SetSite就被调用,在执行SetSite时如果先前已保留了一个IInputObjectSite应用,就要先释放引用。
2.如果传入的IUnknown为空,表示栏窗口被移除,直接返回即可。
3.如果传入的IUnknown不为空,表示你的栏窗口将被放到一个新Site,这时你要准备创建你的栏窗口,首先向IUnknown索要一个IoleWindow,利用此IOleWindow的GetWindow方法取得父窗口句柄,利用此句柄正式创建你的窗口栏为它的子窗口,最后向IUnknown索要一个IInputObjectSite对象,并保留其引用到上面所声明的类变量。
GetSite就是利用保存的IInputObjectSite指针获取调用者所要求的接口指针。
最后一个要实现的接口是IDeskBand,它本身只有一个GetBandInfo方法,不过由于IDeskBand扩展于IDockingWindow接口,而IDockingWindow又扩展于IOleWindow, 所以连带也要实现它们的接口。不过也很简单。
IOleWindow有两个方法,在GetWindow中返回你创建的栏窗口的句柄,对ContextSensitiveHelp直接返回S_OK.
IDockingWindow有三个方法,在ShowDW中显示或隐藏你的窗口栏,在CloseDW中销毁窗口栏,ResizeBorderDW中返回E_NOTIMPL。
IDeskBand的GetBandInfo根据传入的DESKBANDINFO结构的信息掩码,为其赋给相应的信息值。
另外,如果你要实现栏窗口上的上下文菜单,你必须实现IcontextMenu接口,
以上的接口细节,推荐使用RadBytes的RBDeskBand Wizard一下就可搞定,你根本不用去关心它的实现.,你所作的只是实现你的窗口类。如果使用MFC,你的窗口栏可以直接派生于CWnd或CtoolBar等等;不使用MFC,你可以用ATL的CwindowImpl类来派生窗口类,如果使用RadBytes的CwindowImpl Wizard就更简单了,这样你所做的跟在MFC下没什么区别,真的很好用。
5.捕获浏览器点击,
这个技术牵涉到一个很强大的对象Browser Helper Objects(BHO).
BHO是IE提供的一种可定制控制对象,使用它,你可以监测到IE的各种事件,如 前进,打开一个URL,下载完毕等;可以完全获取IE的菜单,工具栏并定制它;可以定制当前显示页的额外信息窗口,几乎是无所不能。
理所当然的,该对象也是你以COM形式提供的,并且每当一个IE进程实例运行,你的一个BHO实例也随之生成,并与之关联。
除了正常的COM注册,只要在HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects下以你的COM类GUID为名称创建一个子键即可(安装FlashGet的可在这发现它的注册项)。
Browser Helper Objects对象必须的接口只有IObjectWithSite,基本原理与上述一致,但实现的功能是不同的。
在SetSite中,你收到的是一个很谦虚的IUnknown,通过它,你可以索要BHO所在IE实例的IWebBrowser2接口,使用该接口你可以获取当前IE的所有信息,特别是get_Document可获得页面的内容。
要截获某一事件,可以通过上述IWebBrowser2接口索要IConnectionPointerContainer接口,再FindConnectionPoint,找到某一事件对应的出接口的连接点对象,然后用你的COM对象的指针调用Advice注册。从这个角度,你的COM就是一个接收器外象,所以你要实现IDispatch接口(在ATL工程选dual自动实现),并重载Invoke, 响应IE发给你的事件。如:
CComQIPtr
CComQIPtr
CComPtr
m_spWebBrowser2 = pUnkSite;//pUnkSite是由SetSite传入的
m_spCPC = m_spWebBrowser2;//智能指针在赋值时会自动请求对应变量类型的接口
m_spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);//DWebBrowserEvents2是出接口
spCP->Advise(reinterpret_cast
在IDispatch的OnInvoke中:
if (dispidMember == DISPID_BEFORENAVIGATE2)//传入开始跳转事件 DoYourJob();
具体参数见MSDN索引DWebBrowserEvents2.
选用ATL的Internet Explorer Object向导很可以方便的生成基本实现框架,你只要重载实现必要的功能就可。更详细的资料及代码见MSDN索引Browser Helper Objects,IWebBrowser2。
1 comment助手的反叛——浏览器劫持
一. 谁误导了浏览器
今天是大年初二,王先生家中来了许多客人,把平时埋头于工作的王先生弄了个手忙脚乱,由于客人带来的几个小孩子嚷嚷着要出去上网,王先生只好把寝室里的电脑让给了这一群孩子玩,好容易到了晚上,客人散尽,王先生想在休息前上网浏览一下新闻,可是当他打开IE的时候,却发现它自动连接到一个莫名其妙的网站去了,而且收藏夹里也多了一些奇怪的网址,王先生担心是系统感染了病毒,赶紧输入一个在线杀毒工具的网址,结果IE打开的却是另一个不知所谓的网站。看着IE地址栏里准确无误的杀毒工具网址和下面那根本扯不上关系的内容,王先生真的手忙脚乱了…… 相信不少用户也遇到过与之类似的奇怪事情,究竟是谁,把我们的浏览器领到了一处陌生的地方呢?
近年来,针对浏览器的攻击手段层出不穷,对浏览器的渗透攻击逐渐成为入侵者攻破用户层层防御的首要目标,在“钓鱼”(Publishing)危机尚未解除的时候,另一种攻击方式也在同时进行着,这就是“浏览器劫持”——故意误导浏览器行进路线的策划者。
“浏览器劫持”(Browser Hijack)是一种不同于普通病毒木马感染途径的网络攻击手段,它的渗透途径很多,目前最常见的方式有通过BHO、DLL插件、Hook技术、Winsock LSP等载体达到对用户的浏览器进行篡改的目的。这些载体可以直接寄生于浏览器的模块里,成为浏览器的一部分,进而直接操纵浏览器的行为,轻者把用户带到自家门户网站,严重的则会在用户计算机中收集敏感信息,危及用户隐私安全。“浏览器劫持”的后果非常严重,用户只有在受到劫持后才会发现异常情况,但是这时候已经太迟了。目前,浏览器劫持已经成为Internet用户最大的威胁之一。
二. BHO,你是助手还是敌人?
为什么“浏览器劫持”能够如此猖狂呢?放眼众多论坛的求助贴,我们不时可以看到诸如“我的IE被主页被改了,我用杀毒工具扫了一遍都没发现病毒,我把主页改回自己的地址,可是一重启它又回来了!”、“我的系统一开机就跳出一个广告,我明明用了最新版的杀毒软件的啊!”等这类关于IE异常问题的求助,80%的提问者都表示纳闷,他们已经安装了杀毒软件,可是IE仍然被“黑”了,这又是为什么?
其实这些都是典型的“浏览器劫持”现象,但是受害者不是已经安装了杀毒软件吗?为什么浏览器依然躲不过这只黑手?许多用户对这个领域都存在一种误区心理:浏览器劫持?我有最新的杀毒软件,我不怕!
于是,当他们遭遇“浏览器劫持”时,惊讶了。
要知道,杀毒软件自身也只是一种辅助工具,它不可能完全保护系统的安全,更何况,杀毒软件用户必须知道一个事实:“浏览器劫持”的攻击手段是可以通过被系统认可的“合法途径”来进行的!杀毒软件只能通过“特征码”的形式来判断程序是否合法,但这是建立在人为定义以后的,而实施“浏览器劫持”的程序可以有很多,防不胜防。
为什么说“浏览器劫持”可以说是合法的呢?因为大部分浏览器劫持的发起者,都是通过一种被称为“BHO”(Browser Helper Object,浏览器辅助对象)的技术手段植入系统的。
BHO是微软早在1999年推出的作为浏览器对第三方程序员开放交互接口的业界标准,它是一种可以让程序员使用简单代码进入浏览器领域的“交互接口”(INTERACTIVED Interface)。通过BHO接口,第三方程序员可以自己编写代码获取浏览器的一些行为(Action)和事件通知(Event),如“后退”、“前进”、“当前页面”等,甚至可以获取浏览器的各个组件信息,像菜单、工具栏、坐标等。由于BHO的交互特性,程序员还可以使用代码去控制浏览器的行为,比如常见的修改替换浏览器工具栏、在浏览器界面上添加自己的程序按钮等操作,而这些操作都被视为“合法”的,这就是一切罪恶根源的开始。
BHO的出现帮助程序员更好的打造个性化浏览器或者为自己的程序实现了方便简洁的交互功能,可以说,如果没有BHO接口的诞生,我们今天就不能用一些工具实现个性化IE的功能了。从某一方面来看,BHO的确是各种缤纷网络互动功能的幕后功臣,但是一切事物都是有两面性的,这个恒古不变的真理同样对BHO有效,于是就有了今天让安全界头痛的“浏览器劫持”的攻击手段诞生。
看看前面我提到的BHO接口特性,你想到了什么?BHO可以获知和实现浏览器的大部分事件和功能,也就是说,它可以利用少量的代码控制浏览器行为。程序员可以设计出一个BHO按钮以实现用户点击时通知浏览器跳转到某个页面完成交互功能,当然就可以进一步写出控制浏览器跳转到他想让用户去的页面,这就是最初的“浏览器劫持”的成因:BHO劫持。
在描述BHO劫持之前,我们先要对BHO接口的启动做个简单介绍:符合BHO接口标准的程序代码被写为DLL动态链接库形式在注册表里注册为COM对象,还要在BHO接口的注册表入口处进行组件注册,以后每次IE启动时都会通过这里描述的注册信息调用加载这个DLL文件,而这个DLL文件就因此成为IE的一个模块(BHO组件),与IE共享一个运行周期,直到IE被关闭。
IE启动时,会加载任何BHO组件,这些组件直接进入IE领域,而IE则成为它们的父进程和载体,从此IE的每一个事件都会通过IUnknown接口传递到BHO用以提供交互的IObjectWithSite接口里,这是BHO实现与IE交互的入口函数。
BHO接收到IE接口传递来的参数后开始判断IE正在做什么,理论上BHO可以获取IE的大部分事件,然后根据程序员编写的代码,BHO持有对特定事件做出反应的决定权,例如一个可以实现“中文网址”的BHO,就是通过GetSite方法获取到IE当前打开的站点URL(或通过IURLSearchHook接口来获知),如果BHO发现获取到的URL和内置的判断条件匹配,该BHO就会启用SetSite方法强制IE跳转到程序员设定的页面去,这个过程就是利用about:blank篡改主页的“浏览器劫持”方法之一,它的实现原理其实很简单,程序员编写一个恶意BHO组件,当它获取到IE窗口的当前站点为“about:blank”时就强制IE内部跳转到指定的广告页面,于是闹出了不久之前沸沸扬扬的“IE空白页劫持事件”。
了解了这种类似恶作剧的作案手段,要解决它就容易了,只要找到并删除这个隐藏在系统里的BHO程序即可。
除了这类“广告软件”性质的BHO,还有一种利用IURLSearchHook接口实现的另一类更隐蔽的BHO,这种BHO从某些方面来说大概不算BHO,因为它并不是响应IUnknown,而是等待IE创建IURLSearchHook来启动。IURLSearchHook被浏览器用来转换一个未知的URL协议地址,当浏览器企图去打开一个未知协议的URL地址时,浏览器首先尝试从这个地址得到当前的协议,如果不成功,浏览器将寻找系统里所有注册为“URL Search Hook”(资源搜索钩子,USH)的对象并把这个IE不能理解的地址发送过去,如果某个USH对象“认识”这个地址,它就返回一个特定的标识告诉IE它知道怎么打开这个地址,然后IE就根据约定的方法调用它,最终打开这个地址。其实USH对象并不陌生,我们一些偷懒的用户就经常为了省事而不输入“http://”,但是IE最终还是能认出并打开某个地址,就是USH的功劳,但是这一点又被恶意程序员拿来磨刀了,通过创建自己的USH对象,恶意程序员能够命令IE在找不到一些网站时自动跳转到事先设置的站点里,如果这个站点带毒或者挂马,用户就完了。
这类BHO的解决方法和前面一样,只是它比较隐蔽,除非用户经常偷懒,否则可能直到系统崩溃也不会知道自己已经感染了这种东西。也许你会说,只要用户的输入永远不会让IE无法识别,这种渗透不就白费了?但是事实不容乐观,我们无法得知BHO作者还会不会通过其他方法拦截IE,说不定每隔一段时间就让IE弹出一个广告呢?
上面说了这么多BHO和IE合作搞破坏的事例,可能会给读者造成一种“BHO必须在IE传递数据后才能行动”的误解,然而事实并非如此,浏览器自身也是一个标准的可执行程序,而BHO只是借用这个程序进程启动的DLL,它并非API那种要用的时候就让你过来忙活,忙活完了就一脚踹开的奴隶形态DLL,前面说过了,BHO是一种在浏览器加载时一同启动的例程,它相当于一种自身运行逻辑不太明确的子进程(里面都是对IE事件的响应和操作代码),这个特性就造成了BHO DLL和API DLL本质的区别,BHO并不需要所有事件都必须依赖这个大家伙,它可以有自己决定的权利,只要适当的修改,就能用BHO实现类似DLL木马的功能,当然,这并不是说我们就能在IE眼皮下公然的肆无忌弹干坏事的,由于BHO自身是作为IE子进程启动的,它就必须受到一些限制,例如程序员不能在里面自己创建网络连接,这样会导致IE报错崩溃并供出你写的DLL,害怕BHO成为另一种后门的用户可以松口气了,要在BHO里实现Winsock大概只能在IE休息的时候才可以,但是会有哪个用户开着个开空IE什么事情都不做呢?
但这并不是说BHO就一定能无害了,虽然用它不能做到远程控制,但是别忘记,BHO能看到IE的所有东西,也就能任意的访问用户文件和注册表,在这个条件成立的前提下,入侵者可以编写代码查找用户隐私,然后在适当时候通过SetSite提交出去——谁叫现在Webmail这么流行呢?这就是为什么许多厂商发布诸如“中文网址”、“网络搜索”、“IE定制”、“IE监视”这些功能的BHO的同时都保证“不搜集用户隐私”的原因,只要你想要,BHO就能得到一切。
有些人也许会想,既然BHO是微软浏览器的权利,那我不用IE了,我用Opera、Firefox不行?对于这点固然无可厚非,但是你用不用Windows?用不用共享软件?如果你用Windows,那么,你仍然可能处于被BHO接触到的世界,因为Windows本身就是和IE紧密结合的,这就把“IE进程”的范围给扩大了,细心的用户大概会发现,IE里能直接访问“我的电脑”,“我的电脑”窗口也能迅速变成IE,因为它们实质都是依赖于IE内核的,正因为这个原因,BHO可以在你打开一个文件夹时跟着偷偷启动。同时,现在的网络正处于一种“共享软件捆绑战略”大肆实施的时代,你再小心也不能避免某些共享软件固定捆绑了BHO的行为,安装后你才会发现文件夹上又多了个什么“助手”、“搜索”了。要想彻底逃开BHO的围困,大概只能放弃使用Windows了。
三. Hook,你钩住浏览器了
“Life finds its way.”——《侏罗纪公园》
正如《侏》里的这句话一样,入侵者也在不断寻找他们的新出路,虽然上面我说了这么多BHO的负面事例,但是真正的危机并不是只有BHO的,在一些使用BHO行不通的场合里,入侵者开始投掷他们的钩子。
什么是钩子?让我们先看看它的官方定义:
钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
可能上面的官方定义对一部分读者理解有点困难,其实,钩子就像是一切程序的“先知”,一个实现了钩子的程序自身虽然也是普通程序,但是它总能在别的程序得到数据之前就已经知道了一切,这是为什么呢?对Windows系统有一定了解的读者应该知道,Windows系统是一个通过“信息处理机制”运作的系统,在这个系统里传递的数据都是通过“消息”(Message)的形式发送的,各个消息都遵循了官方的约定,否则就不能让系统产生回应。而且这个传递步骤是颠倒的,例如我们关闭了某个程序,我们可能会认为是程序自己关闭后通知系统的,其实不然,当用户点击关闭按钮的时候,Windows就会把一个叫做WM_CLOSE的消息传递给这个程序,程序接收到消息后就执行卸载自身例程的操作。理解了这点,就能知道钩子的原理了,所谓钩子程序,就是利用了系统提供的Hook API,让自己比每一个程序都提前接收到系统消息,然后做出处理,如果一个钩子拦截了系统给某个程序的WM_CLOSE消息,那么这个程序就会因为接收不到关闭消息而无法关闭自身。除了消息以外,钩子还可以拦截API,像我们都熟悉的屏幕翻译软件就是Hook了一些文本输出函数如TextOutA而达到了目的。
Hook技术让编程人员可以轻松获取其他程序的一些有用数据或传递相关数据,像现在常见的一些游戏外挂,它们就是利用Hook技术钩住了游戏窗体,然后就可以识别游戏里面的行为和模拟发送按键鼠标消息,最终实现电脑自己玩游戏的功能。把这个技术应用到浏览器上面,就成了另一种控制浏览器行为的方法。
钩子有两种,本地钩子(Local Hook)和全局钩子(Global Hook),本地钩子只在本进程里起作用,故不属于讨论范围;全局钩子代码必须以DLL形式编写,以便在钩子生效时被其它进程所加载调用,因此我们看到的大部分Hook程序都是DLL形式的。
其实之前提到的BHO也可以视为一种针对IE的钩子,它钩的是IE的事件,这就是IE与BHO交互的起点,但是对于再复杂一点的操作,例如判断IE下载的是GIF图片还是JPEG图片,BHO无能为力,因为它仅仅知道IE的事件为DownloadBegin和DownloadComplete,对于具体内容,IE本身是不会告诉它的,否则IE岂不是要忙死了?至少我也没见过哪个领导还需要向秘书汇报中午吃了鸡肉还是鸭肉的吧,BHO可不是IE的老婆,或者说IE没有气管炎。
所以,为了得到IE的更多数据,程序员开始钩IE了。与BHO不同,钩子不需要被动的等待IE事件,它直接和IE形成上司对下属的关系,这次轮到IE要做什么都得经过它批准了。Hook形式的控制不需要DLL文件必须与IE的注册表入口产生组件关系,它可以是一个独立的DLL,通过Rundll32.exe或自带的Loader EXE启动,而且由于它属于Hook形式, 在钩子有效的情况下会被系统自动插入其他程序的进程中,是不是有点像DLL木马呢?
IE钩子程序载入进程后便能获知所有的消息类型、API和内容,一旦发现某个符合要求的消息,如IE执行了某个事件,或者用户输入了特定内容,钩子的处理代码就开始工作了,它先拦截系统发送给IE的消息,然后分析消息内容,根据不同消息内容作出修改后再发给IE,就完成了一次Hook篡改过程。用著名的3721实名搜索做例子,一些人会以为它是采用了BHO或者IURLSearchHook完成中文域名的识别跳转的,其实它是用了能够第一个得到Windows消息的Hook技术,这样一来就可以避免被其他的竞争对手抢先解析域名了:3721的主程序就是一个Hook DLL,它监视IE地址栏的消息,一旦用户输入的是中文,它便在其他BHO类插件工作之前拦截了这个消息,并调用自身代码完成中文域名到英文URL的转换工作,然后返回(也可能与自己的BHO DLL配合)一个让IE跳转到英文URL的消息,完成域名的翻译任务。
IE钩子能帮助程序员用少量代码完成更多的IE交互工作,但是一旦这个钩子被用于犯罪,其后果也是严重的,恶意程序员可以写一个拦截IE输入的键盘钩子,达到窃取密码的作用,这样无论你是用HTTP明文协议还是SecurityHTTP加密协议都不能逃避密码被盗的下场了,因为它抓的是你在IE里的输入,后面的数据传输已经不重要了。
四. Winsock LSP
全称为“Windows Socket Layered Service Provider”(分层服务提供商),这是Winsock 2.0才有的功能,它需要Winsock支持服务提供商接口(Service Provider Interface,SPI)才能实现,SPI是一种不能独立工作的技术,它依赖于系统商已经存在的基本协议提供商,如TCP/IP协议等,在这些协议上派分出的子协议即为“分层协议”,如SSL等,它们必须通过一定的接口函数调用,LSP就是这些协议的接口。
通过LSP,我们可以比分析基本协议更简单的得到我们想要的数据内容,如直接得到系统上运行的浏览器当前正在进行传输的地址和内容,不管这个浏览器是IE,还是Opera或Firefox,因为LSP是直接从Winsock获取信息的,即使不用微软生产的汽车,至少你这辆汽车一直是在微软建造的公路上跑的吧。
LSP用在正途上可以方便程序员们编写监视系统网络通讯情况的Sniffer,可是现在常见的LSP都被用于浏览器劫持,使用户又多了个噩梦。
五. 亡羊补牢,还是居安思危?
也许大部分家庭用户都是在经历过一次入侵或中毒事件后才知道安全防范的重要性的,能亡羊补牢当然是好事,但是如果能对自己的要求提高一点,做到未雨绸缪岂不是更好?我们总是依赖于别人的技术,依赖于模式化的杀毒手段,但那些始终都是别人的东西,控制权不能掌握在自己手上,这并不是很好的事情,也许,该是暂时放弃游戏挂级、搜集明星电影,好好研读一下安全方面和系统原理书籍的时候了,否则在这个不安全的网络中,我们随时可能会迷失自己。
可能有人会想,小金又在发感慨了。也许是的,因为清除“浏览器劫持”一般都需要手工进行,虽然现在已经有了多个检测浏览器劫持的工具如HijackThis、Browser Hijack Recover等软件面世,但是如果你抱着和以往使用杀毒工具那样“一开扫描就安枕无忧”想法的话,你会发现自己真的会迷失了,由于BHO的特殊性(别忘记,它是合法的),这些工具只会把系统的进程、BHO项目、启动项、LSP等需要有一定技术基础方能理解的东西显示给你,然后由你自己决定IE的明天,如果你不曾重视过安全技术,那么就会觉得这些工具如同另一种折磨你的病毒了。

浙公网安备 33010602011771号