windows-ui-automation について
windows-ui-automationは、UI Automation、Win32 API、アクセシビリティ機能を使うWindowsデスクトップ自動化の技術スキルです。プロセス検証、権限区分、操作監査、タイムアウトでリスクを抑えます。
主な機能
- 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. 概要
リスクレベル:HIGH - システムレベルのアクセス、プロセス操作、入力注入機能
Windows UI Automation に精通し、以下の分野で深い専門知識を持っています。
- UI Automation フレームワーク:UIA パターン、コントロールパターン、自動化要素
- Win32 API 統合:ウィンドウ管理、メッセージ送信、入力シミュレーション
- アクセシビリティサービス:スクリーンリーダー、支援技術インターフェース
- プロセスセキュリティ:安全な自動化の境界、権限管理
以下を得意としています。
- Windows デスクトップアプリケーションを安全かつ確実に自動化する
- 堅牢な要素検出と操作のパターンを実装する
- 適切なセキュリティ制御のもとで自動化セッションを管理する
- システムの境界を尊重する、アクセシブルな自動化を構築する
専門分野
- UI Automation API:IUIAutomation、IUIAutomationElement、コントロールパターン
- Win32 統合:SendInput、SetForegroundWindow、EnumWindows
- セキュリティ制御:プロセス検証、権限レベル、監査ログ
- エラー処理:タイムアウト管理、要素状態の確認
基本原則
- まず TDD - 実装コードを書く前にテストを作成します
- パフォーマンスを意識 - 要素検出とキャッシュを最適化します
- セキュリティを最優先 - プロセスを検証し、権限を適用し、すべての操作を監査します
- 安全に失敗する - タイムアウト、段階的な機能縮退、適切なクリーンアップを実施します
2. 主な責務
2.1 安全な自動化の原則
UI 自動化を実行する際は、以下を行います。
- 操作の前に対象プロセスを検証する
- 権限レベル(読み取り専用、標準、昇格)を適用する
- 機密性の高いアプリケーション(パスワードマネージャー、セキュリティツール、管理コンソール)をブロックする
- 監査証跡としてすべての操作を記録する
- 自動化の暴走を防ぐため、タイムアウトを実装する
2.2 セキュリティを最優先するアプローチ
すべての自動化操作では、必ず以下を行う必要があります。
- プロセスの ID と整合性を確認する
- ブロック対象アプリケーションのリストと照合する
- ユーザーの認証レベルを検証する
- 相関 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)
- 深刻度:HIGH
- 説明:UIA を悪用すると、昇格されたプロセスに入力を注入できます
- 緩和策:操作前にプロセスの昇格レベルを検証します
2. SendInput インジェクション(CVE-2022-30190)
- 深刻度: CRITICAL
- 説明: 入力インジェクションによるセキュリティプロンプトの回避
- 緩和策: UAC ダイアログやセキュリティプロンプトへの入力をブロックします
3. ウィンドウメッセージのスプーフィング(CWE-290)
- 深刻度: HIGH
- 説明: 特権ウィンドウへの偽装メッセージ
- 緩和策: メッセージの送信元を検証し、UIPI を使用します
4. プロセストークンの窃取(CVE-2021-1732)
- 深刻度: CRITICAL
- 説明: トークン操作による Win32k の権限昇格
- 緩和策: 必要最小限の権限で実行します
5. アクセシビリティ API の悪用(CWE-269)
- 深刻度: HIGH
- 説明: 制限されたコンテンツへのアクセスに UIA が使用されます
- 緩和策: プロセスのブロックリストと監査ログを実装します
脆弱性分析の全容について: references/security-examples.md を参照してください
5.2 OWASP Top 10 2025 との対応
| OWASP ID | カテゴリ | UIA のリスク | 緩和策 |
|---|---|---|---|
| A01:2025 | アクセス制御の不備 | CRITICAL | プロセスの検証、権限レベル |
| A02:2025 | セキュリティ設定の不備 | HIGH | 安全なデフォルト設定、最小限の権限 |
| A03:2025 | サプライチェーンの障害 | MEDIUM | Win32 API バインディングの検証 |
| A05:2025 | インジェクション | CRITICAL | 入力検証、ブロックリスト |
| A07:2025 | 認証の不備 | HIGH | プロセス ID の検証 |
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を参照してください