diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index 2689ea665..f7452beda 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -2073,219 +2073,6 @@ static int selectfile(uint8_t *aid, uint8_t fileno, uint8_t *cs) { return res; } -static int CmdHF14ADesReadData(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes read", - "Read data from File\n" - "Make sure to select aid or authenticate aid before running this command.", - "hf mfdes read -n 1 -t 0 -o 000000 -l 000000 -a 123456\n" - "hf mfdes read -n 1 -t 0 --> Read all data from standard file, fileno 1" - ); - - void *argtable[] = { - arg_param_begin, - arg_int0("n", "fileno", "", "File Number (0 - 31)"), - arg_strx0("o", "offset", "", "File Offset (3 hex bytes, big endian)"), - arg_strx0("l", "length", "", "Length to read (3 hex bytes, big endian -> 000000 = Read all data)"), - arg_int0("t", "type", "", "File Type (0 = Standard / Backup, 1 = Record)"), - arg_strx0("a", "aid", "", "App ID to select (3 hex bytes, big endian)"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, false); - int fno = arg_get_int_def(ctx, 1, 0); - - int offsetlength = 0; - uint8_t offset[3] = {0}; - int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength); - - int flength = 0; - uint8_t filesize[3] = {0}; - int res_flen = CLIParamHexToBuf(arg_get_str(ctx, 3), filesize, 3, &flength); - - int type = arg_get_int(ctx, 4); - - int aidlength = 3; - uint8_t aid[3] = {0}; - CLIGetHexWithReturn(ctx, 5, aid, &aidlength); - swap24(aid); - CLIParserFree(ctx); - - if (type > 1) { - PrintAndLogEx(ERR, "Invalid file type (0 = Standard/Backup, 1 = Record)"); - return PM3_EINVARG; - } - - if (res_offset || (offsetlength != 3 && offsetlength != 0)) { - PrintAndLogEx(ERR, "Offset needs 3 hex bytes"); - return PM3_EINVARG; - } - - if (fno > 0x1F) { - PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); - return PM3_EINVARG; - } - - if (res_flen) { - PrintAndLogEx(ERR, "File size input error"); - return PM3_EINVARG; - } - - swap24(filesize); - swap24(offset); - - mfdes_data_t ft; - memcpy(ft.offset, offset, 3); - memcpy(ft.length, filesize, 3); - ft.fileno = fno; - - uint32_t bytestoread = (uint32_t)le24toh(filesize); - bytestoread &= 0xFFFFFF; - - if (bytestoread == 0) - bytestoread = 0xFFFFFF; - - if (aidlength != 3 && aidlength != 0) { - PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); - return PM3_ESOFT; - } else if (aidlength == 0) { - if (memcmp(&tag->selected_application, aid, 3) == 0) { - PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); - return PM3_ESOFT; - } - memcpy(aid, (uint8_t *)&tag->selected_application, 3); - } - uint8_t cs = 0; - if (selectfile(aid, ft.fileno, &cs) != PM3_SUCCESS) { - PrintAndLogEx(ERR, _RED_(" Error on selecting file.")); - return PM3_ESOFT; - } - - uint8_t *data = (uint8_t *)calloc(bytestoread, sizeof(uint8_t)); - int res = PM3_ESOFT; - if (data != NULL) { - ft.data = data; - res = handler_desfire_readdata(&ft, type, cs); - if (res == PM3_SUCCESS) { - uint32_t len = le24toh(ft.length); - - PrintAndLogEx(SUCCESS, "Read %u bytes from file %d", ft.fileno, len); - PrintAndLogEx(INFO, "Offset | Data | Ascii"); - PrintAndLogEx(INFO, "----------------------------------------------------------------------------"); - - for (uint32_t i = 0; i < len; i += 16) { - uint32_t l = len - i; - PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s", i, i, sprint_hex(&ft.data[i], l > 16 ? 16 : l), sprint_ascii(&ft.data[i], l > 16 ? 16 : l)); - } - } else { - PrintAndLogEx(ERR, "Couldn't read data. Error %d", res); - DropFieldDesfire(); - return res; - } - free(data); - } - DropFieldDesfire(); - return res; -} - -static int CmdHF14ADesWriteData(const char *Cmd) { - - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mfdes write", - "Write data to file\n" - "Make sure to select aid or authenticate aid before running this command.", - "hf mfdes write -n 01 -t 0 -o 000000 -d 3132333435363738" - ); - - void *argtable[] = { - arg_param_begin, - arg_int0("n", "fileno", "", "File Number (0 - 31)"), - arg_strx0("o", "offset", "", "File Offset (3 hex bytes, big endian), optional"), - arg_strx0("d", "data", "", "Data to write (hex bytes, 256 bytes max)"), - arg_int0("t", "type", "", "File Type (0 = Standard / Backup, 1 = Record)"), - arg_strx0("a", "aid", "", "App ID to select as hex bytes (3 bytes, big endian)"), - arg_param_end - }; - - CLIExecWithReturn(ctx, Cmd, argtable, false); - int fno = arg_get_int_def(ctx, 1, 0); - - int offsetlength = 0; - uint8_t offset[3] = {0}; - int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength); - - // iceman: we only have a 1024 byte commandline input array. So this is pointlessly large. - // with 2char hex, 512bytes could be input. - // Instead large binary inputs should be BINARY files and written to card. - int dlength = 512; - uint8_t data[512] = {0}; - int res_data = CLIParamHexToBuf(arg_get_str(ctx, 3), data, 512, &dlength); - - int type = arg_get_int(ctx, 4); - int aidlength = 3; - uint8_t aid[3] = {0}; - CLIGetHexWithReturn(ctx, 5, aid, &aidlength); - swap24(aid); - - CLIParserFree(ctx); - - swap24(offset); - - if (type < 0 || type > 1) { - PrintAndLogEx(ERR, "Unknown type (0=Standard/Backup, 1=Record)"); - return PM3_EINVARG; - } - - if (res_data || dlength == 0) { - PrintAndLogEx(ERR, "Data needs some hex bytes to write"); - return PM3_EINVARG; - } - - if (res_offset || (offsetlength != 3 && offsetlength != 0)) { - PrintAndLogEx(ERR, "Offset needs 3 hex bytes"); - return PM3_EINVARG; - } - - if (fno > 0x1F) { - PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); - return PM3_EINVARG; - } - - mfdes_data_t ft; - - memcpy(ft.offset, offset, 3); - htole24(dlength, ft.length); - ft.fileno = fno; - - if (aidlength != 3 && aidlength != 0) { - PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); - return PM3_ESOFT; - } else if (aidlength == 0) { - if (memcmp(&tag->selected_application, aid, 3) == 0) { - PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); - return PM3_ESOFT; - } - memcpy(aid, (uint8_t *)&tag->selected_application, 3); - } - uint8_t cs = 0; - if (selectfile(aid, fno, &cs) != PM3_SUCCESS) { - PrintAndLogEx(ERR, _RED_(" Error on selecting file.")); - DropFieldDesfire(); - return PM3_ESOFT; - } - - int res = PM3_ESOFT; - ft.data = data; - res = handler_desfire_writedata(&ft, type, cs); - if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Successfully wrote data"); - } else { - PrintAndLogEx(ERR, "Couldn't read data. Error %d", res); - } - DropFieldDesfire(); - return res; -} - static int CmdHF14ADesInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfdes info", @@ -6443,6 +6230,219 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14ADesReadData(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes read", + "Read data from File\n" + "Make sure to select aid or authenticate aid before running this command.", + "hf mfdes read -n 1 -t 0 -o 000000 -l 000000 -a 123456\n" + "hf mfdes read -n 1 -t 0 --> Read all data from standard file, fileno 1" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0("n", "fileno", "", "File Number (0 - 31)"), + arg_strx0("o", "offset", "", "File Offset (3 hex bytes, big endian)"), + arg_strx0("l", "length", "", "Length to read (3 hex bytes, big endian -> 000000 = Read all data)"), + arg_int0("t", "type", "", "File Type (0 = Standard / Backup, 1 = Record)"), + arg_strx0("a", "aid", "", "App ID to select (3 hex bytes, big endian)"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, false); + int fno = arg_get_int_def(ctx, 1, 0); + + int offsetlength = 0; + uint8_t offset[3] = {0}; + int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength); + + int flength = 0; + uint8_t filesize[3] = {0}; + int res_flen = CLIParamHexToBuf(arg_get_str(ctx, 3), filesize, 3, &flength); + + int type = arg_get_int(ctx, 4); + + int aidlength = 3; + uint8_t aid[3] = {0}; + CLIGetHexWithReturn(ctx, 5, aid, &aidlength); + swap24(aid); + CLIParserFree(ctx); + + if (type > 1) { + PrintAndLogEx(ERR, "Invalid file type (0 = Standard/Backup, 1 = Record)"); + return PM3_EINVARG; + } + + if (res_offset || (offsetlength != 3 && offsetlength != 0)) { + PrintAndLogEx(ERR, "Offset needs 3 hex bytes"); + return PM3_EINVARG; + } + + if (fno > 0x1F) { + PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); + return PM3_EINVARG; + } + + if (res_flen) { + PrintAndLogEx(ERR, "File size input error"); + return PM3_EINVARG; + } + + swap24(filesize); + swap24(offset); + + mfdes_data_t ft; + memcpy(ft.offset, offset, 3); + memcpy(ft.length, filesize, 3); + ft.fileno = fno; + + uint32_t bytestoread = (uint32_t)le24toh(filesize); + bytestoread &= 0xFFFFFF; + + if (bytestoread == 0) + bytestoread = 0xFFFFFF; + + if (aidlength != 3 && aidlength != 0) { + PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); + return PM3_ESOFT; + } else if (aidlength == 0) { + if (memcmp(&tag->selected_application, aid, 3) == 0) { + PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); + return PM3_ESOFT; + } + memcpy(aid, (uint8_t *)&tag->selected_application, 3); + } + uint8_t cs = 0; + if (selectfile(aid, ft.fileno, &cs) != PM3_SUCCESS) { + PrintAndLogEx(ERR, _RED_(" Error on selecting file.")); + return PM3_ESOFT; + } + + uint8_t *data = (uint8_t *)calloc(bytestoread, sizeof(uint8_t)); + int res = PM3_ESOFT; + if (data != NULL) { + ft.data = data; + res = handler_desfire_readdata(&ft, type, cs); + if (res == PM3_SUCCESS) { + uint32_t len = le24toh(ft.length); + + PrintAndLogEx(SUCCESS, "Read %u bytes from file %d", ft.fileno, len); + PrintAndLogEx(INFO, "Offset | Data | Ascii"); + PrintAndLogEx(INFO, "----------------------------------------------------------------------------"); + + for (uint32_t i = 0; i < len; i += 16) { + uint32_t l = len - i; + PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s", i, i, sprint_hex(&ft.data[i], l > 16 ? 16 : l), sprint_ascii(&ft.data[i], l > 16 ? 16 : l)); + } + } else { + PrintAndLogEx(ERR, "Couldn't read data. Error %d", res); + DropFieldDesfire(); + return res; + } + free(data); + } + DropFieldDesfire(); + return res; +} + +static int CmdHF14ADesWriteData(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfdes write", + "Write data to file\n" + "Make sure to select aid or authenticate aid before running this command.", + "hf mfdes write -n 01 -t 0 -o 000000 -d 3132333435363738" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0("n", "fileno", "", "File Number (0 - 31)"), + arg_strx0("o", "offset", "", "File Offset (3 hex bytes, big endian), optional"), + arg_strx0("d", "data", "", "Data to write (hex bytes, 256 bytes max)"), + arg_int0("t", "type", "", "File Type (0 = Standard / Backup, 1 = Record)"), + arg_strx0("a", "aid", "", "App ID to select as hex bytes (3 bytes, big endian)"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, false); + int fno = arg_get_int_def(ctx, 1, 0); + + int offsetlength = 0; + uint8_t offset[3] = {0}; + int res_offset = CLIParamHexToBuf(arg_get_str(ctx, 2), offset, 3, &offsetlength); + + // iceman: we only have a 1024 byte commandline input array. So this is pointlessly large. + // with 2char hex, 512bytes could be input. + // Instead large binary inputs should be BINARY files and written to card. + int dlength = 512; + uint8_t data[512] = {0}; + int res_data = CLIParamHexToBuf(arg_get_str(ctx, 3), data, 512, &dlength); + + int type = arg_get_int(ctx, 4); + int aidlength = 3; + uint8_t aid[3] = {0}; + CLIGetHexWithReturn(ctx, 5, aid, &aidlength); + swap24(aid); + + CLIParserFree(ctx); + + swap24(offset); + + if (type < 0 || type > 1) { + PrintAndLogEx(ERR, "Unknown type (0=Standard/Backup, 1=Record)"); + return PM3_EINVARG; + } + + if (res_data || dlength == 0) { + PrintAndLogEx(ERR, "Data needs some hex bytes to write"); + return PM3_EINVARG; + } + + if (res_offset || (offsetlength != 3 && offsetlength != 0)) { + PrintAndLogEx(ERR, "Offset needs 3 hex bytes"); + return PM3_EINVARG; + } + + if (fno > 0x1F) { + PrintAndLogEx(ERR, "File number range is invalid (exp 0 - 31), got %d", fno); + return PM3_EINVARG; + } + + mfdes_data_t ft; + + memcpy(ft.offset, offset, 3); + htole24(dlength, ft.length); + ft.fileno = fno; + + if (aidlength != 3 && aidlength != 0) { + PrintAndLogEx(ERR, _RED_(" The given aid must have 3 bytes (big endian).")); + return PM3_ESOFT; + } else if (aidlength == 0) { + if (memcmp(&tag->selected_application, aid, 3) == 0) { + PrintAndLogEx(ERR, _RED_(" You need to select an aid first.")); + return PM3_ESOFT; + } + memcpy(aid, (uint8_t *)&tag->selected_application, 3); + } + uint8_t cs = 0; + if (selectfile(aid, fno, &cs) != PM3_SUCCESS) { + PrintAndLogEx(ERR, _RED_(" Error on selecting file.")); + DropFieldDesfire(); + return PM3_ESOFT; + } + + int res = PM3_ESOFT; + ft.data = data; + res = handler_desfire_writedata(&ft, type, cs); + if (res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Successfully wrote data"); + } else { + PrintAndLogEx(ERR, "Couldn't read data. Error %d", res); + } + DropFieldDesfire(); + return res; +} + static int CmdHF14ADesTest(const char *Cmd) { DesfireTest(true); return PM3_SUCCESS; @@ -6486,7 +6486,7 @@ static command_t CommandTable[] = { {"getfilesettings", CmdHF14ADesGetFileSettings, IfPm3Iso14443a, "[new]Get file settings"}, {"chfilesettings", CmdHF14ADesChFileSettings, IfPm3Iso14443a, "[new]Change file settings"}, {"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"}, - {"read", CmdHF14ADesReadData, IfPm3Iso14443a, "Read data from standard/backup/record file"}, + {"read", CmdHF14ADesReadData, IfPm3Iso14443a, "[new]Read data from standard/backup/record file"}, {"write", CmdHF14ADesWriteData, IfPm3Iso14443a, "Write data to standard/backup/record file"}, {"value", CmdHF14ADesValueOperations, IfPm3Iso14443a, "[new]Operations with value file (get/credit/limited credit/debit/clear)"}, {"clearrecfile", CmdHF14ADesClearRecordFile, IfPm3Iso14443a, "[new]Clear record File"},