diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0797eaa82..e7d6fae8d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1174,6 +1174,10 @@ static void PacketReceived(PacketCommandNG *packet) { em4x70_write((em4x70_data_t *)packet->data.asBytes); break; } + case CMD_LF_EM4X70_UNLOCK: { + em4x70_unlock((em4x70_data_t *)packet->data.asBytes); + break; + } #endif #ifdef WITH_ISO15693 diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index 843cb0978..0b6cf36e6 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -302,6 +302,12 @@ static void em4x70_send_nibble(uint8_t nibble, bool with_parity) { em4x70_send_bit(parity); } +static void em4x70_send_byte(uint8_t byte) { + // Send byte msb first + for (int i = 0; i < 8; i++) + em4x70_send_bit((byte >> (7 - i)) & 1); +} + static void em4x70_send_word(const uint16_t word) { // Split into nibbles @@ -354,6 +360,47 @@ static bool check_ack(void) { return false; } +static int send_pin(const uint32_t pin) { + + // sends pin code for unlocking + if (find_listen_window(true)) { + + // send PIN command + em4x70_send_nibble(EM4X70_COMMAND_PIN, true); + + // --> Send TAG ID (bytes 4-7) + for(int i=0; i < 4; i++) { + em4x70_send_byte(tag.data[7-i]); + } + + // --> Send PIN + for(int i=0; i < 4 ; i++) { + em4x70_send_byte((pin>>(i*8)) & 0xff); + } + + // Wait TWALB (write access lock bits) + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_TWALB); + + // <-- Receive ACK + if (check_ack()) { + + // Writes Lock Bits + WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_WEE); + // <-- Receive header + ID + uint8_t tag_id[64]; + int num = em4x70_receive(tag_id); + if(num < 32) { + Dbprintf("Invalid ID Received"); + return PM3_ESOFT; + } + bits2bytes(tag_id, num, &tag.data[4]); + return PM3_SUCCESS; + } + } + + return PM3_ESOFT; +} + static int write(const uint16_t word, const uint8_t address) { // writes to specified
@@ -651,4 +698,37 @@ void em4x70_write(em4x70_data_t *etd) { reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data)); } +void em4x70_unlock(em4x70_data_t *etd) { + + uint8_t status = 0; + + command_parity = etd->parity; + + init_tag(); + EM4170_setup_read(); + + // Find the Tag + if (get_signalproperties() && find_EM4X70_Tag()) { + + // Read ID (required for send_pin command) + if(em4x70_read_id()) { + + // Send PIN + status = send_pin(etd->pin) == PM3_SUCCESS; + + // If the write succeeded, read the rest of the tag + if(status) { + // Read Tag + // ID doesn't change + em4x70_read_um1(); + em4x70_read_um2(); + } + } + } + + StopTicks(); + lf_finalize(); + reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data)); +} + diff --git a/armsrc/em4x70.h b/armsrc/em4x70.h index 63a06136d..2d9f077f8 100644 --- a/armsrc/em4x70.h +++ b/armsrc/em4x70.h @@ -19,5 +19,6 @@ typedef struct { void em4x70_info(em4x70_data_t *etd); void em4x70_write(em4x70_data_t *etd); +void em4x70_unlock(em4x70_data_t *etd); #endif /* EM4x70_H */ diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index b3bd192b1..0b9a18785 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -86,12 +86,12 @@ int CmdEM4x70Info(const char *Cmd) { " ID48 does not use command parity (default).\n" " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" - "lf em 4x70 info -p -> adds parity bit to command\n" + "lf em 4x70 info -x -> adds parity bit to command\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_lit0("x", "parity", "Add parity bit when sending commands"), arg_param_end }; @@ -104,7 +104,7 @@ int CmdEM4x70Info(const char *Cmd) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_LF_EM4X70_INFO, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); return PM3_ETIMEOUT; } @@ -113,7 +113,7 @@ int CmdEM4x70Info(const char *Cmd) { return PM3_SUCCESS; } - PrintAndLogEx(FAILED, "reading tag " _RED_("failed")); + PrintAndLogEx(FAILED, "Reading " _RED_("Failed")); return PM3_ESOFT; } @@ -127,12 +127,12 @@ int CmdEM4x70Write(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x10 write", "Write EM4x70\n", "lf em 4x70 write -b 15 d c0de -> write 'c0de' to block 15\n" - "lf em 4x70 write -p -b 15 -d c0de -> adds parity bit to commands\n" + "lf em 4x70 write -x -b 15 -d c0de -> adds parity bit to commands\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("p", "parity", "Add parity bit when sending commands"), + arg_lit0("x", "parity", "Add parity bit when sending commands"), arg_int1("b", "block", "", "block/word address, dec"), arg_str1("d", "data", "", "data, 2 bytes"), arg_param_end @@ -181,10 +181,70 @@ int CmdEM4x70Write(const char *Cmd) { return PM3_ESOFT; } +int CmdEM4x70Unlock(const char *Cmd) { + + // send pin code to device, unlocking it for writing + em4x70_data_t etd = {0}; + + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf em 4x10 unlock", + "Unlock EM4x70 by sending PIN\n" + "Default pin may be:\n" + " AAAAAAAA\n" + " 00000000\n", + "lf em 4x70 unlock -p 11223344 -> Unlock with PIN\n" + "lf em 4x70 unlock -x -p 11223344 -> Unlock with PIN using parity commands\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("x", "parity", "Add parity bit when sending commands"), + arg_str1("p", "pin", "", "pin, 4 bytes"), + arg_param_end + }; + + CLIExecWithReturn(ctx, Cmd, argtable, true); + + etd.parity = arg_get_lit(ctx, 1); + + int pin_len = 0; + uint8_t pin[4] = {0x0}; + + CLIGetHexWithReturn(ctx, 2, pin, &pin_len); + + CLIParserFree(ctx); + + if (pin_len != 4) { + PrintAndLogEx(FAILED, "PIN length must be 4 bytes instead of %d", pin_len); + return PM3_EINVARG; + } + + etd.pin = BYTES2UINT32(pin); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_EM4X70_UNLOCK, (uint8_t *)&etd, sizeof(etd)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_LF_EM4X70_UNLOCK, &resp, TIMEOUT)) { + PrintAndLogEx(WARNING, "Timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.status) { + print_info_result(resp.data.asBytes); + return PM3_SUCCESS; + } + + PrintAndLogEx(FAILED, "Unlocking tag " _RED_("failed")); + return PM3_ESOFT; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"}, {"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"}, + {"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfem4x70.h b/client/src/cmdlfem4x70.h index a6adb83d5..3f7930673 100644 --- a/client/src/cmdlfem4x70.h +++ b/client/src/cmdlfem4x70.h @@ -19,6 +19,7 @@ int CmdLFEM4X70(const char *Cmd); int CmdEM4x70Info(const char *Cmd); int CmdEM4x70Write(const char *Cmd); +int CmdEM4x70Unlock(const char *Cmd); int em4x70_info(void); bool detect_4x70_block(void); diff --git a/include/em4x70.h b/include/em4x70.h index 47e8acdce..a9d94403d 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -19,6 +19,10 @@ typedef struct { // Used for writing address uint8_t address; uint16_t word; + + // PIN to unlock + uint32_t pin; + } em4x70_data_t; #endif /* EM4X70_H__ */ diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 9f2f7f0c1..f5585f192 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -518,6 +518,7 @@ typedef struct { #define CMD_LF_EM4X50_CHK 0x0253 #define CMD_LF_EM4X70_INFO 0x0260 #define CMD_LF_EM4X70_WRITE 0x0261 +#define CMD_LF_EM4X70_UNLOCK 0x0262 // Sampling configuration for LF reader/sniffer #define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E