digital forensics

Extracting Windows Event Logs Artifacts

Extract, parse, and analyze Windows Event Logs (EVTX) using Chainsaw, Hayabusa, and EvtxECmd to detect lateral movement, persistence, and privilege escalation.

chainsawevtxforensicshayabusaincident-responsesigma-ruleswindows-event-logs
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • When investigating security incidents on Windows systems through event log analysis
  • For detecting lateral movement, privilege escalation, and persistence mechanisms
  • When performing threat hunting across Windows event log data
  • During compliance audits requiring review of authentication and access events
  • When building forensic timelines from Windows system activity

Prerequisites

  • Windows Event Log files (EVTX format) from forensic image or live system
  • Chainsaw, Hayabusa, or EvtxECmd for parsing and detection
  • Sigma rules for automated threat detection
  • Understanding of critical Windows Event IDs
  • Python with python-evtx or evtx library for custom parsing
  • PowerShell for live system analysis (if applicable)

Workflow

Step 1: Collect Windows Event Log Files

# Extract EVTX files from forensic image
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
 
mkdir -p /cases/case-2024-001/evtx/
cp /mnt/evidence/Windows/System32/winevt/Logs/*.evtx /cases/case-2024-001/evtx/
 
# Key event logs to prioritize
# Security.evtx - Authentication, authorization, audit events
# System.evtx - System services, drivers, hardware events
# Application.evtx - Application errors and events
# Microsoft-Windows-Sysmon%4Operational.evtx - Detailed process/network monitoring
# Microsoft-Windows-PowerShell%4Operational.evtx - PowerShell activity
# Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx - RDP sessions
# Microsoft-Windows-TaskScheduler%4Operational.evtx - Scheduled tasks
# Microsoft-Windows-WinRM%4Operational.evtx - Windows Remote Management
# Microsoft-Windows-Bits-Client%4Operational.evtx - BITS transfers
# Microsoft-Windows-Windows Defender%4Operational.evtx - AV detections
 
# List available log files and sizes
ls -lhS /cases/case-2024-001/evtx/ | head -20
 
# Hash for integrity
sha256sum /cases/case-2024-001/evtx/*.evtx > /cases/case-2024-001/evtx/evtx_hashes.txt

Step 2: Run Chainsaw for Sigma-Based Detection

# Install Chainsaw
wget https://github.com/WithSecureLabs/chainsaw/releases/latest/download/chainsaw_all_platforms+rules.zip
unzip chainsaw_all_platforms+rules.zip -d /opt/chainsaw
 
# Run Chainsaw with bundled Sigma rules
/opt/chainsaw/chainsaw hunt /cases/case-2024-001/evtx/ \
   -s /opt/chainsaw/sigma/rules/ \
   --mapping /opt/chainsaw/mappings/sigma-event-logs-all.yml \
   --output /cases/case-2024-001/analysis/chainsaw_results.txt
 
# Run with CSV output for easier analysis
/opt/chainsaw/chainsaw hunt /cases/case-2024-001/evtx/ \
   -s /opt/chainsaw/sigma/rules/ \
   --mapping /opt/chainsaw/mappings/sigma-event-logs-all.yml \
   --csv \
   --output /cases/case-2024-001/analysis/chainsaw_results/
 
# Run with JSON output
/opt/chainsaw/chainsaw hunt /cases/case-2024-001/evtx/ \
   -s /opt/chainsaw/sigma/rules/ \
   --mapping /opt/chainsaw/mappings/sigma-event-logs-all.yml \
   --json \
   --output /cases/case-2024-001/analysis/chainsaw_results.json
 
# Search for specific keywords
/opt/chainsaw/chainsaw search /cases/case-2024-001/evtx/ \
   -s "mimikatz" --json
 
# Search for specific event IDs
/opt/chainsaw/chainsaw search /cases/case-2024-001/evtx/ \
   -e 4688 --json | head -100

Step 3: Run Hayabusa for Fast Timeline Generation

# Install Hayabusa
wget https://github.com/Yamato-Security/hayabusa/releases/latest/download/hayabusa-linux-x64-musl.zip
unzip hayabusa-linux-x64-musl.zip -d /opt/hayabusa
 
# Generate CSV timeline with all detection rules
/opt/hayabusa/hayabusa csv-timeline \
   -d /cases/case-2024-001/evtx/ \
   -o /cases/case-2024-001/analysis/hayabusa_timeline.csv \
   -p verbose
 
# Generate JSON timeline
/opt/hayabusa/hayabusa json-timeline \
   -d /cases/case-2024-001/evtx/ \
   -o /cases/case-2024-001/analysis/hayabusa_timeline.json
 
# Run with only critical and high severity detections
/opt/hayabusa/hayabusa csv-timeline \
   -d /cases/case-2024-001/evtx/ \
   -o /cases/case-2024-001/analysis/hayabusa_critical.csv \
   -p verbose \
   --min-level critical
 
# Generate detection summary (metrics)
/opt/hayabusa/hayabusa metrics \
   -d /cases/case-2024-001/evtx/ \
   -o /cases/case-2024-001/analysis/hayabusa_metrics.csv
 
# Logon summary
/opt/hayabusa/hayabusa logon-summary \
   -d /cases/case-2024-001/evtx/ \
   -o /cases/case-2024-001/analysis/logon_summary.csv

Step 4: Parse Specific Critical Event IDs

# Extract authentication events with python-evtx
pip install evtx
 
python3 << 'PYEOF'
import json
from evtx import PyEvtxParser
 
parser = PyEvtxParser("/cases/case-2024-001/evtx/Security.evtx")
 
# Critical Event IDs mapping
critical_events = {
    '4624': 'Successful Logon',
    '4625': 'Failed Logon',
    '4634': 'Logoff',
    '4648': 'Explicit Credential Logon',
    '4672': 'Special Privileges Assigned',
    '4688': 'Process Created',
    '4689': 'Process Exited',
    '4697': 'Service Installed',
    '4698': 'Scheduled Task Created',
    '4720': 'User Account Created',
    '4724': 'Password Reset Attempted',
    '4728': 'Member Added to Global Group',
    '4732': 'Member Added to Local Group',
    '4756': 'Member Added to Universal Group',
    '1102': 'Audit Log Cleared',
    '4688': 'New Process Created'
}
 
results = {eid: [] for eid in critical_events}
 
for record in parser.records_json():
    data = json.loads(record['data'])
    event_id = str(data['Event']['System']['EventID'])
 
    if event_id in critical_events:
        event_data = data['Event'].get('EventData', {})
        results[event_id].append({
            'timestamp': data['Event']['System']['TimeCreated']['#attributes']['SystemTime'],
            'event_id': event_id,
            'description': critical_events[event_id],
            'data': event_data
        })
 
# Print summary
for eid, events in results.items():
    if events:
        print(f"\n[{eid}] {critical_events[eid]}: {len(events)} events")
        for e in events[:3]:
            print(f"  {e['timestamp']}: {json.dumps(e['data'], default=str)[:200]}")
        if len(events) > 3:
            print(f"  ... and {len(events)-3} more")
 
# Save full results
with open('/cases/case-2024-001/analysis/critical_events.json', 'w') as f:
    json.dump(results, f, indent=2, default=str)
PYEOF

Step 5: Detect Specific Attack Patterns

# Detect Pass-the-Hash (Logon Type 9 with NTLM)
python3 << 'PYEOF'
import json
from evtx import PyEvtxParser
 
parser = PyEvtxParser("/cases/case-2024-001/evtx/Security.evtx")
 
print("=== PASS-THE-HASH INDICATORS ===")
print("Looking for: Event 4624, Logon Type 9, NTLM authentication\n")
 
for record in parser.records_json():
    data = json.loads(record['data'])
    event_id = str(data['Event']['System']['EventID'])
 
    if event_id == '4624':
        event_data = data['Event'].get('EventData', {})
        logon_type = str(event_data.get('LogonType', ''))
        auth_package = str(event_data.get('AuthenticationPackageName', ''))
        logon_process = str(event_data.get('LogonProcessName', ''))
 
        # Pass-the-Hash indicators
        if logon_type == '9' and 'NTLM' in auth_package:
            timestamp = data['Event']['System']['TimeCreated']['#attributes']['SystemTime']
            target = event_data.get('TargetUserName', 'Unknown')
            source_ip = event_data.get('IpAddress', 'N/A')
            print(f"  [{timestamp}] PtH: User={target}, IP={source_ip}, Auth={auth_package}")
 
        # Network logon with NTLM (lateral movement)
        if logon_type == '3' and 'NTLM' in auth_package:
            timestamp = data['Event']['System']['TimeCreated']['#attributes']['SystemTime']
            target = event_data.get('TargetUserName', 'Unknown')
            source_ip = event_data.get('IpAddress', 'N/A')
            workstation = event_data.get('WorkstationName', 'N/A')
            print(f"  [{timestamp}] Network NTLM: User={target}, IP={source_ip}, WS={workstation}")
PYEOF
 
# Detect log clearing / anti-forensics
python3 << 'PYEOF'
import json
from evtx import PyEvtxParser
 
for log_file in ['Security.evtx', 'System.evtx']:
    path = f"/cases/case-2024-001/evtx/{log_file}"
    try:
        parser = PyEvtxParser(path)
        for record in parser.records_json():
            data = json.loads(record['data'])
            event_id = str(data['Event']['System']['EventID'])
            if event_id in ('1102', '104'):  # Security log cleared, System log cleared
                timestamp = data['Event']['System']['TimeCreated']['#attributes']['SystemTime']
                print(f"LOG CLEARED: [{timestamp}] EventID {event_id} in {log_file}")
    except Exception as e:
        print(f"Error parsing {log_file}: {e}")
PYEOF

Key Concepts

Concept Description
EVTX format Binary XML-based Windows Event Log format introduced in Vista/Server 2008
Event ID Numeric identifier for specific event types (e.g., 4624 = successful logon)
Logon types Classification of authentication methods (2=interactive, 3=network, 10=RDP)
Sigma rules Generic detection signatures that map to specific SIEM/log queries
Sysmon Microsoft system monitoring driver providing detailed process and network events
Audit policy GPO settings controlling which events Windows records
Event forwarding (WEF) Windows mechanism for centralized event log collection
EVTX channels Separate log files for different event categories and applications

Tools & Systems

Tool Purpose
Chainsaw Sigma-based EVTX analysis and threat hunting tool
Hayabusa Fast Windows Event Log forensic timeline generator
EvtxECmd Eric Zimmerman command-line EVTX parser with CSV/JSON output
python-evtx Python library for EVTX file parsing
LogParser Microsoft SQL-like query engine for Windows logs
Event Log Explorer GUI tool for browsing and analyzing EVTX files
KAPE Automated triage collection including event logs
Velociraptor Endpoint agent with EVTX collection and hunting artifacts

Common Scenarios

Scenario 1: Detecting Lateral Movement Filter for Event 4624 with Logon Type 3 (network) and Type 10 (RDP), identify unusual source-destination pairs, check for Event 4648 (explicit credentials) indicating pass-the-hash, correlate with process creation events (4688) on target systems.

Scenario 2: Privilege Escalation Detection Search for Event 4672 (special privileges assigned) for unexpected users, check for Event 4728/4732 (group membership changes) adding users to admin groups, look for Event 4697 (service installed) indicating new system-level access, correlate with 4720 (account creation).

Scenario 3: PowerShell Attack Detection Analyze PowerShell Operational log for Script Block Logging (Event 4104), search for encoded commands in Event 4688 (process creation with command line), detect AMSI bypass attempts, identify download cradles and invocation of known attack tools.

Scenario 4: Ransomware Incident Reconstruction Build timeline starting from initial access (4624 from external IP), trace privilege escalation through group membership changes, identify service installations for persistence, find process creation events for encryption executable, detect volume shadow copy deletion in System log.

Output Format

Windows Event Log Analysis Summary:
  System: DC01.corp.local (Windows Server 2019)
  Log Files Analyzed: 15 EVTX files
  Total Events: 2,456,789
  Analysis Period: 2024-01-10 to 2024-01-20
 
  Chainsaw Detections:
    Critical:  12 (Mimikatz usage, PsExec, log clearing)
    High:      34 (Network NTLM logons, encoded PowerShell)
    Medium:    89 (Unusual service installations, scheduled tasks)
    Low:       234 (Informational)
 
  Hayabusa Timeline:
    Total Alerts: 369
    Unique Rules Triggered: 45
    Top Rules:
      - Suspicious NTLM Authentication (34 hits)
      - PowerShell Download Cradle (12 hits)
      - Service Installation Suspicious Path (8 hits)
 
  Critical Findings:
    2024-01-15 14:32 - RDP brute force (234 failed, 1 success from 203.0.113.45)
    2024-01-15 14:45 - Admin account created (svcbackup) - Event 4720
    2024-01-16 02:30 - PsExec service installed on DC01 - Event 4697
    2024-01-18 03:00 - Security log cleared - Event 1102
 
  Reports:
    Chainsaw: /analysis/chainsaw_results/
    Hayabusa: /analysis/hayabusa_timeline.csv
    Critical Events: /analysis/critical_events.json
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md2.8 KB

API Reference: Windows Event Log Artifact Extraction Agent

Dependencies

Library Version Purpose
evtx (python-evtx) >=0.8 Parse Windows EVTX binary log files into JSON records

CLI Usage

python scripts/agent.py \
  --evtx-dir /cases/case-001/evtx/ \
  --output-dir /cases/case-001/analysis/ \
  --output evtx_report.json
 
# Or specify individual files:
python scripts/agent.py \
  --evtx-files Security.evtx System.evtx \
  --output-dir /cases/analysis/

Functions

parse_evtx_file(evtx_path) -> list

Parses a single EVTX file using PyEvtxParser. Returns list of dicts with event_id, timestamp, channel, computer, event_data.

filter_critical_events(records) -> dict

Filters records to 15 critical Event IDs (4624, 4625, 4688, 4697, 1102, etc.) grouped by Event ID.

detect_lateral_movement(records) -> list

Identifies network logons (Type 3) and RDP (Type 10) from non-local IPs. Flags pass-the-hash indicators (Type 9 + NTLM).

detect_privilege_escalation(records) -> list

Detects special privilege assignment (4672), group membership changes (4728/4732/4756), and account creation (4720).

detect_suspicious_processes(records) -> list

Matches 4688 process creation events against a list of known attack tools (mimikatz, psexec, rubeus, etc.).

detect_log_clearing(records) -> list

Identifies audit log clearing events (Event ID 1102 and 104).

detect_persistence(records) -> list

Detects service installations (4697/7045) and scheduled task creation (4698).

generate_summary(records, findings) -> dict

Computes statistics: total records, top event IDs, alert counts per detection category.

export_timeline_csv(records, output_path)

Exports critical events as a sorted CSV timeline with timestamp, event_id, description, details.

analyze_evtx(evtx_paths, output_dir) -> dict

Orchestrates parsing of multiple EVTX files and runs all detection functions.

Critical Event IDs

Event ID Description
1102 Audit Log Cleared
4624 Successful Logon
4625 Failed Logon
4648 Explicit Credential Logon
4672 Special Privileges Assigned
4688 New Process Created
4697 Service Installed
4698 Scheduled Task Created
4720 User Account Created
7045 New Service Installed (System log)

Output Schema

{
  "files_analyzed": ["/cases/evtx/Security.evtx"],
  "summary": {
    "total_records": 245678,
    "lateral_movement_alerts": 12,
    "suspicious_processes": 3,
    "persistence": 5
  },
  "findings": {
    "lateral_movement": [{"user": "admin", "source_ip": "10.0.0.5", "logon_type": "Network"}],
    "suspicious_processes": [{"matched_pattern": "mimikatz", "process": "m.exe"}]
  }
}

Scripts 1

agent.py10.9 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Windows Event Log artifact extraction agent using evtx library for EVTX parsing."""

import argparse
import csv
import json
import logging
import os
import sys
from collections import Counter, defaultdict
from datetime import datetime
from typing import Dict, List

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

try:
    from evtx import PyEvtxParser
except ImportError:
    sys.exit("evtx required: pip install evtx")

CRITICAL_EVENT_IDS = {
    "1102": "Audit Log Cleared",
    "4624": "Successful Logon",
    "4625": "Failed Logon",
    "4634": "Logoff",
    "4648": "Explicit Credential Logon",
    "4672": "Special Privileges Assigned",
    "4688": "New Process Created",
    "4697": "Service Installed",
    "4698": "Scheduled Task Created",
    "4720": "User Account Created",
    "4724": "Password Reset Attempted",
    "4728": "Member Added to Global Group",
    "4732": "Member Added to Local Group",
    "4756": "Member Added to Universal Group",
    "7045": "New Service Installed (System)",
}

LOGON_TYPES = {
    "2": "Interactive", "3": "Network", "4": "Batch", "5": "Service",
    "7": "Unlock", "8": "NetworkCleartext", "9": "NewCredentials",
    "10": "RemoteInteractive (RDP)", "11": "CachedInteractive",
}

SUSPICIOUS_PROCESSES = [
    "mimikatz", "psexec", "procdump", "lazagne", "sharphound",
    "rubeus", "certutil", "powershell -enc", "bitsadmin",
    "wmic shadowcopy delete", "vssadmin delete", "bcdedit /set",
]


def parse_evtx_file(evtx_path: str) -> List[dict]:
    """Parse an EVTX file and return list of event records."""
    if not os.path.isfile(evtx_path):
        logger.warning("EVTX file not found: %s", evtx_path)
        return []
    records = []
    try:
        parser = PyEvtxParser(evtx_path)
        for record in parser.records_json():
            try:
                data = json.loads(record["data"])
                event = data.get("Event", {})
                system = event.get("System", {})
                event_id = str(system.get("EventID", ""))
                if isinstance(system.get("EventID"), dict):
                    event_id = str(system["EventID"].get("#text", ""))
                timestamp = system.get("TimeCreated", {}).get("#attributes", {}).get("SystemTime", "")
                event_data = event.get("EventData", {})
                records.append({
                    "event_id": event_id, "timestamp": timestamp,
                    "channel": system.get("Channel", ""),
                    "computer": system.get("Computer", ""),
                    "event_data": event_data if isinstance(event_data, dict) else {},
                })
            except (json.JSONDecodeError, KeyError):
                continue
    except Exception as exc:
        logger.error("Error parsing %s: %s", evtx_path, exc)
    logger.info("Parsed %d records from %s", len(records), evtx_path)
    return records


def filter_critical_events(records: List[dict]) -> Dict[str, List[dict]]:
    """Filter records for critical security event IDs."""
    filtered = defaultdict(list)
    for r in records:
        if r["event_id"] in CRITICAL_EVENT_IDS:
            r["description"] = CRITICAL_EVENT_IDS[r["event_id"]]
            filtered[r["event_id"]].append(r)
    return dict(filtered)


def detect_lateral_movement(records: List[dict]) -> List[dict]:
    """Detect lateral movement indicators from logon events."""
    findings = []
    for r in records:
        if r["event_id"] != "4624":
            continue
        ed = r["event_data"]
        logon_type = str(ed.get("LogonType", ""))
        auth_pkg = str(ed.get("AuthenticationPackageName", ""))
        src_ip = ed.get("IpAddress", "-")
        user = ed.get("TargetUserName", "")
        if logon_type in ("3", "10") and src_ip not in ("-", "::1", "127.0.0.1"):
            findings.append({
                "timestamp": r["timestamp"], "type": "lateral_movement",
                "logon_type": LOGON_TYPES.get(logon_type, logon_type),
                "user": user, "source_ip": src_ip, "auth_package": auth_pkg,
                "pth_indicator": logon_type == "9" and "NTLM" in auth_pkg,
            })
    return findings


def detect_privilege_escalation(records: List[dict]) -> List[dict]:
    """Detect privilege escalation from group membership and special privilege events."""
    findings = []
    escalation_ids = {"4672", "4728", "4732", "4756", "4720"}
    for r in records:
        if r["event_id"] not in escalation_ids:
            continue
        ed = r["event_data"]
        findings.append({
            "timestamp": r["timestamp"], "type": "privilege_escalation",
            "event_id": r["event_id"], "description": CRITICAL_EVENT_IDS.get(r["event_id"], ""),
            "user": ed.get("TargetUserName", ed.get("SubjectUserName", "")),
            "group": ed.get("TargetDomainName", ""),
        })
    return findings


def detect_suspicious_processes(records: List[dict]) -> List[dict]:
    """Detect suspicious process creation events."""
    findings = []
    for r in records:
        if r["event_id"] != "4688":
            continue
        ed = r["event_data"]
        cmd = str(ed.get("CommandLine", ed.get("NewProcessName", ""))).lower()
        process_name = str(ed.get("NewProcessName", "")).lower()
        for pattern in SUSPICIOUS_PROCESSES:
            if pattern in cmd or pattern in process_name:
                findings.append({
                    "timestamp": r["timestamp"], "type": "suspicious_process",
                    "matched_pattern": pattern,
                    "process": ed.get("NewProcessName", ""),
                    "command_line": str(ed.get("CommandLine", ""))[:300],
                    "user": ed.get("SubjectUserName", ""),
                    "parent": ed.get("ParentProcessName", ""),
                })
                break
    return findings


def detect_log_clearing(records: List[dict]) -> List[dict]:
    """Detect audit log clearing events."""
    findings = []
    for r in records:
        if r["event_id"] in ("1102", "104"):
            findings.append({
                "timestamp": r["timestamp"], "type": "log_cleared",
                "event_id": r["event_id"], "channel": r.get("channel", ""),
                "user": r["event_data"].get("SubjectUserName", "SYSTEM"),
            })
    return findings


def detect_persistence(records: List[dict]) -> List[dict]:
    """Detect persistence mechanisms from service and scheduled task events."""
    findings = []
    for r in records:
        if r["event_id"] in ("4697", "7045"):
            ed = r["event_data"]
            findings.append({
                "timestamp": r["timestamp"], "type": "service_install",
                "service_name": ed.get("ServiceName", ""),
                "image_path": ed.get("ImagePath", ed.get("ServiceFileName", "")),
                "start_type": ed.get("StartType", ""),
                "user": ed.get("AccountName", ed.get("SubjectUserName", "")),
            })
        elif r["event_id"] == "4698":
            ed = r["event_data"]
            findings.append({
                "timestamp": r["timestamp"], "type": "scheduled_task",
                "task_name": ed.get("TaskName", ""),
                "user": ed.get("SubjectUserName", ""),
            })
    return findings


def generate_summary(records: List[dict], findings: dict) -> dict:
    """Generate analysis summary statistics."""
    event_counts = Counter(r["event_id"] for r in records)
    top_events = [(eid, count, CRITICAL_EVENT_IDS.get(eid, "Other"))
                  for eid, count in event_counts.most_common(15)]
    return {
        "total_records": len(records),
        "unique_event_ids": len(event_counts),
        "top_events": top_events,
        "lateral_movement_alerts": len(findings.get("lateral_movement", [])),
        "priv_esc_alerts": len(findings.get("privilege_escalation", [])),
        "suspicious_processes": len(findings.get("suspicious_processes", [])),
        "log_clearing": len(findings.get("log_clearing", [])),
        "persistence": len(findings.get("persistence", [])),
    }


def export_timeline_csv(records: List[dict], output_path: str) -> None:
    """Export critical events as a CSV timeline."""
    critical = [r for r in records if r["event_id"] in CRITICAL_EVENT_IDS]
    critical.sort(key=lambda r: r["timestamp"])
    with open(output_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["timestamp", "event_id", "description", "computer", "details"])
        for r in critical:
            desc = CRITICAL_EVENT_IDS.get(r["event_id"], "")
            details = json.dumps(r["event_data"], default=str)[:300]
            writer.writerow([r["timestamp"], r["event_id"], desc, r["computer"], details])
    logger.info("Timeline exported: %d events to %s", len(critical), output_path)


def analyze_evtx(evtx_paths: List[str], output_dir: str) -> dict:
    """Run full EVTX analysis across multiple log files."""
    all_records = []
    for path in evtx_paths:
        all_records.extend(parse_evtx_file(path))

    all_records.sort(key=lambda r: r["timestamp"])
    findings = {
        "lateral_movement": detect_lateral_movement(all_records),
        "privilege_escalation": detect_privilege_escalation(all_records),
        "suspicious_processes": detect_suspicious_processes(all_records),
        "log_clearing": detect_log_clearing(all_records),
        "persistence": detect_persistence(all_records),
    }

    report = {
        "analysis_date": datetime.utcnow().isoformat(),
        "files_analyzed": evtx_paths,
        "summary": generate_summary(all_records, findings),
        "findings": findings,
        "critical_events": filter_critical_events(all_records),
    }

    export_timeline_csv(all_records, os.path.join(output_dir, "event_timeline.csv"))
    return report


def main():
    parser = argparse.ArgumentParser(description="Windows Event Log Artifact Extraction Agent")
    parser.add_argument("--evtx-dir", default="", help="Directory containing EVTX files")
    parser.add_argument("--evtx-files", nargs="*", default=[], help="Specific EVTX files to parse")
    parser.add_argument("--output-dir", default=".", help="Output directory")
    parser.add_argument("--output", default="evtx_report.json")
    args = parser.parse_args()

    os.makedirs(args.output_dir, exist_ok=True)
    evtx_paths = list(args.evtx_files)
    if args.evtx_dir and os.path.isdir(args.evtx_dir):
        for f in os.listdir(args.evtx_dir):
            if f.lower().endswith(".evtx"):
                evtx_paths.append(os.path.join(args.evtx_dir, f))

    if not evtx_paths:
        logger.error("No EVTX files specified")
        sys.exit(1)

    report = analyze_evtx(evtx_paths, args.output_dir)
    out_path = os.path.join(args.output_dir, args.output)
    with open(out_path, "w") as f:
        json.dump(report, f, indent=2, default=str)
    logger.info("Report saved to %s", out_path)
    print(json.dumps(report["summary"], indent=2, default=str))


if __name__ == "__main__":
    main()
Keep exploring