From 2acec63b2ed75bf4b71ad257db573c4b8f9639e7 Mon Sep 17 00:00:00 2001 From: tumagonx Date: Tue, 8 Aug 2017 10:54:53 +0700 Subject: initial commit --- log.c | 459 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 459 insertions(+) create mode 100644 log.c (limited to 'log.c') diff --git a/log.c b/log.c new file mode 100644 index 0000000..7048b05 --- /dev/null +++ b/log.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2004 Security Architects Corporation. All rights reserved. + * + * Module Name: + * + * log.c + * + * Abstract: + * + * This module implements various alert logging routines. + * + * Author: + * + * Eugene Tsyrklevich 24-Mar-2004 + * + * Revision History: + * + * None. + */ + + +#include "log.h" +#include "procname.h" +#include "policy.h" // CDrive declaration + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, InitLog) +#pragma alloc_text (PAGE, ShutdownLog) +#pragma alloc_text (PAGE, LogPostBootup) +#endif + + +KSPIN_LOCK gLogSpinLock; + +PKEVENT LogUserEvent = NULL; +HANDLE LogUserEventHandle = NULL; + +PSECURITY_ALERT LogList = NULL; /* alert queue */ +PSECURITY_ALERT LastAlert = NULL; /* pointer to the last queued alert, used for quick inserts */ + +USHORT NumberOfAlerts; /* number of queued alerts */ + + + +/* + * GetObjectAccessAlertPriority() + * + * Description: + * Figure out a priority for object access alert category. + * + * Parameters: + * AlertSubSystem + * Operation + * ActionTaken + * + * Returns: + * Chosen priority. + */ + +ALERT_PRIORITY +GetObjectAccessAlertPriority(UCHAR AlertSubSystem, UCHAR Operation, ACTION_TYPE ActionTaken) +{ + switch (AlertSubSystem) + { + case RULE_FILE: + case RULE_DIRECTORY: + case RULE_NAMEDPIPE: + case RULE_REGISTRY: + case RULE_SECTION: + case RULE_JOB: + case RULE_PORT: + case RULE_SYMLINK: + + /* default actions are given low priority */ + if (ActionTaken & ACTION_DEFAULT) + return ALERT_PRIORITY_LOW; + + /* non-read operations are marked medium priority */ + if (Operation != OP_READ) + return ALERT_PRIORITY_MEDIUM; + + /* whilst read operations are marked low priority */ + return ALERT_PRIORITY_LOW; + + + /* high priority rules */ + case RULE_DLL: + case RULE_PROCESS: + case RULE_DRIVER: + case RULE_NETWORK: + case RULE_SERVICE: + + return ALERT_PRIORITY_HIGH; + + + case RULE_TIME: + case RULE_TOKEN: + + return ALERT_PRIORITY_MEDIUM; + + + /* low priority rules */ + case RULE_MAILSLOT: + case RULE_EVENT: + case RULE_SEMAPHORE: + case RULE_MUTANT: + case RULE_DIROBJ: + case RULE_ATOM: + case RULE_SYSCALL: + case RULE_TIMER: + + return ALERT_PRIORITY_LOW; + + + default: + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("GetAlertPriority: Unknown alert subsystem %d\n", AlertSubSystem)); + return ALERT_PRIORITY_MEDIUM; + } +} + + + +/* + * FilterObjectName() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ +//XXX move elsewhere +PCHAR +FilterObjectName(PCHAR ObjectName) +{ + if (_strnicmp(ObjectName, "\\??\\PIPE\\", 9) == 0) + return ObjectName + 3; + + if (_strnicmp(ObjectName, "\\??\\", 4) == 0) + return ObjectName + 4; + + if (_strnicmp(ObjectName, "\\DosDevices\\", 12) == 0) + return ObjectName + 12; + + if (_strnicmp(ObjectName, "\\BaseNamedObjects\\", 18) == 0) + return ObjectName + 18; + + if (_strnicmp(ObjectName, CDrive, CDriveLength) == 0 && CDriveLength) + { + /* replace any possible \device\harddiskvolumeX references with a DOS C:\ name */ + ObjectName[CDriveLength-2] = 'C'; + ObjectName[CDriveLength-1] = ':'; + + ObjectName += CDriveLength - 2; + } + + + return ObjectName; +} + + + +/* + * LogAlert() + * + * Description: + * . + * + * Parameters: + * . + * + * Returns: + * Nothing. + */ + +VOID +LogAlert(UCHAR AlertSubSystem, UCHAR OperationType, UCHAR AlertRuleNumber, ACTION_TYPE ActionTaken, ALERT_PRIORITY AlertPriority, PWSTR PolicyFilename, USHORT PolicyLineNumber, PCHAR ObjectName) +{ + USHORT Size; + PSECURITY_ALERT pAlert; + KIRQL irql; + +#define NAME_BUFFER_SIZE 256 + ANSI_STRING asObjectName; + UNICODE_STRING usObjectName; + WCHAR ProcessName[NAME_BUFFER_SIZE], ObjectNameW[NAME_BUFFER_SIZE] = { 0 }; + USHORT ObjectNameLength = 0, ProcessNameLength = 0, PolicyNameLength = 0; + +/* + if (PolicyFilename == NULL) + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, (("LogAlert: NULL PolicyFilename\n")); + return; + } +*/ + + /* \KnownDlls section rules need to be converted to DLLs */ + if (AlertSubSystem == RULE_SECTION) + { + if (_strnicmp(ObjectName, "\\KnownDlls\\", 11) == 0) + { + ObjectName += 11; + AlertSubSystem = RULE_DLL; + OperationType = OP_LOAD; + } + } + + + if (ObjectName) + { + ObjectName = FilterObjectName(ObjectName); + + usObjectName.Length = 0; + usObjectName.MaximumLength = sizeof(ObjectNameW); + usObjectName.Buffer = ObjectNameW; + + RtlInitAnsiString(&asObjectName, ObjectName); + + RtlAnsiStringToUnicodeString(&usObjectName, &asObjectName, FALSE); + ObjectNameW[ asObjectName.Length ] = 0; + } + + + wcsncpy(ProcessName, GetCurrentProcessName(), NAME_BUFFER_SIZE - 1); + ProcessName[NAME_BUFFER_SIZE - 1] = 0; + + + /* + * extra +1 for ProcessName & PolicyName zero termination + * (ObjectName zero is covered by SECURITY_ALERT wchar[1] declaration) + */ + + if (ObjectName) + ObjectNameLength = (USHORT) wcslen(ObjectNameW); + + ProcessNameLength = (USHORT) wcslen(ProcessName); + + if (PolicyFilename) + PolicyNameLength = (USHORT) wcslen(PolicyFilename); + + Size = sizeof(SECURITY_ALERT) + (ObjectNameLength + ProcessNameLength + 1 + PolicyNameLength + 1) * sizeof(WCHAR); + + + if ((pAlert = (PSECURITY_ALERT) GetCurrentUserSid(&Size)) == NULL) + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("NULL UserInfo. Security Alert\n")); + return; + } + + + pAlert->Next = NULL; + pAlert->Size = Size; + pAlert->AlertSubsystem = AlertSubSystem; + pAlert->AlertType = OperationType; + pAlert->AlertRuleNumber = AlertRuleNumber; + pAlert->Priority = AlertPriority; + pAlert->ObjectNameLength = ObjectNameLength; + pAlert->ProcessNameLength = ProcessNameLength; + pAlert->PolicyNameLength = PolicyNameLength; + pAlert->ProcessId = (ULONG) PsGetCurrentProcessId(); + pAlert->Action = ActionTaken; + pAlert->PolicyLineNumber = PolicyLineNumber; + + + if (ObjectName) + wcscpy(pAlert->ObjectName, ObjectNameW); + + /* process name follows the object name */ + wcscpy(pAlert->ObjectName + ObjectNameLength + 1, ProcessName); + + /* policy name follows the process name */ + if (PolicyFilename) + wcscpy(pAlert->ObjectName + ObjectNameLength + 1 + ProcessNameLength + 1, PolicyFilename); + + /* save the alert for user agent to pick-up */ + if (ObjectName) + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%S Alert. Name %S. Object type %d. Alert type %d.\n", ProcessName, pAlert->ObjectName, pAlert->AlertSubsystem, pAlert->AlertType)); + } + else + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("%S Alert. Object type %d. Alert type %d.\n", ProcessName, pAlert->AlertSubsystem, pAlert->AlertType)); + } + + + KeAcquireSpinLock(&gLogSpinLock, &irql); + { + /* + * Put a ceiling on how many alerts we can queue, otherwise we can run out of memory + * if userland service is down + */ + + if (NumberOfAlerts > MAXIMUM_OUTSTANDING_ALERTS) + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("LogAlert: Exceeded maximum number of queued alerts. Dropping.\n")); + + ExFreePoolWithTag(pAlert, _POOL_TAG); + + KeReleaseSpinLock(&gLogSpinLock, irql); + + return; + } + + ++NumberOfAlerts; + + /* + * Append alerts to the end of the list so that they show up in a proper order when + * picked up by the userland service + */ + + if (LogList == NULL) + { + /* first alert on the list */ + LastAlert = LogList = pAlert; + } + else + { + LastAlert->Next = pAlert; + LastAlert = pAlert; + } + +// pAlert->Next = LogList; +// LogList = pAlert; + } + KeReleaseSpinLock(&gLogSpinLock, irql); + + + /* + * Pulse the event to notify the user agent. + * User-mode apps can't reset a kernel mode event, which is why we're pulsing it here. + */ + + if (LogUserEvent) + { + KeSetEvent(LogUserEvent, 0, FALSE); + KeClearEvent(LogUserEvent); + } +} + + + +/* + * LogPostBootup() + * + * Description: + * Initializes logging related data once computer is done booting up. + * + * \BaseNamedObjects object directory is not created until the Win32® system initializes. + * Therefore, drivers that are loaded at boot time cannot create event objects in their DriverEntry + * routines that are visible to user-mode programs. + * + * Parameters: + * None. + * + * Returns: + * TRUE to indicate success, FALSE if failed. + */ + +BOOLEAN +LogPostBootup() +{ + UNICODE_STRING uszLogEventString; + + + ASSERT(BootingUp == FALSE); + + + /* Create events for user-mode processes to monitor */ + RtlInitUnicodeString(&uszLogEventString, LOG_USER_EVENT_NAME); + + + if ((LogUserEvent = IoCreateNotificationEvent(&uszLogEventString, &LogUserEventHandle)) == NULL) + { + LOG(LOG_SS_MISC, LOG_PRIORITY_DEBUG, ("LogPostBootup: IoCreateNotificationEvent failed\n")); + return FALSE; + } + + KeClearEvent(LogUserEvent); + + + return TRUE; +} + + + +/* + * InitLog() + * + * Description: + * Initializes logging related data. + * + * NOTE: Called once during driver initialization (DriverEntry()). + * + * Parameters: + * None. + * + * Returns: + * TRUE to indicate success, FALSE if failed. + */ + +BOOLEAN +InitLog() +{ + KeInitializeSpinLock(&gLogSpinLock); + + + if (BootingUp == FALSE) + + return LogPostBootup(); + + + return TRUE; +} + + + +/* + * ShutdownLog() + * + * Description: + * Clean up the logging subsystem - close all the handles & delete any outstanding alerts. + * + * NOTE: Called once during driver unload (DriverUnload()). + * + * Parameters: + * None. + * + * Returns: + * Nothing. + */ + +VOID +ShutdownLog() +{ + PSECURITY_ALERT tmp; + KIRQL irql; + + + if (LogUserEventHandle) + ZwClose(LogUserEventHandle); + + + /* XXX logs will need to be flushed to a file and then sent to MC */ + KeAcquireSpinLock(&gLogSpinLock, &irql); + { + while (LogList) + { + tmp = LogList; + LogList = LogList->Next; + + ExFreePoolWithTag(tmp, _POOL_TAG); + } + } + KeReleaseSpinLock(&gLogSpinLock, irql); +} -- cgit v1.3