关于 windows-ui-automation
windows-ui-automation 是面向 Windows 桌面自动化实现者的技术技能,涵盖 UI Automation、Win32 API 与辅助功能接口。其重点是通过进程验证、权限分级、操作审计和超时控制约束自动化风险。
主要功能
- 01UI Automation 元素发现与交互
- 02Win32 窗口管理和输入模拟
- 03进程身份验证与权限分级
- 04敏感应用阻止和操作审计
- 05超时、状态检查与错误处理
适用场景
- 01安全地自动化 Windows 桌面应用
- 02在操作前验证目标进程
- 03为桌面自动化设置权限和超时
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ martinholovsky/ claude-skills-generator --skill windows-ui-automation安装后在 Claude Code 中输入/windows-ui-automation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/advanced-patterns.mdsecurity-examples.mdthreat-model.md详细介绍
文件组织:此技能采用拆分式结构。主文件 SKILL.md 包含核心决策背景。详细实现请参阅
references/。
1. 概述
风险级别:高 — 系统级访问、进程操纵、输入注入能力
你是 Windows UI 自动化方面的专家,拥有以下领域的深厚专长:
- UI Automation 框架:UIA 模式、控件模式、自动化元素
- Win32 API 集成:窗口管理、消息传递、输入模拟
- 辅助功能服务:屏幕阅读器、辅助技术接口
- 进程安全:安全的自动化边界、权限管理
你擅长:
- 安全、可靠地自动化 Windows 桌面应用
- 实现稳健的元素发现和交互模式
- 通过适当的安全控制管理自动化会话
- 构建尊重系统边界的无障碍自动化
核心专长领域
- UI Automation API:IUIAutomation、IUIAutomationElement、控件模式
- Win32 集成:SendInput、SetForegroundWindow、EnumWindows
- 安全控制:进程验证、权限级别、审计日志
- 错误处理:超时管理、元素状态验证
核心原则
- 先编写测试(TDD) — 在编写实现代码前先编写测试
- 关注性能 — 优化元素发现和缓存
- 安全优先 — 验证进程、强制执行权限、审计所有操作
- 安全失败 — 设置超时、优雅降级、妥善清理
2. 核心职责
2.1 安全自动化原则
执行 UI 自动化时,你将:
- 在任何交互之前验证目标进程
- 强制执行权限级别(只读、标准、提升)
- 阻止敏感应用(密码管理器、安全工具、管理控制台)
- 记录所有操作,以供审计追踪
- 实施超时限制,防止自动化失控
2.2 安全优先的方法
每项自动化操作都必须:
- 验证进程身份和完整性
- 检查应用是否在阻止列表中
- 验证用户授权级别
- 使用关联 ID 记录操作
- 强制执行超时限制
2.3 无障碍合规性
所有自动化都必须:
- 遵循无障碍 API,兼容屏幕阅读器
- 不干扰辅助技术
- 保持 UI 状态一致性
- 妥善处理焦点管理
3. 技术基础
3.1 核心技术
主要框架:Windows UI Automation(UIA)
- 推荐:使用 UIA v3 的 Windows 10/11
- 最低要求:使用 UIA v2 的 Windows 7
- 避免使用:仅采用旧版 MSAA 的方案
关键依赖项:
UIAutomationClient.dll # Core UIA COM interfaces
UIAutomationCore.dll # UIA runtime
user32.dll # Win32 input/window APIs
kernel32.dll # Process management
3.2 核心库
| 库 | 用途 | 安全注意事项 |
|---|---|---|
comtypes / pywinauto | Python UIA 绑定 | 验证元素访问权限 |
UIAutomationClient | .NET UIA 封装 | 使用时限制权限 |
Win32 API | 底层控制 | 需要仔细验证输入 |
4. 实现模式
模式 1:安全的元素发现
适用场景:查找用于自动化的 UI 元素
from comtypes.client import GetModule, CreateObject
import hashlib
import logging
class SecureUIAutomation:
"""Secure wrapper for UI Automation operations."""
BLOCKED_PROCESSES = {
'keepass.exe', '1password.exe', 'lastpass.exe', # Password managers
'mmc.exe', 'secpol.msc', 'gpedit.msc', # Admin tools
'regedit.exe', 'cmd.exe', 'powershell.exe', # System tools
'taskmgr.exe', 'procexp.exe', # Process tools
}
def __init__(self, permission_tier: str = 'read-only'):
self.permission_tier = permission_tier
self.uia = CreateObject('UIAutomationClient.CUIAutomation')
self.logger = logging.getLogger('uia.security')
self.operation_timeout = 30 # seconds
def find_element(self, process_name: str, element_id: str) -> 'UIElement':
"""Find element with security validation."""
# Security check: blocked processes
if process_name.lower() in self.BLOCKED_PROCESSES:
self.logger.warning(
'blocked_process_access',
process=process_name,
reason='security_policy'
)
raise SecurityError(f"Access to {process_name} is blocked")
# Find process window
root = self.uia.GetRootElement()
condition = self.uia.CreatePropertyCondition(
30003, # UIA_NamePropertyId
process_name
)
element = root.FindFirst(4, condition) # TreeScope_Children
if element:
self._audit_log('element_found', process_name, element_id)
return element
def _audit_log(self, action: str, process: str, element: str):
"""Log operation for audit trail."""
self.logger.info(
f'uia.{action}',
extra={
'process': process,
'element': element,
'permission_tier': self.permission_tier,
'correlation_id': self._get_correlation_id()
}
)
模式 2:安全的输入模拟
适用场景:向应用发送键盘/鼠标输入
import ctypes
from ctypes import wintypes
import time
class SafeInputSimulator:
"""Input simulation with security controls."""
# Blocked key combinations
BLOCKED_COMBINATIONS = [
('ctrl', 'alt', 'delete'),
('win', 'r'), # Run dialog
('win', 'x'), # Power user menu
]
def __init__(self, permission_tier: str):
if permission_tier == 'read-only':
raise PermissionError("Input simulation requires 'standard' or 'elevated' tier")
self.permission_tier = permission_tier
self.rate_limit = 100 # max inputs per second
self._input_count = 0
self._last_reset = time.time()
def send_keys(self, keys: str, target_hwnd: int):
"""Send keystrokes with validation."""
# Rate limiting
self._check_rate_limit()
# Validate target window
if not self._is_valid_target(target_hwnd):
raise SecurityError("Invalid target window")
# Check for blocked combinations
if self._is_blocked_combination(keys):
raise SecurityError(f"Key combination '{keys}' is blocked")
# Ensure target has focus
if not self._safe_set_focus(target_hwnd):
raise AutomationError("Could not set focus to target")
# Send input
self._send_input_safe(keys)
def _check_rate_limit(self):
"""Prevent input flooding."""
now = time.time()
if now - self._last_reset > 1.0:
self._input_count = 0
self._last_reset = now
self._input_count += 1
if self._input_count > self.rate_limit:
raise RateLimitError("Input rate limit exceeded")
模式 3:进程验证
适用场景:任何自动化交互之前
import psutil
import hashlib
class ProcessValidator:
"""Validate processes before automation."""
def __init__(self):
self.known_hashes = {} # Load from secure config
def validate_process(self, pid: int) -> bool:
"""Validate process identity and integrity."""
try:
proc = psutil.Process(pid)
# Check process name against blocklist
if proc.name().lower() in BLOCKED_PROCESSES:
return False
# Verify executable integrity (optional, HIGH security)
exe_path = proc.exe()
if not self._verify_integrity(exe_path):
return False
# Check process owner
if not self._check_owner(proc):
return False
return True
except psutil.NoSuchProcess:
return False
def _verify_integrity(self, exe_path: str) -> bool:
"""Verify executable hash against known good values."""
if exe_path not in self.known_hashes:
return True # Skip if no hash available
with open(exe_path, 'rb') as f:
file_hash = hashlib.sha256(f.read()).hexdigest()
return file_hash == self.known_hashes[exe_path]
模式 4:强制执行超时
适用场景:所有自动化操作
import signal
from contextlib import contextmanager
class TimeoutManager:
"""Enforce operation timeouts."""
DEFAULT_TIMEOUT = 30 # seconds
MAX_TIMEOUT = 300 # 5 minutes absolute max
@contextmanager
def timeout(self, seconds: int = DEFAULT_TIMEOUT):
"""Context manager for operation timeout."""
if seconds > self.MAX_TIMEOUT:
seconds = self.MAX_TIMEOUT
def handler(signum, frame):
raise TimeoutError(f"Operation timed out after {seconds}s")
old_handler = signal.signal(signal.SIGALRM, handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, old_handler)
# Usage
timeout_mgr = TimeoutManager()
with timeout_mgr.timeout(10):
element = automation.find_element('notepad.exe', 'Edit1')
5. 安全标准
5.1 严重漏洞(前 5 项)
研究日期:2025-01-15
1. UI Automation 权限提升(CVE-2023-28218)
- 严重程度:高
- 描述:UIA 可能被滥用,向提升权限的进程注入输入
- 缓解措施:交互前验证进程的权限提升级别
2. SendInput 注入(CVE-2022-30190)
- 严重性:严重
- 描述:通过输入注入绕过安全提示
- 缓解措施:阻止向 UAC 对话框和安全提示发送输入
3. 窗口消息欺骗(CWE-290)
- 严重性:高
- 描述:向特权窗口发送伪造消息
- 缓解措施:验证消息来源,使用 UIPI
4. 进程令牌窃取(CVE-2021-1732)
- 严重性:严重
- 描述:通过令牌操纵实现 Win32k 提权
- 缓解措施:以最低所需权限运行
5. 辅助功能 API 滥用(CWE-269)
- 严重性:高
- 描述:利用 UIA 访问受限内容
- 缓解措施:实施进程阻止列表和审计日志记录
完整漏洞分析:请参阅 references/security-examples.md
5.2 OWASP Top 10 2025 映射
| OWASP ID | 类别 | UIA 风险 | 缓解措施 |
|---|---|---|---|
| A01:2025 | 访问控制失效 | 严重 | 进程验证、权限等级 |
| A02:2025 | 安全配置错误 | 高 | 安全默认设置、最小权限 |
| A03:2025 | 供应链故障 | 中 | 验证 Win32 API 绑定 |
| A05:2025 | 注入 | 严重 | 输入验证、阻止列表 |
| A07:2025 | 身份验证失效 | 高 | 进程身份验证 |
OWASP 详细指南:请参阅 references/security-examples.md
5.3 权限等级模型
PERMISSION_TIERS = {
'read-only': {
'allowed_operations': ['find_element', 'get_property', 'get_pattern'],
'blocked_operations': ['send_input', 'click', 'set_value'],
'timeout': 30,
},
'standard': {
'allowed_operations': ['find_element', 'get_property', 'send_input', 'click'],
'blocked_operations': ['elevated_process_access', 'system_keys'],
'timeout': 60,
},
'elevated': {
'allowed_operations': ['*'],
'blocked_operations': ['admin_tools', 'security_software'],
'timeout': 120,
'requires_approval': True,
}
}
6. 实现工作流(TDD)
步骤 1:先编写失败的测试
# tests/test_ui_automation.py
import pytest
from unittest.mock import MagicMock, patch
class TestSecureUIAutomation:
"""TDD tests for UI automation security."""
def test_blocks_password_manager_access(self, automation):
"""Test that blocked processes are rejected."""
with pytest.raises(SecurityError, match="blocked"):
automation.find_element('keepass.exe', 'PasswordField')
def test_validates_process_before_input(self, automation):
"""Test process validation before any input."""
with patch.object(automation, '_validate_process') as mock_validate:
mock_validate.return_value = False
with pytest.raises(SecurityError):
automation.send_keys('test', hwnd=12345)
mock_validate.assert_called_once()
def test_enforces_rate_limiting(self, input_simulator):
"""Test input rate limiting prevents flooding."""
for _ in range(100):
input_simulator.send_keys('a', hwnd=12345)
with pytest.raises(RateLimitError):
input_simulator.send_keys('a', hwnd=12345)
def test_timeout_prevents_hanging(self, automation):
"""Test timeout enforcement on element search."""
with pytest.raises(TimeoutError):
with automation.timeout(0.001):
automation.find_element('app.exe', 'NonExistent')
@pytest.fixture
def automation():
return SecureUIAutomation(permission_tier='standard')
步骤 2:实现足以通过测试的最少代码
class SecureUIAutomation:
BLOCKED_PROCESSES = {'keepass.exe', '1password.exe'}
def find_element(self, process_name: str, element_id: str):
if process_name.lower() in self.BLOCKED_PROCESSES:
raise SecurityError(f"Access to {process_name} is blocked")
# Minimal implementation
步骤 3:使用完整模式进行重构
测试通过后,应用第 4 节中的安全模式。
步骤 4:运行完整验证
# Run all tests with coverage
pytest tests/test_ui_automation.py -v --cov=src/automation --cov-report=term-missing
# Run security-specific tests
pytest tests/ -k "security or blocked" -v
# Type checking
mypy src/automation --strict
7. 性能模式
模式 1:元素缓存
# BAD: Re-find element every operation
for i in range(100):
element = uia.find_element('app.exe', 'TextField')
element.send_keys(str(i))
# GOOD: Cache element reference
element = uia.find_element('app.exe', 'TextField')
for i in range(100):
if element.is_valid():
element.send_keys(str(i))
else:
element = uia.find_element('app.exe', 'TextField')
模式 2:限制范围
# BAD: Search from root every time
root = uia.GetRootElement()
element = root.FindFirst(TreeScope.Descendants, condition) # Searches entire desktop
# GOOD: Narrow search scope
app_window = uia.find_window('notepad.exe')
element = app_window.FindFirst(TreeScope.Children, condition) # Only direct children
模式 3:异步操作
# BAD: Blocking wait for element
while not element.is_enabled():
time.sleep(0.1) # Blocks thread
# GOOD: Async with timeout
import asyncio
async def wait_for_element(element, timeout=10):
start = asyncio.get_event_loop().time()
while not element.is_enabled():
if asyncio.get_event_loop().time() - start > timeout:
raise TimeoutError("Element not enabled")
await asyncio.sleep(0.05) # Non-blocking
模式 4:COM 对象池化
# BAD: Create new COM object per operation
def find_element(name):
uia = CreateObject('UIAutomationClient.CUIAutomation') # Expensive
return uia.GetRootElement().FindFirst(...)
# GOOD: Reuse COM object
class UIAutomationPool:
_instance = None
@classmethod
def get_automation(cls):
if cls._instance is None:
cls._instance = CreateObject('UIAutomationClient.CUIAutomation')
return cls._instance
模式 5:条件优化
# BAD: Multiple sequential conditions
name_cond = uia.CreatePropertyCondition(UIA_NamePropertyId, 'Submit')
type_cond = uia.CreatePropertyCondition(UIA_ControlTypeId, ButtonControl)
element = root.FindFirst(TreeScope.Descendants, name_cond)
if element.ControlType != ButtonControl:
element = None
# GOOD: Combined condition for single search
and_cond = uia.CreateAndCondition(
uia.CreatePropertyCondition(UIA_NamePropertyId, 'Submit'),
uia.CreatePropertyCondition(UIA_ControlTypeId, ButtonControl)
)
element = root.FindFirst(TreeScope.Descendants, and_cond)
8. 常见错误
8.1 严重安全反模式
切勿:未验证进程就执行自动化
# BAD: No validation
element = uia.find_element_by_name('Password')
element.send_keys(password)
# GOOD: Full validation
if validator.validate_process(target_pid):
if automation.permission_tier != 'read-only':
element = automation.find_element(process_name, 'Password')
element.send_keys(password)
切勿:跳过超时强制执行
# BAD: No timeout
element = uia.find_element(condition) # Could hang forever
# GOOD: With timeout
with timeout_mgr.timeout(10):
element = uia.find_element(condition)
切勿:允许系统按键组合
# BAD: Allow any keys
def send_keys(keys):
SendInput(keys)
# GOOD: Block dangerous combinations
def send_keys(keys):
if is_blocked_combination(keys):
raise SecurityError("Blocked key combination")
SendInput(keys)
13. 实施前检查清单
阶段 1:编写代码前
- 阅读
references/threat-model.md中的威胁模型 - 确定目标进程和所需权限等级
- 为安全要求编写失败的测试
- 为预期功能编写失败的测试
- 为所有操作定义超时限制
阶段 2:实施期间
- 先实现足以通过安全测试的最少代码
- 验证所有目标交互涉及的进程
- 配置被阻止的应用列表
- 启用权限等级强制执行
- 实施输入速率限制
- 对所有操作强制执行超时
- 对所有操作进行审计日志记录
阶段 3:提交前
- 所有测试通过:
pytest tests/ -v - 安全测试通过:
pytest tests/ -k security - 类型检查通过:
mypy src/automation --strict - 不含硬编码凭据或敏感数据
- 正确配置审计日志
- 达到性能目标(元素查找 <100ms)
14. 总结
你的目标是创建具备以下特性的 Windows UI 自动化:
- 安全:严格的进程验证、权限分级和审计日志记录
- 可靠:强制执行超时、处理错误并验证状态
- 无障碍:遵循无障碍 API 和辅助技术的规范
你了解 UI 自动化存在重大安全风险。你在自动化能力与严格控制之间取得平衡,确保所有操作都经过记录、验证并受到约束。
安全提示:
- 始终验证目标进程的身份
- 切勿自动化操作被阻止的安全应用程序
- 对所有操作强制执行超时
- 使用关联 ID 记录每项操作
- 根据风险实施适当的权限分级
自动化应提升工作效率,同时维护系统安全边界。
参考资料
- 高级模式:参见
references/advanced-patterns.md - 安全示例:参见
references/security-examples.md - 威胁模型:参见
references/threat-model.md
评论
支持 Markdown