Skip to content

Commit bb0110d

Browse files
Add new RFID scan and attack features for ChameleonUltra
Introduces support for EMV, DESFire, NTAG brute-force, NDEF URI generation, FDX-B, Indala, and T5577 brute-force in firmware and CLI. Adds new source files for RFID protocols and utilities, updates Makefile to include new modules, and extends command definitions and CLI units to expose these features. This enhances the device's capability to scan, attack, and interact with a wider range of RFID tags. (Nah, for real; i tried my best, but is harf af to obtain an asnwer from android google walllet thing.... idk how BRUCE OS manages to event get the cards issuer) *dont add tis crap ;( (still)
1 parent 97dfe5b commit bb0110d

24 files changed

+1042
-0
lines changed

build_dev.ps1

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<#
2+
.SYNOPSIS
3+
Compila el firmware de ChameleonUltra (Application) y genera el paquete DFU.
4+
5+
.DESCRIPTION
6+
Este script configura el entorno (PATH) para usar el compilador ARM descargado localmente
7+
y las utilidades de Git, compila el código fuente en firmware/application usando 'make',
8+
y finalmente empaqueta el resultado en un archivo .zip usando 'nrfutil'.
9+
10+
.NOTES
11+
Requisitos:
12+
- Carpeta 'tools' con 'arm-toolchain' y 'nrfutil.exe' en la raíz del repo.
13+
- Git instalado (para utilidades Unix como mkdir, rm).
14+
- 'make' instalado (vía Scoop o Choco).
15+
#>
16+
17+
$ErrorActionPreference = "Stop"
18+
19+
# --- Configuración de Rutas ---
20+
$ScriptDir = $PSScriptRoot
21+
$ToolsDir = Join-Path $ScriptDir "tools"
22+
$FirmwareDir = Join-Path $ScriptDir "firmware"
23+
$AppDir = Join-Path $FirmwareDir "application"
24+
$ObjDir = Join-Path $FirmwareDir "objects"
25+
26+
# Rutas específicas de herramientas
27+
# Ajusta la versión del toolchain si cambia la carpeta descomprimida
28+
$ArmBin = Join-Path $ToolsDir "arm-toolchain\arm-gnu-toolchain-12.2.rel1-mingw-w64-i686-arm-none-eabi\bin"
29+
$NrfUtil = Join-Path $ToolsDir "nrfutil.exe"
30+
$GitBin = "C:\Program Files\Git\usr\bin" # Necesario para comandos unix dentro del Makefile
31+
$DfuKey = Join-Path $ScriptDir "resource\dfu_key\chameleon.pem"
32+
33+
# --- Verificaciones ---
34+
Write-Host "Verificando herramientas..." -ForegroundColor Cyan
35+
36+
if (-not (Test-Path "$ArmBin\arm-none-eabi-gcc.exe")) {
37+
Write-Error "No se encontró el compilador ARM en: $ArmBin"
38+
exit 1
39+
}
40+
41+
if (-not (Test-Path $NrfUtil)) {
42+
Write-Error "No se encontró nrfutil en: $NrfUtil"
43+
exit 1
44+
}
45+
46+
# --- Configurar Entorno ---
47+
Write-Host "Configurando entorno de compilación..."
48+
# Añadimos ARM y Git/usr/bin al inicio del PATH
49+
$env:PATH = "$ArmBin;$GitBin;$env:PATH"
50+
51+
# --- Compilar Aplicación ---
52+
Write-Host "Compilando Aplicación (Make)..." -ForegroundColor Cyan
53+
Push-Location $AppDir
54+
55+
try {
56+
# Ejecutamos make. '-j' usa todos los núcleos para ir rápido.
57+
make -j
58+
if ($LASTEXITCODE -ne 0) { throw "Error en la compilación." }
59+
}
60+
finally {
61+
Pop-Location
62+
}
63+
64+
# --- Generar Paquete DFU ---
65+
Write-Host "Generando paquete DFU (ZIP)..." -ForegroundColor Cyan
66+
67+
# Asegurar que existe directorio objects
68+
if (-not (Test-Path $ObjDir)) { New-Item -ItemType Directory -Path $ObjDir | Out-Null }
69+
70+
$AppHex = Join-Path $ObjDir "application.hex"
71+
$OutputZip = Join-Path $ObjDir "ultra-dfu-app.zip"
72+
73+
if (-not (Test-Path $AppHex)) {
74+
Write-Error "No se encontró el archivo compilado: $AppHex"
75+
exit 1
76+
}
77+
78+
# Comando nrfutil para generar el paquete de actualización
79+
& $NrfUtil pkg generate --hw-version 0 `
80+
--key-file $DfuKey `
81+
--application $AppHex `
82+
--application-version 1 `
83+
--sd-req 0x0100 `
84+
$OutputZip
85+
86+
if ($LASTEXITCODE -eq 0) {
87+
Write-Host "`n---------------------------------------------------" -ForegroundColor Green
88+
Write-Host "¡ÉXITO! Firmware compilado y empaquetado." -ForegroundColor Green
89+
Write-Host "Archivo listo para flashear: $OutputZip" -ForegroundColor Yellow
90+
Write-Host "---------------------------------------------------"
91+
} else {
92+
Write-Error "Falló la generación del paquete DFU."
93+
}

firmware/application/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ SRC_FILES += \
4141
$(PROJ_DIR)/utils/dataframe.c \
4242
$(PROJ_DIR)/utils/delayed_reset.c \
4343
$(PROJ_DIR)/utils/fds_util.c \
44+
$(PROJ_DIR)/utils/ndef_gen.c \
4445
$(PROJ_DIR)/utils/syssleep.c \
4546
$(PROJ_DIR)/utils/timeslot.c \
4647
$(SDK_ROOT)/modules/nrfx/mdk/gcc_startup_nrf52840.S \
@@ -336,6 +337,11 @@ LIB_FILES += \
336337
ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
337338
# Append reader module source code to compile list.
338339
SRC_FILES +=\
340+
$(PROJ_DIR)/rfid/emv.c \
341+
$(PROJ_DIR)/rfid/desfire.c \
342+
$(PROJ_DIR)/rfid/ntag_attack.c \
343+
$(PROJ_DIR)/rfid/t5577_brute.c \
344+
$(PROJ_DIR)/rfid/reader/hf/iso14443_4_transceiver.c \
339345
$(PROJ_DIR)/rfid/reader/hf/mf1_toolbox.c \
340346
$(PROJ_DIR)/rfid/reader/hf/rc522.c \
341347
$(PROJ_DIR)/rfid/reader/lf/lf_125khz_radio.c \
@@ -345,6 +351,8 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
345351
$(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \
346352
$(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \
347353
$(PROJ_DIR)/rfid/reader/lf/lf_viking_data.c \
354+
$(PROJ_DIR)/rfid/reader/lf/fdx_b.c \
355+
$(PROJ_DIR)/rfid/reader/lf/indala.c \
348356

349357
INC_FOLDERS +=\
350358
${PROJ_DIR}/rfid/reader/ \

firmware/application/src/app_cmd.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
#include "settings.h"
1515
#include "delayed_reset.h"
1616
#include "netdata.h"
17+
#include "emv.h"
18+
#include "desfire.h"
19+
#include "ntag_attack.h"
20+
#include "ndef_gen.h"
21+
#include "fdx_b.h"
22+
#include "indala.h"
23+
#include "t5577_brute.h"
1724

1825

1926
#define NRF_LOG_MODULE_NAME app_cmd
@@ -490,6 +497,73 @@ static data_frame_tx_t *cmd_processor_mf1_write_one_block(uint16_t cmd, uint16_t
490497

491498
#if defined(PROJECT_CHAMELEON_ULTRA)
492499

500+
static data_frame_tx_t *cmd_processor_hf14a_scan_emv(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
501+
char buffer[128];
502+
bool result = emv_scan(buffer, sizeof(buffer));
503+
uint16_t len = strlen(buffer);
504+
if (result) {
505+
return data_frame_make(cmd, STATUS_HF_TAG_OK, len, (uint8_t *)buffer);
506+
} else {
507+
return data_frame_make(cmd, STATUS_HF_ERR_STAT, len, (uint8_t *)buffer);
508+
}
509+
}
510+
511+
static data_frame_tx_t *cmd_processor_hf_desfire_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
512+
char buffer[128];
513+
bool result = desfire_scan(buffer, sizeof(buffer));
514+
uint16_t len = strlen(buffer);
515+
if (result) {
516+
return data_frame_make(cmd, STATUS_HF_TAG_OK, len, (uint8_t *)buffer);
517+
} else {
518+
return data_frame_make(cmd, STATUS_HF_ERR_STAT, len, (uint8_t *)buffer);
519+
}
520+
}
521+
522+
static data_frame_tx_t *cmd_processor_hf_ntag_brute(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
523+
char buffer[128];
524+
bool result = ntag_attack_run(buffer, sizeof(buffer));
525+
uint16_t len = strlen(buffer);
526+
if (result) {
527+
return data_frame_make(cmd, STATUS_HF_TAG_OK, len, (uint8_t *)buffer);
528+
} else {
529+
return data_frame_make(cmd, STATUS_HF_ERR_STAT, len, (uint8_t *)buffer);
530+
}
531+
}
532+
533+
static data_frame_tx_t *cmd_processor_hf_ndef_gen_uri(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
534+
// Input: URI String
535+
if (length == 0) return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
536+
537+
char uri[128] = {0};
538+
memcpy(uri, data, length < 127 ? length : 127);
539+
540+
uint8_t buffer[256];
541+
uint16_t gen_len = ndef_gen_uri(buffer, sizeof(buffer), uri);
542+
543+
return data_frame_make(cmd, STATUS_SUCCESS, gen_len, buffer);
544+
}
545+
546+
static data_frame_tx_t *cmd_processor_lf_fdxb_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
547+
char buffer[128];
548+
bool result = fdx_b_scan(buffer, sizeof(buffer));
549+
uint16_t len = strlen(buffer);
550+
return data_frame_make(cmd, result ? STATUS_LF_TAG_OK : STATUS_LF_TAG_NO_FOUND, len, (uint8_t *)buffer);
551+
}
552+
553+
static data_frame_tx_t *cmd_processor_lf_indala_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
554+
char buffer[128];
555+
bool result = indala_scan(buffer, sizeof(buffer));
556+
uint16_t len = strlen(buffer);
557+
return data_frame_make(cmd, result ? STATUS_LF_TAG_OK : STATUS_LF_TAG_NO_FOUND, len, (uint8_t *)buffer);
558+
}
559+
560+
static data_frame_tx_t *cmd_processor_lf_t5577_brute(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
561+
char buffer[128];
562+
bool result = t5577_brute_run(buffer, sizeof(buffer));
563+
uint16_t len = strlen(buffer);
564+
return data_frame_make(cmd, result ? STATUS_LF_TAG_OK : STATUS_LF_TAG_NO_FOUND, len, (uint8_t *)buffer);
565+
}
566+
493567
static data_frame_tx_t *cmd_processor_hf14a_set_field_on(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
494568
device_mode_t mode = get_device_mode();
495569
if (mode != DEVICE_MODE_READER) {
@@ -1599,13 +1673,20 @@ static cmd_data_map_t m_data_cmd_map[] = {
15991673
{ DATA_CMD_MF1_CHECK_KEYS_OF_SECTORS, before_hf_reader_run, cmd_processor_mf1_check_keys_of_sectors, after_hf_reader_run },
16001674
{ DATA_CMD_MF1_HARDNESTED_ACQUIRE, before_hf_reader_run, cmd_processor_mf1_hardnested_nonces_acquire, after_hf_reader_run },
16011675
{ DATA_CMD_MF1_CHECK_KEYS_ON_BLOCK, before_hf_reader_run, cmd_processor_mf1_check_keys_on_block, after_hf_reader_run },
1676+
{ DATA_CMD_HF14A_SCAN_EMV, before_hf_reader_run, cmd_processor_hf14a_scan_emv, after_hf_reader_run },
1677+
{ DATA_CMD_HF_DESFIRE_SCAN, before_hf_reader_run, cmd_processor_hf_desfire_scan, after_hf_reader_run },
1678+
{ DATA_CMD_HF_NTAG_BRUTE, before_hf_reader_run, cmd_processor_hf_ntag_brute, after_hf_reader_run },
1679+
{ DATA_CMD_HF_NDEF_GEN_URI, NULL, cmd_processor_hf_ndef_gen_uri, NULL },
16021680

16031681
{ DATA_CMD_EM410X_SCAN, before_reader_run, cmd_processor_em410x_scan, NULL },
16041682
{ DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55xx, NULL },
16051683
{ DATA_CMD_HIDPROX_SCAN, before_reader_run, cmd_processor_hidprox_scan, NULL },
16061684
{ DATA_CMD_HIDPROX_WRITE_TO_T55XX, before_reader_run, cmd_processor_hidprox_write_to_t55xx, NULL },
16071685
{ DATA_CMD_VIKING_SCAN, before_reader_run, cmd_processor_viking_scan, NULL },
16081686
{ DATA_CMD_VIKING_WRITE_TO_T55XX, before_reader_run, cmd_processor_viking_write_to_t55xx, NULL },
1687+
{ DATA_CMD_LF_FDXB_SCAN, before_reader_run, cmd_processor_lf_fdxb_scan, NULL },
1688+
{ DATA_CMD_LF_INDALA_SCAN, before_reader_run, cmd_processor_lf_indala_scan, NULL },
1689+
{ DATA_CMD_LF_T5577_BRUTE, before_reader_run, cmd_processor_lf_t5577_brute, NULL },
16091690

16101691
{ DATA_CMD_HF14A_SET_FIELD_ON, before_reader_run, cmd_processor_hf14a_set_field_on, NULL },
16111692
{ DATA_CMD_HF14A_SET_FIELD_OFF, before_reader_run, cmd_processor_hf14a_set_field_off, NULL },

firmware/application/src/data_cmd.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
#define DATA_CMD_MF1_HARDNESTED_ACQUIRE (2013)
7373
#define DATA_CMD_MF1_ENC_NESTED_ACQUIRE (2014)
7474
#define DATA_CMD_MF1_CHECK_KEYS_ON_BLOCK (2015)
75+
#define DATA_CMD_HF14A_SCAN_EMV (2016)
76+
#define DATA_CMD_HF_DESFIRE_SCAN (2017)
77+
#define DATA_CMD_HF_NTAG_BRUTE (2018)
78+
#define DATA_CMD_HF_NDEF_GEN_URI (2019)
7579

7680
#define DATA_CMD_HF14A_SET_FIELD_ON (2100)
7781
#define DATA_CMD_HF14A_SET_FIELD_OFF (2101)
@@ -91,6 +95,9 @@
9195
#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003)
9296
#define DATA_CMD_VIKING_SCAN (3004)
9397
#define DATA_CMD_VIKING_WRITE_TO_T55XX (3005)
98+
#define DATA_CMD_LF_FDXB_SCAN (3006)
99+
#define DATA_CMD_LF_INDALA_SCAN (3007)
100+
#define DATA_CMD_LF_T5577_BRUTE (3008)
94101

95102
//
96103
// ******************************************************************
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#include "desfire.h"
2+
#include "rc522.h"
3+
#include "iso14443_4_transceiver.h"
4+
#include "rfid_main.h"
5+
#include <stdio.h>
6+
#include <string.h>
7+
8+
bool desfire_scan(char *out_buffer, uint16_t max_len) {
9+
picc_14a_tag_t tag;
10+
uint8_t status;
11+
uint8_t tx_buf[64];
12+
uint8_t rx_buf[256];
13+
uint16_t rx_len;
14+
15+
out_buffer[0] = '\0';
16+
17+
// Increase timeout
18+
pcd_14a_reader_timeout_set(500);
19+
20+
// 1. Scan for card
21+
status = pcd_14a_reader_scan_auto(&tag);
22+
if (status != STATUS_HF_TAG_OK) {
23+
snprintf(out_buffer, max_len, "No Card");
24+
return false;
25+
}
26+
27+
if (tag.ats_len == 0) {
28+
snprintf(out_buffer, max_len, "Not DESFire (No ATS)");
29+
return false;
30+
}
31+
32+
iso14443_4_reset_block_num();
33+
34+
// 2. Get Version (0x60)
35+
tx_buf[0] = 0x60;
36+
37+
if (iso14443_4_transceive(tx_buf, 1, rx_buf, &rx_len, sizeof(rx_buf))) {
38+
// DESFire returns version in 3 frames usually (AF -> AF -> 00)
39+
// Frame 1: HW Vendor, Type, Subtype, Version, Storage
40+
if (rx_len > 0) {
41+
uint8_t vendor = rx_buf[0];
42+
uint8_t type = rx_buf[1];
43+
uint8_t storage = rx_buf[5]; // 16=2k, 18=4k, 1A=8k usually (approx)
44+
45+
char type_str[20] = "Unknown";
46+
if (type == 0x81) strcpy(type_str, "DESFire EV1");
47+
else if (type == 0x82) strcpy(type_str, "DESFire EV2");
48+
else if (type == 0x83) strcpy(type_str, "DESFire EV3");
49+
else if (type == 0x88) strcpy(type_str, "DESFire Light");
50+
51+
snprintf(out_buffer, max_len, "%s (0x%02X), V:0x%02X, S:0x%02X", type_str, type, vendor, storage);
52+
53+
// Get more frames if status is 0xAF (More Data)
54+
// We can stop here for basic info
55+
}
56+
} else {
57+
snprintf(out_buffer, max_len, "GetVersion Failed");
58+
return false;
59+
}
60+
61+
// 3. Get Application IDs (0x6A)
62+
tx_buf[0] = 0x6A;
63+
if (iso14443_4_transceive(tx_buf, 1, rx_buf, &rx_len, sizeof(rx_buf))) {
64+
if (rx_len > 0 && rx_buf[rx_len-1] == 0x00) { // Success
65+
int apps = (rx_len - 1) / 3;
66+
char temp[32];
67+
snprintf(temp, sizeof(temp), ", Apps: %d", apps);
68+
strncat(out_buffer, temp, max_len - strlen(out_buffer) - 1);
69+
70+
if (apps > 0) {
71+
strncat(out_buffer, " [", max_len - strlen(out_buffer) - 1);
72+
for (int i=0; i<apps && i<3; i++) { // Show first 3
73+
uint32_t aid = (rx_buf[i*3] << 16) | (rx_buf[i*3+1] << 8) | rx_buf[i*3+2];
74+
snprintf(temp, sizeof(temp), "%06lX ", (unsigned long)aid);
75+
strncat(out_buffer, temp, max_len - strlen(out_buffer) - 1);
76+
}
77+
strncat(out_buffer, "]", max_len - strlen(out_buffer) - 1);
78+
}
79+
}
80+
}
81+
82+
return true;
83+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef DESFIRE_H
2+
#define DESFIRE_H
3+
4+
#include <stdint.h>
5+
#include <stdbool.h>
6+
7+
bool desfire_scan(char *buffer, uint16_t max_len);
8+
9+
#endif

0 commit comments

Comments
 (0)