Merge pull request #56 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-10-17 18:38:15 +11:00 committed by GitHub
commit a21f08d07d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 108455 additions and 179 deletions

View file

@ -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 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 {
void **argtable;

View file

@ -47,9 +47,6 @@ EEEEEEEE
FFFFFFFF
a0a1a2a3
b0b1b2b3
aabbccdd
bbccddee
ccddeeff
50415353
00000001
00000002

View file

@ -209,6 +209,7 @@ static int cmd_hf_fido_register(const char *cmd) {
if (paramsPlain) {
memset(cdata, 0x00, 32);
chlen = sizeof(cdata);
CLIGetStrWithReturn(ctx, 6, cdata, &chlen);
if (chlen > 16) {
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;
}
} else {
chlen = sizeof(cdata);
CLIGetHexWithReturn(ctx, 6, cdata, &chlen);
if (chlen && chlen != 32) {
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) {
memset(adata, 0x00, 32);
applen = sizeof(adata);
CLIGetStrWithReturn(ctx, 7, adata, &applen);
if (applen > 16) {
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;
}
} else {
applen = sizeof(adata);
CLIGetHexWithReturn(ctx, 7, adata, &applen);
if (applen && applen != 32) {
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) {
memset(hdata, 0x00, 32);
hdatalen = sizeof(hdata);
CLIGetStrWithReturn(ctx, 9, hdata, &hdatalen);
if (hdatalen > 16) {
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;
}
} else {
hdatalen = sizeof(hdata);
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
if (hdatalen && hdatalen != 32) {
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) {
memset(hdata, 0x00, 32);
hdatalen = sizeof(hdata);
CLIGetStrWithReturn(ctx, 11, hdata, &hdatalen);
if (hdatalen > 16) {
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;
}
} else {
hdatalen = sizeof(hdata);
CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen);
if (hdatalen && hdatalen != 32) {
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};
char *cjsonname = (char *)jsonname;
int jsonnamelen = 0;
jsonnamelen = sizeof(jsonname);
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
if (!jsonnamelen) {
@ -817,7 +826,7 @@ static int cmd_hf_fido_2get_assertion(const char *cmd) {
uint8_t jsonname[FILE_PATH_SIZE] = {0};
char *cjsonname = (char *)jsonname;
int jsonnamelen = 0;
int jsonnamelen = sizeof(jsonname);
CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen);
if (!jsonnamelen) {

View file

@ -35,20 +35,7 @@
#include "cmdhw.h"
//////////////// 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) {
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
@ -103,6 +90,48 @@ static int usage_lf_em4x05_info(void) {
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
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;
@ -366,37 +395,52 @@ int CmdEM4x05Demod(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;
uint32_t pwd = 0;
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;
uint8_t cmdp = 0;
uint8_t bytes[4] = {0};
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 status, status14, status15;
@ -404,22 +448,33 @@ int CmdEM4x05Dump(const char *Cmd) {
bool gotLockBits = false;
bool lockInPW2 = false;
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 *info4x69 [] = {"Info", "UID", "Password", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User", "User"};
// EM4305 vs EM4469
em_tech_type_t card_type = em_get_card_type(block0);
PrintAndLogEx(INFO, "Found a " _GREEN_("%s") " tag", em_get_card_str(block0));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Addr | data | ascii |lck| info");
PrintAndLogEx(INFO, "-----+----------+-------+---+-----");
if ( card_type == EM_4205 || card_type == EM_4305 || card_type == EM_UNKNOWN) {
if (usePwd) {
// Test first if a password is required
status = EM4x05ReadWord_ext(14, pwd, false, &word);
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;
}
}
PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info");
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
// 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(14, pwd, usePwd, &word);
status14 = EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word);
if (status14 == PM3_SUCCESS) {
if (!usePwd)
needReadPwd = false;
@ -427,18 +482,18 @@ int CmdEM4x05Dump(const char *Cmd) {
lock_bits = word;
gotLockBits = true;
}
data[14] = word;
data[EM4305_PROT1_BLOCK] = word;
} else {
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
}
status15 = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
status15 = EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word);
if (status15 == PM3_SUCCESS) {
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
lock_bits = word;
gotLockBits = true;
lockInPW2 = true;
}
data[15] = word;
data[EM4305_PROT2_BLOCK] = word;
} else {
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
}
@ -451,14 +506,14 @@ int CmdEM4x05Dump(const char *Cmd) {
if ((needReadPwd) && (success != PM3_ESOFT)) {
data[addr] = BSWAP_32(pwd);
num_to_bytes(pwd, 4, bytes);
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
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(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
PrintAndLogEx(INFO, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
}
} else {
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 {
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
@ -468,9 +523,9 @@ int CmdEM4x05Dump(const char *Cmd) {
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]);
PrintAndLogEx(INFO, " %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"));
PrintAndLogEx(INFO, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
}
}
// Print blocks 14 and 15
@ -478,31 +533,104 @@ int CmdEM4x05Dump(const char *Cmd) {
addr = 14;
if (status14 == PM3_SUCCESS) {
lockbit = (lock_bits >> addr) & 1;
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"));
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(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
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(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
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(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
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 {
}
if (success == PM3_SUCCESS) { // all ok save dump to file
// saveFileEML will add .eml extension to filename
// saveFile (binary) passes in the .bin extension.
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
if (strcmp(filename, "") == 0) {
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
saveFile(preferredName, ".bin", data, sizeof(data));
if ( card_type == EM_4X69) {
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;
}
@ -787,7 +915,7 @@ static void printEM4x05config(uint32_t wordData) {
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ---------------------------");
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ------------------------");
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
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;
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
// 0, rfu
// 1,2,3,4 chip type
@ -834,51 +957,35 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
char ctstr[50];
snprintf(ctstr, sizeof(ctstr), " Chip Type: %u | ", chipType);
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);
PrintAndLogEx(SUCCESS, " Block0: " _GREEN_("%08x") " (Word 0)", block0);
PrintAndLogEx(SUCCESS, " Chip Type: %3u | " _YELLOW_("%s"), chipType, em_get_card_str(block0));
switch (cap) {
case 3:
PrintAndLogEx(SUCCESS, " Cap Type: %u | 330pF", cap);
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 330pF", cap);
break;
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;
case 1:
PrintAndLogEx(SUCCESS, " Cap Type: %u | 250pF", cap);
PrintAndLogEx(SUCCESS, " Cap Type: %3u | 250pF", cap);
break;
case 0:
PrintAndLogEx(SUCCESS, " Cap Type: %u | no resonant capacitor", cap);
PrintAndLogEx(SUCCESS, " Cap Type: %3u | no resonant capacitor", cap);
break;
default:
PrintAndLogEx(SUCCESS, " Cap Type: %u | unknown", cap);
PrintAndLogEx(SUCCESS, " Cap Type: %3u | unknown", cap);
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)
PrintAndLogEx(SUCCESS, " Serial #: " _YELLOW_("%08X"), serial);
}
static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " ---------------------------");
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " --------------------------------");
PrintAndLogEx(INFO, "ProtectionWord: %08X (Word %i)", word, addr);
for (uint8_t i = 0; i < 15; i++) {
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) {
#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 word = 0, block0 = 0, serial = 0;
bool usePwd = false;
@ -914,9 +1017,13 @@ int CmdEM4x05Info(const char *Cmd) {
if (EM4x05IsBlock0(&block0) == false)
return PM3_ESOFT;
// based on Block0 , decide type.
int card_type = em_get_card_type(block0);
// read word 1 (serial #) doesn't need pwd
// continue if failed, .. non blocking fail.
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
printEM4x05info(block0, serial);
// read word 4 (config block)
@ -926,21 +1033,33 @@ int CmdEM4x05Info(const char *Cmd) {
printEM4x05config(word);
// if 4469 read EM4469_PROT_BLOCK
// if 4305 read 14,15
if (card_type == EM_4205 || card_type == EM_4305) {
// read word 14 and 15 to see which is being used for the protection bits
if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
if (EM4x05ReadWord_ext(EM4305_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
return PM3_ESOFT;
}
if (word & 0x8000) {
printEM4x05ProtectionBits(word, EM_PROT1_BLOCK);
printEM4x05ProtectionBits(word, EM4305_PROT1_BLOCK);
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)
if (EM4x05ReadWord_ext(EM4305_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
return PM3_ESOFT;
if (word & 0x8000) {
printEM4x05ProtectionBits(word, EM_PROT2_BLOCK);
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
return PM3_ESOFT;
}

View file

@ -417,7 +417,7 @@ static int CmdHIDBrute(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool verbose = arg_get_lit(ctx, 1);
formatLen = sizeof(format);
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
format_idx = HIDFindCardFormat((char *) format);

View file

@ -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;
q5 = true;
}
typeLen = sizeof(keritype);
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
fc = arg_get_int_def(ctx, 3, 0);

View file

@ -1435,7 +1435,7 @@ static int CmdEMVScan(const char *Cmd) {
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
uint8_t filename[FILE_PATH_SIZE] = {0};
int filenamelen = 0;
int filenamelen = sizeof(filename);
CLIGetStrWithReturn(ctx, 12, filename, &filenamelen);
CLIParserFree(ctx);

View file

@ -494,6 +494,33 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
}
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: {
JsonSaveStr(root, "FileType", "mfp");
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);

View file

@ -64,6 +64,8 @@ typedef enum {
jsfMfPlusKeys,
jsfCustom,
jsfMfDesfireKeys,
jsfEM4x05,
jsfEM4x69,
} JSONFileType;
typedef enum {

View file

@ -60,6 +60,7 @@ extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, char
if (getenv("DISPLAY") == NULL)
return;
#endif
unsetenv("SESSION_MANAGER");
main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, stayInCommandLoop);
gui = new ProxGuiQT(argc, argv, main_loop_thread);
}

View file

@ -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 ???
**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
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);
**string option**

View file

@ -56,6 +56,7 @@
|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-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|

File diff suppressed because it is too large Load diff