mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
commit
a21f08d07d
13 changed files with 108455 additions and 179 deletions
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||||
|
|
||||||
#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), (*datalen), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void **argtable;
|
void **argtable;
|
||||||
|
|
|
@ -47,9 +47,6 @@ EEEEEEEE
|
||||||
FFFFFFFF
|
FFFFFFFF
|
||||||
a0a1a2a3
|
a0a1a2a3
|
||||||
b0b1b2b3
|
b0b1b2b3
|
||||||
aabbccdd
|
|
||||||
bbccddee
|
|
||||||
ccddeeff
|
|
||||||
50415353
|
50415353
|
||||||
00000001
|
00000001
|
||||||
00000002
|
00000002
|
||||||
|
|
|
@ -209,6 +209,7 @@ static int cmd_hf_fido_register(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(cdata, 0x00, 32);
|
memset(cdata, 0x00, 32);
|
||||||
|
chlen = sizeof(cdata);
|
||||||
CLIGetStrWithReturn(ctx, 6, cdata, &chlen);
|
CLIGetStrWithReturn(ctx, 6, cdata, &chlen);
|
||||||
if (chlen > 16) {
|
if (chlen > 16) {
|
||||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
||||||
|
@ -216,6 +217,7 @@ static int cmd_hf_fido_register(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
chlen = sizeof(cdata);
|
||||||
CLIGetHexWithReturn(ctx, 6, cdata, &chlen);
|
CLIGetHexWithReturn(ctx, 6, cdata, &chlen);
|
||||||
if (chlen && chlen != 32) {
|
if (chlen && chlen != 32) {
|
||||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
||||||
|
@ -229,6 +231,7 @@ static int cmd_hf_fido_register(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(adata, 0x00, 32);
|
memset(adata, 0x00, 32);
|
||||||
|
applen = sizeof(adata);
|
||||||
CLIGetStrWithReturn(ctx, 7, adata, &applen);
|
CLIGetStrWithReturn(ctx, 7, adata, &applen);
|
||||||
if (applen > 16) {
|
if (applen > 16) {
|
||||||
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
||||||
|
@ -236,6 +239,7 @@ static int cmd_hf_fido_register(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
applen = sizeof(adata);
|
||||||
CLIGetHexWithReturn(ctx, 7, adata, &applen);
|
CLIGetHexWithReturn(ctx, 7, adata, &applen);
|
||||||
if (applen && applen != 32) {
|
if (applen && applen != 32) {
|
||||||
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
||||||
|
@ -485,6 +489,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(hdata, 0x00, 32);
|
memset(hdata, 0x00, 32);
|
||||||
|
hdatalen = sizeof(hdata);
|
||||||
CLIGetStrWithReturn(ctx, 9, hdata, &hdatalen);
|
CLIGetStrWithReturn(ctx, 9, hdata, &hdatalen);
|
||||||
if (hdatalen > 16) {
|
if (hdatalen > 16) {
|
||||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||||
|
@ -492,6 +497,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 32) {
|
if (hdatalen && hdatalen != 32) {
|
||||||
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only.");
|
||||||
|
@ -505,6 +511,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(hdata, 0x00, 32);
|
memset(hdata, 0x00, 32);
|
||||||
|
hdatalen = sizeof(hdata);
|
||||||
CLIGetStrWithReturn(ctx, 11, hdata, &hdatalen);
|
CLIGetStrWithReturn(ctx, 11, hdata, &hdatalen);
|
||||||
if (hdatalen > 16) {
|
if (hdatalen > 16) {
|
||||||
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||||
|
@ -512,6 +519,7 @@ static int cmd_hf_fido_authenticate(const char *cmd) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
hdatalen = sizeof(hdata);
|
||||||
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 32) {
|
if (hdatalen && hdatalen != 32) {
|
||||||
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only.");
|
||||||
|
@ -693,6 +701,7 @@ static int cmd_hf_fido_2make_credential(const char *cmd) {
|
||||||
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
||||||
char *cjsonname = (char *)jsonname;
|
char *cjsonname = (char *)jsonname;
|
||||||
int jsonnamelen = 0;
|
int jsonnamelen = 0;
|
||||||
|
jsonnamelen = sizeof(jsonname);
|
||||||
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
||||||
|
|
||||||
if (!jsonnamelen) {
|
if (!jsonnamelen) {
|
||||||
|
@ -817,7 +826,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) {
|
||||||
|
|
||||||
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
uint8_t jsonname[FILE_PATH_SIZE] = {0};
|
||||||
char *cjsonname = (char *)jsonname;
|
char *cjsonname = (char *)jsonname;
|
||||||
int jsonnamelen = 0;
|
int jsonnamelen = sizeof(jsonname);
|
||||||
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
|
||||||
|
|
||||||
if (!jsonnamelen) {
|
if (!jsonnamelen) {
|
||||||
|
|
|
@ -35,20 +35,7 @@
|
||||||
#include "cmdhw.h"
|
#include "cmdhw.h"
|
||||||
|
|
||||||
//////////////// 4205 / 4305 commands
|
//////////////// 4205 / 4305 commands
|
||||||
static int usage_lf_em4x05_dump(void) {
|
|
||||||
PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. ");
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
|
||||||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [f <filename prefix>] <pwd>");
|
|
||||||
PrintAndLogEx(NORMAL, "Options:");
|
|
||||||
PrintAndLogEx(NORMAL, " h - this help");
|
|
||||||
PrintAndLogEx(NORMAL, " f <filename prefix> - overide filename prefix (optional). Default is based on UID");
|
|
||||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
|
||||||
PrintAndLogEx(NORMAL, "Examples:");
|
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump");
|
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344");
|
|
||||||
PrintAndLogEx(NORMAL, " lf em 4x05_dump f card1 11223344");
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
static int usage_lf_em4x05_wipe(void) {
|
static int usage_lf_em4x05_wipe(void) {
|
||||||
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
|
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
@ -103,6 +90,48 @@ static int usage_lf_em4x05_info(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EM_SERIAL_BLOCK 1
|
||||||
|
#define EM_CONFIG_BLOCK 4
|
||||||
|
#define EM4305_PROT1_BLOCK 14
|
||||||
|
#define EM4305_PROT2_BLOCK 15
|
||||||
|
#define EM4469_PROT_BLOCK 3
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EM_UNKNOWN,
|
||||||
|
EM_4205,
|
||||||
|
EM_4305,
|
||||||
|
EM_4X69,
|
||||||
|
} em_tech_type_t;
|
||||||
|
|
||||||
|
// 1 = EM4x69
|
||||||
|
// 2 = EM4x05
|
||||||
|
static em_tech_type_t em_get_card_type(uint32_t config) {
|
||||||
|
uint8_t t = (config >> 1) & 0xF;
|
||||||
|
switch(t) {
|
||||||
|
case 4:
|
||||||
|
return EM_4X69;
|
||||||
|
case 8:
|
||||||
|
return EM_4205;
|
||||||
|
case 9:
|
||||||
|
return EM_4305;
|
||||||
|
}
|
||||||
|
return EM_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* em_get_card_str(uint32_t config) {
|
||||||
|
switch (em_get_card_type(config)) {
|
||||||
|
case EM_4305:
|
||||||
|
return "EM4305";
|
||||||
|
case EM_4X69:
|
||||||
|
return "EM4469";
|
||||||
|
case EM_4205:
|
||||||
|
return "EM4205";
|
||||||
|
case EM_UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
// even parity COLUMN
|
// even parity COLUMN
|
||||||
static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
|
||||||
if (rows * cols > size) return false;
|
if (rows * cols > size) return false;
|
||||||
|
@ -366,37 +395,52 @@ int CmdEM4x05Demod(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x05Dump(const char *Cmd) {
|
int CmdEM4x05Dump(const char *Cmd) {
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "lf em dump",
|
||||||
|
"Dump EM4x05/EM4x69. Tag must be on antenna.",
|
||||||
|
"lf em dump\n"
|
||||||
|
"lf em dump -p 11223344\n"
|
||||||
|
"lf em dump -f myfile -p 11223344"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_u64_0("p", "pwd", "<hex>", "password (0x00000000)"),
|
||||||
|
arg_str0("f", "file", "<filename>", "overide filename prefix (optional). Default is based on UID"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
uint64_t inputpwd = arg_get_u64_def(ctx, 1, 0xFFFFFFFFFFFFFFFF);
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t addr = 0;
|
uint8_t addr = 0;
|
||||||
uint32_t pwd = 0;
|
uint32_t pwd = 0;
|
||||||
bool usePwd = false;
|
bool usePwd = false;
|
||||||
|
if (inputpwd != 0xFFFFFFFFFFFFFFFF) {
|
||||||
|
|
||||||
|
if (inputpwd & 0xFFFFFFFF00000000) {
|
||||||
|
PrintAndLogEx(FAILED, "Pwd too large");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
usePwd = true;
|
||||||
|
pwd = (inputpwd & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t block0 = 0;
|
||||||
|
// read word 0 (chip info)
|
||||||
|
// block 0 can be read even without a password.
|
||||||
|
if (EM4x05IsBlock0(&block0) == false)
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
bool needReadPwd = true;
|
bool needReadPwd = true;
|
||||||
uint8_t cmdp = 0;
|
|
||||||
uint8_t bytes[4] = {0};
|
uint8_t bytes[4] = {0};
|
||||||
uint32_t data[16];
|
uint32_t data[16];
|
||||||
char preferredName[FILE_PATH_SIZE] = {0};
|
|
||||||
char optchk[10];
|
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00) {
|
|
||||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
|
||||||
case 'h':
|
|
||||||
return usage_lf_em4x05_dump();
|
|
||||||
break;
|
|
||||||
case 'f': // since f could match in password, lets confirm it is 1 character only for an option
|
|
||||||
param_getstr(Cmd, cmdp, optchk, sizeof(optchk));
|
|
||||||
if (strlen(optchk) == 1) { // Have a single character f so filename no password
|
|
||||||
param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE);
|
|
||||||
cmdp += 2;
|
|
||||||
break;
|
|
||||||
} // if not a single 'f' dont break and flow onto default as should be password
|
|
||||||
|
|
||||||
default : // for backwards-compatibility options should be > 'f' else assume its the hex password`
|
|
||||||
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
|
|
||||||
pwd = param_get32ex(Cmd, cmdp, 1, 16);
|
|
||||||
if (pwd != 1)
|
|
||||||
usePwd = true;
|
|
||||||
cmdp++;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
int success = PM3_SUCCESS;
|
int success = PM3_SUCCESS;
|
||||||
int status, status14, status15;
|
int status, status14, status15;
|
||||||
|
@ -404,105 +448,189 @@ int CmdEM4x05Dump(const char *Cmd) {
|
||||||
bool gotLockBits = false;
|
bool gotLockBits = false;
|
||||||
bool lockInPW2 = false;
|
bool lockInPW2 = false;
|
||||||
uint32_t word = 0;
|
uint32_t word = 0;
|
||||||
|
|
||||||
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
|
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
|
||||||
|
const char *info4x69 [] = {"Info", "UID", "Password", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
|
||||||
|
|
||||||
if (usePwd) {
|
// EM4305 vs EM4469
|
||||||
// Test first if a password is required
|
em_tech_type_t card_type = em_get_card_type(block0);
|
||||||
status = EM4x05ReadWord_ext(14, pwd, false, &word);
|
|
||||||
if (status == PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
|
||||||
needReadPwd = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info");
|
|
||||||
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
|
|
||||||
|
|
||||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
PrintAndLogEx(INFO, "Found a " _GREEN_("%s") " tag", em_get_card_str(block0));
|
||||||
// dont swap endin until we get block lock flags.
|
PrintAndLogEx(NORMAL, "");
|
||||||
status14 = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
|
|
||||||
if (status14 == PM3_SUCCESS) {
|
PrintAndLogEx(INFO, "Addr | data | ascii |lck| info");
|
||||||
if (!usePwd)
|
PrintAndLogEx(INFO, "-----+----------+-------+---+-----");
|
||||||
needReadPwd = false;
|
|
||||||
if ((word & 0x00008000) != 0x00) {
|
if ( card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
|
||||||
lock_bits = word;
|
|
||||||
gotLockBits = true;
|
if (usePwd) {
|
||||||
|
// Test first if a password is required
|
||||||
|
status = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, false, &word);
|
||||||
|
if (status == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||||
|
needReadPwd = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data[14] = word;
|
|
||||||
} else {
|
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
// dont swap endin until we get block lock flags.
|
||||||
}
|
status14 = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
|
||||||
status15 = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
|
if (status14 == PM3_SUCCESS) {
|
||||||
if (status15 == PM3_SUCCESS) {
|
if (!usePwd)
|
||||||
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
needReadPwd = false;
|
||||||
lock_bits = word;
|
if ((word & 0x00008000) != 0x00) {
|
||||||
gotLockBits = true;
|
lock_bits = word;
|
||||||
lockInPW2 = true;
|
gotLockBits = true;
|
||||||
|
}
|
||||||
|
data[EM4305_PROT1_BLOCK] = word;
|
||||||
|
} else {
|
||||||
|
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||||
}
|
}
|
||||||
data[15] = word;
|
status15 = EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word);
|
||||||
} else {
|
if (status15 == PM3_SUCCESS) {
|
||||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
||||||
}
|
lock_bits = word;
|
||||||
uint32_t lockbit;
|
gotLockBits = true;
|
||||||
// Now read blocks 0 - 13 as we have 14 and 15
|
lockInPW2 = true;
|
||||||
for (; addr < 14; addr++) {
|
}
|
||||||
lockbit = (lock_bits >> addr) & 1;
|
data[EM4305_PROT2_BLOCK] = word;
|
||||||
if (addr == 2) {
|
} else {
|
||||||
if (usePwd) {
|
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
}
|
||||||
data[addr] = BSWAP_32(pwd);
|
uint32_t lockbit;
|
||||||
num_to_bytes(pwd, 4, bytes);
|
// Now read blocks 0 - 13 as we have 14 and 15
|
||||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
for (; addr < 14; addr++) {
|
||||||
|
lockbit = (lock_bits >> addr) & 1;
|
||||||
|
if (addr == 2) {
|
||||||
|
if (usePwd) {
|
||||||
|
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||||
|
data[addr] = BSWAP_32(pwd);
|
||||||
|
num_to_bytes(pwd, 4, bytes);
|
||||||
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||||
|
} else {
|
||||||
|
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
|
||||||
|
if (status != PM3_SUCCESS)
|
||||||
|
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||||
|
data[addr] = BSWAP_32(word);
|
||||||
|
if (status == PM3_SUCCESS) {
|
||||||
|
num_to_bytes(word, 4, bytes);
|
||||||
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||||
|
} else
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
|
||||||
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
|
|
||||||
if (status != PM3_SUCCESS)
|
|
||||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
|
||||||
data[addr] = BSWAP_32(word);
|
|
||||||
if (status == PM3_SUCCESS) {
|
|
||||||
num_to_bytes(word, 4, bytes);
|
|
||||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
|
||||||
} else
|
|
||||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
|
||||||
}
|
}
|
||||||
}
|
// Print blocks 14 and 15
|
||||||
// Print blocks 14 and 15
|
// Both lock bits are protected with bit idx 14 (special case)
|
||||||
// Both lock bits are protected with bit idx 14 (special case)
|
addr = 14;
|
||||||
addr = 14;
|
if (status14 == PM3_SUCCESS) {
|
||||||
if (status14 == PM3_SUCCESS) {
|
lockbit = (lock_bits >> addr) & 1;
|
||||||
lockbit = (lock_bits >> addr) & 1;
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? "" : _GREEN_("active"));
|
||||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? "" : _GREEN_("active"));
|
} else {
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||||
|
}
|
||||||
|
addr = 15;
|
||||||
|
if (status15 == PM3_SUCCESS) {
|
||||||
|
lockbit = (lock_bits >> 14) & 1; // beware lock bit of word15 is pr14
|
||||||
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||||
|
}
|
||||||
|
// Update endian for files
|
||||||
|
data[14] = BSWAP_32(data[14]);
|
||||||
|
data[15] = BSWAP_32(data[15]);
|
||||||
|
|
||||||
|
} else if (card_type == EM_4X69) {
|
||||||
|
|
||||||
|
if (usePwd) {
|
||||||
|
// Test first if a password is required
|
||||||
|
status = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, false, &word);
|
||||||
|
if (status == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||||
|
needReadPwd = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||||
|
// dont swap endin until we get block lock flags.
|
||||||
|
status14 = EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word);
|
||||||
|
if (status14 == PM3_SUCCESS) {
|
||||||
|
if (!usePwd)
|
||||||
|
needReadPwd = false;
|
||||||
|
if ((word & 0x00008000) != 0x00) {
|
||||||
|
lock_bits = word;
|
||||||
|
gotLockBits = true;
|
||||||
|
}
|
||||||
|
data[EM4469_PROT_BLOCK] = word;
|
||||||
|
} else {
|
||||||
|
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lockbit;
|
||||||
|
|
||||||
|
for (; addr < 15; addr++) {
|
||||||
|
lockbit = (lock_bits >> addr) & 1;
|
||||||
|
if (addr == 2) {
|
||||||
|
if (usePwd) {
|
||||||
|
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||||
|
data[addr] = BSWAP_32(pwd);
|
||||||
|
num_to_bytes(pwd, 4, bytes);
|
||||||
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||||
|
} else {
|
||||||
|
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info4x69[addr]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||||
|
if (status != PM3_SUCCESS) {
|
||||||
|
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||||
|
}
|
||||||
|
|
||||||
|
data[addr] = BSWAP_32(word);
|
||||||
|
if (status == PM3_SUCCESS) {
|
||||||
|
num_to_bytes(word, 4, bytes);
|
||||||
|
PrintAndLogEx(INFO, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info4x69[addr]);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info4x69[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
|
||||||
}
|
}
|
||||||
addr = 15;
|
|
||||||
if (status15 == PM3_SUCCESS) {
|
|
||||||
lockbit = (lock_bits >> 14) & 1; // beware lock bit of word15 is pr14
|
|
||||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
|
||||||
}
|
|
||||||
// Update endian for files
|
|
||||||
data[14] = BSWAP_32(data[14]);
|
|
||||||
data[15] = BSWAP_32(data[15]);
|
|
||||||
|
|
||||||
if (success == PM3_SUCCESS) { // all ok save dump to file
|
if (success == PM3_SUCCESS) { // all ok save dump to file
|
||||||
// saveFileEML will add .eml extension to filename
|
// saveFileEML will add .eml extension to filename
|
||||||
// saveFile (binary) passes in the .bin extension.
|
// saveFile (binary) passes in the .bin extension.
|
||||||
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
|
if (strcmp(filename, "") == 0) {
|
||||||
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
|
||||||
|
|
||||||
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
if ( card_type == EM_4X69) {
|
||||||
saveFile(preferredName, ".bin", data, sizeof(data));
|
sprintf(filename, "lf-4x69-%08X-dump", BSWAP_32(data[1]));
|
||||||
|
} else {
|
||||||
|
sprintf(filename, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
saveFileJSON(filename, (card_type == EM_4X69) ? jsfEM4x69 : jsfEM4x05, (uint8_t *)data, 16 * sizeof(uint32_t), NULL);
|
||||||
|
|
||||||
|
saveFileEML(filename, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
||||||
|
saveFile(filename, ".bin", data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,7 +915,7 @@ static void printEM4x05config(uint32_t wordData) {
|
||||||
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
|
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ---------------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ------------------------");
|
||||||
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
|
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
|
||||||
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
|
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
|
||||||
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
|
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
|
||||||
|
@ -810,11 +938,6 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
||||||
uint8_t cap = (block0 >> 5) & 3;
|
uint8_t cap = (block0 >> 5) & 3;
|
||||||
uint16_t custCode = (block0 >> 9) & 0x2FF;
|
uint16_t custCode = (block0 >> 9) & 0x2FF;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, " block0: %X", block0);
|
|
||||||
PrintAndLogEx(INFO, " chiptype: %X", chipType);
|
|
||||||
PrintAndLogEx(INFO, "capacitor: %X", cap);
|
|
||||||
PrintAndLogEx(INFO, " custcode: %X", custCode);
|
|
||||||
|
|
||||||
/* bits
|
/* bits
|
||||||
// 0, rfu
|
// 0, rfu
|
||||||
// 1,2,3,4 chip type
|
// 1,2,3,4 chip type
|
||||||
|
@ -834,51 +957,35 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||||
|
|
||||||
char ctstr[50];
|
PrintAndLogEx(SUCCESS, " Block0: " _GREEN_("%08x") " (Word 0)", block0);
|
||||||
snprintf(ctstr, sizeof(ctstr), " Chip Type: %u | ", chipType);
|
PrintAndLogEx(SUCCESS, " Chip Type: %3u | " _YELLOW_("%s"), chipType, em_get_card_str(block0));
|
||||||
switch (chipType) {
|
|
||||||
case 9:
|
|
||||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205");
|
|
||||||
break;
|
|
||||||
//add more here when known
|
|
||||||
default:
|
|
||||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(SUCCESS, "%s", ctstr);
|
|
||||||
|
|
||||||
switch (cap) {
|
switch (cap) {
|
||||||
case 3:
|
case 3:
|
||||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | 330pF", cap);
|
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 330pF", cap);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | %spF", cap, (chipType == 2) ? "75" : "210");
|
PrintAndLogEx(SUCCESS, " Cap Type: %3u | %spF", cap, (chipType == 4) ? "75" : "210");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | 250pF", cap);
|
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 250pF", cap);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | no resonant capacitor", cap);
|
PrintAndLogEx(SUCCESS, " Cap Type: %3u | no resonant capacitor", cap);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLogEx(SUCCESS, " Cap Type: %u | unknown", cap);
|
PrintAndLogEx(SUCCESS, " Cap Type: %3u | unknown", cap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, " Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
|
PrintAndLogEx(SUCCESS, " Cust Code: 0x%x | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
|
||||||
if (serial != 0)
|
if (serial != 0)
|
||||||
PrintAndLogEx(SUCCESS, " Serial #: " _YELLOW_("%08X"), serial);
|
PrintAndLogEx(SUCCESS, " Serial #: " _YELLOW_("%08X"), serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " ---------------------------");
|
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " --------------------------------");
|
||||||
PrintAndLogEx(INFO, "ProtectionWord: %08X (Word %i)", word, addr);
|
PrintAndLogEx(INFO, "ProtectionWord: %08X (Word %i)", word, addr);
|
||||||
for (uint8_t i = 0; i < 15; i++) {
|
for (uint8_t i = 0; i < 15; i++) {
|
||||||
PrintAndLogEx(INFO, " Word: %02u | %s", i, ((1 << i) & word) ? _RED_("write Locked") : "unlocked");
|
PrintAndLogEx(INFO, " Word: %02u | %s", i, ((1 << i) & word) ? _RED_("write Locked") : "unlocked");
|
||||||
|
@ -893,10 +1000,6 @@ bool EM4x05IsBlock0(uint32_t *word) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x05Info(const char *Cmd) {
|
int CmdEM4x05Info(const char *Cmd) {
|
||||||
#define EM_SERIAL_BLOCK 1
|
|
||||||
#define EM_CONFIG_BLOCK 4
|
|
||||||
#define EM_PROT1_BLOCK 14
|
|
||||||
#define EM_PROT2_BLOCK 15
|
|
||||||
uint32_t pwd;
|
uint32_t pwd;
|
||||||
uint32_t word = 0, block0 = 0, serial = 0;
|
uint32_t word = 0, block0 = 0, serial = 0;
|
||||||
bool usePwd = false;
|
bool usePwd = false;
|
||||||
|
@ -914,9 +1017,13 @@ int CmdEM4x05Info(const char *Cmd) {
|
||||||
if (EM4x05IsBlock0(&block0) == false)
|
if (EM4x05IsBlock0(&block0) == false)
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
||||||
|
// based on Block0 , decide type.
|
||||||
|
int card_type = em_get_card_type(block0);
|
||||||
|
|
||||||
// read word 1 (serial #) doesn't need pwd
|
// read word 1 (serial #) doesn't need pwd
|
||||||
// continue if failed, .. non blocking fail.
|
// continue if failed, .. non blocking fail.
|
||||||
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
|
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
|
||||||
|
|
||||||
printEM4x05info(block0, serial);
|
printEM4x05info(block0, serial);
|
||||||
|
|
||||||
// read word 4 (config block)
|
// read word 4 (config block)
|
||||||
|
@ -926,20 +1033,32 @@ int CmdEM4x05Info(const char *Cmd) {
|
||||||
|
|
||||||
printEM4x05config(word);
|
printEM4x05config(word);
|
||||||
|
|
||||||
// read word 14 and 15 to see which is being used for the protection bits
|
// if 4469 read EM4469_PROT_BLOCK
|
||||||
if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
// if 4305 read 14,15
|
||||||
return PM3_ESOFT;
|
if (card_type == EM_4205 || card_type == EM_4305) {
|
||||||
}
|
|
||||||
if (word & 0x8000) {
|
// read word 14 and 15 to see which is being used for the protection bits
|
||||||
printEM4x05ProtectionBits(word, EM_PROT1_BLOCK);
|
if (EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||||
return PM3_SUCCESS;
|
|
||||||
} else { // if status bit says this is not the used protection word
|
|
||||||
if (EM4x05ReadWord_ext(EM_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
if (word & 0x8000) {
|
|
||||||
printEM4x05ProtectionBits(word, EM_PROT2_BLOCK);
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (word & 0x8000) {
|
||||||
|
printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
} else { // if status bit says this is not the used protection word
|
||||||
|
if (EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||||
|
return PM3_ESOFT;
|
||||||
|
if (word & 0x8000) {
|
||||||
|
printEM4x05ProtectionBits(word, EM4305_PROT2_BLOCK);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (card_type == EM_4X69) {
|
||||||
|
// read word 3 to see which is being used for the protection bits
|
||||||
|
if (EM4x05ReadWord_ext(EM4469_PROT_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
printEM4x05ProtectionBits(word, EM4469_PROT_BLOCK);
|
||||||
}
|
}
|
||||||
//something went wrong
|
//something went wrong
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
|
|
@ -417,7 +417,7 @@ static int CmdHIDBrute(const char *Cmd) {
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
bool verbose = arg_get_lit(ctx, 1);
|
bool verbose = arg_get_lit(ctx, 1);
|
||||||
|
formatLen = sizeof(format);
|
||||||
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
|
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
|
||||||
|
|
||||||
format_idx = HIDFindCardFormat((char *) format);
|
format_idx = HIDFindCardFormat((char *) format);
|
||||||
|
|
|
@ -225,7 +225,7 @@ static int CmdKeriClone(const char *Cmd) {
|
||||||
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
|
||||||
q5 = true;
|
q5 = true;
|
||||||
}
|
}
|
||||||
|
typeLen = sizeof(keritype);
|
||||||
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
|
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
|
||||||
|
|
||||||
fc = arg_get_int_def(ctx, 3, 0);
|
fc = arg_get_int_def(ctx, 3, 0);
|
||||||
|
|
|
@ -1435,7 +1435,7 @@ static int CmdEMVScan(const char *Cmd) {
|
||||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||||
|
|
||||||
uint8_t filename[FILE_PATH_SIZE] = {0};
|
uint8_t filename[FILE_PATH_SIZE] = {0};
|
||||||
int filenamelen = 0;
|
int filenamelen = sizeof(filename);
|
||||||
CLIGetStrWithReturn(ctx, 12, filename, &filenamelen);
|
CLIGetStrWithReturn(ctx, 12, filename, &filenamelen);
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
|
@ -494,6 +494,33 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case jsfEM4x05: {
|
||||||
|
JsonSaveStr(root, "FileType", "EM4205/EM4305");
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Protection1", data + (14 * 4), 4);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Protection2", data + (15 * 4), 4);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (datalen / 4); i++) {
|
||||||
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
|
sprintf(path, "$.blocks.%zu", i);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case jsfEM4x69: {
|
||||||
|
JsonSaveStr(root, "FileType", "EM4469/EM4569");
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (1 * 4), 4);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (3 * 4), 4);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (4 * 4), 4);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (datalen / 4); i++) {
|
||||||
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
|
sprintf(path, "$.blocks.%zu", i);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case jsfMfPlusKeys: {
|
case jsfMfPlusKeys: {
|
||||||
JsonSaveStr(root, "FileType", "mfp");
|
JsonSaveStr(root, "FileType", "mfp");
|
||||||
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
|
||||||
|
|
|
@ -64,6 +64,8 @@ typedef enum {
|
||||||
jsfMfPlusKeys,
|
jsfMfPlusKeys,
|
||||||
jsfCustom,
|
jsfCustom,
|
||||||
jsfMfDesfireKeys,
|
jsfMfDesfireKeys,
|
||||||
|
jsfEM4x05,
|
||||||
|
jsfEM4x69,
|
||||||
} JSONFileType;
|
} JSONFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -60,6 +60,7 @@ extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, char
|
||||||
if (getenv("DISPLAY") == NULL)
|
if (getenv("DISPLAY") == NULL)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
unsetenv("SESSION_MANAGER");
|
||||||
main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, stayInCommandLoop);
|
main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, stayInCommandLoop);
|
||||||
gui = new ProxGuiQT(argc, argv, main_loop_thread);
|
gui = new ProxGuiQT(argc, argv, main_loop_thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,11 +203,11 @@ CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to sto
|
||||||
quick test : seems res_keylen == 0 when ok so not key len ???
|
quick test : seems res_keylen == 0 when ok so not key len ???
|
||||||
|
|
||||||
**string option return**
|
**string option return**
|
||||||
CLIGetStrWithReturn(\<context\>,\<opt index\>, \<unsigned char \*\>, \<int \*\>);
|
CLIGetStrWithReturn(\<context\>,\<opt index\>, \<uint8_t \*\>, \<int \*\>);
|
||||||
If failed to retrieve string, it will exit fct
|
If failed to retrieve string, it will exit fct
|
||||||
|
|
||||||
uint8_t buffer[100];
|
uint8_t buffer[100];
|
||||||
int slen = 0;
|
int slen = sizeof(buffer); // <- slen MUST be the maximum number of characters that you want returned. e.g. Buffer Size
|
||||||
CLIGetStrWithReturn(ctx, 1, buffer, &slen);
|
CLIGetStrWithReturn(ctx, 1, buffer, &slen);
|
||||||
|
|
||||||
**string option**
|
**string option**
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
|filename|description|
|
|filename|description|
|
||||||
|--------|-----------|
|
|--------|-----------|
|
||||||
|
|lf_sniff_blue_cloner_em4100.pm3 |Sniffing of blue cloner writing an EM4100 on T5577 and EM4305|
|
||||||
|lf_sniff_ht2-BC3B8810-acg-reader.pm3 |Sniffing of Hitag2 being read by an HID ACG LF Multitag reader|
|
|lf_sniff_ht2-BC3B8810-acg-reader.pm3 |Sniffing of Hitag2 being read by an HID ACG LF Multitag reader|
|
||||||
|lf_sniff_ht2-BC3B8810-frosch-reader.pm3 |Sniffing of Hitag2 being read by a Frosch Hitag reader|
|
|lf_sniff_ht2-BC3B8810-frosch-reader.pm3 |Sniffing of Hitag2 being read by a Frosch Hitag reader|
|
||||||
|lf_sniff_ht2-BC3B8810-rfidler-reader.pm3 |Sniffing of Hitag2 being read by a RFIDler|
|
|lf_sniff_ht2-BC3B8810-rfidler-reader.pm3 |Sniffing of Hitag2 being read by a RFIDler|
|
||||||
|
|
108120
traces/lf_sniff_blue_cloner_em4100.pm3
Normal file
108120
traces/lf_sniff_blue_cloner_em4100.pm3
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue