中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > 综合其它
《Undocumented Windows 2000 Secrets》翻译 --- 第五章(6)
作者:未知 时间:2005-07-27 23:24 出处:CSDN 责编:chinaitpower
              摘要:《Undocumented Windows 2000 Secrets》翻译 --- 第五章(6)

第五章  监控Native API调用

翻译:Kendiv( fcczj@263.net )

更新:Thursday, April 28, 2005

 

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

 

IOCTL函数  SPY_IO_HOOK_REMOVE

IOCTL函数SPY_IO_HOOK_REMOVE函数和SPY_IO_HOOK_INSTALL很相似,只不过它执行与SPY_IO_HOOK_INSTALL相反的操作。这两个函数的输入、输出参数都是相同的。下面是列表5-12列表5-13的对比:

 

l         如果全局标志gfSpyHookState表示当前并未安装Hooks,那么调用将被忽略。

 

l         在将Service Table恢复到修改前的状态后,在全局变量ghSpyHookThread中保存的安装Hook的线程ID将被置零。

 

l         最重要的扩展特性是位于列表5-13中部的do/while循环,SpyHookRemove()通过测试全局结构DEVICE_CONTEXT中的所有SPY_CALL子结构的fInUse成员来判断Hook Dispatcher是否还在为其他线程提供服务。这种测试是必须的,因为客户可能会在卸载Hook后就立即卸载Spy驱动程序。如果在Hook Dispatcher中还存在其他程序的API调用的情况下,就卸载Spy驱动程序,系统将抛出一个异常,随后将引发蓝屏。对fInUse的测试每隔100msec就进行一次,以使其他线程有机会推出Spy

 

NTSTATUS SpyHookRemove (BOOL   fReset,

                        PDWORD pdCount)

    {

    LARGE_INTEGER liDelay;

    BOOL          fInUse;

    DWORD         i;

    DWORD         n  = 0;

    NTSTATUS      ns = STATUS_INVALID_DEVICE_STATE;

 

    if (gfSpyHookState)

        {

        n = SpyHookExchange ();

        if (fReset) SpyHookReset ();

 

        do  {

            for (i = 0; i < SPY_CALLS; i++)

                {

                if (fInUse = gpDeviceContext->SpyCalls [i].fInUse)

                    break;

                }

            liDelay.QuadPart = -1000000;

            KeDelayExecutionThread (KernelMode, FALSE, &liDelay);

            }

        while (fInUse);

 

        ghSpyHookThread = 0;

 

        ns = STATUS_SUCCESS;

        }

    *pdCount = n;

    return ns;

    }

列表5-13.  恢复系统的API Service Table

 

注意,即使所有的fInUse标志都被清除,最后的100msec延迟也是必须的。这种预防措施是由于在Hook Dispatcher中存在一个很小的安全漏洞,这一漏洞存在于重置当前SPY_CALL中的fInUse标志的指令和Dispatcher将控制返回给调用着的RET指令(参考列表5-2中,SpyHook8SpyHook9之间的ASM代码)之间。如果所有的fInUse标志都是FALSE,则存在一个很小的可能性,使得某些线程在要执行RET指令之前被暂停(Suspend)。继续延迟100msec后再移除Hook,则可以使得这些线程有机会离开这一临界区。

 

 

IOCTL函数  SPY_IO_HOOK_PAUSE

列表5-14给出了SPY_IO_HOOK_PAUSE函数,该函数允许一个客户临时禁止(或再次允许)Hook协议函数。实质上,该函数让客户设置全局逻辑变量gfSpyHookPause并将其原始值返回给客户来实现这一功能的,这里用到了ntoskrnl.exe中的InterlockExchange()函数。默认情况下,协议是被允许的;这就意味着,gfSpyHookPause的初值为FALSE

 

BOOL SpyHookPause (BOOL fPause)

    {

    BOOL fPause1 = (BOOL)

                   InterlockedExchange ((PLONG) &gfSpyHookPause,

                                        ( LONG) fPause);

    if (!fPause) SpyHookReset ();

    return fPause1;

    }

列表5-14.  打开/关闭协议

 

这里要特别注意的是,SPY_IO_HOOK_PAUSE的工作完全依赖于SPY_IO_HOOK_INSTALLSPY_IO_HOOK_REMOVE。如果在安装Hook时,禁止了协议,Hook仍然会起作用,但是此时Hook Dispatcher将对所有捕获到的API调用不进行任何干扰。如果你不希望SPY_IO_HOOK_INSTALL修改Service Table后,协议就自动开始的话,你可以在安装Hook之前禁止Hook协议。注意,当协议被再次恢复时,协议将被自动重置。

 

 

IOCTL函数  SPY_IO_HOOK_FILTER

IOCTL函数SPY_IO_HOOK_FILTER维护一个全局标志,如列表5-15所示。这里,全局标志gfSpyHookFilter被设置为一个由客户提供的值,其先前的值将被返回给客户。该标志的默认值为FALSE;这意味着,默认情况下,过滤器是被禁止的。

 

BOOL SpyHookFilter (BOOL fFilter)

    {

    return (BOOL) InterlockedExchange ((PLONG) &gfSpyHookFilter,

                                       ( LONG) fFilter);

    }

列表5-15.  打开/关闭协议过滤器

 

在讨论列表5-8中的SpyWriteFilter()函数时,就已经涉及到gfSpyHookFilter,你应该对该变量不再陌生。如果gfSpyHookFilterTRUE,辅助函数SpyHookProtocol()(参见列表5-7)将忽略所有的API调用,这包括含有先前并未在Spy device中注册的句柄的API调用。

 

 

IOCTL函数  SPY_IO_HOOK_RESET

IOCTL函数SPY_IO_HOOK_RESET用于将协议机制恢复到原始状态,这包括清除数据缓冲区和“丢掉”所有已注册的句柄。由SpyDispatcher()调用的SpyHookReset()函数只是SpyWriteReset()的一个外包函数而已。这两个函数都包含在列表5-16中。SpyHookReset()的附加特性只是调用了使用mutexSpyHookWait()SpyHookRelease()函数(参见列表5-7)来进行同步。

void SpyWriteReset (PSPY_PROTOCOL psp)

{

    KeQuerySystemTime (&psp->sh.liStart);

 

    psp->sh.dRead    = 0;

    psp->sh.dWrite   = 0;

    psp->sh.dCalls   = 0;

    psp->sh.dHandles = 0;

    psp->sh.dName    = 0;

}

 

 

// -----------------------------------------------------------------

void SpyHookReset (void)

{

    SpyHookWait    ();

    SpyWriteReset  (&gpDeviceContext->SpyProtocol);

    SpyHookRelease ();

    return;

}

 

 

// -----------------------------------------------------------------

NTSTATUS SpyHookWait (void)

{

    return MUTEX_WAIT (gpDeviceContext->kmProtocol);

}

 

// -----------------------------------------------------------------

LONG SpyHookRelease (void)

{

    return MUTEX_RELEASE (gpDeviceContext->kmProtocol);

}

列表5-16.  重置协议

 

 

IOCTL函数  SPY_IO_HOOK_READ

API Hook记录器(logger)将协议数据写入abData[]缓冲区中,该缓冲区位于全局结构SPY_PROTOCOL中,该结构体已在列表5-9中给出。这种类型的缓冲区被设计为一个环形缓冲区。这意味着,其特点是使用一对指针来分别进行读/写访问。只要其中的一个指针移动到了缓冲区的尾端,它就会被重置并指向缓冲区的头部。读指针一直试图追上写指针,如果这两个指针指向相同地址,那意味着缓冲区为空。

 

SPY_IO_HOOK_READ是到目前为止,Spy Device提供的最重要的管理Hook的函数之一。它可以从协议数据缓冲区中读取任意大小的数据,并适当的调整读指针。在协议被允许时,该函数应该被频繁的调用,以避免缓冲区的溢出。列表5-17给出了处理此种IOCTL请求的一组函数。其中最基本的是SpyReadData()SpyReadLine()。二者的区别在于如果可能,前者将返回所请求的数据,而后者仅返回一整行数据。当客户端要对读取到的数据进行过滤时,行模式就显得很方便了。SPY_IO_HOOK_READ的调用者通过传入一个逻辑型变量来确定是读取方式是行模式还是块模式。

 

DWORD SpyReadData (PSPY_PROTOCOL psp,

                   PBYTE         pbData,

                   DWORD         dData)

{

    DWORD i = psp->sh.dRead;

    DWORD n = 0;

 

    while ((n < dData) && (i != psp->sh.dWrite))

        {

        pbData [n++] = psp->abData [i++];

        if (i == SPY_DATA_BUFFER) i = 0;

        }

    psp->sh.dRead = i;

    return n;

}

 

// -----------------------------------------------------------------

DWORD SpyReadLine (PSPY_PROTOCOL psp,

                   PBYTE         pbData,

                   DWORD         dData)

{

    BYTE  b = 0;

    DWORD i = psp->sh.dRead;

    DWORD n = 0;

 

    while ((b != '\n') && (i != psp->sh.dWrite))

    {

        b = psp->abData [i++];

        if (i == SPY_DATA_BUFFER) i = 0;

        if (n < dData) pbData [n++] = b;

    }

    if (b == '\n')

    {

        // remove current line from buffer

        psp->sh.dRead = i;

    }

    else

    {

        // don't return any data until full line available

        n = 0;

    }

    if (n)

    {

        pbData [n-1] = 0;

    }

    else

    {

        if (dData) pbData [0] = 0;

    }

    return n;

}

 

// -----------------------------------------------------------------

DWORD SpyHookRead (PBYTE pbData,

                   DWORD dData,

                   BOOL  fLine)

{

    DWORD n = 0;

 

    SpyHookWait ();

 

    n = (fLine ? SpyReadLine : SpyReadData)

            (&gpDeviceContext->SpyProtocol, pbData, dData);

 

    SpyHookRelease ();

    return n;

}

 

// -----------------------------------------------------------------

NTSTATUS SpyOutputHookRead (BOOL   fLine,

                            PVOID  pOutput,

                            DWORD  dOutput,

                            PDWORD pdInfo)

{

    *pdInfo = SpyHookRead (pOutput, dOutput, fLine);

    return STATUS_SUCCESS;

}

列表5-17.  从协议缓冲区中读取数据

 

SpyOutputHookRead()SpyHookRead()函数没有太大价值。SpyHookRead()使用了Mutex来进行同步,而且可以选择SpyReadLine()SpyReadData()