diff --git a/.github/workflows/firmware.yml b/.github/workflows/firmware.yml index f54f507..9fd6b6e 100644 --- a/.github/workflows/firmware.yml +++ b/.github/workflows/firmware.yml @@ -76,7 +76,8 @@ jobs: name: ${{ matrix.device_type }}-dfu-full path: firmware/objects/dfu-full/* create_release: - permissions: write-all + permissions: + contents: write name: Create Pre-Release with dfu app images runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' @@ -85,52 +86,34 @@ jobs: steps: - name: Check out the repo uses: actions/checkout@v3 - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.run_number }} - release_name: Compiled commit ${{ github.sha }} - body: | - Auto-Generated DFU images - draft: false - prerelease: true - name: Download Ultra DFU uses: actions/download-artifact@v3 with: name: ultra-dfu-app - path: dfu-app-artifacts - - name: Compress + path: ultra-dfu-app + - name: Compress Ultra DFU package run: | - zip --junk-paths -0 -r ./dfu-app-artifacts/dfu-app.zip ./dfu-app-artifacts/* - - name: Upload Ultra DFU - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./dfu-app-artifacts/dfu-app.zip - asset_name: ultra-dfu-app.zip - asset_content_type: application/zip - - name: Clear - run: | - rm -rf ./dfu-app-artifacts/ + zip --junk-paths -0 -r ./ultra-dfu-app.zip ./ultra-dfu-app/* - name: Download Lite DFU uses: actions/download-artifact@v3 with: name: lite-dfu-app - path: dfu-app-artifacts - - name: Compress + path: lite-dfu-app + - name: Compress Lite DFU package run: | - zip --junk-paths -0 -r ./dfu-app-artifacts/dfu-app.zip ./dfu-app-artifacts/* - - name: Upload Lite DFU - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + zip --junk-paths -0 -r ./lite-dfu-app.zip ./lite-dfu-app/* + - name: Upload to dev release + uses: softprops/action-gh-release@v1 with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./dfu-app-artifacts/dfu-app.zip - asset_name: lite-dfu-app.zip - asset_content_type: application/zip + body: | + Auto-Generated DFU packages from latest `main` commit. + For development purposes only. + These are not tested, here be dragons. + Built from commit ${{ github.sha }} + tag_name: dev + name: Development release + draft: false + prerelease: true + target_commitish: main + generate_release_notes: true + files: ./*-dfu-app.zip diff --git a/firmware/application/src/app_cmd.c b/firmware/application/src/app_cmd.c index ac22dd8..c2da08d 100644 --- a/firmware/application/src/app_cmd.c +++ b/firmware/application/src/app_cmd.c @@ -377,6 +377,14 @@ data_frame_tx_t* cmd_processor_set_em410x_emu_id(uint16_t cmd, uint16_t status, return data_frame_make(cmd, status, 0, NULL); } +data_frame_tx_t* cmd_processor_get_em410x_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + tag_data_buffer_t* buffer = get_buffer_by_tag_type(TAG_TYPE_EM410X); + uint8_t responseData[LF_EM410X_TAG_ID_SIZE]; + memcpy(responseData, buffer->buffer, LF_EM410X_TAG_ID_SIZE); + status = STATUS_DEVICE_SUCCESS; + return data_frame_make(cmd, status, LF_EM410X_TAG_ID_SIZE, responseData); +} + data_frame_tx_t* cmd_processor_set_mf1_detection_enable(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length == 1 && (data[0] == 0 || data[0] == 1)) { nfc_tag_mf1_detection_log_clear(); @@ -456,6 +464,33 @@ data_frame_tx_t* cmd_processor_set_mf1_emulator_block(uint16_t cmd, uint16_t sta return data_frame_make(cmd, status, 0, NULL); } +data_frame_tx_t* cmd_processor_get_mf1_emulator_block(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { + if (length == 3) { + uint8_t block_index = data[0]; + uint16_t block_count = data[1] | (data[2] << 8); + if (block_count == 0 || block_index + block_count > NFC_TAG_MF1_BLOCK_MAX) { + status = STATUS_PAR_ERR; + } + else { + tag_data_buffer_t* buffer = get_buffer_by_tag_type(TAG_TYPE_MIFARE_4096); + nfc_tag_mf1_information_t *info = (nfc_tag_mf1_information_t *)buffer->buffer; + uint16_t result_length = block_count * NFC_TAG_MF1_DATA_SIZE; + uint8_t result_buffer[result_length]; + for (int i = 0, j = block_index; i < result_length; i += NFC_TAG_MF1_DATA_SIZE, j++) { + uint8_t *p_block = &result_buffer[i]; + memcpy(p_block, info->memory[j], NFC_TAG_MF1_DATA_SIZE); + } + + return data_frame_make(cmd, status, result_length, result_buffer); + } + } + else { + status = STATUS_PAR_ERR; + } + + return data_frame_make(cmd, status, 0, NULL); +} + data_frame_tx_t* cmd_processor_set_mf1_anti_collision_res(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) { if (length > 13) { // sak(1) + atqa(2) + uid(10) @@ -737,12 +772,14 @@ static cmd_data_map_t m_data_cmd_map[] = { { DATA_CMD_SET_EM410X_EMU_ID, NULL, cmd_processor_set_em410x_emu_id, NULL }, + { DATA_CMD_GET_EM410X_EMU_ID, NULL, cmd_processor_get_em410x_emu_id, NULL }, { DATA_CMD_GET_MF1_DETECTION_STATUS, NULL, cmd_processor_get_mf1_detection_status, NULL }, { DATA_CMD_SET_MF1_DETECTION_ENABLE, NULL, cmd_processor_set_mf1_detection_enable, NULL }, { DATA_CMD_GET_MF1_DETECTION_COUNT, NULL, cmd_processor_get_mf1_detection_count, NULL }, { DATA_CMD_GET_MF1_DETECTION_RESULT, NULL, cmd_processor_get_mf1_detection_log, NULL }, - { DATA_CMD_LOAD_MF1_BLOCK_DATA, NULL, cmd_processor_set_mf1_emulator_block, NULL }, + { DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA, NULL, cmd_processor_set_mf1_emulator_block, NULL }, + { DATA_CMD_READ_MF1_EMU_BLOCK_DATA, NULL, cmd_processor_get_mf1_emulator_block, NULL }, { DATA_CMD_SET_MF1_ANTI_COLLISION_RES, NULL, cmd_processor_set_mf1_anti_collision_res, NULL }, { DATA_CMD_GET_MF1_EMULATOR_CONFIG, NULL, cmd_processor_get_mf1_info, NULL }, { DATA_CMD_GET_MF1_GEN1A_MODE, NULL, cmd_processor_get_mf1_gen1a_magic_mode, NULL }, diff --git a/firmware/application/src/data_cmd.h b/firmware/application/src/data_cmd.h index ce00e3a..a1bf6e7 100644 --- a/firmware/application/src/data_cmd.h +++ b/firmware/application/src/data_cmd.h @@ -68,9 +68,15 @@ // Range from 4000 -> 4999 // ****************************************************************** // -#define DATA_CMD_LOAD_MF1_BLOCK_DATA (4000) +#define DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA (4000) #define DATA_CMD_SET_MF1_ANTI_COLLISION_RES (4001) - +#define DATA_CMD_SET_MF1_ANTICOLLISION_INFO (4002) +#define DATA_CMD_SET_MF1_ATS_RESOURCE (4003) +#define DATA_CMD_SET_MF1_DETECTION_ENABLE (4004) +#define DATA_CMD_GET_MF1_DETECTION_COUNT (4005) +#define DATA_CMD_GET_MF1_DETECTION_RESULT (4006) +#define DATA_CMD_GET_MF1_DETECTION_STATUS (4007) +#define DATA_CMD_READ_MF1_EMU_BLOCK_DATA (4008) #define DATA_CMD_GET_MF1_EMULATOR_CONFIG (4009) #define DATA_CMD_GET_MF1_GEN1A_MODE (4010) #define DATA_CMD_SET_MF1_GEN1A_MODE (4011) @@ -80,7 +86,6 @@ #define DATA_CMD_SET_MF1_USE_FIRST_BLOCK_COLL (4015) #define DATA_CMD_GET_MF1_WRITE_MODE (4016) #define DATA_CMD_SET_MF1_WRITE_MODE (4017) - // // ****************************************************************** @@ -94,11 +99,6 @@ // // ****************************************************************** #define DATA_CMD_SET_EM410X_EMU_ID (5000) -#define DATA_CMD_SET_MF1_ANTICOLLISION_INFO (5001) -#define DATA_CMD_SET_MF1_ATS_RESOURCE (5002) -#define DATA_CMD_SET_MF1_DETECTION_ENABLE (5003) -#define DATA_CMD_GET_MF1_DETECTION_COUNT (5004) -#define DATA_CMD_GET_MF1_DETECTION_RESULT (5005) -#define DATA_CMD_GET_MF1_DETECTION_STATUS (5006) +#define DATA_CMD_GET_EM410X_EMU_ID (5001) #endif diff --git a/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c b/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c index b345c09..f1741dd 100644 --- a/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c +++ b/firmware/nrf52_sdk/modules/nrfx/drivers/src/nrfx_nfct.c @@ -41,6 +41,8 @@ #include #if NRFX_CHECK(NRFX_NFCT_ENABLED) +// ChameleonUltra: workaround because NFC IRQ gets repetitively called when in HF field once a comm has started +#include "bsp_wdt.h" #include @@ -907,6 +909,8 @@ void nrfx_nfct_irq_handler(void) m_nfct_cb.config.cb(&nfct_evt); } } + // ChameleonUltra: workaround because NFC IRQ gets repetitively called when in HF field once a comm has started + bsp_wdt_feed(); } #endif // NRFX_CHECK(NRFX_NFCT_ENABLED) diff --git a/software/script/chameleon_cli_main.py b/software/script/chameleon_cli_main.py index 3c3e380..8f5e5cb 100755 --- a/software/script/chameleon_cli_main.py +++ b/software/script/chameleon_cli_main.py @@ -116,6 +116,7 @@ class ChameleonCLI: 'settings': new_uint(chameleon_cli_unit.HFMFSettings, "Settings of Mifare Classic emulator"), 'sim': new_uint(chameleon_cli_unit.HFMFSim, "Simulate a Mifare Classic card"), 'eload': new_uint(chameleon_cli_unit.HFMFELoad, "Load data to emulator memory"), + 'eread': new_uint(chameleon_cli_unit.HFMFERead, "Read data from emulator memory"), 'help': "Mifare Classic mini/1/2/4, attack/read/write" }, 'help': "high frequency tag/reader", @@ -124,7 +125,11 @@ class ChameleonCLI: 'em': { 'read': new_uint(chameleon_cli_unit.LFEMRead, "Scan em410x tag and print id"), 'write': new_uint(chameleon_cli_unit.LFEMWriteT55xx, "Write em410x id to t55xx"), - 'sim': new_uint(chameleon_cli_unit.LFEMSim, "Simulation a em410x id card"), + 'sim': { + 'set': new_uint(chameleon_cli_unit.LFEMSimSet, "Set simulated em410x card id"), + 'get': new_uint(chameleon_cli_unit.LFEMSimGet, "Get simulated em410x card id"), + 'help': "Manage EM410x emulation data for selected slot" + }, 'help': "EM410x read/write/emulator", }, 'help': "low frequency tag/reader", diff --git a/software/script/chameleon_cli_unit.py b/software/script/chameleon_cli_unit.py index c5a2a60..eb87bfd 100644 --- a/software/script/chameleon_cli_unit.py +++ b/software/script/chameleon_cli_unit.py @@ -1,3 +1,4 @@ +import binascii import os import re import subprocess @@ -681,6 +682,55 @@ class HFMFELoad(DeviceRequiredUnit): block += 1 print("\n - Load success") +class HFMFERead(DeviceRequiredUnit): + + def args_parser(self) -> ArgumentParserNoExit or None: + parser = ArgumentParserNoExit() + parser.add_argument('-f', '--file', type=str, required=True, help="file path") + parser.add_argument('-t', '--type', type=str, required=False, help="content type", choices=['bin', 'hex']) + return parser + + def on_exec(self, args: argparse.Namespace): + file = args.file + if args.type is None: + if file.endswith('.bin'): + content_type = 'bin' + elif file.endswith('.eml'): + content_type = 'hex' + else: + raise Exception("Unknown file format, Specify content type with -t option") + else: + content_type = args.type + + selected_slot = self.cmd_positive.get_active_slot().data[0] + slot_info = self.cmd_positive.get_slot_info().data + tag_type = chameleon_cmd.TagSpecificType(slot_info[selected_slot * 2]) + if tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_Mini: + block_count = 20 + elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_1024: + block_count = 64 + elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_2048: + block_count = 128 + elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_4096: + block_count = 256 + else: + raise Exception("Card in current slot is not Mifare Classic/Plus in SL1 mode") + + with open(file, 'wb') as fd: + block = 0 + while block < block_count: + response = self.cmd_positive.get_mf1_block_data(block, 1) + print('.', end='') + block += 1 + if content_type == 'hex': + hex_char_repr = binascii.hexlify(response.data) + fd.write(hex_char_repr) + fd.write(bytes([0x0a])) + else: + fd.write(response.data) + + print("\n - Read success") + class HFMFSettings(DeviceRequiredUnit): def args_parser(self) -> ArgumentParserNoExit or None: @@ -965,18 +1015,29 @@ class HWSlotEnableSet(SlotIndexRequireUint): print(f' - Set slot {slot_num} {"enable" if enable else "disable"} success.') -class LFEMSim(LFEMCardRequiredUint): +class LFEMSimSet(LFEMCardRequiredUint): def args_parser(self) -> ArgumentParserNoExit or None: parser = ArgumentParserNoExit() return self.add_card_arg(parser) - # lf em sim --id 4545454545 + # lf em sim set --id 4545454545 def on_exec(self, args: argparse.Namespace): id_hex = args.id id_bytes = bytearray.fromhex(id_hex) - self.cmd_positive.set_em140x_sim_id(id_bytes) + self.cmd_positive.set_em410x_sim_id(id_bytes) print(f' - Set em410x tag id success.') +class LFEMSimGet(DeviceRequiredUnit): + + def args_parser(self) -> ArgumentParserNoExit or None: + return None + + # lf em sim get + def on_exec(self, args: argparse.Namespace): + response = self.cmd_positive.get_em410x_sim_id() + print(f' - Get em410x tag id success.') + print(f'ID: {response.data.hex()}') + class HWSlotNickSet(SlotIndexRequireUint, SenseTypeRequireUint): def args_parser(self) -> ArgumentParserNoExit or None: diff --git a/software/script/chameleon_cmd.py b/software/script/chameleon_cmd.py index 8db0db3..10ce159 100644 --- a/software/script/chameleon_cmd.py +++ b/software/script/chameleon_cmd.py @@ -1,4 +1,5 @@ import enum +import struct import chameleon_com import chameleon_status @@ -48,9 +49,15 @@ DATA_CMD_MF1_WRITE_ONE_BLOCK = 2009 DATA_CMD_SCAN_EM410X_TAG = 3000 DATA_CMD_WRITE_EM410X_TO_T5577 = 3001 -DATA_CMD_LOAD_MF1_BLOCK_DATA = 4000 +DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA = 4000 DATA_CMD_SET_MF1_ANTI_COLLISION_RES = 4001 +DATA_CMD_SET_MF1_DETECTION_ENABLE = 4004 +DATA_CMD_GET_MF1_DETECTION_COUNT = 4005 +DATA_CMD_GET_MF1_DETECTION_RESULT = 4006 + +DATA_CMD_READ_MF1_EMU_BLOCK_DATA = 4008 + DATA_CMD_GET_MF1_EMULATOR_CONFIG = 4009 DATA_CMD_GET_MF1_GEN1A_MODE = 4010 DATA_CMD_SET_MF1_GEN1A_MODE = 4011 @@ -62,9 +69,7 @@ DATA_CMD_GET_MF1_WRITE_MODE = 4016 DATA_CMD_SET_MF1_WRITE_MODE = 4017 DATA_CMD_SET_EM410X_EMU_ID = 5000 -DATA_CMD_SET_MF1_DETECTION_ENABLE = 5003 -DATA_CMD_GET_MF1_DETECTION_COUNT = 5004 -DATA_CMD_GET_MF1_DETECTION_RESULT = 5005 +DATA_CMD_GET_EM410X_EMU_ID = 5001 @enum.unique @@ -439,7 +444,7 @@ class BaseChameleonCMD: data.append(0x01 if enable else 0x00) return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_ENABLE, 0X00, data) - def set_em140x_sim_id(self, id_bytes: bytearray): + def set_em410x_sim_id(self, id_bytes: bytearray): """ 设置EM410x模拟的卡号 :param id_bytes: 卡号的字节 @@ -448,6 +453,12 @@ class BaseChameleonCMD: if len(id_bytes) != 5: raise ValueError("The id bytes length must equal 5") return self.device.send_cmd_sync(DATA_CMD_SET_EM410X_EMU_ID, 0x00, id_bytes) + + def get_em410x_sim_id(self): + """ + Get the simulated EM410x card id + """ + return self.device.send_cmd_sync(DATA_CMD_GET_EM410X_EMU_ID, 0x00) def set_mf1_detection_enable(self, enable: bool): """ @@ -486,7 +497,14 @@ class BaseChameleonCMD: data = bytearray() data.append(block_start & 0xFF) data.extend(block_data) - return self.device.send_cmd_sync(DATA_CMD_LOAD_MF1_BLOCK_DATA, 0x00, data) + return self.device.send_cmd_sync(DATA_CMD_LOAD_MF1_EMU_BLOCK_DATA, 0x00, data) + + def get_mf1_block_data(self, block_start: int, block_count: int): + """ + Gets data for selected block range + """ + data = struct.pack('