mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-08-28 00:54:25 +00:00
Merge pull request #3375 from kormax/felica-dump-improvements
FeliCa dump improvements
This commit is contained in:
+256
-41
@@ -55,7 +55,9 @@
|
||||
#define FELICA_PLATFORM_INFO_WITH_MAC_INFO_LEN 25U
|
||||
#define FELICA_PLATFORM_INFO_WITH_MAC_LEN 20U
|
||||
#define FELICA_PLATFORM_INFO_WITH_MAC_TOTAL_LEN (FELICA_PLATFORM_INFO_WITH_MAC_INFO_LEN + FELICA_PLATFORM_INFO_WITH_MAC_LEN)
|
||||
#define FELICA_CONTAINER_ISSUE_INFO_LEN 16U
|
||||
#define FELICA_CONTAINER_PROPERTY_MAX_LEN 64U
|
||||
#define FELICA_SPECIFICATION_VERSION_MAX_LEN (4U + (FELICA_SPECIFICATION_VERSION_MAX_OPTIONS * 2U))
|
||||
#define FELICA_OPTIONAL_CMD_TIMEOUT_MS 250U
|
||||
#define FELICA_OPTIONAL_CMD_RETRIES 3U
|
||||
// Per FeliCa spec, Polling max response at 16 timeslots is ~25ms; keep extra margin.
|
||||
@@ -67,6 +69,7 @@
|
||||
#define FELICA_SYSTEM_CODE_MAX_COUNT 16U
|
||||
#define FELICA_DISCOVERED_SYSTEM_MAX_COUNT FELICA_SYSTEM_CODE_MAX_COUNT
|
||||
#define FELICA_SYSTEM_CODE_WILDCARD 0xFFFFU
|
||||
#define FELICA_SYSTEM_NODE 0xFFFFU
|
||||
#define FELICA_SYSTEM_CODE_NFC_TYPE3 0x12FCU
|
||||
#define FELICA_SYSTEM_CODE_FELICA_LITE 0x88B4U
|
||||
#define FELICA_SYSTEM_CODE_FELICA_SECURE_ID 0x957AU
|
||||
@@ -85,6 +88,7 @@
|
||||
#define FELICA_SERVICE_ATTRIBUTE_PURSE (0b010000)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_PIN_REQUIRED (0b100000)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_PURSE_SUBFIELD (0b000110)
|
||||
#define FELICA_NODE_ATTRIBUTE_MASK 0x3FU
|
||||
|
||||
#define FELICA_AREA_ATTRIBUTE_CAN_CREATE_SUBAREA 0x00U
|
||||
#define FELICA_AREA_ATTRIBUTE_CANNOT_CREATE_SUBAREA 0x01U
|
||||
@@ -255,8 +259,14 @@ typedef enum {
|
||||
FELICA_NODE_DISCOVERY_READ_WITHOUT_ENCRYPTION,
|
||||
} felica_node_discovery_method_t;
|
||||
|
||||
typedef enum {
|
||||
FELICA_NODE_TYPE_AREA = 0,
|
||||
FELICA_NODE_TYPE_SERVICE,
|
||||
FELICA_NODE_TYPE_SYSTEM,
|
||||
} felica_node_type_t;
|
||||
|
||||
typedef struct {
|
||||
bool is_area;
|
||||
felica_node_type_t type;
|
||||
uint16_t node_code_le;
|
||||
bool has_end_code;
|
||||
uint16_t end_code_le;
|
||||
@@ -278,7 +288,7 @@ typedef struct {
|
||||
} felica_dump_encryption_identifier_t;
|
||||
|
||||
typedef struct {
|
||||
bool is_area;
|
||||
felica_node_type_t type;
|
||||
uint16_t node_code_le;
|
||||
bool has_end_code;
|
||||
uint16_t end_code_le;
|
||||
@@ -299,6 +309,43 @@ typedef struct {
|
||||
size_t node_capacity;
|
||||
} felica_dump_system_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_specification_version;
|
||||
uint8_t specification_version[FELICA_SPECIFICATION_VERSION_MAX_LEN];
|
||||
size_t specification_version_len;
|
||||
bool has_product_information;
|
||||
uint8_t product_information[FELICA_PLATFORM_INFO_MAX_LEN];
|
||||
size_t product_information_len;
|
||||
bool has_container_issue_information;
|
||||
uint8_t container_issue_information[FELICA_CONTAINER_ISSUE_INFO_LEN];
|
||||
} felica_dump_metadata_t;
|
||||
|
||||
static uint8_t felica_node_attribute(uint16_t node_code_le) {
|
||||
return node_code_le & FELICA_NODE_ATTRIBUTE_MASK;
|
||||
}
|
||||
|
||||
static bool felica_is_area_start_attribute(uint8_t attribute) {
|
||||
switch (attribute) {
|
||||
case FELICA_AREA_ATTRIBUTE_CAN_CREATE_SUBAREA:
|
||||
case FELICA_AREA_ATTRIBUTE_CANNOT_CREATE_SUBAREA:
|
||||
case FELICA_AREA_ATTRIBUTE_CAN_CREATE_SUBAREA_WITH_PIN:
|
||||
case FELICA_AREA_ATTRIBUTE_CANNOT_CREATE_SUBAREA_WITH_PIN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static felica_node_type_t felica_node_type_from_code(uint16_t node_code_le) {
|
||||
if (node_code_le == FELICA_SYSTEM_NODE) {
|
||||
return FELICA_NODE_TYPE_SYSTEM;
|
||||
}
|
||||
if (felica_is_area_start_attribute(felica_node_attribute(node_code_le))) {
|
||||
return FELICA_NODE_TYPE_AREA;
|
||||
}
|
||||
return FELICA_NODE_TYPE_SERVICE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t encryption_identifier;
|
||||
bool has_aes_key_versions;
|
||||
@@ -3182,12 +3229,14 @@ static bool felica_discover_nodes_with_request_code_list(uint8_t *flags,
|
||||
|
||||
for (uint8_t i = 0; i < area_count; i++) {
|
||||
felica_discovered_node_t node = {0};
|
||||
node.is_area = true;
|
||||
node.node_code_le = (uint16_t)resp.data.asBytes[offset] |
|
||||
((uint16_t)resp.data.asBytes[offset + 1] << 8);
|
||||
node.has_end_code = true;
|
||||
node.end_code_le = (uint16_t)resp.data.asBytes[offset + 2] |
|
||||
((uint16_t)resp.data.asBytes[offset + 3] << 8);
|
||||
node.type = felica_node_type_from_code(node.node_code_le);
|
||||
node.has_end_code = (node.type == FELICA_NODE_TYPE_AREA);
|
||||
node.end_code_le = node.has_end_code
|
||||
? ((uint16_t)resp.data.asBytes[offset + 2] |
|
||||
((uint16_t)resp.data.asBytes[offset + 3] << 8))
|
||||
: 0;
|
||||
offset += 4;
|
||||
if (batch_count < ARRAYLEN(batch_nodes)) {
|
||||
batch_nodes[batch_count++] = node;
|
||||
@@ -3203,9 +3252,9 @@ static bool felica_discover_nodes_with_request_code_list(uint8_t *flags,
|
||||
|
||||
for (uint8_t i = 0; i < service_count; i++) {
|
||||
felica_discovered_node_t node = {0};
|
||||
node.is_area = false;
|
||||
node.node_code_le = (uint16_t)resp.data.asBytes[offset] |
|
||||
((uint16_t)resp.data.asBytes[offset + 1] << 8);
|
||||
node.type = felica_node_type_from_code(node.node_code_le);
|
||||
node.has_end_code = false;
|
||||
node.end_code_le = 0;
|
||||
offset += 2;
|
||||
@@ -3227,6 +3276,23 @@ static bool felica_discover_nodes_with_request_code_list(uint8_t *flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
felica_discovered_node_t node = {0};
|
||||
node.type = FELICA_NODE_TYPE_SYSTEM;
|
||||
node.node_code_le = FELICA_SYSTEM_NODE;
|
||||
node.has_end_code = false;
|
||||
node.end_code_le = 0;
|
||||
/*
|
||||
* RequestCodeList does not report the system node explicitly, but any
|
||||
* target supporting node-list discovery has a system node. Treat it as
|
||||
* implicit and emit it last, matching SearchServiceCode ordering.
|
||||
*/
|
||||
if (felica_emit_discovered_node(&node, visitor, ctx, &local_count, stop_status) != PM3_SUCCESS) {
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
|
||||
return supported;
|
||||
@@ -3280,20 +3346,20 @@ static bool felica_discover_nodes_with_search_service_code(uint8_t *flags,
|
||||
}
|
||||
|
||||
const uint16_t node_code_le = (uint16_t)resp.payload[0] | ((uint16_t)resp.payload[1] << 8);
|
||||
if (node_code_le == 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
felica_discovered_node_t node = {0};
|
||||
node.is_area = (frame_len == 0x0E);
|
||||
node.node_code_le = node_code_le;
|
||||
node.has_end_code = (frame_len == 0x0E);
|
||||
node.type = felica_node_type_from_code(node_code_le);
|
||||
node.has_end_code = (node.type == FELICA_NODE_TYPE_AREA && frame_len == 0x0E);
|
||||
node.end_code_le = node.has_end_code ? ((uint16_t)resp.payload[2] | ((uint16_t)resp.payload[3] << 8)) : 0;
|
||||
|
||||
if (felica_emit_discovered_node(&node, visitor, ctx, &local_count, stop_status) != PM3_SUCCESS) {
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node.type == FELICA_NODE_TYPE_SYSTEM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
@@ -3305,7 +3371,7 @@ static bool felica_request_service_send_probe_batch(uint8_t *flags,
|
||||
const uint8_t *idm,
|
||||
uint32_t retry_count,
|
||||
const uint16_t *node_codes_le,
|
||||
const bool *is_area_nodes,
|
||||
const felica_node_type_t *node_types,
|
||||
size_t node_count,
|
||||
felica_node_discovery_visitor_t visitor,
|
||||
void *ctx,
|
||||
@@ -3358,12 +3424,12 @@ static bool felica_request_service_send_probe_batch(uint8_t *flags,
|
||||
for (size_t i = 0; i < returned_nodes; i++) {
|
||||
const uint16_t key_version = (uint16_t)resp.data.asBytes[offset + i * 2] |
|
||||
((uint16_t)resp.data.asBytes[offset + i * 2 + 1] << 8);
|
||||
if (key_version == 0xFFFF) {
|
||||
if (key_version == 0xFFFF && node_types[i] != FELICA_NODE_TYPE_SYSTEM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
felica_discovered_node_t node = {0};
|
||||
node.is_area = is_area_nodes[i];
|
||||
node.type = node_types[i];
|
||||
node.node_code_le = node_codes_le[i];
|
||||
node.has_end_code = false;
|
||||
node.end_code_le = 0;
|
||||
@@ -3387,7 +3453,7 @@ static bool felica_discover_nodes_with_request_service(uint8_t *flags,
|
||||
uint32_t local_count = 0;
|
||||
|
||||
uint16_t batch_codes[FELICA_REQUEST_SERVICE_DISCOVERY_BATCH_SIZE] = {0};
|
||||
bool batch_is_area[FELICA_REQUEST_SERVICE_DISCOVERY_BATCH_SIZE] = {0};
|
||||
felica_node_type_t batch_types[FELICA_REQUEST_SERVICE_DISCOVERY_BATCH_SIZE] = {0};
|
||||
size_t batch_count = 0;
|
||||
|
||||
for (uint16_t number = 0; number <= FELICA_MAX_NODE_NUMBER; number++) {
|
||||
@@ -3405,14 +3471,17 @@ static bool felica_discover_nodes_with_request_service(uint8_t *flags,
|
||||
}
|
||||
|
||||
const uint16_t node_code_le = (uint16_t)((number << 6) | probe_attr.attribute);
|
||||
if (node_code_le == FELICA_SYSTEM_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
batch_codes[batch_count] = node_code_le;
|
||||
batch_is_area[batch_count] = probe_attr.is_area;
|
||||
batch_types[batch_count] = felica_node_type_from_code(node_code_le);
|
||||
batch_count++;
|
||||
|
||||
if (batch_count == FELICA_REQUEST_SERVICE_DISCOVERY_BATCH_SIZE) {
|
||||
if (felica_request_service_send_probe_batch(flags, idm, retry_count,
|
||||
batch_codes, batch_is_area, batch_count,
|
||||
batch_codes, batch_types, batch_count,
|
||||
visitor, ctx, &supported, &local_count, stop_status) == false) {
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
if (stop_status && *stop_status == PM3_EOPABORTED) {
|
||||
@@ -3428,9 +3497,13 @@ static bool felica_discover_nodes_with_request_service(uint8_t *flags,
|
||||
}
|
||||
}
|
||||
|
||||
batch_codes[batch_count] = FELICA_SYSTEM_NODE;
|
||||
batch_types[batch_count] = FELICA_NODE_TYPE_SYSTEM;
|
||||
batch_count++;
|
||||
|
||||
if (batch_count > 0) {
|
||||
if (felica_request_service_send_probe_batch(flags, idm, retry_count,
|
||||
batch_codes, batch_is_area, batch_count,
|
||||
batch_codes, batch_types, batch_count,
|
||||
visitor, ctx, &supported, &local_count, stop_status) == false) {
|
||||
felica_set_discovered_count(discovered_count, local_count);
|
||||
if (stop_status && *stop_status == PM3_EOPABORTED) {
|
||||
@@ -3517,7 +3590,7 @@ static bool felica_discover_nodes_with_read_without_encryption_ex(uint8_t *flags
|
||||
}
|
||||
|
||||
felica_discovered_node_t node = {0};
|
||||
node.is_area = false;
|
||||
node.type = FELICA_NODE_TYPE_SERVICE;
|
||||
node.node_code_le = service_code_le;
|
||||
node.has_end_code = false;
|
||||
node.end_code_le = 0;
|
||||
@@ -3699,8 +3772,8 @@ static int felica_compare_discovered_nodes(const void *lhs, const void *rhs) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a->is_area != b->is_area) {
|
||||
return a->is_area ? -1 : 1;
|
||||
if (a->type != b->type) {
|
||||
return a->type < b->type ? -1 : 1;
|
||||
}
|
||||
|
||||
if (a->has_end_code != b->has_end_code) {
|
||||
@@ -3742,7 +3815,9 @@ static int felica_scsvcode_discovery_visitor(const felica_discovered_node_t *nod
|
||||
const uint16_t node_code_be = felica_to_network_order(node->node_code_le);
|
||||
const uint16_t node_number = node->node_code_le >> 6;
|
||||
|
||||
if (node->is_area) {
|
||||
if (node->type == FELICA_NODE_TYPE_SYSTEM) {
|
||||
PrintAndLogEx(INFO, "%sSYSTEM_%04X", prefix, node_code_be);
|
||||
} else if (node->type == FELICA_NODE_TYPE_AREA) {
|
||||
scsv_ctx->area_count++;
|
||||
if (node->has_end_code) {
|
||||
const uint16_t end_code_be = felica_to_network_order(node->end_code_le);
|
||||
@@ -3816,7 +3891,7 @@ static felica_dump_node_t *felica_dump_system_add_node(felica_dump_system_t *sys
|
||||
|
||||
for (size_t i = 0; i < system->node_count; i++) {
|
||||
felica_dump_node_t *dump_node = &system->nodes[i];
|
||||
if (dump_node->is_area == node->is_area &&
|
||||
if (dump_node->type == node->type &&
|
||||
dump_node->node_code_le == node->node_code_le &&
|
||||
dump_node->has_end_code == node->has_end_code &&
|
||||
dump_node->end_code_le == node->end_code_le) {
|
||||
@@ -3842,11 +3917,10 @@ static felica_dump_node_t *felica_dump_system_add_node(felica_dump_system_t *sys
|
||||
|
||||
felica_dump_node_t *dump_node = &system->nodes[system->node_count++];
|
||||
memset(dump_node, 0, sizeof(*dump_node));
|
||||
dump_node->is_area = node->is_area;
|
||||
dump_node->type = node->type;
|
||||
dump_node->node_code_le = node->node_code_le;
|
||||
dump_node->has_end_code = node->has_end_code;
|
||||
dump_node->end_code_le = node->end_code_le;
|
||||
|
||||
return dump_node;
|
||||
}
|
||||
|
||||
@@ -3972,6 +4046,18 @@ static int felica_dump_json_set_new(json_t *object, const char *key, json_t *val
|
||||
return (ret == 0) ? PM3_SUCCESS : PM3_EMALLOC;
|
||||
}
|
||||
|
||||
static int felica_dump_json_set_hex_or_null(json_t *object, const char *key,
|
||||
const uint8_t *data, size_t data_len, bool has_value) {
|
||||
if (has_value == false) {
|
||||
return felica_dump_json_set_new(object, key, json_null());
|
||||
}
|
||||
if (data == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
return felica_dump_json_set_new(object, key, json_string(sprint_hex_inrow(data, data_len)));
|
||||
}
|
||||
|
||||
static json_t *felica_dump_node_json(const felica_dump_node_t *node) {
|
||||
if (node == NULL) {
|
||||
return NULL;
|
||||
@@ -3987,14 +4073,21 @@ static json_t *felica_dump_node_json(const felica_dump_node_t *node) {
|
||||
|
||||
char node_code_hex[9] = {0};
|
||||
const uint16_t node_code_be = felica_to_network_order(node->node_code_le);
|
||||
if (node->is_area && node->has_end_code) {
|
||||
if (node->type == FELICA_NODE_TYPE_AREA && node->has_end_code) {
|
||||
const uint16_t end_code_be = felica_to_network_order(node->end_code_le);
|
||||
snprintf(node_code_hex, sizeof(node_code_hex), "%04X%04X", node_code_be, end_code_be);
|
||||
} else {
|
||||
snprintf(node_code_hex, sizeof(node_code_hex), "%04X", node_code_be);
|
||||
}
|
||||
|
||||
if (felica_dump_json_set_new(node_json, "type", json_string(node->is_area ? "area" : "service")) != PM3_SUCCESS ||
|
||||
const char *node_type = "service";
|
||||
if (node->type == FELICA_NODE_TYPE_SYSTEM) {
|
||||
node_type = "system";
|
||||
} else if (node->type == FELICA_NODE_TYPE_AREA) {
|
||||
node_type = "area";
|
||||
}
|
||||
|
||||
if (felica_dump_json_set_new(node_json, "type", json_string(node_type)) != PM3_SUCCESS ||
|
||||
felica_dump_json_set_new(node_json, "code", json_string(node_code_hex)) != PM3_SUCCESS ||
|
||||
felica_dump_json_set_new(node_json, "des_key_version", node->des_key_version.has_value ? felica_dump_key_version_json(node->des_key_version.value_le) : json_null()) != PM3_SUCCESS ||
|
||||
felica_dump_json_set_new(node_json, "aes_key_version", node->aes_key_version.has_value ? felica_dump_key_version_json(node->aes_key_version.value_le) : json_null()) != PM3_SUCCESS) {
|
||||
@@ -4062,7 +4155,14 @@ static json_t *felica_dump_system_json(const felica_dump_system_t *system) {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < system->node_count; i++) {
|
||||
json_t *node_json = felica_dump_node_json(&system->nodes[i]);
|
||||
const felica_dump_node_t *node = &system->nodes[i];
|
||||
if (node->type == FELICA_NODE_TYPE_SYSTEM &&
|
||||
node->des_key_version.has_value == false &&
|
||||
node->aes_key_version.has_value == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
json_t *node_json = felica_dump_node_json(node);
|
||||
if (node_json == NULL) {
|
||||
json_decref(nodes_json);
|
||||
json_decref(system_json);
|
||||
@@ -4087,7 +4187,8 @@ static json_t *felica_dump_system_json(const felica_dump_system_t *system) {
|
||||
return system_json;
|
||||
}
|
||||
|
||||
static json_t *felica_dump_systems_json(const felica_dump_system_t *systems, size_t system_count) {
|
||||
static json_t *felica_dump_systems_json(const felica_dump_system_t *systems, size_t system_count,
|
||||
const felica_dump_metadata_t *metadata) {
|
||||
if (systems == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -4100,6 +4201,23 @@ static json_t *felica_dump_systems_json(const felica_dump_system_t *systems, siz
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (felica_dump_json_set_hex_or_null(root, "specification_version",
|
||||
metadata ? metadata->specification_version : NULL,
|
||||
metadata ? metadata->specification_version_len : 0,
|
||||
metadata && metadata->has_specification_version) != PM3_SUCCESS ||
|
||||
felica_dump_json_set_hex_or_null(root, "product_information",
|
||||
metadata ? metadata->product_information : NULL,
|
||||
metadata ? metadata->product_information_len : 0,
|
||||
metadata && metadata->has_product_information) != PM3_SUCCESS ||
|
||||
felica_dump_json_set_hex_or_null(root, "container_issue_information",
|
||||
metadata ? metadata->container_issue_information : NULL,
|
||||
metadata ? sizeof(metadata->container_issue_information) : 0,
|
||||
metadata && metadata->has_container_issue_information) != PM3_SUCCESS) {
|
||||
json_decref(systems_json);
|
||||
json_decref(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < system_count; i++) {
|
||||
json_t *system_json = felica_dump_system_json(&systems[i]);
|
||||
if (system_json == NULL) {
|
||||
@@ -4126,6 +4244,94 @@ static json_t *felica_dump_systems_json(const felica_dump_system_t *systems, siz
|
||||
return root;
|
||||
}
|
||||
|
||||
static bool felica_dump_specification_version_to_bytes(const felica_request_specification_version_info_t *info,
|
||||
uint8_t *data, size_t data_capacity, size_t *data_len) {
|
||||
if (info == NULL || data == NULL || data_len == NULL || info->has_specification_version == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*data_len = 0;
|
||||
if (info->option_version_count < info->number_of_option) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t option_bytes = (size_t)info->number_of_option * 2U;
|
||||
const size_t payload_len = 4U + option_bytes;
|
||||
if (payload_len > data_capacity || option_bytes > sizeof(info->option_version_list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data[0] = info->format_version;
|
||||
memcpy(data + 1, info->basic_version, sizeof(info->basic_version));
|
||||
data[3] = info->number_of_option;
|
||||
memcpy(data + 4, info->option_version_list, option_bytes);
|
||||
*data_len = payload_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void felica_dump_collect_metadata(const uint8_t *idm, felica_dump_metadata_t *metadata) {
|
||||
if (idm == NULL || metadata == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(metadata, 0, sizeof(*metadata));
|
||||
const uint8_t optional_flags = FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW;
|
||||
|
||||
felica_request_specification_version_request_t spec_request;
|
||||
memset(&spec_request, 0, sizeof(spec_request));
|
||||
spec_request.length[0] = sizeof(spec_request);
|
||||
spec_request.command_code[0] = FELICA_REQUEST_SPEC_VERSION_REQ;
|
||||
memcpy(spec_request.IDm, idm, sizeof(spec_request.IDm));
|
||||
|
||||
felica_request_specification_version_info_t spec_info;
|
||||
if (send_request_specification_version(optional_flags, sizeof(spec_request),
|
||||
(uint8_t *)&spec_request, false, false,
|
||||
FELICA_OPTIONAL_CMD_TIMEOUT_MS, FELICA_OPTIONAL_CMD_RETRIES,
|
||||
&spec_info) == PM3_SUCCESS &&
|
||||
felica_dump_specification_version_to_bytes(&spec_info,
|
||||
metadata->specification_version,
|
||||
sizeof(metadata->specification_version),
|
||||
&metadata->specification_version_len)) {
|
||||
metadata->has_specification_version = true;
|
||||
}
|
||||
|
||||
felica_get_platform_info_request_t product_request;
|
||||
memset(&product_request, 0, sizeof(product_request));
|
||||
product_request.length[0] = sizeof(product_request);
|
||||
product_request.command_code[0] = FELICA_GETPLATFORMINFO_REQ;
|
||||
memcpy(product_request.IDm, idm, sizeof(product_request.IDm));
|
||||
|
||||
felica_status_flags_t product_status_flags;
|
||||
if (send_get_platform_information(optional_flags,
|
||||
sizeof(product_request), (uint8_t *)&product_request,
|
||||
false, &product_status_flags,
|
||||
metadata->product_information,
|
||||
sizeof(metadata->product_information),
|
||||
&metadata->product_information_len) == PM3_SUCCESS &&
|
||||
metadata->product_information_len > 0) {
|
||||
metadata->has_product_information = true;
|
||||
}
|
||||
|
||||
felica_get_container_issue_info_request_t container_issue_request;
|
||||
memset(&container_issue_request, 0, sizeof(container_issue_request));
|
||||
container_issue_request.length[0] = sizeof(container_issue_request);
|
||||
container_issue_request.command_code[0] = FELICA_GET_CONTAINER_ISSUE_INFO_REQ;
|
||||
memcpy(container_issue_request.IDm, idm, sizeof(container_issue_request.IDm));
|
||||
|
||||
felica_get_container_issue_info_response_t container_issue_response;
|
||||
if (send_get_container_issue_information(optional_flags,
|
||||
sizeof(container_issue_request), (uint8_t *)&container_issue_request,
|
||||
false, &container_issue_response) == PM3_SUCCESS) {
|
||||
memcpy(metadata->container_issue_information,
|
||||
container_issue_response.format_version_carrier_information,
|
||||
sizeof(container_issue_response.format_version_carrier_information));
|
||||
memcpy(metadata->container_issue_information + sizeof(container_issue_response.format_version_carrier_information),
|
||||
container_issue_response.mobile_phone_model_information,
|
||||
sizeof(container_issue_response.mobile_phone_model_information));
|
||||
metadata->has_container_issue_information = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int felica_dump_collect_key_versions_v2(felica_dump_system_t *system, uint8_t flags, uint32_t retry_count) {
|
||||
if (system == NULL) {
|
||||
return PM3_EINVARG;
|
||||
@@ -4262,7 +4468,7 @@ static int felica_dump_discovery_visitor(const felica_discovered_node_t *node, v
|
||||
}
|
||||
}
|
||||
|
||||
if (node->is_area) {
|
||||
if (node->type != FELICA_NODE_TYPE_SERVICE) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -4378,26 +4584,32 @@ static int felica_dump_single_system(const felica_discovered_system_t *system,
|
||||
dump_ctx.block_frame[14] = 0x80;
|
||||
|
||||
uint32_t discovered_nodes = 0;
|
||||
const int ret = felica_discover_nodes(idm, pmm, &flags, retry_count,
|
||||
FELICA_NODE_DISCOVERY_NONE,
|
||||
felica_dump_discovery_visitor, &dump_ctx,
|
||||
NULL, &discovered_nodes);
|
||||
|
||||
*discovered_nodes_out = discovered_nodes;
|
||||
*service_count_out = dump_ctx.service_count;
|
||||
*public_service_count_out = dump_ctx.public_service_count;
|
||||
int ret = felica_discover_nodes(idm, pmm, &flags, retry_count,
|
||||
FELICA_NODE_DISCOVERY_NONE,
|
||||
felica_dump_discovery_visitor, &dump_ctx,
|
||||
NULL, &discovered_nodes);
|
||||
|
||||
if (ret == PM3_EOPABORTED) {
|
||||
*discovered_nodes_out = discovered_nodes;
|
||||
*service_count_out = dump_ctx.service_count;
|
||||
*public_service_count_out = dump_ctx.public_service_count;
|
||||
PrintAndLogEx(WARNING, "Unauth service dump aborted by user. Discovered %" PRIu32 " node(s), visited %" PRIu32 " service(s), dumped %" PRIu32 " public service(s).",
|
||||
discovered_nodes, dump_ctx.service_count, dump_ctx.public_service_count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != PM3_SUCCESS) {
|
||||
*discovered_nodes_out = discovered_nodes;
|
||||
*service_count_out = dump_ctx.service_count;
|
||||
*public_service_count_out = dump_ctx.public_service_count;
|
||||
PrintAndLogEx(FAILED, "Unable to discover nodes using RequestCodeList/SearchServiceCode/RequestService/ReadWithoutEncryption.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*discovered_nodes_out = discovered_nodes;
|
||||
*service_count_out = dump_ctx.service_count;
|
||||
*public_service_count_out = dump_ctx.public_service_count;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "System dump complete. Discovered %" PRIu32 " node(s), visited %" PRIu32 " service(s), dumped %" PRIu32 " public service(s).",
|
||||
discovered_nodes, dump_ctx.service_count, dump_ctx.public_service_count);
|
||||
|
||||
@@ -5460,6 +5672,9 @@ static int CmdHFFelicaDump(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to abort discovery or dumping");
|
||||
|
||||
felica_dump_metadata_t dump_metadata;
|
||||
felica_dump_collect_metadata(idm, &dump_metadata);
|
||||
|
||||
uint8_t system_flags = FELICA_NO_DISCONNECT | FELICA_APPEND_CRC | FELICA_RAW;
|
||||
felica_discovered_system_list_t discovered_systems;
|
||||
res = discover_systems(system_flags, idm, true, retry_count, &discovered_systems);
|
||||
@@ -5520,7 +5735,7 @@ static int CmdHFFelicaDump(const char *Cmd) {
|
||||
snprintf(filename, sizeof(filename), "hf-felica-%s-dump", sprint_hex_inrow(idm, sizeof(idm)));
|
||||
}
|
||||
|
||||
json_t *root = felica_dump_systems_json(dump_systems, dump_system_count);
|
||||
json_t *root = felica_dump_systems_json(dump_systems, dump_system_count, &dump_metadata);
|
||||
if (root == NULL) {
|
||||
felica_dump_systems_free(dump_systems, dump_system_count);
|
||||
return PM3_EMALLOC;
|
||||
|
||||
Reference in New Issue
Block a user