Merge branch 'master' into mf-supercard

Signed-off-by: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com>
This commit is contained in:
AloneLiberty 2023-04-03 21:45:32 +00:00 committed by GitHub
commit 2b248e03e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 180 additions and 91 deletions

View file

@ -4,6 +4,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased] ## [unreleased][unreleased]
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty) - Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
- Added iClass credit key to default iClass key table and reorganized key order (@GuruSteve)
- Changed `hf mf value` - ability to use transfer on different block (@AloneLiberty)
- Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001) - Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001) - Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001) - Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)

View file

@ -1584,7 +1584,7 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_HF_MIFARE_VALUE: { case CMD_HF_MIFARE_VALUE: {
MifareValue(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); MifareValue(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break; break;
} }
case CMD_HF_MIFAREU_WRITEBL: { case CMD_HF_MIFAREU_WRITEBL: {

View file

@ -1053,6 +1053,30 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// some first pages of UL/NTAG dump is special data // some first pages of UL/NTAG dump is special data
mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr();
*pages = MAX(mfu_header->pages, 15); *pages = MAX(mfu_header->pages, 15);
// counters and tearing flags
// for old dumps with all zero headers, we need to set default values.
for (uint8_t i = 0; i < 3; i++) {
counters[i] = le24toh(mfu_header->counter_tearing[i]);
if (mfu_header->counter_tearing[i][3] != 0x00) {
tearings[i] = mfu_header->counter_tearing[i][3];
}
}
// GET_VERSION
if (memcmp(mfu_header->version, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) {
memcpy(rVERSION, "\x00\x04\x04\x02\x01\x00\x11\x03", 8);
} else {
memcpy(rVERSION, mfu_header->version, 8);
}
AddCrc14A(rVERSION, sizeof(rVERSION) - 2);
// READ_SIG
memcpy(rSIGN, mfu_header->signature, 32);
AddCrc14A(rSIGN, sizeof(rSIGN) - 2);
} }
break; break;
case 3: { // MIFARE DESFire case 3: { // MIFARE DESFire
@ -2577,7 +2601,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
uint8_t fudan_read[] = { 0x30, 0x01, 0x8B, 0xB9}; uint8_t fudan_read[] = { 0x30, 0x01, 0x8B, 0xB9};
ReaderTransmit(fudan_read, sizeof(fudan_read), NULL); ReaderTransmit(fudan_read, sizeof(fudan_read), NULL);
if (!ReaderReceive(resp, resp_par)) { if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to select all"); if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to select all");
return 0; return 0;
} }
@ -2626,7 +2650,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
// SELECT_ALL // SELECT_ALL
ReaderTransmit(sel_all, sizeof(sel_all), NULL); ReaderTransmit(sel_all, sizeof(sel_all), NULL);
if (!ReaderReceive(resp, resp_par)) { if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1); if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1);
return 0; return 0;
} }
@ -2704,7 +2728,7 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint
// Receive the SAK // Receive the SAK
if (!ReaderReceive(resp, resp_par)) { if (!ReaderReceive(resp, resp_par)) {
Dbprintf("Card didn't answer to select"); if (g_dbglevel >= DBG_INFO) Dbprintf("Card didn't answer to select");
return 0; return 0;
} }
sak = resp[0]; sak = resp[0];

View file

@ -642,21 +642,28 @@ OUT:
} }
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) { void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
// params // params
uint8_t blockNo = arg0; uint8_t blockNo = arg0;
uint8_t keyType = arg1; uint8_t keyType = arg1;
uint8_t transferKeyType = arg2;
uint64_t ui64Key = 0; uint64_t ui64Key = 0;
uint64_t transferUi64Key = 0;
uint8_t blockdata[16] = {0x00}; uint8_t blockdata[16] = {0x00};
ui64Key = bytes_to_num(datain, 6); ui64Key = bytes_to_num(datain, 6);
memcpy(blockdata, datain + 10, 16); memcpy(blockdata, datain + 11, 16);
transferUi64Key = bytes_to_num(datain + 27, 6);
// variables // variables
uint8_t action = datain[9]; uint8_t action = datain[9];
uint8_t transferBlk = datain[10];
bool needAuth = datain[33];
uint8_t isOK = 0; uint8_t isOK = 0;
uint8_t uid[10] = {0x00}; uint8_t uid[10] = {0x00};
uint32_t cuid = 0; uint32_t cuid = 0;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t len = 0;
struct Crypto1State mpcs = {0, 0}; struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs; struct Crypto1State *pcs;
pcs = &mpcs; pcs = &mpcs;
@ -686,6 +693,21 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
break; break;
}; };
if (needAuth) {
// transfer to other sector
if (mifare_classic_auth(pcs, cuid, transferBlk, transferKeyType, transferUi64Key, AUTH_NESTED)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Nested auth error");
break;
}
}
// send transfer (commit the change)
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_TRANSFER, (transferBlk != 0) ? transferBlk : blockNo, receivedAnswer, NULL, NULL);
if (len != 1 && receivedAnswer[0] != 0x0A) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error in transfer: %02x", receivedAnswer[0]);
break;
}
if (mifare_classic_halt(pcs, cuid)) { if (mifare_classic_halt(pcs, cuid)) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error"); if (g_dbglevel >= DBG_ERROR) Dbprintf("Halt error");
break; break;
@ -1334,10 +1356,13 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
LED_C_ON(); LED_C_ON();
// get crypted nonces for target sector // get crypted nonces for target sector
for (i = 0; i < 2 && !isOK; i++) { // look for exactly two different nonces for (i = 0; ((i < 2) && (isOK == PM3_SUCCESS)); i++) {
// look for exactly two different nonces
target_nt[i] = 0; target_nt[i] = 0;
while (target_nt[i] == 0) { // continue until we have an unambiguous nonce // continue until we have an unambiguous nonce
while (target_nt[i] == 0) {
// Test if the action was cancelled // Test if the action was cancelled
if (BUTTON_PRESS() || data_available()) { if (BUTTON_PRESS() || data_available()) {
@ -1351,7 +1376,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
continue; continue;
} }
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card"); if (g_dbglevel >= DBG_INFO) Dbprintf("Nested: Can't select card");
continue; continue;
}; };
@ -1430,6 +1455,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
memcpy(payload.nt_b, &target_nt[1], 4); memcpy(payload.nt_b, &target_nt[1], 4);
memcpy(payload.ks_b, &target_ks[1], 4); memcpy(payload.ks_b, &target_ks[1], 4);
LED_B_ON();
reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
@ -1475,7 +1501,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
continue; continue;
}; };
// first colleciton // first collection
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
continue; continue;
}; };
@ -1497,7 +1523,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
nt2 = bytes_to_num(receivedAnswer, 4); nt2 = bytes_to_num(receivedAnswer, 4);
target_ks[0] = nt2 ^ target_nt[0]; target_ks[0] = nt2 ^ target_nt[0];
// second colleciton // second collection
if (mifare_classic_halt(pcs, cuid)) { if (mifare_classic_halt(pcs, cuid)) {
continue; continue;
@ -2052,7 +2078,6 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
uint64_t key = 0; uint64_t key = 0;
uint32_t cuid = 0; uint32_t cuid = 0;
int i, res;
uint8_t cascade_levels = 0; uint8_t cascade_levels = 0;
struct { struct {
uint8_t key[6]; uint8_t key[6];
@ -2091,12 +2116,12 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
set_tracing(false); set_tracing(false);
for (i = 0; i < key_count; i++) { for (uint16_t i = 0; i < key_count; i++) {
// Iceman: use piwi's faster nonce collecting part in hardnested. // Iceman: use piwi's faster nonce collecting part in hardnested.
if (!have_uid) { // need a full select cycle to get the uid first if (have_uid == false) { // need a full select cycle to get the uid first
iso14a_card_select_t card_info; iso14a_card_select_t card_info;
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == false) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)"); if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)");
--i; // try same key once again --i; // try same key once again
continue; continue;
@ -2116,7 +2141,7 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
} }
have_uid = true; have_uid = true;
} else { // no need for anticollision. We can directly select the card } else { // no need for anticollision. We can directly select the card
if (!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) { if (iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true) == false) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)"); if (g_dbglevel >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)");
--i; // try same key once again --i; // try same key once again
continue; continue;
@ -2124,12 +2149,10 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
} }
key = bytes_to_num(datain + i * 6, 6); key = bytes_to_num(datain + i * 6, 6);
res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST); if (mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST)) {
// CHK_TIMEOUT(); // CHK_TIMEOUT();
if (res)
continue; continue;
}
memcpy(keyresult.key, datain + i * 6, 6); memcpy(keyresult.key, datain + i * 6, 6);
keyresult.found = true; keyresult.found = true;
@ -2137,14 +2160,12 @@ void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
} }
LED_B_ON(); LED_B_ON();
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_CHKKEYS, PM3_SUCCESS, (uint8_t *)&keyresult, sizeof(keyresult)); reply_ng(CMD_HF_MIFARE_CHKKEYS, PM3_SUCCESS, (uint8_t *)&keyresult, sizeof(keyresult));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();
set_tracing(false); set_tracing(false);
crypto1_deinit(pcs);
g_dbglevel = oldbg; g_dbglevel = oldbg;
} }

View file

@ -26,7 +26,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);

View file

@ -533,6 +533,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
if (action == 0x01) if (action == 0x01)
command = MIFARE_CMD_DEC; command = MIFARE_CMD_DEC;
if (action == 0x02)
command = MIFARE_CMD_RESTORE;
// Send increment or decrement command // Send increment or decrement command
len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL); len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL);
@ -567,13 +569,6 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
return 2; return 2;
} }
} else {
// send trnasfer (commit the change)
len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_TRANSFER, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
}
} }
return 0; return 0;

View file

@ -63,9 +63,9 @@ static void printIclassSIO(uint8_t *iclass_dump);
static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = {
{ 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 }, { 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 },
{ 0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00 }, { 0xFD, 0xCB, 0x5A, 0x52, 0xEA, 0x8F, 0x30, 0x90 },
{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 }, { 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x76, 0x65, 0x54, 0x43, 0x32, 0x21, 0x10, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },

View file

@ -7899,6 +7899,7 @@ static int CmdHF14AMfValue(const char *Cmd) {
"hf mf value --blk 16 -k FFFFFFFFFFFF --inc 10\n" "hf mf value --blk 16 -k FFFFFFFFFFFF --inc 10\n"
"hf mf value --blk 16 -k FFFFFFFFFFFF -b --dec 10\n" "hf mf value --blk 16 -k FFFFFFFFFFFF -b --dec 10\n"
"hf mf value --blk 16 -k FFFFFFFFFFFF -b --get\n" "hf mf value --blk 16 -k FFFFFFFFFFFF -b --get\n"
"hf mf value --blk 16 -k FFFFFFFFFFFF --res --transfer 30 --tk FFFFFFFFFFFF --> transfer block 16 value to block 30 (even if block can't be incremented by ACL)\n"
"hf mf value --get -d 87D612007829EDFF87D6120011EE11EE\n" "hf mf value --get -d 87D612007829EDFF87D6120011EE11EE\n"
); );
void *argtable[] = { void *argtable[] = {
@ -7906,17 +7907,22 @@ static int CmdHF14AMfValue(const char *Cmd) {
arg_str0("k", "key", "<hex>", "key, 6 hex bytes"), arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
arg_lit0("a", NULL, "input key type is key A (def)"), arg_lit0("a", NULL, "input key type is key A (def)"),
arg_lit0("b", NULL, "input key type is key B"), arg_lit0("b", NULL, "input key type is key B"),
arg_u64_0(NULL, "inc", "<dec>", "Incremenet value by X (0 - 2147483647)"), arg_u64_0(NULL, "inc", "<dec>", "Increment value by X (0 - 2147483647)"),
arg_u64_0(NULL, "dec", "<dec>", "Dcrement value by X (0 - 2147483647)"), arg_u64_0(NULL, "dec", "<dec>", "Decrement value by X (0 - 2147483647)"),
arg_u64_0(NULL, "set", "<dec>", "Set value to X (-2147483647 - 2147483647)"), arg_u64_0(NULL, "set", "<dec>", "Set value to X (-2147483647 - 2147483647)"),
arg_u64_0(NULL, "transfer", "<dec>", "Transfer value to other block (after inc/dec/restore)"),
arg_str0(NULL, "tkey", "<hex>", "transfer key, 6 hex bytes (if transfer is preformed to other sector)"),
arg_lit0(NULL, "ta", "transfer key type is key A (def)"),
arg_lit0(NULL, "tb", "transfer key type is key B"),
arg_lit0(NULL, "get", "Get value from block"), arg_lit0(NULL, "get", "Get value from block"),
arg_lit0(NULL, "res", "Restore (copy value to card buffer, should be used with --transfer)"),
arg_int0(NULL, "blk", "<dec>", "block number"), arg_int0(NULL, "blk", "<dec>", "block number"),
arg_str0("d", "data", "<hex>", "block data to extract values from (16 hex bytes)"), arg_str0("d", "data", "<hex>", "block data to extract values from (16 hex bytes)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
uint8_t blockno = (uint8_t)arg_get_int_def(ctx, 8, 1); uint8_t blockno = (uint8_t)arg_get_int_def(ctx, 13, 1);
uint8_t keytype = MF_KEY_A; uint8_t keytype = MF_KEY_A;
if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) { if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) {
@ -7927,29 +7933,44 @@ static int CmdHF14AMfValue(const char *Cmd) {
keytype = MF_KEY_B;; keytype = MF_KEY_B;;
} }
uint8_t transferkeytype = MF_KEY_A;
if (arg_get_lit(ctx, 9) && arg_get_lit(ctx, 10)) {
CLIParserFree(ctx);
PrintAndLogEx(WARNING, "Input key type must be A or B");
return PM3_EINVARG;
} else if (arg_get_lit(ctx, 10)) {
keytype = MF_KEY_B;;
}
int keylen = 0; int keylen = 0;
uint8_t key[6] = {0}; uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 1, key, &keylen); CLIGetHexWithReturn(ctx, 1, key, &keylen);
int transferkeylen = 0;
uint8_t transferkey[6] = {0};
CLIGetHexWithReturn(ctx, 8, transferkey, &transferkeylen);
/* /*
Value /Value Value BLK /BLK BLK /BLK Value /Value Value BLK /BLK BLK /BLK
00000000 FFFFFFFF 00000000 10 EF 10 EF 00000000 FFFFFFFF 00000000 10 EF 10 EF
BLK is used to referece where the backup come from, I suspect its just the current block for the actual value ? BLK is used to reference where the backup come from, I suspect it's just the current block for the actual value ?
increment and decrement are an unsigned value increment and decrement are an unsigned value
set value is a signed value set value is a signed value
We are getting signed and/or bigger values to allow a defult to be set meaning users did not supply that option. We are getting signed and/or bigger values to allow a default to be set meaning users did not supply that option.
*/ */
int64_t incval = (int64_t)arg_get_u64_def(ctx, 4, -1); // Inc by -1 is invalid, so not set. int64_t incval = (int64_t)arg_get_u64_def(ctx, 4, -1); // Inc by -1 is invalid, so not set.
int64_t decval = (int64_t)arg_get_u64_def(ctx, 5, -1); // Inc by -1 is invalid, so not set. int64_t decval = (int64_t)arg_get_u64_def(ctx, 5, -1); // Dec by -1 is invalid, so not set.
int64_t setval = (int64_t)arg_get_u64_def(ctx, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set int64_t setval = (int64_t)arg_get_u64_def(ctx, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set
bool getval = arg_get_lit(ctx, 7); int64_t trnval = (int64_t)arg_get_u64_def(ctx, 7, -1); // block to transfer to
bool getval = arg_get_lit(ctx, 11);
bool resval = arg_get_lit(ctx, 12);
int dlen = 0; int dlen = 0;
uint8_t data[16] = {0}; uint8_t data[16] = {0};
CLIGetHexWithReturn(ctx, 9, data, &dlen); CLIGetHexWithReturn(ctx, 14, data, &dlen);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t action = 3; // 0 Increment, 1 - Decrement, 2 - Set, 3 - Get, 4 - Decode from data uint8_t action = 4; // 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
uint32_t value = 0; uint32_t value = 0;
// Need to check we only have 1 of inc/dec/set and get the value from the selected option // Need to check we only have 1 of inc/dec/set and get the value from the selected option
@ -7977,7 +7998,7 @@ static int CmdHF14AMfValue(const char *Cmd) {
if (setval != 0x7FFFFFFFFFFFFFFF) { if (setval != 0x7FFFFFFFFFFFFFFF) {
optionsprovided++; optionsprovided++;
action = 2; action = 3;
if ((setval < -2147483647) || (setval > 2147483647)) { if ((setval < -2147483647) || (setval > 2147483647)) {
PrintAndLogEx(WARNING, "set value must be between -2147483647 and 2147483647. Got %lli", setval); PrintAndLogEx(WARNING, "set value must be between -2147483647 and 2147483647. Got %lli", setval);
return PM3_EINVARG; return PM3_EINVARG;
@ -7985,9 +8006,19 @@ static int CmdHF14AMfValue(const char *Cmd) {
value = (uint32_t)setval; value = (uint32_t)setval;
} }
if (resval) {
if (trnval == -1) {
PrintAndLogEx(WARNING, "You can't use restore without using transfer");
return PM3_EINVARG;
}
optionsprovided++;
action = 2;
}
if (dlen != 0) { if (dlen != 0) {
optionsprovided++; optionsprovided++;
action = 4; action = 5;
if (dlen != 16) { if (dlen != 16) {
PrintAndLogEx(WARNING, "date length must be 16 hex bytes long, got %d", dlen); PrintAndLogEx(WARNING, "date length must be 16 hex bytes long, got %d", dlen);
return PM3_EINVARG; return PM3_EINVARG;
@ -7999,34 +8030,52 @@ static int CmdHF14AMfValue(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
// dont want to write value data and break something if (trnval != -1 && action > 2) {
if ((blockno == 0) || (mfIsSectorTrailer(blockno))) { PrintAndLogEx(WARNING, "You can't use transfer without using --inc, --dec or --res");
PrintAndLogEx(WARNING, "invlaid block number, should be a data block ");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (action < 3) { if (trnval != -1 && transferkeylen == 0 && mfSectorNum(trnval) != mfSectorNum(blockno)) {
PrintAndLogEx(WARNING, "Transfer is preformed to other sector, but no key for new sector provided");
return PM3_EINVARG;
}
// don't want to write value data and break something
if ((blockno == 0) || (mfIsSectorTrailer(blockno)) || (trnval == 0) || (trnval != -1 && mfIsSectorTrailer(trnval))) {
PrintAndLogEx(WARNING, "invalid block number, should be a data block");
return PM3_EINVARG;
}
if (action < 4) {
uint8_t isok = true;
if (g_session.pm3_present == false) if (g_session.pm3_present == false)
return PM3_ENOTTY; return PM3_ENOTTY;
// 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
if (action <= 1) { // increment/decrement value if (action <= 2) { // increment/decrement/restore value
uint8_t block[MFBLOCK_SIZE] = {0x00}; uint8_t block[MFBLOCK_SIZE] = {0x00};
memcpy(block, (uint8_t *)&value, 4); memcpy(block, (uint8_t *)&value, 4);
uint8_t cmddata[26]; uint8_t cmddata[34];
memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec memcpy(cmddata, key, sizeof(key)); // Key == 6 data went to 10, so lets offset 9 for inc/dec
if (action == 0) if (action == 0)
PrintAndLogEx(INFO, "value increment by : %d", value); PrintAndLogEx(INFO, "Value incremented by : %d", value);
else if (action == 1)
PrintAndLogEx(INFO, "value decrement by : %d", value); PrintAndLogEx(INFO, "Value decremented by : %d", value);
cmddata[9] = action; // 00 if increment, 01 if decrement, 02 if restore
if (trnval != -1) {
cmddata[10] = trnval; // transfer to block
memcpy(cmddata + 27, transferkey, sizeof(transferkey));
if (mfSectorNum(trnval) != mfSectorNum(blockno))
cmddata[33] = 1; // should send nested auth
PrintAndLogEx(INFO, "Transfer block no %d to block %d", blockno, trnval);
} else {
cmddata[10] = 0;
PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key))); PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
}
cmddata[9] = action; // 00 if increment, 01 if decrement. memcpy(cmddata + 11, block, sizeof(block));
memcpy(cmddata + 10, block, sizeof(block));
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_VALUE, blockno, keytype, 0, cmddata, sizeof(cmddata)); SendCommandMIX(CMD_HF_MIFARE_VALUE, blockno, keytype, transferkeytype, cmddata, sizeof(cmddata));
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
@ -8034,14 +8083,7 @@ static int CmdHF14AMfValue(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
if (resp.oldarg[0] & 0xFF) { isok = resp.oldarg[0] & 0xff;
// all ok so set flag to read current value
getval = true;
PrintAndLogEx(SUCCESS, "Update ( " _GREEN_("success") " )");
} else {
PrintAndLogEx(FAILED, "Update ( " _RED_("failed") " )");
}
} else { // set value } else { // set value
// To set a value block (or setup) we can use the normal mifare classic write block // To set a value block (or setup) we can use the normal mifare classic write block
// So build the command options can call CMD_HF_MIFARE_WRITEBL // So build the command options can call CMD_HF_MIFARE_WRITEBL
@ -8066,17 +8108,15 @@ static int CmdHF14AMfValue(const char *Cmd) {
PrintAndLogEx(FAILED, "Command execute timeout"); PrintAndLogEx(FAILED, "Command execute timeout");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
int status = resp.oldarg[0];
if (status) { isok = resp.oldarg[0] & 0xff;
// all ok so set flag to read current value
getval = true;
PrintAndLogEx(SUCCESS, "Update ( " _GREEN_("success") " )");
} else if (status == PM3_ETEAROFF) {
// all ok so set flag to read current value
getval = true;
} else {
PrintAndLogEx(FAILED, "Update ( " _RED_("failed") " )");
} }
if (isok) {
PrintAndLogEx(SUCCESS, "Update ... : " _GREEN_("success"));
getval = true; // all ok so set flag to read current value
} else {
PrintAndLogEx(FAILED, "Update ... : " _RED_("failed"));
} }
} }
@ -8085,10 +8125,17 @@ static int CmdHF14AMfValue(const char *Cmd) {
int32_t readvalue; int32_t readvalue;
int res = -1; int res = -1;
if (action == 4) { if (action == 5) {
res = PM3_SUCCESS; // alread have data from command line res = PM3_SUCCESS; // already have data from command line
} else { } else {
if (trnval == -1) {
res = mfReadBlock(blockno, keytype, key, data); res = mfReadBlock(blockno, keytype, key, data);
} else {
if (mfSectorNum(trnval) != mfSectorNum(blockno))
res = mfReadBlock(trnval, transferkeytype, transferkey, data);
else
res = mfReadBlock(trnval, keytype, key, data);
}
} }
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {