X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/46cd801c5ad5d5f60b2526b4a1e6700a2a008f7b..f53020e729d583f7975095ca7b4b467741d99edb:/client/cmdhfmfu.c?ds=sidebyside diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 0c116eb4..3b577061 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -13,7 +13,7 @@ #include "cmdhf14a.h" #include "mifare.h" #include "util.h" -#include "../common/protocols.h" +#include "protocols.h" #include "data.h" #define MAX_UL_BLOCKS 0x0f @@ -26,6 +26,9 @@ #define MAX_NTAG_213 0x2c #define MAX_NTAG_215 0x86 #define MAX_NTAG_216 0xe6 +#define MAX_MY_D_NFC 0xff +#define MAX_MY_D_MOVE 0x25 +#define MAX_MY_D_MOVE_LEAN 0x0f #define KEYS_3DES_COUNT 7 uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { @@ -54,17 +57,18 @@ uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x32,0x0C,0x16,0x17}, // PACK 0x80,0x80 -- AMiiboo (sniffed) }; -#define MAX_UL_TYPES 16 -uint16_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC}; +#define MAX_UL_TYPES 18 +uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_UL_BLOCKS}; + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; static int CmdHelp(const char *Cmd); +// get version nxp product type char *getProductTypeStr( uint8_t id){ static char buf[20]; @@ -102,17 +106,20 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ static void ul_switch_on_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + clearCommandBuffer(); SendCommand(&c); } void ul_switch_off_field(void) { UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + clearCommandBuffer(); SendCommand(&c); } static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}}; memcpy(c.d.asBytes, cmd, cmdlen); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; @@ -122,23 +129,7 @@ static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uin memcpy(response, resp.d.asBytes, resplen); return resplen; } -/* -static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength, bool append_crc ) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT , cmdlen, 0}}; - if (append_crc) - c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; - if (!resp.arg[0] && responseLength) return -1; - - uint16_t resplen = (resp.arg[0] < responseLength) ? resp.arg[0] : responseLength; - memcpy(response, resp.d.asBytes, resplen); - return resplen; -} -*/ static int ul_select( iso14a_card_select_t *card ){ ul_switch_on_field(); @@ -193,6 +184,7 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){ UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}}; memcpy(c.d.asBytes, key, 16); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) return 0; @@ -209,7 +201,6 @@ static int ulev1_requestAuthentication( uint8_t *pwd, uint8_t *pack, uint16_t pa } static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize){ - if ( hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { @@ -268,6 +259,38 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ return len; } + +// Fudan check checks for which error is given for a command with incorrect crc +// NXP UL chip responds with 01, fudan 00. +// other possible checks: +// send a0 + crc +// UL responds with 00, fudan doesn't respond +// or +// send a200 + crc +// UL doesn't respond, fudan responds with 00 +// or +// send 300000 + crc (read with extra byte(s)) +// UL responds with read of page 0, fudan doesn't respond. +// +// make sure field is off before calling this function +static int ul_fudan_check( void ){ + iso14a_card_select_t card; + if ( !ul_select(&card) ) + return UL_ERROR; + + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; + + uint8_t cmd[4] = {0x30,0x00,0x02,0xa7}; //wrong crc on purpose should be 0xa8 + memcpy(c.d.asBytes, cmd, 4); + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return UL_ERROR; + if (resp.arg[0] != 1) return UL_ERROR; + + return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP +} + static int ul_print_default( uint8_t *data){ uint8_t uid[7]; @@ -281,12 +304,12 @@ static int ul_print_default( uint8_t *data){ PrintAndLog(" UID : %s ", sprint_hex(uid, 7)); PrintAndLog(" UID[0] : %02X, %s", uid[0], getTagInfo(uid[0]) ); - if ( uid[0] == 0x05 ) { + if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ - case 0xc2: PrintAndLog(" IC type : SLE 66R04P"); break; - case 0xc4: PrintAndLog(" IC type : SLE 66R16P"); break; - case 0xc6: PrintAndLog(" IC type : SLE 66R32P"); break; + case 0xc2: PrintAndLog(" IC type : SLE 66R04P 770 Bytes"); break; //77 pages + case 0xc4: PrintAndLog(" IC type : SLE 66R16P 2560 Bytes"); break; //256 pages + case 0xc6: PrintAndLog(" IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors } } // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 @@ -327,7 +350,9 @@ static int ndef_print_CC(uint8_t *data) { PrintAndLog(" %02X : NDEF Magic Number", data[0]); PrintAndLog(" %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); PrintAndLog(" %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); - if ( data[2] == 0x12 ) + if ( data[2] == 0x96 ) + PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 48); + else if ( data[2] == 0x12 ) PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 144); else if ( data[2] == 0x3e ) PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 496); @@ -372,13 +397,17 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){ else if ( tagtype & NTAG_I2C_2K ) PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); else if ( tagtype & MY_D ) - PrintAndLog("%sTYPE : INFINEON my-d\x99", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); else if ( tagtype & MY_D_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); else if ( tagtype & MY_D_MOVE ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC", spacer); + PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); + else if ( tagtype & MY_D_MOVE_LEAN ) + PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); + else if ( tagtype & FUDAN_UL ) + PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype); return 0; @@ -612,13 +641,20 @@ uint32_t GetHF14AMfU_Type(void){ ul_switch_off_field(); } } + if (tagtype & UL) { + tagtype = ul_fudan_check(); + ul_switch_off_field(); + } } else { + ul_switch_off_field(); // Infinition MY-D tests Exam high nibble uint8_t nib = (card.uid[1] & 0xf0) >> 4; switch ( nib ){ - case 1: tagtype = MY_D; break; - case 2: tagtype = (MY_D | MY_D_NFC); break; //notice: we can not currently distinguish between these two - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //notice: we can not currently distinguish between these two + // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two + case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } @@ -856,11 +892,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ uint8_t data[16] = {0x00}; uint8_t authenticationkey[16] = {0x00}; uint8_t *authKeyPtr = authenticationkey; - - // starting with getting tagtype - TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; - + while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) @@ -892,19 +924,8 @@ int CmdHF14AMfUWrBl(const char *Cmd){ case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); - - uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) - maxblockno = UL_MEMORY_ARRAY[idx]; - } - if (blockNo < 0) { PrintAndLog("Wrong block number"); - errors = true; - } - if (blockNo > maxblockno){ - PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); errors = true; } cmdp += 2; @@ -933,7 +954,20 @@ int CmdHF14AMfUWrBl(const char *Cmd){ } if ( blockNo == -1 ) return usage_hf_mfu_wrbl(); - + // starting with getting tagtype + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + if (tagtype == UL_ERROR) return -1; + + uint8_t maxblockno = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ + if (tagtype & UL_TYPES_ARRAY[idx]) + maxblockno = UL_MEMORY_ARRAY[idx]; + } + if (blockNo > maxblockno){ + PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + return usage_hf_mfu_wrbl(); + } + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); @@ -956,6 +990,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ memcpy(c.d.asBytes+4,authKeyPtr,4); } + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -982,11 +1017,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ uint8_t data[16] = {0x00}; uint8_t authenticationkey[16] = {0x00}; uint8_t *authKeyPtr = authenticationkey; - - // starting with getting tagtype - TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; - + while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) @@ -1018,19 +1049,8 @@ int CmdHF14AMfURdBl(const char *Cmd){ case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); - - uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) - maxblockno = UL_MEMORY_ARRAY[idx]; - } - if (blockNo < 0) { PrintAndLog("Wrong block number"); - errors = true; - } - if (blockNo > maxblockno){ - PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); errors = true; } cmdp += 2; @@ -1048,8 +1068,22 @@ int CmdHF14AMfURdBl(const char *Cmd){ //Validations if(errors) return usage_hf_mfu_rdbl(); } + if ( blockNo == -1 ) return usage_hf_mfu_rdbl(); - + // start with getting tagtype + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + if (tagtype == UL_ERROR) return -1; + + uint8_t maxblockno = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ + if (tagtype & UL_TYPES_ARRAY[idx]) + maxblockno = UL_MEMORY_ARRAY[idx]; + } + if (blockNo > maxblockno){ + PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + return usage_hf_mfu_rdbl(); + } + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); @@ -1065,13 +1099,16 @@ int CmdHF14AMfURdBl(const char *Cmd){ memcpy(c.d.asBytes,authKeyPtr,4); } + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; - PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(data, 4)); + PrintAndLog("\nBlock# | Data | Ascii"); + PrintAndLog("-----------------------------"); + PrintAndLog("%02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data); } else { PrintAndLog("Failed reading block: (%02x)", isOK); @@ -1149,6 +1186,18 @@ int usage_hf_mfu_wrbl(void) { return 0; } +int usage_hf_mfu_eload(void) { + PrintAndLog("It loads emulator dump from the file `filename.eml`\n"); + PrintAndLog("Usage: hf mf eload t i \n"); + PrintAndLog(" Options:"); + PrintAndLog(" t : Tag memorysize/type"); + PrintAndLog(" i : file name w/o `.eml`"); + PrintAndLog(""); + PrintAndLog(" sample : hf mfu eload filename"); + PrintAndLog(" : hf mfu eload 4 filename"); + return 0; +} + // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. @@ -1256,6 +1305,8 @@ int CmdHF14AMfUDump(const char *Cmd){ memcpy(c.d.asBytes, authKeyPtr, dataLen); } + + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { @@ -1314,11 +1365,11 @@ int CmdHF14AMfUDump(const char *Cmd){ } } - PrintAndLog("Block# | Data |lck| Ascii"); + PrintAndLog("\nBlock# | Data |lck| Ascii"); PrintAndLog("---------------------------------"); for (i = 0; i < Pages; ++i) { if ( i < 3 ) { - PrintAndLog("%02d/0x%02X | %s | |", i, i,sprint_hex(data + i * 4, 4)); + PrintAndLog("%02d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); continue; } switch(i){ @@ -1365,7 +1416,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 43: tmplockbit = bit2[9]; break; //auth1 default: break; } - PrintAndLog("%02d/0x%02X | %s |%d| %.4s",i , i, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4); + PrintAndLog("%02d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, data+i*4); } PrintAndLog("---------------------------------"); @@ -1558,6 +1609,7 @@ int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand c = {CMD_MIFAREUC_SETPWD}; memcpy( c.d.asBytes, pwd, 16); + clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -1606,6 +1658,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ // read block2. c.cmd = CMD_MIFAREU_READBL; c.arg[0] = 2; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { PrintAndLog("Command execute timeout"); @@ -1623,6 +1676,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = uid[1]; c.d.asBytes[2] = uid[2]; c.d.asBytes[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { PrintAndLog("Command execute timeout"); @@ -1635,6 +1689,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = uid[4]; c.d.asBytes[2] = uid[5]; c.d.asBytes[3] = uid[6]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { PrintAndLog("Command execute timeout"); @@ -1647,6 +1702,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[1] = oldblock2[1]; c.d.asBytes[2] = oldblock2[2]; c.d.asBytes[3] = oldblock2[3]; + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { PrintAndLog("Command execute timeout"); @@ -1755,6 +1811,97 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ // return; // } +int CmdHF14AMfuELoad(const char *Cmd) +{ + FILE * f; + char filename[FILE_PATH_SIZE]; + char *fnameptr = filename; + char buf[64] = {0x00}; + uint8_t buf8[64] = {0x00}; + int i, len, blockNum, numBlocks; + int nameParamNo = 1; + + char ctmp = param_getchar(Cmd, 0); + + if ( ctmp == 'h' || ctmp == 0x00) { + return usage_hf_mfu_eload(); + } +/* + switch (ctmp) { + case '0' : numBlocks = 5*4; break; + case '1' : + case '\0': numBlocks = 16*4; break; + case '2' : numBlocks = 32*4; break; + case '4' : numBlocks = 256; break; + default: { + numBlocks = 16*4; + nameParamNo = 0; + } + } + + len = param_getstr(Cmd,nameParamNo,filename); + + if (len > FILE_PATH_SIZE - 4) len = FILE_PATH_SIZE - 4; + + fnameptr += len; + + sprintf(fnameptr, ".eml"); + + // open file + f = fopen(filename, "r"); + if (f == NULL) { + PrintAndLog("File %s not found or locked", filename); + return 1; + } + + blockNum = 0; + while(!feof(f)){ + memset(buf, 0, sizeof(buf)); + + if (fgets(buf, sizeof(buf), f) == NULL) { + + if (blockNum >= numBlocks) break; + + PrintAndLog("File reading error."); + fclose(f); + return 2; + } + + if (strlen(buf) < 32){ + if(strlen(buf) && feof(f)) + break; + PrintAndLog("File content error. Block data must include 32 HEX symbols"); + fclose(f); + return 2; + } + + for (i = 0; i < 32; i += 2) { + sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); + } + + if (mfEmlSetMem(buf8, blockNum, 1)) { + PrintAndLog("Cant set emul block: %3d", blockNum); + fclose(f); + return 3; + } + printf("."); + blockNum++; + + if (blockNum >= numBlocks) break; + } + fclose(f); + printf("\n"); + + if ((blockNum != numBlocks)) { + PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks); + return 4; + } + PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename); + */ + return 0; +} + + //------------------------------------ // Menu Stuff //------------------------------------ @@ -1765,7 +1912,8 @@ static command_t CommandTable[] = {"info", CmdHF14AMfUInfo, 0, "Tag information"}, {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, {"rdbl", CmdHF14AMfURdBl, 0, "Read block"}, - {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, + {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, + {"eload", CmdHF14AMfuELoad, 0, "Load from file emulator dump"}, {"cauth", CmdHF14AMfucAuth, 0, "Authentication - Ultralight C"}, {"setpwd", CmdHF14AMfucSetPwd, 1, "Set 3des password - Ultralight-C"}, {"setuid", CmdHF14AMfucSetUid, 1, "Set UID - MAGIC tags only"},