added lf hitag view command to view dump files

This commit is contained in:
iceman1001 2024-01-30 10:35:30 +01:00
commit 53a5087d67
3 changed files with 225 additions and 134 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... 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]
- Added `lf hitag view` - now supports viewing of dump files (@iceman1001)
- Changed `lf hitag dump --ns` - now support nosave flag (@iceman1001) - Changed `lf hitag dump --ns` - now support nosave flag (@iceman1001)
- Added `hf xerox rdbl` - read block of a Fuji/Xerox tag (@iceman1001) - Added `hf xerox rdbl` - read block of a Fuji/Xerox tag (@iceman1001)
- Added a xerox trace file, thanks @jeroenSteen, (@iceman1001) - Added a xerox trace file, thanks @jeroenSteen, (@iceman1001)
@ -20,8 +21,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010) - Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010)
- Added `CMD_READ_MEM_DOWNLOAD` and `CMD_READ_MEM_DOWNLOADED` to osimage and bootloader (@martian01010) - Added `CMD_READ_MEM_DOWNLOAD` and `CMD_READ_MEM_DOWNLOADED` to osimage and bootloader (@martian01010)
- Changed `hf mfu info` - now correctly identifies NTAG I2C tags (@icemann1001) - Changed `hf mfu info` - now correctly identifies NTAG I2C tags (@icemann1001)
- Changed `hf 14b dump/view` - now supports `z` flag for dense output (@iceman1001) - Changed `hf 14b dump/view` - now supports `-z` flag for dense output (@iceman1001)
- Changed `hf xerox dump/view` - now supports `z` flag for dense output (@iceman1001) - Changed `hf xerox dump/view` - now supports `-z` flag for dense output (@iceman1001)
- Changed `hf mfu dump/view/eview` - now supports `-z` flag for dense output (@iceman1001) - Changed `hf mfu dump/view/eview` - now supports `-z` flag for dense output (@iceman1001)
- Added `data crypto` to encrypt and decrypt data in the proxmark client using built-in methods (@team-orangeBlue) - Added `data crypto` to encrypt and decrypt data in the proxmark client using built-in methods (@team-orangeBlue)
- Changed `hf tune` and `lf tune` - Added an option to show statistical data after tuning (@wh201906) - Changed `hf tune` and `lf tune` - Added an option to show statistical data after tuning (@wh201906)
@ -44,9 +45,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Changed `hf 15 findafi` - improved the params (@iceman1001) - Changed `hf 15 findafi` - improved the params (@iceman1001)
- Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001) - Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001)
- Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001) - Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001)
- Changed `hf 15 raw` - now supports "-k" keep field on and "-s" select (@iceman1001) - Changed `hf 15 raw` - now supports `-k` keep field on and `-s` select (@iceman1001)
- Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001) - Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001)
- Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001) - Changed `hf 14b sriwrbl` - now supports `--force` to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001)
- Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001) - Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001)
- Changed `hf 14b apdu` - now supports tearoff (@iceman1001) - Changed `hf 14b apdu` - now supports tearoff (@iceman1001)
- Fixed `hf 14b raw` - fixed a potential write out of bounds. (@iceman1001) - Fixed `hf 14b raw` - fixed a potential write out of bounds. (@iceman1001)

View file

@ -332,8 +332,7 @@ static int CmdLFHitagSim(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void print_hitag2_paxton(const uint8_t *data) {
static void printHitag2PaxtonDowngrade(const uint8_t *data) {
uint64_t bytes = 0; uint64_t bytes = 0;
uint64_t num = 0; uint64_t num = 0;
@ -359,116 +358,150 @@ static void printHitag2PaxtonDowngrade(const uint8_t *data) {
} }
} }
PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------"); PrintAndLogEx(INFO, "");
PrintAndLogEx(SUCCESS, "Paxton id: %lu | 0x%lx", paxton_id, paxton_id); PrintAndLogEx(INFO, "--- " _CYAN_("Possible de-scramble patterns") " -------------");
PrintAndLogEx(SUCCESS, "Paxton id... %" PRIu64 " | 0x%" PRIx64, paxton_id, paxton_id);
} }
static void printHitag2Configuration(uint8_t config) { static void print_hitag2_configuration(uint32_t uid, uint8_t config) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid);
PrintAndLogEx(SUCCESS, "TYPE... " _GREEN_("%s"), getHitagTypeStr(uid));
char msg[100]; char msg[100];
memset(msg, 0, sizeof(msg)); memset(msg, 0, sizeof(msg));
char bits[9]; uint8_t bits[8 + 1] = {0};
char *bs = bits; num_to_bytebits(config, 8, bits);
for (uint8_t i = 0 ; i < 8 ; i++) { const char *bs = sprint_bytebits_bin(bits, 8);
snprintf(bs, sizeof(bits) - i, "%1d", (config >> (7 - i)) & 1);
bs++;
}
PrintAndLogEx(INFO, "\n\nHitag2 tag information ");
PrintAndLogEx(INFO, "------------------------------------");
//configuration byte //configuration byte
PrintAndLogEx(SUCCESS, "Config byte : 0x%02X [ %s ]", config, bits); PrintAndLogEx(SUCCESS, "");
PrintAndLogEx(SUCCESS, "Config byte... 0x%02X", config);
PrintAndLogEx(SUCCESS, " %s", bs);
// encoding
strcat(msg, "Encoding : "); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 0, 4, "RFU"));
if (config & 0x1) {
strcat(msg + strlen(msg), _YELLOW_("Biphase")); if (config & 0x8) {
PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_YELLOW, bs, 8, 4, 1, "Crypto mode"));
} else { } else {
strcat(msg + strlen(msg), _YELLOW_("Manchester")); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 4, 1, "Password mode"));
} }
PrintAndLogEx(SUCCESS, "%s", msg);
memset(msg, 0, sizeof(msg));
// version // version
strcat(msg, "Coding in HITAG 2 operation: %s"); uint8_t foo = ((config & 0x6) >> 1);
uint8_t foo = (config & 0x6) >> 1;
switch (foo) { switch (foo) {
case 0: case 0:
PrintAndLogEx(SUCCESS, "Version : public mode B, Coding: biphase"); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode B, Coding: biphase"));
PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
break; break;
case 1: case 1:
PrintAndLogEx(SUCCESS, "Version : public mode A, Coding: manchester"); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode A, Coding: manchester"));
PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
break; break;
case 2: case 2:
PrintAndLogEx(SUCCESS, "Version : public mode C, Coding: biphase"); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Public mode C, Coding: biphase"));
PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
break; break;
case 3: case 3:
PrintAndLogEx(SUCCESS, "Version : Hitag2"); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 5, 2, "Hitag2"));
PrintAndLogEx(SUCCESS, msg, (config & 0x1) ? "biphase" : "manchester");
break; break;
} }
memset(msg, 0, sizeof(msg));
// mode // encoding
strcat(msg, "Tag is in : "); if (config & 0x01) {
if (config & 0x8) { PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 7, 1, "Biphase"));
strcat(msg + strlen(msg), _YELLOW_("Crypto mode"));
} else { } else {
strcat(msg + strlen(msg), _YELLOW_("Password mode")); PrintAndLogEx(SUCCESS, " %s", sprint_breakdown_bin(C_NONE, bs, 8, 7, 1, "Manchester"));
} }
PrintAndLogEx(SUCCESS, "%s", msg);
memset(msg, 0, sizeof(msg));
// page access }
strcat(msg, "Page 6,7 : ");
if (config & 0x10) {
strcat(msg + strlen(msg), "read only");
} else {
strcat(msg + strlen(msg), _GREEN_("RW"));
}
PrintAndLogEx(SUCCESS, "%s", msg);
memset(msg, 0, sizeof(msg));
// page access const char* annotation[] = {
strcat(msg, "Page 4,5 : "); "UID", "Pwd", "Key/Pwd", "Config",
if (config & 0x20) { "User", "User", "User", "User",
strcat(msg + strlen(msg), "read only"); "User", "User", "User", "User"
} else { };
strcat(msg + strlen(msg), _GREEN_("RW"));
}
PrintAndLogEx(SUCCESS, "%s", msg);
memset(msg, 0, sizeof(msg));
// OTP static void print_hitag2_blocks(uint8_t *d, uint16_t n) {
strcat(msg, "Page 3 : ");
if (config & 0x40) {
strcat(msg + strlen(msg), "read only. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE"));
} else {
strcat(msg + strlen(msg), _GREEN_("RW"));
}
PrintAndLogEx(SUCCESS, "%s", msg);
memset(msg, 0, sizeof(msg));
// OTP PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, "-----------------------------------------------");
PrintAndLogEx(INFO, "block# | data | ascii | lck | Info");
PrintAndLogEx(INFO, "---------+-------------+-------+-----+---------");
uint8_t config = d[HITAG2_CONFIG_OFFSET];
uint8_t blocks = (n / HITAG_BLOCK_SIZE);
for (uint8_t i = 0; i < blocks; ++i) {
char lckstr[20] = {0};
sprintf(lckstr, " ");
switch (i) {
case 0:
sprintf(lckstr, "%s", _RED_("L "));
break;
case 1:
if (config & 0x80) {
sprintf(lckstr, "%s", _RED_("L "));
} else {
sprintf(lckstr, "%s", _GREEN_("RW"));
}
break;
case 2:
if (config & 0x80) { if (config & 0x80) {
strcat(msg, "Page 1 : " _RED_("locked") "\n");
strcat(msg + strlen(msg), "Page 2 : ");
if (config & 0x8) { if (config & 0x8) {
strcat(msg + strlen(msg), _RED_("locked")); sprintf(lckstr, "%s", _RED_("L "));
} else { } else {
strcat(msg + strlen(msg), "read only"); sprintf(lckstr, "%s", _RED_("R "));
} }
} else { } else {
strcat(msg, "Page 1,2 : " _GREEN_("RW")); sprintf(lckstr, "%s", _GREEN_("RW"));
} }
PrintAndLogEx(SUCCESS, "%s", msg); break;
PrintAndLogEx(INFO, "------------------------------------"); case 3:
// OTP Page 3.
if (config & 0x40) {
sprintf(lckstr, "%s", _RED_("R "));
//. Configuration byte and password tag " _RED_("FIXED / IRREVERSIBLE"));
} else {
sprintf(lckstr, "%s", _GREEN_("RW"));
}
break;
case 4:
case 5:
if (config & 0x20) {
sprintf(lckstr, "%s", _RED_("R "));
} else {
sprintf(lckstr, "%s", _GREEN_("RW"));
}
break;
case 6:
case 7:
if (config & 0x10) {
sprintf(lckstr, "%s", _RED_("R "));
} else {
sprintf(lckstr, "%s", _GREEN_("RW"));
}
break;
default:
break;
}
PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s | %s | %s"
, i
, i
, sprint_hex(d + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE)
, sprint_ascii(d + (i * HITAG_BLOCK_SIZE), HITAG_BLOCK_SIZE)
, lckstr
, annotation[i]
);
}
PrintAndLogEx(INFO, "---------+-------------+-------+-----+---------");
PrintAndLogEx(INFO, " L = Locked, "_GREEN_("RW") " = Read Write, R = Read Only");
PrintAndLogEx(INFO, " FI = Fixed / Irreversible");
PrintAndLogEx(INFO, "-----------------------------------------------");
} }
static bool getHitag2Uid(uint32_t *uid) { static bool getHitag2Uid(uint32_t *uid) {
@ -477,7 +510,7 @@ static bool getHitag2Uid(uint32_t *uid) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_UID_ONLY, 0, 0, &htd, sizeof(htd)); SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_UID_ONLY, 0, 0, &htd, sizeof(htd));
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return false; return false;
} }
@ -487,8 +520,9 @@ static bool getHitag2Uid(uint32_t *uid) {
return false; return false;
} }
if (uid) if (uid) {
*uid = bytes_to_num(resp.data.asBytes, 4); *uid = bytes_to_num(resp.data.asBytes, HITAG_UID_SIZE);
}
return true; return true;
} }
@ -509,24 +543,18 @@ static int CmdLFHitagInfo(const char *Cmd) {
// read UID // read UID
uint32_t uid = 0; uint32_t uid = 0;
if (getHitag2Uid(&uid) == false) if (getHitag2Uid(&uid) == false) {
return PM3_ESOFT; return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%08X"), uid);
PrintAndLogEx(SUCCESS, " TYPE: " _GREEN_("%s"), getHitagTypeStr(uid));
// how to determine Hitag types? // how to determine Hitag types?
// read block3, get configuration byte. // read block3, get configuration byte.
// common configurations. // common configurations.
// printHitag2Configuration(0x06); print_hitag2_configuration( uid, 0x06 );
//printHitag2Configuration( 0x0E ); // print_hitag2_configuration( uid, 0x0E );
//printHitag2Configuration( 0x02 ); // print_hitag2_configuration( uid, 0x02 );
//printHitag2Configuration( 0x00 ); // print_hitag2_configuration( uid, 0x00 );
//printHitag2Configuration( 0x04 ); // print_hitag2_configuration( uid, 0x04 );
PrintAndLogEx(INFO, "-------------------------------------------------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -700,12 +728,11 @@ static int CmdLFHitagReader(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
uint8_t *data = resp.data.asBytes; uint8_t *data = resp.data.asBytes;
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); uint32_t uid = bytes_to_num(data, HITAG_UID_SIZE);
printHitag2Configuration(data[4 * 3]); print_hitag2_configuration(uid, data[HITAG_BLOCK_SIZE * 3]);
print_hex_break(data, 48, 4); print_hex_break(data, HITAG2_MAX_BYTE_SIZE, HITAG_BLOCK_SIZE);
printHitag2PaxtonDowngrade(data); print_hitag2_paxton(data);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -773,7 +800,6 @@ static int CmdLFHitag2CheckChallenges(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdLFHitagWriter(const char *Cmd) { static int CmdLFHitagWriter(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag wrbl", CLIParserInit(&ctx, "lf hitag wrbl",
@ -985,6 +1011,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
arg_lit0(NULL, "crypto", "crypto mode"), arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"), arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_str0("f", "file", "<fn>", "specify file name"), arg_str0("f", "file", "<fn>", "specify file name"),
arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -1006,7 +1033,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
bool use_nrar = nalen > 0; bool use_nrar = nalen > 0;
bool use_crypto = arg_get_lit(ctx, 3); bool use_crypto = arg_get_lit(ctx, 3);
uint8_t key[6]; uint8_t key[HITAG_CRYPTOKEY_SIZE];
int keylen = 0; int keylen = 0;
res = CLIParamHexToBuf(arg_get_str(ctx, 4), key, sizeof(key), &keylen); res = CLIParamHexToBuf(arg_get_str(ctx, 4), key, sizeof(key), &keylen);
if (res != 0) { if (res != 0) {
@ -1018,6 +1045,7 @@ static int CmdLFHitag2Dump(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool nosave = arg_get_lit(ctx, 6);
CLIParserFree(ctx); CLIParserFree(ctx);
// sanity checks // sanity checks
@ -1036,19 +1064,21 @@ static int CmdLFHitag2Dump(const char *Cmd) {
} }
// complete options // complete options
if (keylen == 4) { if (keylen == HITAG_PASSWORD_SIZE) {
use_pwd = true; use_pwd = true;
} }
if (keylen == 6) { if (keylen == HITAG_CRYPTOKEY_SIZE) {
use_crypto = true; use_crypto = true;
} }
// Set default key / pwd
if ((keylen == 0) && use_pwd) { if ((keylen == 0) && use_pwd) {
memcpy(key, "MIKR", 4); memcpy(key, "MIKR", HITAG_PASSWORD_SIZE);
keylen = 4; keylen = HITAG_PASSWORD_SIZE;
} }
if ((keylen == 0) && use_crypto) { if ((keylen == 0) && use_crypto) {
memcpy(key, "ONMIKR", 6); memcpy(key, "ONMIKR", HITAG_CRYPTOKEY_SIZE);
keylen = 6; keylen = HITAG_CRYPTOKEY_SIZE;
} }
// check coherence // check coherence
@ -1081,11 +1111,11 @@ static int CmdLFHitag2Dump(const char *Cmd) {
if (use_ht2 && use_pwd) { if (use_ht2 && use_pwd) {
htf = RHT2F_PASSWORD; htf = RHT2F_PASSWORD;
memcpy(htd.pwd.password, key, sizeof(htd.pwd.password)); memcpy(htd.pwd.password, key, sizeof(htd.pwd.password));
PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Password mode"); PrintAndLogEx(INFO, "Authenticating to Hitag2 in Password mode");
} else if (use_ht2 && use_crypto) { } else if (use_ht2 && use_crypto) {
htf = RHT2F_CRYPTO; htf = RHT2F_CRYPTO;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key)); memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Crypto mode"); PrintAndLogEx(INFO, "Authenticating to Hitag2 in Crypto mode");
} else { } else {
PrintAndLogEx(WARNING, "Sorry, not yet implemented"); PrintAndLogEx(WARNING, "Sorry, not yet implemented");
return PM3_ENOTIMPL; return PM3_ENOTIMPL;
@ -1103,34 +1133,77 @@ static int CmdLFHitag2Dump(const char *Cmd) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed"); PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return PM3_ESOFT; return PM3_ESOFT;
} }
uint8_t *data = resp.data.asBytes; uint8_t *data = resp.data.asBytes;
if (data == NULL) // block3, 1 byte
return PM3_ESOFT; uint32_t uid = bytes_to_num(data, HITAG_UID_SIZE);
print_hitag2_configuration(uid, data[HITAG_BLOCK_SIZE * 3]);
print_hitag2_blocks(data, HITAG2_MAX_BYTE_SIZE);
print_hitag2_paxton(data);
uint32_t id = bytes_to_num(resp.data.asBytes, 4); if (nosave) {
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Called with no save option");
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
if (fnlen < 1) { if (fnlen < 1) {
char *fptr = filename; char *fptr = filename;
fptr += snprintf(filename, sizeof(filename), "lf-hitag-"); fptr += snprintf(filename, sizeof(filename), "lf-hitag-");
FillFileNameByUID(fptr, data, "-dump", 4); FillFileNameByUID(fptr, data, "-dump", HITAG_UID_SIZE);
} }
// block3, 1 byte pm3_save_dump(filename, data, HITAG2_MAX_BYTE_SIZE, jsfHitag);
printHitag2Configuration(data[4 * 3]);
// print data
print_hex_break(data, 48, 4);
printHitag2PaxtonDowngrade(data);
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
pm3_save_dump(filename, data, 48, jsfHitag);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdLFHitagView(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag view",
"Print a HITAG dump file (bin/eml/json)",
"lf hitag view -f lf-hitag-01020304-dump.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
arg_lit0("v", "verbose", "Verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE];
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool verbose = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
// read dump file
uint8_t *dump = NULL;
size_t bytes_read = 0;
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, HITAG2_MAX_BYTE_SIZE);
if (res != PM3_SUCCESS) {
return res;
}
if (bytes_read < HITAG2_MAX_BYTE_SIZE) {
PrintAndLogEx(ERR, "Error, dump file is too small");
free(dump);
return PM3_ESOFT;
}
if (verbose) {
// block3, 1 byte
uint8_t config = dump[HITAG_BLOCK_SIZE * 3];
uint32_t uid = bytes_to_num(dump, HITAG_UID_SIZE);
print_hitag2_configuration(uid, config);
print_hitag2_paxton(dump);
}
print_hitag2_blocks(dump, HITAG2_MAX_BYTE_SIZE);
free(dump);
return PM3_SUCCESS;
}
// Annotate HITAG protocol // Annotate HITAG protocol
void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) { void annotateHitag1(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize, bool is_response) {
@ -1197,6 +1270,7 @@ static command_t CommandTable[] = {
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"}, {"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"},
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag 2 tag"}, {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag 2 tag"},
{"read", CmdLFHitagReader, IfPm3Hitag, "Read Hitag memory"}, {"read", CmdLFHitagReader, IfPm3Hitag, "Read Hitag memory"},
{"view", CmdLFHitagView, AlwaysAvailable, "Display content from tag dump file"},
{"wrbl", CmdLFHitagWriter, IfPm3Hitag, "Write a block (page) in Hitag memory"}, {"wrbl", CmdLFHitagWriter, IfPm3Hitag, "Write a block (page) in Hitag memory"},
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"}, {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
{"cc", CmdLFHitagSCheckChallenges, IfPm3Hitag, "Hitag S: test all provided challenges"}, {"cc", CmdLFHitagSCheckChallenges, IfPm3Hitag, "Hitag S: test all provided challenges"},
@ -1223,6 +1297,8 @@ int readHitagUid(void) {
} }
uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit) { uint8_t hitag1_CRC_check(uint8_t *d, uint32_t nbit) {
if (nbit < 9) return 2; if (nbit < 9) {
return 2;
}
return (CRC8Hitag1Bits(d, nbit) == 0); return (CRC8Hitag1Bits(d, nbit) == 0);
} }

View file

@ -21,6 +21,20 @@
#include "common.h" #include "common.h"
#define HITAG_CRYPTOKEY_SIZE 6
#define HITAG_PASSWORD_SIZE 4
#define HITAG_UID_SIZE 4
#define HITAG_BLOCK_SIZE 4
#define HITAG2_MAX_BYTE_SIZE 48
// need to see which limits these cards has
#define HITAG1_MAX_BYTE_SIZE 64
#define HITAGS_MAX_BYTE_SIZE 64
#define HITAGU_MAX_BYTE_SIZE 64
#define HITAG2_CONFIG_BLOCK 3
#define HITAG2_CONFIG_OFFSET (HITAG_BLOCK_SIZE * HITAG2_CONFIG_BLOCK)
int CmdLFHitag(const char *Cmd); int CmdLFHitag(const char *Cmd);
int readHitagUid(void); int readHitagUid(void);