
Specter — leitor/skimmer NFC passivo de 13,56 MHz e varredura de bugs para o Flipper Zero. Medidor de EMF de contravigilância usando o chip NFC integrado. Sem hardware adicional, nunca transmite.
<!-- banner: paper by default, true black when the reader's GitHub is dark -->
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="images/banner-dark.png">
<img src="https://assets.kitploit.com/production/public/readmes/42070/74bc06f0a6a1b0731b4768b4256f662b34a582f5b9701a9bce44cb1b10bedd0d.png" alt="Specter — NFC reader and skimmer bug-sweep for Flipper Zero" width="100%">
</picture>
</p>
<p align="center">
<sub>
A forma de onda não é um gráfico. São 128 colunas de portadora de 13,56 MHz que
o Specter registrou de um leitor de polling real a 8 ms por coluna, lidas de volta
a partir da captura de tela ao lado. Seu duty mede 28% onde o próprio contador
do dispositivo imprimiu 27%, e ambos os números estão no banner.
</sub>
</p>
<p align="center"><i>Varra os leitores que você não consegue ver.</i></p>
<p align="center">
<a href="https://at0m-b0mb.github.io/Specter-FlipperZero/"><b>Site do projeto</b></a>
·
<a href="https://github.com/at0m-b0mb/Specter-FlipperZero/releases/latest">Download</a>
·
<a href="https://github.com/at0m-b0mb/specter-flipperzero/blob/main/docs/changelog.md">Changelog</a>
</p>
<!-- live badges: these track the repo, so the README never goes stale -->
<p align="center">
<a href="https://github.com/at0m-b0mb/Specter-FlipperZero/releases/latest"><img src="https://img.shields.io/github/v/release/at0m-b0mb/Specter-FlipperZero?style=flat-square&color=8A6714&labelColor=000000" alt="Latest release"></a>
<a href="https://github.com/at0m-b0mb/Specter-FlipperZero/releases"><img src="https://img.shields.io/github/downloads/at0m-b0mb/Specter-FlipperZero/total?style=flat-square&color=8A6714&labelColor=000000&label=downloads" alt="Downloads"></a>
<a href="https://github.com/at0m-b0mb/Specter-FlipperZero/stargazers"><img src="https://img.shields.io/github/stars/at0m-b0mb/Specter-FlipperZero?style=flat-square&color=8A6714&labelColor=000000" alt="Stars"></a>
<a href="https://github.com/at0m-b0mb/Specter-FlipperZero/actions/workflows/build.yml"><img src="https://img.shields.io/github/actions/workflow/status/at0m-b0mb/Specter-FlipperZero/build.yml?branch=main&style=flat-square&labelColor=000000&color=8A6714&label=build" alt="Build"></a>
</p>
<p align="center">
<img src="https://img.shields.io/badge/platform-Flipper%20Zero-8A6714?style=flat-square&logo=flipper&logoColor=FE8A2C&labelColor=000000" alt="Flipper Zero">
<img src="https://img.shields.io/badge/radio-13.56%20MHz%20NFC%20(onboard)-8A6714?style=flat-square&labelColor=000000" alt="Onboard NFC">
<img src="https://img.shields.io/badge/extra%20hardware-none-8A6714?style=flat-square&labelColor=000000" alt="No extra hardware">
<img src="https://img.shields.io/badge/transmits-never-8A6714?style=flat-square&labelColor=000000" alt="Listen-only">
<img src="https://img.shields.io/badge/license-MIT-8A6714?style=flat-square&labelColor=000000" alt="MIT">
</p>
<p align="center">
O <b>Specter</b> transforma seu Flipper Zero em uma <b>varredura de contra-vigilância</b> de bolso
para <b>leitores NFC ativos de 13,56 MHz</b>. Ele <i>escuta passivamente</i> o campo de RF que um
leitor ligado está constantemente emitindo — um skimmer de cartão escondido dentro de um terminal de pagamento, um
leitor clandestino atrás de um painel de porta, um logger malicioso colado embaixo de uma mesa — e então te diz <b>onde ele está</b>,
<b>que tipo de coisa é</b>, <b>se a sala está limpa</b> e — deixado de vigia — <b>o
momento em que um aparece enquanto você está fora</b>. Ele nunca transmite.
</p>
<p align="center"><sub>Os leitores são invisíveis. O Specter os torna visíveis.</sub></p>
<p align="center">
<sub>
<b>Destacado em</b><br>
<a href="https://www.helpnetsecurity.com/2026/07/29/specter-flipper-zero-skimmer-detector/">Help Net Security</a>
·
<a href="https://cybersecuritynews.com/specter-with-flipper-zero/">Cyber Security News</a>
</sub>
</p>
---
## No Flipper
<p align="center">
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/images/demo.gif" width="70%" alt="Specter in use: sweeping a quiet room, closing in on a reader, locking on at PEGGED, fingerprinting its polling cadence, then a site-survey verdict">
</p>
<p align="center">
<sub>Uma varredura, do início ao fim: sala silenciosa → aproximando-se → travado → <b>o que</b> é → o veredito da sala.</sub>
</p>
### As telas que nenhum modo isolado possui
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="images/screens-dark.png">
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/images/screens.png" width="100%" alt="The boot intro, main menu, Sweep listening, Fingerprint with nothing there, a Site Survey walking, Watch with a contact logged, the Logbook and Settings — all captured from a real Flipper Zero">
</picture>
</p>
<p align="center">
<sub>
Os estados silenciosos e a introdução — os quatro modos abaixo carregam cada um sua própria
captura, então estas são as que eles não têm. <b>Toda imagem
neste README é uma captura de um dispositivo real</b>, tirada pela própria sessão
RPC do Flipper por <code>tools_screenshot.py</code>. Não há mais nenhum renderizador de mockup
neste projeto — um desenho da UI é uma segunda
implementação dela, e ele divergia do firmware enquanto parecia
perfeitamente convincente (veja <a href="https://github.com/at0m-b0mb/specter-flipperzero/blob/main/docs/changelog.md">3.0.1</a>).
</sub>
</p>
---
## Os cinco modos
O Specter são cinco ferramentas em torno de um sensor. Cada uma responde a uma pergunta diferente, então
a certa depende do que você está realmente tentando descobrir:
| Modo | A pergunta que ele responde | Use quando |
|---|---|---|
| **Sweep** | *Onde está?* | Você suspeita de um dispositivo e quer localizá-lo movendo-se ao redor |
| **Fingerprint** | *Que tipo de coisa é?* | Você encontrou um emissor e quer saber como ele se comporta |
| **Site Survey** | *Esta sala está limpa?* | Você quer um veredito único para um espaço inteiro, sem usar as mãos |
| **Watch Mode** | *Apareceu algum enquanto eu estava fora?* | Você vai deixar o Flipper em algum lugar para montar guarda |
| **Logbook** | *O que eu encontrei, e quando?* | Você está escrevendo um relatório, ou comparando hoje com a semana passada — filtre por tipo de achado |
---
### Sweep — *onde está?*
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/screenshots/sweep_reader.png" width="42%" align="right" alt="Sweep — reader found, meter pegged">
**O que faz.** Um medidor ao vivo estilo EMF. Segure o Flipper plano e mova-o lentamente
sobre a coisa que você está verificando — um terminal de cartão, um leitor de porta, a parte de baixo de
uma fenda de ATM, um pacote, uma mesa. A agulha acompanha a força do campo em tempo real.
**O que você vê.**
- **O mostrador** — agulha = leitura ao vivo, o pequeno ponto = *peak-hold* (o ponto mais forte
que você tocou, para que você possa comparar posições).
- **`FIELD %`** — a mesma leitura como número, com uma **seta de tendência ▲ / ▼**
dizendo se o último meio segundo deixou as coisas *mais quentes ou mais frias*. Quando
você está caçando, essa seta importa mais que o número.
- **`PEAK %`** — a leitura mais forte desde que você armou, o número por trás do
ponto de peak-hold.
- **A marca no mostrador** — onde `READER` *começa* na sua sensibilidade
atual. Tudo além dela é o que o Specter vai chamar de acerto, então o mostrador
responde "o que conta?" em vez de te deixar adivinhando.
- **Faixa inferior** — até você encontrar seu primeiro leitor, ela carrega as duas teclas
que você não consegue descobrir apertando coisas (`LEFT=cal`, `hold OK=log`); depois disso,
sua sensibilidade e uma forma de onda ao vivo. Ela muda para uma barra de alarme
preta **`● ACTIVE READER`** com uma palavra de proximidade no momento em que uma portadora é
detectada.
- **Proximidade** — `FAINT → NEAR → CLOSE → STRONG → PEGGED`. `PEGGED` significa que o medidor está
*pegged*: você está o mais perto que esta medição consegue resolver.
**Som.** Cliques de geiger opcionais que **aceleram conforme você se aproxima**, para que você possa
varrer com o Flipper no bolso e caçar apenas pelo ouvido.
| Tecla | Ação |
|---|---|
| `OK` | Redefine o peak-hold e a contagem de contatos |
| `hold OK` | Salva esta leitura no logbook |
| `LEFT` | Calibra para o piso de ruído da sala (3 s) |
| `UP` / `DOWN` | Ajusta a sensibilidade sem sair da caçada |
<br clear="right">
### Fingerprint — *que tipo de coisa é?*
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/screenshots/fingerprint_reader.png" width="42%" align="right" alt="Fingerprint — polling reader identified">
**O que faz.** Depois que o Sweep encontrou algo, segure o Flipper **parado**
contra ele. O Fingerprint para de medir proximidade e começa a **cronometrar as
bordas de liga/desliga da portadora**, que é o que de fato distingue um tipo de
emissor de outro.
**O que você vê.** Um veredito, uma barra de confiança e as evidências por trás de ambos:
| Classe | O que significa na prática |
|---|---|
| **CONTINUOUS** | A portadora é mantida permanentemente ativa |
| **POLLING** | Um ciclo de polling fixo, cronometrado por cristal — o período é mostrado em ms |
| **INTERMITTENT** | Em rajadas, mas irregular — frequentemente um telefone ou um leitor em uso |
Abaixo estão `PER` (período de polling), `BST` (largura da rajada), `JIT` (jitter) e
`UP` (duty-cycle real), além de um **trem de pulsos de analisador lógico** da portadora
bruta — então o veredito nunca é algo que você precise aceitar por fé. Um leitor de
polling genuíno aparece como uma onda quadrada inconfundível.
> Um `~` antes de uma medição de tempo significa que ela está próxima do piso de amostragem de 2 ms, e a
> confiança é descontada de acordo.
| Tecla | Ação |
|---|---|
| `OK` | Salva o achado no logbook |
| `hold OK` | Reinicia a medição |
<br clear="right">
### Site Survey — *esta sala está limpa?*
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/screenshots/survey_active.png" width="42%" align="right" alt="Site Survey — verdict">
**O que faz.** Uma varredura **cronometrada** de um espaço inteiro. Inicie, percorra a sala
normalmente e receba um veredito único no final — sem ficar olhando para a agulha.
**O que você vê.** Uma contagem regressiva e uma barra de progresso enquanto roda, depois um cartão de veredito:
- **`CLEAN`** — nada cruzou o piso de ruído
- **`TRACE`** — acertos breves ou fracos; vale uma segunda passada mais lenta
- **`ACTIVE READER`** — algo estava genuinamente ativo e emitindo
- **`TOO SHORT`** — você o interrompeu antes que ele tivesse conquistado o direito de dizer `CLEAN`
…com `PEAK` / `AVG` de campo, contagem de contatos e `UP %` — **quanto da varredura
uma portadora esteve de fato ativa**, que muitas vezes é o número mais revelador dos quatro.
Roda por 30 s, 60 s ou 2 min, e registra o resultado automaticamente. O cartão nomeia
a duração sobre a qual foi avaliado, porque um `CLEAN` de 30 segundos não é o mesmo
achado que um de dois minutos — e uma execução cortada em menos de 10 s reporta
`TOO SHORT` em vez de `CLEAN`. A assimetria é deliberada: **presença é
prova, ausência não é.** Encontrar algo em um segundo é um achado real, então
`TRACE` e `ACTIVE READER` nunca são retidos por serem rápidos; não encontrar nada
em um segundo é uma afirmação sobre a sala inteira que um segundo não pode sustentar.
| Tecla | Ação |
|---|---|
| `OK` *(em execução)* | Para agora e avalia o que tem |
| `OK` *(no cartão)* | Roda outra varredura |
<br clear="right">
### Watch Mode — *apareceu algum enquanto eu estava fora?*
<img src="https://raw.githubusercontent.com/at0m-b0mb/specter-flipperzero/main/screenshots/watch_reader.png" width="42%" align="right" alt="Watch Mode — reader present">
**O que faz.** Monta guarda **indefinidamente**. Arme-o, deixe o Flipper em algum lugar,
vá embora. Onde o Sweep é você caçando e o Survey é um teste de duração fixa, o Watch
apenas espera — por minutos ou horas.
**O que você vê.** Um grande relógio de tempo decorrido e `NO READER` enquanto nada está lá.
No instante em que um leitor aparece, a faixa se inverte para **`ACTIVE READER`**, uma barra de força
mostra o quão perto ele está, a **tela acorda** e o alarme soa. A faixa
é estável em vez de piscar — em uma tela de 1 bit, um bloco invertido sólido já é
a coisa mais chamativa nela, e as leituras que genuinamente mudam carregam
a vivacidade. Depois que ele passa, a tela mantém a evidência: `HITS` (quantos
contatos separados), `PEAK`, `LAST` (há quanto tempo foi o mais recente) e
`UP` (tempo total em que uma portadora esteve de fato ativa). O relógio passa para `hh:mm`
após 99:59 em vez de congelar, então uma vigília durante a noite ainda soma certo.
O Watch **deliberadamente ignora o modo stealth** — um guarda escuro e silencioso que nunca
te diz que viu algo seria pior que inútil.
| Tecla | Ação |
|---|---|
| `OK` | Rearma — limpa o relógio e os contadores |
<br clear="right">
### Logbook — *o que eu encontrei, e quando?*
Os achados são salvos **duas vezes, a partir de uma única ação**, para que sejam legíveis no dispositivo
*e* já sejam uma planilha — sem etapa de exportação para lembrar:
<table>
<tr><th><code>logbook.txt</code> — agrupado, para o visualizador no dispositivo</th><th><code>logbook.csv</code> — uma linha plana por entrada</th></tr>
<tr><td>```
2026-07-18 14:35:11
SURVEY 60s ACTIVE max74…
2026-07-18 14:32:07
READER POLLING 204ms…
```
</td><td>```
timestamp,type,detail
2026-07-18 14:35:11,SURVEY,60s ACTIVE …
2026-07-18 14:32:07,READER,POLLING 204ms …
```
</td></tr>
</table>
As entradas são marcadas como `SWEEP`, `READER`, `SURVEY` ou `WATCH` e datadas pelo
relógio do Flipper. Ambos os arquivos ficam em `apps_data/specter/` no cartão SD. Nada
sai jamais do dispositivo. Limpe-os em **Settings → Clear logbook** (confirmado
primeiro — é a única coisa irreversível que o app pode fazer).
---
## Os componentes de apoio
### Auto-calibração
Pressione **LEFT** na tela Sweep e o Specter escuta o **ruído de fundo
ambiente por 3 segundos**, depois define o limiar de detecção logo acima do que
mediu — salvo como sua sensibilidade **Custom**. Cada ambiente tem um piso de RF
diferente; isto sintoniza com o ambiente em que você está, em vez de um número fixado no
momento da compilação. Fique em um lugar silencioso quando executá-lo.
### Modo stealth
Mantém a **tela e o LED apagados** durante toda a varredura, para que o Flipper não brilhe
enquanto você é quem está observando. Som e vibração continuam funcionando — o
objetivo não é desativar o feedback pelo qual você está varrendo. Sair de uma tela stealth
reacende o display, então `BACK` sempre te leva a um menu iluminado.
### Lendo o medidor
**Por que um leitor que você está tocando não emite 100% do tempo.** O detector
mede uma coisa física: qual fração do tempo uma portadora de 13,56 MHz está ativa.
Mas os leitores **fazem polling** — uma rajada curta, uma pausa, outra rajada. Um terminal
típico só irradia **20–35% do tempo**, então o duty-cycle bruto *satura* em torno de 30%
não importa o quão perto você chegue.
Mostrar esse número bruto no medidor fazia uma detecção perfeita parecer um terço
de uma. O medidor é escalado contra essa faixa real de polling:
| Duty da portadora bruto | Medidor | Proximidade |
|---|---|---|
| 3% (ruído do ambiente) | 10% | `FAINT` |
| 12% | 40% | `NEAR` |
| 20% | 67% | `CLOSE` |
| 28% | 93% | `STRONG` |
| ≥30% *(apoiado em um leitor)* | **100%** | `PEGGED` |
O **duty bruto nunca é perdido**: o piso de ruído, a auto-calibração e o `UP` da
tela Fingerprint ainda funcionam em duty-cycle real, porque esses descrevem o
*sinal*, não sua distância dele. Quer o número literal?
**Settings → Meter scale → Duty %**.
### Tudo persiste
Sensibilidade, duração da varredura, som, vibração, LED, stealth, logging e modo do medidor são
**salvos no cartão SD** no momento em que você os altera. Um kit de varredura que esquece sua
configuração é pior do que nenhuma persistência.
---
## Como funciona
Todo leitor NFC ligado continuamente **emite pulsos no ar com uma portadora de 13,56 MHz**, esperando que um cartão
desperte. Você não consegue vê-la, mas o chip NFC do Flipper consegue: o **ST25R3916** tem um
**detector de campo externo** por hardware (o mesmo circuito que permite ao Flipper emular um cartão e saber quando um leitor
está falando com ele). O Specter coloca o chip em modo somente-detecção e **amostra esse bit de "campo presente?"
~500 vezes por segundo** — sem nunca ligar sua própria portadora.
Esse único bit, amostrado rápido o suficiente, carrega dois sinais independentes:```mermaid
flowchart LR
R["Hidden 13.56 MHz reader / skimmer<br/>(constantly polling its field)"] -- "RF carrier" --> A
subgraph FLIP["Flipper Zero — Specter.fap"]
A["ST25R3916 NFC chip<br/>external-field detector"] --> S["Sampler thread<br/>~500 samples/s"]
S --> M["<b>How much?</b><br/>carrier duty-cycle<br/>peak · average · contacts"]
S --> C["<b>What rhythm?</b><br/>burst / gap edge timing<br/>period · jitter"]
M --> G["EMF gauge · waveform<br/>geiger clicks · LED · vibe"]
M --> V["Survey verdict<br/>CLEAN / TRACE / ACTIVE"]
C --> K["Emitter class<br/>CONTINUOUS / POLLING /<br/>INTERMITTENT + pulse train"]
V --> L["SD logbook"]
K --> L
end
```
**Quanto → intensidade.** Numa janela curta, o Specter mede *que fração do tempo* um carrier está
presente e suaviza isso no **FIELD %**. Um leitor mesmo em cima do Flipper satura o medidor;
um mais fraco ou mais distante apenas o desloca. Isso comanda a agulha, a palavra de proximidade e a taxa de cliques.
**Que ritmo → identidade.** Separadamente, cada transição desse bit é cronometrada. Um leitor que acorda por
20 ms a cada 200 ms produz um padrão de burst/gap com quase nenhum jitter, porque seu loop de polling é
comandado por uma máquina de estados temporizada por cristal. Movimento de mão e ruído de RF não são tão estáveis. Essa
diferença é o que separa **POLLING** de **INTERMITTENT**.
### As camadas de decisão são testadas num computador real
Os pontos onde o Specter transforma números numa *afirmação* — "isto é um leitor de polling", "esta sala está
limpa", "isto é o que a agulha deve ler" — são C puro sem dependências de hardware, e são
fixados por testes no host em vez de descobertos no dispositivo:```bash
make -C test # 527 checks: classifier, verdict, meter scaling, presence,
# cadence, log filtering, log wrapping
```
---
## Instalação
Sem devboard, sem firmware para gravar — é um único `.fap`.
**Opção A — `.fap` pré-compilado (mais fácil)**
1. Baixe o `.fap` correto na página de [**Releases**](https://github.com/at0m-b0mb/Specter-FlipperZero/releases):
| Seu firmware | Arquivo |
|---|---|
| **Oficial / stock** | `specter.fap` |
| **Unleashed, RogueMaster, Momentum** ou qualquer mais recente | `specter-fw-dev.fap` |
> Se o Flipper exibir **`APP:87 < FW:88 — This app might not work`**, você está com o
> arquivo errado — use o outro. A versão da API do app é fixada no momento da compilação,
> então uma única build não consegue atender as duas linhas de firmware. Normalmente ele
> ainda funciona se você pressionar Continue, mas a build correspondente não vai perguntar.
2. Abra o **qFlipper**, arraste o arquivo para `SD Card / apps / NFC /`.
3. No Flipper: **Apps → NFC → Specter**.
**Opção B — compile você mesmo com [`ufbt`](https://github.com/flipperdevices/flipperzero-ufbt)**```bash
# one-time
python3 -m pip install --upgrade ufbt
# from the repo root, with your Flipper plugged in over USB:
ufbt # build specter.fap into ./dist
ufbt launch # build, upload to the Flipper and open it
make -C test # run the host tests for the pure logic
```
O `.fap` vai para `dist/specter.fap`; `ufbt launch` copia-o para `apps/NFC/` e inicia-o por ti.
> Os ícones em `icons/` e o banner em `images/` são gerados — regenera-os com
> `python3 tools_gen_icons.py` e `python3 tools_gen_banner.py` (requer `pillow`).
> Tudo em `screenshots/` é capturado de um dispositivo real com
> `python3 tools_screenshot.py` (requer `pyserial` e um Flipper ligado por USB).
---
## Utilização
**Uma varredura, de início ao fim:**
1. Inicia o **Specter**. No ecrã **Sweep**, prime **LEFT** e mantém-te imóvel durante 3 segundos para
calibrar ao ruído de fundo da sala.
2. Segura o Flipper plano e move-o **lentamente** sobre o que estás a verificar — um terminal de cartões, um
leitor de porta, a parte inferior da ranhura de uma ATM, uma encomenda, uma secretária.
- **Forma de onda silenciosa / plana** → nenhum leitor ativo ao alcance.
- **Agulha a subir, cliques a acelerar** → estás a aproximar-te de um emissor. Continua em direção ao pico.
- **`● ACTIVE READER` + borda de alarme** → há um leitor ativo mesmo aqui.
3. Encontraste algo? Sai e abre **Fingerprint**. Mantém o Flipper imóvel junto ao leitor e deixa a
cadência estabilizar — alguns segundos costumam ser suficientes. Prime **OK** para guardar o achado.
4. Vais limpar uma sala inteira? Abre **Site Survey**, percorre o espaço até a barra encher e lê
o veredicto.
5. Vais sair da área? Deixa o Flipper em **Watch Mode** e ele ficará de guarda, acordando e soando
se um leitor aparecer enquanto estiveres fora.
6. Consulta o **Logbook** para tudo o que guardaste, com data e hora — ou extrai o `logbook.csv` do cartão
para uma folha de cálculo.
> Varre primeiro um leitor que sabes ser legítimo (o teu próprio telemóvel a fazer NFC, ou um terminal
> contactless em que confias) para ver como é um campo forte e legítimo no medidor — e como se lê a sua
> impressão digital. Depois vai à caça.
### Controlos
| Ecrã | Tecla | Ação |
|---|---|---|
| **Sweep** | `OK` | Reiniciar pico / contactos |
| | `hold OK` | Registar a leitura atual |
| | `LEFT` | Calibrar o ruído de fundo (3 s) |
| **Fingerprint** | `OK` | Guardar o achado no logbook |
| | `hold OK` | Reiniciar a medição |
| **Site Survey** | `OK` | Executar a varredura novamente |
| **Watch Mode** | `OK` | Rearmar (limpar contagem e relógio) |
| *em qualquer lugar* | `BACK` | Subir um nível |
---
## Limitações honestas
- **Apenas 13,56 MHz (HF).** O Specter deteta a **banda NFC** — a usada por skimmers de pagamento contactless,
pela maioria dos leitores de acesso modernos, leitores de transportes e de hotéis. **Não consegue** ver leitores
de **125 kHz (LF)** (painéis de porta HID Prox / EM4100 mais antigos); o caminho LF do Flipper não tem um bit
equivalente de deteção de campo.
- **Deteta a *portadora* de um leitor, não o que ele lê.** O Specter diz-te *que há um leitor ativo aqui,
aproximadamente quão perto, e com que ritmo faz polling* — não descodifica, identifica nem captura nada
do que o leitor faz.
- **A intensidade é relativa, não calibrada.** `FIELD %` e as palavras de proximidade são um guia comparativo
de "mais quente / mais frio" para a varredura, não uma distância medida em cm. É uma leitura *escalada* do
duty-cycle da portadora em relação a uma banda de polling típica (ver [Ler o medidor](#-reading-the-meter--fixed-in-23));
um leitor que faz polling invulgarmente esparso lerá mais baixo à mesma distância, e um em modo de onda contínua
marcará o máximo a partir de mais longe.
- **O medidor atinge o máximo.** `PEGGED` significa que a portadora está tão alta quanto este leitor alguma vez a mantém — a partir
desse ponto, aproximar-se genuinamente não pode produzir um número maior. O Flipper vibra uma vez quando isso acontece,
para saberes que deves parar de te mover mesmo quando não consegues ver o ecrã. Usa a retenção `PEAK` para comparar
posições em vez disso.
- **A cadência resolve até ~2 ms.** Esse é o período de amostragem. Temporizações próximas disso são mostradas com um
**`~`** e a confiança é descontada em conformidade — o Specter prefere sinalizar o seu próprio limite de resolução
do que citar um número de aspeto preciso que não pode sustentar.
- **`CLEAN` significa limpo à sensibilidade que escolheste.** Um skimmer dormente que só acorda com um toque real,
ou um que esteja blindado, permanece invisível a *qualquer* limiar. A ausência de leitura não é garantia de
ausência.
- **Um rádio de cada vez.** O Specter assume o controlo do chip NFC durante a varredura, por isso fecha primeiro qualquer outra app NFC
(dirá *NFC unavailable* se algo mais estiver a usar o rádio).
---
## Legal e ético
O Specter é uma ferramenta **defensiva, apenas de escuta** — **nunca transmite**, nunca alimenta um campo, nunca toca
no leitor. Usa-o para varrer **a tua própria** área de POS, porta, secretária ou pertences, ou hardware que estás **explicitamente
autorizado** a avaliar. És responsável pela forma como o usas. Conhece as leis locais.
---
## Roadmap
- [x] Persistir sensibilidade / som / vibração / LED entre reinícios
- [x] "Logbook" de deteções com data e hora para o cartão SD
- [x] Varredura em segundo plano com o ecrã desligado — *modo furtivo*
- [x] Limiar ajustável para controlo de alcance mais fino — *auto-calibração + sensibilidade personalizada*
- [x] Impressão digital de um emissor pela sua cadência de polling
- [x] Varredura de local temporizada com veredicto da sala
- [x] Exportar o logbook como CSV para relatórios — *escrito em tempo real juntamente com o .txt*
- [x] Modo de vigilância prolongada sem supervisão com alarme de despertar por deteção
- [x] Fazer o medidor usar todo o seu alcance contra leitores de polling reais
- [x] Seta de tendência mais quente/mais frio durante a caça
- [ ] Investigar uma deteção de leitor baseada em bobina LF (125 kHz) como modo separado
- [ ] Filtragem do logbook por tipo no dispositivo
---
## Estrutura do projeto```
Specter-FlipperZero/
├── application.fam # Flipper app manifest (category: NFC)
├── specter.c / specter_i.h # app entry, wiring, alert feedback, stealth
├── helpers/
│ ├── field_detector.{c,h} # worker thread: samples the field-present bit,
│ │ # duty-cycle + edge timing + calibration
│ ├── emitter_classify.{c,h} # pure: cadence -> CONTINUOUS/POLLING/INTERMITTENT
│ ├── survey_verdict.{c,h} # pure: survey stats -> CLEAN/TRACE/ACTIVE
│ ├── field_scale.{c,h} # pure: raw carrier duty -> full-scale meter
│ ├── present_hold.h # pure: debounce presence across poll gaps
│ ├── cadence.h # pure: burst/gap/period timing with liveness
│ ├── ema.h # pure: the strength smoother
│ ├── log_filter.h # pure: keep only one kind of finding
│ ├── log_wrap.h # pure: wrap an entry at words, not mid-word
│ ├── specter_settings.{c,h} # persisted settings (saved_struct)
│ └── specter_log.{c,h} # SD logbook, RTC-stamped .txt + live .csv
├── views/
│ ├── view_chrome.h # the header, presence dot and error screen
│ │ # every measurement view shares
│ ├── sweep_view.{c,h} # the EMF gauge / waveform / alarm screen
│ ├── fingerprint_view.{c,h} # classification card + pulse-train trace
│ ├── survey_view.{c,h} # progress + verdict card
│ └── watch_view.{c,h} # unattended guard: clock + count + alarm
├── scenes/ # scene-manager navigation
├── test/ # host tests for the pure decision layers
├── icons/ # 1-bit Flipper icons (generated)
├── images/ # banner, mark and social card (generated), plus
│ # device_*.png: real captures off a Flipper
├── screenshots/ # the six captures the Apps Catalog listing uses
├── docs/catalog/ # the prepared catalog manifest + how to submit
├── tools_check_layout.py # static overlap + clearance checker (CI-gated)
└── tools_gen_*.py # regenerate icons / mockups / banner / GIF
```
---
## Branding
**BACKLIGHT.** Definido em **Didot** para identidade, **Futura** para voz, **Andale Mono**
para cada valor medido. O laranja é `#FE8A2C` — *amostrado* de uma captura do qFlipper
deste app em execução, portanto é a própria luz de fundo do Flipper e não uma
cor escolhida para se parecer com ela. Cada captura em `screenshots/` tem exatamente duas
cores, `(254,138,44)` e `(0,0,0)`; é isso que o hardware emite.
Nunca é usado como cor de marca. **A única brasa em qualquer asset é luz que o
dispositivo realmente emitiu** — pixels dentro de uma captura real, colados intactos em uma
escala inteira. A arte é desenhada no mesmo tom quinze graus mais frio. Uma rampa,
lida de extremos opostos: **mais tinta significa mais sinal no papel, mais luz significa
mais sinal no preto** — porque o papel é onde uma varredura termina (Specter escreve um
logbook com timestamp que você pode entregar a alguém) e o preto é onde acontece
(o modo stealth força o desligamento da luz de fundo).
O acento desenha uma coisa e nada mais: **portadora medida.** Nunca é uma
régua, uma moldura, uma margem ou uma palavra — não há palavras douradas em lugar algum do
sistema, e o renderer levanta erro se uma for tentada. Então o banner carrega
exatamente um objeto na cor de acento, e esse objeto é uma medição.
A forma de onda são 128 colunas de portadora que o Specter gravou de um leitor de polling real
a 8 ms por coluna, extraídas de volta da captura de tela ao lado. O trecho plano
à esquerda é o buffer de traço antes de encher, não silêncio que alguém mediu. Seu
duty lê **28%** onde o próprio contador do dispositivo imprimiu **27%**, e ambos os
números estão no banner. A marca é um ciclo de poll a **30%** de duty — os 12 ms de 40 ms daquele
leitor, e também `SPECTER_FULL_SCALE_DUTY`, o duty no qual o
medidor lê 100%. Um número, duas razões independentes para ser ele.
`#FE8A2C` é a única cor aqui que não escolhemos.
| Asset | Tamanho | Onde vai |
|---|---|---|
| `images/banner.png` | 2560×800 | Cabeçalho do README, fundo de papel (2× para permanecer nítido em retina) |
| `images/banner-dark.png` | 2560×800 | O mesmo desenho em preto verdadeiro, servido por `<picture>` para leitores em modo escuro |
| `images/social-preview.png` | **1280×640** | **Settings → Social preview** — tamanho recomendado pelo GitHub (mín 640×320, limite de 1 MB) |
| `images/mark.png` | 512×512 | Marca quadrada do logo: posts sociais, slides, favicon. **Não é um avatar de repo** — o GitHub mostra a foto de perfil do *proprietário* ao lado de um repo, então não há avatar por repo para definir |
| `images/mark-180/64/32/16.png` | conforme nomeado | 180 e 64 reduzidos; **32 e 16 são desenhados nativamente** para que nada sofra anti-aliasing até virar borrão |
| `images/demo.gif` | 384×192 | Um passeio roteirizado por todos os modos, **gravado do dispositivo** — `tools_screenshot.py --tour-gif` |
| `images/splash.gif` | 384×192 | A intro de boot, gravada a partir da requisição de lançamento em diante — `--splash` |
| `images/screens.png` | — | Folha de contato das capturas, fundo claro, reconstruída por `--sheet` |
| `images/screens-dark.png` | — | A mesma folha em preto verdadeiro, servida por `<picture>` para leitores em modo escuro |
| `screenshots/*.png` | 512×256 | **Todas as telas, capturadas de um dispositivo real** via RPC. Exatamente duas cores: as do próprio painel. |```bash
python3 tools_brand_data.py # the facts the branding is allowed to state
python3 tools_gen_banner.py # banner (light + dark), social preview, logo mark
python3 tools_gen_icons.py # 1-bit Flipper icons
# these need a Flipper on USB (pip install pyserial)
python3 tools_screenshot.py --all # walk every screen and capture it
python3 tools_screenshot.py --reader # the shots that need a live reader
python3 tools_screenshot.py --splash # the boot intro
python3 tools_screenshot.py --tour-gif # one GIF of the app being used
```
> A pré-visualização social é o único recurso que o GitHub não consegue obter do repositório — ela
> precisa ser enviada manualmente uma vez em **Settings → Social preview**. É o que é renderizado
> quando o repositório é compartilhado no Slack, X, LinkedIn ou Discord.
---
## Créditos
- Criado por **[at0m-b0mb](https://github.com/at0m-b0mb)**.
- Parte de uma família de ferramentas de segurança para Flipper: **[Argus](https://github.com/at0m-b0mb/Argus-FlipperZero)** (watchdog de deauth Wi-Fi / evil-twin), **[GhostTag](https://github.com/at0m-b0mb/GhostTag-FlipperZero)** (caçador anti-stalking BLE) e **[Cerberus](https://github.com/at0m-b0mb/flipper-cerberus)** (watchdog de RF Sub-GHz).
- Desenvolvido com o [firmware do Flipper Zero](https://github.com/flipperdevices/flipperzero-firmware) NFC HAL (detecção de campo `furi_hal_nfc`) + [ufbt](https://github.com/flipperdevices/flipperzero-ufbt).
## Licença
[MIT](https://github.com/at0m-b0mb/specter-flipperzero/blob/main/LICENSE) © 2026 at0m-b0mb