《Undocumented Windows 2000 Secrets》翻译 --- 第五章(5)

第五章  监控Native API调用

翻译:Kendiv( [email protected] )

更新:Tuesday, April 19, 2005

 

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

 

在用户模式下控制API Hooks

运行在用户模式的Spy客户端可通过一组IOCTL函数来控制API Hook机制及其生成的协议。这一组函数的名字都以SPY_IO_HOOK_开始,在第四章已介绍过它们,在第四章还讨论了w2k_spy.sys的内存Spy函数(参见列表4-74-2)。

 

下面的5-3再次给出了与4-2相关的部分。列表5-10列表4-7的一个摘录,示范了Hook管理函数是如何被分派(dispatch)的。这些管理函数在后面将会被反复提及。

 

5-3.   Spy Device支持的IOCTL Hook管理函数

函数名称

ID

IOCTL代码

  

SPY_IO_HOOK_INFO

11

0x 8000602C

返回Native API Hook的相关信息

SPY_IO_HOOK_INSTALL

12

0x8000E030

安装Native API Hook

SPY_IO_HOOK_REMOVE

13

0x8000 E034

移除Native API Hook

SPY_IO_HOOK_PAUSE

14

0x8000 E038

暂停/恢复 Hook协议

SPY_IO_HOOK_FILTER

15

0x8000 E 03C

允许/禁止 Hook协议过滤器

SPY_IO_HOOK_RESET

16

0x8000 E040

清除Hook协议

SPY_IO_HOOK_READ

17

0x80006044

Hook协议中读取数据

SPY_IO_HOOK_WRITE

18

0x8000E048

Hook协议中写入数据

 

NTSTATUS SpyDispatcher (PDEVICE_CONTEXT pDeviceContext,

                        DWORD           dCode,

                        PVOID           pInput,

                        DWORD           dInput,

                        PVOID           pOutput,

                        DWORD           dOutput,

                        PDWORD          pdInfo)

    {

    SPY_MEMORY_BLOCK smb;

    SPY_PAGE_ENTRY   spe;

    SPY_CALL_INPUT   sci;

    PHYSICAL_ADDRESS pa;

    DWORD            dValue, dCount;

    BOOL             fReset, fPause, fFilter, fLine;

    PVOID            pAddress;

    PBYTE            pbName;

    HANDLE           hObject;

    NTSTATUS         ns = STATUS_INVALID_PARAMETER;

 

    MUTEX_WAIT (pDeviceContext->kmDispatch);

 

    *pdInfo = 0;

 

    switch (dCode)

        {

        case SPY_IO_VERSION_INFO:

            {

            ns = SpyOutputVersionInfo (pOutput, dOutput, pdInfo);

            break;

            }

        case SPY_IO_OS_INFO:

            {

            ns = SpyOutputOsInfo (pOutput, dOutput, pdInfo);

            break;

            }

        case SPY_IO_SEGMENT:

            {

            if ((ns = SpyInputDword (&dValue,

                                     pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputSegment (dValue,

                                       pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_INTERRUPT:

            {

            if ((ns = SpyInputDword (&dValue,

                                     pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputInterrupt (dValue,

                                         pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_PHYSICAL:

            {

            if ((ns = SpyInputPointer (&pAddress,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                pa = MmGetPhysicalAddress (pAddress);

 

                ns = SpyOutputBinary (&pa, PHYSICAL_ADDRESS_,

                                      pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_CPU_INFO:

            {

            ns = SpyOutputCpuInfo (pOutput, dOutput, pdInfo);

            break;

            }

        case SPY_IO_PDE_ARRAY:

            {

            ns = SpyOutputBinary (X86_PDE_ARRAY, SPY_PDE_ARRAY_,

                                  pOutput, dOutput, pdInfo);

            break;

            }

        case SPY_IO_PAGE_ENTRY:

            {

            if ((ns = SpyInputPointer (&pAddress,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                SpyMemoryPageEntry (pAddress, &spe);

 

                ns = SpyOutputBinary (&spe, SPY_PAGE_ENTRY_,

                                      pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_MEMORY_DATA:

            {

            if ((ns = SpyInputMemory (&smb,

                                      pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputMemory (&smb,

                                      pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_MEMORY_BLOCK:

            {

            if ((ns = SpyInputMemory (&smb,

                                      pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputBlock (&smb,

                                     pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HANDLE_INFO:

            {

            if ((ns = SpyInputHandle (&hObject,

                                      pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputHandleInfo (hObject,

                                          pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_INFO:

            {

            ns = SpyOutputHookInfo (pOutput, dOutput, pdInfo);

            break;

            }

        case SPY_IO_HOOK_INSTALL:

            {

            if (((ns = SpyInputBool (&fReset,

                                     pInput, dInput))

                 == STATUS_SUCCESS)

                &&

                ((ns = SpyHookInstall (fReset, &dCount))

                 == STATUS_SUCCESS))

                {

                ns = SpyOutputDword (dCount,

                                     pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_REMOVE:

            {

            if (((ns = SpyInputBool (&fReset,

                                     pInput, dInput))

                 == STATUS_SUCCESS)

                &&

                ((ns = SpyHookRemove (fReset, &dCount))

                 == STATUS_SUCCESS))

                {

                ns = SpyOutputDword (dCount,

                                     pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_PAUSE:

            {

            if ((ns = SpyInputBool (&fPause,

                                    pInput, dInput))

                == STATUS_SUCCESS)

                {

                fPause = SpyHookPause (fPause);

 

                ns = SpyOutputBool (fPause,

                                    pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_FILTER:

            {

            if ((ns = SpyInputBool (&fFilter,

                                    pInput, dInput))

                == STATUS_SUCCESS)

                {

                fFilter = SpyHookFilter (fFilter);

 

                ns = SpyOutputBool (fFilter,

                                    pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_RESET:

            {

            SpyHookReset ();

            ns = STATUS_SUCCESS;

            break;

            }

        case SPY_IO_HOOK_READ:

            {

            if ((ns = SpyInputBool (&fLine,

                                    pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputHookRead (fLine,

                                        pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_HOOK_WRITE:

            {

            SpyHookWrite (pInput, dInput);

            ns = STATUS_SUCCESS;

            break;

            }

        case SPY_IO_MODULE_INFO:

            {

            if ((ns = SpyInputPointer (&pbName,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputModuleInfo (pbName,

                                          pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_PE_HEADER:

            {

            if ((ns = SpyInputPointer (&pAddress,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputPeHeader (pAddress,

                                        pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_PE_EXPORT:

            {

            if ((ns = SpyInputPointer (&pAddress,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputPeExport (pAddress,

                                        pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_PE_SYMBOL:

            {

            if ((ns = SpyInputPointer (&pbName,

                                       pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputPeSymbol (pbName,

                                        pOutput, dOutput, pdInfo);

                }

            break;

            }

        case SPY_IO_CALL:

            {

            if ((ns = SpyInputBinary (&sci, SPY_CALL_INPUT_,

                                      pInput, dInput))

                == STATUS_SUCCESS)

                {

                ns = SpyOutputCall (&sci,

                                    pOutput, dOutput, pdInfo);

                }

            break;

            }

        }

    MUTEX_RELEASE (pDeviceContext->kmDispatch);

    return ns;

    }

列表5-10.  Spy DriverHook命令分派器

 

 

IOCTL函数  SPY_IO_HOOK_INFO

IOCTL函数SPY_IO_HOOK_INFO采用Hook机制的当前信息来填充一个SPY_HOOK_INFO结构,这和系统的SDT类似。SPY_HOOK_INFO结构(列表5-11)中引用了多个前面介绍过的结构:

l         SERVICE_DESCRIPTOR_TABLE结构,定义于列表5-1

l         SPY_CALLSPY_HOOK_ENTRY结构,定义于列表5-2

l         SPY_HEADERSPY_PROTOCOL结构,定义于列表5-9

 

typedef struct _SPY_HOOK_INFO

    {

        SPY_HEADER                   sh;

        PSPY_CALL                     psc;

        PSPY_PROTOCOL                psp;

        PSERVICE_DESCRIPTOR_TABLE   psdt;

        SERVICE_DESCRIPTOR_TABLE    sdt;

        DWORD                         ServiceLimit;

        NTPROC                         ServiceTable  [SDT_SYMBOLS_MAX];

        BYTE                           ArgumentTable [SDT_SYMBOLS_MAX];

        SPY_HOOK_ENTRY               SpyHooks    [SDT_SYMBOLS_MAX];

    }

    SPY_HOOK_INFO, *PSPY_HOOK_INFO, **PPSPY_HOOK_INFO;

 

#define SPY_HOOK_INFO_ sizeof (SPY_HOOK_INFO)

列表5-11.  SPY_HOOK_INFO结构定义

 

在计算该结构体成员的值时一定要小心。某些成员中的指针指向内核模式下的内存块,这些内存地址在用户模式下是无法访问的。不过,你可以使用Spy设备的SPY_IO_MEMORY_DATA函数来检查这些内存块中的数据。

 

 

IOCTL函数  SPY_IO_HOOK_INSTALL

SPY_IO_HOOK_INSTALL函数使用存储在全局aSpyHooks[]数组中的Hook进入点(Hook Entry Point)来修改(patchntoskrnl.exe在系统SDT中的服务表(Service Table)。该全局数组在驱动程序初始化时由SpyHookInitialize()(列表5-5)SpyHookInitializeEx()(列表5-3)函数构建。aSpyHooks[]数组中的每个有效的元素均包含一个hook进入点以及相应的格式字符串地址。SpyDispatcher()调用辅助函数SpyHookInstall()(见列表5-12)来安装HookSpyHookInstall()使用的SpyHookExchange()函数也包含在列表5-12中。

 

 

DWORD SpyHookExchange (void)

    {

    PNTPROC ServiceTable;

    BOOL    fPause;

    DWORD   i;

    DWORD   n = 0;

 

    fPause     = SpyHookPause (TRUE);

    ServiceTable = KeServiceDescriptorTable->ntoskrnl.ServiceTable;

 

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

        {

        if (aSpyHooks [i].pbFormat != NULL)

            {

            aSpyHooks [i].Handler = (NTPROC)

                InterlockedExchange ((PLONG) ServiceTable+i,

                                     ( LONG) aSpyHooks [i].Handler);

            n++;

            }

        }

    gfSpyHookState = !gfSpyHookState;

    SpyHookPause (fPause);

    return n;

    }

 

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

 

NTSTATUS SpyHookInstall (BOOL   fReset,

                         PDWORD pdCount)

    {

    DWORD    n  = 0;

    NTSTATUS ns = STATUS_INVALID_DEVICE_STATE;

 

    if (!gfSpyHookState)

        {

        ghSpyHookThread = PsGetCurrentThreadId ();

 

        n = SpyHookExchange ();

        if (fReset) SpyHookReset ();

 

        ns = STATUS_SUCCESS;

        }

    *pdCount = n;

    return ns;

    }

列表5-12.  Patch the System’s API Service Table

 

在安装和移除Hooks时都需要用到SpyHookExchange()函数,该函数只是简单的交换系统的API服务表和aSpyHooks[]数组中的内容。因此,若调用两次SpyHookExchange(),则可恢复服务表和数组的初始状态。SpyHookExchange()遍历aSpyHooks[]数组来寻找包含格式字符串指针的数组元素。这里的格式字符串是为了指定要监控的API函数。在这种情况下,将使用ntoskrnl.exe中的InterlockedExchange()函数来交换服务表中的API函数指针和aSpyHooks[]元素的Handler成员,使用InterlockedExchange()函数是为了保证没有其他线程干扰这一操作。协议机制在这一过程中将被临时停止,直到对服务表的修改结束。SpyHookInstall()仅是SpyHookExchange()的一个外包函数,这样做是为了执行一些附加的操作:

l         如果全局标志gfSpyHookState表示Hooks仍在安装,则禁止访问服务表(Service Table)。

 

l         调用者的线程ID将被写入全局变量ghSpyHookThreadSpyHookInitializeEx()函数中的Hook分派器(Dispatcher)将屏蔽该变量所指线程发出的API调用。以避免Hook协议受到干扰。

 

l         根据客户端的请求,协议会被重置。这意味着所有的缓冲区都将被清空,并且句柄目录也将被重新初始化。

 

SPY_IO_HOOK_INSTALL接收调用者传入的一个逻辑型参数。如果为TRUE,协议将在Hooks安装完成后被重置。这是常用的一个选项。如果为FALSE,协议将从前一次Hook会话结束的位置继续。该函数的返回值表示服务表中被修改的项数。如果是Windows 2000SPY_IO_HOOK_INSTALL返回的是44,这一数值正是列表5-6给出的格式字符串数组apdSdtFormats[]的大小。在Windows NT 4.0下,则仅有42Hook被安装,因为API函数NtNotifyChangeMultipleKeys()NtQueryOpenSubKeys()并不被NT 4.0支持。

 

 

…………待续…………..

你可能感兴趣的:(《Undocumented Windows 2000 Secrets》翻译 --- 第五章(5))