lf em stuff

This commit is contained in:
iceman1001 2020-10-15 19:29:54 +02:00
parent 53c7e47e75
commit ba8aa6f0ab
5 changed files with 416 additions and 14 deletions

View file

@ -233,6 +233,7 @@ static int plus_print_version(uint8_t *version) {
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version[7 + 7 + 7 + 5], version[7 + 7 + 7 + 5 + 1]);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version, 7));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1]));
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]);
@ -241,6 +242,7 @@ static int plus_print_version(uint8_t *version) {
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version + 7, 6));
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7]));
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8]));
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]);
@ -265,13 +267,21 @@ static int get_plus_version(uint8_t *version, int *version_len) {
static int CmdHFMFPInfo(const char *Cmd) {
if (Cmd && strlen(Cmd) > 0)
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(INFO, "-------------------------------------------------------------");
// Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
WaitForResponse(CMD_ACK, &resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
bool supportVersion = false;
bool supportSignature = false;
@ -284,17 +294,11 @@ static int CmdHFMFPInfo(const char *Cmd) {
} else {
// info about 14a part
infoHF14A(false, false, false);
// Historical bytes.
}
// Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
PacketResponseNG resp;
WaitForResponse(CMD_ACK, &resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// Signature originality check
uint8_t signature[56] = {0};

View file

@ -22,6 +22,7 @@
#include "cmdhw.h"
#include "cmddata.h"
#include "commonutil.h"
#include "pm3_cmd.h"
static int CmdHelp(const char *Cmd);
@ -516,6 +517,32 @@ static int CmdStatus(const char *Cmd) {
return PM3_SUCCESS;
}
int handle_tearoff(tearoff_params_t *params, bool verbose) {
if (params == NULL)
return PM3_EINVARG;
clearCommandBuffer();
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)params, sizeof(tearoff_params_t));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) {
PrintAndLogEx(WARNING, "Tear-off command timeout.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
if (params->delay_us > 0 && verbose)
PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params->delay_us);
if (params->on && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
if (params->off && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
}
return resp.status;
}
static int CmdTearoff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hw tearoff",

View file

@ -12,9 +12,11 @@
#define CMDHW_H__
#include "common.h"
#include "pm3_cmd.h"
int CmdHW(const char *Cmd);
int handle_tearoff(tearoff_params_t *params, bool verbose);
void pm3_version(bool verbose, bool oneliner);
#endif

View file

@ -32,6 +32,7 @@
#include "lfdemod.h"
#include "generator.h"
#include "cliparser.h"
#include "cmdhw.h"
static uint64_t g_em410xid = 0;
@ -715,7 +716,7 @@ static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t col
static bool downloadSamplesEM(void) {
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
uint8_t got[6000];
uint8_t got[5500];
if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) {
PrintAndLogEx(WARNING, "(downloadSamplesEM) command execution time out");
return false;
@ -1413,10 +1414,11 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
// 7,8, rfu
// 9 - 18 customer code
// 19, rfu
98765432109876543210
001000000000
// 00100000000001111000
xxx----
// 1100
// 011
// 00100000000
@ -1643,6 +1645,366 @@ static int CmdEM4x05Chk(const char *Cmd) {
return PM3_SUCCESS;
}
static int unlock_write_protect(bool use_pwd, uint32_t pwd, uint32_t data, bool verbose) {
struct {
uint32_t password;
uint32_t data;
uint8_t usepwd;
} PACKED payload;
payload.password = pwd;
payload.data = data;
payload.usepwd = use_pwd;
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000) == false) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (!downloadSamplesEM())
return PM3_ENODATA;
uint32_t dummy = 0;
int status = demodEM4x05resp(&dummy, true);
if (status == PM3_SUCCESS && verbose)
PrintAndLogEx(SUCCESS, "Success writing to tag");
else if (status == PM3_EFAILED)
PrintAndLogEx(ERR, "Tag denied PROTECT operation");
else
PrintAndLogEx(DEBUG, "No answer from tag");
return status;
}
static int unlock_reset(bool use_pwd, uint32_t pwd, uint32_t data) {
PrintAndLogEx(FAILED, "resetting the " _RED_("active") " lock block");
return unlock_write_protect(use_pwd, pwd, data, false);
}
static int CmdEM4x05Unlock(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x05_unlock",
"execute tear off against EM4205/4305/4469/4569",
"lf em 4x05_unlock\n"
"lf em 4x05_unlock -s 4100 -e 4100 -> lock on and autotune at 4100us\n"
"lf em 4x05_unlock -n 10 -s 3000 -e 4400 -> scan delays 3000us -> 4400us"
);
void *argtable[] = {
arg_param_begin,
arg_u64_0("n", NULL, NULL, "steps to skip"),
arg_u64_0("s", "start", "<us>", "start scan from delay (us)"),
arg_u64_0("e", "end", "<us>", "end scan at delay (us)"),
arg_u64_0("p", "pwd", "", "password (0x00000000)"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint64_t n = arg_get_u64_def(ctx, 1, 10);
uint64_t start = arg_get_u64_def(ctx, 2, 2000);
uint64_t end = arg_get_u64_def(ctx, 3, 6000);
uint64_t inputpwd = arg_get_u64_def(ctx, 4, 0xFFFFFFFFFFFFFFFF);
bool verbose = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
if (session.pm3_present == false) {
PrintAndLogEx(WARNING, "device offline\n");
return PM3_ENODATA;
}
bool use_pwd = false;
uint32_t pwd = 0;
if (inputpwd != 0xFFFFFFFFFFFFFFFF) {
use_pwd = true;
pwd = inputpwd & 0xFFFFFFFF;
}
uint32_t search_value = 0;
uint32_t write_value = 0;
//
// inital phase
//
// read word 14
uint32_t init_14 = 0;
int res = EM4x05ReadWord_ext(14, pwd, use_pwd, &init_14);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "failed to read word 14\n");
return PM3_ENODATA;
}
// read 15
uint32_t init_15 = 0;
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &init_15);
if (res != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "failed to read word 15\n");
return PM3_ENODATA;
}
#define UNLOCK_WORD 0x00008000
if (init_15 == UNLOCK_WORD) {
PrintAndLogEx(SUCCESS, "Tag already fully unlocked, nothing to do");
return PM3_SUCCESS;
}
#define ACTIVE_MASK 0x00008000
if ((init_15 & ACTIVE_MASK) == ACTIVE_MASK) {
search_value = init_15;
} else {
search_value = init_14;
}
bool my_auto = false;
if (n == 0) {
my_auto = true;
n = (end - start) / 2;
} else {
if ( start > end ) {
PrintAndLogEx(FAILED, "start delay can\'t be larger than end delay %u vs %u", start, end);
return PM3_EINVARG;
}
}
// fix at one specific delay
if (start == end) {
n = 0;
}
PrintAndLogEx(INFO, "--------------- " _CYAN_("EM4x05 tear-off : target PROTECT") " -----------------------\n");
PrintAndLogEx(INFO, " Word 14,15 inital [ " _GREEN_("%08"PRIX32) ", " _GREEN_("%08"PRIX32) " ]", init_14, init_15);
if (use_pwd) {
PrintAndLogEx(INFO, " target password [ " _GREEN_("%08"PRIX32) " ]", pwd);
}
if (my_auto) {
PrintAndLogEx(INFO, " automatic mode [ " _GREEN_("enabled") " ]");
}
PrintAndLogEx(INFO, " target stepping [ " _GREEN_("%u") " ]", n);
PrintAndLogEx(INFO, "target delay range [ " _GREEN_("%"PRIu32) " ... " _GREEN_("%"PRIu32) " ]", start, end);
PrintAndLogEx(INFO, " search value [ " _GREEN_("%08"PRIX32) " ]", search_value);
PrintAndLogEx(INFO, " write value [ " _GREEN_("%08"PRIX32) " ]", write_value);
PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n");
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
int exit_code = PM3_SUCCESS;
uint32_t word14 = 0, word15 = 0;
uint32_t tries = 0;
uint32_t soon = 0;
uint32_t late = 0;
//
// main loop
//
//uint32_t prev_delay = 0;
uint64_t t1 = msclock();
while (start <= end) {
if (my_auto && n < 1) {
PrintAndLogEx(INFO, "Reached n < 1 => " _YELLOW_("disabling automatic mode"));
end = start;
my_auto = false;
n = 0;
}
if (my_auto == false) {
start += n;
}
if (tries >= 5 && n == 0 && soon != late) {
if (soon > late) {
PrintAndLogEx(INFO, "Tried %d times, soon:%i late:%i => " _CYAN_("adjust +1us >> %u us"), tries, soon, late, start);
start++;
end++;
} else {
PrintAndLogEx(INFO, "Tried %d times, soon:%i late:%i => " _CYAN_("adjust -1us >> %u us"), tries, soon, late, start);
start--;
end--;
}
tries = 0;
soon = 0;
late = 0;
}
if (is_cancelled()) {
exit_code = PM3_EOPABORTED;
break;
}
/*
if ( start != prev_delay) {
PrintAndLogEx(INFO, "Tear-off delay hook configured => " _GREEN_("%u us"), start);
prev_delay = start;
}
*/
// set tear off trigger
clearCommandBuffer();
tearoff_params_t params = {
.delay_us = start,
.on = true,
.off = false
};
res = handle_tearoff(&params, verbose);
if ( res != PM3_SUCCESS ) {
PrintAndLogEx(WARNING, "failed to configure tear off");
return PM3_EOPABORTED;
}
// write
res = unlock_write_protect(use_pwd, pwd, write_value, verbose);
// read after trigger
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14);
if (res == PM3_SUCCESS) {
//PrintAndLogEx(INFO, "14 after [ " _GREEN_("%08"PRIX32) " ]", word14);
} else {
continue;
}
// read after trigger
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15);
if (res == PM3_SUCCESS) {
//PrintAndLogEx(INFO, "15 after [ " _GREEN_("%08"PRIX32) " ]", word15);
} else {
continue;
}
PrintAndLogEx(INFO, "ref:%08X 14:%08X 15:%08X ", search_value, word14, word15);
if ( word14 == search_value && word15 == 0) {
PrintAndLogEx(INFO, "Status: Nothing happened => " _GREEN_("tearing too soon"));
if (my_auto) {
start += n;
n /= 2;
PrintAndLogEx(INFO, "Adjusting params: n %i start %i end %i", n, start, end);
} else {
soon++;
}
} else {
if (word15 == search_value) {
if (word14 == 0) {
PrintAndLogEx(INFO, "Status: Protect succeeded => " _GREEN_("tearing too late"));
} else {
if ( word14 == search_value) {
PrintAndLogEx(INFO, "Status: 15 ok, 14 not yet erased => " _GREEN_("tearing too late"));
} else {
PrintAndLogEx(INFO, "Status: 15 ok, 14 partially erased => " _GREEN_("tearing too late"));
}
}
unlock_reset(use_pwd, pwd, write_value);
// read after reset
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14);
if (res != PM3_SUCCESS) {
continue;
}
if (word14 == 0) {
unlock_reset(use_pwd, pwd, write_value);
}
if (word14 != search_value) {
// read after reset
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15);
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "Status: new definitive value! => " _RED_("SUCCESS:") " 14: " _CYAN_("%08X") " 15: %08X", word14, word15);
break;
} else {
continue;
}
}
if (my_auto) {
end = start;
start -= n;
n /= 2;
PrintAndLogEx(INFO, "Adjusting params: n %i start %i end %i", n, start, end);
} else {
late++;
}
} else {
if (( word15 & ACTIVE_MASK) == ACTIVE_MASK) {
PrintAndLogEx(INFO, "Status: 15 bitflipped and active => " _RED_("SUCCESS?: ") "14: %08X 15: " _CYAN_("%08X"), word14, word15);
PrintAndLogEx(INFO, "Committing results...");
unlock_reset(use_pwd, pwd, write_value);
// read after reset
res = EM4x05ReadWord_ext(14, pwd, use_pwd, &word14);
if ( res != PM3_SUCCESS ) {
PrintAndLogEx(WARNING, "failed to read 14");
return PM3_EOPABORTED;
}
res = EM4x05ReadWord_ext(15, pwd, use_pwd, &word15);
if ( res != PM3_SUCCESS ) {
PrintAndLogEx(WARNING, "failed to read 15");
return PM3_EOPABORTED;
}
PrintAndLogEx(INFO, "ref:%08x 14:%08X 15:%08X", search_value, word14, word15);
if ((word14 & ACTIVE_MASK) == ACTIVE_MASK) {
if (word14 == word15) {
PrintAndLogEx(INFO, "Status: confirmed => " _RED_("SUCCESS: ") "14: " _CYAN_("%08X") " 15: %08X", word14, word15);
break;
}
if (word14 != search_value) {
PrintAndLogEx(INFO, "Status: new definitive value! => " _RED_("SUCCESS: ") "14: " _CYAN_("%08X") " 15: %08X", word14, word15);
break;
}
PrintAndLogEx(INFO, "Status: failed to commit bitflip => " _RED_("FAIL: ") "14: %08X 15: %08X", word14, word15);
} else {
PrintAndLogEx(INFO, "Status: 15 bitflipped but inactive => " _YELLOW_("PROMISING: ") "14: %08X 15: " _CYAN_("%08X"), word14, word15);
}
if (my_auto) {
n = 0;
end = start;
} else {
tries = 0;
soon = 0;
late = 0;
}
}
}
}
if (my_auto == false) {
tries++;
}
}
PrintAndLogEx(INFO, "----------------------------- " _CYAN_("exit") " ----------------------------------\n");
t1 = msclock() - t1;
PrintAndLogEx(SUCCESS, "\ntime in unlock " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
PrintAndLogEx(INFO, "try " _YELLOW_("`lf em 4x05_dump`"));
PrintAndLogEx(NORMAL, "");
return exit_code;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 410x") " -----------------------"},
@ -1662,6 +2024,7 @@ static command_t CommandTable[] = {
{"4x05_info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"},
{"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"},
{"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"},
{"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"},
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"},
{"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
{"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},

View file

@ -375,6 +375,12 @@ typedef struct {
} PACKED picopass_ns_hdr;
typedef struct {
uint16_t delay_us;
bool on;
bool off;
} PACKED tearoff_params_t;
// For the bootloader
#define CMD_DEVICE_INFO 0x0000
//#define CMD_SETUP_WRITE 0x0001