mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-20 15:26:13 +08:00
Add hf mf gload, ggetblk, gsetblk
This commit is contained in:
parent
42b48fec85
commit
876abf2818
|
@ -5,6 +5,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
- Fixed `trace list -c` - annotation of CRC bytes now is colored or squared if no ansi colors is supported (@iceman1001)
|
- Fixed `trace list -c` - annotation of CRC bytes now is colored or squared if no ansi colors is supported (@iceman1001)
|
||||||
- Fixed `trace list -t mf` - now also finds UID if anticollision is partial captured, to be used for mfkey (@iceman1001)
|
- Fixed `trace list -t mf` - now also finds UID if anticollision is partial captured, to be used for mfkey (@iceman1001)
|
||||||
|
- Added `hf mf gload, ggetblk, gsetblk` for Gen4 GTU in mifare classic mode (@DidierA)
|
||||||
|
|
||||||
## [Radium.4.15864][2022-10-29]
|
## [Radium.4.15864][2022-10-29]
|
||||||
- Changed `lf indala sim` - now accepts fc / cn (@iceman1001)
|
- Changed `lf indala sim` - now accepts fc / cn (@iceman1001)
|
||||||
|
|
|
@ -1656,6 +1656,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
MifareG4ReadBlk(payload->blockno, payload->pwd);
|
MifareG4ReadBlk(payload->blockno, payload->pwd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CMD_HF_MIFARE_G4_WRBL: {
|
||||||
|
struct p {
|
||||||
|
uint8_t blockno;
|
||||||
|
uint8_t pwd[4];
|
||||||
|
uint8_t data[16]; // data to be written
|
||||||
|
} PACKED;
|
||||||
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t keytype;
|
uint8_t keytype;
|
||||||
|
|
|
@ -2723,6 +2723,51 @@ OUT:
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data) {
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(true);
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
int retval = PM3_SUCCESS;
|
||||||
|
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||||
|
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||||
|
uint8_t *uid = BigBuf_malloc(10);
|
||||||
|
if (iso14443a_select_card(uid, NULL, NULL, true, 0, true) == false) {
|
||||||
|
retval = PM3_ESOFT;
|
||||||
|
goto OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
LED_B_ON();
|
||||||
|
uint32_t save_iso14a_timeout = iso14a_get_timeout();
|
||||||
|
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
|
||||||
|
|
||||||
|
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCD, blockno,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(cmd + 1, pwd, 4);
|
||||||
|
memcpy(cmd + 7, data, 16);
|
||||||
|
|
||||||
|
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||||
|
|
||||||
|
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||||
|
res = ReaderReceive(buf, par);
|
||||||
|
if ((res != 4) || (memcmp(buf, "\x90\x00\xfd\x07", 4) != 0)) {
|
||||||
|
retval = PM3_ESOFT;
|
||||||
|
}
|
||||||
|
iso14a_set_timeout(save_iso14a_timeout);
|
||||||
|
LED_B_OFF();
|
||||||
|
|
||||||
|
OUT:
|
||||||
|
reply_ng(CMD_HF_MIFARE_G4_WRBL, retval, buf, res);
|
||||||
|
// turns off
|
||||||
|
OnSuccessMagic();
|
||||||
|
BigBuf_free();
|
||||||
|
}
|
||||||
|
|
||||||
void MifareSetMod(uint8_t *datain) {
|
void MifareSetMod(uint8_t *datain) {
|
||||||
|
|
||||||
uint8_t mod = datain[0];
|
uint8_t mod = datain[0];
|
||||||
|
|
|
@ -58,6 +58,7 @@ void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
|
||||||
|
|
||||||
// MFC GEN4 GTU
|
// MFC GEN4 GTU
|
||||||
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd);
|
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd);
|
||||||
|
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data);
|
||||||
|
|
||||||
void MifareSetMod(uint8_t *datain);
|
void MifareSetMod(uint8_t *datain);
|
||||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||||
|
|
|
@ -1608,7 +1608,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||||
arg_lit0("a", NULL, "Input key specified is keyA (def)"),
|
arg_lit0("a", NULL, "Input key specified is keyA (def)"),
|
||||||
arg_lit0("b", NULL, "Input key specified is keyB"),
|
arg_lit0("b", NULL, "Input key specified is keyB"),
|
||||||
arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
|
arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
|
||||||
arg_lit0(NULL, "dumpkeys", "Dump found keys to file"),
|
arg_lit0(NULL, "dumpkeys", "Dump found keys to file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -1690,7 +1690,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
||||||
e_sector = calloc(SectorsCnt, sizeof(sector_t));
|
e_sector = calloc(SectorsCnt, sizeof(sector_t));
|
||||||
if (e_sector == NULL)
|
if (e_sector == NULL)
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
|
|
||||||
// add our known key
|
// add our known key
|
||||||
|
@ -6749,6 +6749,313 @@ static int CmdHF14AMfView(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read block from Gen4 GTU card
|
||||||
|
static int CmdHF14AGen4GetBlk(const char *cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mf ggetblk",
|
||||||
|
"Get block data from magic gen4 GTU card.",
|
||||||
|
"hf mf ggetblk --blk 0 --> get block 0 (manufacturer)\n"
|
||||||
|
"hf mf ggetblk --blk 3 -v --> get block 3, decode sector trailer\n"
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_int1("b", "blk", "<dec>", "block number"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
int b = arg_get_int_def(ctx, 1, 0);
|
||||||
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
|
int pwd_len = 0;
|
||||||
|
uint8_t pwd[4] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
//validate args
|
||||||
|
if (b > MIFARE_4K_MAXBLOCK) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwd_len != 4 && pwd_len != 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t blockno = (uint8_t)b;
|
||||||
|
uint8_t data[16] = {0};
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "Block: %x", blockno) ;
|
||||||
|
|
||||||
|
int res = mfG4GetBlock(pwd, blockno, data);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(ERR, "Can't read block. error=%d", res);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sector = mfSectorNum(blockno);
|
||||||
|
mf_print_sector_hdr(sector);
|
||||||
|
mf_print_block(blockno, data, verbose);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
decode_print_st(blockno, data);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load dump to Gen4 GTU card
|
||||||
|
static int CmdHF14AGen4Load(const char *cmd) {
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mf gload",
|
||||||
|
"Load magic gen4 gtu card with data from (bin/eml/json) dump file\n"
|
||||||
|
"or from emulator memory.",
|
||||||
|
"hf mf gload --emu\n"
|
||||||
|
"hf mf gload -f hf-mf-01020304.eml\n"
|
||||||
|
"hf mf gload -p AABBCCDD --4k -v -f hf-mf-01020304-dump.bin\n"
|
||||||
|
"\n"
|
||||||
|
"Card must be configured beforehand with `script run hf_mf_ultimatecard`.\n"
|
||||||
|
"Blocks are 16 bytes long."
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
|
||||||
|
arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
|
||||||
|
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
||||||
|
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
||||||
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_str0("f", "file", "<fn>", "filename of dump"),
|
||||||
|
arg_lit0(NULL, "emu", "from emulator memory"),
|
||||||
|
arg_int0(NULL, "start", "<dec>", "index of block to start writing (default 0)"),
|
||||||
|
arg_int0(NULL, "end", "<dec>", "index of block to end writing (default last block)"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
|
||||||
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
bool m0 = arg_get_lit(ctx, 1);
|
||||||
|
bool m1 = arg_get_lit(ctx, 2);
|
||||||
|
bool m2 = arg_get_lit(ctx, 3);
|
||||||
|
bool m4 = arg_get_lit(ctx, 4);
|
||||||
|
|
||||||
|
int pwd_len = 0;
|
||||||
|
uint8_t pwd[4] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 5, pwd, &pwd_len);
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(ctx, 6);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
bool fill_from_emulator = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
|
int start = arg_get_int_def(ctx, 9, 0);
|
||||||
|
int end = arg_get_int_def(ctx, 10, -1);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// validations
|
||||||
|
if (pwd_len != 4 && pwd_len != 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m0 + m1 + m2 + m4) > 1) {
|
||||||
|
PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
} else if ((m0 + m1 + m2 + m4) == 0) {
|
||||||
|
m1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char s[6];
|
||||||
|
memset(s, 0, sizeof(s));
|
||||||
|
uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
|
||||||
|
if (m0) {
|
||||||
|
block_cnt = MIFARE_MINI_MAXBLOCK;
|
||||||
|
strncpy(s, "Mini", 5);
|
||||||
|
} else if (m1) {
|
||||||
|
block_cnt = MIFARE_1K_MAXBLOCK;
|
||||||
|
strncpy(s, "1K", 3);
|
||||||
|
} else if (m2) {
|
||||||
|
block_cnt = MIFARE_2K_MAXBLOCK;
|
||||||
|
strncpy(s, "2K", 3);
|
||||||
|
} else if (m4) {
|
||||||
|
block_cnt = MIFARE_4K_MAXBLOCK;
|
||||||
|
strncpy(s, "4K", 3);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fill_from_emulator && (fnlen != 0)) {
|
||||||
|
PrintAndLogEx(WARNING, "Please specify file or emulator memory, but not both");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fill_from_emulator && (fnlen == 0)) {
|
||||||
|
PrintAndLogEx(WARNING, "Please specify file or emulator memory");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == -1) {
|
||||||
|
end = block_cnt - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < 0 || end < 0) {
|
||||||
|
PrintAndLogEx(WARNING, "start and end must be positive integers");
|
||||||
|
return PM3_EINVARG ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start > end) {
|
||||||
|
PrintAndLogEx(WARNING, "start cannot be more than end");
|
||||||
|
return PM3_EINVARG ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start >= block_cnt) {
|
||||||
|
PrintAndLogEx(WARNING, "Last block for Mifare %s is %d. Start is too high.", s, block_cnt - 1) ;
|
||||||
|
return PM3_EINVARG ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end >= block_cnt) {
|
||||||
|
PrintAndLogEx(WARNING, "Last block for Mifare %s is %d. End is too high.", s, block_cnt - 1) ;
|
||||||
|
return PM3_EINVARG ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *data = NULL;
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
|
||||||
|
if (fill_from_emulator) {
|
||||||
|
data = calloc(block_cnt * MFBLOCK_SIZE, sizeof(uint8_t));
|
||||||
|
if (data == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "downloading emulator memory");
|
||||||
|
if (!GetFromDevice(BIG_BUF_EML, data, block_cnt * MFBLOCK_SIZE, 0, NULL, 0, NULL, 2500, false)) {
|
||||||
|
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
|
||||||
|
free(data);
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// read from file
|
||||||
|
int res = pm3_load_dump(filename, (void **)&data, &bytes_read, (MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK));
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check file size corresponds to card size.
|
||||||
|
if (bytes_read != (block_cnt * MFBLOCK_SIZE)) {
|
||||||
|
PrintAndLogEx(ERR, "File content error. Read %zu bytes, expected %zu", bytes_read, block_cnt * MFBLOCK_SIZE);
|
||||||
|
if (data != NULL) free(data);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
if (fnlen != 0) {
|
||||||
|
PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
|
||||||
|
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "Read %zu blocks from emulator memory", block_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Copying to magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
|
||||||
|
PrintAndLogEx(INFO, "Starting block: %d. Ending block: %d.", start, end);
|
||||||
|
|
||||||
|
// copy to card
|
||||||
|
for (uint16_t blockno = start; blockno <= end; blockno++) {
|
||||||
|
|
||||||
|
// 4k writes can be long, so we split status each 64 block boundary.
|
||||||
|
if (blockno % 64 == 0 || blockno == start) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "" NOLF) ;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// write block
|
||||||
|
if (mfG4SetBlock(pwd, blockno, data + (blockno * MFBLOCK_SIZE)) != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(WARNING, "Can't set magic card block: %d", blockno);
|
||||||
|
PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
|
||||||
|
if (data != NULL) free(data);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "\n");
|
||||||
|
|
||||||
|
if (data != NULL) free(data);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Card loaded " _YELLOW_("%d") " blocks from %s", end - start + 1,
|
||||||
|
(fill_from_emulator ? "emulator memory" : "file"));
|
||||||
|
PrintAndLogEx(INFO, "Done!");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write block to Gen4 GTU card
|
||||||
|
static int CmdHF14AGen4SetBlk(const char *cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mf gsetblk",
|
||||||
|
"Set block data on a magic gen4 GTU card",
|
||||||
|
"hf mf gsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_int1("b", "blk", "<dec>", "block number"),
|
||||||
|
arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
|
||||||
|
arg_str0("p", "pwd", "<hex>", "password 4bytes"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, cmd, argtable, false);
|
||||||
|
|
||||||
|
int b = arg_get_int_def(ctx, 1, -1);
|
||||||
|
|
||||||
|
uint8_t data[MFBLOCK_SIZE] = {0x00};
|
||||||
|
int datalen = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 2, data, &datalen);
|
||||||
|
|
||||||
|
int pwd_len = 0;
|
||||||
|
uint8_t pwd[4] = {0};
|
||||||
|
CLIGetHexWithReturn(ctx, 3, pwd, &pwd_len);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// validations
|
||||||
|
if (pwd_len != 4 && pwd_len != 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (b < 0 || b >= MIFARE_4K_MAXBLOCK) {
|
||||||
|
PrintAndLogEx(FAILED, "target block number out-of-range, got %i", b);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datalen != MFBLOCK_SIZE) {
|
||||||
|
PrintAndLogEx(FAILED, "expected 16 bytes data, got %i", datalen);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write block
|
||||||
|
PrintAndLogEx(INFO, "Writing block number:%2d data:%s", b, sprint_hex_inrow(data, sizeof(data)));
|
||||||
|
|
||||||
|
uint8_t blockno = (uint8_t)b;
|
||||||
|
int res = mfG4SetBlock(pwd, blockno, data);
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(ERR, "Can't write block. error=%d", res);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHF14AGen4View(const char *Cmd) {
|
static int CmdHF14AGen4View(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -6813,7 +7120,6 @@ static int CmdHF14AGen4View(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, "View magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
|
PrintAndLogEx(SUCCESS, "View magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s);
|
||||||
PrintAndLogEx(INFO, "." NOLF);
|
|
||||||
|
|
||||||
// Select card to get UID/UIDLEN information
|
// Select card to get UID/UIDLEN information
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
|
@ -6850,14 +7156,20 @@ static int CmdHF14AGen4View(const char *Cmd) {
|
||||||
|
|
||||||
for (uint16_t i = 0; i < block_cnt; i++) {
|
for (uint16_t i = 0; i < block_cnt; i++) {
|
||||||
|
|
||||||
|
// 4k READs can be long, so we split status each 64 blocks.
|
||||||
|
if (i % 64 == 0) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "" NOLF) ;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
if (mfG4GetBlock(pwd, i, dump + (i * MFBLOCK_SIZE)) != PM3_SUCCESS) {
|
if (mfG4GetBlock(pwd, i, dump + (i * MFBLOCK_SIZE)) != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(WARNING, "Can't get magic card block: %u", i);
|
PrintAndLogEx(WARNING, "Can't get magic card block: %u", i);
|
||||||
PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
|
PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(NORMAL, "." NOLF);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
@ -7131,6 +7443,9 @@ static command_t CommandTable[] = {
|
||||||
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
|
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
|
||||||
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
|
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GTU") " --------------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GTU") " --------------------------"},
|
||||||
|
{"ggetblk", CmdHF14AGen4GetBlk, IfPm3Iso14443a, "Read block from card"},
|
||||||
|
{"gload", CmdHF14AGen4Load, IfPm3Iso14443a, "Load dump to card"},
|
||||||
|
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
|
||||||
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
|
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
|
||||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
||||||
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||||
|
|
|
@ -1181,6 +1181,29 @@ int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data) {
|
||||||
|
struct p {
|
||||||
|
uint8_t blockno;
|
||||||
|
uint8_t pwd[4];
|
||||||
|
uint8_t data[16];
|
||||||
|
} PACKED payload;
|
||||||
|
payload.blockno = blockno;
|
||||||
|
memcpy(payload.pwd, pwd, sizeof(payload.pwd));
|
||||||
|
memcpy(payload.data, data, sizeof(payload.data));
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_HF_MIFARE_G4_WRBL, (uint8_t *)&payload, sizeof(payload));
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_WRBL, &resp, 1500)) {
|
||||||
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
return PM3_EUNDEF;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
uint32_t cuid = 0; // uid part used for crypto1.
|
uint32_t cuid = 0; // uid part used for crypto1.
|
||||||
|
|
|
@ -96,6 +96,7 @@ int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock);
|
||||||
int mfGen3Freeze(void);
|
int mfGen3Freeze(void);
|
||||||
|
|
||||||
int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data);
|
int mfG4GetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data);
|
||||||
|
int mfG4SetBlock(uint8_t *pwd, uint8_t blockno, uint8_t *data);
|
||||||
|
|
||||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4303,6 +4303,64 @@
|
||||||
],
|
],
|
||||||
"usage": "hf mf gen3uid [-h] [-u <hex>]"
|
"usage": "hf mf gen3uid [-h] [-u <hex>]"
|
||||||
},
|
},
|
||||||
|
"hf mf ggetblk": {
|
||||||
|
"command": "hf mf ggetblk",
|
||||||
|
"description": "Get block data from magic gen4 GTU card.",
|
||||||
|
"notes": [
|
||||||
|
"hf mf ggetblk --blk 0 -> get block 0 (manufacturer)",
|
||||||
|
"hf mf ggetblk --blk 3 -v -> get block 3, decode sector trailer"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"-b, --blk <dec> block number",
|
||||||
|
"-v, --verbose verbose output",
|
||||||
|
"-p, --pwd <hex> password 4bytes"
|
||||||
|
],
|
||||||
|
"usage": "hf mf ggetblk [-hv] -b <dec> [-p <hex>]"
|
||||||
|
},
|
||||||
|
"hf mf gload": {
|
||||||
|
"command": "hf mf gload",
|
||||||
|
"description": "Load magic gen4 gtu card with data from (bin/eml/json) dump file or from emulator memory.",
|
||||||
|
"notes": [
|
||||||
|
"hf mf gload --emu",
|
||||||
|
"hf mf gload -f hf-mf-01020304.eml",
|
||||||
|
"hf mf gload -p AABBCCDD --4k -v -f hf-mf-01020304-dump.bin",
|
||||||
|
"",
|
||||||
|
"Card must be configured beforehand with `script run hf_mf_ultimatecard`.",
|
||||||
|
"Blocks are 16 bytes long."
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"--mini MIFARE Classic Mini / S20",
|
||||||
|
"--1k MIFARE Classic 1k / S50 (def)",
|
||||||
|
"--2k MIFARE Classic/Plus 2k",
|
||||||
|
"--4k MIFARE Classic 4k / S70",
|
||||||
|
"-p, --pwd <hex> password 4bytes",
|
||||||
|
"-v, --verbose verbose output",
|
||||||
|
"-f, --file <fn> filename of dump",
|
||||||
|
"--emu from emulator memory",
|
||||||
|
"--start <dec> index of block to start writing (default 0)",
|
||||||
|
"--end <dec> index of block to end writing (default last block)"
|
||||||
|
],
|
||||||
|
"usage": "hf mf gload [-hv] [--mini] [--1k] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu] --start <dec> --end <dec>"
|
||||||
|
},
|
||||||
|
"hf mf gsetblk": {
|
||||||
|
"command": "hf mf gsetblk",
|
||||||
|
"description": "Set block data on a magic gen4 GTU card",
|
||||||
|
"notes": [
|
||||||
|
"hf mf gsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"-b, --blk <dec> block number",
|
||||||
|
"-d, --data <hex> bytes to write, 16 hex bytes",
|
||||||
|
"-p, --pwd <hex> password 4bytes"
|
||||||
|
],
|
||||||
|
"usage": "hf mf gsetblk [-h] -b <dec> [-d <hex>] [-p <hex>]"
|
||||||
|
},
|
||||||
"hf mf gview": {
|
"hf mf gview": {
|
||||||
"command": "hf mf gview",
|
"command": "hf mf gview",
|
||||||
"description": "View `magic gen4 gtu` card memory",
|
"description": "View `magic gen4 gtu` card memory",
|
||||||
|
@ -11537,8 +11595,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 728,
|
"commands_extracted": 731,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2022-10-30T15:28:49"
|
"extracted_on": "2022-11-05T18:17:23"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -510,6 +510,9 @@ Check column "offline" for their availability.
|
||||||
|`hf mf gen3uid `|N |`Set UID without changing manufacturer block`
|
|`hf mf gen3uid `|N |`Set UID without changing manufacturer block`
|
||||||
|`hf mf gen3blk `|N |`Overwrite manufacturer block`
|
|`hf mf gen3blk `|N |`Overwrite manufacturer block`
|
||||||
|`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible`
|
|`hf mf gen3freeze `|N |`Perma lock UID changes. irreversible`
|
||||||
|
|`hf mf ggetblk `|N |`Read block from card`
|
||||||
|
|`hf mf gload `|N |`Load dump to card`
|
||||||
|
|`hf mf gsetblk `|N |`Write block to card`
|
||||||
|`hf mf gview `|N |`View card`
|
|`hf mf gview `|N |`View card`
|
||||||
|`hf mf ndefformat `|N |`Format MIFARE Classic Tag as NFC Tag`
|
|`hf mf ndefformat `|N |`Format MIFARE Classic Tag as NFC Tag`
|
||||||
|`hf mf ndefread `|N |`Read and print NDEF records from card`
|
|`hf mf ndefread `|N |`Read and print NDEF records from card`
|
||||||
|
|
|
@ -676,6 +676,7 @@ typedef struct {
|
||||||
|
|
||||||
// Gen 4 GTU magic cards
|
// Gen 4 GTU magic cards
|
||||||
#define CMD_HF_MIFARE_G4_RDBL 0x0860
|
#define CMD_HF_MIFARE_G4_RDBL 0x0860
|
||||||
|
#define CMD_HF_MIFARE_G4_WRBL 0x0861
|
||||||
|
|
||||||
#define CMD_UNKNOWN 0xFFFF
|
#define CMD_UNKNOWN 0xFFFF
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue