#!/usr/bin/env python3 """ Analyze Flipper Zero signature database Parses all Flipper Zero .sub files and creates a comprehensive device signature database """ import sys from pathlib import Path from collections import defaultdict from typing import Dict, List # Add project root to path sys.path.insert(0, str(Path(__file__).parent.parent)) from src.parser.sub_parser import SubFileParser def analyze_flipper_database(flipper_dir: Path): """Analyze all Flipper Zero .sub files""" print("="*80) print("FLIPPER ZERO SIGNATURE DATABASE ANALYSIS") print("="*80) print() parser = SubFileParser() # Find all .sub files sub_files = list(flipper_dir.glob('**/*.sub')) print(f"Found {len(sub_files)} Flipper Zero .sub files\n") # Parse all files signatures = [] parse_errors = [] for sub_file in sub_files: try: metadata = parser.parse(str(sub_file)) # Extract device name from path device_name = sub_file.stem signatures.append({ 'filename': sub_file.name, 'device_name': device_name, 'path': str(sub_file.relative_to(flipper_dir)), 'frequency': metadata.frequency, 'protocol': metadata.protocol, 'file_format': metadata.file_format, 'modulation': metadata.modulation, 'bit_length': metadata.bit_length, 'has_raw_data': bool(metadata.raw_data), 'raw_samples': len(metadata.raw_data) if metadata.raw_data else 0 }) except Exception as e: parse_errors.append((sub_file.name, str(e))) print(f"Successfully parsed: {len(signatures)} files") print(f"Parse errors: {len(parse_errors)} files\n") # Analyze by frequency print("-"*80) print("FREQUENCY DISTRIBUTION") print("-"*80) freq_groups = defaultdict(list) for sig in signatures: freq_mhz = sig['frequency'] / 1e6 if sig['frequency'] else 0 freq_groups[freq_mhz].append(sig) for freq in sorted(freq_groups.keys()): if freq > 0: count = len(freq_groups[freq]) print(f"{freq:8.2f} MHz: {count:3d} devices") # Analyze by protocol print(f"\n{'-'*80}") print("PROTOCOL DISTRIBUTION") print("-"*80) protocol_groups = defaultdict(list) for sig in signatures: proto = sig['protocol'] or 'RAW' protocol_groups[proto].append(sig) for proto in sorted(protocol_groups.keys(), key=lambda x: len(protocol_groups[x]), reverse=True)[:15]: count = len(protocol_groups[proto]) print(f"{proto:30s}: {count:3d} devices") # Analyze by format print(f"\n{'-'*80}") print("FILE FORMAT DISTRIBUTION") print("-"*80) format_groups = defaultdict(list) for sig in signatures: format_groups[sig['file_format']].append(sig) for fmt in sorted(format_groups.keys()): count = len(format_groups[fmt]) print(f"{fmt:10s}: {count:3d} files") # Show sample devices by frequency band print(f"\n{'-'*80}") print("SAMPLE DEVICES BY FREQUENCY BAND") print("-"*80) # Group into common RF bands bands = { '300-350 MHz (Garage/Gate)': (300, 350), '400-450 MHz (Key Fobs/Remotes)': (400, 450), '800-900 MHz (Sensors/Utility)': (800, 900), '900-930 MHz (ISM Band - US)': (900, 930) } for band_name, (min_freq, max_freq) in bands.items(): matching = [s for s in signatures if min_freq <= (s['frequency']/1e6) <= max_freq] print(f"\n{band_name}: {len(matching)} devices") # Show first 10 for sig in matching[:10]: print(f" - {sig['device_name']:40s} {sig['frequency']/1e6:7.2f} MHz {sig['protocol'] or 'RAW'}") return signatures, parse_errors def main(): """Main entry point""" flipper_dir = Path(__file__).parent.parent / 'signatures' / 'flipperzero-firmware' if not flipper_dir.exists(): print(f"❌ Flipper Zero directory not found: {flipper_dir}") print("Run: git clone https://github.com/flipperdevices/flipperzero-firmware.git") return 1 signatures, errors = analyze_flipper_database(flipper_dir) # Summary print(f"\n{'='*80}") print("SUMMARY") print(f"{'='*80}") print(f"Total signatures: {len(signatures)}") print(f"Parse errors: {len(errors)}") print(f"\nThese signatures can now be imported into GigLez database") print(f"for device matching against wardriving captures.") print("="*80) return 0 if __name__ == '__main__': sys.exit(main())