From dc28a82b19bd2687ae49fbc1c23f1a48823c89ca Mon Sep 17 00:00:00 2001 From: Foxushka <135865149+Foxushka@users.noreply.github.com> Date: Sun, 10 Aug 2025 21:39:08 +0300 Subject: [PATCH] Mifare Ultralight key logger from reader --- firmware/application/src/app_cmd.c | 95 +++++++++++++++---- firmware/application/src/data_cmd.h | 5 + .../src/rfid/nfctag/hf/nfc_mf0_ntag.c | 38 ++++++++ .../src/rfid/nfctag/hf/nfc_mf0_ntag.h | 15 ++- .../application/src/rfid/nfctag/hf/nfc_mf1.c | 2 +- software/script/chameleon_cli_unit.py | 79 +++++++++++++++ software/script/chameleon_cmd.py | 58 +++++++++++ software/script/chameleon_enum.py | 6 ++ 8 files changed, 276 insertions(+), 22 deletions(-) diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index d4ba55e..c99d007 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -1419,6 +1419,54 @@ static data_frame_tx_t *cmd_processor_mf0_ntag_set_write_mode(uint16_t cmd, uint return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); } +static data_frame_tx_t *cmd_processor_mf0_ntag_set_detection_enable(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + if (length != 1 || data[0] > 1) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + nfc_tag_mf0_ntag_detection_log_clear(); + nfc_tag_mf0_ntag_set_detection_enable(data[0]); + return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL); +} + +static data_frame_tx_t *cmd_processor_mf0_ntag_get_detection_enable(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t is_enable = nfc_tag_mf0_ntag_is_detection_enable(); + return data_frame_make(cmd, STATUS_SUCCESS, 1, (uint8_t *)(&is_enable)); +} + +static data_frame_tx_t *cmd_processor_mf0_ntag_get_detection_count(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint32_t count = nfc_tag_mf0_ntag_detection_log_count(); + if (count == 0xFFFFFFFF) { + count = 0; + } + uint32_t payload = U32HTONL(count); + return data_frame_make(cmd, STATUS_SUCCESS, sizeof(uint32_t), (uint8_t *)&payload); +} + +static data_frame_tx_t *cmd_processor_mf0_ntag_get_detection_log(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint32_t count; + uint32_t index; + uint8_t *resp = NULL; + nfc_tag_mf0_ntag_auth_log_t *logs = mf0_get_auth_log(&count); + if (length != 4 || count == 0xFFFFFFFF) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + index = U32NTOHL(*(uint32_t *)data); + if (index >= count) { + return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL); + } + resp = (uint8_t *)(logs + index); + length = MIN(count - index, NETDATA_MAX_DATA_LENGTH / sizeof(nfc_tag_mf0_ntag_auth_log_t)) * sizeof(nfc_tag_mf0_ntag_auth_log_t); + return data_frame_make(cmd, STATUS_SUCCESS, length, resp); +} + +static data_frame_tx_t *cmd_processor_mf0_get_emulator_config(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + uint8_t mf0_info[3] = {}; + mf0_info[0] = nfc_tag_mf0_ntag_is_detection_enable(); + mf0_info[1] = nfc_tag_mf0_ntag_get_uid_mode(); + mf0_info[2] = nfc_tag_mf0_ntag_get_write_mode(); + return data_frame_make(cmd, STATUS_SUCCESS, 3, mf0_info); +} + /** * (cmd -> processor) function map, the map struct is: * cmd code before process cmd processor after process @@ -1490,9 +1538,10 @@ static cmd_data_map_t m_data_cmd_map[] = { #endif - { DATA_CMD_MF1_WRITE_EMU_BLOCK_DATA, NULL, cmd_processor_mf1_write_emu_block_data, NULL }, + { DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL }, { DATA_CMD_HF14A_SET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_set_anti_coll_data, NULL }, + { DATA_CMD_MF1_WRITE_EMU_BLOCK_DATA, NULL, cmd_processor_mf1_write_emu_block_data, NULL }, { DATA_CMD_MF1_SET_DETECTION_ENABLE, NULL, cmd_processor_mf1_set_detection_enable, NULL }, { DATA_CMD_MF1_GET_DETECTION_COUNT, NULL, cmd_processor_mf1_get_detection_count, NULL }, { DATA_CMD_MF1_GET_DETECTION_LOG, NULL, cmd_processor_mf1_get_detection_log, NULL }, @@ -1507,25 +1556,31 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_MF1_SET_BLOCK_ANTI_COLL_MODE, NULL, cmd_processor_mf1_set_block_anti_coll_mode, NULL }, { DATA_CMD_MF1_GET_WRITE_MODE, NULL, cmd_processor_mf1_get_write_mode, NULL }, { DATA_CMD_MF1_SET_WRITE_MODE, NULL, cmd_processor_mf1_set_write_mode, NULL }, - { DATA_CMD_HF14A_GET_ANTI_COLL_DATA, NULL, cmd_processor_hf14a_get_anti_coll_data, NULL }, - { DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_get_uid_mode, NULL }, - { DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_set_uid_mode, NULL }, - { DATA_CMD_MF0_NTAG_READ_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_read_emu_page_data, NULL }, - { DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_write_emu_page_data, NULL }, - { DATA_CMD_MF0_NTAG_GET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_get_version_data, NULL }, - { DATA_CMD_MF0_NTAG_SET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_set_version_data, NULL }, - { DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_get_signature_data, NULL }, - { DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_set_signature_data, NULL }, - { DATA_CMD_MF0_NTAG_GET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_get_counter_data, NULL }, - { DATA_CMD_MF0_NTAG_SET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_set_counter_data, NULL }, - { DATA_CMD_MF0_NTAG_RESET_AUTH_CNT, NULL, cmd_processor_mf0_ntag_reset_auth_cnt, NULL }, - { DATA_CMD_MF0_NTAG_GET_PAGE_COUNT, NULL, cmd_processor_mf0_ntag_get_emu_page_count, NULL }, - { DATA_CMD_MF0_NTAG_GET_WRITE_MODE, NULL, cmd_processor_mf0_ntag_get_write_mode, NULL }, - { DATA_CMD_MF0_NTAG_SET_WRITE_MODE, NULL, cmd_processor_mf0_ntag_set_write_mode, NULL }, - { DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL }, - { DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL }, - { DATA_CMD_HIDPROX_SET_EMU_ID, NULL, cmd_processor_hidprox_set_emu_id, NULL }, - { DATA_CMD_HIDPROX_GET_EMU_ID, NULL, cmd_processor_hidprox_get_emu_id, NULL }, + + { DATA_CMD_MF0_NTAG_GET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_get_uid_mode, NULL }, + { DATA_CMD_MF0_NTAG_SET_UID_MAGIC_MODE, NULL, cmd_processor_mf0_ntag_set_uid_mode, NULL }, + { DATA_CMD_MF0_NTAG_READ_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_read_emu_page_data, NULL }, + { DATA_CMD_MF0_NTAG_WRITE_EMU_PAGE_DATA, NULL, cmd_processor_mf0_ntag_write_emu_page_data, NULL }, + { DATA_CMD_MF0_NTAG_GET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_get_version_data, NULL }, + { DATA_CMD_MF0_NTAG_SET_VERSION_DATA, NULL, cmd_processor_mf0_ntag_set_version_data, NULL }, + { DATA_CMD_MF0_NTAG_GET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_get_signature_data, NULL }, + { DATA_CMD_MF0_NTAG_SET_SIGNATURE_DATA, NULL, cmd_processor_mf0_ntag_set_signature_data, NULL }, + { DATA_CMD_MF0_NTAG_GET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_get_counter_data, NULL }, + { DATA_CMD_MF0_NTAG_SET_COUNTER_DATA, NULL, cmd_processor_mf0_ntag_set_counter_data, NULL }, + { DATA_CMD_MF0_NTAG_RESET_AUTH_CNT, NULL, cmd_processor_mf0_ntag_reset_auth_cnt, NULL }, + { DATA_CMD_MF0_NTAG_GET_PAGE_COUNT, NULL, cmd_processor_mf0_ntag_get_emu_page_count, NULL }, + { DATA_CMD_MF0_NTAG_GET_WRITE_MODE, NULL, cmd_processor_mf0_ntag_get_write_mode, NULL }, + { DATA_CMD_MF0_NTAG_SET_WRITE_MODE, NULL, cmd_processor_mf0_ntag_set_write_mode, NULL }, + { DATA_CMD_MF0_NTAG_SET_DETECTION_ENABLE, NULL, cmd_processor_mf0_ntag_set_detection_enable, NULL }, + { DATA_CMD_MF0_NTAG_GET_DETECTION_COUNT, NULL, cmd_processor_mf0_ntag_get_detection_count, NULL }, + { DATA_CMD_MF0_NTAG_GET_DETECTION_LOG, NULL, cmd_processor_mf0_ntag_get_detection_log, NULL }, + { DATA_CMD_MF0_NTAG_GET_DETECTION_ENABLE, NULL, cmd_processor_mf0_ntag_get_detection_enable, NULL }, + { DATA_CMD_MF0_NTAG_GET_EMULATOR_CONFIG, NULL, cmd_processor_mf0_get_emulator_config, NULL }, + + { DATA_CMD_EM410X_SET_EMU_ID, NULL, cmd_processor_em410x_set_emu_id, NULL }, + { DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL }, + { DATA_CMD_HIDPROX_SET_EMU_ID, NULL, cmd_processor_hidprox_set_emu_id, NULL }, + { DATA_CMD_HIDPROX_GET_EMU_ID, NULL, cmd_processor_hidprox_get_emu_id, NULL }, }; data_frame_tx_t *cmd_processor_get_device_capabilities(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index 65ea385..242158b 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -128,6 +128,11 @@ #define DATA_CMD_MF0_NTAG_GET_PAGE_COUNT (4030) #define DATA_CMD_MF0_NTAG_GET_WRITE_MODE (4031) #define DATA_CMD_MF0_NTAG_SET_WRITE_MODE (4032) +#define DATA_CMD_MF0_NTAG_SET_DETECTION_ENABLE (4033) +#define DATA_CMD_MF0_NTAG_GET_DETECTION_COUNT (4034) +#define DATA_CMD_MF0_NTAG_GET_DETECTION_LOG (4035) +#define DATA_CMD_MF0_NTAG_GET_DETECTION_ENABLE (4036) +#define DATA_CMD_MF0_NTAG_GET_EMULATOR_CONFIG (4037) // // ****************************************************************** diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c index bd4aa41..5d40c7e 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.c @@ -135,6 +135,12 @@ static tag_specific_type_t m_tag_type; static bool m_tag_authenticated = false; static bool m_did_first_read = false; +#define MF0_NTAG_AUTH_LOG_MAX 32 +static __attribute__((section(".noinit_mf0"))) struct nfc_tag_mf0_auth_log_buffer { + nfc_tag_mf0_ntag_auth_log_t logs[MF0_NTAG_AUTH_LOG_MAX]; + uint32_t count; +} m_auth_log = {.count = 0}; + int nfc_tag_mf0_ntag_get_nr_pages_by_tag_type(tag_specific_type_t tag_type) { int nr_pages = -1; @@ -924,6 +930,14 @@ static void handle_pwd_auth_command(uint8_t *p_data) { uint32_t pwd = *(uint32_t *)m_tag_information->memory[first_cfg_page + CONF_PWD_PAGE_OFFSET]; uint32_t supplied_pwd = *(uint32_t *)&p_data[1]; + + if (m_tag_information->config.detection_enable && m_auth_log.count < MF0_NTAG_AUTH_LOG_MAX) { + memcpy(m_auth_log.logs[m_auth_log.count].pwd, &p_data[1], 4); + m_auth_log.count++; + NRF_LOG_INFO("NTAG password: %02x%02x%02x%02x", + p_data[1], p_data[2], p_data[3], p_data[4]); + } + if (pwd != supplied_pwd) { if (auth_lim) { cnt_data[MF0_NTAG_AUTHLIM_OFF_IN_CTR] &= ~MF0_NTAG_AUTHLIM_MASK_IN_CTR; @@ -1238,6 +1252,7 @@ bool nfc_tag_mf0_ntag_data_factory(uint8_t slot, tag_specific_type_t tag_type) { // default ntag config p_ntag_information->config.mode_uid_magic = false; p_ntag_information->config.mode_block_write = NFC_TAG_MF0_NTAG_WRITE_NORMAL; + p_ntag_information->config.detection_enable = false; // save data to flash tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type); @@ -1282,3 +1297,26 @@ nfc_tag_mf0_ntag_write_mode_t nfc_tag_mf0_ntag_get_write_mode(void) { return m_tag_information->config.mode_block_write; } + +nfc_tag_mf0_ntag_auth_log_t *mf0_get_auth_log(uint32_t *count) { + *count = m_auth_log.count; + return m_auth_log.logs; +} + +void nfc_tag_mf0_ntag_set_detection_enable(bool enable) { + if (m_tag_type == TAG_TYPE_UNDEFINED || m_tag_information == NULL) return; + m_tag_information->config.detection_enable = enable; +} + +bool nfc_tag_mf0_ntag_is_detection_enable(void) { + if (m_tag_type == TAG_TYPE_UNDEFINED || m_tag_information == NULL) return false; + return m_tag_information->config.detection_enable; +} + +void nfc_tag_mf0_ntag_detection_log_clear(void) { + m_auth_log.count = 0; +} + +uint32_t nfc_tag_mf0_ntag_detection_log_count(void) { + return m_auth_log.count; +} diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h index a5298b0..21fec74 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf0_ntag.h @@ -56,12 +56,19 @@ typedef enum { NFC_TAG_MF0_NTAG_WRITE_SHADOW_REQ = 4u, } nfc_tag_mf0_ntag_write_mode_t; +// M0/NTAG password authentication log for key collection +typedef struct { + uint8_t pwd[4]; // Password used in authentication +} PACKED nfc_tag_mf0_ntag_auth_log_t; + typedef struct { uint8_t mode_uid_magic: 1; // New field for write mode nfc_tag_mf0_ntag_write_mode_t mode_block_write: 3; + // Enable key detection (password logging) + uint8_t detection_enable: 1; // reserve remaining bits - uint8_t reserved1: 4; + uint8_t reserved1: 3; uint8_t reserved2; uint8_t reserved3; } nfc_tag_mf0_ntag_configure_t; @@ -93,4 +100,10 @@ bool nfc_tag_mf0_ntag_set_uid_mode(bool enabled); void nfc_tag_mf0_ntag_set_write_mode(nfc_tag_mf0_ntag_write_mode_t write_mode); nfc_tag_mf0_ntag_write_mode_t nfc_tag_mf0_ntag_get_write_mode(void); +nfc_tag_mf0_ntag_auth_log_t *mf0_get_auth_log(uint32_t *count); +void nfc_tag_mf0_ntag_set_detection_enable(bool enable); +bool nfc_tag_mf0_ntag_is_detection_enable(void); +void nfc_tag_mf0_ntag_detection_log_clear(void); +uint32_t nfc_tag_mf0_ntag_detection_log_count(void); + #endif diff --git a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c index 3ae6164..15d27c5 100644 --- a/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c +++ b/firmware/application/src/rfid/nfctag/hf/nfc_mf1.c @@ -201,7 +201,7 @@ static struct Crypto1State *pcs = &mpcs; // Define the buffer of the data that stored the detected data // Place this data in a dormant RAM to save time and space to write into Flash #define MF1_AUTH_LOG_MAX_SIZE 1000 -static __attribute__((section(".noinit"))) struct nfc_tag_mf1_auth_log_buffer { +static __attribute__((section(".noinit_mf1"))) struct nfc_tag_mf1_auth_log_buffer { uint32_t count; nfc_tag_mf1_auth_log_t logs[MF1_AUTH_LOG_MAX_SIZE]; } m_auth_log; diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index c1938c6..00c6879 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -2983,6 +2983,12 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired help="Set data to be returned by the READ_SIG command.") parser.add_argument('--reset-auth-cnt', action='store_true', help="Resets the counter of unsuccessful authentication attempts.") + + detection_group = parser.add_mutually_exclusive_group() + detection_group.add_argument('--enable-log', action='store_true', + help="Enable password authentication logging") + detection_group.add_argument('--disable-log', action='store_true', + help="Disable password authentication logging") return parser def on_exec(self, args: argparse.Namespace): @@ -3078,6 +3084,30 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired except: print(f"{CR}Failed to set write mode. Check if device firmware supports this feature.{C0}") + detection = self.cmd.mf0_ntag_get_detection_enable() + if args.enable_log: + change_requested = True + if detection is not None: + if not detection: + detection = True + self.cmd.mf0_ntag_set_detection_enable(detection) + change_done = True + else: + print(f'{CY}Requested logging of MFU authentication data already enabled{C0}') + else: + print(f'{CR}Detection functionality not available in this firmware{C0}') + elif args.disable_log: + change_requested = True + if detection is not None: + if detection: + detection = False + self.cmd.mf0_ntag_set_detection_enable(detection) + change_done = True + else: + print(f'{CY}Requested logging of MFU authentication data already disabled{C0}') + else: + print(f'{CR}Detection functionality not available in this firmware{C0}') + if change_done or aux_data_changed: print(' - MFU/NTAG Emulator settings updated') if not (change_requested or aux_data_change_requested): @@ -3116,6 +3146,55 @@ class HFMFUEConfig(SlotIndexArgsAndGoUnit, HF14AAntiCollArgsUnit, DeviceRequired except: pass + try: + detection = self.cmd.mf0_ntag_get_detection_enable() + print( + f'- {"Log (password) mode:":40}{f"{CG}enabled{C0}" if detection else f"{CR}disabled{C0}"}') + except: + pass + +@hf_mfu.command('edetect') +class HFMFUEDetect(SlotIndexArgsAndGoUnit, DeviceRequiredUnit): + def args_parser(self) -> ArgumentParserNoExit: + parser = ArgumentParserNoExit() + parser.description = 'Get Mifare Ultralight / NTAG emulator detection logs' + self.add_slot_args(parser) + parser.add_argument('--count', type=int, help="Number of log entries to retrieve", metavar="COUNT") + parser.add_argument('--index', type=int, default=0, help="Starting index (default: 0)", metavar="INDEX") + return parser + + def on_exec(self, args: argparse.Namespace): + detection_enabled = self.cmd.mf0_ntag_get_detection_enable() + if not detection_enabled: + print(f"{CY}Detection logging is disabled for this slot{C0}") + return + + total_count = self.cmd.mf0_ntag_get_detection_count() + print(f"Total detection log entries: {total_count}") + + if total_count == 0: + print(f"{CY}No detection logs available{C0}") + return + + if args.count is not None: + entries_to_get = min(args.count, total_count - args.index) + else: + entries_to_get = total_count - args.index + + if entries_to_get <= 0: + print(f"{CY}No entries available from index {args.index}{C0}") + return + + logs = self.cmd.mf0_ntag_get_detection_log(args.index) + + print(f"\nPassword detection logs (showing {len(logs)} entries from index {args.index}):") + print("-" * 50) + + for i, log_entry in enumerate(logs): + actual_index = args.index + i + password = log_entry['password'] + print(f"{actual_index:3d}: {CY}{password.upper()}{C0}") + @lf_em_410x.command('read') class LFEMRead(ReaderRequiredUnit): diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index de7bc93..86a978a 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -663,6 +663,64 @@ class ChameleonCMD: resp.parsed = result_list return resp + @expect_response(Status.SUCCESS) + def mf0_ntag_get_detection_enable(self): + """ + Get whether NTAG password detection is enabled. + + :return: + """ + resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_DETECTION_ENABLE) + if resp.status == Status.SUCCESS: + resp.parsed = struct.unpack('!B', resp.data)[0] == 1 + return resp + + @expect_response(Status.SUCCESS) + def mf0_ntag_set_detection_enable(self, enabled: bool): + """ + Set whether to enable NTAG password detection. + + :param enable: Whether to enable + :return: + """ + data = struct.pack('!B', enabled) + return self.device.send_cmd_sync(Command.MF0_NTAG_SET_DETECTION_ENABLE, data) + + @expect_response(Status.SUCCESS) + def mf0_ntag_get_detection_count(self): + """ + Get the statistics of the current NTAG password detection records. + + :return: + """ + resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_DETECTION_COUNT) + if resp.status == Status.SUCCESS: + resp.parsed = struct.unpack('!I', resp.data)[0] + return resp + + @expect_response(Status.SUCCESS) + def mf0_ntag_get_detection_log(self, index: int): + """ + Get NTAG password detection logs from the specified index position. + + :param index: start index + :return: + """ + data = struct.pack('!I', index) + resp = self.device.send_cmd_sync(Command.MF0_NTAG_GET_DETECTION_LOG, data) + if resp.status == Status.SUCCESS: + # convert - each log entry is just a 4-byte password + result_list = [] + pos = 0 + while pos < len(resp.data): + password = resp.data[pos:pos+4] + result_list.append({ + 'password': password.hex() + }) + pos += 4 + resp.parsed = result_list + return resp + @expect_response(Status.SUCCESS) def mf1_write_emu_block_data(self, block_start: int, block_data: bytes): """ diff --git a/software/script/chameleon_enum.py b/software/script/chameleon_enum.py index dd70e73..bdd6ec6 100644 --- a/software/script/chameleon_enum.py +++ b/software/script/chameleon_enum.py @@ -115,6 +115,12 @@ class Command(enum.IntEnum): MF0_NTAG_GET_PAGE_COUNT = 4030 MF0_NTAG_GET_WRITE_MODE = 4031 MF0_NTAG_SET_WRITE_MODE = 4032 + MF0_NTAG_SET_DETECTION_ENABLE = 4033 + MF0_NTAG_GET_DETECTION_COUNT = 4034 + MF0_NTAG_GET_DETECTION_LOG = 4035 + MF0_NTAG_GET_DETECTION_ENABLE = 4036 + # FIXME: not implemented + MF0_NTAG_GET_EMULATOR_CONFIG = 4037 EM410X_SET_EMU_ID = 5000 EM410X_GET_EMU_ID = 5001