added "Listen NfcV Reader" to sniff traffic from reader to card

This commit is contained in:
g3gg0.de
2023-01-21 01:04:02 +01:00
parent 4addd1fedc
commit 02e3a30f06
8 changed files with 365 additions and 1 deletions

View File

@@ -19,6 +19,7 @@ ADD_SCENE(nfc, nfcv_unlock_menu, NfcVUnlockMenu)
ADD_SCENE(nfc, nfcv_key_input, NfcVKeyInput)
ADD_SCENE(nfc, nfcv_unlock, NfcVUnlock)
ADD_SCENE(nfc, nfcv_emulate, NfcVEmulate)
ADD_SCENE(nfc, nfcv_sniff, NfcVSniff)
ADD_SCENE(nfc, mf_ultralight_read_success, MfUltralightReadSuccess)
ADD_SCENE(nfc, mf_ultralight_data, MfUltralightData)
ADD_SCENE(nfc, mf_ultralight_menu, MfUltralightMenu)

View File

@@ -5,6 +5,7 @@ enum SubmenuIndex {
SubmenuIndexMfClassicKeys,
SubmenuIndexMfUltralightUnlock,
SubmenuIndexNfcVUnlock,
SubmenuIndexNfcVSniff,
};
void nfc_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
@@ -41,6 +42,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
SubmenuIndexNfcVUnlock,
nfc_scene_extra_actions_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Listen NfcV Reader",
SubmenuIndexNfcVSniff,
nfc_scene_extra_actions_submenu_callback,
nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
@@ -66,6 +73,9 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubmenuIndexNfcVUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVUnlockMenu);
consumed = true;
} else if(event.event == SubmenuIndexNfcVSniff) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVSniff);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
}

View File

@@ -0,0 +1,155 @@
#include "../nfc_i.h"
#define NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX (200)
enum {
NfcSceneNfcVSniffStateWidget,
NfcSceneNfcVSniffStateTextBox,
};
bool nfc_scene_nfcv_sniff_worker_callback(NfcWorkerEvent event, void* context) {
UNUSED(event);
furi_assert(context);
Nfc* nfc = context;
switch(event) {
case NfcWorkerEventNfcVCommandExecuted:
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventUpdateLog);
break;
case NfcWorkerEventNfcVContentChanged:
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventSaveShadow);
break;
default:
break;
}
return true;
}
void nfc_scene_nfcv_sniff_widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
Nfc* nfc = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
}
void nfc_scene_nfcv_sniff_textbox_callback(void* context) {
furi_assert(context);
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit);
}
static void nfc_scene_nfcv_sniff_widget_config(Nfc* nfc, bool data_received) {
Widget* widget = nfc->widget;
widget_reset(widget);
FuriString* info_str;
info_str = furi_string_alloc();
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Listen NfcV");
furi_string_trim(info_str);
widget_add_text_box_element(
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
furi_string_free(info_str);
if(data_received) {
widget_add_button_element(
widget, GuiButtonTypeCenter, "Log", nfc_scene_nfcv_sniff_widget_callback, nfc);
}
}
void nfc_scene_nfcv_sniff_on_enter(void* context) {
Nfc* nfc = context;
// Setup Widget
nfc_scene_nfcv_sniff_widget_config(nfc, false);
// Setup TextBox
TextBox* text_box = nfc->text_box;
text_box_set_font(text_box, TextBoxFontHex);
text_box_set_focus(text_box, TextBoxFocusEnd);
text_box_set_text(text_box, "");
furi_string_reset(nfc->text_box_store);
// Set Widget state and view
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
// Start worker
memset(&nfc->dev->dev_data.reader_data, 0, sizeof(NfcReaderRequestData));
nfc_worker_start(
nfc->worker,
NfcWorkerStateNfcVSniff,
&nfc->dev->dev_data,
nfc_scene_nfcv_sniff_worker_callback,
nfc);
nfc_blink_emulate_start(nfc);
}
bool nfc_scene_nfcv_sniff_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
NfcVData* nfcv_data = &nfc->dev->dev_data.nfcv_data;
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneNfcVSniff);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventUpdateLog) {
// Add data button to widget if data is received for the first time
if(strlen(nfcv_data->last_command) > 0) {
if(!furi_string_size(nfc->text_box_store)) {
nfc_scene_nfcv_sniff_widget_config(nfc, true);
}
/* use the last n bytes from the log so there's enough space for the new log entry */
size_t maxSize =
NFC_SCENE_EMULATE_NFCV_LOG_SIZE_MAX - (strlen(nfcv_data->last_command) + 1);
if(furi_string_size(nfc->text_box_store) >= maxSize) {
furi_string_right(nfc->text_box_store, (strlen(nfcv_data->last_command) + 1));
}
furi_string_cat_printf(nfc->text_box_store, "%s", nfcv_data->last_command);
furi_string_push_back(nfc->text_box_store, '\n');
text_box_set_text(nfc->text_box, furi_string_get_cstr(nfc->text_box_store));
/* clear previously logged command */
strcpy(nfcv_data->last_command, "");
}
consumed = true;
} else if(event.event == NfcCustomEventSaveShadow) {
if(furi_string_size(nfc->dev->load_path)) {
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
}
consumed = true;
} else if(event.event == GuiButtonTypeCenter && state == NfcSceneNfcVSniffStateWidget) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateTextBox);
consumed = true;
} else if(event.event == NfcCustomEventViewExit && state == NfcSceneNfcVSniffStateTextBox) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state == NfcSceneNfcVSniffStateTextBox) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneNfcVSniff, NfcSceneNfcVSniffStateWidget);
consumed = true;
}
}
return consumed;
}
void nfc_scene_nfcv_sniff_on_exit(void* context) {
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
widget_reset(nfc->widget);
text_box_reset(nfc->text_box);
furi_string_reset(nfc->text_box_store);
nfc_blink_stop(nfc);
}

View File

@@ -885,6 +885,8 @@ static bool nfc_device_save_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
case NfcVTypeSlix2:
saved = nfc_device_save_slix2_data(file, dev);
break;
default:
break;
}
} while(false);
@@ -936,6 +938,8 @@ bool nfc_device_load_nfcv_data(FlipperFormat* file, NfcDevice* dev) {
case NfcVTypeSlix2:
parsed = nfc_device_load_slix2_data(file, dev);
break;
default:
break;
}
} while(false);

View File

@@ -111,6 +111,8 @@ int32_t nfc_worker_task(void* context) {
nfc_worker_analyze_reader(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateNfcVEmulate) {
nfc_worker_nfcv_emulate(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateNfcVSniff) {
nfc_worker_nfcv_sniff(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateNfcVUnlock) {
nfc_worker_nfcv_unlock(nfc_worker);
} else if(nfc_worker->state == NfcWorkerStateNfcVUnlockAndSave) {
@@ -180,6 +182,34 @@ void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker) {
}
}
void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker) {
FuriHalNfcTxRxContext tx_rx = {};
FuriHalNfcDevData* nfc_data = &nfc_worker->dev_data->nfc_data;
NfcVData* nfcv_data = &nfc_worker->dev_data->nfcv_data;
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
reader_analyzer_prepare_tx_rx(nfc_worker->reader_analyzer, &tx_rx, true);
reader_analyzer_start(nfc_worker->reader_analyzer, ReaderAnalyzerModeDebugLog);
}
nfcv_data->sub_type = NfcVTypeSniff;
nfcv_emu_init(nfc_data, nfcv_data);
while(nfc_worker->state == NfcWorkerStateNfcVSniff) {
if(nfcv_emu_loop(&tx_rx, nfc_data, nfcv_data, 100)) {
if(nfc_worker->callback) {
nfc_worker->callback(NfcWorkerEventNfcVCommandExecuted, nfc_worker->context);
}
}
furi_delay_ms(10);
}
nfcv_emu_deinit(nfcv_data);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
reader_analyzer_stop(nfc_worker->reader_analyzer);
}
}
void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker) {
furi_assert(nfc_worker);
furi_assert(nfc_worker->callback);

View File

@@ -21,6 +21,7 @@ typedef enum {
NfcWorkerStateNfcVEmulate,
NfcWorkerStateNfcVUnlock,
NfcWorkerStateNfcVUnlockAndSave,
NfcWorkerStateNfcVSniff,
// Debug
NfcWorkerStateEmulateApdu,
NfcWorkerStateField,
@@ -97,3 +98,4 @@ void nfc_worker_start(
void nfc_worker_stop(NfcWorker* nfc_worker);
void nfc_worker_nfcv_unlock(NfcWorker* nfc_worker);
void nfc_worker_nfcv_emulate(NfcWorker* nfc_worker);
void nfc_worker_nfcv_sniff(NfcWorker* nfc_worker);

View File

@@ -732,6 +732,160 @@ void nfcv_emu_handle_packet(
}
}
void nfcv_emu_sniff_packet(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
void* nfcv_data_in) {
furi_assert(tx_rx);
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
if(nfcv_data->frame_length < 2) {
return;
}
/* parse the frame data for the upcoming part 3 handling */
ctx->flags = nfcv_data->frame[0];
ctx->command = nfcv_data->frame[1];
ctx->selected = (ctx->flags & RFAL_NFCV_REQ_FLAG_SELECT);
ctx->addressed = !(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) &&
(ctx->flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
ctx->advanced = (ctx->command >= 0xA0);
ctx->address_offset = 2 + (ctx->advanced ? 1 : 0);
ctx->payload_offset = ctx->address_offset + (ctx->addressed ? 8 : 0);
char flags_string[5];
snprintf(
flags_string,
5,
"%c%c%c%d",
(ctx->flags & RFAL_NFCV_REQ_FLAG_INVENTORY) ?
'I' :
(ctx->addressed ? 'A' : (ctx->selected ? 'S' : '*')),
ctx->advanced ? 'X' : ' ',
(ctx->flags & RFAL_NFCV_REQ_FLAG_DATA_RATE) ? 'h' : 'l',
(ctx->flags & RFAL_NFCV_REQ_FLAG_SUB_CARRIER) ? 2 : 1);
switch(ctx->command) {
case ISO15693_INVENTORY: {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
break;
}
case ISO15693_STAYQUIET: {
snprintf(
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s STAYQUIET", flags_string);
nfcv_data->quiet = true;
break;
}
case ISO15693_LOCKBLOCK: {
uint8_t block = nfcv_data->frame[ctx->payload_offset];
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s LOCK %d",
flags_string,
block);
break;
}
case ISO15693_SELECT: {
snprintf(
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s SELECT", flags_string);
break;
}
case ISO15693_RESET_TO_READY: {
snprintf(
nfcv_data->last_command, sizeof(nfcv_data->last_command), "%s RESET", flags_string);
break;
}
case ISO15693_READ_MULTI_BLOCK:
case ISO15693_READBLOCK: {
uint8_t block = nfcv_data->frame[ctx->payload_offset];
uint8_t blocks = 1;
if(ctx->command == ISO15693_READ_MULTI_BLOCK) {
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
}
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s READ %d cnt: %d",
flags_string,
block,
blocks);
break;
}
case ISO15693_WRITE_MULTI_BLOCK:
case ISO15693_WRITEBLOCK: {
uint8_t block = nfcv_data->frame[ctx->payload_offset];
uint8_t blocks = 1;
uint8_t data_pos = 1;
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
data_pos++;
}
uint8_t* data = &nfcv_data->frame[ctx->payload_offset + data_pos];
if(ctx->command == ISO15693_WRITE_MULTI_BLOCK) {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s WRITE %d, cnd %d",
flags_string,
block,
blocks);
} else {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s WRITE %d %02X %02X %02X %02X",
flags_string,
block,
data[0],
data[1],
data[2],
data[3]);
}
break;
}
case ISO15693_GET_SYSTEM_INFO: {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s SYSTEMINFO",
flags_string);
break;
}
default:
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"%s unsupported: %02X",
flags_string,
ctx->command);
break;
}
if(strlen(nfcv_data->last_command) > 0) {
FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command);
}
}
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
furi_assert(nfc_data);
furi_assert(nfcv_data);
@@ -765,8 +919,12 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
/* if not set already, initialize the default protocol handler */
if(!nfcv_data->emu_protocol_ctx) {
nfcv_data->emu_protocol_ctx = malloc(sizeof(NfcVEmuProtocolCtx));
if(nfcv_data->sub_type == NfcVTypeSniff) {
nfcv_data->emu_protocol_handler = &nfcv_emu_sniff_packet;
} else {
nfcv_data->emu_protocol_handler = &nfcv_emu_handle_packet;
}
}
FURI_LOG_D(TAG, "Starting NfcV emulation");
FURI_LOG_D(
@@ -801,6 +959,9 @@ void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
case NfcVTypePlain:
FURI_LOG_D(TAG, " Card type: Plain");
break;
case NfcVTypeSniff:
FURI_LOG_D(TAG, " Card type: Sniffing");
break;
}
/* allocate a 512 edge buffer, more than enough */

View File

@@ -96,6 +96,7 @@ typedef enum {
NfcVTypeSlixS = 2,
NfcVTypeSlixL = 3,
NfcVTypeSlix2 = 4,
NfcVTypeSniff = 255,
} NfcVSubtype;
typedef enum {