mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
hf 14a info: add ATR fingerprinting
This commit is contained in:
@@ -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]
|
||||
- Added ATR fingerprinting to `hf 14a info` (@doegox)
|
||||
|
||||
## [Phrack.4.20728][2025-09-11]
|
||||
- Change `lf t55xx restore` - now skips writing block0 if its all zeros (@iceman1001)
|
||||
|
||||
@@ -48,6 +48,7 @@ C_HEADER="""//------------------------------------------------------------------
|
||||
|
||||
#define ATRS_H__
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct atr_s {
|
||||
const char *bytes;
|
||||
@@ -55,6 +56,8 @@ typedef struct atr_s {
|
||||
} atr_t;
|
||||
|
||||
const char *getAtrInfo(const char *atr_str);
|
||||
void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen);
|
||||
void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen);
|
||||
|
||||
// atr_t array is expected to be NULL terminated
|
||||
const static atr_t AtrTable[] = {
|
||||
|
||||
@@ -67,3 +67,62 @@ const char *getAtrInfo(const char *atr_str) {
|
||||
return AtrTable[ARRAYLEN(AtrTable) - 1].desc;
|
||||
}
|
||||
}
|
||||
|
||||
void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen) {
|
||||
uint8_t historicalLen = 0;
|
||||
uint8_t offset = 2;
|
||||
|
||||
if (ats[0] < 2) {
|
||||
historicalLen = 0;
|
||||
} else {
|
||||
|
||||
if ((ats[1] & 64) != 0) {
|
||||
offset++;
|
||||
}
|
||||
if ((ats[1] & 32) != 0) {
|
||||
offset++;
|
||||
}
|
||||
if ((ats[1] & 16) != 0) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (offset >= ats[0]) {
|
||||
historicalLen = 0;
|
||||
} else {
|
||||
historicalLen = ats[0] - offset;
|
||||
}
|
||||
}
|
||||
|
||||
atr[0] = 0x3B;
|
||||
atr[1] = 0x80 | historicalLen;
|
||||
atr[2] = 0x80;
|
||||
atr[3] = 0x01;
|
||||
|
||||
uint8_t tck = atr[1] ^ atr[2] ^ atr[3];
|
||||
for (uint8_t i = 0; i < historicalLen; ++i) {
|
||||
atr[4 + i] = ats[offset + i];
|
||||
tck = tck ^ ats[offset + i];
|
||||
}
|
||||
atr[4 + historicalLen] = tck;
|
||||
|
||||
*atrLen = 5 + historicalLen;
|
||||
}
|
||||
|
||||
void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen) {
|
||||
atr[0] = 0x3B;
|
||||
atr[1] = 0x80 | 8;
|
||||
atr[2] = 0x80;
|
||||
atr[3] = 0x01;
|
||||
|
||||
memcpy(atr + 4, atqb, 7);
|
||||
atr[11] = cid >> 4;
|
||||
|
||||
uint8_t tck = 0;
|
||||
for (int i = 1; i < 12; ++i) {
|
||||
tck = tck ^ atr[i];
|
||||
}
|
||||
atr[12] = tck;
|
||||
|
||||
*atrLen = 13;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#define ATRS_H__
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct atr_s {
|
||||
const char *bytes;
|
||||
@@ -30,6 +31,8 @@ typedef struct atr_s {
|
||||
} atr_t;
|
||||
|
||||
const char *getAtrInfo(const char *atr_str);
|
||||
void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen);
|
||||
void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen);
|
||||
|
||||
// atr_t array is expected to be NULL terminated
|
||||
const static atr_t AtrTable[] = {
|
||||
|
||||
+13
-1
@@ -2946,7 +2946,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
if ((card.ats[0] > pos) && (card.ats_len >= card.ats[0] + 2)) {
|
||||
uint8_t calen = card.ats[0] - pos;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " ----------------------------");
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " ---------------------------");
|
||||
|
||||
if (card.ats[pos] == 0xC1) {
|
||||
PrintAndLogEx(INFO, " %s", sprint_hex(card.ats + pos, calen));
|
||||
@@ -3024,6 +3024,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
, sprint_ascii(card.ats + pos, calen)
|
||||
);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------------------ " _CYAN_("ATR fingerprinting") " ---------------------------");
|
||||
uint8_t atr[256] = {0};
|
||||
int atrLen = 0;
|
||||
atsToEmulatedAtr(card.ats, atr, &atrLen);
|
||||
char *copy = str_dup(getAtrInfo(sprint_hex_inrow(atr, atrLen)));
|
||||
char *token = strtok(copy, "\n");
|
||||
while (token != NULL) {
|
||||
PrintAndLogEx(INFO, " %s", token);
|
||||
token = strtok(NULL, "\n");
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1212,64 +1212,6 @@ static int CmdSmartBruteforceSFI(const char *Cmd) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen) {
|
||||
uint8_t historicalLen = 0;
|
||||
uint8_t offset = 2;
|
||||
|
||||
if (ats[0] < 2) {
|
||||
historicalLen = 0;
|
||||
} else {
|
||||
|
||||
if ((ats[1] & 64) != 0) {
|
||||
offset++;
|
||||
}
|
||||
if ((ats[1] & 32) != 0) {
|
||||
offset++;
|
||||
}
|
||||
if ((ats[1] & 16) != 0) {
|
||||
offset++;
|
||||
}
|
||||
|
||||
if (offset >= ats[0]) {
|
||||
historicalLen = 0;
|
||||
} else {
|
||||
historicalLen = ats[0] - offset;
|
||||
}
|
||||
}
|
||||
|
||||
atr[0] = 0x3B;
|
||||
atr[1] = 0x80 | historicalLen;
|
||||
atr[2] = 0x80;
|
||||
atr[3] = 0x01;
|
||||
|
||||
uint8_t tck = atr[1] ^ atr[2] ^ atr[3];
|
||||
for (uint8_t i = 0; i < historicalLen; ++i) {
|
||||
atr[4 + i] = ats[offset + i];
|
||||
tck = tck ^ ats[offset + i];
|
||||
}
|
||||
atr[4 + historicalLen] = tck;
|
||||
|
||||
*atrLen = 5 + historicalLen;
|
||||
}
|
||||
|
||||
static void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen) {
|
||||
atr[0] = 0x3B;
|
||||
atr[1] = 0x80 | 8;
|
||||
atr[2] = 0x80;
|
||||
atr[3] = 0x01;
|
||||
|
||||
memcpy(atr + 4, atqb, 7);
|
||||
atr[11] = cid >> 4;
|
||||
|
||||
uint8_t tck = 0;
|
||||
for (int i = 1; i < 12; ++i) {
|
||||
tck = tck ^ atr[i];
|
||||
}
|
||||
atr[12] = tck;
|
||||
|
||||
*atrLen = 13;
|
||||
}
|
||||
|
||||
static int CmdPCSC(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "smart pcsc",
|
||||
|
||||
Reference in New Issue
Block a user