mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
add hf felica dump
for unauth readable blocks
This commit is contained in:
parent
948dce9230
commit
ac0f747104
1 changed files with 158 additions and 2 deletions
|
@ -36,6 +36,14 @@
|
|||
#define FELICA_BLK_SIZE 16
|
||||
#define FELICA_BLK_HALF (FELICA_BLK_SIZE/2)
|
||||
|
||||
#define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_RANDOM_ACCESS (0b001000)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_CYCLIC (0b001100)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_PURSE (0b010000)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_PURSE_SUBFIELD (0b000110)
|
||||
|
||||
|
||||
#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
@ -254,6 +262,7 @@ static const char *felica_model_name(uint8_t rom_type, uint8_t ic_type) {
|
|||
return "FeliCa Standard RC-S919";
|
||||
case 0x0B:
|
||||
case 0x31:
|
||||
case 0x36:
|
||||
return "Suica card (FeliCa Standard RC-S ?)";
|
||||
default:
|
||||
break;
|
||||
|
@ -1660,6 +1669,153 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command parser for rqservice.
|
||||
* @param Cmd input data of the user.
|
||||
* @return client result code.
|
||||
*/
|
||||
static int CmdHFFelicaDump(const char *Cmd) {
|
||||
/* -- CLI boilerplate (unchanged) ------------------------------- */
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf felica dump",
|
||||
"Dump all existing Area Code and Service Code.\n"
|
||||
"Only works on services that do not require authentication yet.\n",
|
||||
"hf felica dump");
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0(NULL, "no-auth", "read public services"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// bool no_auth = arg_get_lit(ctx, 1);
|
||||
|
||||
uint8_t data_service_dump[PM3_CMD_DATA_SIZE] = {0};
|
||||
data_service_dump[0] = 0x0C;
|
||||
data_service_dump[1] = 0x0A;
|
||||
uint16_t service_datalen = 12;
|
||||
if (!check_last_idm(data_service_dump, service_datalen))
|
||||
return PM3_EINVARG;
|
||||
|
||||
uint8_t data_block_dump[PM3_CMD_DATA_SIZE] = {0};
|
||||
data_block_dump[0] = 0x10; // Static length
|
||||
data_block_dump[1] = 0x06; // unauth read block command
|
||||
data_block_dump[10] = 1; // read one service at a time
|
||||
data_block_dump[13] = 1; // read one block at a time
|
||||
data_block_dump[14] = 0x80; // block list element first byte
|
||||
uint16_t block_datalen = 16; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3)
|
||||
if (!check_last_idm(data_block_dump, block_datalen)) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t flags = FELICA_APPEND_CRC | FELICA_RAW;
|
||||
|
||||
uint16_t cursor = 0x0000;
|
||||
|
||||
felica_service_dump_response_t resp;
|
||||
|
||||
while (true) {
|
||||
|
||||
data_service_dump[10] = cursor & 0xFF;
|
||||
data_service_dump[11] = cursor >> 8;
|
||||
AddCrc(data_service_dump, service_datalen);
|
||||
|
||||
if (send_dump_sv_plain(flags, service_datalen + 2, data_service_dump, 0,
|
||||
&resp, false) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "No response at cursor 0x%04X", cursor);
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
if (resp.frame_response.cmd_code[0] != 0x0B) {
|
||||
PrintAndLogEx(FAILED, "Bad response cmd 0x%02X @ 0x%04X.",
|
||||
resp.frame_response.cmd_code[0], cursor);
|
||||
PrintAndLogEx(INFO, "This is a normal signal issue. Please try again.");
|
||||
PrintAndLogEx(INFO, "If the issue persists, move the card around and check signal strength. FeliCa can be hard to keep in field.");
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
uint8_t len = resp.frame_response.length[0];
|
||||
uint16_t node_code = resp.payload[0] | (resp.payload[1] << 8);
|
||||
if (node_code == 0xFFFF) break;
|
||||
char attrib_str[64] = "";
|
||||
switch (len) {
|
||||
case 0x0E:
|
||||
break;
|
||||
case 0x0C: {
|
||||
uint8_t attribute = node_code & 0x3F;
|
||||
bool is_public = (attribute & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) != 0;
|
||||
strcat(attrib_str, is_public ? "| Public " : "| Private ");
|
||||
|
||||
bool is_purse = (attribute & FELICA_SERVICE_ATTRIBUTE_PURSE) != 0;
|
||||
// Subfield bitwise attributes are applicable depending on is PURSE or not
|
||||
|
||||
if(is_purse) {
|
||||
strcat(attrib_str, "| Purse |");
|
||||
switch((attribute & FELICA_SERVICE_ATTRIBUTE_PURSE_SUBFIELD) >> 1) {
|
||||
case 0:
|
||||
strcat(attrib_str, " Direct |");
|
||||
break;
|
||||
case 1:
|
||||
strcat(attrib_str, " Cashback |");
|
||||
break;
|
||||
case 2:
|
||||
strcat(attrib_str, " Decrement |");
|
||||
break;
|
||||
case 3:
|
||||
strcat(attrib_str, " Read Only |");
|
||||
break;
|
||||
default:
|
||||
strcat(attrib_str, " Unknown |");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bool is_random = (attribute & FELICA_SERVICE_ATTRIBUTE_RANDOM_ACCESS) != 0;
|
||||
strcat(attrib_str, is_random ? "| Random |" : "| Cyclic |");
|
||||
bool is_readonly = (attribute & FELICA_SERVICE_ATTRIBUTE_READ_ONLY) != 0;
|
||||
strcat(attrib_str, is_readonly ? " Read Only |" : " Read/Write |");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Service %04X %s", node_code, attrib_str);
|
||||
|
||||
if (is_public) {
|
||||
// dump blocks here
|
||||
PrintAndLogEx(INFO, " block | data ");
|
||||
PrintAndLogEx(INFO, "-------+----------------------------------------");
|
||||
|
||||
data_block_dump[11] = resp.payload[0]; // convert service code to little endian
|
||||
data_block_dump[12] = resp.payload[1];
|
||||
|
||||
uint16_t last_blockno = 0xFF;
|
||||
for (uint16_t i = 0x00; i < last_blockno; i++) {
|
||||
data_block_dump[15] = i;
|
||||
AddCrc(data_block_dump, block_datalen);
|
||||
felica_read_without_encryption_response_t rd_noCry_resp;
|
||||
if ((send_rd_plain(flags, block_datalen + 2, data_block_dump, 0, &rd_noCry_resp) == PM3_SUCCESS)) {
|
||||
if (rd_noCry_resp.status_flags.status_flag1[0] == 0 && rd_noCry_resp.status_flags.status_flag2[0] == 0) {
|
||||
print_rd_plain_response(&rd_noCry_resp);
|
||||
} else {
|
||||
break; // no more blocks to read
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PrintAndLogEx(FAILED, "Unexpected length 0x%02X @ 0x%04X",
|
||||
len, cursor);
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
cursor++;
|
||||
if (cursor == 0) break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Unauth service dump complete.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Command parser for rqservice.
|
||||
* @param Cmd input data of the user.
|
||||
|
@ -2761,7 +2917,7 @@ static command_t CommandTable[] = {
|
|||
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"},
|
||||
{"wrbl", CmdHFFelicaWritePlain, IfPm3Felica, "write block data to an authentication-not-required Service."},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("FeliCa Standard") " -----------------------"},
|
||||
//{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
|
||||
{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
|
||||
{"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."},
|
||||
{"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."},
|
||||
{"scsvcode", CmdHFFelicaDumpServiceArea, IfPm3Felica, "acquire Area Code and Service Code."},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue