Architecture

This page describes how ToolSicurezza is structured internally.

Module map

┌──────────────────────────────────────────────────────────────────┐
│ infostealer_audit.py (orchestrator, ~1000 LOC)                   │
│                                                                  │
│  9-step workflow:                                                │
│   1. Load KB                  ──► browser_versions.load_kb()     │
│   2. Detect installed         ──► browser_versions.detect_*()    │
│   3. Online version check     ──► online_versions.fetch_all()    │
│   4. Tool auto-install        ──► external_tools.ensure_*()      │
│   5. Match version vs KB      ──► browser_versions.render_*()    │
│   6. Decrypt Chromium creds   ──► chromium_decrypt.extract_all() │
│      Decrypt Firefox creds    ──► firefox_nss.decrypt_*()        │
│   7. Detect targets+legacy    ──► infostealer_targets +          │
│                                    legacy_decrypt                │
│   8. LaZagne Light            ──► lazagne_light.run_*()          │
│   9. Generate fix recs        ──► browser_versions.generate_*()  │
└──────────────────────────────────────────────────────────────────┘
                       │
                       ├─ detect language ──► i18n.detect_system_language()
                       │                      i18n.get_strings(lang)
                       ▼
         render_html(state) → reports/infostealer_*.html

Module responsibilities

modules/browser_versions.py

No side effects, no filesystem writes.

modules/chromium_decrypt.py

Pure local operation. Writes nothing outside %TEMP% (transient
SQLite copies, deleted after use).

modules/firefox_nss.py

modules/online_versions.py

modules/external_tools.py

modules/infostealer_targets.py

No decryption or extraction of third-party data, only enumeration.

modules/lazagne_light.py

modules/legacy_decrypt.py

modules/i18n.py

No side effects. No file I/O. No network calls.

kb/vulnerabilities.json

A JSON file with four top-level sections:

Data flow for "decrypt all Chromium passwords"

Local State (JSON)
   │
   ├─ os_crypt.encrypted_key (base64)
   │     │
   │     ├─ strip "DPAPI" prefix
   │     ├─ CryptUnprotectData()  ── user-context
   │     └─► MASTER_KEY_v10 (32 bytes)
   │
   └─ os_crypt.app_bound_encrypted_key (base64, Chrome 127+)
         │
         ├─ strip "APPB" prefix + 4-byte version
         ├─ CryptUnprotectData()  ── needs SYSTEM context (aggressive mode)
         ├─ inner: another DPAPI blob, user-context
         └─► MASTER_KEY_v20 (32 bytes)   [aggressive mode only]

Login Data (SQLite)
   │
   └─ logins.password_value (BLOB)
         │
         if blob[:3] == b"v10":
            nonce  = blob[3:15]
            ct_tag = blob[15:]
            AESGCM(MASTER_KEY_v10).decrypt(nonce, ct_tag) → plaintext
         elif blob[:3] == b"v20":
            (requires MASTER_KEY_v20)
            AESGCM(MASTER_KEY_v20).decrypt(nonce, ct_tag) → opaque header + plaintext
         else:
            CryptUnprotectData(blob) → plaintext  (pre-v10)

Data flow for "online version check"

fetch_all_latest()
   │
   ├─ Check %TEMP%\pwd_audit_versions_cache.json
   │  └─ if age < 24h: return cached
   │
   ├─ HTTP GET chromiumdash.appspot.com
   ├─ HTTP GET product-details.mozilla.org
   ├─ HTTP GET edgeupdates.microsoft.com
   ├─ HTTP GET api.github.com (brave releases)
   │
   ├─ Parse + normalise to {version, major, release_date, source}
   ├─ Save to cache
   └─ Return dict

Data flow for aggressive mode

User runs: py pwd_audit.py --aggressive
   │
   ├─ is_admin()? → no
   │  └─ ShellExecuteW(verb="runas", file=python.exe, args=...)
   │     └─ UAC prompt → user accepts
   │        └─ Elevated console starts the same script with admin token
   │
   ├─ get_app_bound_key_aggressive(local_state)
   │  ├─ user-DPAPI unwrap outer blob
   │  ├─ Write inner blob to %TEMP%\pa<rnd>i.bin
   │  ├─ Write helper script to %TEMP%\pa<rnd>h.py
   │  ├─ Write batch wrapper to %TEMP%\pa<rnd>w.bat
   │  ├─ schtasks /Create /RU SYSTEM /TR <wrapper.bat>
   │  ├─ schtasks /Run
   │  ├─ Wait for output file
   │  ├─ Read output (SYSTEM-decrypted inner blob)
   │  ├─ Try brute-force 32-byte windows against a known v20 sample
   │  └─ schtasks /Delete + remove temp files
   │
   └─ If brute-force succeeds → MASTER_KEY_v20 → decrypt all v20 entries
      If brute-force fails → "Stratum 3 resists" → fall back to v20-protected

Threading and concurrency

The tool is strictly single-threaded. Operations are sequential.
This is intentional:

The only "parallel" operation is the subprocess invocation of
schtasks and netsh, which are atomic from our perspective.

Error handling philosophy

File system footprint

The tool writes only to:

Nothing is written to the registry. Nothing is written to system
paths. Nothing is written outside the project directory or %TEMP%.