# Análise estática do APK `NFCLocator-.apk`

**Data:** 2026-10-30 · **Analista:** Hermes (agente) · **Escopo:** análise estática; o APK **não foi executado**.

---

## 1. Identificação do artefato

| Campo | Valor |
|---|---|
| Arquivo original | `C:\Users\ADM\Downloads\NFCLocator-.apk` (preservado, não modificado) |
| Tamanho | 3.770.889 bytes |
| SHA-256 | `21ccef318fed2f2013fda52603a0d3473aba1b75b8dcf0ce46f98460de98d205` |
| Cópia de trabalho | `analise-apk/NFCLocator-analysis.apk` (mesmo SHA-256) |
| `applicationId` (manifest) | **`com.banking.trackerpro`** |
| Namespace das classes / resource package | **`app.nfcsecurity.vault`** |
| Nome exibido | **Nfc Security** (`@string/app_name`) |
| versionName / versionCode | `7.28.82` / `431870` |
| minSdk / targetSdk / compileSdk | 24 / 34 / 34 |
| Conteúdo | 728 entradas, 1 `classes.dex`, `resources.arsc` 937.140 B, **sem** `lib/`, **sem** OBB, **sem** split APK |
| Assinatura | v1 + v2 + v3, 1 signer, certificado **autoassinado** `CN=Android, OU=Mobile, O=Local, L=City, ST=SP, C=BR` (RSA-2048/SHA-256, SHA-256 `06c08cb7e562e94f3e3a07325f26d47f4de3ffc08b6b1725f01c799deb227fdc`) |

**Três identidades divergentes no mesmo APK** (`com.banking.trackerpro`, `app.nfcsecurity.vault`, rótulo "Nfc Security")
somadas ao nome do arquivo (`NFCLocator-`) são evidência de **repackaging/rebranding** de um app de terceiros —
não de um aplicativo bancário legítimo.

---

## 2. O que este APK é (conclusão principal)

> **É um cliente de relay NFC/EMV.** Ele conecta um **cartão bancário físico** (chip, `IsoDep`) a um **servidor remoto
> via WebSocket**, repassando APDUs nos dois sentidos, e ainda **captura o PIN digitado em uma página web** e o envia
> pelo mesmo canal. Os dados do cartão não são processados localmente: o servidor remoto comanda o chip.

Evidências diretas (arquivo → classe → método):

1. `decompilado/jadx/sources/app/nfcsecurity/vault/ReFragment.java:172-189` — `lambda$handleTagData$10`:
   `isoDep.transceive(bArr)` com o comando recebido do servidor, e `serviceClient.sendResponse(...)` devolvendo a resposta do cartão.
2. `decompilado/jadx/sources/defpackage/vn9w9z8k.java:onMessage` — escuta `{"direction":"request","data":"<APDU hex>"}` e entrega ao consumidor que fala com o cartão.
3. `decompilado/jadx/sources/defpackage/vo5bwh.java` — cliente WebSocket (`wss://…/ws-relay`) que, ao abrir, envia
   `{role:"IsoDep", deviceReady:…, id:<sessão>}` e passa a mandar `{type:"deviceStatus"}`, `{type:"pin", pin:…}` e
   `{direction:"response", data:<APDU hex>}`.
4. `decompilado/jadx/sources/defpackage/bd.java:injectJavascript` — injeta JavaScript em **toda página carregada** que
   lê `window.currentPin` / botão `submitBtn` (PIN de 4 ou 6 dígitos) e chama `window.Android.onDocumentLoaded(url?pin=…)`.
5. `decompilado/jadx/sources/defpackage/cd.java` — a ponte `@JavascriptInterface "Android"` extrai `pin=` da URL e chama
   `serviceClient.sendPin(pin)` → **o PIN sai do aparelho pelo WebSocket**.
6. `decompilado/jadx/sources/app/nfcsecurity/vault/MainActivity.java` — variante com utilitários de manipulação de APDU:
   `injectTrack2Data()` (substitui a tag EMV `0x57` por dados Track-2 injetados), `modifyCtqForPinBypass()`
   (troca `9F6B` → `02 80`, *Card Transaction Qualifiers*, típico de tentativa de **bypass de CVM/PIN**),
   `modifyAidToVisa()` (stub), `isGenerateAcResponse()` (passthrough). `ACCEPT_ANY_AID = true`.

**Fluxo observado:** WebView com página de "leitura de cartão" → cartão aproximado → APDUs vão e voltam do servidor →
a página pede o PIN → PIN é exfiltrado. A vítima vê uma interface de "verificação de segurança"; o atacante opera o
cartão em tempo real do outro lado.

> Classificação: **relay de cartão presencial com captura de PIN** (padrão "GhostTap"/relay-NFC de fraude), com
> elementos de *PIN bypass* (`9F6B`). Trate como **artefato malicioso**. Detalhes em `telas-e-fluxos.md` e `api-e-integracoes.md`.

---

## 3. Números da análise

| Métrica | Valor | Fonte |
|---|---|---|
| Classes no DEX (`class_defs_size`) | **3.287** | cabeçalho DEX (`dexdump`/parse) |
| Strings / tipos / métodos no DEX | 21.858 / 4.229 / 27.619 | cabeçalho DEX |
| Classes carregadas pelo engine JADX | 3.036 | `evidencias/rea-inspect-android-package.json` |
| Arquivos `.java` gerados pelo JADX | 3.028 (7 erros de decompilação) | `evidencias/jadx-decompile.log` |
| Classes em pacote default (ofuscadas) | 2.608 | `estrutura.md` |
| Bibliotecas reconhecíveis | okhttp3 131, androidx 111, com.google 90, okio 50, org.json 22 | idem |
| Recursos | 728 arquivos, 110 locales | `evidencias/tree-apk.txt` |

---

## 4. Como navegar

| Arquivo | Conteúdo |
|---|---|
| `progresso.md` | o que foi feito, o que não foi e por quê (retomada) |
| `estrutura.md` | árvore de arquivos, pacotes, arquitetura e diagramas Mermaid |
| `componentes-android.md` | manifest completo, permissões, componentes, exportação, assinatura |
| `telas-e-fluxos.md` | telas, layouts, textos, fluxos (comprovado × inferido) |
| `api-e-integracoes.md` | domínios, endpoints, contrato WebSocket, ausência de autenticação |
| `armazenamento.md` | persistência, WebView DOM Storage, assets binários |
| `dependencias.md` | frameworks, versões, obfuscação |
| `limitacoes.md` | lacunas, o que não pôde ser analisado, ferramentas ausentes |
| `inventario.csv` | componentes e arquivos relevantes, um por linha |
| `evidencias/` | saídas brutas das ferramentas (JSON do REA, logs, listagens, árvore) |
| `extraido/` | conteúdo do APK extraído sem decodificação (manifest binário, dex, arsc, assets, res/, META-INF/) |
| `decompilado/apktool/` | recursos decodificados + `smali/` |
| `decompilado/jadx/` | código decompilado para Java |
| `projeto-reconstruido/` | APK **recompilado e assinado** a partir do material recuperado (ver §5) |
| `tools/` | scripts de apoio usados na análise (`reach.py`, `smali_reach.py`) |

---

## 5. Reconstrução — resultado real

O material recuperado foi **recompilado de verdade** com `apktool b` (smali + recursos) e **assinado** com uma chave
gerada localmente para esta análise:

```
projeto-reconstruido/NFCLocator-rebuilt-unsigned.apk   3.668.797 B
projeto-reconstruido/NFCLocator-rebuilt-signed.apk     (apksigner verify => OK)
```

Verificação de fidelidade após o round-trip:

| Item | Original | Recompilado | Situação |
|---|---|---|---|
| `resources.arsc` | 937.140 B | 937.140 B | **byte-idêntico (SHA-256 igual)** |
| `classes.dex` class_defs | 3.287 | 3.287 | igual |
| `classes.dex` métodos / strings / tipos | 27.619 / 21.858 / 4.229 | idem | igual |
| `classes.dex` bytes | 3.597.808 | 3.460.208 | **diferente** (re-encodamento smali: SHA-256 diverge) |
| `AndroidManifest.xml` (binário) | 6.984 B | 6.984 B | mesmo tamanho, **não byte-idêntico** |
| nº de entradas | 728 | 728 | igual |

**Não foi produzido um projeto Gradle compilável** — e isso não é uma promessa vaga: veja o motivo técnico e o que
faltaria em `limitacoes.md` §"Projeto compilável". O que existe é a **recompilação do material recuperado**
(smali + recursos), não código-fonte original.

---

## 6. Proxy e limpeza

- Proxy HTTP configurado **apenas para as requisições necessárias à análise** (download de JADX/Apktool/JAR do motor JADX).
- IP de saída observado: **148.227.87.37** — São Paulo/SP, Brasil — AS14593 (Starlink). Ver `evidencias/proxy-validacao.txt`.
- Credenciais do proxy **não foram gravadas** neste projeto, nem em relatórios, nem em logs (mascaradas nas saídas);
  a configuração temporária (arquivo de ambiente fora do projeto) foi **removida ao final**.
- Nenhuma chamada foi feita a `dashboard.gripe`, `cupworldcup.site` ou qualquer endpoint do aplicativo.
- Recomendação: **revogar/rotacionar** as credenciais do proxy, já que foram transmitidas nesta sessão.
- Observação operacional: para habilitar as ferramentas Android do REA também foi apontada a variável
  `mcp_servers.rea.env.REA_JADX_MCP_JAR` no `config.yaml` do Hermes (caminho de JAR local, sem segredo).

---

## 7. Publicação (relatório navegável)

Site estático gerado por `tools/build_site.py` (`site/`, self-contained: CSS e **Mermaid embutidos**, sem CDN)
e publicado em VPS própria com nginx + TLS Let's Encrypt + HTTP Basic Auth:

```
https://185.95.159.46.sslip.io/          (usuário: analise)
|-- /srv/analise-site                    site estático
|-- /etc/nginx/sites-available/analise.conf
|-- TLS: Let's Encrypt, CN=185.95.159.46.sslip.io (renovação por certbot.timer)
```

- Conteúdo servido: **apenas documentação e evidências** (HTML, CSV, JSON, logs). Os binários do APK
  **não** estão no site (`/*.apk` → 404).
- Verificado de fora: `401` sem credencial, `200` com credencial, `301` de HTTP para HTTPS,
  páginas e assets com tamanho correto (`mermaid.min.js` 3.335.717 B), CSP restrita a `'self'`.
- Deploy reproduzível: `bash deploy/scripts/package.sh` → `scp` do pacote → `deploy/scripts/install-debian.sh`
  (idempotente; não refaz certificado nem senha se já existirem).
- Para regerar o site após editar os markdown: `python tools/build_site.py`.
- Servidor local de apoio (teste): `python tools/serve.py --host 127.0.0.1 --port 8899`.
