mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Merge pull request #465 from merlokk/hf_info_aid_search
Hf info aid search
This commit is contained in:
commit
7b650e98a0
9 changed files with 2449 additions and 17 deletions
|
@ -186,6 +186,7 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
cmdanalyse.c \
|
||||
cmdhf.c \
|
||||
cmdhflist.c \
|
||||
aidsearch.c \
|
||||
cmdhf14a.c \
|
||||
cmdhf14b.c \
|
||||
cmdhf15.c \
|
||||
|
|
180
client/aidsearch.c
Normal file
180
client/aidsearch.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2019 merlokk
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Proxmark3 RDV40 AID list library
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "aidsearch.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fileutils.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
|
||||
int openAIDFile(json_t **root, bool verbose) {
|
||||
json_error_t error;
|
||||
|
||||
char *path;
|
||||
int res = searchFile(&path, RESOURCES_SUBDIR, "aidlist", ".json", false);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
*root = json_load_file(path, 0, &error);
|
||||
if (!*root) {
|
||||
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_is_array(*root)) {
|
||||
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
|
||||
retval = PM3_ESOFT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %d records.", path, json_array_size(*root));
|
||||
out:
|
||||
free(path);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int closeAIDFile(json_t *root) {
|
||||
|
||||
json_decref(root);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
json_t *AIDSearchInit(bool verbose) {
|
||||
json_t *root = NULL;
|
||||
int res = openAIDFile(&root, verbose);
|
||||
if (res != PM3_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
json_t *AIDSearchGetElm(json_t *root, int elmindx) {
|
||||
json_t *data = json_array_get(root, elmindx);
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLogEx(ERR, "data [%d] is not an object\n", elmindx);
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int AIDSearchFree(json_t *root) {
|
||||
|
||||
return closeAIDFile(root);
|
||||
}
|
||||
|
||||
const char * jsonStrGet(json_t *data, char *name) {
|
||||
json_t *jstr;
|
||||
|
||||
jstr = json_object_get(data, name);
|
||||
if (jstr == NULL)
|
||||
return NULL;
|
||||
if (!json_is_string(jstr)) {
|
||||
PrintAndLogEx(ERR, "`%s` is not a string", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *cstr = json_string_value(jstr);
|
||||
if (strlen(cstr) == 0)
|
||||
return NULL;
|
||||
return cstr;
|
||||
}
|
||||
|
||||
bool aidCompare(const char *aidlarge, const char *aidsmall) {
|
||||
if (strcmp(aidlarge, aidsmall) == 0)
|
||||
return true;
|
||||
|
||||
if (strlen(aidlarge) > strlen(aidsmall))
|
||||
if (strncmp(aidlarge, aidsmall, strlen(aidsmall)) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen) {
|
||||
*aidlen = 0;
|
||||
const char *hexaid = jsonStrGet(data, "AID");
|
||||
if (hexaid == NULL || strlen(hexaid) == 0)
|
||||
return false;
|
||||
|
||||
int res = param_gethex_to_eol(hexaid, 0, aid, aidmaxlen, aidlen);
|
||||
if (res)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int PrintAIDDescription(json_t *xroot, char *aid, bool verbose) {
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
json_t *root = xroot;
|
||||
if (root == NULL)
|
||||
root = AIDSearchInit(verbose);
|
||||
if (root == NULL)
|
||||
goto out;
|
||||
|
||||
json_t *elm = NULL;
|
||||
int maxaidlen = 0;
|
||||
for (int elmindx = 0; elmindx < json_array_size(root); elmindx++) {
|
||||
json_t *data = AIDSearchGetElm(root, elmindx);
|
||||
if (data == NULL)
|
||||
continue;
|
||||
const char *dictaid = jsonStrGet(data, "AID");
|
||||
if (aidCompare(aid, dictaid)) { // dictaid may be less length than requested aid
|
||||
if (maxaidlen < strlen(dictaid) && strlen(dictaid) <= strlen(aid)) {
|
||||
maxaidlen = strlen(dictaid);
|
||||
elm = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elm == NULL)
|
||||
goto out;
|
||||
|
||||
// print here
|
||||
const char *vaid = jsonStrGet(elm, "AID");
|
||||
const char *vendor = jsonStrGet(elm, "Vendor");
|
||||
const char *name = jsonStrGet(elm, "Name");
|
||||
const char *country = jsonStrGet(elm, "Country");
|
||||
const char *description = jsonStrGet(elm, "Description");
|
||||
const char *type = jsonStrGet(elm, "Type");
|
||||
|
||||
if (!verbose) {
|
||||
PrintAndLogEx(SUCCESS, "AID %s | %s | %s", vaid, vendor, name);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Input AID: %s", aid);
|
||||
if (aid)
|
||||
PrintAndLogEx(SUCCESS, "Found AID: %s", vaid);
|
||||
if (vendor)
|
||||
PrintAndLogEx(SUCCESS, "Vendor: %s", vendor);
|
||||
if (type)
|
||||
PrintAndLogEx(SUCCESS, "Type: %s", type);
|
||||
if (name)
|
||||
PrintAndLogEx(SUCCESS, "Name: %s", name);
|
||||
if (country)
|
||||
PrintAndLogEx(SUCCESS, "Country: %s", country);
|
||||
if (description)
|
||||
PrintAndLogEx(SUCCESS, "Description: %s", description);
|
||||
}
|
||||
|
||||
out:
|
||||
if (xroot == NULL)
|
||||
AIDSearchFree(root);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose) {
|
||||
return PrintAIDDescription(root, sprint_hex_inrow(aid, aidlen), verbose);
|
||||
}
|
||||
|
28
client/aidsearch.h
Normal file
28
client/aidsearch.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2019 merlokk
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Proxmark3 RDV40 AID list library
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AIDSEARCH_H__
|
||||
#define AIDSEARCH_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
int PrintAIDDescription(json_t *root, char *aid, bool verbose);
|
||||
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose);
|
||||
json_t *AIDSearchInit(bool verbose);
|
||||
json_t *AIDSearchGetElm(json_t *root, int elmindx);
|
||||
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen);
|
||||
int AIDSearchFree();
|
||||
|
||||
#endif
|
|
@ -91,7 +91,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag...");
|
||||
if (IfPm3Iso14443a()) {
|
||||
if (infoHF14A(false, false) > 0) {
|
||||
if (infoHF14A(false, false, false) > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "ui.h"
|
||||
#include "crc16.h"
|
||||
#include "util_posix.h" // msclock
|
||||
#include "aidsearch.h"
|
||||
|
||||
bool APDUInFramingEnable = true;
|
||||
|
||||
|
@ -226,13 +227,6 @@ static int usage_hf_14a_reader(void) {
|
|||
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
|
||||
return 0;
|
||||
}
|
||||
static int usage_hf_14a_info(void) {
|
||||
PrintAndLogEx(NORMAL, "This command makes more extensive tests against a ISO14443a tag in order to collect information");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a info [h|s]");
|
||||
PrintAndLogEx(NORMAL, " s silent (no messages)");
|
||||
PrintAndLogEx(NORMAL, " n test for nack bug");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CmdHF14AList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
|
@ -367,12 +361,30 @@ static int CmdHF14AReader(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHF14AInfo(const char *Cmd) {
|
||||
bool verbose = false;
|
||||
bool do_nack_test = false;
|
||||
bool do_aid_search = false;
|
||||
|
||||
if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_hf_14a_info();
|
||||
CLIParserInit("hf 14a info",
|
||||
"This command makes more extensive tests against a ISO14443a tag in order to collect information",
|
||||
"Sample:\n\thf 14a info -nsv - shows full information about the card\n");
|
||||
|
||||
bool verbose = !(Cmd[0] == 's' || Cmd[0] == 'S');
|
||||
bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N');
|
||||
infoHF14A(verbose, do_nack_test);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("vV", "verbose", "adds some information to results"),
|
||||
arg_lit0("nN", "naktest", "test for nack bug"),
|
||||
arg_lit0("sS", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(Cmd, argtable, true);
|
||||
|
||||
verbose = arg_get_lit(1);
|
||||
do_nack_test = arg_get_lit(2);
|
||||
do_aid_search = arg_get_lit(3);
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
infoHF14A(verbose, do_nack_test, do_aid_search);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1225,7 +1237,7 @@ int CmdHF14A(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
int infoHF14A(bool verbose, bool do_nack_test) {
|
||||
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
@ -1493,6 +1505,72 @@ int infoHF14A(bool verbose, bool do_nack_test) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (do_aid_search) {
|
||||
int elmindx = 0;
|
||||
json_t *root = AIDSearchInit(verbose);
|
||||
if (root != NULL) {
|
||||
bool ActivateField = true;
|
||||
for (elmindx = 0; elmindx < json_array_size(root); elmindx++) {
|
||||
json_t *data = AIDSearchGetElm(root, elmindx);
|
||||
uint8_t vaid[200] = {0};
|
||||
int vaidlen = 0;
|
||||
if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen)
|
||||
continue;
|
||||
|
||||
uint16_t sw = 0;
|
||||
uint8_t result[1024] = {0};
|
||||
size_t resultlen = 0;
|
||||
int res = EMVSelect(ECC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw, NULL);
|
||||
ActivateField = false;
|
||||
if (res)
|
||||
continue;
|
||||
|
||||
uint8_t dfname[200] = {0};
|
||||
size_t dfnamelen = 0;
|
||||
if (resultlen > 3) {
|
||||
struct tlvdb *tlv = tlvdb_parse_multi(result, resultlen);
|
||||
if (tlv) {
|
||||
// 0x84 Dedicated File (DF) Name
|
||||
const struct tlv *dfnametlv = tlvdb_get_tlv(tlvdb_find_full(tlv, 0x84));
|
||||
if (dfnametlv) {
|
||||
dfnamelen = dfnametlv->len;
|
||||
memcpy(dfname, dfnametlv->value, dfnamelen);
|
||||
}
|
||||
tlvdb_free(tlv);
|
||||
}
|
||||
}
|
||||
|
||||
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
||||
if (sw == 0x9000) {
|
||||
if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------");
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------");
|
||||
}
|
||||
|
||||
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
|
||||
|
||||
if (dfnamelen) {
|
||||
if (dfnamelen == vaidlen) {
|
||||
if (memcmp(dfname, vaid, vaidlen) == 0) {
|
||||
if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
|
||||
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
|
||||
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
|
||||
}
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(INFO, "(DF) Name not found");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
DropField();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ int CmdHF14A(const char *Cmd);
|
|||
int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
|
||||
int CmdHF14ASim(const char *Cmd); // used by hf mfu sim
|
||||
|
||||
int infoHF14A(bool verbose, bool do_nack_test);
|
||||
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
|
||||
const char *getTagInfo(uint8_t uid);
|
||||
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
||||
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
|
|
|
@ -47,7 +47,7 @@ static int CmdHFFidoInfo(const char *cmd) {
|
|||
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false);
|
||||
infoHF14A(false, false, false);
|
||||
|
||||
// FIDO info
|
||||
PrintAndLogEx(NORMAL, "--------------------------------------------");
|
||||
|
|
|
@ -36,7 +36,7 @@ static int CmdHFMFPInfo(const char *cmd) {
|
|||
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false);
|
||||
infoHF14A(false, false, false);
|
||||
|
||||
// Mifare Plus info
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue