mirror of
https://github.com/8damon/Blackbird-Platform
synced 2026-06-21 13:41:12 +00:00
376 lines
12 KiB
C++
376 lines
12 KiB
C++
#include "core/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;
|
|
|
|
class ControllerLogger
|
|
{
|
|
public:
|
|
ControllerLogger() noexcept = default;
|
|
~ControllerLogger() noexcept
|
|
{
|
|
Close();
|
|
}
|
|
|
|
ControllerLogger(const ControllerLogger &) = delete;
|
|
ControllerLogger &operator=(const ControllerLogger &) = delete;
|
|
|
|
void Init() noexcept
|
|
{
|
|
CHAR logDir[MAX_PATH];
|
|
CHAR logPath[MAX_PATH];
|
|
CHAR rotatePath[MAX_PATH];
|
|
CHAR intermediate[MAX_PATH];
|
|
DWORD expanded;
|
|
|
|
ScopedCriticalSection guard(m_lock);
|
|
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
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))
|
|
{
|
|
return;
|
|
}
|
|
CreateDirectoryA(logDir, NULL);
|
|
ApplyLogDirectoryAcl(logDir);
|
|
|
|
(void)StringCchPrintfA(logPath, RTL_NUMBER_OF(logPath), "%s\\controller.log", logDir);
|
|
(void)StringCchPrintfA(rotatePath, RTL_NUMBER_OF(rotatePath), "%s\\controller.log.1", logDir);
|
|
|
|
HANDLE probe = CreateFileA(logPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
OPEN_EXISTING, 0, NULL);
|
|
if (probe != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(probe);
|
|
(void)MoveFileExA(logPath, rotatePath, MOVEFILE_REPLACE_EXISTING);
|
|
}
|
|
|
|
m_file = CreateFileA(logPath, FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
LARGE_INTEGER end = {};
|
|
(void)SetFilePointerEx(m_file, end, NULL, FILE_END);
|
|
}
|
|
}
|
|
|
|
void Close() noexcept
|
|
{
|
|
ScopedCriticalSection guard(m_lock);
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
FlushFileBuffers(m_file);
|
|
CloseHandle(m_file);
|
|
m_file = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
static bool TagEquals(_In_reads_(tagLen) PCSTR tag, _In_ SIZE_T tagLen, _In_z_ PCSTR expected) noexcept
|
|
{
|
|
SIZE_T expectedLen = strlen(expected);
|
|
return tagLen == expectedLen && _strnicmp(tag, expected, expectedLen) == 0;
|
|
}
|
|
|
|
static bool IsSeverityTag(_In_reads_(tagLen) PCSTR tag, _In_ SIZE_T tagLen) noexcept
|
|
{
|
|
return TagEquals(tag, tagLen, "WARN") || TagEquals(tag, tagLen, "ERR") || TagEquals(tag, tagLen, "ERROR") ||
|
|
TagEquals(tag, tagLen, "INFO") || TagEquals(tag, tagLen, "DIAG") || TagEquals(tag, tagLen, "PANIC");
|
|
}
|
|
|
|
static PCSTR ComponentForTag(_In_reads_(tagLen) PCSTR tag, _In_ SIZE_T tagLen) noexcept
|
|
{
|
|
if (TagEquals(tag, tagLen, "DRIVER"))
|
|
{
|
|
return "blackbird.sys";
|
|
}
|
|
if (TagEquals(tag, tagLen, "NETSVC") || TagEquals(tag, tagLen, "NODE"))
|
|
{
|
|
return "BlackbirdNetSvc.exe";
|
|
}
|
|
if (TagEquals(tag, tagLen, "INJ") || TagEquals(tag, tagLen, "HOOK"))
|
|
{
|
|
return "SR71.dll";
|
|
}
|
|
if (TagEquals(tag, tagLen, "IPC") || TagEquals(tag, tagLen, "ETW") || TagEquals(tag, tagLen, "MON") ||
|
|
TagEquals(tag, tagLen, "MITIGATION") || TagEquals(tag, tagLen, "WARN") || TagEquals(tag, tagLen, "ERR") ||
|
|
TagEquals(tag, tagLen, "ERROR") || TagEquals(tag, tagLen, "INFO") || TagEquals(tag, tagLen, "*") ||
|
|
TagEquals(tag, tagLen, "-"))
|
|
{
|
|
return "BlackbirdController.exe";
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void ApplyLogDirectoryAcl(_In_z_ PCSTR logDir) noexcept
|
|
{
|
|
PSECURITY_DESCRIPTOR securityDescriptor = NULL;
|
|
|
|
if (logDir == NULL || logDir[0] == '\0')
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
|
"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GRGW;;;BU)", SDDL_REVISION_1, &securityDescriptor, NULL) &&
|
|
securityDescriptor != NULL)
|
|
{
|
|
(void)SetFileSecurityA(logDir, DACL_SECURITY_INFORMATION, securityDescriptor);
|
|
LocalFree(securityDescriptor);
|
|
}
|
|
}
|
|
|
|
static void NormalizeComponentPrefix(_In_z_ PCSTR message, _Out_writes_z_(normalizedChars) PSTR normalized,
|
|
_In_ SIZE_T normalizedChars) noexcept
|
|
{
|
|
PCSTR close;
|
|
PCSTR component;
|
|
PCSTR tail;
|
|
SIZE_T tagLen;
|
|
|
|
if (normalized == NULL || normalizedChars == 0)
|
|
{
|
|
return;
|
|
}
|
|
normalized[0] = '\0';
|
|
|
|
if (message == NULL || message[0] != '[')
|
|
{
|
|
(void)StringCchCopyA(normalized, normalizedChars, message != NULL ? message : "");
|
|
return;
|
|
}
|
|
|
|
close = strchr(message + 1, ']');
|
|
if (close == NULL || close == message + 1)
|
|
{
|
|
(void)StringCchCopyA(normalized, normalizedChars, message);
|
|
return;
|
|
}
|
|
|
|
tagLen = (SIZE_T)(close - (message + 1));
|
|
component = ComponentForTag(message + 1, tagLen);
|
|
if (component == NULL)
|
|
{
|
|
(void)StringCchCopyA(normalized, normalizedChars, message);
|
|
return;
|
|
}
|
|
tail = close + 1;
|
|
if (_stricmp(component, "BlackbirdController.exe") == 0 && _strnicmp(tail, " BlackbirdController:", 21) == 0)
|
|
{
|
|
tail += 21;
|
|
}
|
|
|
|
if (IsSeverityTag(message + 1, tagLen))
|
|
{
|
|
(void)StringCchPrintfA(normalized, normalizedChars, "[%s][%.*s]%s", component, (int)tagLen, message + 1,
|
|
tail);
|
|
}
|
|
else
|
|
{
|
|
(void)StringCchPrintfA(normalized, normalizedChars, "[%s]%s", component, tail);
|
|
}
|
|
}
|
|
|
|
void Log(_In_z_ _Printf_format_string_ PCSTR fmt, va_list args) noexcept
|
|
{
|
|
char message[2048];
|
|
char normalized[2048];
|
|
char stamped[2200];
|
|
SYSTEMTIME st;
|
|
DWORD written;
|
|
|
|
(void)StringCchVPrintfA(message, RTL_NUMBER_OF(message), fmt, args);
|
|
NormalizeComponentPrefix(message, normalized, RTL_NUMBER_OF(normalized));
|
|
|
|
(void)OutputDebugStringA(normalized);
|
|
(void)printf("%s", normalized);
|
|
|
|
if (m_file == INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetLocalTime(&st);
|
|
SIZE_T msgLen = strlen(normalized);
|
|
while (msgLen > 0 && (normalized[msgLen - 1] == '\n' || normalized[msgLen - 1] == '\r'))
|
|
{
|
|
normalized[--msgLen] = '\0';
|
|
}
|
|
(void)StringCchPrintfA(stamped, RTL_NUMBER_OF(stamped),
|
|
"[%04u-%02u-%02u %02u:%02u:%02u pid=%lu tid=%lu] %s\r\n", st.wYear, st.wMonth, st.wDay,
|
|
st.wHour, st.wMinute, st.wSecond, GetCurrentProcessId(), GetCurrentThreadId(),
|
|
normalized);
|
|
|
|
ScopedCriticalSection guard(m_lock);
|
|
if (m_file != INVALID_HANDLE_VALUE)
|
|
{
|
|
(void)WriteFile(m_file, stamped, (DWORD)strlen(stamped), &written, NULL);
|
|
(void)FlushFileBuffers(m_file);
|
|
}
|
|
}
|
|
|
|
private:
|
|
OwnedCriticalSection m_lock;
|
|
HANDLE m_file = INVALID_HANDLE_VALUE;
|
|
};
|
|
|
|
static ControllerLogger g_Log;
|
|
|
|
HANDLE g_ServerThread = NULL;
|
|
HANDLE g_DriverPumpThread = NULL;
|
|
HANDLE g_EtwThread = NULL;
|
|
HANDLE g_DriverHandle = INVALID_HANDLE_VALUE;
|
|
BKSC_ETW_SESSION *g_EtwSession = NULL;
|
|
BOOL g_ThreatIntelEnabled = FALSE;
|
|
DWORD g_ThreatIntelEnableError = ERROR_SUCCESS;
|
|
volatile LONG g_EtwDetectionEvents = 0;
|
|
volatile LONG g_EtwTiEvents = 0;
|
|
OwnedCriticalSection g_ClientListLock;
|
|
OwnedCriticalSection g_DriverLock;
|
|
OwnedCriticalSection g_DriverConfigLock;
|
|
volatile LONG g_DriverSubscriptionsDirty = 0;
|
|
PBK_CONTROLLER_CLIENT g_ClientList = NULL;
|
|
PBK_CONTROLLER_CLIENT g_ClientSlots[BK_CONTROLLER_MAX_CLIENTS];
|
|
DWORD g_ClientCount = 0;
|
|
DWORD g_ProgrammedPids[BK_MAX_PID_LIST];
|
|
DWORD g_ProgrammedPidCount = 0;
|
|
BK_CONTROLLER_PID_INDEX_ENTRY g_PidIndex[BK_MAX_PID_LIST];
|
|
DWORD g_PidIndexCount = 0;
|
|
SRWLOCK g_HollowLock = SRWLOCK_INIT;
|
|
BK_CONTROLLER_HOLLOW_ENTRY g_HollowEntries[BK_CONTROLLER_HOLLOW_MAX_ENTRIES];
|
|
|
|
VOID ControllerLogInit(VOID)
|
|
{
|
|
g_Log.Init();
|
|
}
|
|
|
|
VOID ControllerLogClose(VOID)
|
|
{
|
|
g_Log.Close();
|
|
}
|
|
|
|
VOID ControllerLog(_In_z_ _Printf_format_string_ PCSTR Format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, Format);
|
|
g_Log.Log(Format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
VOID ControllerApplyProcessMitigations(VOID)
|
|
{
|
|
PROCESS_MITIGATION_DYNAMIC_CODE_POLICY dynamicCode = {};
|
|
PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY extensionPoints = {};
|
|
PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY strictHandles = {};
|
|
PROCESS_MITIGATION_IMAGE_LOAD_POLICY imageLoad = {};
|
|
|
|
SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
|
|
dynamicCode.ProhibitDynamicCode = 1;
|
|
dynamicCode.AllowThreadOptOut = 0;
|
|
dynamicCode.AllowRemoteDowngrade = 0;
|
|
if (!SetProcessMitigationPolicy(ProcessDynamicCodePolicy, &dynamicCode, sizeof(dynamicCode)))
|
|
{
|
|
ControllerLog("[MITIGATION][WARN] dynamic-code mitigation failed err=%lu\n", GetLastError());
|
|
}
|
|
|
|
extensionPoints.DisableExtensionPoints = 1;
|
|
if (!SetProcessMitigationPolicy(ProcessExtensionPointDisablePolicy, &extensionPoints, sizeof(extensionPoints)))
|
|
{
|
|
ControllerLog("[MITIGATION][WARN] extension-point mitigation failed err=%lu\n", GetLastError());
|
|
}
|
|
|
|
strictHandles.RaiseExceptionOnInvalidHandleReference = 1;
|
|
strictHandles.HandleExceptionsPermanentlyEnabled = 1;
|
|
if (!SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, &strictHandles, sizeof(strictHandles)))
|
|
{
|
|
ControllerLog("[MITIGATION][WARN] strict-handle mitigation failed err=%lu\n", GetLastError());
|
|
}
|
|
|
|
imageLoad.NoRemoteImages = 1;
|
|
imageLoad.NoLowMandatoryLabelImages = 1;
|
|
imageLoad.PreferSystem32Images = 1;
|
|
if (!SetProcessMitigationPolicy(ProcessImageLoadPolicy, &imageLoad, sizeof(imageLoad)))
|
|
{
|
|
ControllerLog("[MITIGATION][WARN] image-load mitigation failed err=%lu\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
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 = BkscStopSessionByName(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(BK_CONTROLLER_ETW_SESSION_NAMEW, "pre-start");
|
|
}
|