首页 运维 网络学院 查看内容

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

2005-7-6 16:57 584 0

摘要: 第五章 监控Native API调用 翻译:Kendiv( [email protected] ) 更新:Tue...
关键词: Windows 一个 函数 NtQuerylnformati NtSetlnformation 服务 API KeServiceDescrip TABLE SERVICE

第五章 监控Native API调用 翻译:Kendiv( [email protected] ) 更新:Tuesday, February 22, 2005 声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。 拦截系统调用在任何时候都是程序员们的最爱。这种大众化爱好的动机也是多种多样的:代码性能测试(Code Profiling)和优化,逆向工程,用户活动记录等等。所有这些都有一个共同的目的:将控制传递给一块特殊的代码,这样无论一个应用程序何时调用系统服务,都可以发现哪个服务被调用了,接收了什么参数,返回的结果是什么以及执行它花费了多少时间。根据最初由Mark Russinovich和Bryce Cogswell提出的技巧,本章将介绍一个可以hook任意Native API函数的通用框架。这里使用的方法完全是数据驱动(data-driven)的,因此,它可以很容易被扩展,并能适应其他Windows NT/2000版本。所有进程的API调用产生的数据都被写入一个环状缓冲区中,客户端程序可以通过设备I/O控制来读取该缓冲区。采用的数据协议(protocol data)的格式是以行为导向的ANSI文本流,它符合严格的格式化规则,应用程序可以很容易的再次处理它们(postprocessing)。为了示范此种客户端程序的基本框架,本章还提供了一个示例性的数据协议察看器,该程序运行于控制台窗口中。 译注: profiling 一般是指对程序做性能方面的测试, 主要是速度上的。 在翻译时,可译为:剖析,最好是根据上文环境进行翻译。 修改服务描述符表 对比“原始”的操作系统,如DOS或Windows 3.x,它们对程序员在API中加入hook的限制很少,而Win32系统,如Windows 2000/NT和Windows 9.x则很难驾驭,因为它们使用了巧妙的保护机制把不相关的代码分离出来。在Win32 API上设置一个系统范围的hook绝不是一个小任务。幸运的是,我们有像Matt Pietrek和Jeffery Richter这样的Win32向导,他们做了大量的工作来向我们展示如何完成这一任务,尽管事实上,并没有简单和优雅的解决方案。在1997年,Russinovich和Cogswell介绍了一种可在Windows NT上实现系统范围hook的完全不同的方法,可在更低一层上拦截系统调用(Russinovich和Cogswell 1997)。他们提议向Native API Dispatcher中注入日志机制,这仅比用户模式和内核模式之间的边界低一些,在这个位置上Windows NT暴露出一个“瓶颈”:所有用户模式的线程必须通过此处,才能使用操作系统内核提供的服务。 服务和参数表 就像在第二章讨论过的,发生在用户模式下的Native API调用必须通过INT 2eh接口,该接口提供一个i386的中断门来改变特权级别。你可能还记得所有INT 2eh调用都是由内部函数KiSystemService()在内核模式下处理的,该函数使用系统服务描述符表(SDT)来查找Native API处理例程的入口地址。图5-1给出了这种分派机制的基本组件之间的相互关系。列表5-1再次给出了SERVICE_DESCRIPTOR_TABLE结构及其子结构的正式定义,在第二章中,已经给出过它们的定义(列表2-1)。 调用KiSystemService()时,需提供两个参数,由INT 2eh的调用者通过EAX和EDX寄存器传入。EAX包含从0开始的索引,该索引可用于一个API函数指针的数组,EDX指向调用者的参数堆栈。KiSystemService()通过读取ServiceTable的一个成员的值(该成员是ntoskrnl.exe的一个公开数据结构:KeServiceDescriptorTable,图5-1的左面列出了该结构)来获取函数数组的基地址。实际上,KeServiceDescriptorTable指向一个包含四个服务表的结构,但默认情况下,仅有第一个服务表是有效的。KiSystemService()通过EAX中的索引值进入内部结构KiServiceTable,以查找可处理此API调用的函数的入口地址。在调用目标函数之前,KiSystemServie()以相同的方式查询KiArgumentTable结构,以找出调用者在参数堆栈中传入了多少字节,然后使用这个值将参数复制到当前内核堆栈中。此后,就只需要一个简单的汇编指令:CALL来执行API处理例程了。这里涉及的所有函数都符合__stdcall标准。 图5-1. KeServiceDescriptorTable的结构图 typedef NTSTATUS (NTAPI*NTPROC)(); typedef NTPROC* PNTPROC; #define NTPROC_ sizeof(NTPROC) typedef struct _SYSTEM_SERVICE_TABLE { PNTPROC ServiceTable; // array of entry points PDOWRD CounterTable; // array of usage counters DWORD ServiceLimit; // number of table entries PBYTE ArgumentTable; // array of byte counts } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE, **PPSYSTEM_SERVICE_TABLE; //----------------------------------------------------------------------------------------------------------- typedef struct _SERVICE_DESCRIPTOR_TABLE { SYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe ( native api ) SYSTEM_SERVICE_TABLE win32k; // win32k.sys (gdi/user support) SYSTEM_SERVICE_TABLE Table3; // not used SYSTEM_SERVICE_TABLE Table4; // not used } SYSTEM_DESCRIPTOR_TABLE, *PSYSTEM_DESCRIPTOR_TABLE, **PPSYSTEM_DESCRIPTOR_TABLE; 列表5-1. SERVICE_DESCRIPTOR_TABLE结构的定义 Windows 2000还提供了另一个服务描述符表参数块----KeServiceDescriptorTableShadow。不过,KeServiceDescriptorTable已经由ntoskrnl.exe公开的导出了,因此,内核模式的驱动程序可以很容易的访问它,而KeServiceDescriptorTableShadow则不行。在Windows 2000下,KeServiceDescriptorTableShadow紧随KeServiceDescriptorTable之后,但是你不能在Windows NT中以这样的方法找到它,因为,这一规则并不使用于Windows NT。可能在Windows 2000的后续版本的中,这种方法也不行。这两个参数块的不同之处在于:KeServiceDescriptorTableShadow中的第二个项被系统使用了,用来指向内部的W32pServiceTable和w32pArgumentTable结构,Win32的内核模式组件Win32K.sys使用这两个结构来分派自己的API调用,如图5-2所示。KiSystemService()通过检查EAX中索引值的第12和13位来确认是不是应该由Win32K.sys处理API调用。如果这两个位都是0,则是由ntoskrnl.exe处理的Native API调用,因此KiSystemService()使用第一个SDT。如果第12位为1并且第13位为0,KiSystemService()使用第二个SDT,这个SDT并没有被当前系统使用。这意味着Native API调用的索引值的潜在范围是:0x0000 --- 0x0FFFF,Win32K.sys调用使用的索引范围是:0x1000 --- 0x1FFF。因此,0x2000 --- 0x2FFF和0x3000 --- 0x3FFF保留给剩下的两个SDT。在Windows 2000中,Native API服务表包含248个项,Win32K.sys表包含639个项。 图5-2. KeServiceDescriptorTableShadow的结构图 Russinovich和Cogswell的独具特色的方法是:通过简单的向KiServiceTable数组中放入一个不同的处理例程来hook所有API调用。这个处理例程最终会调用位于ntoskrnl.exe中的原始处理例程,但它有机会察看一下被调用函数的输入/输出参数。这个方法非常强大却又如此简单。因为所有用户模式的线程必须经过这个“针眼”才能获得Native API的服务,安装一个全局hook来简单的替换一个函数指针的方法,在启动一个新的进程和线程的情况下,也能很稳定的工作。这并不需要一种通讯机制来通知新加入或将要移除的进程/线程。 不幸的是,系统服务表在不同Windows NT版本上不相同。表5-1比较了Windows NT/2000的KiServiceTable。很显然,不仅是处理例程的号码从211增加到了248,而且新的处理例程并不是直接添加到列表的末尾,而是被插入到了各个地方!因此,一个服务函数索引,如0x20在Windows 2000中指向NtCreateFile(),而在Windows NT中却指向NtCreateProfile()。所以,通过操作服务函数表进行hook的API调用监控器必须小心的检查它所在的Windows NT的版本。这可以通过如下几个方式来完成: l 一种可能性是,检查由ntoskrnl.exe导出的公开变量:NtBuildNumber,就像Russinovich和Cogswell在他们的原文中所作的那样。Windows NT 4.0为所有Service Pack提供的Build Number是:1381。Windows 2000的当前Build Number是:2195。看来有希望,这个版本号在Windows NT的早期版本中很稳定。 l 另一个可能性是,检查SharedUserData结构中的NtMajorVersion和NtMinorVersion成员,该结构定义与Windows 2000头文件ntddk.h中。Windows NT 4.0的所有Service Pack都将SharedUserData->NtMajorVersion设为4,将SharedUserData->NtMinorVersion设为0。Windows 2000的当前版本为Windows NT Version 5.0。 l 本章给出的代码采用了另一中替代方法:它测试SDT的ServiceLimit成员是否和它的预期值相匹配,该预期值是211(0xD3)针对Windows NT 4.0和248(0xF8)针对Windows 2000。 表5-1. Windows 2000/NT 服务表对比 Windows 2000 索引 Windows NT 4.0 NtAcceptConnectPort 0x00 NtAcceptConnectPort NtAccessCheck 0x01 NtAccessCheck NtAccessCheckAndAuditAlarm 0x02 NtAccessCheckAndAuditAlarm NtAccessCheckByType 0x03 NtAddAtom NtAccessCheckByTypeAndAuditAlarm 0x04 NtAdjustGroupsToken NtAccessCheckByTypeResultList 0x05 NtAdjustPrivilegesToken NtAccessCheckByTypeResultListAndAuditAlarm 0x06 NtAlertResumeThread NtAccessCheckByTypeResultListAndAuditAlarmByHandle 0x07 NtAlertThread NtAddAtom 0x08 NtAllocateLocallyUniqueld NtAdjustGroupsToken 0x09 NtAllocateUuids NtAdjustPrivilegesToken 0x0A NtAllocateVirtualMemory NtAlertResumeThread 0x0B NtCallbackReturn NtAlertThread 0x0C NtCancelloFile NtAllocateLocallyUniqueld 0x0D NtCancelTimer NtAllocateUserPhysicalPages 0x0E NtClearEvent NtAllocateUuids 0x0F NtClose NtAllocateVirtualMemory 0x10 NtCloseObjectAuditAlarm NtAreMappedFilesTheSame 0x11 NtCompleteConnectPort NtAssignProcessToJobObject 0x12 NtConnectPort NtCallbackReturn 0x13 NtContinue NtCancelloFile 0x14 NtCreateDirectoryObject NtCancelTi mer 0x15 NtCreateEvent NtCancelDeviceWakeupRequest 0x16 NtCreateEventPair NtClearEvent 0x17 NtCreateFile NtClose 0x18 NtCreateloCompletion NtCloseObjectAuditAlarm 0x19 NtCreateKey NtCompleteConnectPort 0x1A NtCreateMailslotFile NtConnectPort 0x1B NtCreateMutant NtContinue 0x1C NtCreateNamedPipeFile NtCreateDirectoryObject 0x1D NtCreatePagingFile NtCreateEvent 0x1E NtCreatePort NtCreateEventPair 0x1F NtCreateProcess NtCreateFile 0x20 NtCreateProfile NtCreateloCompletion 0x21 NtCreateSection NtCreateJobObject 0x22 NtCreateSemaphore NtCreateKey 0x23 NtCreateSymbolicLinkObject NtCreateMailslotFile 0x24 NtCreateThread NtCreateMutant 0x25 NtCreateTimer NtCreateNamedPipeFile 0x26 NtCreateToken NtCreatePagingFile 0x27 NtDelayExecution NtCreatePort 0x28 NtDeleteAtom NtCreateProcess 0x29 NtDeleteFile NtCreateProfile 0x2A NtDeleteKey NtCreateSection 0x2B NtDeleteObjectAuditAlarm NtCreateSemaphore 0x2C NtDeleteValueKey NtCreateSymbolicLinkObject 0x2D NtDeviceloControlFile NtCreateThread 0x2E NtDisplayString NtCreateTimer 0x2F NtDuplicateObject NtCreateToken 0x30 NtDuplicateToken NtCreateWaitablePort 0x31 NtEnumerateKey NtDelayExecution 0x32 NtEnumerateValueKey NtDeleteAtom 0x33 NtExtendSection NtDeleteFile 0x34 NtFindAtom NtDeleteKey 0x35 NtFlushBuffersFile NtDeleteObj ectAuditAlarm 0x36 NtFlushlnstructionCache NtDeleteValueKey 0x37 NtFlushKey NtDeviceloControlFile 0x38 NtFlushVirtualMemory NtDisplayString 0x39 NtFlushWriteBuffer NtDuplicateObject 0x3A NtFreeVirtualMemory NtDuplicateToken 0x3B NtFsControlFile NtEnumerateKey 0x3C NtGetContextThread NtEnumerateValueKey 0x3D NtGetPlugPlayEvent NtExtendSection 0x3E NtGetTickCount NtFilterToken 0x3F NtlmpersonateClientOfPort NtFindAtom 0x40 NtlmpersonateThread NtFlushBuffersFile 0x41 NtlnitializeRegistry NtFlushlnstructionCache 0x42 NtListenPort NtFlushKey 0x43 NtLoadDriver NtFlushVirtualMemory 0x44 NtLoadKey NtFlushWriteBuffer 0x45 NtLoadKey2 NtFreeUserPhysicalPages 0x46 NtLockFile NtFreeVirtualMemory 0x47 NtLockVirtualMemory NtFsControlFile 0x48 NtMakeTemporaryObject NtGetContextThread 0x49 NtMapViewOfSection NtGetDevicePowerState 0x4A NtNotifyChangeDirectoryFile NtGetPlugPlayEvent 0x4B NtNotifyChangeKey NtGetTickCount 0x4C NtOpenDirectoryObject NtGetWriteWatch 0x4D NtOpenEvent NtlmpersonateAnonymousToken 0x4E NtOpenEventPair NtlmpersonateClientOfPort 0x4F NtOpenFile NtlmpersonateThread 0x50 NtOpenloCompletion NtlnitializeRegistry 0x51 NtOpenKey NtlnitiatePowerAction 0x52 NtOpenMutant NtlsSystemResumeAutomatic 0x53 NtOpenObjectAuditAlarm NtListenPort 0x54 NtOpenProcess NtLoadDriver 0x55 NtOpenProcessToken NtLoadKey 0x56 NtOpenSection NtLoadKey2 0x57 NtOpenSemaphore NtLockFile 0x58 NtOpenSymbolicLinkObject NtLockVirtualMemory 0x59 NtOpenThread NtMakeTemporaryObject 0x5A NtOpenThreadToken NtMapUserPhysicalPages 0x5B NtOpenTimer NtMapUserPhysicalPagesScatter 0x5C NtPlugPlayControl NtMapViewOfSection 0x5D NtPrivilegeCheck NtNotifyChangeDirectoryFile 0x5E NtPrivilegedServiceAuditAlarm NtNotifyChangeKey 0x5F NtPrivilegeObjectAuditAlarm NtNotifyChangeMultipleKeys 0x60 NtProtectVirtualMemory NtOpenDirectoryObject 0x61 NtPulseEvent NtOpenEvent 0x62 NtQuerylnformationAtom NtOpenEventPair 0x63 NtQueryAttributesFile NtOpenFile 0x64 NtQueryDefaultLocale NtOpenloCompletion 0x65 NtQueryDirectoryFile NtOpenJobObject 0x66 NtQueryDirectoryObject NtOpenKey 0x67 NtQueryEaFile NtOpenMutant 0x68 NtQueryEvent NtOpenObjectAuditAlarm 0x69 NtQueryFullAttributesFile NtOpenProcess 0x6A NtQuerylnformationFile NtOpenProcessToken 0x6B NtQueryloCompletion NtOpenSection 0x6C NtQuerylnformationPort NtOpenSemaphore 0x6D NtQuerylnformationProcess NtOpenSymbolicLinkObject 0x6E NtQuerylnformationThread NtOpenThread 0x6F NtQuerylnformationToken NtOpenThreadToken 0x70 NtQuerylntervalProfile NtOpenTimer 0x71 NtQueryKey NtPlugPlayControl 0x72 NtQueryMultipleValueKey NtPowerlnformation 0x73 NtQueryMutant NtPrivilegeCheck 0x74 NtQueryObject NtPrivilegedServiceAuditAlarm 0x75 NtQueryOleDirectoryFile NtPrivilegeObjectAuditAlarm 0x76 NtQueryPerformanceCounter NtProtectVirtualMemory 0x77 NtQuerySection NtPulseEvent 0x78 NtQuerySecurityObject NtQuerylnformationAtom 0x79 NtQuery Semaphore NtQueryAttributesFile 0x7A NtQuerySymbolicLinkObject NtQueryDefaultLocale 0x7B NtQuerySystemEnvironmentValue NtQueryDefaultUILanguage 0x7C NtQuerySystemlnformation NtQueryDirectoryFile 0x7D NtQuerySystemTime NtQueryDirectoryObject 0x7E NtQuery Timer NtQueryEaFile 0x7F NtQueryTimerResolution NtQueryEvent 0x80 NtQuery ValueKey NtQueryFullAttributesFile 0x81 NtQuery VirtualMemory NtQuerylnformationFile 0x82 NtQuery VolumelnformationFile NtQuerylnformationJobObject 0x83 NtQueueApcThread NtQueryloCompletion 0x84 NtRaiseException NtQuerylnformationPort 0x85 NtRaiseHardError NtQuerylnformationProcess 0x86 NtReadFile NtQuerylnformationThread 0x87 NtReadFileScatter NtQuerylnformationToken 0x88 NtReadRequestData NtQuerylnstallUILanguage 0x89 NtReadVirtualMemory NtQuerylntervalProfile 0x8A NtRegisterThreadTerminatePort NtQueryKey 0x8B NtReleaseMutant NtQueryMultiple ValueKey 0x8C NtReleaseSemaphore NtQueryMutant 0x8D NtRemoveloCompletion NtQueryObject 0x8E NtReplaceKey NtQueryOpenSubKeys 0x8F NtReplyPort NtQueryPerformanceCounter 0x90 NtReplyWaitReceivePort NtQueryQuotalnformationFile 0x91 NtReplyWaitReplyPort NtQuerySection 0x92 NtRequestPort NtQuerySecurityObject 0x93 NtRequestWaitReplyPort NtQuerySemaphore 0x94 NtResetEvent NtQuerySymbolicLinkObject 0x95 NtRestoreKey NtQuerySystemEnvironmentValue 0x96 NtResumeThread NtQuerySystemlnformation 0x97 NtSaveKey NtQuerySystemTime 0x98 NtSetloCompletion NtQueryTimer 0x99 NtSetContextThread NtQueryTimerResolution 0x9A NtSetDefaultHardErrorPort NtQueryValueKey 0x9B NtSetDefaultLocale NtQueryVirtualMemory 0x9C NtSetEaFile NtQueryVolumelnformationFile 0x9D NtSetEvent NtQueueApcThread 0x9E NtSetHighEventPair NtRaiseException 0x9F NtSetHighWaitLowEventPair NtRaiseHardError 0xA0 NtSetHighWaitLowThread NtReadFile 0xA1 NtSetlnformationFile NtReadFileScatter 0xA2 NtSetlnformationKey NtReadRequestData 0xA3 NtSetlnformationObject NtReadVirtualMemory 0xA4 NtSetlnformationProcess NtRegisterThreadTerminatePort 0xA5 NtSetlnformationThread NtReleaseMutant 0xA6 NtSetlnformationToken NtReleaseSemaphore 0xA7 NtSetlntervalProfile NtRemoveloCompletion 0xA8 NtSetLdtEntries NtReplaceKey 0xA9 NtSetLowEventPair NtReplyPort 0xAA NtSetLowWaitHighEventPair NtReplyWaitReceivePort 0xAB NtSetLowWaitHighThread NtReplyWaitReceivePortEx 0xAC NtSetSecurity Object NtReplyWaitRepiyPort 0xAD NtSetSystemEnvironmentValue NtRequestDeviceWakeup 0xAE NtSetSystemlnformation NtRequestPort 0xAF NtSetSystemPowerState NtRequestWaitReplyPort 0xB0 NtSetSystemTime NtRequestWakeupLatency 0xB1 NtSetTimer NtResetEvent 0xB2 NtSetTimerResolution NtResetWriteWatch 0xB3 NtSetValueKey NtRestoreKey 0xB4 NtSetVolumelnformationFile NtResumeThread 0xB5 NtShutdownSystem NtSaveKey 0xB6 NtSignalAndWaitForSingleObject NtSaveMergedKeys 0xB7 NtStartProfile NtSecureConnectPort 0xB8 NtStopProfile NtSetloCompletion 0xB9 NtSuspendThread NtSetContextThread 0xBA NtSystemDebugControl NtSetDefaultHardErrorPort 0xBB NtTerminateProcess NtSetDefaultLocale 0xBC NtTerminateThread NtSetDefaultUILanguage 0xBD NtTestAlert NtSetEaFile 0xBE NtUnloadDriver NtSetEvent 0xBF NtUnloadKey NtSetHighEventPair 0xC0 NtUnlockFile NtSetHighWaitLowEventPair 0xC1 NtUnlockVirtualMemory NtSetlnformationFile 0xC2 NtUnmapViewOfSection NtSetlnformationJobObject 0xC3 NtVdmControl NtSetlnformationKey 0xC4 NtWaitForMultipleObjects NtSetlnformationObject 0xC5 NtWaitForSingleObject NtSetlnformationProcess 0xC6 NtWaitHighEventPair NtSetlnformationThread 0xC7 NtWaitLowEventPair NtSetlnformationToken 0xC8 NtWriteFile NtSetlntervalProfile 0xC9 NtWriteFileGather NtSetLdtEntries 0xCA NtWriteRequestData NtSetLowEventPair 0xCB NtWriteVirtualMemory NtSetLowWaitHighEventPair 0xCC NtCreateChannel NtSetQuotalnformationFile 0xCD NtListenChannel NtSetSecurity O b j ect 0xCE NtOpenChannel NtSetSystemEnvironment Value 0xCF NtReplyWaitSendChannel NtSetSystemlnformation 0xD0 NtSendWaitReplyChannel NtSetSystemPowerSrate 0xD1 NtSetContextChannel NtSetSystemTime 0xD2 NtYieldExecution NtSetThreadExecutionState 0xD3 N/A NtSetTimer 0xD4 N/A NtSetTimerResolution 0xD5 N/A NtSetUuidSeed 0xD6 N/A NtSetValueKey 0xD7 N/A NtSetVolumelnformationFile 0xD8 N/A NtShutdownSystem 0xD9 N/A NtSignalAndWaitForSingleObject 0xDA N/A NtStartProfile 0xDB N/A NtStopProfile 0xDC N/A NtSuspendThread 0xDD N/A NtSystemDebugControl 0xDE N/A NtTerminateJobObject 0xDF N/A NtTerminateProcess 0xE0 N/A NtTerminateThread 0xE1 N/A NtTestAlert 0xE2 N/A NtUnloadDriver 0xE3 N/A NtUnloadKey 0xE4 N/A NtUnlockFile 0xE5 N/A NtUnlockVirtualMemory 0xE6 N/A NtUnmapViewOfSection 0xE7 N/A NtVdmControl 0xE8 N/A NtWaitForMultipleObjects 0xE9 N/A NtWaitForSingleObject 0xEA N/A NtWaitHighEventPair 0xEB N/A NtWaitLowEventPair 0xEC N/A NtWriteFile 0xED N/A NtWriteFileGather 0xEE N/A NtWriteRequestData 0xEF N/A NtWriteVirtualMemory 0xF0 N/A NtCreateChannel 0xF1 N/A NtListenChannel 0xF2 N/A NtOpenChannel 0xF3 N/A NtReplyWaitSendChannel 0xF4 N/A NtSendWaitReplyChannel 0xF5 N/A NtSetContextChannel 0xF6 N/A NtYieldExecution 0xF7 N/A Russinoich和Cogewell采用的最重要的一步是:编写一个内核模式的设备驱动程序来安装和维护Native API Hook。因为,用户模式下的模块没有修改系统服务描述符表的权限。就像第四章中的Spy驱动程序,这是一种多少有些特殊的驱动程序,因为它不处理通常的I/O请求。它只是导出一个简单的设备I/O控制(IOCTL)接口,以让用户模式下的代码访问它收集到的数据。该驱动程序的主要任务是修改KiServiceTable、拦截并记录所选的Windows 2000 Native API调用。尽管这种方法很简单而且优雅,它还是有些让人担心。它的简单使我想起了在DOS时代,hook一个系统服务只需要简单的修改处理器的中断向量表中的指针。任何知道如何编写基本的Windows 2000内核驱动程序的人都可以hook任意的NT系统服务而不需要而外的努力。 Russinovich和Cogswell使用他们的技术开发了一个非常有用的Windows NT注册表监视器。当使用他们的技术来完成其他“间谍”任务时,我很快就变得烦躁起来,这是因为我需要为我要监控的每个API函数都编写一个独立的hook API函数。为了避免编写大量的代码,我打算找出一种方法来强迫所有我感兴趣的API函数进入同一个hook函数中。这个任务花费了我大量的时间,并给我展示了多种多样的蓝屏。不过,最终的结果是我得到了一个通用的解决方案,只需花费很少的努力,我就能hook不同的API函数集合。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部