mirror of
https://github.com/8damon/Blackbird-Platform
synced 2026-06-21 13:41:12 +00:00
d68c57008e
Replace Blackbird_controller.c with controller.cpp. The C++ translation uses RAII for the log file and service handles through a ControllerLogger class, removing the manual critical-section teardown paths. Refs #11.
222 lines
7.1 KiB
C++
222 lines
7.1 KiB
C++
#include "core/blackbird_controller_private.h"
|
|
|
|
#pragma comment(lib, "advapi32.lib")
|
|
#pragma comment(lib, "tdh.lib")
|
|
|
|
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = NULL;
|
|
SERVICE_STATUS g_ServiceStatus;
|
|
HANDLE g_StopEvent = NULL;
|
|
|
|
static HANDLE g_LogFile = INVALID_HANDLE_VALUE;
|
|
static CRITICAL_SECTION g_LogLock;
|
|
static BOOL g_LogLockInitialized = FALSE;
|
|
HANDLE g_ServerThread = NULL;
|
|
HANDLE g_DriverPumpThread = NULL;
|
|
HANDLE g_EtwThread = NULL;
|
|
HANDLE g_DriverHandle = INVALID_HANDLE_VALUE;
|
|
BLACKBIRDSC_ETW_SESSION *g_EtwSession = NULL;
|
|
BOOL g_ThreatIntelEnabled = FALSE;
|
|
DWORD g_ThreatIntelEnableError = ERROR_SUCCESS;
|
|
volatile LONG g_EtwDetectionEvents = 0;
|
|
volatile LONG g_EtwTiEvents = 0;
|
|
CRITICAL_SECTION g_ClientListLock;
|
|
CRITICAL_SECTION g_DriverLock;
|
|
CRITICAL_SECTION g_DriverConfigLock;
|
|
BOOL g_LocksInitialized = FALSE;
|
|
volatile LONG g_DriverSubscriptionsDirty = 0;
|
|
PBLACKBIRD_CONTROLLER_CLIENT g_ClientList = NULL;
|
|
PBLACKBIRD_CONTROLLER_CLIENT g_ClientSlots[BLACKBIRD_CONTROLLER_MAX_CLIENTS];
|
|
DWORD g_ClientCount = 0;
|
|
volatile DWORD g_AuthorizedControlProcessId = 0;
|
|
volatile DWORD g_AuthorizedControlSessionId = 0;
|
|
DWORD g_ProgrammedPids[BLACKBIRD_MAX_PID_LIST];
|
|
DWORD g_ProgrammedPidCount = 0;
|
|
BLACKBIRD_CONTROLLER_PID_INDEX_ENTRY g_PidIndex[BLACKBIRD_MAX_PID_LIST];
|
|
DWORD g_PidIndexCount = 0;
|
|
SRWLOCK g_HollowLock = SRWLOCK_INIT;
|
|
BLACKBIRD_CONTROLLER_HOLLOW_ENTRY g_HollowEntries[BLACKBIRD_CONTROLLER_HOLLOW_MAX_ENTRIES];
|
|
|
|
VOID ControllerLogInit(VOID)
|
|
{
|
|
CHAR logDir[MAX_PATH];
|
|
CHAR logPath[MAX_PATH];
|
|
CHAR rotatePath[MAX_PATH];
|
|
CHAR intermediate[MAX_PATH];
|
|
DWORD expanded;
|
|
LARGE_INTEGER fileSize;
|
|
HANDLE probe;
|
|
|
|
if (!g_LogLockInitialized)
|
|
{
|
|
InitializeCriticalSection(&g_LogLock);
|
|
g_LogLockInitialized = TRUE;
|
|
}
|
|
|
|
EnterCriticalSection(&g_LogLock);
|
|
__try
|
|
{
|
|
if (g_LogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
__leave;
|
|
}
|
|
|
|
// Build the log directory path: %ProgramData%\Blackbird\Node\logs
|
|
expanded = ExpandEnvironmentStringsA("%ProgramData%\\Blackbird", intermediate, RTL_NUMBER_OF(intermediate));
|
|
if (expanded > 0 && expanded <= RTL_NUMBER_OF(intermediate))
|
|
{
|
|
CreateDirectoryA(intermediate, NULL);
|
|
}
|
|
expanded =
|
|
ExpandEnvironmentStringsA("%ProgramData%\\Blackbird\\Node", intermediate, RTL_NUMBER_OF(intermediate));
|
|
if (expanded > 0 && expanded <= RTL_NUMBER_OF(intermediate))
|
|
{
|
|
CreateDirectoryA(intermediate, NULL);
|
|
}
|
|
expanded = ExpandEnvironmentStringsA("%ProgramData%\\Blackbird\\Node\\logs", logDir, RTL_NUMBER_OF(logDir));
|
|
if (expanded == 0 || expanded > RTL_NUMBER_OF(logDir))
|
|
{
|
|
__leave;
|
|
}
|
|
CreateDirectoryA(logDir, NULL);
|
|
|
|
(void)StringCchPrintfA(logPath, RTL_NUMBER_OF(logPath), "%s\\controller.log", logDir);
|
|
(void)StringCchPrintfA(rotatePath, RTL_NUMBER_OF(rotatePath), "%s\\controller.log.1", logDir);
|
|
|
|
// Rotate if existing log exceeds 4 MB so the file stays small enough for the UI to tail.
|
|
probe = CreateFileA(logPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
OPEN_EXISTING, 0, NULL);
|
|
if (probe != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (GetFileSizeEx(probe, &fileSize) && fileSize.QuadPart > (4LL * 1024 * 1024))
|
|
{
|
|
CloseHandle(probe);
|
|
probe = INVALID_HANDLE_VALUE;
|
|
(void)MoveFileExA(logPath, rotatePath, MOVEFILE_REPLACE_EXISTING);
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(probe);
|
|
probe = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
// Open with FILE_APPEND_DATA and share-read so the interface can tail it concurrently.
|
|
g_LogFile = CreateFileA(logPath, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
__finally
|
|
{
|
|
LeaveCriticalSection(&g_LogLock);
|
|
}
|
|
}
|
|
|
|
VOID ControllerLogClose(VOID)
|
|
{
|
|
if (!g_LogLockInitialized)
|
|
{
|
|
return;
|
|
}
|
|
EnterCriticalSection(&g_LogLock);
|
|
if (g_LogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
FlushFileBuffers(g_LogFile);
|
|
CloseHandle(g_LogFile);
|
|
g_LogFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
LeaveCriticalSection(&g_LogLock);
|
|
}
|
|
|
|
VOID ControllerLog(_In_z_ _Printf_format_string_ PCSTR Format, ...)
|
|
{
|
|
char message[1024];
|
|
char stamped[1080];
|
|
SYSTEMTIME st;
|
|
va_list args;
|
|
DWORD written;
|
|
|
|
va_start(args, Format);
|
|
(void)StringCchVPrintfA(message, RTL_NUMBER_OF(message), Format, args);
|
|
va_end(args);
|
|
|
|
(void)OutputDebugStringA(message);
|
|
(void)printf("%s", message);
|
|
|
|
if (g_LogLockInitialized && g_LogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
GetLocalTime(&st);
|
|
// Strip trailing newline from message before adding our own; keeps the log tidy.
|
|
SIZE_T msgLen = strlen(message);
|
|
while (msgLen > 0 && (message[msgLen - 1] == '\n' || message[msgLen - 1] == '\r'))
|
|
{
|
|
message[--msgLen] = '\0';
|
|
}
|
|
(void)StringCchPrintfA(stamped, RTL_NUMBER_OF(stamped), "[%04u-%02u-%02u %02u:%02u:%02u] %s\r\n", st.wYear,
|
|
st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, message);
|
|
EnterCriticalSection(&g_LogLock);
|
|
if (g_LogFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
(void)WriteFile(g_LogFile, stamped, (DWORD)strlen(stamped), &written, NULL);
|
|
}
|
|
LeaveCriticalSection(&g_LogLock);
|
|
}
|
|
}
|
|
|
|
VOID ControllerUpdateServiceStatus(_In_ DWORD CurrentState, _In_ DWORD Win32ExitCode, _In_ DWORD WaitHint)
|
|
{
|
|
static DWORD checkpoint = 1;
|
|
|
|
if (g_ServiceStatusHandle == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
g_ServiceStatus.dwCurrentState = CurrentState;
|
|
g_ServiceStatus.dwWin32ExitCode = Win32ExitCode;
|
|
g_ServiceStatus.dwWaitHint = WaitHint;
|
|
g_ServiceStatus.dwControlsAccepted = 0;
|
|
g_ServiceStatus.dwCheckPoint = 0;
|
|
|
|
if (CurrentState == SERVICE_START_PENDING || CurrentState == SERVICE_STOP_PENDING)
|
|
{
|
|
g_ServiceStatus.dwCheckPoint = checkpoint++;
|
|
}
|
|
|
|
if (CurrentState == SERVICE_RUNNING)
|
|
{
|
|
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
|
}
|
|
|
|
(void)SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
|
|
}
|
|
|
|
BOOL ControllerShouldStop(VOID)
|
|
{
|
|
return (g_StopEvent != NULL && WaitForSingleObject(g_StopEvent, 0) == WAIT_OBJECT_0);
|
|
}
|
|
|
|
VOID ControllerStopEtwSessionByNameBestEffort(_In_z_ PCWSTR SessionName, _In_z_ PCSTR Reason)
|
|
{
|
|
ULONG status;
|
|
|
|
if (SessionName == NULL || SessionName[0] == L'\0')
|
|
{
|
|
return;
|
|
}
|
|
|
|
status = BLACKBIRDSCStopSessionByName(SessionName);
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
ControllerLog("[ETW] stopped session reason=%s name=%ws\n", Reason, SessionName);
|
|
}
|
|
else
|
|
{
|
|
ControllerLog("[ETW][WARN] stop-by-name failed reason=%s name=%ws status=%lu\n", Reason, SessionName, status);
|
|
}
|
|
}
|
|
|
|
VOID ControllerCleanupStaleEtwSessions(VOID)
|
|
{
|
|
ControllerStopEtwSessionByNameBestEffort(BLACKBIRD_CONTROLLER_ETW_SESSION_NAMEW, "pre-start");
|
|
}
|