Skip to content

Commit 47a502b

Browse files
authored
Merge pull request #36 from Leptopt1los/dev
NFC Magic update to 1.5
2 parents 5803cfe + 1316afb commit 47a502b

19 files changed

+742
-85
lines changed

base_pack/nfc_magic/application.fam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ App(
1010
],
1111
stack_size=4 * 1024,
1212
fap_description="Application for writing to NFC tags with modifiable sector 0",
13-
fap_version="1.4",
13+
fap_version="1.5",
1414
fap_icon="assets/Nfc_10px.png",
1515
fap_category="NFC",
1616
fap_private_libs=[

base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.c

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
#include "core/log.h"
21
#include "gen4_poller_i.h"
2+
#include "protocols/gen4/gen4_poller.h"
33
#include <nfc/protocols/iso14443_3a/iso14443_3a.h>
44
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
55
#include <nfc/helpers/nfc_util.h>
66
#include <nfc/nfc_poller.h>
77

8-
#include <furi/furi.h>
9-
108
#define GEN4_POLLER_THREAD_FLAG_DETECTED (1U << 0)
119

1210
typedef NfcCommand (*Gen4PollerStateHandler)(Gen4Poller* instance);
@@ -171,12 +169,16 @@ NfcCommand gen4_poller_request_mode_handler(Gen4Poller* instance) {
171169
instance->state = Gen4PollerStateRequestWriteData;
172170
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetPassword) {
173171
instance->state = Gen4PollerStateChangePassword;
174-
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDefaultCFG) {
172+
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDefaultCfg) {
175173
instance->state = Gen4PollerStateSetDefaultConfig;
176-
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetCFG) {
174+
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetCfg) {
177175
instance->state = Gen4PollerStateGetCurrentConfig;
178176
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeGetRevision) {
179177
instance->state = Gen4PollerStateGetRevision;
178+
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetShadowMode) {
179+
instance->state = Gen4PollerStateSetShadowMode;
180+
} else if(instance->gen4_event_data.request_mode.mode == Gen4PollerModeSetDirectWriteBlock0Mode) {
181+
instance->state = Gen4PollerStateSetDirectWriteBlock0;
180182
} else {
181183
instance->state = Gen4PollerStateFail;
182184
}
@@ -269,13 +271,13 @@ static NfcCommand gen4_poller_write_mf_classic(Gen4Poller* instance) {
269271
break;
270272
}
271273

272-
instance->config[6] = Gen4PollerShadowModeIgnore;
274+
instance->config[6] = Gen4PollerShadowModeDisabled;
273275
instance->config[24] = iso3_data->atqa[0];
274276
instance->config[25] = iso3_data->atqa[1];
275277
instance->config[26] = iso3_data->sak;
276278
instance->config[27] = 0x00;
277-
instance->config[28] = instance->total_blocks;
278-
instance->config[29] = 0x01;
279+
instance->config[28] = instance->total_blocks - 1;
280+
instance->config[29] = Gen4PollerDirectWriteBlock0ModeDisabled;
279281

280282
Gen4PollerError error = gen4_poller_set_config(
281283
instance, instance->password, instance->config, sizeof(instance->config), false);
@@ -348,13 +350,13 @@ static NfcCommand gen4_poller_write_mf_ultralight(Gen4Poller* instance) {
348350
break;
349351
}
350352

351-
instance->config[6] = Gen4PollerShadowModeHighSpeedIgnore;
353+
instance->config[6] = Gen4PollerShadowModeHighSpeedDisabled;
352354
instance->config[24] = iso3_data->atqa[0];
353355
instance->config[25] = iso3_data->atqa[1];
354356
instance->config[26] = iso3_data->sak;
355357
instance->config[27] = 0x00;
356-
instance->config[28] = instance->total_blocks;
357-
instance->config[29] = 0x01;
358+
instance->config[28] = instance->total_blocks - 1;
359+
instance->config[29] = Gen4PollerDirectWriteBlock0ModeDisabled;
358360

359361
Gen4PollerError error = gen4_poller_set_config(
360362
instance, instance->password, instance->config, sizeof(instance->config), false);
@@ -534,6 +536,44 @@ NfcCommand gen4_poller_get_revision_handler(Gen4Poller* instance) {
534536
return command;
535537
}
536538

539+
NfcCommand gen4_poller_set_shadow_mode_handler(Gen4Poller* instance) {
540+
NfcCommand command = NfcCommandContinue;
541+
542+
do {
543+
Gen4PollerError error =
544+
gen4_poller_set_shadow_mode(instance, instance->password, instance->shadow_mode);
545+
546+
if(error != Gen4PollerErrorNone) {
547+
FURI_LOG_E(TAG, "Failed to set shadow mode: %d", error);
548+
instance->state = Gen4PollerStateFail;
549+
break;
550+
}
551+
552+
instance->state = Gen4PollerStateSuccess;
553+
} while(false);
554+
555+
return command;
556+
}
557+
558+
NfcCommand gen4_poller_set_direct_write_block_0_mode_handler(Gen4Poller* instance) {
559+
NfcCommand command = NfcCommandContinue;
560+
561+
do {
562+
Gen4PollerError error = gen4_poller_set_direct_write_block_0_mode(
563+
instance, instance->password, instance->direct_write_block_0_mode);
564+
565+
if(error != Gen4PollerErrorNone) {
566+
FURI_LOG_E(TAG, "Failed to set direct write to block 0 mode: %d", error);
567+
instance->state = Gen4PollerStateFail;
568+
break;
569+
}
570+
571+
instance->state = Gen4PollerStateSuccess;
572+
} while(false);
573+
574+
return command;
575+
}
576+
537577
NfcCommand gen4_poller_success_handler(Gen4Poller* instance) {
538578
NfcCommand command = NfcCommandContinue;
539579

@@ -568,6 +608,8 @@ static const Gen4PollerStateHandler gen4_poller_state_handlers[Gen4PollerStateNu
568608
[Gen4PollerStateSetDefaultConfig] = gen4_poller_set_default_cfg_handler,
569609
[Gen4PollerStateGetCurrentConfig] = gen4_poller_get_current_cfg_handler,
570610
[Gen4PollerStateGetRevision] = gen4_poller_get_revision_handler,
611+
[Gen4PollerStateSetShadowMode] = gen4_poller_set_shadow_mode_handler,
612+
[Gen4PollerStateSetDirectWriteBlock0] = gen4_poller_set_direct_write_block_0_mode_handler,
571613
[Gen4PollerStateSuccess] = gen4_poller_success_handler,
572614
[Gen4PollerStateFail] = gen4_poller_fail_handler,
573615

base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ typedef enum {
3838
Gen4PollerModeWrite,
3939
Gen4PollerModeSetPassword,
4040

41-
Gen4PollerModeSetDefaultCFG,
42-
Gen4PollerModeGetCFG,
41+
Gen4PollerModeSetDefaultCfg,
42+
Gen4PollerModeGetCfg,
4343
Gen4PollerModeGetRevision,
44+
Gen4PollerModeSetShadowMode,
45+
Gen4PollerModeSetDirectWriteBlock0Mode
4446
} Gen4PollerMode;
4547

4648
typedef struct {

base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.c

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
#include "gen4_poller_i.h"
22

33
#include "bit_buffer.h"
4-
#include "core/log.h"
4+
#include "protocols/gen4/gen4_poller.h"
55
#include <nfc/protocols/iso14443_3a/iso14443_3a_poller.h>
66
#include <nfc/helpers/nfc_util.h>
77

88
#define GEN4_CMD_PREFIX (0xCF)
99

10+
#define GEN4_CMD_SET_SHD_MODE (0x32)
1011
#define GEN4_CMD_GET_CFG (0xC6)
1112
#define GEN4_CMD_GET_REVISION (0xCC)
1213
#define GEN4_CMD_WRITE (0xCD)
1314
#define GEN4_CMD_READ (0xCE)
15+
#define GEN4_CMD_SET_DW_BLOCK_0 (0xCF)
1416
#define GEN4_CMD_SET_CFG (0xF0)
1517
#define GEN4_CMD_FUSE_CFG (0xF1)
1618
#define GEN4_CMD_SET_PWD (0xFE)
1719

18-
#define CONFIG_SIZE (32)
20+
#define GEM4_RESPONSE_SUCCESS (0x02)
21+
22+
#define CONFIG_SIZE_MAX (32)
23+
#define CONFIG_SIZE_MIN (30)
1924
#define REVISION_SIZE (5)
2025

2126
static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
@@ -30,6 +35,80 @@ static Gen4PollerError gen4_poller_process_error(Iso14443_3aError error) {
3035
return ret;
3136
}
3237

38+
Gen4PollerError gen4_poller_set_shadow_mode(
39+
Gen4Poller* instance,
40+
uint32_t password,
41+
Gen4PollerShadowMode mode) {
42+
Gen4PollerError ret = Gen4PollerErrorNone;
43+
bit_buffer_reset(instance->tx_buffer);
44+
45+
do {
46+
uint8_t password_arr[4] = {};
47+
nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
48+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
49+
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
50+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_SHD_MODE);
51+
bit_buffer_append_byte(instance->tx_buffer, mode);
52+
53+
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
54+
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
55+
56+
if(error != Iso14443_3aErrorNone) {
57+
ret = gen4_poller_process_error(error);
58+
break;
59+
}
60+
61+
uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
62+
63+
FURI_LOG_D(TAG, "Card response: 0x%02X, Shadow mode set: 0x%02X", response, mode);
64+
65+
if(response != GEM4_RESPONSE_SUCCESS) {
66+
ret = Gen4PollerErrorProtocol;
67+
break;
68+
}
69+
70+
} while(false);
71+
72+
return ret;
73+
}
74+
75+
Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
76+
Gen4Poller* instance,
77+
uint32_t password,
78+
Gen4PollerDirectWriteBlock0Mode mode) {
79+
Gen4PollerError ret = Gen4PollerErrorNone;
80+
bit_buffer_reset(instance->tx_buffer);
81+
82+
do {
83+
uint8_t password_arr[4] = {};
84+
nfc_util_num2bytes(password, COUNT_OF(password_arr), password_arr);
85+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_PREFIX);
86+
bit_buffer_append_bytes(instance->tx_buffer, password_arr, COUNT_OF(password_arr));
87+
bit_buffer_append_byte(instance->tx_buffer, GEN4_CMD_SET_DW_BLOCK_0);
88+
bit_buffer_append_byte(instance->tx_buffer, mode);
89+
90+
Iso14443_3aError error = iso14443_3a_poller_send_standard_frame(
91+
instance->iso3_poller, instance->tx_buffer, instance->rx_buffer, GEN4_POLLER_MAX_FWT);
92+
93+
if(error != Iso14443_3aErrorNone) {
94+
ret = gen4_poller_process_error(error);
95+
break;
96+
}
97+
uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
98+
99+
FURI_LOG_D(
100+
TAG, "Card response: 0x%02X, Direct write to block 0 mode set: 0x%02X", response, mode);
101+
102+
if(response != GEM4_RESPONSE_SUCCESS) {
103+
ret = Gen4PollerErrorProtocol;
104+
break;
105+
}
106+
107+
} while(false);
108+
109+
return ret;
110+
}
111+
33112
Gen4PollerError
34113
gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result) {
35114
Gen4PollerError ret = Gen4PollerErrorNone;
@@ -52,11 +131,11 @@ Gen4PollerError
52131

53132
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
54133

55-
if(rx_bytes != CONFIG_SIZE) {
134+
if(rx_bytes != CONFIG_SIZE_MAX || rx_bytes != CONFIG_SIZE_MIN) {
56135
ret = Gen4PollerErrorProtocol;
57136
break;
58137
}
59-
bit_buffer_write_bytes(instance->rx_buffer, config_result, CONFIG_SIZE);
138+
bit_buffer_write_bytes(instance->rx_buffer, config_result, CONFIG_SIZE_MAX);
60139
} while(false);
61140

62141
return ret;
@@ -83,7 +162,7 @@ Gen4PollerError
83162
}
84163

85164
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
86-
if(rx_bytes != 5) {
165+
if(rx_bytes != REVISION_SIZE) {
87166
ret = Gen4PollerErrorProtocol;
88167
break;
89168
}
@@ -119,8 +198,11 @@ Gen4PollerError gen4_poller_set_config(
119198
break;
120199
}
121200

122-
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
123-
if(rx_bytes != 2) {
201+
uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
202+
203+
FURI_LOG_D(TAG, "Card response to set default config command: 0x%02X", response);
204+
205+
if(response != GEM4_RESPONSE_SUCCESS) {
124206
ret = Gen4PollerErrorProtocol;
125207
break;
126208
}
@@ -187,8 +269,16 @@ Gen4PollerError
187269
break;
188270
}
189271

190-
size_t rx_bytes = bit_buffer_get_size_bytes(instance->rx_buffer);
191-
if(rx_bytes != 2) {
272+
uint16_t response = bit_buffer_get_size_bytes(instance->rx_buffer);
273+
274+
FURI_LOG_D(
275+
TAG,
276+
"Trying to change password from 0x%08lX to 0x%08lX. Card response: 0x%02X",
277+
pwd_current,
278+
pwd_new,
279+
response);
280+
281+
if(response != GEM4_RESPONSE_SUCCESS) {
192282
ret = Gen4PollerErrorProtocol;
193283
break;
194284
}

base_pack/nfc_magic/lib/magic/protocols/gen4/gen4_poller_i.h

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,23 @@ typedef enum {
3636
Gen4PollerShadowModePreWrite = 0x00,
3737
// written data can be read once before restored to original
3838
Gen4PollerShadowModeRestore = 0x01,
39-
// written data is discarded
40-
Gen4PollerShadowModeIgnore = 0x02,
39+
// shadow mode disabled
40+
Gen4PollerShadowModeDisabled = 0x02,
4141
// apparently for UL?
42-
Gen4PollerShadowModeHighSpeedIgnore = 0x03
42+
Gen4PollerShadowModeHighSpeedDisabled = 0x03,
43+
// work with new UMC. With old UMC is untested
44+
Gen4PollerShadowModeSplit = 0x04,
4345
} Gen4PollerShadowMode;
4446

47+
typedef enum {
48+
// gen2 card behavour
49+
Gen4PollerDirectWriteBlock0ModeEnabled = 0x00,
50+
// common card behavour
51+
Gen4PollerDirectWriteBlock0ModeDisabled = 0x01,
52+
// default mode. same behavour as Gen4PollerDirectWriteBlock0ModeActivate
53+
Gen4PollerDirectWriteBlock0ModeDefault = 0x02,
54+
} Gen4PollerDirectWriteBlock0Mode;
55+
4556
typedef enum {
4657
Gen4PollerStateIdle,
4758
Gen4PollerStateRequestMode,
@@ -53,6 +64,8 @@ typedef enum {
5364
Gen4PollerStateSetDefaultConfig,
5465
Gen4PollerStateGetCurrentConfig,
5566
Gen4PollerStateGetRevision,
67+
Gen4PollerStateSetShadowMode,
68+
Gen4PollerStateSetDirectWriteBlock0,
5669

5770
Gen4PollerStateSuccess,
5871
Gen4PollerStateFail,
@@ -78,6 +91,9 @@ struct Gen4Poller {
7891

7992
uint8_t config[GEN4_POLLER_CONFIG_SIZE_MAX];
8093

94+
Gen4PollerShadowMode shadow_mode;
95+
Gen4PollerDirectWriteBlock0Mode direct_write_block_0_mode;
96+
8197
Gen4PollerEvent gen4_event;
8298
Gen4PollerEventData gen4_event_data;
8399

@@ -107,6 +123,14 @@ Gen4PollerError
107123
Gen4PollerError
108124
gen4_poller_get_config(Gen4Poller* instance, uint32_t password, uint8_t* config_result);
109125

126+
Gen4PollerError
127+
gen4_poller_set_shadow_mode(Gen4Poller* instance, uint32_t password, Gen4PollerShadowMode mode);
128+
129+
Gen4PollerError gen4_poller_set_direct_write_block_0_mode(
130+
Gen4Poller* instance,
131+
uint32_t password,
132+
Gen4PollerDirectWriteBlock0Mode mode);
133+
110134
#ifdef __cplusplus
111135
}
112136
#endif

base_pack/nfc_magic/scenes/nfc_magic_scene_config.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ ADD_SCENE(nfc_magic, magic_info, MagicInfo)
55
ADD_SCENE(nfc_magic, gen1_menu, Gen1Menu)
66
ADD_SCENE(nfc_magic, gen4_menu, Gen4Menu)
77
ADD_SCENE(nfc_magic, gen4_actions_menu, Gen4ActionsMenu)
8-
ADD_SCENE(nfc_magic, gen4_get_cfg, Gen4GetCFG)
9-
ADD_SCENE(nfc_magic, gen4_set_cfg, Gen4SetCFG)
8+
ADD_SCENE(nfc_magic, gen4_get_cfg, Gen4GetCfg)
9+
ADD_SCENE(nfc_magic, gen4_set_cfg, Gen4SetCfg)
1010
ADD_SCENE(nfc_magic, gen4_revision, Gen4Revision)
1111
ADD_SCENE(nfc_magic, gen4_show_rev, Gen4ShowRev)
12-
ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCFG)
12+
ADD_SCENE(nfc_magic, gen4_show_cfg, Gen4ShowCfg)
13+
ADD_SCENE(nfc_magic, gen4_select_shd_mode, Gen4SelectShdMode)
14+
ADD_SCENE(nfc_magic, gen4_set_shd_mode, Gen4SetShdMode)
15+
ADD_SCENE(nfc_magic, gen4_select_direct_write_block_0_mode, Gen4SelectDirectWriteBlock0Mode)
16+
ADD_SCENE(nfc_magic, gen4_set_direct_write_block_0_mode, Gen4SetDirectWriteBlock0Mode)
1317
ADD_SCENE(nfc_magic, gen4_fail, Gen4Fail)
1418
ADD_SCENE(nfc_magic, wipe, Wipe)
1519
ADD_SCENE(nfc_magic, wipe_fail, WipeFail)

0 commit comments

Comments
 (0)