微軟文檔介紹說,
安全日志在其他兩個重要方面與其他日志不同。首先,在默認配置中,它受到強大的訪問控制列表(ACL)和特權檢查的保護,這將可以讀取其內容的個人的范圍限制為本地系統,管理員和安全特權的持有者。其次,也是最重要的一點,只允許一個實體(本地安全機構(LSA))寫入安全日志。這實際上意味着,每次嘗試為安全日志調用RegisterEventSource API時,即使您以本地系統身份運行,也會收到ACCESS_DENIED錯誤!這種設計可確保安全日志僅包含來自受信任來源的信息。
在Windows Server 2003中,安全日志寫訪問限制在某種程度上得到了放松,而沒有通過引入一組特殊的API來更改基本設計(請參見圖2)。這些API在內部使用本地過程調用(LPC)與LSA進行交互,指示LSA代表應用程序生成審核日志。該機制優雅而簡單。
首先,應用程序通過調用AuthzRegisterSecurityEventSource向LSA注冊安全事件源句柄。此API唯一感興趣的參數是事件源的名稱,該名稱可以是幾乎任何內容,並受一些限制。例如,它不能命名為“ Security”,因為該名稱保留供系統使用。在以下步驟中使用此調用返回的安全事件源句柄。
接下來,通過調用兩個緊密相關的API之一來生成事件:AuthzReportSecurityEvent或AuthzReportSecurityEventFromParams。最后,當應用程序關閉時,它將通過調用AuthzUnregisterSecurityEventSource取消注冊安全事件源句柄。
在編譯代碼之前,我們需要賦予當前用戶相關的權限,也就是Generate Security audits
具體步驟:
在開始菜單中,打開Local Security Policy,如下圖,

找到Generate Security audits, 在里面添加當前用戶,我們的計算機一般是以管理員身份運行的,所以可以將管理員也添加進來(添加完需要將電腦重啟,以使組策略生效)。
如果是以管理員身份運行的,那么我們在編譯代碼時,也需要以管理員身份運行代碼。不然還是無法獲取SeAuditPrivilege權限。
另外,我們還需要在Audit Policy中Enable Audit object access的Success,Failure, 見下圖,

代碼示例:
#include <stdio.h> #include <iostream> #include <string> #include <strsafe.h> #include <windows.h> #include <Authz.h> #include <Ntsecapi.h> #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) #pragma comment(lib,"Authz.lib") #pragma comment(lib,"Advapi32.lib") void print_privileges(HANDLE hToken); BOOL SetPrivilege( HANDLE hToken, // access token handle LPCTSTR lpszPrivilege, // name of privilege to enable/disable BOOL bEnablePrivilege // to enable or disable privilege ) { TOKEN_PRIVILEGES tp; LUID luid; if (!LookupPrivilegeValue( NULL, // lookup privilege on local system lpszPrivilege, // privilege to lookup &luid)) // receives LUID of privilege { printf("LookupPrivilegeValue error: %u\n", GetLastError()); return FALSE; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if (bEnablePrivilege) tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; else tp.Privileges[0].Attributes = 0; // Enable the privilege or disable all privileges. if (!AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { printf("AdjustTokenPrivileges error: %u\n", GetLastError()); return FALSE; } if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { printf("The token does not have the specified privilege. \n"); return FALSE; } printf("Get the specified privilege! \n"); return TRUE; } int main(int argc, const char* argv[]) { // Declare and initialize variables. BOOL bResult = TRUE; DWORD event_id = 4624; AUTHZ_SECURITY_EVENT_PROVIDER_HANDLE hEventProvider = NULL; PAUDIT_PARAMS p; std::string Source_Name = "Test security audit"; std::wstring ws; std::string pbuf = "What is your purpose ?"; std::wstring ws_buf; int return_code = 0; int i = 0; // Register the audit provider. HANDLE token; HANDLE hevent_source; ws.assign(Source_Name.begin(), Source_Name.end()); ws_buf.assign(pbuf.begin(), pbuf.end()); if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) return FALSE; SetPrivilege(token, L"SeAuditPrivilege", true); print_privileges(token); AUTHZ_SOURCE_SCHEMA_REGISTRATION ar; memset(&ar, 0, sizeof(ar)); ar.dwFlags = AUTHZ_ALLOW_MULTIPLE_SOURCE_INSTANCES; ar.szEventSourceName = &ws[0]; ar.szEventMessageFile = &ws_buf[0]; ar.szEventSourceXmlSchemaFile = NULL; ar.szEventAccessStringsFile = &ws_buf[0]; ar.szExecutableImagePath = NULL; AuthzInstallSecurityEventSource(0, &ar); bResult = AuthzRegisterSecurityEventSource(0, ws.c_str(), &hEventProvider); int err = GetLastError(); if (!bResult) { printf("AuthzRegisterSecurityEventSource failed, error is %d\n", err); return_code = -1; } SID id; if (hEventProvider) { // Generate the audit. while (i < 10) { bResult = AuthzReportSecurityEvent( APF_AuditSuccess, hEventProvider, event_id, NULL, 3, APT_String, L"Jay Hamlin", APT_String, L"March 21, 1960", APT_Ulong, 45); int err1 = GetLastError(); if (!bResult) { printf("AuthzReportSecurityEvent failed, error is %d\n", err1); return_code = -2; break; } i++; } AuthzUnregisterSecurityEventSource(0, &hEventProvider); AuthzUninstallSecurityEventSource(0, &ws[0]); } std::cout << "Exit : " << return_code << std::endl; getchar(); } void print_privileges(HANDLE hToken) { DWORD size = 0; if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &size) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)malloc(size); if (tp != NULL && GetTokenInformation(hToken, TokenPrivileges, tp, size, &size)) { size_t i; for (i = 0; i < tp->PrivilegeCount; ++i) { char name[64] = "?"; DWORD name_size = sizeof name; LookupPrivilegeNameA(0, &tp->Privileges[i].Luid, name, &name_size); PRIVILEGE_SET ps = { 1, PRIVILEGE_SET_ALL_NECESSARY, { { { tp->Privileges[i].Luid.LowPart, tp->Privileges[i].Luid.HighPart } } } }; BOOL fResult; PrivilegeCheck(hToken, &ps, &fResult); printf("%-*s %s\n", 32, name, fResult ? "Enabled" : "Disabled"); } } free(tp); } }
在運行過程中,首先確定是否獲取了我們需要的權限。

如果是Enabled的狀態,說明獲取權限成功,后面只需要通過AuthzRegisterSecurityEventSource和AuthzReportSecurityEvent這兩個api與LSA進行交互,從而寫入安全日志。
最后的結果:

