如何通过AuthzReportSecurityEvent为安全日志添加Data Name字段
问题描述
我写了一段用AuthzReportSecurityEvent生成安全日志的C++代码,现在需要给日志添加特定信息,但找不到创建“Data Name”字段的方法,相关资料极少,想在日志对应位置加上这个信息。我试过AuthzReportSecurityEventFromParams函数,但缺乏相关文档,不确定是不是更优方案。现有代码如下:
#include <stdio.h> #include <iostream> #include <string> #include <strsafe.h> #include <windows.h> #include <Authz.h> #include <Ntsecapi.h> #pragma comment(lib,"Authz.lib") #pragma comment(lib,"Advapi32.lib") 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[]) { 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; 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); 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(); }
解决方案
1. 核心问题说明
AuthzReportSecurityEvent是可变参数接口,只能按顺序传递参数值,无法指定参数的名称(即你需要的“Data Name”字段)。要实现带命名字段的安全日志,必须使用AuthzReportSecurityEventFromParams——这是专门为传递带名称的审计参数设计的接口。
2. 实现步骤
定义带名称的审计参数
使用AUDIT_PARAMS结构体数组,每个元素指定参数的类型、名称和值:
AUDIT_PARAMS auditParams[] = { { APT_String, L"UserName", L"Jay Hamlin" }, { APT_String, L"BirthDate", L"March 21, 1960" }, { APT_Ulong, L"EmployeeID", (PVOID)45 } };
替换日志生成函数
用AuthzReportSecurityEventFromParams替代原有的AuthzReportSecurityEvent,传入定义好的参数数组:
bResult = AuthzReportSecurityEventFromParams( APF_AuditSuccess, hEventProvider, event_id, NULL, _countof(auditParams), auditParams );
3. 注意事项
AUDIT_PARAMS的Name字段必须是宽字符串(LPCWSTR),参数值的类型要和Type字段匹配(例如APT_Ulong对应PVOID类型的数值指针)。- 若需要日志查看工具完美识别命名字段,需为事件源注册对应的XML Schema(设置
AUTHZ_SOURCE_SCHEMA_REGISTRATION的szEventSourceXmlSchemaFile字段),否则部分工具可能仅显示原始参数值。 SeAuditPrivilege权限的启用逻辑和原代码保持一致即可。
完整修改后的代码
#include <stdio.h> #include <iostream> #include <string> #include <strsafe.h> #include <windows.h> #include <Authz.h> #include <Ntsecapi.h> #pragma comment(lib,"Authz.lib") #pragma comment(lib,"Advapi32.lib") 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[]) { BOOL bResult = TRUE; DWORD event_id = 4624; AUTHZ_SECURITY_EVENT_PROVIDER_HANDLE hEventProvider = NULL; 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; HANDLE token; 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); 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; } if (hEventProvider) { // 定义带Data Name的审计参数 AUDIT_PARAMS auditParams[] = { { APT_String, L"UserName", L"Jay Hamlin" }, { APT_String, L"BirthDate", L"March 21, 1960" }, { APT_Ulong, L"EmployeeID", (PVOID)45 } }; // Generate the audit. while (i < 10) { bResult = AuthzReportSecurityEventFromParams( APF_AuditSuccess, hEventProvider, event_id, NULL, _countof(auditParams), auditParams ); int err1 = GetLastError(); if (!bResult) { printf("AuthzReportSecurityEventFromParams 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(); }
内容的提问来源于stack exchange,提问作者Avihai Cohen
相关产品推荐
相关产品推荐

