如何向Windows安全日志写入条目及相关技术问题咨询
我们需要给VB技术栈的客户实现向Windows安全日志(而非应用日志)写入条目的功能,通过AuthzReportSecurityEvent()实现后遇到几个问题,以下是针对这些问题的分析和处理方案:
1. 关键字列显示“Classic, Audit Success”,能否去除Classic关键字?
微软明确说明这是设计使然——使用AuthzReportSecurityEvent()生成的安全日志条目默认会带有"Classic"关键字,无法通过该API直接去除。如果必须去掉,只能考虑非官方或复杂的绕过手段,但不推荐,因为会破坏系统安全日志的标准机制。
2. 事件查看器提示“无法找到来自源的事件ID的描述”,如何消除?
这个问题的根源是当前代码里指定的wszEventMessagesFile是系统自带的EventCreate.exe,它根本没有我们自定义事件ID(42)的消息描述。解决步骤如下:
- 编写自定义消息资源文件(.mc),给目标事件ID定义对应的描述文本
- 用
mc.exe编译该文件生成.res,再通过rc.exe编译成.obj,最终嵌入到你的C程序中 - 修改
AUTHZ_SOURCE_SCHEMA_REGISTRATION结构里的szEventMessageFile,指向包含消息表的自定义程序路径
示例消息资源文件(.mc):
MessageId=42 Severity=Success SymbolicName=MY_SECURITY_EVENT_ID Language=English 自定义安全审计事件描述内容。 .
3. 提示“消息资源存在但未在消息表中找到”,如何消除?
和第二个问题同源,都是消息资源不匹配导致的。要确保:
- 自定义消息资源文件里正确定义了目标事件ID
- 编译后的程序包含正确的消息表
AuthzInstallSecurityEventSource注册的文件路径无误
另外,建议自定义事件ID使用1000+的数值,避免和系统内置ID冲突。
4. 任务类别列值为(3),能否设置更合理的值?
当前代码调用AuthzReportSecurityEvent()时第四个参数传的是NULL,系统默认填充为3。要自定义任务类别:
- 在消息资源文件中添加任务类别定义
- 调用API时传入对应的任务ID
示例消息资源文件中添加任务类别:
TaskCategoryCount=2 TaskCategoryMessageId=1000 Language=English 用户管理 . TaskCategoryMessageId=1001 Language=English 网络访问 .
修改调用代码:
// 传入自定义任务ID(比如1000,对应用户管理) bStatus = AuthzReportSecurityEvent(APF_AuditSuccess, hEventProvider, 42, 1000, 3, APT_String, L"Stack Overflow security audit", APT_String, wszUserName, APT_String, wszIpAddress);
5. 传入的字符串参数在XML中仅显示标签,能否设置这类有意义的标签?
要实现结构化的XML数据标签,需要用到事件XML架构:
- 创建自定义XML架构文件(.xsd),定义事件数据的结构和标签名称
- 在
AUTHZ_SOURCE_SCHEMA_REGISTRATION结构中指定szEventSourceXmlSchemaFile的路径 - 确保调用
AuthzReportSecurityEvent()时的参数顺序和XML架构中的字段对应
另外,也可以使用AuthzReportSecurityEventFromXml() API直接传入XML格式的事件数据,这样能更灵活地定义数据标签,但要保证XML符合Windows事件日志的格式规范。
关键说明
微软官方明确表示,AuthzReportSecurityEvent()的部分行为(比如"Classic"关键字)是设计使然,这类限制无法通过常规手段绕过。如果追求更灵活的安全日志自定义,可考虑Windows事件跟踪(ETW),但ETW主要用于跟踪诊断,并非写入安全日志的标准方式,需要权衡需求和实现复杂度。
修改后的示例代码片段
// 自定义消息资源文件路径 const wchar_t wszEventMessagesFile[] = L"%SystemRoot%\\System32\\MySecurityLogger.exe"; // 自定义XML架构文件路径(如果使用) const wchar_t wszEventXmlSchemaFile[] = L"%SystemRoot%\\System32\\MySecuritySchema.xsd"; // 修改Schema注册部分 memset(&tSchemaRegistration, 0, sizeof(AUTHZ_SOURCE_SCHEMA_REGISTRATION)); tSchemaRegistration.dwFlags = AUTHZ_ALLOW_MULTIPLE_SOURCE_INSTANCES; tSchemaRegistration.szEventSourceName = (PWSTR)wszSourceName; tSchemaRegistration.szEventMessageFile = (PWSTR)wszEventMessagesFile; tSchemaRegistration.szEventSourceXmlSchemaFile = (PWSTR)wszEventXmlSchemaFile; // 指定XML架构 tSchemaRegistration.szEventAccessStringsFile = (PWSTR)wszEventMessagesFile; tSchemaRegistration.szExecutableImagePath = NULL; // 调用时传入自定义任务ID bStatus = AuthzReportSecurityEvent(APF_AuditSuccess, hEventProvider, 42, 1000, 3, APT_String, L"Stack Overflow security audit", APT_String, wszUserName, APT_String, wszIpAddress);
内容的提问来源于stack exchange,提问作者Douglas Coup

