You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的xml.etree解析Windows安全事件XML并提取指定字段

Windows安全事件XML数据解析方案

需求说明

需解析Windows安全事件XML,完成两个核心操作:

  1. 输出System和EventData节点下的所有字段列表
  2. 根据指定字段集合,提取对应键值对并格式化输出

现有代码仅能处理System节点的直接子节点,无法解析EventData下带Name属性的Data节点。

原始XML数据

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}" /> 
 <EventID>4771</EventID> 
 <Version>0</Version> 
 <Level>0</Level> 
 <Task>14339</Task> 
 <Opcode>0</Opcode> 
 <Keywords>0x8010000000000000</Keywords> 
 <TimeCreated SystemTime="2015-08-07T18:10:21.495462300Z" /> 
 <EventRecordID>166708</EventRecordID> 
 <Correlation /> 
 <Execution ProcessID="520" ThreadID="1084" /> 
 <Channel>Security</Channel> 
 <Computer>DC01.contoso.local</Computer> 
 <Security /> 
 </System>
 <EventData>
 <Data Name="TargetUserName">dadmin</Data> 
 <Data Name="TargetSid">S-1-5-21-3457937927-2839227994-823803824-1104</Data> 
 <Data Name="ServiceName">krbtgt/CONTOSO.LOCAL</Data> 
 <Data Name="TicketOptions">0x40810010</Data> 
 <Data Name="Status">0x10</Data> 
 <Data Name="PreAuthType">15</Data> 
 <Data Name="IpAddress">::ffff:10.0.0.12</Data> 
 <Data Name="IpPort">49254</Data> 
 <Data Name="CertIssuerName" /> 
 <Data Name="CertSerialNumber" /> 
 <Data Name="CertThumbprint" /> 
 </EventData>
 </Event>

现有代码

from tkinter.font import names
import xml.etree.ElementTree as ET

tree = ET.parse('C:/tmp/test.xml')
root = tree.getroot()

namespace = "{"+root.tag.split('}')[0].strip('{')+"}"

for child in root:
  print(child.tag, child.attrib)
  print((''.join([child.tag for child in child.iter()])).replace(namespace,"| "))

print("



")
testlist = ["EventID", "Computer"]
i = 0
for tag in testlist:
  for tag in root.iter(namespace+tag): #'EventID'
    print(testlist[i],":",tag.text)
    i += 1

期望输出

System: Provider Name | EventID | Version | Level | Task | Opcode | Keywords | TimeCreated | EventRecordID | ProcessID | ThreadID | Channel | Computer
EventData: TargetUserName | TargetSid | ServiceName | TicketOptions | Status | PreAuthType | IpAddress | IpPort | CertIssuerName | CertSerialNumber | CertThumbprint
    
EventID : 4771
Status : 0x10
PreAuthType : 15
Computer : DC01.contoso.local
TimeCreated : 2015-08-07T18:10:21.495462300Z
TargetUserName : dadmin
ServiceName : krbtgt/CONTOSO.LOCAL
IpAddress : ::ffff:10.0.0.12
IpPort : 49254

解决方案代码

import xml.etree.ElementTree as ET

# 加载XML文件
tree = ET.parse('C:/tmp/test.xml')
root = tree.getroot()

# 提取命名空间并构建命名空间映射
namespace = root.tag.split('}')[0].strip('{')
ns_map = {'win': namespace}

# 1. 收集System节点的所有字段
system_fields = []
system_node = root.find('win:System', ns_map)
for child in system_node:
    tag_name = child.tag.split('}')[-1]
    if tag_name == 'Provider':
        system_fields.append('Provider Name')
    elif tag_name == 'TimeCreated':
        system_fields.append('TimeCreated')
    elif tag_name == 'Execution':
        system_fields.extend(['ProcessID', 'ThreadID'])
    elif tag_name not in ['Correlation', 'Security']:  # 跳过无实际内容的节点
        system_fields.append(tag_name)

# 2. 收集EventData节点的所有字段
event_data_fields = []
event_data_node = root.find('win:EventData', ns_map)
for data in event_data_node.findall('win:Data', ns_map):
    event_data_fields.append(data.attrib['Name'])

# 3. 输出字段列表
print(f"System: {' | '.join(system_fields)}")
print(f"EventData: {' | '.join(event_data_fields)}")
print()

# 4. 定义需要提取的目标字段
target_fields = [
    "EventID", "Status", "PreAuthType", "Computer",
    "TimeCreated", "TargetUserName", "ServiceName",
    "IpAddress", "IpPort"
]

# 5. 构建所有字段的键值映射字典
field_value_map = {}
# 处理System节点的字段
for child in system_node:
    tag_name = child.tag.split('}')[-1]
    if tag_name == 'EventID':
        field_value_map['EventID'] = child.text
    elif tag_name == 'Computer':
        field_value_map['Computer'] = child.text
    elif tag_name == 'TimeCreated':
        field_value_map['TimeCreated'] = child.attrib['SystemTime']
    elif tag_name == 'Execution':
        field_value_map['ProcessID'] = child.attrib['ProcessID']
        field_value_map['ThreadID'] = child.attrib['ThreadID']

# 处理EventData节点的字段
for data in event_data_node.findall('win:Data', ns_map):
    field_name = data.attrib['Name']
    field_value_map[field_name] = data.text or ''

# 6. 按指定顺序输出目标字段的键值对
for field in target_fields:
    print(f"{field} : {field_value_map.get(field, '')}")

代码说明

  1. 命名空间处理:使用带命名空间的find/findall方法,避免因XML命名空间导致的标签匹配失败
  2. System字段收集:特殊处理Provider、TimeCreated、Execution等节点,提取对应属性或标签名
  3. EventData字段收集:直接提取Data节点的Name属性值作为字段名
  4. 键值映射构建:遍历节点将字段名与对应值存入字典,方便后续快速查询
  5. 目标字段输出:按指定列表顺序输出键值对,确保格式完全符合要求

内容的提问来源于stack exchange,提问作者Peter Asp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:20:52