// __________________________________________________________ // // w2k_spy.c // SBS Windows 2000 Spy Device V1.00 // 08-27-2000 Sven B. Schreiber // sbs@orgon.com // __________________________________________________________ #define _W2K_SPY_SYS_ #include #include "w2k_spy.h" // ================================================================= // DISCLAIMER // ================================================================= /* This software is provided "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the author Sven B. Schreiber be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. */ // ================================================================= // REVISION HISTORY // ================================================================= /* 08-27-2000 V1.00 Original version (SBS). */ // ================================================================= // EXTERNAL VARIABLES // ================================================================= extern PWORD NlsAnsiCodePage; extern PWORD NlsOemCodePage; extern PWORD NtBuildNumber; extern PDWORD NtGlobalFlag; extern PDWORD KeI386MachineType; extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; // ================================================================= // GLOBAL DATA // ================================================================= PRESET_UNICODE_STRING (usDeviceName, CSTRING (DRV_DEVICE)); PRESET_UNICODE_STRING (usSymbolicLinkName, CSTRING (DRV_LINK )); PDEVICE_OBJECT gpDeviceObject = NULL; PDEVICE_CONTEXT gpDeviceContext = NULL; BOOL gfSpyHookState = FALSE; BOOL gfSpyHookPause = FALSE; BOOL gfSpyHookFilter = FALSE; HANDLE ghSpyHookThread = 0; BYTE abHex [] = "0123456789ABCDEF"; // ================================================================= // DISCARDABLE FUNCTIONS // ================================================================= NTSTATUS DriverInitialize (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pusRegistryPath); NTSTATUS DriverEntry (PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pusRegistryPath); // ----------------------------------------------------------------- #ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverInitialize) #pragma alloc_text (INIT, DriverEntry) #endif // ================================================================= // WINDOWS NT 4.0 SYSTEM SERVICE NAMES // ================================================================= // number of entries must match SDT_SYMBOLS_NT4 in w2k_spy.h PBYTE apbSdtSymbolsNT4 [] = { "NtAcceptConnectPort", "NtAccessCheck", "NtAccessCheckAndAuditAlarm", "NtAddAtom", "NtAdjustGroupsToken", "NtAdjustPrivilegesToken", "NtAlertResumeThread", "NtAlertThread", "NtAllocateLocallyUniqueId", "NtAllocateUuids", "NtAllocateVirtualMemory", "NtCallbackReturn", "NtCancelIoFile", "NtCancelTimer", "NtClearEvent", "NtClose", "NtCloseObjectAuditAlarm", "NtCompleteConnectPort", "NtConnectPort", "NtContinue", "NtCreateDirectoryObject", "NtCreateEvent", "NtCreateEventPair", "NtCreateFile", "NtCreateIoCompletion", "NtCreateKey", "NtCreateMailslotFile", "NtCreateMutant", "NtCreateNamedPipeFile", "NtCreatePagingFile", "NtCreatePort", "NtCreateProcess", "NtCreateProfile", "NtCreateSection", "NtCreateSemaphore", "NtCreateSymbolicLinkObject", "NtCreateThread", "NtCreateTimer", "NtCreateToken", "NtDelayExecution", "NtDeleteAtom", "NtDeleteFile", "NtDeleteKey", "NtDeleteObjectAuditAlarm", "NtDeleteValueKey", "NtDeviceIoControlFile", "NtDisplayString", "NtDuplicateObject", "NtDuplicateToken", "NtEnumerateKey", "NtEnumerateValueKey", "NtExtendSection", "NtFindAtom", "NtFlushBuffersFile", "NtFlushInstructionCache", "NtFlushKey", "NtFlushVirtualMemory", "NtFlushWriteBuffer", "NtFreeVirtualMemory", "NtFsControlFile", "NtGetContextThread", "NtGetPlugPlayEvent", "NtGetTickCount", "NtImpersonateClientOfPort", "NtImpersonateThread", "NtInitializeRegistry", "NtListenPort", "NtLoadDriver", "NtLoadKey", "NtLoadKey2", "NtLockFile", "NtLockVirtualMemory", "NtMakeTemporaryObject", "NtMapViewOfSection", "NtNotifyChangeDirectoryFile", "NtNotifyChangeKey", "NtOpenDirectoryObject", "NtOpenEvent", "NtOpenEventPair", "NtOpenFile", "NtOpenIoCompletion", "NtOpenKey", "NtOpenMutant", "NtOpenObjectAuditAlarm", "NtOpenProcess", "NtOpenProcessToken", "NtOpenSection", "NtOpenSemaphore", "NtOpenSymbolicLinkObject", "NtOpenThread", "NtOpenThreadToken", "NtOpenTimer", "NtPlugPlayControl", "NtPrivilegeCheck", "NtPrivilegedServiceAuditAlarm", "NtPrivilegeObjectAuditAlarm", "NtProtectVirtualMemory", "NtPulseEvent", "NtQueryInformationAtom", "NtQueryAttributesFile", "NtQueryDefaultLocale", "NtQueryDirectoryFile", "NtQueryDirectoryObject", "NtQueryEaFile", "NtQueryEvent", "NtQueryFullAttributesFile", "NtQueryInformationFile", "NtQueryIoCompletion", "NtQueryInformationPort", "NtQueryInformationProcess", "NtQueryInformationThread", "NtQueryInformationToken", "NtQueryIntervalProfile", "NtQueryKey", "NtQueryMultipleValueKey", "NtQueryMutant", "NtQueryObject", "NtQueryOleDirectoryFile", "NtQueryPerformanceCounter", "NtQuerySection", "NtQuerySecurityObject", "NtQuerySemaphore", "NtQuerySymbolicLinkObject", "NtQuerySystemEnvironmentValue", "NtQuerySystemInformation", "NtQuerySystemTime", "NtQueryTimer", "NtQueryTimerResolution", "NtQueryValueKey", "NtQueryVirtualMemory", "NtQueryVolumeInformationFile", "NtQueueApcThread", "NtRaiseException", "NtRaiseHardError", "NtReadFile", "NtReadFileScatter", "NtReadRequestData", "NtReadVirtualMemory", "NtRegisterThreadTerminatePort", "NtReleaseMutant", "NtReleaseSemaphore", "NtRemoveIoCompletion", "NtReplaceKey", "NtReplyPort", "NtReplyWaitReceivePort", "NtReplyWaitReplyPort", "NtRequestPort", "NtRequestWaitReplyPort", "NtResetEvent", "NtRestoreKey", "NtResumeThread", "NtSaveKey", "NtSetIoCompletion", "NtSetContextThread", "NtSetDefaultHardErrorPort", "NtSetDefaultLocale", "NtSetEaFile", "NtSetEvent", "NtSetHighEventPair", "NtSetHighWaitLowEventPair", "NtSetHighWaitLowThread (INT 2B)", "NtSetInformationFile", "NtSetInformationKey", "NtSetInformationObject", "NtSetInformationProcess", "NtSetInformationThread", "NtSetInformationToken", "NtSetIntervalProfile", "NtSetLdtEntries", "NtSetLowEventPair", "NtSetLowWaitHighEventPair", "NtSetLowWaitHighThread (INT 2C)", "NtSetSecurityObject", "NtSetSystemEnvironmentValue", "NtSetSystemInformation", "NtSetSystemPowerState", "NtSetSystemTime", "NtSetTimer", "NtSetTimerResolution", "NtSetValueKey", "NtSetVolumeInformationFile", "NtShutdownSystem", "NtSignalAndWaitForSingleObject", "NtStartProfile", "NtStopProfile", "NtSuspendThread", "NtSystemDebugControl", "NtTerminateProcess", "NtTerminateThread", "NtTestAlert", "NtUnloadDriver", "NtUnloadKey", "NtUnlockFile", "NtUnlockVirtualMemory", "NtUnmapViewOfSection", "NtVdmControl", "NtWaitForMultipleObjects", "NtWaitForSingleObject", "NtWaitHighEventPair", "NtWaitLowEventPair", "NtWriteFile", "NtWriteFileGather", "NtWriteRequestData", "NtWriteVirtualMemory", "NtCreateChannel", "NtListenChannel", "NtOpenChannel", "NtReplyWaitSendChannel", "NtSendWaitReplyChannel", "NtSetContextChannel", "NtYieldExecution", NULL }; // ================================================================= // WINDOWS 2000 SYSTEM SERVICE NAMES // ================================================================= // number of entries must match SDT_SYMBOLS_NT5 in w2k_spy.h PBYTE apbSdtSymbolsNT5 [] = { "NtAcceptConnectPort", "NtAccessCheck", "NtAccessCheckAndAuditAlarm", "NtAccessCheckByType", "NtAccessCheckByTypeAndAuditAlarm", "NtAccessCheckByTypeResultList", "NtAccessCheckByTypeResultListAndAuditAlarm", "NtAccessCheckByTypeResultListAndAuditAlarmByHandle", "NtAddAtom", "NtAdjustGroupsToken", "NtAdjustPrivilegesToken", "NtAlertResumeThread", "NtAlertThread", "NtAllocateLocallyUniqueId", "NtAllocateUserPhysicalPages", "NtAllocateUuids", "NtAllocateVirtualMemory", "NtAreMappedFilesTheSame", "NtAssignProcessToJobObject", "NtCallbackReturn", "NtCancelIoFile", "NtCancelTimer", "NtCancelDeviceWakeupRequest", "NtClearEvent", "NtClose", "NtCloseObjectAuditAlarm", "NtCompleteConnectPort", "NtConnectPort", "NtContinue", "NtCreateDirectoryObject", "NtCreateEvent", "NtCreateEventPair", "NtCreateFile", "NtCreateIoCompletion", "NtCreateJobObject", "NtCreateKey", "NtCreateMailslotFile", "NtCreateMutant", "NtCreateNamedPipeFile", "NtCreatePagingFile", "NtCreatePort", "NtCreateProcess", "NtCreateProfile", "NtCreateSection", "NtCreateSemaphore", "NtCreateSymbolicLinkObject", "NtCreateThread", "NtCreateTimer", "NtCreateToken", "NtCreateWaitablePort", "NtDelayExecution", "NtDeleteAtom", "NtDeleteFile", "NtDeleteKey", "NtDeleteObjectAuditAlarm", "NtDeleteValueKey", "NtDeviceIoControlFile", "NtDisplayString", "NtDuplicateObject", "NtDuplicateToken", "NtEnumerateKey", "NtEnumerateValueKey", "NtExtendSection", "NtFilterToken", "NtFindAtom", "NtFlushBuffersFile", "NtFlushInstructionCache", "NtFlushKey", "NtFlushVirtualMemory", "NtFlushWriteBuffer", "NtFreeUserPhysicalPages", "NtFreeVirtualMemory", "NtFsControlFile", "NtGetContextThread", "NtGetDevicePowerState", "NtGetPlugPlayEvent", "NtGetTickCount", "NtGetWriteWatch", "NtImpersonateAnonymousToken", "NtImpersonateClientOfPort", "NtImpersonateThread", "NtInitializeRegistry", "NtInitiatePowerAction", "NtIsSystemResumeAutomatic", "NtListenPort", "NtLoadDriver", "NtLoadKey", "NtLoadKey2", "NtLockFile", "NtLockVirtualMemory", "NtMakeTemporaryObject", "NtMapUserPhysicalPages", "NtMapUserPhysicalPagesScatter", "NtMapViewOfSection", "NtNotifyChangeDirectoryFile", "NtNotifyChangeKey", "NtNotifyChangeMultipleKeys", "NtOpenDirectoryObject", "NtOpenEvent", "NtOpenEventPair", "NtOpenFile", "NtOpenIoCompletion", "NtOpenJobObject", "NtOpenKey", "NtOpenMutant", "NtOpenObjectAuditAlarm", "NtOpenProcess", "NtOpenProcessToken", "NtOpenSection", "NtOpenSemaphore", "NtOpenSymbolicLinkObject", "NtOpenThread", "NtOpenThreadToken", "NtOpenTimer", "NtPlugPlayControl", "NtPowerInformation", "NtPrivilegeCheck", "NtPrivilegedServiceAuditAlarm", "NtPrivilegeObjectAuditAlarm", "NtProtectVirtualMemory", "NtPulseEvent", "NtQueryInformationAtom", "NtQueryAttributesFile", "NtQueryDefaultLocale", "NtQueryDefaultUILanguage", "NtQueryDirectoryFile", "NtQueryDirectoryObject", "NtQueryEaFile", "NtQueryEvent", "NtQueryFullAttributesFile", "NtQueryInformationFile", "NtQueryInformationJobObject", "NtQueryIoCompletion", "NtQueryInformationPort", "NtQueryInformationProcess", "NtQueryInformationThread", "NtQueryInformationToken", "NtQueryInstallUILanguage", "NtQueryIntervalProfile", "NtQueryKey", "NtQueryMultipleValueKey", "NtQueryMutant", "NtQueryObject", "NtQueryOpenSubKeys", "NtQueryPerformanceCounter", "NtQueryQuotaInformationFile", "NtQuerySection", "NtQuerySecurityObject", "NtQuerySemaphore", "NtQuerySymbolicLinkObject", "NtQuerySystemEnvironmentValue", "NtQuerySystemInformation", "NtQuerySystemTime", "NtQueryTimer", "NtQueryTimerResolution", "NtQueryValueKey", "NtQueryVirtualMemory", "NtQueryVolumeInformationFile", "NtQueueApcThread", "NtRaiseException", "NtRaiseHardError", "NtReadFile", "NtReadFileScatter", "NtReadRequestData", "NtReadVirtualMemory", "NtRegisterThreadTerminatePort", "NtReleaseMutant", "NtReleaseSemaphore", "NtRemoveIoCompletion", "NtReplaceKey", "NtReplyPort", "NtReplyWaitReceivePort", "NtReplyWaitReceivePortEx", "NtReplyWaitReplyPort", "NtRequestDeviceWakeup", "NtRequestPort", "NtRequestWaitReplyPort", "NtRequestWakeupLatency", "NtResetEvent", "NtResetWriteWatch", "NtRestoreKey", "NtResumeThread", "NtSaveKey", "NtSaveMergedKeys", "NtSecureConnectPort", "NtSetIoCompletion", "NtSetContextThread", "NtSetDefaultHardErrorPort", "NtSetDefaultLocale", "NtSetDefaultUILanguage", "NtSetEaFile", "NtSetEvent", "NtSetHighEventPair", "NtSetHighWaitLowEventPair", "NtSetInformationFile", "NtSetInformationJobObject", "NtSetInformationKey", "NtSetInformationObject", "NtSetInformationProcess", "NtSetInformationThread", "NtSetInformationToken", "NtSetIntervalProfile", "NtSetLdtEntries", "NtSetLowEventPair", "NtSetLowWaitHighEventPair", "NtSetQuotaInformationFile", "NtSetSecurityObject", "NtSetSystemEnvironmentValue", "NtSetSystemInformation", "NtSetSystemPowerState", "NtSetSystemTime", "NtSetThreadExecutionState", "NtSetTimer", "NtSetTimerResolution", "NtSetUuidSeed", "NtSetValueKey", "NtSetVolumeInformationFile", "NtShutdownSystem", "NtSignalAndWaitForSingleObject", "NtStartProfile", "NtStopProfile", "NtSuspendThread", "NtSystemDebugControl", "NtTerminateJobObject", "NtTerminateProcess", "NtTerminateThread", "NtTestAlert", "NtUnloadDriver", "NtUnloadKey", "NtUnlockFile", "NtUnlockVirtualMemory", "NtUnmapViewOfSection", "NtVdmControl", "NtWaitForMultipleObjects", "NtWaitForSingleObject", "NtWaitHighEventPair", "NtWaitLowEventPair", "NtWriteFile", "NtWriteFileGather", "NtWriteRequestData", "NtWriteVirtualMemory", "NtCreateChannel", "NtListenChannel", "NtOpenChannel", "NtReplyWaitSendChannel", "NtSendWaitReplyChannel", "NtSetContextChannel", "NtYieldExecution", NULL }; // ================================================================= // SYSTEM SERVICE HOOK FORMAT STRINGS // ================================================================= // each string must contain the exact function name PBYTE apbSdtFormats [] = { "%s=NtCancelIoFile(%!,%i)", "%s=NtClose(%-)", "%s=NtCreateFile(%+,%n,%o,%i,%l,%n,%n,%n,%n,%p,%n)", "%s=NtCreateKey(%+,%n,%o,%n,%u,%n,%d)", "%s=NtDeleteFile(%o)", "%s=NtDeleteKey(%-)", "%s=NtDeleteValueKey(%!,%u)", "%s=NtDeviceIoControlFile(%!,%p,%p,%p,%i,%n,%p,%n,%p,%n)", "%s=NtEnumerateKey(%!,%n,%n,%p,%n,%d)", "%s=NtEnumerateValueKey(%!,%n,%n,%p,%n,%d)", "%s=NtFlushBuffersFile(%!,%i)", "%s=NtFlushKey(%!)", "%s=NtFsControlFile(%!,%p,%p,%p,%i,%n,%p,%n,%p,%n)", "%s=NtLoadKey(%o,%o)", "%s=NtLoadKey2(%o,%o,%n)", "%s=NtNotifyChangeKey(%!,%p,%p,%p,%i,%n,%b,%p,%n,%b)", "%s=NtNotifyChangeMultipleKeys(%!,%n,%o,%p,%p,%p,%i,%n,%b,%p,%n,%b)", "%s=NtOpenFile(%+,%n,%o,%i,%n,%n)", "%s=NtOpenKey(%+,%n,%o)", "%s=NtOpenProcess(%+,%n,%o,%c)", "%s=NtOpenThread(%+,%n,%o,%c)", "%s=NtQueryDirectoryFile(%!,%p,%p,%p,%i,%p,%n,%n,%b,%u,%b)", "%s=NtQueryInformationFile(%!,%i,%p,%n,%n)", "%s=NtQueryInformationProcess(%!,%n,%p,%n,%d)", "%s=NtQueryInformationThread(%!,%n,%p,%n,%d)", "%s=NtQueryKey(%!,%n,%p,%n,%d)", "%s=NtQueryMultipleValueKey(%!,%p,%n,%p,%d,%d)", "%s=NtQueryOpenSubKeys(%o,%d)", "%s=NtQuerySystemInformation(%n,%p,%n,%d)", "%s=NtQuerySystemTime(%l)", "%s=NtQueryValueKey(%!,%u,%n,%p,%n,%d)", "%s=NtQueryVolumeInformationFile(%!,%i,%p,%n,%n)", "%s=NtReadFile(%!,%p,%p,%p,%i,%p,%n,%l,%d)", "%s=NtReplaceKey(%o,%!,%o)", "%s=NtSetInformationKey(%!,%n,%p,%n)", "%s=NtSetInformationFile(%!,%i,%p,%n,%n)", "%s=NtSetInformationProcess(%!,%n,%p,%n)", "%s=NtSetInformationThread(%!,%n,%p,%n)", "%s=NtSetSystemInformation(%n,%p,%n)", "%s=NtSetSystemTime(%l,%l)", "%s=NtSetValueKey(%!,%u,%n,%n,%p,%n)", "%s=NtSetVolumeInformationFile(%!,%i,%p,%n,%n)", "%s=NtUnloadKey(%o)", "%s=NtWriteFile(%!,%p,%p,%p,%i,%p,%n,%l,%d)", NULL }; // ================================================================= // SYSTEM SERVICE HOOK ENTRIES // ================================================================= SPY_HOOK_ENTRY aSpyHooks [SDT_SYMBOLS_MAX]; // ================================================================= // STRING FUNCTIONS // ================================================================= PBYTE strcpyn (PBYTE pbBuffer, PBYTE pbData, DWORD dBuffer) { DWORD i; if (dBuffer) { for (i = 0; (i < dBuffer-1) && pbData [i]; i++) { pbBuffer [i] = pbData [i]; } pbBuffer [i] = 0; } return pbBuffer; } // ----------------------------------------------------------------- PWORD wcscpyn (PWORD pwBuffer, PWORD pwData, DWORD dBuffer) { DWORD i; if (dBuffer) { for (i = 0; (i < dBuffer-1) && pwData [i]; i++) { pwBuffer [i] = pwData [i]; } pwBuffer [i] = 0; } return pwBuffer; } // ================================================================= // MEMORY MANAGEMENT // ================================================================= PVOID SpyMemoryCreate (DWORD dSize) { return ExAllocatePoolWithTag (PagedPool, max (dSize, 1), SPY_TAG); } // ----------------------------------------------------------------- PVOID SpyMemoryDestroy (PVOID pData) { if (pData != NULL) ExFreePool (pData); return NULL; } // ================================================================= // SHIFT/AND SEARCH ENGINE // ================================================================= void SpySearchReset (PSPY_SEARCH pss) { pss->qTest = 0; pss->dNext = 0; pss->dHit = MAXDWORD; return; } // ----------------------------------------------------------------- BOOL SpySearchNew (PSPY_SEARCH pss, PBYTE pbPattern) { DWORD i; QWORD qMask; PQWORD pqFlags = pss->aqFlags; for (i = 0; i < 256; i++) pqFlags [i] = 0; for (i = 0, qMask = 1; pbPattern [i] && qMask; i++, qMask <<= 1) { pqFlags [pbPattern [i]] |= qMask; } pss->qMask = (qMask ? qMask >> 1 : 0x8000000000000000); pss->dBytes = i; SpySearchReset (pss); return (i && (!pbPattern [i])); } // ----------------------------------------------------------------- BOOL SpySearchTest (PSPY_SEARCH pss, BYTE bData) { BOOL fOk = FALSE; if (pss->qMask) { pss->qTest <<= 1; pss->qTest |= 1; pss->qTest &= pss->aqFlags [bData]; pss->dNext++; if (pss->qTest & pss->qMask) { pss->qTest = 0; pss->dHit = pss->dNext - pss->dBytes; fOk = TRUE; } } return fOk; } // ----------------------------------------------------------------- BOOL SpySearchText (PSPY_SEARCH pss, PBYTE pbText) { DWORD i; BOOL fHit = FALSE; SpySearchReset (pss); for (i = 0; (!fHit) && pbText [i]; i++) { fHit = SpySearchTest (pss, pbText [i]); } return fHit; } // ----------------------------------------------------------------- PBYTE SpySearchFormat (PBYTE pbSymbol, PPBYTE ppbFormats) { SPY_SEARCH ss; DWORD i; PBYTE pbFormat = NULL; if (SpySearchNew (&ss, pbSymbol)) { for (i = 0; (pbFormat = ppbFormats [i]) != NULL; i++) { if (SpySearchText (&ss, pbFormat)) break; } } return pbFormat; } // ================================================================= // SELECTORS, DESCRIPTORS, GATES, AND SEGMENTS // ================================================================= BOOL SpySelector (DWORD dSegment, DWORD dSelector, PX86_SELECTOR pSelector) { X86_SELECTOR Selector = {0, 0}; BOOL fOk = FALSE; if (pSelector != NULL) { fOk = TRUE; switch (dSegment) { case X86_SEGMENT_OTHER: { if (fOk = ((dSelector >> X86_SELECTOR_SHIFT) <= X86_SELECTOR_LIMIT)) { Selector.wValue = (WORD) dSelector; } break; } case X86_SEGMENT_CS: { __asm mov Selector.wValue, cs break; } case X86_SEGMENT_DS: { __asm mov Selector.wValue, ds break; } case X86_SEGMENT_ES: { __asm mov Selector.wValue, es break; } case X86_SEGMENT_FS: { __asm mov Selector.wValue, fs break; } case X86_SEGMENT_GS: { __asm mov Selector.wValue, gs break; } case X86_SEGMENT_SS: { __asm mov Selector.wValue, ss break; } case X86_SEGMENT_TSS: { __asm str Selector.wValue break; } default: { fOk = FALSE; break; } } RtlCopyMemory (pSelector, &Selector, X86_SELECTOR_); } return fOk; } // ----------------------------------------------------------------- PVOID SpyDescriptorBase (PX86_DESCRIPTOR pDescriptor) { return (PVOID) ((pDescriptor->Base1 ) | (pDescriptor->Base2 << 16) | (pDescriptor->Base3 << 24)); } // ----------------------------------------------------------------- DWORD SpyDescriptorLimit (PX86_DESCRIPTOR pDescriptor) { return (pDescriptor->G ? (pDescriptor->Limit1 << 12) | (pDescriptor->Limit2 << 28) | 0xFFF : (pDescriptor->Limit1 ) | (pDescriptor->Limit2 << 16)); } // ----------------------------------------------------------------- DWORD SpyDescriptorType (PX86_DESCRIPTOR pDescriptor, PBOOL pfSystem) { if (pfSystem != NULL) *pfSystem = !pDescriptor->S; return pDescriptor->Type; } // ----------------------------------------------------------------- BOOL SpyDescriptor (PX86_SELECTOR pSelector, PX86_DESCRIPTOR pDescriptor) { X86_SELECTOR ldt; X86_TABLE gdt; DWORD dType, dLimit; BOOL fSystem; PX86_DESCRIPTOR pDescriptors = NULL; BOOL fOk = FALSE; if (pDescriptor != NULL) { if (pSelector != NULL) { if (pSelector->TI) // ldt descriptor { __asm { sldt ldt.wValue sgdt gdt.wLimit } if ((!ldt.TI) && ldt.Index && ((ldt.wValue & X86_SELECTOR_INDEX) <= gdt.wLimit)) { dType = SpyDescriptorType (gdt.pDescriptors + ldt.Index, &fSystem); dLimit = SpyDescriptorLimit (gdt.pDescriptors + ldt.Index); if (fSystem && (dType == X86_DESCRIPTOR_SYS_LDT) && ((DWORD) (pSelector->wValue & X86_SELECTOR_INDEX) <= dLimit)) { pDescriptors = SpyDescriptorBase (gdt.pDescriptors + ldt.Index); } } } else // gdt descriptor { if (pSelector->Index) { __asm { sgdt gdt.wLimit } if ((pSelector->wValue & X86_SELECTOR_INDEX) <= gdt.wLimit) { pDescriptors = gdt.pDescriptors; } } } } if (pDescriptors != NULL) { RtlCopyMemory (pDescriptor, pDescriptors + pSelector->Index, X86_DESCRIPTOR_); fOk = TRUE; } else { RtlZeroMemory (pDescriptor, X86_DESCRIPTOR_); } } return fOk; } // ----------------------------------------------------------------- PVOID SpyGateOffset (PX86_GATE pGate) { return (PVOID) (pGate->Offset1 | (pGate->Offset2 << 16)); } // ----------------------------------------------------------------- BOOL SpyIdtGate (PX86_SELECTOR pSelector, PX86_GATE pGate) { X86_TABLE idt; PX86_GATE pGates = NULL; BOOL fOk = FALSE; if (pGate != NULL) { if (pSelector != NULL) { __asm { sidt idt.wLimit } if ((pSelector->wValue & X86_SELECTOR_INDEX) <= idt.wLimit) { pGates = idt.pGates; } } if (pGates != NULL) { RtlCopyMemory (pGate, pGates + pSelector->Index, X86_GATE_); fOk = TRUE; } else { RtlZeroMemory (pGate, X86_GATE_); } } return fOk; } // ----------------------------------------------------------------- BOOL SpySegment (DWORD dSegment, DWORD dSelector, PSPY_SEGMENT pSegment) { BOOL fOk = FALSE; if (pSegment != NULL) { fOk = TRUE; if (!SpySelector (dSegment, dSelector, &pSegment->Selector)) { fOk = FALSE; } if (!SpyDescriptor (&pSegment->Selector, &pSegment->Descriptor)) { fOk = FALSE; } pSegment->pBase = SpyDescriptorBase (&pSegment->Descriptor); pSegment->dLimit = SpyDescriptorLimit (&pSegment->Descriptor); pSegment->fOk = fOk; } return fOk; } // ----------------------------------------------------------------- BOOL SpyInterrupt (DWORD dInterrupt, PSPY_INTERRUPT pInterrupt) { BOOL fOk = FALSE; if (pInterrupt != NULL) { if (dInterrupt <= X86_SELECTOR_LIMIT) { fOk = TRUE; if (!SpySelector (X86_SEGMENT_OTHER, dInterrupt << X86_SELECTOR_SHIFT, &pInterrupt->Selector)) { fOk = FALSE; } if (!SpyIdtGate (&pInterrupt->Selector, &pInterrupt->Gate)) { fOk = FALSE; } if (!SpySegment (X86_SEGMENT_OTHER, pInterrupt->Gate.Selector, &pInterrupt->Segment)) { fOk = FALSE; } pInterrupt->pOffset = SpyGateOffset (&pInterrupt->Gate); } else { RtlZeroMemory (pInterrupt, SPY_INTERRUPT_); } pInterrupt->fOk = fOk; } return fOk; } // ================================================================= // MEMORY ACCESS FUNCTIONS // ================================================================= BOOL SpyMemoryPageEntry (PVOID pVirtual, PSPY_PAGE_ENTRY pspe) { SPY_PAGE_ENTRY spe; BOOL fOk = FALSE; spe.pe = X86_PDE_ARRAY [X86_PDI (pVirtual)]; spe.dSize = X86_PAGE_4M; spe.fPresent = FALSE; if (spe.pe.pde4M.P) { if (spe.pe.pde4M.PS) { fOk = spe.fPresent = TRUE; } else { spe.pe = X86_PTE_ARRAY [X86_PAGE (pVirtual)]; spe.dSize = X86_PAGE_4K; if (spe.pe.pte4K.P) { fOk = spe.fPresent = TRUE; } else { fOk = (spe.pe.pnpe.PageFile != 0); } } } if (pspe != NULL) *pspe = spe; return fOk; } // ----------------------------------------------------------------- BOOL SpyMemoryTestAddress (PVOID pVirtual) { return SpyMemoryPageEntry (pVirtual, NULL); } // ----------------------------------------------------------------- BOOL SpyMemoryTestBlock (PVOID pVirtual, DWORD dBytes) { PBYTE pbData; DWORD dData; BOOL fOk = TRUE; if (dBytes) { pbData = (PBYTE) ((DWORD_PTR) pVirtual & X86_PAGE_MASK); dData = (((dBytes + X86_OFFSET_4K (pVirtual) - 1) / PAGE_SIZE) + 1) * PAGE_SIZE; do { fOk = SpyMemoryTestAddress (pbData); pbData += PAGE_SIZE; dData -= PAGE_SIZE; } while (fOk && dData); } return fOk; } // ----------------------------------------------------------------- DWORD SpyMemoryReadBlock (PSPY_MEMORY_BLOCK psmb, PSPY_MEMORY_DATA psmd, DWORD dSize) { DWORD i; DWORD n = SPY_MEMORY_DATA__ (psmb->dBytes); if (dSize >= n) { psmd->smb = *psmb; for (i = 0; i < psmb->dBytes; i++) { psmd->awData [i] = (SpyMemoryTestAddress (psmb->pbAddress + i) ? SPY_MEMORY_DATA_VALUE (psmb->pbAddress [i], TRUE) : SPY_MEMORY_DATA_VALUE (0, FALSE)); } } else { if (dSize >= SPY_MEMORY_DATA_) { psmd->smb.pbAddress = NULL; psmd->smb.dBytes = 0; } n = 0; } return n; } // ================================================================= // HANDLE MANAGEMENT // ================================================================= DWORD SpyHandleSlot (PSPY_PROTOCOL psp, HANDLE hProcess, HANDLE hObject) { DWORD dSlot = 0; if (hObject != NULL) { while ((dSlot < psp->sh.dHandles) && ((psp->ahProcesses [dSlot] != hProcess) || (psp->ahObjects [dSlot] != hObject ))) dSlot++; dSlot = (dSlot < psp->sh.dHandles ? dSlot+1 : 0); } return dSlot; } // ----------------------------------------------------------------- DWORD SpyHandleName (PSPY_PROTOCOL psp, HANDLE hProcess, HANDLE hObject, PWORD pwName, DWORD dName) { WORD w; DWORD i; DWORD dSlot = SpyHandleSlot (psp, hProcess, hObject); if ((pwName != NULL) && dName) { i = 0; if (dSlot) { while ((i+1 < dName) && (w = psp->awNames [psp->adNames [dSlot-1] + i])) { pwName [i++] = w; } } pwName [i] = 0; } return dSlot; } // ----------------------------------------------------------------- DWORD SpyHandleUnregister (PSPY_PROTOCOL psp, HANDLE hProcess, HANDLE hObject, PWORD pwName, DWORD dName) { DWORD i, j; DWORD dSlot = SpyHandleName (psp, hProcess, hObject, pwName, dName); if (dSlot) { if (dSlot == psp->sh.dHandles) { // remove last name entry psp->sh.dName = psp->adNames [dSlot-1]; } else { i = psp->adNames [dSlot-1]; j = psp->adNames [dSlot ]; // shift left all remaining name entries while (j < psp->sh.dName) { psp->awNames [i++] = psp->awNames [j++]; } j -= (psp->sh.dName = i); // shift left all remaining handles and name offsets for (i = dSlot; i < psp->sh.dHandles; i++) { psp->ahProcesses [i-1] = psp->ahProcesses [i]; psp->ahObjects [i-1] = psp->ahObjects [i]; psp->adNames [i-1] = psp->adNames [i] - j; } } psp->sh.dHandles--; } return dSlot; } // ----------------------------------------------------------------- DWORD SpyHandleRegister (PSPY_PROTOCOL psp, HANDLE hProcess, HANDLE hObject, PUNICODE_STRING puName) { PWORD pwName; DWORD dName; DWORD i; DWORD dSlot = 0; if (hObject != NULL) { // unregister old handle with same value SpyHandleUnregister (psp, hProcess, hObject, NULL, 0); if (psp->sh.dHandles == SPY_HANDLES) { // unregister oldest handle if overflow SpyHandleUnregister (psp, psp->ahProcesses [0], psp->ahObjects [0], NULL, 0); } pwName = ((puName != NULL) && SpyMemoryTestAddress (puName) ? puName->Buffer : NULL); dName = ((pwName != NULL) && SpyMemoryTestAddress (pwName) ? puName->Length / WORD_ : 0); if (dName + 1 <= SPY_NAME_BUFFER - psp->sh.dName) { // append object to end of list psp->ahProcesses [psp->sh.dHandles] = hProcess; psp->ahObjects [psp->sh.dHandles] = hObject; psp->adNames [psp->sh.dHandles] = psp->sh.dName; for (i = 0; i < dName; i++) { psp->awNames [psp->sh.dName++] = pwName [i]; } psp->awNames [psp->sh.dName++] = 0; psp->sh.dHandles++; dSlot = psp->sh.dHandles; } } return dSlot; } // ================================================================= // HOOK PROTOCOL MANAGEMENT (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; } // ================================================================= // HOOK PROTOCOL MANAGEMENT (WRITE) // ================================================================= 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; return; } // ----------------------------------------------------------------- DWORD SpyWriteData (PSPY_PROTOCOL psp, PBYTE pbData, DWORD dData) { BYTE b; DWORD i = psp->sh.dRead; DWORD j = psp->sh.dWrite; DWORD n = 0; while (n < dData) { psp->abData [j++] = pbData [n++]; if (j == SPY_DATA_BUFFER) j = 0; if (j == i) { // remove first line from buffer do { b = psp->abData [i++]; if (i == SPY_DATA_BUFFER) i = 0; } while ((b != '\n') && (i != j)); // remove half line only if single line if ((i == j) && ((i += (SPY_DATA_BUFFER / 2)) >= SPY_DATA_BUFFER)) { i -= SPY_DATA_BUFFER; } } } psp->sh.dRead = i; psp->sh.dWrite = j; return n; } // ----------------------------------------------------------------- DWORD SpyWriteChar (PSPY_PROTOCOL psp, BYTE bPrefix, BYTE bData) { DWORD n = 0; if (bPrefix) n += SpyWriteData (psp, &bPrefix, 1); if (bData ) n += SpyWriteData (psp, &bData, 1); return n; } // ----------------------------------------------------------------- DWORD SpyWriteAnsi (PSPY_PROTOCOL psp, BYTE bPrefix, PBYTE pbData) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if (pbData != NULL) { n += SpyWriteData (psp, pbData, strlen (pbData)); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteBoolean (PSPY_PROTOCOL psp, BYTE bPrefix, BOOLEAN bData) { return SpyWriteAnsi (psp, bPrefix, (bData ? "TRUE" : "FALSE")); } // ----------------------------------------------------------------- DWORD SpyWriteNumber (PSPY_PROTOCOL psp, BYTE bPrefix, DWORD dData) { BYTE abNumber [8+1]; DWORD x, i; abNumber [i = 8] = 0; x = dData; do { abNumber [--i] = abHex [x & 0xF]; x >>= 4; } while (x); return SpyWriteAnsi (psp, bPrefix, abNumber+i); } // ----------------------------------------------------------------- DWORD SpyWriteWide (PSPY_PROTOCOL psp, BYTE bPrefix, PWORD pwData, DWORD dData) { UNICODE_STRING us; ANSI_STRING as; WORD awChar [] = L"?"; BYTE abChar [] = "?"; DWORD dData1, i; DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pwData != NULL) && SpyMemoryTestAddress (pwData)) { dData1 = (dData != MAXDWORD ? dData : wcslen (pwData)); RtlInitUnicodeString (&us, awChar); RtlInitAnsiString (&as, abChar); for (i = 0; i < dData1; i++) { if (pwData [i] < 0x100) { abChar [0] = (BYTE) pwData [i]; } else { awChar [0] = pwData [i]; if (RtlUnicodeStringToAnsiString (&as, &us, FALSE) != STATUS_SUCCESS) { abChar [0] = '?'; } } n += SpyWriteChar (psp, 0, abChar [0]); } } return n; } // ----------------------------------------------------------------- DWORD SpyWriteString (PSPY_PROTOCOL psp, BYTE bPrefix, PWORD pwData, DWORD dData, BYTE bStart, BYTE bStop) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pwData != NULL) && SpyMemoryTestAddress (pwData)) { n += SpyWriteChar (psp, 0, bStart); n += SpyWriteWide (psp, 0, pwData, dData); n += SpyWriteChar (psp, 0, bStop); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteName (PSPY_PROTOCOL psp, BYTE bPrefix, PWORD pwData, DWORD dData) { return SpyWriteString (psp, bPrefix, pwData, dData, '\"', '\"'); } // ----------------------------------------------------------------- DWORD SpyWriteUnicode (PSPY_PROTOCOL psp, BYTE bPrefix, PUNICODE_STRING puData) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((puData != NULL) && SpyMemoryTestAddress (puData)) { n += SpyWriteName (psp, 0, puData->Buffer, puData->Length / WORD_); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteObject (PSPY_PROTOCOL psp, BYTE bPrefix, POBJECT_ATTRIBUTES poa) { return SpyWriteUnicode (psp, bPrefix, OBJECT_NAME (poa)); } // ----------------------------------------------------------------- DWORD SpyWriteLarge (PSPY_PROTOCOL psp, BYTE bPrefix, PLARGE_INTEGER pliData) { BYTE abNumber [16+1]; DWORDLONG x; DWORD i; DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pliData != NULL) && SpyMemoryTestAddress (pliData)) { abNumber [i = 16] = 0; x = (pliData->QuadPart); do { abNumber [--i] = abHex [x & 0xF]; x >>= 4; } while (x); n += SpyWriteAnsi (psp, 0, abNumber+i); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteStatus (PSPY_PROTOCOL psp, BYTE bPrefix, NTSTATUS NtStatus) { return SpyWriteNumber (psp, bPrefix, NtStatus); } // ----------------------------------------------------------------- DWORD SpyWriteIoStatus (PSPY_PROTOCOL psp, BYTE bPrefix, PIO_STATUS_BLOCK pisb) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pisb != NULL) && SpyMemoryTestAddress (pisb)) { n += SpyWriteNumber (psp, 0, pisb->Status); n += SpyWriteChar (psp, 0, '.'); n += SpyWriteNumber (psp, 0, pisb->Information); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteClientId (PSPY_PROTOCOL psp, BYTE bPrefix, PCLIENT_ID pci) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pci != NULL) && SpyMemoryTestAddress (pci)) { n += SpyWriteNumber (psp, 0, (DWORD) pci->UniqueProcess); n += SpyWriteChar (psp, 0, '.'); n += SpyWriteNumber (psp, 0, (DWORD) pci->UniqueThread); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteDword (PSPY_PROTOCOL psp, BYTE bPrefix, PDWORD pdData) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((pdData != NULL) && SpyMemoryTestAddress (pdData)) { n += SpyWriteNumber (psp, 0, *pdData); } return n; } // ----------------------------------------------------------------- DWORD SpyWritePointer (PSPY_PROTOCOL psp, BYTE bPrefix, PVOID pData) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if (pData != NULL) { n += SpyWriteNumber (psp, 0, (DWORD) pData); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteHandle (PSPY_PROTOCOL psp, BYTE bPrefix, HANDLE hProcess, HANDLE hObject) { DWORD n = SpyWriteChar (psp, 0, bPrefix); n += SpyWriteNumber (psp, 0, (DWORD) hProcess); n += SpyWriteChar (psp, 0, '.'); n += SpyWriteNumber (psp, 0, (DWORD) hObject); return n; } // ----------------------------------------------------------------- DWORD SpyWriteNewHandle (PSPY_PROTOCOL psp, BYTE bPrefix, HANDLE hProcess, PHANDLE phObject) { DWORD n = SpyWriteChar (psp, 0, bPrefix); if ((phObject != NULL) && SpyMemoryTestAddress (phObject)) { n += SpyWriteHandle (psp, 0, hProcess, *phObject); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteOpenHandle (PSPY_PROTOCOL psp, BYTE bPrefix, HANDLE hProcess, HANDLE hObject) { WORD awName [SPY_NAME]; DWORD n = SpyWriteHandle (psp, bPrefix, hProcess, hObject); if (SpyHandleName (psp, hProcess, hObject, awName, SPY_NAME)) { n += SpyWriteChar (psp, 0, '='); n += SpyWriteName (psp, 0, awName, MAXDWORD); } return n; } // ----------------------------------------------------------------- DWORD SpyWriteClosedHandle (PSPY_PROTOCOL psp, BYTE bPrefix, HANDLE hProcess, HANDLE hObject) { WORD awName [SPY_NAME]; DWORD n = SpyWriteHandle (psp, bPrefix, hProcess, hObject); if (SpyHandleUnregister (psp, hProcess, hObject, awName, SPY_NAME)) { n += SpyWriteChar (psp, 0, '='); n += SpyWriteName (psp, 0, awName, MAXDWORD); } return n; } // ----------------------------------------------------------------- BOOL SpyWriteFilter (PSPY_PROTOCOL psp, PBYTE pbFormat, PVOID pParameters, DWORD dParameters) { PHANDLE phObject = NULL; HANDLE hObject = NULL; POBJECT_ATTRIBUTES poa = NULL; PDWORD pdNext; DWORD i, j; pdNext = pParameters; i = j = 0; while (pbFormat [i]) { while (pbFormat [i] && (pbFormat [i] != '%')) i++; if (pbFormat [i] && pbFormat [++i]) { j++; switch (pbFormat [i++]) { case 'b': case 'a': case 'w': case 'u': case 'n': case 'l': case 's': case 'i': case 'c': case 'd': case 'p': { break; } case 'o': { if (poa == NULL) { poa = (POBJECT_ATTRIBUTES) *pdNext; } break; } case '+': { if (phObject == NULL) { phObject = (PHANDLE) *pdNext; } break; } case '!': case '-': { if (hObject == NULL) { hObject = (HANDLE) *pdNext; } break; } default: { j--; break; } } pdNext++; } } return // number of arguments ok (j == dParameters) && // no handles involved (((phObject == NULL) && (hObject == NULL)) || // new handle, successfully registered ((phObject != NULL) && SpyHandleRegister (psp, PsGetCurrentProcessId (), *phObject, OBJECT_NAME (poa))) || // registered handle SpyHandleSlot (psp, PsGetCurrentProcessId (), hObject) || // filter disabled (!gfSpyHookFilter)); } // ----------------------------------------------------------------- DWORD SpyWriteType (PSPY_PROTOCOL psp, BYTE bEscape, BYTE bType, PVOID pData) { HANDLE hProcess = PsGetCurrentProcessId (); DWORD n = 0; switch (bType) { case 'b': { n = SpyWriteBoolean (psp, bType, *(BOOLEAN *) pData); break; } case 'a': { n = SpyWriteAnsi (psp, bType, *(PBYTE *) pData); break; } case 'w': { n = SpyWriteWide (psp, bType, *(PWORD *) pData, MAXDWORD); break; } case 'u': { n = SpyWriteUnicode (psp, bType, *(PUNICODE_STRING *) pData); break; } case 'n': { n = SpyWriteNumber (psp, bType, *(DWORD *) pData); break; } case 'l': { n = SpyWriteLarge (psp, bType, *(PLARGE_INTEGER *) pData); break; } case 's': { n = SpyWriteStatus (psp, bType, *(NTSTATUS *) pData); break; } case 'i': { n = SpyWriteIoStatus (psp, bType, *(PIO_STATUS_BLOCK *) pData); break; } case 'c': { n = SpyWriteClientId (psp, bType, *(PCLIENT_ID *) pData); break; } case 'd': { n = SpyWriteDword (psp, bType, *(PDWORD *) pData); break; } case 'p': { n = SpyWritePointer (psp, bType, *(PVOID *) pData); break; } case 'o': { n = SpyWriteObject (psp, bType, *(POBJECT_ATTRIBUTES *) pData); break; } case '+': { n = SpyWriteNewHandle (psp, bType, hProcess, *(PHANDLE *) pData); break; } case '!': { n = SpyWriteOpenHandle (psp, bType, hProcess, *(HANDLE *) pData); break; } case '-': { n = SpyWriteClosedHandle (psp, bType, hProcess, *(HANDLE *) pData); break; } default: { n = (bEscape == bType ? SpyWriteChar (psp, 0, bType) : SpyWriteChar (psp, bEscape, bType)); break; } } return n; } // ----------------------------------------------------------------- DWORD SpyWriteFormat (PSPY_PROTOCOL psp, PBYTE pbFormat, PVOID pParameters) { PBYTE pbData; PDWORD pdData; DWORD i; DWORD n = 0; pbData = pbFormat; pdData = pParameters; while (*pbData) { for (i = 0; pbData [i] && (pbData [i] != '%'); i++); n += SpyWriteData (psp, pbData, i); pbData += i; if (*pbData) { n += SpyWriteType (psp, *pbData, *(pbData+1), pdData++); if (*++pbData) ++pbData; } } return n; } // ================================================================= // SERVICE DESCRIPTOR TABLE HOOKS // ================================================================= NTSTATUS SpyHookWait (void) { return MUTEX_WAIT (gpDeviceContext->kmProtocol); } // ----------------------------------------------------------------- LONG SpyHookRelease (void) { return MUTEX_RELEASE (gpDeviceContext->kmProtocol); } // ----------------------------------------------------------------- void SpyHookReset (void) { SpyHookWait (); SpyWriteReset (&gpDeviceContext->SpyProtocol); SpyHookRelease (); return; } // ----------------------------------------------------------------- DWORD SpyHookRead (PBYTE pbData, DWORD dData, BOOL fLine) { DWORD n = 0; SpyHookWait (); n = (fLine ? SpyReadLine : SpyReadData) (&gpDeviceContext->SpyProtocol, pbData, dData); SpyHookRelease (); return n; } // ----------------------------------------------------------------- DWORD SpyHookWrite (PBYTE pbData, DWORD dData) { DWORD n = 0; SpyHookWait (); n = SpyWriteData (&gpDeviceContext->SpyProtocol, pbData, dData); SpyHookRelease (); return n; } // ----------------------------------------------------------------- // <#>:=()