diff --git a/armsrc/appmain.c b/armsrc/appmain.c index d9162dda8..e9c34e2cc 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -73,8 +73,8 @@ extern uint32_t _stack_start, _stack_end; struct common_area common_area __attribute__((section(".commonarea"))); static int button_status = BUTTON_NO_CLICK; static bool allow_send_wtx = false; -static uint16_t tearoff_delay_us = 0; -static bool tearoff_enabled = false; +uint16_t tearoff_delay_us = 0; +bool tearoff_enabled = false; int tearoff_hook(void) { if (tearoff_enabled) { diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 4d5975324..e149254f7 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1881,7 +1881,7 @@ void iClass_WriteBlock(uint8_t *msg) { iclass_send_as_reader(write, write_len, &start_time, &eof_time); - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred res = false; switch_off(); if (payload->req.send_reply) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index cd07a4007..1509cc80c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2972,7 +2972,7 @@ void ReaderIso14443a(PacketCommandNG *c) { } } - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred FpgaDisableTracing(); reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); } else { diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 09c5e775e..c747a0e27 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -2092,7 +2092,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time); - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred FpgaDisableTracing(); reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0); } else { diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index de7a409bd..66539c807 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1477,7 +1477,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred res = PM3_ETEAROFF; @@ -1598,7 +1598,7 @@ void ReaderIso15693(uint32_t parameter) { uint32_t eof_time; int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - if (recvlen == PM3_ETEAROFF) { // tearoff occured + if (recvlen == PM3_ETEAROFF) { // tearoff occurred reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); } else { @@ -1928,7 +1928,7 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint uint32_t start_time = 0; int recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time); - if (recvlen == PM3_ETEAROFF) { // tearoff occured + if (recvlen == PM3_ETEAROFF) { // tearoff occurred reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); } else { diff --git a/armsrc/lfops.c b/armsrc/lfops.c index b4daed774..9555e59c1 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2639,7 +2639,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { SendForward(len, false); - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred StopTicks(); reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0); } else { @@ -2681,7 +2681,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) { SendForward(len, false); - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred StopTicks(); reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0); } else { diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 2ea7aa1b8..bcb47aa24 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2713,20 +2713,15 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) { // // Tear-off attack against MFU. // - Moebius et al -void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain) { +void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *data_testwrite) { uint8_t blockNo = blno; - uint8_t data_fullwrite[4] = {0x00}; - uint8_t data_testwrite[4] = {0x00}; - memcpy(data_fullwrite, datain, 4); - memcpy(data_testwrite, datain + 4, 4); if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off"); if (tearoff_time > 43000) tearoff_time = 43000; - - MifareUWriteBlockEx(blockNo, 0, data_fullwrite, false); - + tearoff_delay_us = tearoff_time; + tearoff_enabled = true; LEDsoff(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -2750,15 +2745,9 @@ void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain) { return; }; // send - ReaderTransmit(cmd, sizeof(cmd), NULL); - - // Wait before cutting power. aka tear-off LED_D_ON(); - - SpinDelayUsPrecision(tearoff_time); - if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!")); - switch_off(); - + ReaderTransmit(cmd, sizeof(cmd), NULL); + tearoff_hook(); reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0); } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 4e4f5c6f4..9488378fd 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -3102,7 +3102,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { "hf mfu otptear -b 3 -i 100 -s 1000\n" "hf mfu otptear -b 3 -i 1 -e 200\n" "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE\n" - "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000 -> quite when OTP is reset" + "hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000 -> quit when OTP is reset" ); void *argtable[] = { @@ -3112,7 +3112,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { arg_u64_0("e", "end", "", "end time (def 3000 us)"), arg_u64_0("s", "start", "", "start time (def 0 us)"), arg_str0("d", "data", "", "initialise data before run (4 bytes)"), - arg_str0("t", "test", "", "test write data (4 bytes)"), + arg_str0("t", "test", "", "test write data (4 bytes, 00000000 by default)"), arg_str0("m", "match", "", "exit criteria, if block matches this value (4 bytes)"), arg_param_end }; @@ -3126,6 +3126,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { int d_len = 0; uint8_t data[4] = {0x00}; CLIGetHexWithReturn(ctx, 5, data, &d_len); + bool use_data = (d_len > 0); int t_len = 0; uint8_t test[4] = {0x00}; @@ -3150,7 +3151,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { return PM3_EINVARG; } if (start > (end - steps)) { - PrintAndLogEx(WARNING, "Start time larger then (end time + steps)"); + PrintAndLogEx(WARNING, "Start time larger than (end time + steps)"); return PM3_EINVARG; } @@ -3169,26 +3170,34 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { return PM3_EINVARG; } - uint8_t teardata[8] = {0x00}; - memcpy(teardata, data, sizeof(data)); - memcpy(teardata + sizeof(data), test, sizeof(test)); + uint8_t teardata[4] = {0x00}; + memcpy(teardata, test, sizeof(test)); PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Tear off") " ---------------------"); PrintAndLogEx(INFO, "Starting Tear-off test"); PrintAndLogEx(INFO, "Target block no: %u", blockno); - PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(teardata, 4)); - PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata + 4, 4)); + if (use_data) { + PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(data, 4)); + } + PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata, 4)); + if (use_match) { + PrintAndLogEx(INFO, "Target match block data : %s", sprint_hex_inrow(match, 4)); + } PrintAndLogEx(INFO, "----------------------------------------------------"); uint8_t isOK; - bool got_pre = false, got_post = false, lock_on = false; + bool lock_on = false; uint8_t pre[4] = {0}; uint8_t post[4] = {0}; uint32_t current = start; - int phase_clear = -1; - int phase_newwr = -1; + int phase_begin_clear = -1; + int phase_end_clear = -1; + int phase_begin_newwr = -1; + int phase_end_newwr = -1; + bool skip_phase1 = false; uint8_t retries = 0; + uint8_t error_retries = 0; - while (current <= (end - steps)) { + while ((current <= (end - steps)) && (error_retries < 10)) { if (kbd_enter_pressed()) { PrintAndLogEx(INFO, "\naborted via keyboard!\n"); @@ -3198,10 +3207,27 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", current); clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0); PacketResponseNG resp; - got_pre = false; + if (use_data) { + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockno, 0, 0, data, d_len); + bool got_written = false; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + isOK = resp.oldarg[0] & 0xff; + if (isOK) { + got_written = true; + } + } + if (! got_written) { + PrintAndLogEx(FAILED, "Failed to write block BEFORE"); + error_retries++; + continue; // try again + } + } + + SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0); + + bool got_pre = false; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { isOK = resp.oldarg[0] & 0xFF; if (isOK) { @@ -3209,9 +3235,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { got_pre = true; } } - + if (! got_pre) { + PrintAndLogEx(FAILED, "Failed to read block BEFORE"); + error_retries++; + continue; // try again + } clearCommandBuffer(); - SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockno, current, 0, teardata, 8); + SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockno, current, 0, teardata, sizeof(teardata)); // we be getting ACK that we are silently ignoring here.. @@ -3222,10 +3252,11 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { if (resp.status != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Tear off reporting failure to select tag"); + error_retries++; continue; } - got_post = false; + bool got_post = false; clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { @@ -3235,55 +3266,53 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { got_post = true; } } + if (! got_post) { + PrintAndLogEx(FAILED, "Failed to read block BEFORE"); + error_retries++; + continue; // try again + } + error_retries = 0; + char prestr[20] = {0}; + snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre))); + char poststr[20] = {0}; + snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post))); - if (got_pre && got_post) { - - char prestr[20] = {0}; - snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre))); - char poststr[20] = {0}; - snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post))); - - if (memcmp(pre, post, sizeof(pre)) == 0) { - - PrintAndLogEx(INFO, "Current %02d (0x%02X) %s" - , blockno - , blockno - , poststr - ); - } else { - - // skip first message, since its the reset write. - if (current == start) { - PrintAndLogEx(INFO, "Inital write"); - } else { - PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %02d (0x%02X) %s vs " _RED_("%s") - , blockno - , blockno - , prestr - , poststr - ); - - lock_on = true; - - if (phase_clear == -1) - phase_clear = current; - - // new write phase must be atleast 100us later.. - if (phase_clear > -1 && phase_newwr == -1 && current > (phase_clear + 100)) - phase_newwr = current; - } - } - - if (use_match && memcmp(pre, match, sizeof(pre)) == 0) { - PrintAndLogEx(SUCCESS, "Block matches!\n"); - break; - } + if (memcmp(pre, post, sizeof(pre)) == 0) { + PrintAndLogEx(INFO, "Current : %02d (0x%02X) %s" + , blockno + , blockno + , poststr + ); } else { - if (got_pre == false) - PrintAndLogEx(FAILED, "Failed to read block BEFORE"); - if (got_post == false) - PrintAndLogEx(FAILED, "Failed to read block AFTER"); + PrintAndLogEx(INFO, _CYAN_("Tear off occurred") " : %02d (0x%02X) %s => " _RED_("%s") + , blockno + , blockno + , prestr + , poststr + ); + + lock_on = true; + + if ((phase_begin_clear == -1) && (bitcount32(*(uint32_t*)pre) > bitcount32(*(uint32_t*)post))) + phase_begin_clear = current; + + if ((phase_begin_clear > -1) && (phase_end_clear == -1) && (bitcount32(*(uint32_t*)post) == 0)) + phase_end_clear = current; + + if ((current == start) && (phase_end_clear > -1)) + skip_phase1 = true; + // new write phase must be atleast 100us later.. + if (((bitcount32(*(uint32_t*)pre) == 0) || (phase_end_clear > -1)) && (phase_begin_newwr == -1) && (bitcount32(*(uint32_t*)post) != 0) && (skip_phase1 || (current > (phase_end_clear + 100)))) + phase_begin_newwr = current; + + if ((phase_begin_newwr > -1) && (phase_end_newwr == -1) && (memcmp(post, teardata, sizeof(teardata)) == 0)) + phase_end_newwr = current; + } + + if (use_match && memcmp(post, match, sizeof(post)) == 0) { + PrintAndLogEx(SUCCESS, "Block matches stop condition!\n"); + break; } /* TEMPORALLY DISABLED @@ -3314,11 +3343,17 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { } PrintAndLogEx(INFO, "----------------------------------------------------"); - if (phase_clear > - 1) { - PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_clear); + if ((phase_begin_clear > - 1) && (phase_begin_clear != start)) { + PrintAndLogEx(INFO, "Erase phase start boundary around " _YELLOW_("%5d") " us", phase_begin_clear); } - if (phase_newwr > - 1) { - PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_newwr); + if ((phase_end_clear > - 1) && (phase_end_clear != start)){ + PrintAndLogEx(INFO, "Erase phase end boundary around " _YELLOW_("%5d") " us", phase_end_clear); + } + if (phase_begin_newwr > - 1) { + PrintAndLogEx(INFO, "Write phase start boundary around " _YELLOW_("%5d") " us", phase_begin_newwr); + } + if (phase_end_newwr > - 1) { + PrintAndLogEx(INFO, "Write phase end boundary around " _YELLOW_("%5d") " us", phase_end_newwr); } PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; diff --git a/include/common.h b/include/common.h index 3c6245e52..f0ba424c8 100644 --- a/include/common.h +++ b/include/common.h @@ -56,6 +56,10 @@ struct version_information { #define DBG_EXTENDED 4 // errors + info + debug + breaking debug messages extern int DBGLEVEL; +// tear-off +extern uint16_t tearoff_delay_us; +extern bool tearoff_enabled; + // reader voltage field detector #define MF_MINFIELDV 4000