VOID EtpProcessDiskPacket( __in PETP_DISK_PACKET Packet, __in ULONG RunId ) { PET_ETW_DISK_EVENT diskEvent; PET_DISK_ITEM diskItem; BOOLEAN added = FALSE; diskEvent = &Packet->Event; // We only process non-zero read/write events. if (diskEvent->Type != EtEtwDiskReadType && diskEvent->Type != EtEtwDiskWriteType) return; if (diskEvent->TransferSize == 0) return; // Ignore packets with no file name - this is useless to the user. if (!Packet->FileName) return; diskItem = EtReferenceDiskItem(diskEvent->ClientId.UniqueProcess, Packet->FileName); if (!diskItem) { PPH_PROCESS_ITEM processItem; // Disk item not found (or the address was re-used), create it. diskItem = EtCreateDiskItem(); diskItem->ProcessId = diskEvent->ClientId.UniqueProcess; diskItem->FileName = Packet->FileName; PhReferenceObject(Packet->FileName); diskItem->FileNameWin32 = PhGetFileName(diskItem->FileName); if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) { diskItem->ProcessName = processItem->ProcessName; PhReferenceObject(processItem->ProcessName); diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); diskItem->ProcessRecord = processItem->Record; PhReferenceProcessRecord(diskItem->ProcessRecord); PhDereferenceObject(processItem); } // Add the disk item to the age list. diskItem->AddTime = RunId; diskItem->FreshTime = RunId; InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); // Add the disk item to the hashtable. PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); PhAddEntryHashtable(EtDiskHashtable, &diskItem); PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); // Raise the disk item added event. PhInvokeCallback(&EtDiskItemAddedEvent, diskItem); added = TRUE; } // The I/O priority number needs to be decoded. diskItem->IoPriority = (diskEvent->IrpFlags >> 17) & 7; if (diskItem->IoPriority == 0) diskItem->IoPriority = IoPriorityNormal; else diskItem->IoPriority--; // Accumulate statistics for this update period. if (diskEvent->Type == EtEtwDiskReadType) diskItem->ReadDelta += diskEvent->TransferSize; else diskItem->WriteDelta += diskEvent->TransferSize; if (EtpPerformanceFrequency.QuadPart != 0) { // Convert the response time to milliseconds. diskItem->ResponseTimeTotal += (FLOAT)diskEvent->HighResResponseTime * 1000 / EtpPerformanceFrequency.QuadPart; diskItem->ResponseTimeCount++; } if (!added) { if (diskItem->FreshTime != RunId) { diskItem->FreshTime = RunId; RemoveEntryList(&diskItem->AgeListEntry); InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry); } PhDereferenceObject(diskItem); } }
static VOID NTAPI ProcessesUpdatedCallback( __in_opt PVOID Parameter, __in_opt PVOID Context ) { static ULONG runCount = 0; PSLIST_ENTRY listEntry; PLIST_ENTRY ageListEntry; // Process incoming disk event packets. listEntry = RtlInterlockedFlushSList(&EtDiskPacketListHead); while (listEntry) { PETP_DISK_PACKET packet; packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry); listEntry = listEntry->Next; EtpProcessDiskPacket(packet, runCount); if (packet->FileName) PhDereferenceObject(packet->FileName); PhFreeToFreeList(&EtDiskPacketFreeList, packet); } // Remove old entries. ageListEntry = EtDiskAgeListHead.Blink; while (ageListEntry != &EtDiskAgeListHead) { PET_DISK_ITEM diskItem; diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); ageListEntry = ageListEntry->Blink; if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems break; PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem); PhAcquireQueuedLockExclusive(&EtDiskHashtableLock); EtpRemoveDiskItem(diskItem); PhReleaseQueuedLockExclusive(&EtDiskHashtableLock); } // Update existing items. ageListEntry = EtDiskAgeListHead.Flink; while (ageListEntry != &EtDiskAgeListHead) { PET_DISK_ITEM diskItem; diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry); // Update statistics. if (diskItem->HistoryPosition != 0) diskItem->HistoryPosition--; else diskItem->HistoryPosition = HISTORY_SIZE - 1; diskItem->ReadHistory[diskItem->HistoryPosition] = diskItem->ReadDelta; diskItem->WriteHistory[diskItem->HistoryPosition] = diskItem->WriteDelta; if (diskItem->HistoryCount < HISTORY_SIZE) diskItem->HistoryCount++; if (diskItem->ResponseTimeCount != 0) { diskItem->ResponseTimeAverage = (FLOAT)diskItem->ResponseTimeTotal / diskItem->ResponseTimeCount; // Reset the total once in a while to avoid the number getting too large (and thus losing precision). if (diskItem->ResponseTimeCount >= 1000) { diskItem->ResponseTimeTotal = diskItem->ResponseTimeAverage; diskItem->ResponseTimeCount = 1; } } diskItem->ReadTotal += diskItem->ReadDelta; diskItem->WriteTotal += diskItem->WriteDelta; diskItem->ReadDelta = 0; diskItem->WriteDelta = 0; diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE); if (diskItem->AddTime != runCount) { BOOLEAN modified = FALSE; PPH_PROCESS_ITEM processItem; if (!diskItem->ProcessName || !diskItem->ProcessIcon || !diskItem->ProcessRecord) { if (processItem = PhReferenceProcessItem(diskItem->ProcessId)) { if (!diskItem->ProcessName) { diskItem->ProcessName = processItem->ProcessName; PhReferenceObject(processItem->ProcessName); modified = TRUE; } if (!diskItem->ProcessIcon) { diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem)); if (diskItem->ProcessIcon) modified = TRUE; } if (!diskItem->ProcessRecord) { diskItem->ProcessRecord = processItem->Record; PhReferenceProcessRecord(diskItem->ProcessRecord); } PhDereferenceObject(processItem); } } if (modified) { // Raise the disk item modified event. PhInvokeCallback(&EtDiskItemModifiedEvent, diskItem); } } ageListEntry = ageListEntry->Flink; } PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL); runCount++; }
static PPH_PROCESS_ITEM PhpCreateProcessItemForHiddenProcess( _In_ PPH_HIDDEN_PROCESS_ENTRY Entry ) { NTSTATUS status; PPH_PROCESS_ITEM processItem; PPH_PROCESS_ITEM idleProcessItem; HANDLE processHandle; PROCESS_BASIC_INFORMATION basicInfo; KERNEL_USER_TIMES times; PROCESS_PRIORITY_CLASS priorityClass; ULONG handleCount; HANDLE processHandle2; if (Entry->Type == NormalProcess) { processItem = PhReferenceProcessItem(Entry->ProcessId); if (processItem) return processItem; } processItem = PhCreateProcessItem(Entry->ProcessId); // Mark the process as terminated if necessary. if (Entry->Type == TerminatedProcess) processItem->State |= PH_PROCESS_ITEM_REMOVED; // We need a process record. Just use the record of System Idle Process. if (idleProcessItem = PhReferenceProcessItem(SYSTEM_IDLE_PROCESS_ID)) { processItem->Record = idleProcessItem->Record; PhReferenceProcessRecord(processItem->Record); } else { PhDereferenceObject(processItem); return NULL; } // Set up the file name and process name. PhSwapReference(&processItem->FileName, Entry->FileName); if (processItem->FileName) { processItem->ProcessName = PhGetBaseName(processItem->FileName); } else { processItem->ProcessName = PhCreateString(L"Unknown"); } if (ProcessesMethod == BruteForceScanMethod) { status = PhOpenProcess( &processHandle, ProcessQueryAccess, Entry->ProcessId ); } else { status = PhOpenProcessByCsrHandles( &processHandle, ProcessQueryAccess, Entry->ProcessId ); } if (NT_SUCCESS(status)) { // Basic information and not-so-dynamic information processItem->QueryHandle = processHandle; if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &basicInfo))) { processItem->ParentProcessId = basicInfo.InheritedFromUniqueProcessId; processItem->BasePriority = basicInfo.BasePriority; } PhGetProcessSessionId(processHandle, &processItem->SessionId); PhPrintUInt32(processItem->ParentProcessIdString, HandleToUlong(processItem->ParentProcessId)); PhPrintUInt32(processItem->SessionIdString, processItem->SessionId); if (NT_SUCCESS(PhGetProcessTimes(processHandle, ×))) { processItem->CreateTime = times.CreateTime; processItem->KernelTime = times.KernelTime; processItem->UserTime = times.UserTime; } // TODO: Token information? if (NT_SUCCESS(NtQueryInformationProcess( processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS), NULL ))) { processItem->PriorityClass = priorityClass.PriorityClass; } if (NT_SUCCESS(NtQueryInformationProcess( processHandle, ProcessHandleCount, &handleCount, sizeof(ULONG), NULL ))) { processItem->NumberOfHandles = handleCount; } } // Stage 1 // Some copy and paste magic here... if (processItem->FileName) { // Small icon, large icon. ExtractIconEx( processItem->FileName->Buffer, 0, &processItem->LargeIcon, &processItem->SmallIcon, 1 ); // Version info. PhInitializeImageVersionInfo(&processItem->VersionInfo, processItem->FileName->Buffer); } // Use the default EXE icon if we didn't get the file's icon. { if (!processItem->SmallIcon || !processItem->LargeIcon) { if (processItem->SmallIcon) { DestroyIcon(processItem->SmallIcon); processItem->SmallIcon = NULL; } else if (processItem->LargeIcon) { DestroyIcon(processItem->LargeIcon); processItem->LargeIcon = NULL; } PhGetStockApplicationIcon(&processItem->SmallIcon, &processItem->LargeIcon); processItem->SmallIcon = DuplicateIcon(NULL, processItem->SmallIcon); processItem->LargeIcon = DuplicateIcon(NULL, processItem->LargeIcon); } } // POSIX, command line status = PhOpenProcess( &processHandle2, ProcessQueryAccess | PROCESS_VM_READ, Entry->ProcessId ); if (NT_SUCCESS(status)) { BOOLEAN isPosix = FALSE; PPH_STRING commandLine; ULONG i; status = PhGetProcessIsPosix(processHandle2, &isPosix); processItem->IsPosix = isPosix; if (!NT_SUCCESS(status) || !isPosix) { status = PhGetProcessCommandLine(processHandle2, &commandLine); if (NT_SUCCESS(status)) { // Some command lines (e.g. from taskeng.exe) have nulls in them. // Since Windows can't display them, we'll replace them with // spaces. for (i = 0; i < (ULONG)commandLine->Length / 2; i++) { if (commandLine->Buffer[i] == 0) commandLine->Buffer[i] = ' '; } } } else { // Get the POSIX command line. status = PhGetProcessPosixCommandLine(processHandle2, &commandLine); } if (NT_SUCCESS(status)) { processItem->CommandLine = commandLine; } NtClose(processHandle2); } // TODO: Other stage 1 tasks. PhSetEvent(&processItem->Stage1Event); return processItem; }