Merge pull request #55 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-10-17 08:38:40 +11:00 committed by GitHub
commit 6221a44773
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 19043 additions and 1830 deletions

View file

@ -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...
## [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 doc/cliparser.md (@mwalker33)
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)

View file

@ -173,6 +173,9 @@ help:
@echo "+ .../check - Run offline tests against specific target. See above."
@echo "+ miscchecks - Detect various encoding issues in source code"
@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 "To activate verbose mode, use make V=1"

View file

@ -302,15 +302,17 @@ static int reader_dump_mode(void) {
Iso15693InitReader();
set_tracing(false);
picopass_hdr *hdr = (picopass_hdr *)card_data;
// select tag.
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) {
switch_off();
continue;
}
picopass_hdr *hdr = (picopass_hdr *)card_data;
// sanity check of CSN.
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
switch_off();
@ -366,7 +368,7 @@ static int reader_dump_mode(void) {
auth.use_credit_key = true;
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) {
// sanity check of CSN.

View file

@ -1473,6 +1473,15 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
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: {
MifareHasStaticNonce();
break;
@ -1503,20 +1512,19 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
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 {
uint8_t reader[4];
uint8_t mac[4];
} PACKED;
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;
}
case CMD_HF_ICLASS_EML_MEMSET: {
@ -1545,18 +1553,8 @@ static void PacketReceived(PacketCommandNG *packet) {
iClass_Dump(packet->data.asBytes);
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: {
iClass_Restore(packet->data.asBytes);
iClass_Restore( (iclass_restore_req_t *)packet->data.asBytes);
break;
}
#endif

View file

@ -14,6 +14,7 @@
#include "lfadc.h"
#include "commonutil.h"
#include "em4x50.h"
#include "appmain.h" // tear
// 4 data bytes
// + byte with row parities
@ -470,6 +471,8 @@ static bool find_double_listen_window(bool bcommand) {
if (bcommand) {
// SpinDelay(10);
// data transmission from card has to be stopped, because
// a commamd shall be issued
@ -816,7 +819,7 @@ void em4x50_info(em4x50_data_t *etd) {
status = (bsuccess << 1) + blogin;
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) {
@ -860,14 +863,13 @@ void em4x50_read(em4x50_data_t *etd) {
status = (now << 2) + (bsuccess << 1) + blogin;
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
//==============================================================================
static bool write(uint8_t word[4], uint8_t address) {
static int write(uint8_t word[4], uint8_t address) {
// writes <word> to specified <address>
@ -882,17 +884,23 @@ static bool write(uint8_t word[4], uint8_t address) {
// send data
em4x50_send_word(word);
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
return PM3_ETEAROFF;
} else {
// look for ACK sequence
if (check_ack(false)) {
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
// for saving data and should return with ACK
if (check_ack(false))
return true;
// look for ACK sequence
if (check_ack(false)) {
// 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 {
@ -900,10 +908,10 @@ static bool write(uint8_t word[4], uint8_t address) {
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>
@ -915,23 +923,29 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
// send address data
em4x50_send_word(password);
// wait for T0 * EM4x50_T_TAG_TPP (processing pause time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
reply_ng(CMD_LF_EM4X50_WRITE, PM3_ETEAROFF, NULL, 0);
return PM3_ETEAROFF;
} else {
// look for ACK sequence and send rm request
// during following listen window
if (check_ack(true)) {
// wait for T0 * EM4x50_T_TAG_TPP (processing pause time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP);
// send new password
em4x50_send_word(new_password);
// look for ACK sequence and send rm request
// during following listen window
if (check_ack(true)) {
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
// send new password
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))
return true;
if (check_ack(false))
return PM3_SUCCESS;
}
}
} else {
@ -939,7 +953,7 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
Dbprintf("error in command request");
}
return false;
return PM3_ESOFT;
}
void em4x50_write(em4x50_data_t *etd) {
@ -966,8 +980,13 @@ void em4x50_write(em4x50_data_t *etd) {
blogin = login(etd->password);
// 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
if (reset()) {
@ -996,9 +1015,8 @@ void em4x50_write(em4x50_data_t *etd) {
}
status = (bsuccess << 1) + blogin;
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) {
@ -1015,12 +1033,18 @@ void em4x50_write_password(em4x50_data_t *etd) {
// login and change 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();
reply_ng(CMD_ACK, bsuccess, 0, 0);
reply_ng(CMD_LF_EM4X50_WRITE_PASSWORD, bsuccess, 0, 0);
}
void em4x50_wipe(em4x50_data_t *etd) {
@ -1078,5 +1102,5 @@ void em4x50_wipe(em4x50_data_t *etd) {
}
lf_finalize();
reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238);
reply_ng(CMD_LF_EM4X50_WIPE, bsuccess, (uint8_t *)tag.sectors, 238);
}

View file

@ -1276,7 +1276,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
* @return false = fail
* 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 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 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 7: parity.
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;
} else {
// on NON_SECURE_PAGEMODE cards, AIA is on block2..
// read App Issuer Area block 2
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) {
*status |= FLAG_ICLASS_AIA;
memcpy(card_data + (8 * 2), resp, 8);
memcpy(hdr->epurse, resp, sizeof(hdr->epurse));
}
}
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;
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
// turn off afterwards
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 resp[ICLASS_BUFFER_SIZE] = {0};
memset(resp, 0xFF, sizeof(resp));
@ -1419,14 +1419,13 @@ void ReaderIClass(uint8_t flags) {
uint8_t result_status = 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) {
reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0);
reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0);
switch_off();
return;
}
// Page mapping for secure mode
// 0 : CSN
// 1 : Configuration
@ -1444,7 +1443,7 @@ void ReaderIClass(uint8_t flags) {
// with 0xFF:s in block 3 and 4.
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 -
// only useful if looping in arm (not try_once && not abort_after_read)
@ -1470,101 +1469,6 @@ void ReaderIClass(uint8_t flags) {
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)
// 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.
@ -1585,24 +1489,30 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse));
if (payload->use_raw)
memcpy(div_key, payload->key, 8);
else
iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite);
if ( payload->use_replay) {
if (payload->use_credit_key)
memcpy(hdr->key_c, div_key, sizeof(hdr->key_c));
else
memcpy(hdr->key_d, div_key, sizeof(hdr->key_d));
memcpy(pmac, payload->key + 4, 4);
memcpy(cmd_check + 1, payload->key, 8);
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)
cmd_check[5] = pmac[0];
cmd_check[6] = pmac[1];
cmd_check[7] = pmac[2];
cmd_check[8] = pmac[3];
if (payload->use_credit_key)
memcpy(hdr->key_c, div_key, sizeof(hdr->key_c));
else
memcpy(hdr->key_d, div_key, sizeof(hdr->key_d));
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);
}
@ -1632,7 +1542,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) {
readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
// select card / e-purse
uint8_t card_data[6 * 8] = {0};
picopass_hdr hdr = {0};
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;
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;
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
@ -1723,7 +1633,7 @@ void iClass_ReadBlock(uint8_t *msg) {
// select tag.
uint32_t eof_time = 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 (payload->send_reply) {
response.isOK = res;
@ -1796,7 +1706,7 @@ void iClass_Dump(uint8_t *msg) {
// select tag.
uint32_t eof_time = 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 (req->send_reply) {
reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0);
@ -1866,10 +1776,12 @@ void iClass_Dump(uint8_t *msg) {
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 };
memcpy(write + 2, data, 12); // data + mac
memcpy(write + 2, data, 8);
memcpy(write + 10, mac, 4);
AddCrc(write + 1, 13);
uint8_t resp[10] = {0};
@ -1914,7 +1826,7 @@ void iClass_WriteBlock(uint8_t *msg) {
// select tag.
uint32_t eof_time = 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) {
goto out;
}
@ -1937,10 +1849,14 @@ void iClass_WriteBlock(uint8_t *msg) {
wb[0] = payload->req.blockno;
memcpy(wb + 1, payload->data, 8);
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);
if (payload->req.use_replay) {
doMAC_N(wb, sizeof(wb), payload->req.key + 4, mac);
} else {
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 + 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;
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;
}
@ -1983,29 +1920,75 @@ out:
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
}
// turn off afterwards
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) {
}
void iClass_Restore(iclass_restore_req_t *msg) {
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;
// iclass_auth_req_t *req = &cmd->req;
if (msg->item_cnt == 0) {
if (msg->req.send_reply) {
reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0);
}
return;
}
LED_A_ON();
uint16_t written = 0;
uint16_t total_blocks = (cmd->end_block - cmd->start_block) + 1;
for (uint8_t b = cmd->start_block; b < total_blocks; b++) {
Iso15693InitReader();
if (iclass_writeblock_ext(b, cmd->data + ((b - cmd->start_block) * 12))) {
Dbprintf("Write block [%02x] successful", b);
written++;
} else {
Dbprintf("Write block [%02x] failed", b);
uint16_t written = 0;
uint32_t eof_time = 0;
picopass_hdr hdr = {0};
// 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();
uint8_t isOK = (written == total_blocks) ? 1 : 0;
reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t));
if (msg->req.send_reply) {
int isOK = (written == msg->item_cnt) ? PM3_SUCCESS : PM3_ESOFT;
reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0);
}
}

View file

@ -17,13 +17,11 @@
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
void ReaderIClass(uint8_t arg0);
void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac);
void iClass_WriteBlock(uint8_t *msg);
void iClass_Dump(uint8_t *msg);
void iClass_Restore(uint8_t *msg);
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
void iClass_Restore(iclass_restore_req_t *msg);
int do_iclass_simulation_nonsec(void);
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);
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);
#endif

View file

@ -2624,13 +2624,13 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
} // else force RATS
// RATS, Request for answer to select
if (!no_rats) {
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0
if (no_rats == false) {
uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0
AddCrc14A(rats, 2);
ReaderTransmit(rats, sizeof(rats), NULL);
int len = ReaderReceive(resp, resp_par);
if (!len) return 0;
if (len == 0)
return 0;
if (p_card) {
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
}
}
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))

View file

@ -1895,12 +1895,17 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw
FpgaDisableTracing();
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
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);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
}
}
out:

View file

@ -290,6 +290,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) {
LED_B_OFF();
*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();
FpgaDisableTracing();
uint32_t sof_time = *eof_time
- (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)
CodeIso15693AsReader256(send, sendlen);
}
int res = 0;
tosend_t *ts = get_tosend();
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;
if (recv != NULL) {
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
res = PM3_ETEAROFF;
} 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;
}
@ -1495,7 +1502,6 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
if (recv != NULL) {
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
}
FpgaDisableTracing();
return res;
}
@ -1588,41 +1594,49 @@ void ReaderIso15693(uint32_t parameter) {
BuildIdentifyRequest(cmd);
uint32_t start_time = 0;
uint32_t eof_time;
int answerLen = 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;
int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time);
if (recvlen == PM3_ETEAROFF) { // tearoff occured
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
if (answerLen >= 12) {
uint8_t uid[8];
uid[0] = answer[9]; // always E0
uid[1] = answer[8]; // IC Manufacturer code
uid[2] = answer[7];
uid[3] = answer[6];
uid[4] = answer[5];
uid[5] = answer[4];
uid[6] = answer[3];
uid[7] = answer[2];
// we should do a better check than this
if (recvlen >= 12) {
uint8_t uid[8];
uid[0] = answer[9]; // always E0
uid[1] = answer[8]; // IC Manufacturer code
uid[2] = answer[7];
uid[3] = answer[6];
uid[4] = answer[5];
uid[5] = answer[4];
uid[6] = answer[3];
uid[7] = answer[2];
if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X",
uid[0], uid[1], uid[2], uid[3],
uid[4], uid[5], uid[5], uid[6]
);
if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X",
uid[0], uid[1], uid[2], uid[3],
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();
BigBuf_free();
}
@ -1767,6 +1781,11 @@ void BruteforceIso15693Afi(uint32_t speed) {
if (recvlen >= 12) {
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
@ -1816,10 +1835,9 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
LED_A_ON();
int recvlen = 0;
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
uint32_t eof_time = 0;
uint16_t timeout;
uint32_t eof_time = 0;
bool request_answer = false;
switch (data[1]) {
@ -1837,43 +1855,29 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
timeout = ISO15693_READER_TIMEOUT;
}
if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("SEND:");
Dbhexdump(datalen, data, false);
}
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 (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 (recvlen == PM3_ETEAROFF) { // tearoff occured
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
} else {
// 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
FpgaWriteConfWord(FPGA_MAJOR_MODE_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);
}
}
/*

View file

@ -2695,9 +2695,8 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
//
// Tear-off attack against MFU.
// - 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;
uint32_t tearOffTime = arg1;
uint8_t data_fullwrite[4] = {0x00};
uint8_t data_testwrite[4] = {0x00};
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 (tearOffTime > 43000)
tearOffTime = 43000;
if (tearoff_time > 43000)
tearoff_time = 43000;
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
LED_D_ON();
SpinDelayUsPrecision(tearOffTime);
SpinDelayUsPrecision(tearoff_time);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
switch_off();
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);
}

View file

@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// Tear-off test for MFU
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

View file

@ -246,7 +246,9 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdlf.c
${PM3_ROOT}/client/src/cmdlfawid.c
${PM3_ROOT}/client/src/cmdlfcotag.c
${PM3_ROOT}/client/src/cmdlfdestron.c
${PM3_ROOT}/client/src/cmdlfem4x.c
${PM3_ROOT}/client/src/cmdlfem4x05.c
${PM3_ROOT}/client/src/cmdlfem4x50.c
${PM3_ROOT}/client/src/cmdlffdxb.c
${PM3_ROOT}/client/src/cmdlfgallagher.c

View file

@ -441,7 +441,9 @@ SRCS = aidsearch.c \
cmdlf.c \
cmdlfawid.c \
cmdlfcotag.c \
cmdlfdestron.c \
cmdlfem4x.c \
cmdlfem4x05.c \
cmdlfem4x50.c \
cmdlffdxb.c \
cmdlfguard.c \

View file

@ -125,6 +125,7 @@ add_library(pm3rrg_rdv4 SHARED
${PM3_ROOT}/client/src/cmdlf.c
${PM3_ROOT}/client/src/cmdlfawid.c
${PM3_ROOT}/client/src/cmdlfcotag.c
${PM3_ROOT}/client/src/cmdlfdestron.c
${PM3_ROOT}/client/src/cmdlfem4x.c
${PM3_ROOT}/client/src/cmdlfem4x50.c
${PM3_ROOT}/client/src/cmdlffdxb.c

View file

@ -26,6 +26,8 @@ A5B4C3D2
50520901
# default PROX
50524F58
# blue gun EM4305
F9DCEBA0
# Default pwd, simple:
00000000
11111111
@ -123,3 +125,7 @@ b5f44686 # seeds ul-ev1
C6EF3720 # TEA
7854794A # xbox tea constant :)
F1EA5EED # burtle
69314718 # ln2
57721566 # euler constant (dec)
93C467E3 # euler constant (hex)
27182818 # natural log

View file

@ -36,7 +36,7 @@ arguments = [[
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'
---
@ -250,6 +250,10 @@ local function main(args)
local wordstr14b = ('%08X'):format(word14b)
if (wordstr14b == '00000000') then
reset(wr_value, password)
word14b, err14b = core.em4x05_read(14, password)
if err14b then
return oops(err14b)
end
end
if (wordstr14b ~= rd_value) then
local word15b, err15b = core.em4x05_read(15, password)
@ -299,17 +303,17 @@ local function main(args)
else
print(('[=] Status: failed to commit => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b))
end
if auto then
n = 0
ed = sd
else
tries = 0
soon = 0
late = 0
end
else
print(('[=] Status: 15 bitflipped but inactive => '..ansicolors.yellow..'PROMISING: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15))
end
if auto then
n = 0
ed = sd
else
tries = 0
soon = 0
late = 0
end
end
end
if not auto then

View file

@ -1949,7 +1949,7 @@ int CmdSave(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
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
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -1958,7 +1958,9 @@ int CmdSave(const char *Cmd) {
int fnlen = 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);
if (as_wave)

View file

@ -1362,7 +1362,7 @@ static int waitCmd(uint8_t iSelect, uint32_t timeout) {
uint8_t *data = resp.data.asBytes;
if (len >= 3) {
if (iSelect == 0 && len >= 3) {
bool crc = check_crc(CRC_14443_A, data, len);
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) {
const char *tip = "";
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";
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 2K or 4K";
if ((card.sak & 0x70) == 0x40) { // and no GetVersion()..
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);
if (card.ats[pos] == 0xC1) {

View file

@ -323,7 +323,7 @@ static int usage_15_raw(void) {
return PM3_SUCCESS;
}
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"
"\t-2 use slower '1 out of 256' mode\n"
"\tuid (either): \n"
@ -334,7 +334,7 @@ static int usage_15_read(void) {
return PM3_SUCCESS;
}
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"
"\t-2 use slower '1 out of 256' mode\n"
"\t-o set OPTION Flag (needed for TI)\n"
@ -816,6 +816,10 @@ static int NxpSysInfo(uint8_t *uid) {
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
if (status < 2) {
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command");
return PM3_EWRONGANSWER;
@ -975,6 +979,9 @@ static int CmdHF15Info(const char *Cmd) {
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
if (status < 2) {
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status);
return PM3_EWRONGANSWER;
@ -1153,9 +1160,13 @@ static int CmdHF15WriteAfi(const char *Cmd) {
DropField();
return PM3_ETIMEOUT;
}
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
uint8_t *data = resp.data.asBytes;
if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
@ -1212,6 +1223,10 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
}
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
uint8_t *data = resp.data.asBytes;
@ -1296,6 +1311,9 @@ static int CmdHF15Dump(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
int len = resp.oldarg[0];
if (len == PM3_ETEAROFF) {
continue;
}
if (len < 2) {
PrintAndLogEx(FAILED, "iso15693 command failed");
continue;
@ -1321,6 +1339,7 @@ static int CmdHF15Dump(const char *Cmd) {
blocknum++;
PrintAndLogEx(NORMAL, "." NOLF);
fflush(stdout);
}
}
@ -1419,6 +1438,10 @@ static int CmdHF15Raw(const char *Cmd) {
if (reply) {
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
int len = resp.oldarg[0];
if (len == PM3_ETEAROFF) {
DropField();
return len;
}
if (len < 2) {
PrintAndLogEx(WARNING, "command failed");
} else {
@ -1491,6 +1514,10 @@ static int CmdHF15Readmulti(const char *Cmd) {
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
if (status < 2) {
PrintAndLogEx(FAILED, "iso15693 card readmulti failed");
return PM3_EWRONGANSWER;
@ -1574,6 +1601,9 @@ static int CmdHF15Read(const char *Cmd) {
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
if (status < 2) {
PrintAndLogEx(ERR, "iso15693 command failed");
return PM3_EWRONGANSWER;
@ -1661,6 +1691,10 @@ static int CmdHF15Write(const char *Cmd) {
DropField();
int status = resp.oldarg[0];
if (status == PM3_ETEAROFF) {
return status;
}
if (status < 2) {
PrintAndLogEx(FAILED, "iso15693 command failed");
return PM3_EWRONGANSWER;
@ -1876,13 +1910,13 @@ static command_t CommandTable[] = {
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
{"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
{"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"},
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
{"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)"},
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
{"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"},
{"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"},
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},

View file

@ -915,7 +915,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) {
static command_t CommandTable[] = {
{"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."},
{"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."},
{"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},

View file

@ -155,10 +155,11 @@ static int usage_hf_iclass_dump(void) {
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : Show this help");
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, " e : elite computations applied to key");
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, "");
PrintAndLogEx(NORMAL, "Examples:");
@ -195,10 +196,11 @@ static int usage_hf_iclass_writeblock(void) {
PrintAndLogEx(NORMAL, " h : Show this help");
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, " 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, " e : elite computations applied to key");
PrintAndLogEx(NORMAL, " r : raw, no computations applied to key (raw)");
// PrintAndLogEx(NORMAL, " n : replay of NR/MAC");
PrintAndLogEx(NORMAL, " v : verbose output");
PrintAndLogEx(NORMAL, "Examples:");
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, " h : Show this help");
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, " e : elite 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, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 06 k 0011223344556677"));
@ -280,18 +283,6 @@ static int usage_hf_iclass_reader(void) {
PrintAndLogEx(NORMAL, "");
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) {
PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack");
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;
}
static int cmp_uint32(const void *a, const void *b) {
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);
}
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) {
DumpFileType_t dftype = BIN;
@ -1271,7 +1136,6 @@ static int CmdHFiClassEView(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHFiClassDecrypt(const char *Cmd) {
bool errors = false;
@ -1567,13 +1431,6 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) {
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) {
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;
}
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) {
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 elite = false;
bool rawkey = false;
bool use_replay = false;
bool errors = false;
bool auth = false;
uint8_t cmdp = 0;
@ -1732,12 +1549,23 @@ static int CmdHFiClassDump(const char *Cmd) {
rawkey = true;
cmdp++;
break;
case 'n':
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
use_replay = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
errors = true;
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();
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_elite = elite,
.req.use_credit_key = false,
.req.use_replay = use_replay,
.req.send_reply = true,
.req.do_auth = auth,
.end_block = app_limit1,
@ -1974,49 +1803,13 @@ write_dump:
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) {
/*
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;
*/
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) {
iclass_writeblock_req_t payload = {
.req.use_raw = rawkey,
.req.use_elite = elite,
.req.use_credit_key = use_credit_key,
.req.use_replay = replay,
.req.blockno = blockno,
.req.send_reply = 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 (verbose) PrintAndLogEx(ERR, "failed to communicate with card");
return PM3_EWRONGANSWER;
return resp.status;
}
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 elite = false;
bool rawkey = false;
bool use_replay = false;
bool errors = false;
bool verbose = false;
uint8_t cmdp = 0;
@ -2105,6 +1898,13 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
rawkey = true;
cmdp++;
break;
/*
case 'n':
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
use_replay = true;
cmdp++;
break;
*/
case 'v':
verbose = true;
cmdp++;
@ -2118,21 +1918,29 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) {
if (got_blockno == false)
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();
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose);
if (isok == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
else
PrintAndLogEx(FAILED, "Writing failed");
int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose);
switch(isok) {
case PM3_SUCCESS:
PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno);
break;
case PM3_ETEAROFF:
if (verbose)
PrintAndLogEx(INFO, "Writing tear off triggered");
break;
default:
PrintAndLogEx(FAILED, "Writing failed");
break;
}
return isok;
}
/*
static int CmdHFiClassClone(const char *Cmd) {
return PM3_SUCCESS;
}
*/
static int CmdHFiClassRestore(const char *Cmd) {
char filename[FILE_PATH_SIZE] = { 0x00 };
char tempStr[50] = {0};
@ -2184,7 +1992,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
} else if (dataLen == 1) {
keyNbr = param_get8(Cmd, cmdp + 1);
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);
} else {
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 (rawkey + elite > 1) {
PrintAndLogEx(FAILED, "Can not use both 'e', 'r'");
return PM3_EINVARG;
}
if (startblock < 5) {
PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4");
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);
return PM3_EINVARG;
}
@ -2246,103 +2059,82 @@ static int CmdHFiClassRestore(const char *Cmd) {
return PM3_EFILE;
}
if (bytes_read < sizeof(iclass_block_t) * (endblock - startblock + 1)) {
PrintAndLogEx(ERR, "file wrong size");
if (bytes_read < ((endblock - startblock + 1) * 8 )) {
PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )",
startblock, endblock
);
free(dump);
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
// 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;
// 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);
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) {
PrintAndLogEx(INFO, "------+--------------------------+-------------");
PrintAndLogEx(INFO, "block | data | mac");
PrintAndLogEx(INFO, "------+--------------------------+-------------");
uint8_t p[12];
for (i = 0; i <= endblock - startblock; i++) {
memcpy(p, data + (i * 12), 12);
char *s = calloc(70, sizeof(uint8_t));
snprintf(s, 70, "| %s ", sprint_hex(p, 8));
snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4));
PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s);
free(s);
PrintAndLogEx(INFO, "Preparing to restore block range 0x%02x..0x%02x", startblock, endblock);
PrintAndLogEx(INFO, "------+----------------------");
PrintAndLogEx(INFO, "block | data");
PrintAndLogEx(INFO, "------+----------------------");
for (uint8_t i = 0; i < payload->item_cnt; i++) {
iclass_restore_item_t item = payload->blocks[i];
PrintAndLogEx(INFO, " %02X | %s", item.blockno, sprint_hex_inrow(item.data, sizeof(item.data)));
}
}
struct p {
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);
PrintAndLogEx(INFO, "restore started...");
PacketResponseNG resp;
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");
DropField();
free(payload);
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
if (resp.data.asBytes[0] == 1)
PrintAndLogEx(SUCCESS, "Restore successful");
else
PrintAndLogEx(WARNING, "Restore failed");
PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful"));
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card");
} else {
PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed"));
}
free(payload);
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 = {
.use_raw = rawkey,
.use_elite = elite,
.use_credit_key = (keyType == 0x18),
.use_replay = replay,
.blockno = blockno,
.send_reply = true,
.do_auth = auth,
@ -2391,6 +2183,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
bool got_blockno = false;
bool elite = false;
bool rawkey = false;
bool use_replay = false;
bool errors = false;
bool auth = false;
bool verbose = false;
@ -2439,6 +2232,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
rawkey = true;
cmdp++;
break;
case 'n':
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode"));
use_replay = true;
cmdp++;
break;
case 'v':
verbose = true;
cmdp++;
@ -2451,6 +2249,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
}
if (got_blockno == false)
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();
@ -2467,7 +2270,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
}
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)
return res;
@ -3541,8 +3344,6 @@ static command_t CommandTable[] = {
{"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"},
{"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"},
{"replay", CmdHFiClassReader_Replay, IfPm3Iclass, "<mac> Read Picopass / iCLASS tag via replay attack"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"},
{"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"},
{"eload", CmdHFiClassELoad, IfPm3Iclass, "[f <fn> ] Load Picopass / iCLASS dump file into emulator memory"},

View file

@ -629,6 +629,10 @@ static int CmdLegicWrbl(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': {
errors = true;
break;
}
case 'd': {
// peek at length of the input string so we can
// figure out how many elements to malloc in "data"
@ -679,10 +683,6 @@ static int CmdLegicWrbl(const char *Cmd) {
cmdp += 2;
break;
}
case 'h': {
errors = true;
break;
}
case 'y': {
autoconfirm = true;
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
// UID 4+1 bytes can't be written to.
if (offset < 5) {
@ -704,13 +711,6 @@ static int CmdLegicWrbl(const char *Cmd) {
return PM3_EOUTOFBOUND;
}
//Validations
if (errors || cmdp == 0) {
if (data)
free(data);
return usage_legic_wrbl();
}
// tagtype
legic_card_select_t card;
if (legic_get_type(&card) != PM3_SUCCESS) {

View file

@ -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) {
uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA;
uint64_t key = 0;
@ -825,12 +895,9 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
if (isOK) {
uint8_t blocks = 4;
uint8_t start = sectorNo * 4;
if (sectorNo > 32) {
blocks = 16;
start = 128 + (sectorNo - 32) * 16;
}
uint8_t blocks = NumBlocksPerSector(sectorNo);
uint8_t start = FirstBlockOfSector(sectorNo);
for (int i = 0; i < blocks; i++) {
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;
}
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) {
PacketResponseNG resp;
@ -3671,7 +3670,7 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
uint8_t blocks = 4;
uint8_t start = sector * 4;
if (sector > 32) {
if (sector >= 32) {
blocks = 16;
start = 128 + (sector - 32) * 16;
}
@ -4365,7 +4364,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) {
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
uint8_t blocks = 4;
uint8_t start = sector * 4;
if (sector > 32) {
if (sector >= 32) {
blocks = 16;
start = 128 + (sector - 32) * 16;
}

View file

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

View file

@ -21,6 +21,7 @@
#include "generator.h"
#include "mifare/ndef.h"
#include "cliparser.h"
#include "cmdmain.h"
#define MAX_UL_BLOCKS 0x0F
@ -170,7 +171,8 @@ static int usage_hf_mfu_sim(void) {
static int usage_hf_mfu_ucauth(void) {
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, "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, "Examples:");
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;
}
static int ul_select(iso14a_card_select_t *card) {
static bool ul_select(iso14a_card_select_t *card) {
ul_switch_on_field();
PacketResponseNG resp;
bool ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500);
if (!ans || resp.oldarg[0] < 1) {
PrintAndLogEx(WARNING, "iso14443a card select failed");
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
DropField();
return 0;
}
return false;
} else {
memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
return 1;
uint16_t len = (resp.oldarg[1] & 0xFFFF);
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.
@ -878,13 +887,13 @@ static int ulev1_print_counters(void) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0};
uint16_t len = 0;
int len = 0;
for (uint8_t i = 0; i < 3; ++i) {
ulev1_readTearing(i, tear, sizeof(tear));
len = ulev1_readCounter(i, counter, sizeof(counter));
if (len == 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;
@ -1026,11 +1035,10 @@ static int ulc_magic_test(){
iso14a_card_select_t card;
uint8_t nonce1[11] = {0x00};
uint8_t nonce2[11] = {0x00};
int status = ul_select(&card);
if ( !status ){
if ( !ul_select(&card) ){
return UL_ERROR;
}
status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
int status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
if ( status > 0 ) {
status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
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");
}
return 0;
return PM3_SUCCESS;
}
//
// Read Single Block
@ -2398,25 +2406,31 @@ static int CmdHF14AMfUSim(const char *Cmd) {
//
static int CmdHF14AMfUCAuth(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') {
uint8_t cmdp = 0;
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h') {
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;
int succeeded;
// 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);
// Else try user-supplied
} 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");
return PM3_EINVARG;
}
succeeded = ulc_authentication(key_buf, true);
succeeded = ulc_authentication(key_buf, ! keep_field_on);
key = key_buf;
}
@ -2933,11 +2947,19 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
clearCommandBuffer();
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)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Tear off reporting failure to select tag");
continue;
}
got_post = false;
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
@ -3037,6 +3059,401 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
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) {
int keylen;
@ -3167,6 +3584,7 @@ static command_t CommandTable[] = {
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
{"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"},
{NULL, NULL, NULL, NULL}
};

View file

@ -22,6 +22,7 @@
#include "cmdhw.h"
#include "cmddata.h"
#include "commonutil.h"
#include "pm3_cmd.h"
static int CmdHelp(const char *Cmd);
@ -516,6 +517,33 @@ static int CmdStatus(const char *Cmd) {
return PM3_SUCCESS;
}
int handle_tearoff(tearoff_params_t *params, bool verbose) {
if (params == NULL)
return PM3_EINVARG;
clearCommandBuffer();
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)params, sizeof(tearoff_params_t));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) {
PrintAndLogEx(WARNING, "Tear-off command timeout.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
if (params->delay_us > 0 && verbose)
PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params->delay_us);
if (params->on && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
if (params->off && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
} else if (verbose)
PrintAndLogEx(WARNING, "Tear-off command failed.");
return resp.status;
}
static int CmdTearoff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hw tearoff",
@ -536,11 +564,7 @@ static int CmdTearoff(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
struct {
uint16_t delay_us;
bool on;
bool off;
} PACKED params;
tearoff_params_t params;
int delay = arg_get_int_def(ctx, 1, -1);
params.on = arg_get_lit(ctx, 2);
params.off = arg_get_lit(ctx, 3);
@ -562,29 +586,7 @@ static int CmdTearoff(const char *Cmd) {
return PM3_EINVARG;
}
clearCommandBuffer();
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)&params, 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;
return handle_tearoff(&params, !silent);
}
static int CmdTia(const char *Cmd) {

View file

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

View file

@ -30,12 +30,14 @@
#include "cmddata.h" // for `lf search`
#include "cmdlfawid.h" // for awid 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 "cmdlfhitag.h" // for hitag menu
#include "cmdlfidteck.h" // for idteck menu
#include "cmdlfio.h" // for ioprox menu
#include "cmdlfcotag.h" // for COTAG meny
#include "cmdlfdestron.h" // for FDX-A FECAVA Destron menu
#include "cmdlffdxb.h" // for FDX-B menu
#include "cmdlfgallagher.h" // for GALLAGHER 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 (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 (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;}
@ -1526,6 +1529,7 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"},
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"},
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},

189
client/src/cmdlfdestron.c Normal file
View 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
View 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

View file

@ -16,10 +16,8 @@
int CmdLFEM4X(const char *Cmd);
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);
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);

1474
client/src/cmdlfem4x05.c Normal file

File diff suppressed because it is too large Load diff

31
client/src/cmdlfem4x05.h Normal file
View 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

View file

@ -16,7 +16,7 @@
#include "em4x50.h"
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, "Usage: lf em 4x50_info [h] [v] [p <pwd>]");
PrintAndLogEx(NORMAL, "Options:");
@ -315,7 +315,7 @@ int CmdEM4x50Info(const char *Cmd) {
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -388,11 +388,14 @@ int CmdEM4x50Write(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_ETEAROFF)
return PM3_SUCCESS;
bool isOK = (resp.status & STATUS_SUCCESS) >> 1;
if (isOK == false) {
PrintAndLogEx(FAILED, "writing " _RED_("failed"));
@ -483,10 +486,14 @@ int CmdEM4x50WritePassword(const char *Cmd) {
clearCommandBuffer();
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.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_ETEAROFF)
return PM3_SUCCESS;
success = (bool)resp.status;
// 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));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -651,7 +658,7 @@ int CmdEM4x50Dump(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -726,7 +733,7 @@ int CmdEM4x50Wipe(const char *Cmd) {
clearCommandBuffer();
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");
return PM3_ETIMEOUT;
}

View file

@ -186,7 +186,7 @@ static int CmdGuardClone(const char *Cmd) {
// Q5
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
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[2] = bytebits_to_byte(bs + 32, 32);

View file

@ -378,7 +378,7 @@ static int usage_t55xx_dangerraw(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, _GREEN_("lf awid clone"));
// todo: rename to clone
PrintAndLogEx(NORMAL, _GREEN_("lf destron clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf em 410x_clone"));
// todo: implement restore
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));

View file

@ -110,9 +110,9 @@ typedef enum {
DEMOD_PSK1 = 0x01,
DEMOD_PSK2 = 0x02,
DEMOD_PSK3 = 0x03,
DEMOD_FSK1 = 0x04,
DEMOD_FSK1a = 0x05,
DEMOD_FSK2 = 0x06,
DEMOD_FSK1 = 0x04,
DEMOD_FSK2 = 0x05,
DEMOD_FSK1a = 0x06,
DEMOD_FSK2a = 0x07,
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
DEMOD_ASK = 0x08,

View file

@ -36,7 +36,9 @@
#include "fileutils.h" // searchfile
#include "cmdlf.h" // lf_config
#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, ...) {
char buffer[200];
@ -1088,7 +1090,7 @@ static int l_T55xx_detect(lua_State *L) {
return 2;
}
//
// 4305
static int l_em4x05_read(lua_State *L) {
bool use_pwd = false;
@ -1103,12 +1105,12 @@ static int l_em4x05_read(lua_State *L) {
sscanf(p_addr, "%u", &addr);
// get password
const char *p_pwd = luaL_checklstring(L, 2, &size);
if (size == 0) {
const char *p_pwd = luaL_checkstring(L, 2);
if (p_pwd == NULL || strlen(p_pwd) == 0 ) {
use_pwd = false;
} else {
if (size != 8)
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", size);
if (strlen(p_pwd) != 8)
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", strlen(p_pwd));
sscanf(p_pwd, "%08x", &password);
use_pwd = true;
@ -1128,6 +1130,66 @@ static int l_em4x05_read(lua_State *L) {
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) {
@ -1320,6 +1382,7 @@ int set_pm3_libraries(lua_State *L) {
{"ud", l_ud},
{"rem", l_remark},
{"em4x05_read", l_em4x05_read},
{"em4x50_read", l_em4x50_read},
{NULL, NULL}
};

View file

@ -895,3 +895,40 @@ int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str)
}
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
}

View file

@ -101,4 +101,9 @@ void strcreplace(char *buf, size_t len, char from, char to);
char *str_dup(const char *src);
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);
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

View file

@ -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)
* [libQt5Core.so.5 not found](#libQt5Coreso5-not-found)
* [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
@ -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
```

View file

@ -49,7 +49,7 @@ typedef struct {
uint8_t addresses[4];
uint8_t address;
uint8_t word[4];
} em4x50_data_t;
} PACKED em4x50_data_t;
typedef struct {
uint8_t byte[4];
@ -60,6 +60,6 @@ typedef struct {
bool cparity[8];
bool stopparity;
bool parity;
} em4x50_word_t;
} PACKED em4x50_word_t;
#endif /* EM4X50_H__ */

View file

@ -306,6 +306,7 @@ typedef struct {
bool use_raw;
bool use_elite;
bool use_credit_key;
bool use_replay;
bool send_reply;
bool do_auth;
uint8_t blockno;
@ -333,11 +334,15 @@ typedef struct {
} PACKED iclass_writeblock_req_t;
// iCLASS dump data structure
typedef struct {
uint8_t blockno;
uint8_t data[8];
} PACKED iclass_restore_item_t;
typedef struct {
iclass_auth_req_t req;
uint8_t start_block;
uint8_t end_block;
uint8_t data[];
uint8_t item_cnt;
iclass_restore_item_t blocks[];
} PACKED iclass_restore_req_t;
@ -350,7 +355,7 @@ typedef struct {
uint8_t mem_config; //[13]
uint8_t eas; //[14]
uint8_t fuses; //[15]
} picopass_conf_block_t;
} PACKED picopass_conf_block_t;
// iCLASS secure mode memory mapping
typedef struct {
@ -360,16 +365,22 @@ typedef struct {
uint8_t key_d[8];
uint8_t key_c[8];
uint8_t app_issuer_area[8];
} picopass_hdr;
} PACKED picopass_hdr;
// iCLASS non-secure mode memory mapping
typedef struct {
uint8_t csn[8];
picopass_conf_block_t conf;
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
#define CMD_DEVICE_INFO 0x0000
//#define CMD_SETUP_WRITE 0x0001
@ -559,12 +570,10 @@ typedef struct {
// iCLASS / Picopass
#define CMD_HF_ICLASS_READCHECK 0x038F
#define CMD_HF_ICLASS_CLONE 0x0390
#define CMD_HF_ICLASS_DUMP 0x0391
#define CMD_HF_ICLASS_SNIFF 0x0392
#define CMD_HF_ICLASS_SIMULATE 0x0393
#define CMD_HF_ICLASS_READER 0x0394
#define CMD_HF_ICLASS_REPLAY 0x0395
#define CMD_HF_ICLASS_READBL 0x0396
#define CMD_HF_ICLASS_WRITEBL 0x0397
#define CMD_HF_ICLASS_EML_MEMSET 0x0398
@ -650,6 +659,9 @@ typedef struct {
// MFU OTP TearOff
#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_PLOT 0x0801

View file

@ -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 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 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/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
@ -366,7 +367,7 @@ while true; do
"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 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 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

File diff suppressed because it is too large Load diff