mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
commit
6221a44773
47 changed files with 19043 additions and 1830 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Removed 'hf iclass replay' - use the 'hf iclass dump' or 'hf iclass rdbl' with option "n" instead (@iceman1001). Concept taken from official repo (@pwpiwi)
|
||||||
- Add low level support for 14b' aka Innovatron (@doegox)
|
- Add low level support for 14b' aka Innovatron (@doegox)
|
||||||
- Add doc/cliparser.md (@mwalker33)
|
- Add doc/cliparser.md (@mwalker33)
|
||||||
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)
|
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -173,6 +173,9 @@ help:
|
||||||
@echo "+ .../check - Run offline tests against specific target. See above."
|
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||||
@echo
|
@echo
|
||||||
|
@echo "+ udev - Sets udev rules on *nix"
|
||||||
|
@echo "+ accessrights - Ensure user belongs to correct group on *nix"
|
||||||
|
@echo
|
||||||
@echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4"
|
@echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4"
|
||||||
@echo "To activate verbose mode, use make V=1"
|
@echo "To activate verbose mode, use make V=1"
|
||||||
|
|
||||||
|
|
|
@ -302,15 +302,17 @@ static int reader_dump_mode(void) {
|
||||||
Iso15693InitReader();
|
Iso15693InitReader();
|
||||||
set_tracing(false);
|
set_tracing(false);
|
||||||
|
|
||||||
|
|
||||||
|
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
||||||
|
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
bool res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time);
|
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
switch_off();
|
switch_off();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
|
||||||
// sanity check of CSN.
|
// sanity check of CSN.
|
||||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||||
switch_off();
|
switch_off();
|
||||||
|
@ -366,7 +368,7 @@ static int reader_dump_mode(void) {
|
||||||
auth.use_credit_key = true;
|
auth.use_credit_key = true;
|
||||||
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
||||||
|
|
||||||
res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time);
|
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
|
||||||
// sanity check of CSN.
|
// sanity check of CSN.
|
||||||
|
|
|
@ -1473,6 +1473,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_HF_MFU_COUNTER_TEAROFF: {
|
||||||
|
struct p {
|
||||||
|
uint8_t counter;
|
||||||
|
uint32_t tearoff_time;
|
||||||
|
} PACKED;
|
||||||
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CMD_HF_MIFARE_STATIC_NONCE: {
|
case CMD_HF_MIFARE_STATIC_NONCE: {
|
||||||
MifareHasStaticNonce();
|
MifareHasStaticNonce();
|
||||||
break;
|
break;
|
||||||
|
@ -1503,20 +1512,19 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_ICLASS_SIMULATE: {
|
case CMD_HF_ICLASS_SIMULATE: {
|
||||||
SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
/*
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CMD_HF_ICLASS_READER: {
|
|
||||||
ReaderIClass(packet->oldarg[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CMD_HF_ICLASS_REPLAY: {
|
|
||||||
struct p {
|
struct p {
|
||||||
uint8_t reader[4];
|
uint8_t reader[4];
|
||||||
uint8_t mac[4];
|
uint8_t mac[4];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) packet->data.asBytes;
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
ReaderIClass_Replay(payload->reader, payload->mac);
|
*/
|
||||||
|
|
||||||
|
SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_HF_ICLASS_READER: {
|
||||||
|
ReaderIClass(packet->oldarg[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_ICLASS_EML_MEMSET: {
|
case CMD_HF_ICLASS_EML_MEMSET: {
|
||||||
|
@ -1545,18 +1553,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
iClass_Dump(packet->data.asBytes);
|
iClass_Dump(packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_ICLASS_CLONE: {
|
|
||||||
struct p {
|
|
||||||
uint8_t startblock;
|
|
||||||
uint8_t endblock;
|
|
||||||
uint8_t data[];
|
|
||||||
} PACKED;
|
|
||||||
struct p *payload = (struct p *)packet->data.asBytes;
|
|
||||||
iClass_Clone(payload->startblock, payload->endblock, payload->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CMD_HF_ICLASS_RESTORE: {
|
case CMD_HF_ICLASS_RESTORE: {
|
||||||
iClass_Restore(packet->data.asBytes);
|
iClass_Restore( (iclass_restore_req_t *)packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "lfadc.h"
|
#include "lfadc.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
#include "em4x50.h"
|
#include "em4x50.h"
|
||||||
|
#include "appmain.h" // tear
|
||||||
|
|
||||||
// 4 data bytes
|
// 4 data bytes
|
||||||
// + byte with row parities
|
// + byte with row parities
|
||||||
|
@ -470,6 +471,8 @@ static bool find_double_listen_window(bool bcommand) {
|
||||||
|
|
||||||
if (bcommand) {
|
if (bcommand) {
|
||||||
|
|
||||||
|
// SpinDelay(10);
|
||||||
|
|
||||||
// data transmission from card has to be stopped, because
|
// data transmission from card has to be stopped, because
|
||||||
// a commamd shall be issued
|
// a commamd shall be issued
|
||||||
|
|
||||||
|
@ -816,7 +819,7 @@ void em4x50_info(em4x50_data_t *etd) {
|
||||||
status = (bsuccess << 1) + blogin;
|
status = (bsuccess << 1) + blogin;
|
||||||
|
|
||||||
lf_finalize();
|
lf_finalize();
|
||||||
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
|
reply_ng(CMD_LF_EM4X50_INFO, status, (uint8_t *)tag.sectors, 238);
|
||||||
}
|
}
|
||||||
|
|
||||||
void em4x50_read(em4x50_data_t *etd) {
|
void em4x50_read(em4x50_data_t *etd) {
|
||||||
|
@ -860,14 +863,13 @@ void em4x50_read(em4x50_data_t *etd) {
|
||||||
status = (now << 2) + (bsuccess << 1) + blogin;
|
status = (now << 2) + (bsuccess << 1) + blogin;
|
||||||
|
|
||||||
lf_finalize();
|
lf_finalize();
|
||||||
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
|
reply_ng(CMD_LF_EM4X50_READ, status, (uint8_t *)tag.sectors, 238);
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
// write functions
|
// write functions
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
static int write(uint8_t word[4], uint8_t address) {
|
||||||
static bool write(uint8_t word[4], uint8_t address) {
|
|
||||||
|
|
||||||
// writes <word> to specified <address>
|
// writes <word> to specified <address>
|
||||||
|
|
||||||
|
@ -882,17 +884,23 @@ static bool write(uint8_t word[4], uint8_t address) {
|
||||||
// send data
|
// send data
|
||||||
em4x50_send_word(word);
|
em4x50_send_word(word);
|
||||||
|
|
||||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
|
||||||
|
return PM3_ETEAROFF;
|
||||||
|
} else {
|
||||||
|
|
||||||
// look for ACK sequence
|
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||||
if (check_ack(false)) {
|
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
||||||
|
|
||||||
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
|
// look for ACK sequence
|
||||||
// for saving data and should return with ACK
|
if (check_ack(false)) {
|
||||||
if (check_ack(false))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
|
||||||
|
// for saving data and should return with ACK
|
||||||
|
if (check_ack(false))
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -900,10 +908,10 @@ static bool write(uint8_t word[4], uint8_t address) {
|
||||||
Dbprintf("error in command request");
|
Dbprintf("error in command request");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
|
static int write_password(uint8_t password[4], uint8_t new_password[4]) {
|
||||||
|
|
||||||
// changes password from <password> to <new_password>
|
// changes password from <password> to <new_password>
|
||||||
|
|
||||||
|
@ -915,23 +923,29 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
|
||||||
// send address data
|
// send address data
|
||||||
em4x50_send_word(password);
|
em4x50_send_word(password);
|
||||||
|
|
||||||
// wait for T0 * EM4x50_T_TAG_TPP (processing pause time)
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP);
|
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
|
||||||
|
return PM3_ETEAROFF;
|
||||||
|
} else {
|
||||||
|
|
||||||
// look for ACK sequence and send rm request
|
// wait for T0 * EM4x50_T_TAG_TPP (processing pause time)
|
||||||
// during following listen window
|
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP);
|
||||||
if (check_ack(true)) {
|
|
||||||
|
|
||||||
// send new password
|
// look for ACK sequence and send rm request
|
||||||
em4x50_send_word(new_password);
|
// during following listen window
|
||||||
|
if (check_ack(true)) {
|
||||||
|
|
||||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
// send new password
|
||||||
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
em4x50_send_word(new_password);
|
||||||
|
|
||||||
|
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||||
|
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
|
||||||
|
|
||||||
if (check_ack(false))
|
|
||||||
if (check_ack(false))
|
if (check_ack(false))
|
||||||
return true;
|
if (check_ack(false))
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -939,7 +953,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
|
||||||
Dbprintf("error in command request");
|
Dbprintf("error in command request");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void em4x50_write(em4x50_data_t *etd) {
|
void em4x50_write(em4x50_data_t *etd) {
|
||||||
|
@ -966,8 +980,13 @@ void em4x50_write(em4x50_data_t *etd) {
|
||||||
blogin = login(etd->password);
|
blogin = login(etd->password);
|
||||||
|
|
||||||
// write word to given address
|
// write word to given address
|
||||||
if (write(etd->word, etd->address)) {
|
int res = write(etd->word, etd->address);
|
||||||
|
if (res == PM3_ETEAROFF) {
|
||||||
|
lf_finalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
// to verify result reset EM4x50
|
// to verify result reset EM4x50
|
||||||
if (reset()) {
|
if (reset()) {
|
||||||
|
|
||||||
|
@ -996,9 +1015,8 @@ void em4x50_write(em4x50_data_t *etd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
status = (bsuccess << 1) + blogin;
|
status = (bsuccess << 1) + blogin;
|
||||||
|
|
||||||
lf_finalize();
|
lf_finalize();
|
||||||
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
|
reply_ng(CMD_LF_EM4X50_WRITE, status, (uint8_t *)tag.sectors, 238);
|
||||||
}
|
}
|
||||||
|
|
||||||
void em4x50_write_password(em4x50_data_t *etd) {
|
void em4x50_write_password(em4x50_data_t *etd) {
|
||||||
|
@ -1015,12 +1033,18 @@ void em4x50_write_password(em4x50_data_t *etd) {
|
||||||
|
|
||||||
// login and change password
|
// login and change password
|
||||||
if (login(etd->password)) {
|
if (login(etd->password)) {
|
||||||
bsuccess = write_password(etd->password, etd->new_password);
|
|
||||||
|
int res = write_password(etd->password, etd->new_password);
|
||||||
|
if (res == PM3_ETEAROFF) {
|
||||||
|
lf_finalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bsuccess = (res == PM3_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lf_finalize();
|
lf_finalize();
|
||||||
reply_ng(CMD_ACK, bsuccess, 0, 0);
|
reply_ng(CMD_LF_EM4X50_WRITE_PASSWORD, bsuccess, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void em4x50_wipe(em4x50_data_t *etd) {
|
void em4x50_wipe(em4x50_data_t *etd) {
|
||||||
|
@ -1078,5 +1102,5 @@ void em4x50_wipe(em4x50_data_t *etd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
lf_finalize();
|
lf_finalize();
|
||||||
reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238);
|
reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, (uint8_t *)tag.sectors, 238);
|
||||||
}
|
}
|
||||||
|
|
281
armsrc/iclass.c
281
armsrc/iclass.c
|
@ -1276,7 +1276,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
||||||
* @return false = fail
|
* @return false = fail
|
||||||
* true = Got all.
|
* true = Got all.
|
||||||
*/
|
*/
|
||||||
static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
|
static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) {
|
||||||
|
|
||||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
||||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
||||||
|
@ -1286,8 +1286,6 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32
|
||||||
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
||||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
|
||||||
|
|
||||||
// Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
|
// Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
|
||||||
// bit 7: parity.
|
// bit 7: parity.
|
||||||
if (use_credit_key)
|
if (use_credit_key)
|
||||||
|
@ -1369,6 +1367,8 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32
|
||||||
*status |= FLAG_ICLASS_CC;
|
*status |= FLAG_ICLASS_CC;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// on NON_SECURE_PAGEMODE cards, AIA is on block2..
|
||||||
|
|
||||||
// read App Issuer Area block 2
|
// read App Issuer Area block 2
|
||||||
read_aia[1] = 0x02;
|
read_aia[1] = 0x02;
|
||||||
|
@ -1385,23 +1385,23 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
*status |= FLAG_ICLASS_AIA;
|
*status |= FLAG_ICLASS_AIA;
|
||||||
memcpy(card_data + (8 * 2), resp, 8);
|
memcpy(hdr->epurse, resp, sizeof(hdr->epurse));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) {
|
bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) {
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
return select_iclass_tag_ex(card_data, use_credit_key, eof_time, &result);
|
return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reader iClass Anticollission
|
// Reader iClass Anticollission
|
||||||
// turn off afterwards
|
// turn off afterwards
|
||||||
void ReaderIClass(uint8_t flags) {
|
void ReaderIClass(uint8_t flags) {
|
||||||
|
|
||||||
uint8_t card_data[6 * 8] = {0xFF};
|
picopass_hdr hdr = {0};
|
||||||
// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
// uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
uint8_t resp[ICLASS_BUFFER_SIZE] = {0};
|
||||||
memset(resp, 0xFF, sizeof(resp));
|
memset(resp, 0xFF, sizeof(resp));
|
||||||
|
@ -1419,14 +1419,13 @@ void ReaderIClass(uint8_t flags) {
|
||||||
|
|
||||||
uint8_t result_status = 0;
|
uint8_t result_status = 0;
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
bool status = select_iclass_tag_ex(card_data, use_credit_key, &eof_time, &result_status);
|
bool status = select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &result_status);
|
||||||
if (status == false) {
|
if (status == false) {
|
||||||
reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0);
|
reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0);
|
||||||
switch_off();
|
switch_off();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Page mapping for secure mode
|
// Page mapping for secure mode
|
||||||
// 0 : CSN
|
// 0 : CSN
|
||||||
// 1 : Configuration
|
// 1 : Configuration
|
||||||
|
@ -1444,7 +1443,7 @@ void ReaderIClass(uint8_t flags) {
|
||||||
// with 0xFF:s in block 3 and 4.
|
// with 0xFF:s in block 3 and 4.
|
||||||
|
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data));
|
reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t*)&hdr, sizeof(hdr));
|
||||||
|
|
||||||
//Send back to client, but don't bother if we already sent this -
|
//Send back to client, but don't bother if we already sent this -
|
||||||
// only useful if looping in arm (not try_once && not abort_after_read)
|
// only useful if looping in arm (not try_once && not abort_after_read)
|
||||||
|
@ -1470,101 +1469,6 @@ void ReaderIClass(uint8_t flags) {
|
||||||
switch_off();
|
switch_off();
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn off afterwards
|
|
||||||
void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac) {
|
|
||||||
|
|
||||||
BigBuf_free();
|
|
||||||
|
|
||||||
uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
memcpy(check + 1, rnr, 4);
|
|
||||||
memcpy(check + 5, mac, 4);
|
|
||||||
|
|
||||||
uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE);
|
|
||||||
if (card_data == NULL) {
|
|
||||||
DbpString("fail to allocate memory");
|
|
||||||
reply_ng(CMD_HF_ICLASS_REPLAY, PM3_EMALLOC, NULL, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
memset(card_data, 0xFF, ICLASS_16KS_SIZE);
|
|
||||||
|
|
||||||
uint32_t start_time = 0;
|
|
||||||
uint32_t eof_time = 0;
|
|
||||||
|
|
||||||
Iso15693InitReader();
|
|
||||||
|
|
||||||
picopass_hdr hdr = {0};
|
|
||||||
bool res = select_iclass_tag((uint8_t *)&hdr, false, &eof_time);
|
|
||||||
if (res == false) {
|
|
||||||
reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0);
|
|
||||||
switch_off();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t resp[10] = {0};
|
|
||||||
|
|
||||||
//for now replay captured auth (as cc not updated)
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
res = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
|
|
||||||
if (res == false) {
|
|
||||||
reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0);
|
|
||||||
switch_off();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t mem = hdr.conf.mem_config;
|
|
||||||
uint8_t cardsize = ((mem & 0x80) == 0x80) ? 255 : 32;
|
|
||||||
|
|
||||||
/*
|
|
||||||
static struct memory_t {
|
|
||||||
int k16;
|
|
||||||
int book;
|
|
||||||
int k2;
|
|
||||||
int lockauth;
|
|
||||||
int keyaccess;
|
|
||||||
} memory;
|
|
||||||
|
|
||||||
// memory.k16 = ((mem & 0x80) == 0x80);
|
|
||||||
// memory.book = ((mem & 0x20) == 0x20);
|
|
||||||
// memory.k2 = ((mem & 0x08) == 0x08);
|
|
||||||
// memory.lockauth = ((mem & 0x02) == 0x02);
|
|
||||||
// memory.keyaccess = ((mem & 0x01) == 0x01);
|
|
||||||
// uint8_t cardsize = memory.k16 ? 255 : 32;
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool dumpsuccess = true;
|
|
||||||
|
|
||||||
// main read loop
|
|
||||||
uint16_t i;
|
|
||||||
for (i = 0; i <= cardsize; i++) {
|
|
||||||
|
|
||||||
uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00};
|
|
||||||
AddCrc(c + 1, 1);
|
|
||||||
|
|
||||||
res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time);
|
|
||||||
if (res) {
|
|
||||||
memcpy(card_data + (8 * i), resp, 8);
|
|
||||||
} else {
|
|
||||||
Dbprintf("failed to read block %u ( 0x%02x)", i, i);
|
|
||||||
dumpsuccess = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct p {
|
|
||||||
bool isOK;
|
|
||||||
uint16_t block_cnt;
|
|
||||||
uint32_t bb_offset;
|
|
||||||
} PACKED response;
|
|
||||||
|
|
||||||
response.isOK = dumpsuccess;
|
|
||||||
response.block_cnt = i;
|
|
||||||
response.bb_offset = card_data - BigBuf_get_addr();
|
|
||||||
reply_ng(CMD_HF_ICLASS_REPLAY, PM3_SUCCESS, (uint8_t *)&response, sizeof(response));
|
|
||||||
|
|
||||||
BigBuf_free();
|
|
||||||
switch_off();
|
|
||||||
}
|
|
||||||
|
|
||||||
// used with function select_and_auth (cmdhficlass.c)
|
// used with function select_and_auth (cmdhficlass.c)
|
||||||
// which needs to authenticate before doing more things like read/write
|
// which needs to authenticate before doing more things like read/write
|
||||||
// selects and authenticate to a card, sends back div_key and mac to client.
|
// selects and authenticate to a card, sends back div_key and mac to client.
|
||||||
|
@ -1585,24 +1489,30 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
|
||||||
|
|
||||||
memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse));
|
memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse));
|
||||||
|
|
||||||
if (payload->use_raw)
|
if ( payload->use_replay) {
|
||||||
memcpy(div_key, payload->key, 8);
|
|
||||||
else
|
|
||||||
iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite);
|
|
||||||
|
|
||||||
if (payload->use_credit_key)
|
memcpy(pmac, payload->key + 4, 4);
|
||||||
memcpy(hdr->key_c, div_key, sizeof(hdr->key_c));
|
memcpy(cmd_check + 1, payload->key, 8);
|
||||||
else
|
|
||||||
memcpy(hdr->key_d, div_key, sizeof(hdr->key_d));
|
|
||||||
|
|
||||||
opt_doReaderMAC(ccnr, div_key, pmac);
|
} else {
|
||||||
|
if (payload->use_raw)
|
||||||
|
memcpy(div_key, payload->key, 8);
|
||||||
|
else
|
||||||
|
iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite);
|
||||||
|
|
||||||
// copy MAC to check command (readersignature)
|
if (payload->use_credit_key)
|
||||||
cmd_check[5] = pmac[0];
|
memcpy(hdr->key_c, div_key, sizeof(hdr->key_c));
|
||||||
cmd_check[6] = pmac[1];
|
else
|
||||||
cmd_check[7] = pmac[2];
|
memcpy(hdr->key_d, div_key, sizeof(hdr->key_d));
|
||||||
cmd_check[8] = pmac[3];
|
|
||||||
|
|
||||||
|
opt_doReaderMAC(ccnr, div_key, pmac);
|
||||||
|
|
||||||
|
// copy MAC to check command (readersignature)
|
||||||
|
cmd_check[5] = pmac[0];
|
||||||
|
cmd_check[6] = pmac[1];
|
||||||
|
cmd_check[7] = pmac[2];
|
||||||
|
cmd_check[8] = pmac[3];
|
||||||
|
}
|
||||||
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
|
return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1632,7 +1542,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
|
||||||
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
||||||
|
|
||||||
// select card / e-purse
|
// select card / e-purse
|
||||||
uint8_t card_data[6 * 8] = {0};
|
picopass_hdr hdr = {0};
|
||||||
|
|
||||||
iclass_premac_t *keys = (iclass_premac_t *)datain;
|
iclass_premac_t *keys = (iclass_premac_t *)datain;
|
||||||
|
|
||||||
|
@ -1646,7 +1556,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
|
||||||
|
|
||||||
uint32_t start_time = 0, eof_time = 0;
|
uint32_t start_time = 0, eof_time = 0;
|
||||||
|
|
||||||
if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false)
|
if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
@ -1723,7 +1633,7 @@ void iClass_ReadBlock(uint8_t *msg) {
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr hdr = {0};
|
||||||
bool res = select_iclass_tag((uint8_t *)&hdr, payload->use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
if (payload->send_reply) {
|
if (payload->send_reply) {
|
||||||
response.isOK = res;
|
response.isOK = res;
|
||||||
|
@ -1796,7 +1706,7 @@ void iClass_Dump(uint8_t *msg) {
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr hdr = {0};
|
||||||
bool res = select_iclass_tag((uint8_t *)&hdr, req->use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
if (req->send_reply) {
|
if (req->send_reply) {
|
||||||
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0);
|
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0);
|
||||||
|
@ -1866,10 +1776,12 @@ void iClass_Dump(uint8_t *msg) {
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data) {
|
static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac) {
|
||||||
|
|
||||||
|
// write command: cmd, 1 blockno, 8 data, 4 mac
|
||||||
uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
|
uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
|
||||||
memcpy(write + 2, data, 12); // data + mac
|
memcpy(write + 2, data, 8);
|
||||||
|
memcpy(write + 10, mac, 4);
|
||||||
AddCrc(write + 1, 13);
|
AddCrc(write + 1, 13);
|
||||||
|
|
||||||
uint8_t resp[10] = {0};
|
uint8_t resp[10] = {0};
|
||||||
|
@ -1914,7 +1826,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
||||||
// select tag.
|
// select tag.
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
picopass_hdr hdr = {0};
|
picopass_hdr hdr = {0};
|
||||||
bool res = select_iclass_tag((uint8_t *)&hdr, payload->req.use_credit_key, &eof_time);
|
bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
||||||
if (res == false) {
|
if (res == false) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1937,10 +1849,14 @@ void iClass_WriteBlock(uint8_t *msg) {
|
||||||
wb[0] = payload->req.blockno;
|
wb[0] = payload->req.blockno;
|
||||||
memcpy(wb + 1, payload->data, 8);
|
memcpy(wb + 1, payload->data, 8);
|
||||||
|
|
||||||
if (payload->req.use_credit_key)
|
if (payload->req.use_replay) {
|
||||||
doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
|
doMAC_N(wb, sizeof(wb), payload->req.key + 4, mac);
|
||||||
else
|
} else {
|
||||||
doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
|
if (payload->req.use_credit_key)
|
||||||
|
doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
|
||||||
|
else
|
||||||
|
doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(write + 2, payload->data, 8); // data
|
memcpy(write + 2, payload->data, 8); // data
|
||||||
memcpy(write + 10, mac, sizeof(mac)); // mac
|
memcpy(write + 10, mac, sizeof(mac)); // mac
|
||||||
|
@ -1949,8 +1865,29 @@ void iClass_WriteBlock(uint8_t *msg) {
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
|
||||||
uint8_t resp[10] = {0};
|
uint8_t resp[10] = {0};
|
||||||
res = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time);
|
|
||||||
if (res == false) {
|
uint8_t tries = 3;
|
||||||
|
while (tries-- > 0) {
|
||||||
|
|
||||||
|
iclass_send_as_reader(write, sizeof(write), &start_time, &eof_time);
|
||||||
|
|
||||||
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
|
res = false;
|
||||||
|
switch_off();
|
||||||
|
if (payload->req.send_reply)
|
||||||
|
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time) == 10) {
|
||||||
|
res = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tries == 0) {
|
||||||
|
res = false;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1983,29 +1920,75 @@ out:
|
||||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
|
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn off afterwards
|
void iClass_Restore(iclass_restore_req_t *msg) {
|
||||||
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void iClass_Restore(uint8_t *msg) {
|
// sanitation
|
||||||
|
if (msg == NULL) {
|
||||||
|
reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iclass_restore_req_t *cmd = (iclass_restore_req_t *)msg;
|
if (msg->item_cnt == 0) {
|
||||||
// iclass_auth_req_t *req = &cmd->req;
|
if (msg->req.send_reply) {
|
||||||
|
reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
uint16_t written = 0;
|
Iso15693InitReader();
|
||||||
uint16_t total_blocks = (cmd->end_block - cmd->start_block) + 1;
|
|
||||||
for (uint8_t b = cmd->start_block; b < total_blocks; b++) {
|
|
||||||
|
|
||||||
if (iclass_writeblock_ext(b, cmd->data + ((b - cmd->start_block) * 12))) {
|
uint16_t written = 0;
|
||||||
Dbprintf("Write block [%02x] successful", b);
|
uint32_t eof_time = 0;
|
||||||
written++;
|
picopass_hdr hdr = {0};
|
||||||
} else {
|
|
||||||
Dbprintf("Write block [%02x] failed", b);
|
// select
|
||||||
|
bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time);
|
||||||
|
if (res == false) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticate
|
||||||
|
uint8_t mac[4] = {0};
|
||||||
|
uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
|
||||||
|
// authenticate
|
||||||
|
if (msg->req.do_auth) {
|
||||||
|
res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac);
|
||||||
|
if (res == false) {
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
for (uint8_t i = 0; i < msg->item_cnt; i++) {
|
||||||
|
|
||||||
|
iclass_restore_item_t item = msg->blocks[i];
|
||||||
|
|
||||||
|
// calc new mac for data, using 1b blockno, 8b data,
|
||||||
|
uint8_t wb[9] = {0};
|
||||||
|
wb[0] = item.blockno;
|
||||||
|
memcpy(wb + 1, item.data, 8);
|
||||||
|
|
||||||
|
if (msg->req.use_credit_key)
|
||||||
|
doMAC_N(wb, sizeof(wb), hdr.key_c, mac);
|
||||||
|
else
|
||||||
|
doMAC_N(wb, sizeof(wb), hdr.key_d, mac);
|
||||||
|
|
||||||
|
// data + mac
|
||||||
|
if (iclass_writeblock_ext(item.blockno, item.data, mac)) {
|
||||||
|
Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno);
|
||||||
|
written++;
|
||||||
|
} else {
|
||||||
|
Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
switch_off();
|
switch_off();
|
||||||
uint8_t isOK = (written == total_blocks) ? 1 : 0;
|
if (msg->req.send_reply) {
|
||||||
reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t));
|
int isOK = (written == msg->item_cnt) ? PM3_SUCCESS : PM3_ESOFT;
|
||||||
|
reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,11 @@
|
||||||
|
|
||||||
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||||
void ReaderIClass(uint8_t arg0);
|
void ReaderIClass(uint8_t arg0);
|
||||||
void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac);
|
|
||||||
|
|
||||||
void iClass_WriteBlock(uint8_t *msg);
|
void iClass_WriteBlock(uint8_t *msg);
|
||||||
void iClass_Dump(uint8_t *msg);
|
void iClass_Dump(uint8_t *msg);
|
||||||
|
|
||||||
void iClass_Restore(uint8_t *msg);
|
void iClass_Restore(iclass_restore_req_t *msg);
|
||||||
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
|
|
||||||
|
|
||||||
int do_iclass_simulation_nonsec(void);
|
int do_iclass_simulation_nonsec(void);
|
||||||
int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf);
|
int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf);
|
||||||
|
@ -37,6 +35,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||||
void iClass_ReadBlock(uint8_t *msg);
|
void iClass_ReadBlock(uint8_t *msg);
|
||||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
||||||
|
|
||||||
bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time);
|
bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time);
|
||||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2624,13 +2624,13 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
||||||
} // else force RATS
|
} // else force RATS
|
||||||
|
|
||||||
// RATS, Request for answer to select
|
// RATS, Request for answer to select
|
||||||
if (!no_rats) {
|
if (no_rats == false) {
|
||||||
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0
|
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0
|
||||||
AddCrc14A(rats, 2);
|
AddCrc14A(rats, 2);
|
||||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
ReaderTransmit(rats, sizeof(rats), NULL);
|
||||||
int len = ReaderReceive(resp, resp_par);
|
int len = ReaderReceive(resp, resp_par);
|
||||||
|
if (len == 0)
|
||||||
if (!len) return 0;
|
return 0;
|
||||||
|
|
||||||
if (p_card) {
|
if (p_card) {
|
||||||
memcpy(p_card->ats, resp, sizeof(p_card->ats));
|
memcpy(p_card->ats, resp, sizeof(p_card->ats));
|
||||||
|
@ -2929,10 +2929,15 @@ void ReaderIso14443a(PacketCommandNG *c) {
|
||||||
ReaderTransmit(cmd, len, NULL); // 8 bits, odd parity
|
ReaderTransmit(cmd, len, NULL); // 8 bits, odd parity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arg0 = ReaderReceive(buf, par);
|
|
||||||
FpgaDisableTracing();
|
|
||||||
|
|
||||||
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
|
FpgaDisableTracing();
|
||||||
|
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
|
||||||
|
} else {
|
||||||
|
arg0 = ReaderReceive(buf, par);
|
||||||
|
FpgaDisableTracing();
|
||||||
|
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((param & ISO14A_REQUEST_TRIGGER))
|
if ((param & ISO14A_REQUEST_TRIGGER))
|
||||||
|
|
|
@ -1895,12 +1895,17 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
|
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
|
||||||
|
|
||||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw
|
FpgaDisableTracing();
|
||||||
FpgaDisableTracing();
|
reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0);
|
||||||
|
} else {
|
||||||
|
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||||
|
status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw
|
||||||
|
FpgaDisableTracing();
|
||||||
|
|
||||||
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
|
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
|
||||||
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
|
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -290,6 +290,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) {
|
||||||
LED_B_OFF();
|
LED_B_OFF();
|
||||||
|
|
||||||
*start_time = *start_time + DELAY_ARM_TO_TAG;
|
*start_time = *start_time + DELAY_ARM_TO_TAG;
|
||||||
|
FpgaDisableTracing();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -732,6 +733,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
||||||
}
|
}
|
||||||
|
|
||||||
FpgaDisableSscDma();
|
FpgaDisableSscDma();
|
||||||
|
FpgaDisableTracing();
|
||||||
|
|
||||||
uint32_t sof_time = *eof_time
|
uint32_t sof_time = *eof_time
|
||||||
- (dt->len * 8 * 8 * 16) // time for byte transfers
|
- (dt->len * 8 * 8 * 16) // time for byte transfers
|
||||||
|
@ -1469,17 +1471,22 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
||||||
// low speed (1 out of 256)
|
// low speed (1 out of 256)
|
||||||
CodeIso15693AsReader256(send, sendlen);
|
CodeIso15693AsReader256(send, sendlen);
|
||||||
}
|
}
|
||||||
|
int res = 0;
|
||||||
tosend_t *ts = get_tosend();
|
tosend_t *ts = get_tosend();
|
||||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
|
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
|
||||||
*eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF
|
|
||||||
LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true);
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||||
|
|
||||||
int res = 0;
|
res = PM3_ETEAROFF;
|
||||||
if (recv != NULL) {
|
|
||||||
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
|
} else {
|
||||||
|
|
||||||
|
*eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF
|
||||||
|
LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true);
|
||||||
|
if (recv != NULL) {
|
||||||
|
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FpgaDisableTracing();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1495,7 +1502,6 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
|
||||||
if (recv != NULL) {
|
if (recv != NULL) {
|
||||||
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
|
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
|
||||||
}
|
}
|
||||||
FpgaDisableTracing();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1588,41 +1594,49 @@ void ReaderIso15693(uint32_t parameter) {
|
||||||
BuildIdentifyRequest(cmd);
|
BuildIdentifyRequest(cmd);
|
||||||
uint32_t start_time = 0;
|
uint32_t start_time = 0;
|
||||||
uint32_t eof_time;
|
uint32_t eof_time;
|
||||||
int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time);
|
int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time);
|
||||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
|
||||||
|
if (recvlen == PM3_ETEAROFF) { // tearoff occured
|
||||||
|
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||||
|
|
||||||
// we should do a better check than this
|
// we should do a better check than this
|
||||||
if (answerLen >= 12) {
|
if (recvlen >= 12) {
|
||||||
uint8_t uid[8];
|
uint8_t uid[8];
|
||||||
uid[0] = answer[9]; // always E0
|
uid[0] = answer[9]; // always E0
|
||||||
uid[1] = answer[8]; // IC Manufacturer code
|
uid[1] = answer[8]; // IC Manufacturer code
|
||||||
uid[2] = answer[7];
|
uid[2] = answer[7];
|
||||||
uid[3] = answer[6];
|
uid[3] = answer[6];
|
||||||
uid[4] = answer[5];
|
uid[4] = answer[5];
|
||||||
uid[5] = answer[4];
|
uid[5] = answer[4];
|
||||||
uid[6] = answer[3];
|
uid[6] = answer[3];
|
||||||
uid[7] = answer[2];
|
uid[7] = answer[2];
|
||||||
|
|
||||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||||
Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X",
|
Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
uid[0], uid[1], uid[2], uid[3],
|
uid[0], uid[1], uid[2], uid[3],
|
||||||
uid[4], uid[5], uid[5], uid[6]
|
uid[4], uid[5], uid[5], uid[6]
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
// send UID back to client.
|
||||||
|
// arg0 = 1 = OK
|
||||||
|
// arg1 = len of response (12 bytes)
|
||||||
|
// arg2 = rtf
|
||||||
|
// asbytes = uid.
|
||||||
|
reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid));
|
||||||
|
|
||||||
|
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||||
|
Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen);
|
||||||
|
DbdecodeIso15693Answer(recvlen, answer);
|
||||||
|
Dbhexdump(recvlen, answer, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DbpString("Failed to select card");
|
||||||
|
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
// send UID back to client.
|
|
||||||
// arg0 = 1 = OK
|
|
||||||
// arg1 = len of response (12 bytes)
|
|
||||||
// arg2 = rtf
|
|
||||||
// asbytes = uid.
|
|
||||||
reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
|
||||||
Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen);
|
|
||||||
DbdecodeIso15693Answer(answerLen, answer);
|
|
||||||
Dbhexdump(answerLen, answer, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_off();
|
switch_off();
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
}
|
}
|
||||||
|
@ -1767,6 +1781,11 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
||||||
|
|
||||||
if (recvlen >= 12) {
|
if (recvlen >= 12) {
|
||||||
Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, recv + 2));
|
Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, recv + 2));
|
||||||
|
} else {
|
||||||
|
DbpString("Failed to select card");
|
||||||
|
reply_ng(CMD_ACK, PM3_ESOFT, NULL, 0);
|
||||||
|
switch_off();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now with AFI
|
// now with AFI
|
||||||
|
@ -1816,10 +1835,9 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
|
||||||
|
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
int recvlen = 0;
|
|
||||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||||
uint32_t eof_time = 0;
|
|
||||||
uint16_t timeout;
|
uint16_t timeout;
|
||||||
|
uint32_t eof_time = 0;
|
||||||
bool request_answer = false;
|
bool request_answer = false;
|
||||||
|
|
||||||
switch (data[1]) {
|
switch (data[1]) {
|
||||||
|
@ -1837,43 +1855,29 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
|
||||||
timeout = ISO15693_READER_TIMEOUT;
|
timeout = ISO15693_READER_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
|
||||||
Dbprintf("SEND:");
|
|
||||||
Dbhexdump(datalen, data, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t start_time = 0;
|
uint32_t start_time = 0;
|
||||||
recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time);
|
int recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time);
|
||||||
|
|
||||||
// send a single EOF to get the tag response
|
if (recvlen == PM3_ETEAROFF) { // tearoff occured
|
||||||
if (request_answer) {
|
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
|
||||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
} else {
|
||||||
recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time);
|
|
||||||
|
// send a single EOF to get the tag response
|
||||||
|
if (request_answer) {
|
||||||
|
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||||
|
recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv) {
|
||||||
|
recvlen = MIN(recvlen,ISO15693_MAX_RESPONSE_LENGTH);
|
||||||
|
reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen);
|
||||||
|
} else {
|
||||||
|
reply_mix(CMD_ACK, 1, 0, 0, NULL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the time being, switch field off to protect rdv4.0
|
|
||||||
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
|
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
LED_D_OFF();
|
LED_D_OFF();
|
||||||
|
|
||||||
if (recv) {
|
|
||||||
|
|
||||||
if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) {
|
|
||||||
recvlen = ISO15693_MAX_RESPONSE_LENGTH;
|
|
||||||
}
|
|
||||||
reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen);
|
|
||||||
|
|
||||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
|
||||||
|
|
||||||
Dbprintf("RECV:");
|
|
||||||
if (recvlen > 0) {
|
|
||||||
Dbhexdump(recvlen, recvbuf, false);
|
|
||||||
DbdecodeIso15693Answer(recvlen, recvbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2695,9 +2695,8 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
|
||||||
//
|
//
|
||||||
// Tear-off attack against MFU.
|
// Tear-off attack against MFU.
|
||||||
// - Moebius et al
|
// - Moebius et al
|
||||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
||||||
uint8_t blockNo = arg0;
|
uint8_t blockNo = arg0;
|
||||||
uint32_t tearOffTime = arg1;
|
|
||||||
uint8_t data_fullwrite[4] = {0x00};
|
uint8_t data_fullwrite[4] = {0x00};
|
||||||
uint8_t data_testwrite[4] = {0x00};
|
uint8_t data_testwrite[4] = {0x00};
|
||||||
memcpy(data_fullwrite, datain, 4);
|
memcpy(data_fullwrite, datain, 4);
|
||||||
|
@ -2705,8 +2704,8 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
||||||
|
|
||||||
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
|
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
|
||||||
|
|
||||||
if (tearOffTime > 43000)
|
if (tearoff_time > 43000)
|
||||||
tearOffTime = 43000;
|
tearoff_time = 43000;
|
||||||
|
|
||||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||||
|
|
||||||
|
@ -2732,9 +2731,50 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
||||||
// Wait before cutting power. aka tear-off
|
// Wait before cutting power. aka tear-off
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
|
|
||||||
SpinDelayUsPrecision(tearOffTime);
|
SpinDelayUsPrecision(tearoff_time);
|
||||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
|
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
|
||||||
switch_off();
|
switch_off();
|
||||||
|
|
||||||
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
|
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Tear-off attack against MFU counter
|
||||||
|
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
||||||
|
|
||||||
|
if (tearoff_time > 43000)
|
||||||
|
tearoff_time = 43000;
|
||||||
|
|
||||||
|
LEDsoff();
|
||||||
|
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||||
|
clear_trace();
|
||||||
|
set_tracing(true);
|
||||||
|
|
||||||
|
// Send MFU counter increase cmd
|
||||||
|
uint8_t cmd[] = {
|
||||||
|
MIFARE_ULEV1_INCR_CNT,
|
||||||
|
counter,
|
||||||
|
0, // lsb
|
||||||
|
0,
|
||||||
|
0, // msb
|
||||||
|
0, // rfu
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||||
|
|
||||||
|
// anticollision / select card
|
||||||
|
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||||
|
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||||
|
OnError(1);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// send
|
||||||
|
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||||
|
LED_D_ON();
|
||||||
|
SpinDelayUsPrecision(tearoff_time);
|
||||||
|
switch_off();
|
||||||
|
|
||||||
|
reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
||||||
|
|
||||||
// Tear-off test for MFU
|
// Tear-off test for MFU
|
||||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
|
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
|
||||||
|
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -246,7 +246,9 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdlf.c
|
${PM3_ROOT}/client/src/cmdlf.c
|
||||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||||
|
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||||
|
${PM3_ROOT}/client/src/cmdlfem4x05.c
|
||||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||||
|
|
|
@ -441,7 +441,9 @@ SRCS = aidsearch.c \
|
||||||
cmdlf.c \
|
cmdlf.c \
|
||||||
cmdlfawid.c \
|
cmdlfawid.c \
|
||||||
cmdlfcotag.c \
|
cmdlfcotag.c \
|
||||||
|
cmdlfdestron.c \
|
||||||
cmdlfem4x.c \
|
cmdlfem4x.c \
|
||||||
|
cmdlfem4x05.c \
|
||||||
cmdlfem4x50.c \
|
cmdlfem4x50.c \
|
||||||
cmdlffdxb.c \
|
cmdlffdxb.c \
|
||||||
cmdlfguard.c \
|
cmdlfguard.c \
|
||||||
|
|
|
@ -125,6 +125,7 @@ add_library(pm3rrg_rdv4 SHARED
|
||||||
${PM3_ROOT}/client/src/cmdlf.c
|
${PM3_ROOT}/client/src/cmdlf.c
|
||||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||||
|
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||||
|
|
|
@ -26,6 +26,8 @@ A5B4C3D2
|
||||||
50520901
|
50520901
|
||||||
# default PROX
|
# default PROX
|
||||||
50524F58
|
50524F58
|
||||||
|
# blue gun EM4305
|
||||||
|
F9DCEBA0
|
||||||
# Default pwd, simple:
|
# Default pwd, simple:
|
||||||
00000000
|
00000000
|
||||||
11111111
|
11111111
|
||||||
|
@ -123,3 +125,7 @@ b5f44686 # seeds ul-ev1
|
||||||
C6EF3720 # TEA
|
C6EF3720 # TEA
|
||||||
7854794A # xbox tea constant :)
|
7854794A # xbox tea constant :)
|
||||||
F1EA5EED # burtle
|
F1EA5EED # burtle
|
||||||
|
69314718 # ln2
|
||||||
|
57721566 # euler constant (dec)
|
||||||
|
93C467E3 # euler constant (hex)
|
||||||
|
27182818 # natural log
|
|
@ -36,7 +36,7 @@ arguments = [[
|
||||||
end
|
end
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local set_tearoff_delay = 'hw tearoff -s --on --delay %d'
|
local set_tearoff_delay = 'hw tearoff --on --delay %d'
|
||||||
local wr_template = 'lf em 4x05_write %s %s %s'
|
local wr_template = 'lf em 4x05_write %s %s %s'
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -250,6 +250,10 @@ local function main(args)
|
||||||
local wordstr14b = ('%08X'):format(word14b)
|
local wordstr14b = ('%08X'):format(word14b)
|
||||||
if (wordstr14b == '00000000') then
|
if (wordstr14b == '00000000') then
|
||||||
reset(wr_value, password)
|
reset(wr_value, password)
|
||||||
|
word14b, err14b = core.em4x05_read(14, password)
|
||||||
|
if err14b then
|
||||||
|
return oops(err14b)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if (wordstr14b ~= rd_value) then
|
if (wordstr14b ~= rd_value) then
|
||||||
local word15b, err15b = core.em4x05_read(15, password)
|
local word15b, err15b = core.em4x05_read(15, password)
|
||||||
|
@ -299,17 +303,17 @@ local function main(args)
|
||||||
else
|
else
|
||||||
print(('[=] Status: failed to commit => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b))
|
print(('[=] Status: failed to commit => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b))
|
||||||
end
|
end
|
||||||
|
if auto then
|
||||||
|
n = 0
|
||||||
|
ed = sd
|
||||||
|
else
|
||||||
|
tries = 0
|
||||||
|
soon = 0
|
||||||
|
late = 0
|
||||||
|
end
|
||||||
else
|
else
|
||||||
print(('[=] Status: 15 bitflipped but inactive => '..ansicolors.yellow..'PROMISING: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15))
|
print(('[=] Status: 15 bitflipped but inactive => '..ansicolors.yellow..'PROMISING: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15))
|
||||||
end
|
end
|
||||||
if auto then
|
|
||||||
n = 0
|
|
||||||
ed = sd
|
|
||||||
else
|
|
||||||
tries = 0
|
|
||||||
soon = 0
|
|
||||||
late = 0
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not auto then
|
if not auto then
|
||||||
|
|
|
@ -1949,7 +1949,7 @@ int CmdSave(const char *Cmd) {
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("w", "wave", "save as wave format (.wav)"),
|
arg_lit0("w", "wave", "save as wave format (.wav)"),
|
||||||
arg_strx0("f", "file", "<fn w/o ext>", "save file name"),
|
arg_str1("f", "file", "<fn w/o ext>", "save file name"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -1958,7 +1958,9 @@ int CmdSave(const char *Cmd) {
|
||||||
|
|
||||||
int fnlen = 0;
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
CLIGetStrWithReturn(ctx, 2, (uint8_t *)filename, &fnlen);
|
// CLIGetStrWithReturn(ctx, 2, (uint8_t *)filename, &fnlen);
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (as_wave)
|
if (as_wave)
|
||||||
|
|
|
@ -1362,7 +1362,7 @@ static int waitCmd(uint8_t iSelect, uint32_t timeout) {
|
||||||
|
|
||||||
uint8_t *data = resp.data.asBytes;
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
|
||||||
if (len >= 3) {
|
if (iSelect == 0 && len >= 3) {
|
||||||
bool crc = check_crc(CRC_14443_A, data, len);
|
bool crc = check_crc(CRC_14443_A, data, len);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s",
|
PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s",
|
||||||
|
@ -1831,11 +1831,47 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) {
|
if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) {
|
||||||
const char *tip = "";
|
const char *tip = "";
|
||||||
if (card.ats[0] - pos >= 7) {
|
if (card.ats[0] - pos >= 7) {
|
||||||
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
|
||||||
tip = "-> MIFARE Plus X 2K or 4K";
|
if ((card.sak & 0x70) == 0x40) { // and no GetVersion()..
|
||||||
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
|
||||||
tip = "-> MIFARE Plus S 2K or 4K";
|
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus X 2K/4K (SL3)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||||
|
|
||||||
|
if ((card.atqa[0] & 0x02) == 0x02)
|
||||||
|
tip = "-> MIFARE Plus S 2K (SL3)";
|
||||||
|
else if ((card.atqa[0] & 0x04) == 0x04)
|
||||||
|
tip = "-> MIFARE Plus S 4K (SL3)";
|
||||||
|
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus SE 1K (17pF)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus SE 1K (70pF)";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { //SAK B4,5,6
|
||||||
|
|
||||||
|
if ((card.sak & 0x20) == 0x20) { // and no GetVersion()..
|
||||||
|
|
||||||
|
|
||||||
|
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus X 2K (SL1)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus S 2K (SL1)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus SE 1K (17pF)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus SE 1K (70pF)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus X 4K (SL1)";
|
||||||
|
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
|
||||||
|
tip = "-> MIFARE Plus S 4K (SL1)";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
|
PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip);
|
||||||
if (card.ats[pos] == 0xC1) {
|
if (card.ats[pos] == 0xC1) {
|
||||||
|
|
|
@ -323,7 +323,7 @@ static int usage_15_raw(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_15_read(void) {
|
static int usage_15_read(void) {
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] <uid|s|u|*> <page>\n"
|
PrintAndLogEx(NORMAL, "Usage: hf 15 rdbl [options] <uid|s|u|*> <page>\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
"\t-2 use slower '1 out of 256' mode\n"
|
"\t-2 use slower '1 out of 256' mode\n"
|
||||||
"\tuid (either): \n"
|
"\tuid (either): \n"
|
||||||
|
@ -334,7 +334,7 @@ static int usage_15_read(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_15_write(void) {
|
static int usage_15_write(void) {
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] <uid|s|u|*> <page> <hexdata>\n"
|
PrintAndLogEx(NORMAL, "Usage: hf 15 wrbl [options] <uid|s|u|*> <page> <hexdata>\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
"\t-2 use slower '1 out of 256' mode\n"
|
"\t-2 use slower '1 out of 256' mode\n"
|
||||||
"\t-o set OPTION Flag (needed for TI)\n"
|
"\t-o set OPTION Flag (needed for TI)\n"
|
||||||
|
@ -816,6 +816,10 @@ static int NxpSysInfo(uint8_t *uid) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
int status = resp.oldarg[0];
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command");
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command");
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
|
@ -975,6 +979,9 @@ static int CmdHF15Info(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
int status = resp.oldarg[0];
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status);
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status);
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
|
@ -1153,9 +1160,13 @@ static int CmdHF15WriteAfi(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *data = resp.data.asBytes;
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
|
||||||
if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
|
if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
|
||||||
|
@ -1212,6 +1223,10 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *data = resp.data.asBytes;
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
|
||||||
|
@ -1296,6 +1311,9 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
|
|
||||||
int len = resp.oldarg[0];
|
int len = resp.oldarg[0];
|
||||||
|
if (len == PM3_ETEAROFF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (len < 2) {
|
if (len < 2) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 command failed");
|
PrintAndLogEx(FAILED, "iso15693 command failed");
|
||||||
continue;
|
continue;
|
||||||
|
@ -1321,6 +1339,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
blocknum++;
|
blocknum++;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "." NOLF);
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1419,6 +1438,10 @@ static int CmdHF15Raw(const char *Cmd) {
|
||||||
if (reply) {
|
if (reply) {
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
int len = resp.oldarg[0];
|
int len = resp.oldarg[0];
|
||||||
|
if (len == PM3_ETEAROFF) {
|
||||||
|
DropField();
|
||||||
|
return len;
|
||||||
|
}
|
||||||
if (len < 2) {
|
if (len < 2) {
|
||||||
PrintAndLogEx(WARNING, "command failed");
|
PrintAndLogEx(WARNING, "command failed");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1491,6 +1514,10 @@ static int CmdHF15Readmulti(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
int status = resp.oldarg[0];
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 card readmulti failed");
|
PrintAndLogEx(FAILED, "iso15693 card readmulti failed");
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
|
@ -1574,6 +1601,9 @@ static int CmdHF15Read(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
int status = resp.oldarg[0];
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(ERR, "iso15693 command failed");
|
PrintAndLogEx(ERR, "iso15693 command failed");
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
|
@ -1661,6 +1691,10 @@ static int CmdHF15Write(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
int status = resp.oldarg[0];
|
int status = resp.oldarg[0];
|
||||||
|
if (status == PM3_ETEAROFF) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
if (status < 2) {
|
if (status < 2) {
|
||||||
PrintAndLogEx(FAILED, "iso15693 command failed");
|
PrintAndLogEx(FAILED, "iso15693 command failed");
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
|
@ -1876,13 +1910,13 @@ static command_t CommandTable[] = {
|
||||||
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
||||||
{"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
{"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
||||||
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
|
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
|
||||||
{"read", CmdHF15Read, IfPm3Iso15693, "Read a block"},
|
{"rdbl", CmdHF15Read, IfPm3Iso15693, "Read a block"},
|
||||||
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
|
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
|
||||||
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
|
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
|
||||||
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
|
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
|
||||||
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
|
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
|
||||||
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
|
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
|
||||||
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
|
{"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"},
|
||||||
{"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"},
|
{"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"},
|
||||||
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
|
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
|
||||||
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},
|
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},
|
||||||
|
|
|
@ -915,7 +915,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) {
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
||||||
{"info", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"},
|
{"list", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"},
|
||||||
{"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."},
|
{"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."},
|
||||||
{"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
{"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
||||||
{"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
{"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
||||||
|
|
|
@ -155,10 +155,11 @@ static int usage_hf_iclass_dump(void) {
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
PrintAndLogEx(NORMAL, " h : Show this help");
|
||||||
PrintAndLogEx(NORMAL, " f <filename> : specify a filename to save dump to");
|
PrintAndLogEx(NORMAL, " f <filename> : specify a filename to save dump to");
|
||||||
PrintAndLogEx(NORMAL, " k <key> : <required> access Key as 16 hex symbols or 1 hex to select key from memory");
|
PrintAndLogEx(NORMAL, " k <key> : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay");
|
||||||
PrintAndLogEx(NORMAL, " c <creditkey>: credit key as 16 hex symbols or 1 hex to select key from memory");
|
PrintAndLogEx(NORMAL, " c <creditkey>: credit key as 16 hex symbols or 1 hex to select key from memory");
|
||||||
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
||||||
PrintAndLogEx(NORMAL, " r : raw, the key is interpreted as raw block 3/4");
|
PrintAndLogEx(NORMAL, " r : raw, the key is interpreted as raw block 3/4");
|
||||||
|
PrintAndLogEx(NORMAL, " n : replay of NR/MAC");
|
||||||
PrintAndLogEx(NORMAL, " v : verbose output");
|
PrintAndLogEx(NORMAL, " v : verbose output");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
|
@ -195,10 +196,11 @@ static int usage_hf_iclass_writeblock(void) {
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
PrintAndLogEx(NORMAL, " h : Show this help");
|
||||||
PrintAndLogEx(NORMAL, " b <block> : The block number as 2 hex symbols");
|
PrintAndLogEx(NORMAL, " b <block> : The block number as 2 hex symbols");
|
||||||
PrintAndLogEx(NORMAL, " d <data> : set the Data to write as 16 hex symbols");
|
PrintAndLogEx(NORMAL, " d <data> : set the Data to write as 16 hex symbols");
|
||||||
PrintAndLogEx(NORMAL, " k <key> : access Key as 16 hex symbols or 1 hex to select key from memory");
|
PrintAndLogEx(NORMAL, " k <key> : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay");
|
||||||
PrintAndLogEx(NORMAL, " c : credit key assumed\n");
|
PrintAndLogEx(NORMAL, " c : credit key assumed\n");
|
||||||
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
||||||
PrintAndLogEx(NORMAL, " r : raw, no computations applied to key (raw)");
|
PrintAndLogEx(NORMAL, " r : raw, no computations applied to key (raw)");
|
||||||
|
// PrintAndLogEx(NORMAL, " n : replay of NR/MAC");
|
||||||
PrintAndLogEx(NORMAL, " v : verbose output");
|
PrintAndLogEx(NORMAL, " v : verbose output");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 0A d AAAAAAAAAAAAAAAA k 001122334455667B"));
|
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 0A d AAAAAAAAAAAAAAAA k 001122334455667B"));
|
||||||
|
@ -213,10 +215,11 @@ static int usage_hf_iclass_readblock(void) {
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
PrintAndLogEx(NORMAL, " h : Show this help");
|
PrintAndLogEx(NORMAL, " h : Show this help");
|
||||||
PrintAndLogEx(NORMAL, " b <block> : The block number as 2 hex symbols");
|
PrintAndLogEx(NORMAL, " b <block> : The block number as 2 hex symbols");
|
||||||
PrintAndLogEx(NORMAL, " k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
|
PrintAndLogEx(NORMAL, " k <key> : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay");
|
||||||
PrintAndLogEx(NORMAL, " c : credit key assumed\n");
|
PrintAndLogEx(NORMAL, " c : credit key assumed\n");
|
||||||
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
PrintAndLogEx(NORMAL, " e : elite computations applied to key");
|
||||||
PrintAndLogEx(NORMAL, " r : raw, no computations applied to key");
|
PrintAndLogEx(NORMAL, " r : raw, no computations applied to key");
|
||||||
|
PrintAndLogEx(NORMAL, " n : replay of NR/MAC");
|
||||||
PrintAndLogEx(NORMAL, " v : verbose output");
|
PrintAndLogEx(NORMAL, " v : verbose output");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 06 k 0011223344556677"));
|
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 06 k 0011223344556677"));
|
||||||
|
@ -280,18 +283,6 @@ static int usage_hf_iclass_reader(void) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
static int usage_hf_iclass_replay(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Replay a collected mac message\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf iclass replay [h] [m <mac>]\n");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h Show this help");
|
|
||||||
PrintAndLogEx(NORMAL, " r <nonce> Reader nonce bytes to replay (8 hexsymbols)");
|
|
||||||
PrintAndLogEx(NORMAL, " m <mac> Mac bytes to replay (8 hexsymbols)");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass replay r 00000000 m 89cb984b"));
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_hf_iclass_loclass(void) {
|
static int usage_hf_iclass_loclass(void) {
|
||||||
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
|
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
|
||||||
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
|
PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of");
|
||||||
|
@ -346,7 +337,6 @@ static int usage_hf_iclass_lookup(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int cmp_uint32(const void *a, const void *b) {
|
static int cmp_uint32(const void *a, const void *b) {
|
||||||
|
|
||||||
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
||||||
|
@ -890,131 +880,6 @@ static int CmdHFiClassReader(const char *Cmd) {
|
||||||
return read_iclass_csn(loop_read, true);
|
return read_iclass_csn(loop_read, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHFiClassReader_Replay(const char *Cmd) {
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t reader[4];
|
|
||||||
uint8_t mac[4];
|
|
||||||
} PACKED payload;
|
|
||||||
|
|
||||||
|
|
||||||
bool got_rnr, got_mac;
|
|
||||||
got_rnr = got_mac = false;
|
|
||||||
bool errors = false;
|
|
||||||
uint8_t cmdp = 0;
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h': {
|
|
||||||
return usage_hf_iclass_replay();
|
|
||||||
}
|
|
||||||
case 'r': {
|
|
||||||
if (param_gethex(Cmd, cmdp + 1, payload.reader, 8)) {
|
|
||||||
PrintAndLogEx(FAILED, "Reader Nr must include 8 HEX symbols");
|
|
||||||
errors = true;
|
|
||||||
} else {
|
|
||||||
got_rnr = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'm': {
|
|
||||||
if (param_gethex(Cmd, cmdp + 1, payload.mac, 8)) {
|
|
||||||
PrintAndLogEx(FAILED, "Reader MAC must include 8 HEX symbols");
|
|
||||||
errors = true;
|
|
||||||
} else {
|
|
||||||
got_mac = true;
|
|
||||||
}
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Validations
|
|
||||||
if (errors || cmdp == 0) {
|
|
||||||
return usage_hf_iclass_replay();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (got_rnr == false || got_mac == false) {
|
|
||||||
PrintAndLogEx(FAILED, "Reader Nr and MAC is needed");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
PacketResponseNG resp;
|
|
||||||
clearCommandBuffer();
|
|
||||||
SendCommandNG(CMD_HF_ICLASS_REPLAY, (uint8_t *)&payload, sizeof(payload));
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
PrintAndLogEx(NORMAL, "." NOLF);
|
|
||||||
|
|
||||||
if (kbd_enter_pressed()) {
|
|
||||||
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
|
|
||||||
DropField();
|
|
||||||
return PM3_EOPABORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_REPLAY, &resp, 2000))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
if (resp.status != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(ERR, "failed to communicate with card");
|
|
||||||
return resp.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct p_resp {
|
|
||||||
bool isOK;
|
|
||||||
uint16_t block_cnt;
|
|
||||||
uint32_t bb_offset;
|
|
||||||
} PACKED;
|
|
||||||
struct p_resp *packet = (struct p_resp *)resp.data.asBytes;
|
|
||||||
|
|
||||||
if (packet->isOK == false) {
|
|
||||||
PrintAndLogEx(WARNING, "replay reading blocks failed");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t startindex = packet->bb_offset;
|
|
||||||
uint32_t bytes_got = (packet->block_cnt * 8);
|
|
||||||
|
|
||||||
uint8_t tag_data[0x100 * 8];
|
|
||||||
memset(tag_data, 0xFF, sizeof(tag_data));
|
|
||||||
|
|
||||||
// response ok - now get bigbuf content of the dump
|
|
||||||
if (!GetFromDevice(BIG_BUF, tag_data, sizeof(tag_data), startindex, NULL, 0, NULL, 2500, false)) {
|
|
||||||
PrintAndLogEx(WARNING, "command execution time out");
|
|
||||||
return PM3_ETIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print the dump
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(INFO, "------+----+-------------------------+----------");
|
|
||||||
PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8));
|
|
||||||
printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got);
|
|
||||||
|
|
||||||
// use CSN as filename
|
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
|
||||||
strcat(filename, "hf-iclass-");
|
|
||||||
FillFileNameByUID(filename, tag_data, "-dump", 8);
|
|
||||||
|
|
||||||
// save the dump to .bin file
|
|
||||||
PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8);
|
|
||||||
saveFile(filename, ".bin", tag_data, bytes_got);
|
|
||||||
saveFileEML(filename, tag_data, bytes_got, 8);
|
|
||||||
saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL);
|
|
||||||
|
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt") "` to decrypt dump file");
|
|
||||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFiClassELoad(const char *Cmd) {
|
static int CmdHFiClassELoad(const char *Cmd) {
|
||||||
|
|
||||||
DumpFileType_t dftype = BIN;
|
DumpFileType_t dftype = BIN;
|
||||||
|
@ -1271,7 +1136,6 @@ static int CmdHFiClassEView(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int CmdHFiClassDecrypt(const char *Cmd) {
|
static int CmdHFiClassDecrypt(const char *Cmd) {
|
||||||
|
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
|
@ -1567,13 +1431,6 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) {
|
|
||||||
uint8_t wb[9];
|
|
||||||
wb[0] = blockno;
|
|
||||||
memcpy(wb + 1, data, 8);
|
|
||||||
doMAC_N(wb, sizeof(wb), div_key, MAC);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) {
|
static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) {
|
||||||
|
|
||||||
uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
||||||
|
@ -1611,47 +1468,6 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
|
|
||||||
|
|
||||||
iclass_auth_req_t payload = {
|
|
||||||
.use_raw = rawkey,
|
|
||||||
.use_elite = elite,
|
|
||||||
.use_credit_key = use_credit_key
|
|
||||||
};
|
|
||||||
memcpy(payload.key, KEY, 8);
|
|
||||||
|
|
||||||
SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t *)&payload, sizeof(payload));
|
|
||||||
PacketResponseNG resp;
|
|
||||||
clearCommandBuffer();
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) {
|
|
||||||
if (verbose) PrintAndLogEx(WARNING, "Command execute timeout");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS) {
|
|
||||||
if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
iclass_readblock_resp_t *packet = (iclass_readblock_resp_t *)resp.data.asBytes;
|
|
||||||
|
|
||||||
if (packet->isOK == 0) {
|
|
||||||
if (verbose) PrintAndLogEx(FAILED, "authentication error");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (div_key)
|
|
||||||
memcpy(div_key, packet->div_key, sizeof(packet->div_key));
|
|
||||||
|
|
||||||
if (MAC)
|
|
||||||
memcpy(MAC, packet->mac, sizeof(packet->mac));
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CmdHFiClassDump(const char *Cmd) {
|
static int CmdHFiClassDump(const char *Cmd) {
|
||||||
|
|
||||||
uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
@ -1665,6 +1481,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||||
bool have_credit_key = false;
|
bool have_credit_key = false;
|
||||||
bool elite = false;
|
bool elite = false;
|
||||||
bool rawkey = false;
|
bool rawkey = false;
|
||||||
|
bool use_replay = false;
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
bool auth = false;
|
bool auth = false;
|
||||||
uint8_t cmdp = 0;
|
uint8_t cmdp = 0;
|
||||||
|
@ -1732,12 +1549,23 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||||
rawkey = true;
|
rawkey = true;
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
|
||||||
|
use_replay = true;
|
||||||
|
cmdp++;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||||
errors = true;
|
errors = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((use_replay + rawkey + elite) > 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||||
|
errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (errors) return usage_hf_iclass_dump();
|
if (errors) return usage_hf_iclass_dump();
|
||||||
|
|
||||||
uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE);
|
||||||
|
@ -1808,6 +1636,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||||
.req.use_raw = rawkey,
|
.req.use_raw = rawkey,
|
||||||
.req.use_elite = elite,
|
.req.use_elite = elite,
|
||||||
.req.use_credit_key = false,
|
.req.use_credit_key = false,
|
||||||
|
.req.use_replay = use_replay,
|
||||||
.req.send_reply = true,
|
.req.send_reply = true,
|
||||||
.req.do_auth = auth,
|
.req.do_auth = auth,
|
||||||
.end_block = app_limit1,
|
.end_block = app_limit1,
|
||||||
|
@ -1974,49 +1803,13 @@ write_dump:
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
|
static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose) {
|
||||||
/*
|
|
||||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
|
||||||
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) {
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
calc_wb_mac(blockno, bldata, div_key, MAC);
|
|
||||||
|
|
||||||
struct p {
|
|
||||||
uint8_t blockno;
|
|
||||||
uint8_t data[12];
|
|
||||||
} PACKED payload;
|
|
||||||
payload.blockno = blockno;
|
|
||||||
|
|
||||||
memcpy(payload.data, bldata, 8);
|
|
||||||
memcpy(payload.data + 8, MAC, 4);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
typedef struct {
|
|
||||||
uint8_t key[8];
|
|
||||||
bool use_raw;
|
|
||||||
bool use_elite;
|
|
||||||
bool use_credit_key;
|
|
||||||
bool send_reply;
|
|
||||||
bool do_auth;
|
|
||||||
uint8_t blockno;
|
|
||||||
} PACKED iclass_auth_req_t;
|
|
||||||
|
|
||||||
// iCLASS write block request data structure
|
|
||||||
typedef struct {
|
|
||||||
iclass_auth_req_t req;
|
|
||||||
uint8_t data[8];
|
|
||||||
} PACKED iclass_writeblock_req_t;
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
iclass_writeblock_req_t payload = {
|
iclass_writeblock_req_t payload = {
|
||||||
.req.use_raw = rawkey,
|
.req.use_raw = rawkey,
|
||||||
.req.use_elite = elite,
|
.req.use_elite = elite,
|
||||||
.req.use_credit_key = use_credit_key,
|
.req.use_credit_key = use_credit_key,
|
||||||
|
.req.use_replay = replay,
|
||||||
.req.blockno = blockno,
|
.req.blockno = blockno,
|
||||||
.req.send_reply = true,
|
.req.send_reply = true,
|
||||||
.req.do_auth = true,
|
.req.do_auth = true,
|
||||||
|
@ -2035,9 +1828,8 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bo
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS) {
|
if (resp.status != PM3_SUCCESS) {
|
||||||
if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
|
if (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
|
||||||
return PM3_EWRONGANSWER;
|
return resp.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT;
|
return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2052,6 +1844,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
||||||
bool use_credit_key = false;
|
bool use_credit_key = false;
|
||||||
bool elite = false;
|
bool elite = false;
|
||||||
bool rawkey = false;
|
bool rawkey = false;
|
||||||
|
bool use_replay = false;
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
uint8_t cmdp = 0;
|
uint8_t cmdp = 0;
|
||||||
|
@ -2105,6 +1898,13 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
||||||
rawkey = true;
|
rawkey = true;
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
|
case 'n':
|
||||||
|
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
|
||||||
|
use_replay = true;
|
||||||
|
cmdp++;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
cmdp++;
|
cmdp++;
|
||||||
|
@ -2118,21 +1918,29 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
|
||||||
if (got_blockno == false)
|
if (got_blockno == false)
|
||||||
errors = true;
|
errors = true;
|
||||||
|
|
||||||
|
if ((use_replay + rawkey + elite) > 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||||
|
errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (errors || cmdp < 6) return usage_hf_iclass_writeblock();
|
if (errors || cmdp < 6) return usage_hf_iclass_writeblock();
|
||||||
|
|
||||||
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose);
|
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose);
|
||||||
if (isok == PM3_SUCCESS)
|
switch(isok) {
|
||||||
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
|
case PM3_SUCCESS:
|
||||||
else
|
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
|
||||||
PrintAndLogEx(FAILED, "Writing failed");
|
break;
|
||||||
|
case PM3_ETEAROFF:
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLogEx(INFO, "Writing tear off triggered");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLogEx(FAILED, "Writing failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
return isok;
|
return isok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static int CmdHFiClassClone(const char *Cmd) {
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
static int CmdHFiClassRestore(const char *Cmd) {
|
static int CmdHFiClassRestore(const char *Cmd) {
|
||||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||||
char tempStr[50] = {0};
|
char tempStr[50] = {0};
|
||||||
|
@ -2184,7 +1992,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
||||||
} else if (dataLen == 1) {
|
} else if (dataLen == 1) {
|
||||||
keyNbr = param_get8(Cmd, cmdp + 1);
|
keyNbr = param_get8(Cmd, cmdp + 1);
|
||||||
if (keyNbr < ICLASS_KEYS_MAX) {
|
if (keyNbr < ICLASS_KEYS_MAX) {
|
||||||
PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8));
|
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8));
|
||||||
memcpy(KEY, iClass_Key_Table[keyNbr], 8);
|
memcpy(KEY, iClass_Key_Table[keyNbr], 8);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n");
|
||||||
|
@ -2221,14 +2029,19 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
||||||
|
|
||||||
if (errors || cmdp < 8) return usage_hf_iclass_restore();
|
if (errors || cmdp < 8) return usage_hf_iclass_restore();
|
||||||
|
|
||||||
|
if (rawkey + elite > 1) {
|
||||||
|
PrintAndLogEx(FAILED, "Can not use both 'e', 'r'");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
if (startblock < 5) {
|
if (startblock < 5) {
|
||||||
PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4");
|
PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_bytes = (((endblock - startblock) + 1) * 12);
|
uint32_t payload_size = sizeof(iclass_restore_req_t) + (sizeof(iclass_restore_item_t) * (endblock - startblock + 1));
|
||||||
|
|
||||||
if (total_bytes > PM3_CMD_DATA_SIZE - 2) {
|
if (payload_size > PM3_CMD_DATA_SIZE) {
|
||||||
PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8);
|
PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -2246,103 +2059,82 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read < sizeof(iclass_block_t) * (endblock - startblock + 1)) {
|
if (bytes_read < ((endblock - startblock + 1) * 8 )) {
|
||||||
PrintAndLogEx(ERR, "file wrong size");
|
PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )",
|
||||||
|
startblock, endblock
|
||||||
|
);
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iclass_restore_req_t *payload = calloc(1, payload_size);
|
||||||
|
payload->req.use_raw = rawkey,
|
||||||
|
payload->req.use_elite = elite,
|
||||||
|
payload->req.use_credit_key = use_credit_key,
|
||||||
|
payload->req.use_replay = false,
|
||||||
|
payload->req.blockno = startblock,
|
||||||
|
payload->req.send_reply = true,
|
||||||
|
payload->req.do_auth = true,
|
||||||
|
memcpy(payload->req.key, KEY, 8);
|
||||||
|
|
||||||
|
payload->item_cnt = (endblock - startblock + 1);
|
||||||
|
|
||||||
// read data from file from block 6 --- 19
|
// read data from file from block 6 --- 19
|
||||||
// we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
|
// we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
|
||||||
// then copy to usbcommand->asbytes;
|
// then copy to usbcommand->asbytes;
|
||||||
// max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes
|
// max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes
|
||||||
iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12];
|
|
||||||
|
|
||||||
memcpy(tag_data, dump + startblock * 8, sizeof(iclass_block_t) * (endblock - startblock + 1));
|
for (uint8_t i = 0; i < payload->item_cnt; i++) {
|
||||||
|
payload->blocks[i].blockno = startblock + i;
|
||||||
|
memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8) , sizeof(payload->blocks[i].data));
|
||||||
|
}
|
||||||
|
|
||||||
free(dump);
|
free(dump);
|
||||||
|
|
||||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
|
||||||
uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
int i;
|
|
||||||
int numberAuthRetries = ICLASS_AUTH_RETRY;
|
|
||||||
do {
|
|
||||||
if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
|
|
||||||
break;
|
|
||||||
} while (numberAuthRetries--);
|
|
||||||
|
|
||||||
if (numberAuthRetries <= 0) {
|
|
||||||
PrintAndLogEx(ERR, "failed to authenticate");
|
|
||||||
DropField();
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t data[total_bytes];
|
|
||||||
|
|
||||||
// calculate all mac for every the block we will write
|
|
||||||
for (i = startblock; i <= endblock; i++) {
|
|
||||||
|
|
||||||
calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC);
|
|
||||||
// usb command d start pointer = d + (i - 6) * 12
|
|
||||||
// memcpy(pointer,tag_data[i - 6],8) 8 bytes
|
|
||||||
// memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
|
|
||||||
// next one
|
|
||||||
uint8_t *ptr = data + (i - startblock) * 12;
|
|
||||||
memcpy(ptr, &(tag_data[i - startblock].d[0]), 8);
|
|
||||||
memcpy(ptr + 8, MAC, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(INFO, "------+--------------------------+-------------");
|
PrintAndLogEx(INFO, "Preparing to restore block range 0x%02x..0x%02x", startblock, endblock);
|
||||||
PrintAndLogEx(INFO, "block | data | mac");
|
|
||||||
PrintAndLogEx(INFO, "------+--------------------------+-------------");
|
PrintAndLogEx(INFO, "------+----------------------");
|
||||||
uint8_t p[12];
|
PrintAndLogEx(INFO, "block | data");
|
||||||
for (i = 0; i <= endblock - startblock; i++) {
|
PrintAndLogEx(INFO, "------+----------------------");
|
||||||
memcpy(p, data + (i * 12), 12);
|
|
||||||
char *s = calloc(70, sizeof(uint8_t));
|
for (uint8_t i = 0; i < payload->item_cnt; i++) {
|
||||||
snprintf(s, 70, "| %s ", sprint_hex(p, 8));
|
iclass_restore_item_t item = payload->blocks[i];
|
||||||
snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4));
|
PrintAndLogEx(INFO, " %02X | %s", item.blockno, sprint_hex_inrow(item.data, sizeof(item.data)));
|
||||||
PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s);
|
|
||||||
free(s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct p {
|
PrintAndLogEx(INFO, "restore started...");
|
||||||
uint8_t startblock;
|
|
||||||
uint8_t endblock;
|
|
||||||
uint8_t data[PM3_CMD_DATA_SIZE - 2];
|
|
||||||
} PACKED payload;
|
|
||||||
|
|
||||||
payload.startblock = startblock;
|
|
||||||
payload.endblock = endblock;
|
|
||||||
memcpy(payload.data, data, total_bytes);
|
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2);
|
SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size);
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) {
|
if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) {
|
||||||
PrintAndLogEx(WARNING, "command execute timeout");
|
PrintAndLogEx(WARNING, "command execute timeout");
|
||||||
DropField();
|
DropField();
|
||||||
|
free(payload);
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.status == PM3_SUCCESS) {
|
if (resp.status == PM3_SUCCESS) {
|
||||||
if (resp.data.asBytes[0] == 1)
|
PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful"));
|
||||||
PrintAndLogEx(SUCCESS, "Restore successful");
|
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card");
|
||||||
else
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Restore failed");
|
PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(payload);
|
||||||
return resp.status;
|
return resp.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth, uint8_t *out) {
|
static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose, bool auth, uint8_t *out) {
|
||||||
|
|
||||||
iclass_auth_req_t payload = {
|
iclass_auth_req_t payload = {
|
||||||
.use_raw = rawkey,
|
.use_raw = rawkey,
|
||||||
.use_elite = elite,
|
.use_elite = elite,
|
||||||
.use_credit_key = (keyType == 0x18),
|
.use_credit_key = (keyType == 0x18),
|
||||||
|
.use_replay = replay,
|
||||||
.blockno = blockno,
|
.blockno = blockno,
|
||||||
.send_reply = true,
|
.send_reply = true,
|
||||||
.do_auth = auth,
|
.do_auth = auth,
|
||||||
|
@ -2391,6 +2183,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
bool got_blockno = false;
|
bool got_blockno = false;
|
||||||
bool elite = false;
|
bool elite = false;
|
||||||
bool rawkey = false;
|
bool rawkey = false;
|
||||||
|
bool use_replay = false;
|
||||||
bool errors = false;
|
bool errors = false;
|
||||||
bool auth = false;
|
bool auth = false;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
|
@ -2439,6 +2232,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
rawkey = true;
|
rawkey = true;
|
||||||
cmdp++;
|
cmdp++;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
|
||||||
|
use_replay = true;
|
||||||
|
cmdp++;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
cmdp++;
|
cmdp++;
|
||||||
|
@ -2451,6 +2249,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
}
|
}
|
||||||
if (got_blockno == false)
|
if (got_blockno == false)
|
||||||
errors = true;
|
errors = true;
|
||||||
|
|
||||||
|
if ((use_replay + rawkey + elite) > 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'");
|
||||||
|
errors = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (errors) return usage_hf_iclass_readblock();
|
if (errors) return usage_hf_iclass_readblock();
|
||||||
|
|
||||||
|
@ -2467,7 +2270,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[8] = {0};
|
uint8_t data[8] = {0};
|
||||||
int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth, data);
|
int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data);
|
||||||
if (res != PM3_SUCCESS)
|
if (res != PM3_SUCCESS)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
@ -3541,8 +3344,6 @@ static command_t CommandTable[] = {
|
||||||
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
|
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
|
||||||
{"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"},
|
{"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"},
|
||||||
{"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"},
|
{"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"},
|
||||||
{"replay", CmdHFiClassReader_Replay, IfPm3Iclass, "<mac> Read Picopass / iCLASS tag via replay attack"},
|
|
||||||
|
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
|
||||||
{"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"},
|
{"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"},
|
||||||
{"eload", CmdHFiClassELoad, IfPm3Iclass, "[f <fn> ] Load Picopass / iCLASS dump file into emulator memory"},
|
{"eload", CmdHFiClassELoad, IfPm3Iclass, "[f <fn> ] Load Picopass / iCLASS dump file into emulator memory"},
|
||||||
|
|
|
@ -629,6 +629,10 @@ static int CmdLegicWrbl(const char *Cmd) {
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||||
|
case 'h': {
|
||||||
|
errors = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'd': {
|
case 'd': {
|
||||||
// peek at length of the input string so we can
|
// peek at length of the input string so we can
|
||||||
// figure out how many elements to malloc in "data"
|
// figure out how many elements to malloc in "data"
|
||||||
|
@ -679,10 +683,6 @@ static int CmdLegicWrbl(const char *Cmd) {
|
||||||
cmdp += 2;
|
cmdp += 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'h': {
|
|
||||||
errors = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'y': {
|
case 'y': {
|
||||||
autoconfirm = true;
|
autoconfirm = true;
|
||||||
break;
|
break;
|
||||||
|
@ -695,6 +695,13 @@ static int CmdLegicWrbl(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Validations
|
||||||
|
if (errors || cmdp == 0) {
|
||||||
|
if (data)
|
||||||
|
free(data);
|
||||||
|
return usage_legic_wrbl();
|
||||||
|
}
|
||||||
|
|
||||||
// OUT-OF-BOUNDS checks
|
// OUT-OF-BOUNDS checks
|
||||||
// UID 4+1 bytes can't be written to.
|
// UID 4+1 bytes can't be written to.
|
||||||
if (offset < 5) {
|
if (offset < 5) {
|
||||||
|
@ -704,13 +711,6 @@ static int CmdLegicWrbl(const char *Cmd) {
|
||||||
return PM3_EOUTOFBOUND;
|
return PM3_EOUTOFBOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Validations
|
|
||||||
if (errors || cmdp == 0) {
|
|
||||||
if (data)
|
|
||||||
free(data);
|
|
||||||
return usage_legic_wrbl();
|
|
||||||
}
|
|
||||||
|
|
||||||
// tagtype
|
// tagtype
|
||||||
legic_card_select_t card;
|
legic_card_select_t card;
|
||||||
if (legic_get_type(&card) != PM3_SUCCESS) {
|
if (legic_get_type(&card) != PM3_SUCCESS) {
|
||||||
|
|
|
@ -627,6 +627,76 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint16_t NumOfBlocks(char card) {
|
||||||
|
switch (card) {
|
||||||
|
case '0' :
|
||||||
|
return MIFARE_MINI_MAXBLOCK;
|
||||||
|
case '1' :
|
||||||
|
return MIFARE_1K_MAXBLOCK;
|
||||||
|
case '2' :
|
||||||
|
return MIFARE_2K_MAXBLOCK;
|
||||||
|
case '4' :
|
||||||
|
return MIFARE_4K_MAXBLOCK;
|
||||||
|
default :
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NumOfSectors(char card) {
|
||||||
|
switch (card) {
|
||||||
|
case '0' :
|
||||||
|
return MIFARE_MINI_MAXSECTOR;
|
||||||
|
case '1' :
|
||||||
|
return MIFARE_1K_MAXSECTOR;
|
||||||
|
case '2' :
|
||||||
|
return MIFARE_2K_MAXSECTOR;
|
||||||
|
case '4' :
|
||||||
|
return MIFARE_4K_MAXSECTOR;
|
||||||
|
default :
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t FirstBlockOfSector(uint8_t sectorNo) {
|
||||||
|
if (sectorNo < 32) {
|
||||||
|
return sectorNo * 4;
|
||||||
|
} else {
|
||||||
|
return 32 * 4 + (sectorNo - 32) * 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t NumBlocksPerSector(uint8_t sectorNo) {
|
||||||
|
if (sectorNo < 32) {
|
||||||
|
return 4;
|
||||||
|
} else {
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t GetSectorFromBlockNo(uint8_t blockNo) {
|
||||||
|
if (blockNo < 128)
|
||||||
|
return blockNo / 4;
|
||||||
|
else
|
||||||
|
return 32 + ((128 - blockNo) / 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char GetFormatFromSector(uint8_t sectorNo) {
|
||||||
|
switch (sectorNo) {
|
||||||
|
case MIFARE_MINI_MAXSECTOR:
|
||||||
|
return '0';
|
||||||
|
case MIFARE_1K_MAXSECTOR:
|
||||||
|
return '1';
|
||||||
|
case MIFARE_2K_MAXSECTOR:
|
||||||
|
return '2';
|
||||||
|
case MIFARE_4K_MAXSECTOR:
|
||||||
|
return '4';
|
||||||
|
default :
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int CmdHF14AMfDarkside(const char *Cmd) {
|
static int CmdHF14AMfDarkside(const char *Cmd) {
|
||||||
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
|
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
|
@ -825,12 +895,9 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
|
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
|
||||||
if (isOK) {
|
if (isOK) {
|
||||||
|
|
||||||
uint8_t blocks = 4;
|
uint8_t blocks = NumBlocksPerSector(sectorNo);
|
||||||
uint8_t start = sectorNo * 4;
|
uint8_t start = FirstBlockOfSector(sectorNo);
|
||||||
if (sectorNo > 32) {
|
|
||||||
blocks = 16;
|
|
||||||
start = 128 + (sectorNo - 32) * 16;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < blocks; i++) {
|
for (int i = 0; i < blocks; i++) {
|
||||||
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16));
|
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16));
|
||||||
}
|
}
|
||||||
|
@ -843,74 +910,6 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t NumOfBlocks(char card) {
|
|
||||||
switch (card) {
|
|
||||||
case '0' :
|
|
||||||
return MIFARE_MINI_MAXBLOCK;
|
|
||||||
case '1' :
|
|
||||||
return MIFARE_1K_MAXBLOCK;
|
|
||||||
case '2' :
|
|
||||||
return MIFARE_2K_MAXBLOCK;
|
|
||||||
case '4' :
|
|
||||||
return MIFARE_4K_MAXBLOCK;
|
|
||||||
default :
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t NumOfSectors(char card) {
|
|
||||||
switch (card) {
|
|
||||||
case '0' :
|
|
||||||
return MIFARE_MINI_MAXSECTOR;
|
|
||||||
case '1' :
|
|
||||||
return MIFARE_1K_MAXSECTOR;
|
|
||||||
case '2' :
|
|
||||||
return MIFARE_2K_MAXSECTOR;
|
|
||||||
case '4' :
|
|
||||||
return MIFARE_4K_MAXSECTOR;
|
|
||||||
default :
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t FirstBlockOfSector(uint8_t sectorNo) {
|
|
||||||
if (sectorNo < 32) {
|
|
||||||
return sectorNo * 4;
|
|
||||||
} else {
|
|
||||||
return 32 * 4 + (sectorNo - 32) * 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t NumBlocksPerSector(uint8_t sectorNo) {
|
|
||||||
if (sectorNo < 32) {
|
|
||||||
return 4;
|
|
||||||
} else {
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t GetSectorFromBlockNo(uint8_t blockNo) {
|
|
||||||
if (blockNo < 128)
|
|
||||||
return blockNo / 4;
|
|
||||||
else
|
|
||||||
return 32 + ((128 - blockNo) / 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char GetFormatFromSector(uint8_t sectorNo) {
|
|
||||||
switch (sectorNo) {
|
|
||||||
case MIFARE_MINI_MAXSECTOR:
|
|
||||||
return '0';
|
|
||||||
case MIFARE_1K_MAXSECTOR:
|
|
||||||
return '1';
|
|
||||||
case MIFARE_2K_MAXSECTOR:
|
|
||||||
return '2';
|
|
||||||
case MIFARE_4K_MAXSECTOR:
|
|
||||||
return '4';
|
|
||||||
default :
|
|
||||||
return ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int FastDumpWithEcFill(uint8_t numsectors) {
|
static int FastDumpWithEcFill(uint8_t numsectors) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
|
@ -3671,7 +3670,7 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
|
||||||
uint8_t blocks = 4;
|
uint8_t blocks = 4;
|
||||||
uint8_t start = sector * 4;
|
uint8_t start = sector * 4;
|
||||||
if (sector > 32) {
|
if (sector >= 32) {
|
||||||
blocks = 16;
|
blocks = 16;
|
||||||
start = 128 + (sector - 32) * 16;
|
start = 128 + (sector - 32) * 16;
|
||||||
}
|
}
|
||||||
|
@ -4365,7 +4364,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) {
|
||||||
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
|
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
|
||||||
uint8_t blocks = 4;
|
uint8_t blocks = 4;
|
||||||
uint8_t start = sector * 4;
|
uint8_t start = sector * 4;
|
||||||
if (sector > 32) {
|
if (sector >= 32) {
|
||||||
blocks = 16;
|
blocks = 16;
|
||||||
start = 128 + (sector - 32) * 16;
|
start = 128 + (sector - 32) * 16;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version[7 + 7 + 7 + 5], version[7 + 7 + 7 + 5 + 1]);
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information"));
|
||||||
|
PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version, 7));
|
||||||
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
|
PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0]));
|
||||||
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1]));
|
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1]));
|
||||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]);
|
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(INFO, " Protocol: %s", getProtocolStr(version[6], true));
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Software Information"));
|
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, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7]));
|
||||||
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8]));
|
PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8]));
|
||||||
PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]);
|
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) {
|
static int CmdHFMFPInfo(const char *Cmd) {
|
||||||
|
|
||||||
if (Cmd && strlen(Cmd) > 0)
|
|
||||||
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
|
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
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 supportVersion = false;
|
||||||
bool supportSignature = false;
|
bool supportSignature = false;
|
||||||
|
|
||||||
|
@ -284,17 +294,11 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
||||||
} else {
|
} else {
|
||||||
// info about 14a part
|
// info about 14a part
|
||||||
infoHF14A(false, false, false);
|
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
|
// Signature originality check
|
||||||
uint8_t signature[56] = {0};
|
uint8_t signature[56] = {0};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "generator.h"
|
#include "generator.h"
|
||||||
#include "mifare/ndef.h"
|
#include "mifare/ndef.h"
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
|
#include "cmdmain.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_UL_BLOCKS 0x0F
|
#define MAX_UL_BLOCKS 0x0F
|
||||||
|
@ -170,7 +171,8 @@ static int usage_hf_mfu_sim(void) {
|
||||||
static int usage_hf_mfu_ucauth(void) {
|
static int usage_hf_mfu_ucauth(void) {
|
||||||
PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
|
PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
|
||||||
PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
|
PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
|
||||||
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth <password (32 hex symbols)>");
|
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth [k] <password (32 hex symbols)>");
|
||||||
|
PrintAndLogEx(NORMAL, " k - keep field on (only if a password is provided too)");
|
||||||
PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
|
PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
PrintAndLogEx(NORMAL, "Examples:");
|
||||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth"));
|
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth"));
|
||||||
|
@ -342,21 +344,28 @@ static int ul_send_cmd_raw(uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint
|
||||||
return resplen;
|
return resplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ul_select(iso14a_card_select_t *card) {
|
static bool ul_select(iso14a_card_select_t *card) {
|
||||||
|
|
||||||
ul_switch_on_field();
|
ul_switch_on_field();
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
bool ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500);
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||||
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
if (!ans || resp.oldarg[0] < 1) {
|
|
||||||
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
|
||||||
DropField();
|
DropField();
|
||||||
return 0;
|
return false;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
|
uint16_t len = (resp.oldarg[1] & 0xFFFF);
|
||||||
return 1;
|
if (len == 0) {
|
||||||
|
PrintAndLogEx(WARNING, "iso14443a card select failed");
|
||||||
|
DropField();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card)
|
||||||
|
memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This read command will at least return 16bytes.
|
// This read command will at least return 16bytes.
|
||||||
|
@ -878,13 +887,13 @@ static int ulev1_print_counters(void) {
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
|
||||||
uint8_t tear[1] = {0};
|
uint8_t tear[1] = {0};
|
||||||
uint8_t counter[3] = {0, 0, 0};
|
uint8_t counter[3] = {0, 0, 0};
|
||||||
uint16_t len = 0;
|
int len = 0;
|
||||||
for (uint8_t i = 0; i < 3; ++i) {
|
for (uint8_t i = 0; i < 3; ++i) {
|
||||||
ulev1_readTearing(i, tear, sizeof(tear));
|
ulev1_readTearing(i, tear, sizeof(tear));
|
||||||
len = ulev1_readCounter(i, counter, sizeof(counter));
|
len = ulev1_readCounter(i, counter, sizeof(counter));
|
||||||
if (len == 3) {
|
if (len == 3) {
|
||||||
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
|
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
|
||||||
PrintAndLogEx(SUCCESS, " - %02X tearing (" _GREEN_("%s") ")", tear[0], (tear[0] == 0xBD) ? "ok" : "failure");
|
PrintAndLogEx(SUCCESS, " - %02X tearing (%s)", tear[0], (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("failure"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
|
@ -1026,11 +1035,10 @@ static int ulc_magic_test(){
|
||||||
iso14a_card_select_t card;
|
iso14a_card_select_t card;
|
||||||
uint8_t nonce1[11] = {0x00};
|
uint8_t nonce1[11] = {0x00};
|
||||||
uint8_t nonce2[11] = {0x00};
|
uint8_t nonce2[11] = {0x00};
|
||||||
int status = ul_select(&card);
|
if ( !ul_select(&card) ){
|
||||||
if ( !status ){
|
|
||||||
return UL_ERROR;
|
return UL_ERROR;
|
||||||
}
|
}
|
||||||
status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
|
int status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
|
||||||
if ( status > 0 ) {
|
if ( status > 0 ) {
|
||||||
status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
|
status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
|
||||||
returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C;
|
returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C;
|
||||||
|
@ -1619,7 +1627,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
|
||||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Read Single Block
|
// Read Single Block
|
||||||
|
@ -2398,25 +2406,31 @@ static int CmdHF14AMfUSim(const char *Cmd) {
|
||||||
//
|
//
|
||||||
|
|
||||||
static int CmdHF14AMfUCAuth(const char *Cmd) {
|
static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
uint8_t cmdp = 0;
|
||||||
if (cmdp == 'h') {
|
char c = tolower(param_getchar(Cmd, 0));
|
||||||
|
if (c == 'h') {
|
||||||
return usage_hf_mfu_ucauth();
|
return usage_hf_mfu_ucauth();
|
||||||
}
|
}
|
||||||
|
bool keep_field_on = false;
|
||||||
|
if (c == 'k') {
|
||||||
|
keep_field_on = true;
|
||||||
|
cmdp++;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t key_buf[16];
|
uint8_t key_buf[16];
|
||||||
uint8_t *key;
|
uint8_t *key;
|
||||||
int succeeded;
|
int succeeded;
|
||||||
|
|
||||||
// If no hex key is specified, try all known ones
|
// If no hex key is specified, try all known ones
|
||||||
if (strlen(Cmd) == 0) {
|
if (strlen(Cmd + cmdp) == 0) {
|
||||||
succeeded = try_default_3des_keys(&key);
|
succeeded = try_default_3des_keys(&key);
|
||||||
// Else try user-supplied
|
// Else try user-supplied
|
||||||
} else {
|
} else {
|
||||||
if (param_gethex(Cmd, 0, key_buf, 32)) {
|
if (param_gethex(Cmd, cmdp, key_buf, 32)) {
|
||||||
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
succeeded = ulc_authentication(key_buf, true);
|
succeeded = ulc_authentication(key_buf, ! keep_field_on);
|
||||||
key = key_buf;
|
key = key_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2933,11 +2947,19 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
|
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
|
||||||
|
|
||||||
|
// we be getting ACK that we are silently ignoring here..
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
|
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "Failed");
|
PrintAndLogEx(WARNING, "Failed");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resp.status != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(WARNING, "Tear off reporting failure to select tag");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
got_post = false;
|
got_post = false;
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
|
||||||
|
@ -3037,6 +3059,401 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static int counter_reset_tear(iso14a_card_select_t *card, uint8_t cnt_no) {
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Reset tear check");
|
||||||
|
|
||||||
|
uint8_t cw[6] = { MIFARE_ULEV1_INCR_CNT, cnt_no, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
uint8_t ct[1] = {0};
|
||||||
|
uint8_t resp[10] = {0};
|
||||||
|
|
||||||
|
if (ul_select(card) == false) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to select card, exiting...");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
if (ul_send_cmd_raw(cw, sizeof(cw), resp, sizeof(resp)) < 0) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to write all ZEROS");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
if (ulev1_readTearing(cnt_no, ct, sizeof(ct)) < 0) {
|
||||||
|
PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
if (ct[0] != 0xBD) {
|
||||||
|
PrintAndLogEx(INFO, "Resetting seem to have failed, WHY!?");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf mfu countertear",
|
||||||
|
"Tear-off test against a Ev1 counter",
|
||||||
|
"hf mfu countertear\n"
|
||||||
|
"hf mfu countertear -s 200 -l 2500 -> target counter 0, start delay 200\n"
|
||||||
|
"hf mfu countertear -i 2 -s 200 -l 400 -> target counter 0, start delay 200\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_int0("c", "cnt", "<0,1,2>", "Target this EV1 counter (0,1,2)"),
|
||||||
|
arg_int0("i", "inc", "<dec>", "time interval to increase in each iteration - default 10 us"),
|
||||||
|
arg_int0("l", "limit", "<dec>", "test upper limit time - default 3000 us"),
|
||||||
|
arg_int0("s", "start", "<dec>", "test start time - default 0 us"),
|
||||||
|
arg_int0(NULL, "fix", "<dec>", "test fixed loop delay"),
|
||||||
|
arg_str0("x", "hex", NULL, "3 byte hex to increase counter with"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int interval = 0;
|
||||||
|
int time_limit, start_time = 0;
|
||||||
|
int counter = arg_get_int_def(ctx, 1, 0);
|
||||||
|
int fixed = arg_get_int_def(ctx, 5, -1);
|
||||||
|
|
||||||
|
if ( fixed == -1 ) {
|
||||||
|
interval = arg_get_int_def(ctx, 2, 10);
|
||||||
|
time_limit = arg_get_int_def(ctx, 3, 3000);
|
||||||
|
start_time = arg_get_int_def(ctx, 4, 0);
|
||||||
|
} else {
|
||||||
|
start_time = fixed;
|
||||||
|
interval = 0;
|
||||||
|
time_limit = fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t newvalue[5] = {0};
|
||||||
|
int newvaluelen = 0;
|
||||||
|
CLIGetHexWithReturn(ctx, 6, newvalue, &newvaluelen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// Validations
|
||||||
|
if (start_time > (time_limit - interval)) {
|
||||||
|
PrintAndLogEx(WARNING, "Wrong start time number");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (time_limit < interval) {
|
||||||
|
PrintAndLogEx(WARNING, "Wrong time limit number");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
if (time_limit > 43000) {
|
||||||
|
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
uint8_t cnt_no = 0;
|
||||||
|
if (counter < 0 || counter > 2) {
|
||||||
|
PrintAndLogEx(WARNING, "Counter must 0, 1 or 2");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt_no = (uint8_t)counter;
|
||||||
|
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
|
||||||
|
// reset counter tear
|
||||||
|
counter_reset_tear(&card, cnt_no);
|
||||||
|
|
||||||
|
if (ul_select(&card) == false) {
|
||||||
|
PrintAndLogEx(INFO, "failed to select card, exiting...");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inital_cnt[3] = {0, 0, 0};
|
||||||
|
int len = ulev1_readCounter(cnt_no, inital_cnt, sizeof(inital_cnt));
|
||||||
|
if ( len != sizeof(inital_cnt) ) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to read counter");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t inital_tear[1] = {0};
|
||||||
|
len = ulev1_readTearing(cnt_no, inital_tear, sizeof(inital_tear));
|
||||||
|
DropField();
|
||||||
|
if ( len != sizeof(inital_tear) ) {
|
||||||
|
PrintAndLogEx(WARNING, "failed to read ANTITEAR, exiting... %d", len);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wr_value = ( newvalue[0] | newvalue[1] << 8 | newvalue[2] << 16 );
|
||||||
|
uint32_t inital_value = ( inital_cnt[0] | inital_cnt[1] << 8 | inital_cnt[2] << 16 );;
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Ev1 Counter Tear off") " ---------------------");
|
||||||
|
PrintAndLogEx(INFO, "Target counter no [ " _GREEN_("%u") " ]", counter);
|
||||||
|
PrintAndLogEx(INFO, " counter value [ " _GREEN_("%s") " ]", sprint_hex_inrow(inital_cnt, sizeof(inital_cnt)));
|
||||||
|
PrintAndLogEx(INFO, " anti-tear value [ " _GREEN_("%02X") " ]", inital_tear[0]);
|
||||||
|
PrintAndLogEx(INFO, " increase value [ " _GREEN_("%s") " ]", sprint_hex_inrow(newvalue, newvaluelen));
|
||||||
|
PrintAndLogEx(INFO, "----------------------------------------------------");
|
||||||
|
|
||||||
|
uint8_t pre_tear = 0, post_tear = 0;
|
||||||
|
uint8_t pre[3] = {0};
|
||||||
|
uint8_t post[3] = {0};
|
||||||
|
uint32_t actual_time = start_time;
|
||||||
|
uint32_t a = 0, b = 0;
|
||||||
|
uint32_t loop = 0;
|
||||||
|
|
||||||
|
uint16_t late = 0;
|
||||||
|
|
||||||
|
while (actual_time <= (time_limit - interval)) {
|
||||||
|
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
loop++;
|
||||||
|
|
||||||
|
if (kbd_enter_pressed()) {
|
||||||
|
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INPLACE, "Using tear-off delay " _GREEN_("%" PRIu32) " us (attempt %u)", actual_time, loop);
|
||||||
|
|
||||||
|
if (ul_select(&card) == false) {
|
||||||
|
PrintAndLogEx(FAILED, "BEFORE, failed to select card, looping...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cntresp[3] = {0, 0, 0};
|
||||||
|
int rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
|
||||||
|
if ( rlen == sizeof(cntresp) ) {
|
||||||
|
memcpy(pre, cntresp, sizeof(pre));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, "BEFORE, failed to read COUNTER, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tear[1] = {0};
|
||||||
|
int tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
|
||||||
|
if ( tlen == sizeof(tear) ) {
|
||||||
|
pre_tear = tear[0];
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, "BEFORE, failed to read ANTITEAR, exiting... %d", tlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
struct p {
|
||||||
|
uint8_t counter;
|
||||||
|
uint32_t tearoff_time;
|
||||||
|
uint8_t value[3];
|
||||||
|
} PACKED payload;
|
||||||
|
payload.counter = cnt_no;
|
||||||
|
payload.tearoff_time = actual_time;
|
||||||
|
memcpy(payload.value, newvalue, sizeof(payload.value));
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
PacketResponseNG resp;
|
||||||
|
SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
|
||||||
|
if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
|
||||||
|
PrintAndLogEx(WARNING, "\ntear off command failed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ul_select(&card) == false) {
|
||||||
|
PrintAndLogEx(FAILED, "AFTER, failed to select card, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
|
||||||
|
if ( rlen == sizeof(cntresp) ) {
|
||||||
|
memcpy(post, cntresp, sizeof(post));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, "AFTER, failed to read COUNTER, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tear[0] = 0;
|
||||||
|
tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
|
||||||
|
if ( tlen == sizeof(tear) ) {
|
||||||
|
post_tear = tear[0];
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
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)));
|
||||||
|
|
||||||
|
bool post_tear_check = (post_tear == 0xBD);
|
||||||
|
a = (pre[0] | pre[1] << 8 | pre[2] << 16);
|
||||||
|
b = (post[0] | post[1] << 8 | post[2] << 16);
|
||||||
|
|
||||||
|
// A != B
|
||||||
|
if (memcmp(pre, post, sizeof(pre)) != 0) {
|
||||||
|
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
|
if (inital_value != a ) {
|
||||||
|
|
||||||
|
if ( inital_value != b )
|
||||||
|
PrintAndLogEx(INFO, "pre %08x, post %08x != inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(INFO, "pre %08x != inital and post %08x == inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ( inital_value != b )
|
||||||
|
PrintAndLogEx(INFO, "pre %08x == inital and post %08x != inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( b == 0 ) {
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Tear off occured (ZEROS value!) -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
|
||||||
|
, prestr
|
||||||
|
, poststr
|
||||||
|
, pre_tear
|
||||||
|
, post_tear
|
||||||
|
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( a > b ) {
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Tear off occured " _RED_("( LESS )") " -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
|
||||||
|
, prestr
|
||||||
|
, poststr
|
||||||
|
, pre_tear
|
||||||
|
, post_tear
|
||||||
|
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
|
||||||
|
PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bar = (0x1000000 - b) + 2;
|
||||||
|
// wr_value = bar;
|
||||||
|
// newvalue[0] = (bar) & 0xFF;
|
||||||
|
// newvalue[1] = ((bar >> 8) & 0xFF);
|
||||||
|
// newvalue[2] = ((bar >> 16) & 0xFF);
|
||||||
|
|
||||||
|
wr_value = 0;
|
||||||
|
newvalue[0] = 0;
|
||||||
|
newvalue[1] = 0;
|
||||||
|
newvalue[2] = 0;
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, " 0x1000000 - 0x%x == 0x%x", b, bar);
|
||||||
|
PrintAndLogEx(INFO, " new increase value 0x%x" , wr_value);
|
||||||
|
PrintAndLogEx(INFO, " because BAR + post == 0x%x" , bar + b);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Tear off occured (+1) (too late) -> ") "%s vs %s Tear: 0x%02X == 0x%02X ( %s )"
|
||||||
|
, prestr
|
||||||
|
, poststr
|
||||||
|
, pre_tear
|
||||||
|
, post_tear
|
||||||
|
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( post_tear_check && b == inital_value) {
|
||||||
|
PrintAndLogEx(INFO, "Reverted to previous value");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( wr_value != 0 ) {
|
||||||
|
|
||||||
|
//uint32_t bar = (0x1000000 - b) + 2;
|
||||||
|
wr_value = 0;
|
||||||
|
newvalue[0] = 0;
|
||||||
|
newvalue[1] = 0;
|
||||||
|
newvalue[2] = 0;
|
||||||
|
|
||||||
|
if ( b >= (inital_value + (2 * wr_value))) {
|
||||||
|
PrintAndLogEx(INFO, "Large " _YELLOW_("( JUMP )") " detected");
|
||||||
|
|
||||||
|
|
||||||
|
// wr_value = bar;
|
||||||
|
// newvalue[0] = (bar) & 0xFF;
|
||||||
|
// newvalue[1] = ((bar >> 8) & 0xFF);
|
||||||
|
// newvalue[2] = ((bar >> 16) & 0xFF);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// wr_value = bar;
|
||||||
|
// newvalue[0] = (bar) & 0xFF;
|
||||||
|
// newvalue[1] = ((bar >> 8) & 0xFF);
|
||||||
|
// newvalue[2] = ((bar >> 16) & 0xFF);
|
||||||
|
// wr_value = 0;
|
||||||
|
// newvalue[0] = 0;
|
||||||
|
// newvalue[1] = 0;
|
||||||
|
// newvalue[2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
|
||||||
|
|
||||||
|
//actual_time--;
|
||||||
|
late++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("Status: same value! -> ") "%s == %s Tear: 0x%02X == 0x%02X ( %s )"
|
||||||
|
, prestr
|
||||||
|
, poststr
|
||||||
|
, pre_tear
|
||||||
|
, post_tear
|
||||||
|
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( post_tear_check ) {
|
||||||
|
if ( a == b ) {
|
||||||
|
//actual_time--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( b == inital_value ) {
|
||||||
|
PrintAndLogEx(INFO, "Reverted to previous value");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
|
||||||
|
PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual_time += interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, " Sent %u tear offs ", loop);
|
||||||
|
|
||||||
|
counter_reset_tear(&card, cnt_no);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "hf 14a raw -s -c 3900 --> read counter 0");
|
||||||
|
PrintAndLogEx(INFO, "hf 14a raw -s -c 3e00 --> read tearing 0");
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
char read_cnt_str[30];
|
||||||
|
sprintf(read_cnt_str, "hf 14a raw -s -c 39%02x", counter);
|
||||||
|
CommandReceived(read_cnt_str);
|
||||||
|
char read_tear_str[30];
|
||||||
|
sprintf(read_tear_str, "hf 14a raw -s -c 3e%02x", counter);
|
||||||
|
CommandReceived(read_tear_str);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
static int CmdHF14MfuNDEF(const char *Cmd) {
|
static int CmdHF14MfuNDEF(const char *Cmd) {
|
||||||
|
|
||||||
int keylen;
|
int keylen;
|
||||||
|
@ -3167,6 +3584,7 @@ static command_t CommandTable[] = {
|
||||||
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
|
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
|
||||||
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
|
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
|
||||||
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
|
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
|
||||||
|
// {"countertear", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1 Counter bits"},
|
||||||
{"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
{"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "cmdhw.h"
|
#include "cmdhw.h"
|
||||||
#include "cmddata.h"
|
#include "cmddata.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
@ -516,6 +517,33 @@ static int CmdStatus(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
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"));
|
||||||
|
} else if (verbose)
|
||||||
|
PrintAndLogEx(WARNING, "Tear-off command failed.");
|
||||||
|
return resp.status;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdTearoff(const char *Cmd) {
|
static int CmdTearoff(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hw tearoff",
|
CLIParserInit(&ctx, "hw tearoff",
|
||||||
|
@ -536,11 +564,7 @@ static int CmdTearoff(const char *Cmd) {
|
||||||
};
|
};
|
||||||
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
struct {
|
tearoff_params_t params;
|
||||||
uint16_t delay_us;
|
|
||||||
bool on;
|
|
||||||
bool off;
|
|
||||||
} PACKED params;
|
|
||||||
int delay = arg_get_int_def(ctx, 1, -1);
|
int delay = arg_get_int_def(ctx, 1, -1);
|
||||||
params.on = arg_get_lit(ctx, 2);
|
params.on = arg_get_lit(ctx, 2);
|
||||||
params.off = arg_get_lit(ctx, 3);
|
params.off = arg_get_lit(ctx, 3);
|
||||||
|
@ -562,29 +586,7 @@ static int CmdTearoff(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
return handle_tearoff(¶ms, !silent);
|
||||||
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)¶ms, sizeof(params));
|
|
||||||
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)
|
|
||||||
PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params.delay_us);
|
|
||||||
if (params.on && silent == false)
|
|
||||||
PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
|
|
||||||
if (params.off && silent == false)
|
|
||||||
PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (silent == false)
|
|
||||||
PrintAndLogEx(WARNING, "Tear-off command failed.");
|
|
||||||
|
|
||||||
return resp.status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdTia(const char *Cmd) {
|
static int CmdTia(const char *Cmd) {
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
#define CMDHW_H__
|
#define CMDHW_H__
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
int CmdHW(const char *Cmd);
|
int CmdHW(const char *Cmd);
|
||||||
|
|
||||||
|
int handle_tearoff(tearoff_params_t *params, bool verbose);
|
||||||
void pm3_version(bool verbose, bool oneliner);
|
void pm3_version(bool verbose, bool oneliner);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,12 +30,14 @@
|
||||||
#include "cmddata.h" // for `lf search`
|
#include "cmddata.h" // for `lf search`
|
||||||
#include "cmdlfawid.h" // for awid menu
|
#include "cmdlfawid.h" // for awid menu
|
||||||
#include "cmdlfem4x.h" // for em4x menu
|
#include "cmdlfem4x.h" // for em4x menu
|
||||||
#include "cmdlfem4x50.h" // for em4x50
|
#include "cmdlfem4x05.h" // for em4x05 / 4x69
|
||||||
|
#include "cmdlfem4x50.h" // for em4x50
|
||||||
#include "cmdlfhid.h" // for hid menu
|
#include "cmdlfhid.h" // for hid menu
|
||||||
#include "cmdlfhitag.h" // for hitag menu
|
#include "cmdlfhitag.h" // for hitag menu
|
||||||
#include "cmdlfidteck.h" // for idteck menu
|
#include "cmdlfidteck.h" // for idteck menu
|
||||||
#include "cmdlfio.h" // for ioprox menu
|
#include "cmdlfio.h" // for ioprox menu
|
||||||
#include "cmdlfcotag.h" // for COTAG meny
|
#include "cmdlfcotag.h" // for COTAG meny
|
||||||
|
#include "cmdlfdestron.h" // for FDX-A FECAVA Destron menu
|
||||||
#include "cmdlffdxb.h" // for FDX-B menu
|
#include "cmdlffdxb.h" // for FDX-B menu
|
||||||
#include "cmdlfgallagher.h" // for GALLAGHER menu
|
#include "cmdlfgallagher.h" // for GALLAGHER menu
|
||||||
#include "cmdlfguard.h" // for gproxii menu
|
#include "cmdlfguard.h" // for gproxii menu
|
||||||
|
@ -1447,6 +1449,7 @@ int CmdLFfind(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (demodVisa2k(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Visa2000 ID") " found!"); goto out;}
|
if (demodVisa2k(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Visa2000 ID") " found!"); goto out;}
|
||||||
|
if (demodDestron(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-A FECAVA Destron ID") " found!"); goto out;} // to do before HID
|
||||||
if (demodHID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;}
|
if (demodHID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;}
|
||||||
if (demodAWID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;}
|
if (demodAWID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;}
|
||||||
if (demodIOProx(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;}
|
if (demodIOProx(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;}
|
||||||
|
@ -1526,6 +1529,7 @@ static command_t CommandTable[] = {
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"},
|
||||||
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
|
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
|
||||||
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
|
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
|
||||||
|
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"},
|
||||||
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
|
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
|
||||||
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||||
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
||||||
|
|
189
client/src/cmdlfdestron.c
Normal file
189
client/src/cmdlfdestron.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Low frequency FDX-A FECAVA Destron tag commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#include "cmdlfdestron.h"
|
||||||
|
|
||||||
|
#include <ctype.h> //tolower
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
#include "commonutil.h" // ARRAYLEN
|
||||||
|
#include "common.h"
|
||||||
|
#include "cmdparser.h" // command_t
|
||||||
|
#include "comms.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "cmddata.h"
|
||||||
|
#include "cmdlf.h"
|
||||||
|
#include "lfdemod.h" // preamble test
|
||||||
|
#include "protocols.h" // t55xx defines
|
||||||
|
#include "cmdlft55xx.h" // clone..
|
||||||
|
#include "cmdlf.h" // cmdlfconfig
|
||||||
|
#include "cliparser.h" // cli parse input
|
||||||
|
#include "parity.h"
|
||||||
|
|
||||||
|
#define DESTRON_FRAME_SIZE 96
|
||||||
|
#define DESTRON_PREAMBLE_SIZE 16
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
int demodDestron(bool verbose) {
|
||||||
|
(void) verbose; // unused so far
|
||||||
|
//PSK1
|
||||||
|
if (FSKrawDemod(0, 0, 0, 0, false) != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: FSK Demod failed");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
size_t size = DemodBufferLen;
|
||||||
|
int ans = detectDestron(DemodBuffer, &size);
|
||||||
|
if (ans < 0) {
|
||||||
|
if (ans == -1)
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: too few bits found");
|
||||||
|
else if (ans == -2)
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: preamble not found");
|
||||||
|
else if (ans == -3)
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: Size not correct: %zu", size);
|
||||||
|
else
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: ans: %d", ans);
|
||||||
|
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
setDemodBuff(DemodBuffer, DESTRON_FRAME_SIZE, ans);
|
||||||
|
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
|
||||||
|
|
||||||
|
uint8_t bits[DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE] = {0};
|
||||||
|
size_t bitlen = DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE;
|
||||||
|
memcpy(bits, DemodBuffer + 16, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
|
||||||
|
|
||||||
|
uint8_t alignPos = 0;
|
||||||
|
uint16_t errCnt = manrawdecode(bits, &bitlen, 0, &alignPos);
|
||||||
|
if (errCnt > 0) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: Manchester decoding errors: %d", ans);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t data[5] = {0};
|
||||||
|
uint8_t parity_err = 0;
|
||||||
|
for (int i=0; i < sizeof(data); i++) {
|
||||||
|
data[i] = bytebits_to_byte(bits + i * 8, 8);
|
||||||
|
parity_err += oddparity8(data[i]);
|
||||||
|
data[i] &= 0x7F;
|
||||||
|
}
|
||||||
|
if (parity_err > 0) {
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: parity errors: %d", parity_err);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%02X%02X%02X%02X%02X"), data[0], data[1], data[2], data[3], data[4]);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdDestronDemod(const char *Cmd) {
|
||||||
|
(void)Cmd;
|
||||||
|
return demodDestron(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdDestronRead(const char *Cmd) {
|
||||||
|
lf_read(false, 16000);
|
||||||
|
return demodDestron(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdDestronClone(const char *Cmd) {
|
||||||
|
|
||||||
|
uint32_t blocks[4] = {0};
|
||||||
|
uint8_t data[8];
|
||||||
|
int datalen = 0;
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "lf destron clone",
|
||||||
|
"Enables cloning of Destron card with specified uid onto T55x7",
|
||||||
|
"lf destron clone 1A2B3C4D5E"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
|
||||||
|
//TODO add selection of chip for Q5 or T55x7
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
CLIGetHexWithReturn(ctx, 1, data, &datalen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
uint8_t data_ex[12 + 24] = {0}; // ManchesterEncode need extra room
|
||||||
|
for (int i=0; i < datalen; i++) {
|
||||||
|
data_ex[i + 1] = ~data [i] | (evenparity8(data[i]) << 7);
|
||||||
|
}
|
||||||
|
for (int i=0; i < 3; i++) {
|
||||||
|
blocks[i+1] = manchesterEncode2Bytes((data_ex[i*2]<<8)+data_ex[i*2+1]);
|
||||||
|
}
|
||||||
|
// inject preamble
|
||||||
|
blocks[1] = (blocks[1] & 0xFFFF) | 0xAAE20000;
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Preparing to clone Destron tag with ID: %s", sprint_hex(data, datalen));
|
||||||
|
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
|
||||||
|
|
||||||
|
print_blocks(blocks, ARRAYLEN(blocks));
|
||||||
|
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||||
|
PrintAndLogEx(SUCCESS, "Done");
|
||||||
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf Destron read`") " to verify");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdDestronSim(const char *Cmd) {
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
|
||||||
|
{"read", CmdDestronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
|
||||||
|
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
|
||||||
|
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdLFDestron(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find Destron preamble in already demoded data
|
||||||
|
int detectDestron(uint8_t *dest, size_t *size) {
|
||||||
|
|
||||||
|
//make sure buffer has data
|
||||||
|
if (*size < 64)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size_t found_size = *size;
|
||||||
|
size_t start_idx = 0;
|
||||||
|
|
||||||
|
uint8_t preamble[DESTRON_PREAMBLE_SIZE] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0};
|
||||||
|
|
||||||
|
// preamble not found
|
||||||
|
if (!preambleSearch(dest, preamble, sizeof(preamble), &found_size, &start_idx)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(DEBUG, "DEBUG: detectDestron FSK found preamble");
|
||||||
|
|
||||||
|
*size = found_size;
|
||||||
|
// wrong demoded size
|
||||||
|
if (*size != 96)
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
return (int)start_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readDestronUid(void) {
|
||||||
|
return (CmdDestronRead("") == PM3_SUCCESS);
|
||||||
|
}
|
19
client/src/cmdlfdestron.h
Normal file
19
client/src/cmdlfdestron.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Low frequency FDX-A FECAVA Destron tag commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#ifndef CMDLFDESTRON_H__
|
||||||
|
#define CMDLFDESTRON_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int CmdLFDestron(const char *Cmd);
|
||||||
|
int detectDestron(uint8_t *bits, size_t *size);
|
||||||
|
int demodDestron(bool verbose);
|
||||||
|
int readDestronUid(void);
|
||||||
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,10 +16,8 @@
|
||||||
int CmdLFEM4X(const char *Cmd);
|
int CmdLFEM4X(const char *Cmd);
|
||||||
|
|
||||||
int demodEM410x(bool verbose);
|
int demodEM410x(bool verbose);
|
||||||
bool EM4x05IsBlock0(uint32_t *word);
|
|
||||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word);
|
|
||||||
|
|
||||||
void printEM410x(uint32_t hi, uint64_t id);
|
void printEM410x(uint32_t hi, uint64_t id);
|
||||||
|
|
||||||
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
|
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
|
||||||
int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);
|
int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);
|
||||||
|
|
||||||
|
|
1474
client/src/cmdlfem4x05.c
Normal file
1474
client/src/cmdlfem4x05.c
Normal file
File diff suppressed because it is too large
Load diff
31
client/src/cmdlfem4x05.h
Normal file
31
client/src/cmdlfem4x05.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
// 2016, 2017 marshmellow, iceman
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Low frequency EM4x05 commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDLFEM4X05_H__
|
||||||
|
#define CMDLFEM4X05_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int CmdLFEM4X05(const char *Cmd);
|
||||||
|
|
||||||
|
bool EM4x05IsBlock0(uint32_t *word);
|
||||||
|
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word);
|
||||||
|
|
||||||
|
|
||||||
|
int CmdEM4x05Demod(const char *Cmd);
|
||||||
|
int CmdEM4x05Dump(const char *Cmd);
|
||||||
|
int CmdEM4x05Read(const char *Cmd);
|
||||||
|
int CmdEM4x05Write(const char *Cmd);
|
||||||
|
int CmdEM4x05Wipe(const char *Cmd);
|
||||||
|
int CmdEM4x05Info(const char *Cmd);
|
||||||
|
int CmdEM4x05Chk(const char *Cmd);
|
||||||
|
int CmdEM4x05Unlock(const char *Cmd);
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,7 +16,7 @@
|
||||||
#include "em4x50.h"
|
#include "em4x50.h"
|
||||||
|
|
||||||
static int usage_lf_em4x50_info(void) {
|
static int usage_lf_em4x50_info(void) {
|
||||||
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag nust be on antenna.");
|
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna.");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [v] [p <pwd>]");
|
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [v] [p <pwd>]");
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
PrintAndLogEx(NORMAL, "Options:");
|
||||||
|
@ -315,7 +315,7 @@ int CmdEM4x50Info(const char *Cmd) {
|
||||||
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -388,11 +388,14 @@ int CmdEM4x50Write(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resp.status == PM3_ETEAROFF)
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
bool isOK = (resp.status & STATUS_SUCCESS) >> 1;
|
bool isOK = (resp.status & STATUS_SUCCESS) >> 1;
|
||||||
if (isOK == false) {
|
if (isOK == false) {
|
||||||
PrintAndLogEx(FAILED, "writing " _RED_("failed"));
|
PrintAndLogEx(FAILED, "writing " _RED_("failed"));
|
||||||
|
@ -483,10 +486,14 @@ int CmdEM4x50WritePassword(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd));
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE_PASSWORD, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resp.status == PM3_ETEAROFF)
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
|
||||||
success = (bool)resp.status;
|
success = (bool)resp.status;
|
||||||
|
|
||||||
// get, prepare and print response
|
// get, prepare and print response
|
||||||
|
@ -515,7 +522,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) {
|
||||||
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata));
|
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata));
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -651,7 +658,7 @@ int CmdEM4x50Dump(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
@ -726,7 +733,7 @@ int CmdEM4x50Wipe(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd));
|
SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd));
|
||||||
|
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2 * TIMEOUT)) {
|
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WIPE, &resp, 2 * TIMEOUT)) {
|
||||||
PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n");
|
PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n");
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,7 +186,7 @@ static int CmdGuardClone(const char *Cmd) {
|
||||||
// Q5
|
// Q5
|
||||||
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
|
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
|
||||||
if (q5)
|
if (q5)
|
||||||
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
|
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT;
|
||||||
|
|
||||||
blocks[1] = bytebits_to_byte(bs, 32);
|
blocks[1] = bytebits_to_byte(bs, 32);
|
||||||
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
blocks[2] = bytebits_to_byte(bs + 32, 32);
|
||||||
|
|
|
@ -378,7 +378,7 @@ static int usage_t55xx_dangerraw(void) {
|
||||||
static int usage_t55xx_clonehelp(void) {
|
static int usage_t55xx_clonehelp(void) {
|
||||||
PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
|
PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
|
||||||
PrintAndLogEx(NORMAL, _GREEN_("lf awid clone"));
|
PrintAndLogEx(NORMAL, _GREEN_("lf awid clone"));
|
||||||
// todo: rename to clone
|
PrintAndLogEx(NORMAL, _GREEN_("lf destron clone"));
|
||||||
PrintAndLogEx(NORMAL, _GREEN_("lf em 410x_clone"));
|
PrintAndLogEx(NORMAL, _GREEN_("lf em 410x_clone"));
|
||||||
// todo: implement restore
|
// todo: implement restore
|
||||||
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));
|
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));
|
||||||
|
|
|
@ -110,9 +110,9 @@ typedef enum {
|
||||||
DEMOD_PSK1 = 0x01,
|
DEMOD_PSK1 = 0x01,
|
||||||
DEMOD_PSK2 = 0x02,
|
DEMOD_PSK2 = 0x02,
|
||||||
DEMOD_PSK3 = 0x03,
|
DEMOD_PSK3 = 0x03,
|
||||||
DEMOD_FSK1 = 0x04,
|
DEMOD_FSK1 = 0x04,
|
||||||
DEMOD_FSK1a = 0x05,
|
DEMOD_FSK2 = 0x05,
|
||||||
DEMOD_FSK2 = 0x06,
|
DEMOD_FSK1a = 0x06,
|
||||||
DEMOD_FSK2a = 0x07,
|
DEMOD_FSK2a = 0x07,
|
||||||
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
|
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
|
||||||
DEMOD_ASK = 0x08,
|
DEMOD_ASK = 0x08,
|
||||||
|
|
|
@ -36,7 +36,9 @@
|
||||||
#include "fileutils.h" // searchfile
|
#include "fileutils.h" // searchfile
|
||||||
#include "cmdlf.h" // lf_config
|
#include "cmdlf.h" // lf_config
|
||||||
#include "generator.h"
|
#include "generator.h"
|
||||||
#include "cmdlfem4x.h" // read 4305
|
#include "cmdlfem4x05.h" // read 4305
|
||||||
|
#include "cmdlfem4x50.h" // read 4350
|
||||||
|
#include "em4x50.h" // 4x50 structs
|
||||||
|
|
||||||
static int returnToLuaWithError(lua_State *L, const char *fmt, ...) {
|
static int returnToLuaWithError(lua_State *L, const char *fmt, ...) {
|
||||||
char buffer[200];
|
char buffer[200];
|
||||||
|
@ -1088,7 +1090,7 @@ static int l_T55xx_detect(lua_State *L) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// 4305
|
||||||
static int l_em4x05_read(lua_State *L) {
|
static int l_em4x05_read(lua_State *L) {
|
||||||
|
|
||||||
bool use_pwd = false;
|
bool use_pwd = false;
|
||||||
|
@ -1103,12 +1105,12 @@ static int l_em4x05_read(lua_State *L) {
|
||||||
sscanf(p_addr, "%u", &addr);
|
sscanf(p_addr, "%u", &addr);
|
||||||
|
|
||||||
// get password
|
// get password
|
||||||
const char *p_pwd = luaL_checklstring(L, 2, &size);
|
const char *p_pwd = luaL_checkstring(L, 2);
|
||||||
if (size == 0) {
|
if (p_pwd == NULL || strlen(p_pwd) == 0 ) {
|
||||||
use_pwd = false;
|
use_pwd = false;
|
||||||
} else {
|
} else {
|
||||||
if (size != 8)
|
if (strlen(p_pwd) != 8)
|
||||||
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", size);
|
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", strlen(p_pwd));
|
||||||
|
|
||||||
sscanf(p_pwd, "%08x", &password);
|
sscanf(p_pwd, "%08x", &password);
|
||||||
use_pwd = true;
|
use_pwd = true;
|
||||||
|
@ -1128,6 +1130,66 @@ static int l_em4x05_read(lua_State *L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4350
|
||||||
|
static int l_em4x50_read(lua_State *L) {
|
||||||
|
|
||||||
|
// get addr
|
||||||
|
size_t size = 0;
|
||||||
|
const char *p_addr = luaL_checklstring(L, 1, &size);
|
||||||
|
uint32_t addr = 0;
|
||||||
|
sscanf(p_addr, "%u", &addr);
|
||||||
|
|
||||||
|
if (addr > 31)
|
||||||
|
return returnToLuaWithError(L, "Address out-of-range (0..31) got %u", addr);
|
||||||
|
|
||||||
|
// setting up structures
|
||||||
|
em4x50_data_t etd;
|
||||||
|
memset(&etd, 0x00, sizeof(em4x50_data_t));
|
||||||
|
etd.addr_given = true;
|
||||||
|
etd.address = addr & 0xFF;
|
||||||
|
etd.newpwd_given = false;
|
||||||
|
|
||||||
|
// get password
|
||||||
|
const char *p_pwd = luaL_checkstring(L, 2);
|
||||||
|
if (p_pwd == NULL || strlen(p_pwd) == 0) {
|
||||||
|
etd.pwd_given = false;
|
||||||
|
} else {
|
||||||
|
if (strlen(p_pwd) != 8)
|
||||||
|
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", strlen(p_pwd));
|
||||||
|
|
||||||
|
uint32_t pwd = 0;
|
||||||
|
sscanf(p_pwd, "%08x", &pwd);
|
||||||
|
|
||||||
|
PrintAndLogEx(DEBUG, " Pwd %08X", pwd);
|
||||||
|
|
||||||
|
etd.password[0] = pwd & 0xFF;
|
||||||
|
etd.password[1] = (pwd >> 8) & 0xFF;
|
||||||
|
etd.password[2] = (pwd >> 16) & 0xFF;
|
||||||
|
etd.password[3] = (pwd >> 24) & 0xFF;
|
||||||
|
etd.pwd_given = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(DEBUG, "Addr %u", etd.address);
|
||||||
|
if (etd.pwd_given)
|
||||||
|
PrintAndLogEx(DEBUG, " Pwd %s", sprint_hex(etd.password, sizeof(etd.password)));
|
||||||
|
|
||||||
|
em4x50_word_t words[EM4X50_NO_WORDS];
|
||||||
|
|
||||||
|
int res = em4x50_read(&etd, words, false);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return returnToLuaWithError(L, "Failed to read EM4x50 data");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t word = (
|
||||||
|
words[etd.address].byte[0] << 24 |
|
||||||
|
words[etd.address].byte[1] << 16 |
|
||||||
|
words[etd.address].byte[2] << 8 |
|
||||||
|
words[etd.address].byte[3]
|
||||||
|
);
|
||||||
|
lua_pushinteger(L, word);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
static int l_ndefparse(lua_State *L) {
|
static int l_ndefparse(lua_State *L) {
|
||||||
|
|
||||||
|
@ -1320,6 +1382,7 @@ int set_pm3_libraries(lua_State *L) {
|
||||||
{"ud", l_ud},
|
{"ud", l_ud},
|
||||||
{"rem", l_remark},
|
{"rem", l_remark},
|
||||||
{"em4x05_read", l_em4x05_read},
|
{"em4x05_read", l_em4x05_read},
|
||||||
|
{"em4x50_read", l_em4x50_read},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -895,3 +895,40 @@ int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str)
|
||||||
}
|
}
|
||||||
return i - 1;
|
return i - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32_t bitcount32(uint32_t a) {
|
||||||
|
#if defined __GNUC__
|
||||||
|
return __builtin_popcountl(a);
|
||||||
|
#else
|
||||||
|
a = a - ((a >> 1) & 0x55555555);
|
||||||
|
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||||
|
return (((a + (a >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t bitcount64(uint64_t a) {
|
||||||
|
#if defined __GNUC__
|
||||||
|
return __builtin_popcountll(a);
|
||||||
|
#else
|
||||||
|
PrintAndLogEx(FAILED, "Was not compiled with fct bitcount64");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t leadingzeros32(uint32_t a) {
|
||||||
|
#if defined __GNUC__
|
||||||
|
return __builtin_clzl(a);
|
||||||
|
#else
|
||||||
|
PrintAndLogEx(FAILED, "Was not compiled with fct bitcount64");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t leadingzeros64(uint64_t a) {
|
||||||
|
#if defined __GNUC__
|
||||||
|
return __builtin_clzll(a);
|
||||||
|
#else
|
||||||
|
PrintAndLogEx(FAILED, "Was not compiled with fct bitcount64");
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -101,4 +101,9 @@ void strcreplace(char *buf, size_t len, char from, char to);
|
||||||
char *str_dup(const char *src);
|
char *str_dup(const char *src);
|
||||||
char *str_ndup(const char *src, size_t len);
|
char *str_ndup(const char *src, size_t len);
|
||||||
int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str);
|
int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str);
|
||||||
|
|
||||||
|
uint32_t bitcount32(uint32_t a);
|
||||||
|
uint64_t bitcount64(uint64_t a);
|
||||||
|
uint32_t leadingzeros32(uint32_t a);
|
||||||
|
uint64_t leadingzeros64(uint64_t a);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,6 +22,7 @@ Always use the latest repository commits from *master* branch. There are always
|
||||||
* [Troubles with running the Proxmark3 client](#troubles-with-running-the-proxmark3-client)
|
* [Troubles with running the Proxmark3 client](#troubles-with-running-the-proxmark3-client)
|
||||||
* [libQt5Core.so.5 not found](#libQt5Coreso5-not-found)
|
* [libQt5Core.so.5 not found](#libQt5Coreso5-not-found)
|
||||||
* [Target attribute is not supported on this machine](#target-attribute-is-not-supported-on-this-machine)
|
* [Target attribute is not supported on this machine](#target-attribute-is-not-supported-on-this-machine)
|
||||||
|
* [Qt: Session management error:](#qt-session-management-error)
|
||||||
|
|
||||||
## `pm3` or `pm3-flash*` doesn't see my Proxmark
|
## `pm3` or `pm3-flash*` doesn't see my Proxmark
|
||||||
|
|
||||||
|
@ -222,4 +223,16 @@ ticks.h:26:1: error: target attribute is not supported on this machine [-Werror=
|
||||||
^
|
^
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Qt Session management error
|
||||||
|
If you get the message
|
||||||
|
|
||||||
|
```
|
||||||
|
Qt: Session management error: None of the authentication protocols specified are supported
|
||||||
|
``` when running the Proxmark3 client it might be because a a environment variable.
|
||||||
|
|
||||||
|
Solution:
|
||||||
|
Try running the client without the SESSION_MANAGER environment variable.
|
||||||
|
|
||||||
|
```
|
||||||
|
env -u SESSION_MANAGER ./pm3
|
||||||
|
```
|
|
@ -49,7 +49,7 @@ typedef struct {
|
||||||
uint8_t addresses[4];
|
uint8_t addresses[4];
|
||||||
uint8_t address;
|
uint8_t address;
|
||||||
uint8_t word[4];
|
uint8_t word[4];
|
||||||
} em4x50_data_t;
|
} PACKED em4x50_data_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t byte[4];
|
uint8_t byte[4];
|
||||||
|
@ -60,6 +60,6 @@ typedef struct {
|
||||||
bool cparity[8];
|
bool cparity[8];
|
||||||
bool stopparity;
|
bool stopparity;
|
||||||
bool parity;
|
bool parity;
|
||||||
} em4x50_word_t;
|
} PACKED em4x50_word_t;
|
||||||
|
|
||||||
#endif /* EM4X50_H__ */
|
#endif /* EM4X50_H__ */
|
||||||
|
|
|
@ -306,6 +306,7 @@ typedef struct {
|
||||||
bool use_raw;
|
bool use_raw;
|
||||||
bool use_elite;
|
bool use_elite;
|
||||||
bool use_credit_key;
|
bool use_credit_key;
|
||||||
|
bool use_replay;
|
||||||
bool send_reply;
|
bool send_reply;
|
||||||
bool do_auth;
|
bool do_auth;
|
||||||
uint8_t blockno;
|
uint8_t blockno;
|
||||||
|
@ -333,11 +334,15 @@ typedef struct {
|
||||||
} PACKED iclass_writeblock_req_t;
|
} PACKED iclass_writeblock_req_t;
|
||||||
|
|
||||||
// iCLASS dump data structure
|
// iCLASS dump data structure
|
||||||
|
typedef struct {
|
||||||
|
uint8_t blockno;
|
||||||
|
uint8_t data[8];
|
||||||
|
} PACKED iclass_restore_item_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
iclass_auth_req_t req;
|
iclass_auth_req_t req;
|
||||||
uint8_t start_block;
|
uint8_t item_cnt;
|
||||||
uint8_t end_block;
|
iclass_restore_item_t blocks[];
|
||||||
uint8_t data[];
|
|
||||||
} PACKED iclass_restore_req_t;
|
} PACKED iclass_restore_req_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -350,7 +355,7 @@ typedef struct {
|
||||||
uint8_t mem_config; //[13]
|
uint8_t mem_config; //[13]
|
||||||
uint8_t eas; //[14]
|
uint8_t eas; //[14]
|
||||||
uint8_t fuses; //[15]
|
uint8_t fuses; //[15]
|
||||||
} picopass_conf_block_t;
|
} PACKED picopass_conf_block_t;
|
||||||
|
|
||||||
// iCLASS secure mode memory mapping
|
// iCLASS secure mode memory mapping
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -360,16 +365,22 @@ typedef struct {
|
||||||
uint8_t key_d[8];
|
uint8_t key_d[8];
|
||||||
uint8_t key_c[8];
|
uint8_t key_c[8];
|
||||||
uint8_t app_issuer_area[8];
|
uint8_t app_issuer_area[8];
|
||||||
} picopass_hdr;
|
} PACKED picopass_hdr;
|
||||||
|
|
||||||
// iCLASS non-secure mode memory mapping
|
// iCLASS non-secure mode memory mapping
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t csn[8];
|
uint8_t csn[8];
|
||||||
picopass_conf_block_t conf;
|
picopass_conf_block_t conf;
|
||||||
uint8_t app_issuer_area[8];
|
uint8_t app_issuer_area[8];
|
||||||
} picopass_ns_hdr;
|
} PACKED picopass_ns_hdr;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t delay_us;
|
||||||
|
bool on;
|
||||||
|
bool off;
|
||||||
|
} PACKED tearoff_params_t;
|
||||||
|
|
||||||
// For the bootloader
|
// For the bootloader
|
||||||
#define CMD_DEVICE_INFO 0x0000
|
#define CMD_DEVICE_INFO 0x0000
|
||||||
//#define CMD_SETUP_WRITE 0x0001
|
//#define CMD_SETUP_WRITE 0x0001
|
||||||
|
@ -559,12 +570,10 @@ typedef struct {
|
||||||
|
|
||||||
// iCLASS / Picopass
|
// iCLASS / Picopass
|
||||||
#define CMD_HF_ICLASS_READCHECK 0x038F
|
#define CMD_HF_ICLASS_READCHECK 0x038F
|
||||||
#define CMD_HF_ICLASS_CLONE 0x0390
|
|
||||||
#define CMD_HF_ICLASS_DUMP 0x0391
|
#define CMD_HF_ICLASS_DUMP 0x0391
|
||||||
#define CMD_HF_ICLASS_SNIFF 0x0392
|
#define CMD_HF_ICLASS_SNIFF 0x0392
|
||||||
#define CMD_HF_ICLASS_SIMULATE 0x0393
|
#define CMD_HF_ICLASS_SIMULATE 0x0393
|
||||||
#define CMD_HF_ICLASS_READER 0x0394
|
#define CMD_HF_ICLASS_READER 0x0394
|
||||||
#define CMD_HF_ICLASS_REPLAY 0x0395
|
|
||||||
#define CMD_HF_ICLASS_READBL 0x0396
|
#define CMD_HF_ICLASS_READBL 0x0396
|
||||||
#define CMD_HF_ICLASS_WRITEBL 0x0397
|
#define CMD_HF_ICLASS_WRITEBL 0x0397
|
||||||
#define CMD_HF_ICLASS_EML_MEMSET 0x0398
|
#define CMD_HF_ICLASS_EML_MEMSET 0x0398
|
||||||
|
@ -650,6 +659,9 @@ typedef struct {
|
||||||
|
|
||||||
// MFU OTP TearOff
|
// MFU OTP TearOff
|
||||||
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
|
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
|
||||||
|
// MFU_Ev1 Counter TearOff
|
||||||
|
#define CMD_HF_MFU_COUNTER_TEAROFF 0x0741
|
||||||
|
|
||||||
|
|
||||||
#define CMD_HF_SNIFF 0x0800
|
#define CMD_HF_SNIFF 0x0800
|
||||||
#define CMD_HF_PLOT 0x0801
|
#define CMD_HF_PLOT 0x0801
|
||||||
|
|
|
@ -341,6 +341,7 @@ while true; do
|
||||||
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search 1'" "AWID ID found"; then break; fi
|
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search 1'" "AWID ID found"; then break; fi
|
||||||
if ! CheckExecute "lf EM410x test" "$CLIENTBIN -c 'data load -f traces/lf_EM4102-1.pm3;lf search 1'" "EM410x ID found"; then break; fi
|
if ! CheckExecute "lf EM410x test" "$CLIENTBIN -c 'data load -f traces/lf_EM4102-1.pm3;lf search 1'" "EM410x ID found"; then break; fi
|
||||||
if ! CheckExecute "lf EM4x05 test" "$CLIENTBIN -c 'data load -f traces/lf_EM4x05.pm3;lf search 1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute "lf EM4x05 test" "$CLIENTBIN -c 'data load -f traces/lf_EM4x05.pm3;lf search 1'" "FDX-B ID found"; then break; fi
|
||||||
|
if ! CheckExecute "lf FDX-A FECAVA test" "$CLIENTBIN -c 'data load -f traces/lf_EM4305_fdxa_destron.pm3;lf search 1'" "FDX-A FECAVA Destron ID found"; then break; fi
|
||||||
if ! CheckExecute "lf FDX-B test" "$CLIENTBIN -c 'data load -f traces/lf_HomeAgain1600.pm3;lf search 1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute "lf FDX-B test" "$CLIENTBIN -c 'data load -f traces/lf_HomeAgain1600.pm3;lf search 1'" "FDX-B ID found"; then break; fi
|
||||||
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load -f traces/lf_FDXB_Bio-Thermo.pm3; lf fdxb demod'" "95.2 F / 35.1 C"; then break; fi
|
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load -f traces/lf_FDXB_Bio-Thermo.pm3; lf fdxb demod'" "95.2 F / 35.1 C"; then break; fi
|
||||||
if ! CheckExecute "lf GPROXII test" "$CLIENTBIN -c 'data load -f traces/lf_GProx_36_30_14489.pm3; lf search 1'" "Guardall G-Prox II ID found"; then break; fi
|
if ! CheckExecute "lf GPROXII test" "$CLIENTBIN -c 'data load -f traces/lf_GProx_36_30_14489.pm3; lf search 1'" "Guardall G-Prox II ID found"; then break; fi
|
||||||
|
@ -366,7 +367,7 @@ while true; do
|
||||||
"EM TAG ID : 0F0368568B"; then break; fi
|
"EM TAG ID : 0F0368568B"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 fdxb_animal test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf search 1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute slow "lf T55 fdxb_animal test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf search 1'" "FDX-B ID found"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 fdxb_animal test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf fdxb demod'" \
|
if ! CheckExecute slow "lf T55 fdxb_animal test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_animal.pm3; lf fdxb demod'" \
|
||||||
"Animal ID 0999-000000112233"; then break; fi
|
"Animal ID 999-000000112233"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 fdxb_extended test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_extended.pm3; lf search 1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute slow "lf T55 fdxb_extended test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_extended.pm3; lf search 1'" "FDX-B ID found"; then break; fi
|
||||||
if ! CheckExecute slow "lf T55 fdxb_extended test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_extended.pm3; lf fdxb demod'" \
|
if ! CheckExecute slow "lf T55 fdxb_extended test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_fdxb_extended.pm3; lf fdxb demod'" \
|
||||||
"temperature 95.2 F / 35.1 C"; then break; fi
|
"temperature 95.2 F / 35.1 C"; then break; fi
|
||||||
|
|
16000
traces/lf_EM4305_fdxa_destron.pm3
Normal file
16000
traces/lf_EM4305_fdxa_destron.pm3
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue