mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-30 11:39:14 -07:00
added the skeleton for fudan card support
This commit is contained in:
parent
11e097c1bb
commit
e17fc29e41
8 changed files with 498 additions and 7 deletions
|
@ -275,6 +275,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||||
${PM3_ROOT}/client/src/cmdhffido.c
|
${PM3_ROOT}/client/src/cmdhffido.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhffudan.c
|
||||||
${PM3_ROOT}/client/src/cmdhfgallagher.c
|
${PM3_ROOT}/client/src/cmdhfgallagher.c
|
||||||
${PM3_ROOT}/client/src/cmdhfcipurse.c
|
${PM3_ROOT}/client/src/cmdhfcipurse.c
|
||||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||||
|
|
|
@ -365,7 +365,7 @@ endif
|
||||||
CFLAGS ?= $(DEFCFLAGS)
|
CFLAGS ?= $(DEFCFLAGS)
|
||||||
# We cannot just use CFLAGS+=... because it has impact on sub-makes if CFLAGS is defined in env:
|
# We cannot just use CFLAGS+=... because it has impact on sub-makes if CFLAGS is defined in env:
|
||||||
PM3CFLAGS = $(CFLAGS)
|
PM3CFLAGS = $(CFLAGS)
|
||||||
PM3CFLAGS += -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES)
|
PM3CFLAGS += -g -I./src -I./include -I../include -I../common -I../common_fpga $(PM3INCLUDES) $(INCLUDES)
|
||||||
# WIP Testing
|
# WIP Testing
|
||||||
#PM3CFLAGS += -std=c11 -pedantic
|
#PM3CFLAGS += -std=c11 -pedantic
|
||||||
|
|
||||||
|
@ -557,6 +557,7 @@ SRCS = mifare/aiddesfire.c \
|
||||||
cmdhfemrtd.c \
|
cmdhfemrtd.c \
|
||||||
cmdhffelica.c \
|
cmdhffelica.c \
|
||||||
cmdhffido.c \
|
cmdhffido.c \
|
||||||
|
cmdhffudan.c \
|
||||||
cmdhfgallagher.c \
|
cmdhfgallagher.c \
|
||||||
cmdhfksx6924.c \
|
cmdhfksx6924.c \
|
||||||
cmdhfcipurse.c \
|
cmdhfcipurse.c \
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "cmdhfwaveshare.h" // Waveshare
|
#include "cmdhfwaveshare.h" // Waveshare
|
||||||
#include "cmdhftexkom.h" // Texkom
|
#include "cmdhftexkom.h" // Texkom
|
||||||
#include "cmdhfxerox.h" // Xerox
|
#include "cmdhfxerox.h" // Xerox
|
||||||
|
#include "cmdhffudan.h" // Fudan cards
|
||||||
#include "cmdtrace.h" // trace list
|
#include "cmdtrace.h" // trace list
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "proxgui.h"
|
#include "proxgui.h"
|
||||||
|
@ -439,6 +440,7 @@ static command_t CommandTable[] = {
|
||||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||||
|
{"fudan", CmdHFFudan, AlwaysAvailable, "{ Fudan RFIDs... }"},
|
||||||
{"gallagher", CmdHFGallagher, AlwaysAvailable, "{ Gallagher DESFire RFIDs... }"},
|
{"gallagher", CmdHFGallagher, AlwaysAvailable, "{ Gallagher DESFire RFIDs... }"},
|
||||||
{"ksx6924", CmdHFKSX6924, AlwaysAvailable, "{ KS X 6924 (T-Money, Snapper+) RFIDs }"},
|
{"ksx6924", CmdHFKSX6924, AlwaysAvailable, "{ KS X 6924 (T-Money, Snapper+) RFIDs }"},
|
||||||
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
|
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
#include "comms.h" // clearCommandBuffer
|
#include "comms.h" // clearCommandBuffer
|
||||||
#include "cmdtrace.h"
|
#include "cmdtrace.h"
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
#include "cmdhfmf.h"
|
#include "cmdhfmf.h"
|
||||||
|
@ -29,9 +29,9 @@
|
||||||
#include "emv/emvcore.h"
|
#include "emv/emvcore.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
#include "util_posix.h" // msclock
|
#include "util_posix.h" // msclock
|
||||||
#include "aidsearch.h"
|
#include "aidsearch.h"
|
||||||
#include "cmdhf.h" // handle HF plot
|
#include "cmdhf.h" // handle HF plot
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
#include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A
|
#include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A
|
||||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||||
|
@ -2301,7 +2301,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`emv search -s`"));
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`emv search -s`"));
|
||||||
|
|
||||||
if (isFUDAN) {
|
if (isFUDAN) {
|
||||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf 14a raw`") " - since FUDAN is different");
|
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf fudan dump`"));
|
||||||
|
/*
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -a -b 7 -k 26");
|
PrintAndLogEx(HINT, " hf 14a raw -a -b 7 -k 26");
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -k -c 3000");
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3000");
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -k -c 3001");
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3001");
|
||||||
|
@ -2311,6 +2312,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -k -c 3005");
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3005");
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -k -c 3006");
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3006");
|
||||||
PrintAndLogEx(HINT, " hf 14a raw -c 3007");
|
PrintAndLogEx(HINT, " hf 14a raw -c 3007");
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
420
client/src/cmdhffudan.c
Normal file
420
client/src/cmdhffudan.c
Normal file
|
@ -0,0 +1,420 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency proximity cards from ISO14443A / Fudan commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "cmdhffudan.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "cliparser.h"
|
||||||
|
#include "cmdparser.h" // command_t
|
||||||
|
#include "comms.h"
|
||||||
|
#include "cmdhf14a.h"
|
||||||
|
#include "cmddata.h"
|
||||||
|
#include "mifare.h" // xiso
|
||||||
|
#include "cmdhf.h" //
|
||||||
|
#include "fileutils.h" // saveFile
|
||||||
|
#include "ui.h"
|
||||||
|
#include "commonutil.h" // MemLeToUint2byte
|
||||||
|
#include "protocols.h" // ISO14 defines
|
||||||
|
#include "crc16.h" // compute_crc
|
||||||
|
#include "util_posix.h" // msclock
|
||||||
|
|
||||||
|
#define FUDAN_BLOCK_READ_RETRY 3
|
||||||
|
#define MAX_FUDAN_BLOCK_SIZE 4
|
||||||
|
#define MAX_FUDAN_05_BLOCKS 8 // 16
|
||||||
|
#define MAX_FUDAN_08_BLOCKS 64
|
||||||
|
|
||||||
|
#ifndef AddCrc14A
|
||||||
|
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// iceman: these types are quite unsure.
|
||||||
|
typedef enum {
|
||||||
|
FM11RF005M,
|
||||||
|
FM11RF008M,
|
||||||
|
FM11RF005SH,
|
||||||
|
FM11RF08SH,
|
||||||
|
FUDAN_NONE,
|
||||||
|
} fudan_type_t;
|
||||||
|
|
||||||
|
static void fudan_print_blocks(uint16_t n, uint8_t *d) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(INFO, "----+-------------+-----------------");
|
||||||
|
PrintAndLogEx(INFO, "blk | data | ascii");
|
||||||
|
PrintAndLogEx(INFO, "----+-------------+-----------------");
|
||||||
|
for (uint16_t b = 0; b < n; b++) {
|
||||||
|
PrintAndLogEx(INFO, "%3d | %s ", b, sprint_hex_ascii(d + (b * MAX_FUDAN_BLOCK_SIZE), MAX_FUDAN_BLOCK_SIZE));
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "----+-------------+-----------------");
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* GenerateFilename(iso14a_card_select_t *card, const char *prefix, const char *suffix) {
|
||||||
|
if (card == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *fptr = calloc(sizeof(char) * (strlen(prefix) + strlen(suffix)) + sizeof(card->uid) * 2 + 1, sizeof(uint8_t));
|
||||||
|
strcpy(fptr, prefix);
|
||||||
|
FillFileNameByUID(fptr, card->uid, suffix, card->uidlen);
|
||||||
|
return fptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fudan_type_t fudan_detected(iso14a_card_select_t *card) {
|
||||||
|
|
||||||
|
if ((card->sak & 0x0A) == 0x0A) {
|
||||||
|
|
||||||
|
uint8_t atqa = MemLeToUint2byte(card->atqa);
|
||||||
|
if ((atqa & 0x0003) == 0x0003) {
|
||||||
|
// Uses Shanghai algo
|
||||||
|
// printTag("FM11RF005SH (FUDAN Shanghai Metro)");
|
||||||
|
return FM11RF005SH;
|
||||||
|
} else if ((atqa & 0x0005) == 0x0005) {
|
||||||
|
// printTag("FM11RF005M (FUDAN MIFARE Classic clone)");
|
||||||
|
return FM11RF005M;
|
||||||
|
} else if ((atqa & 0x0008) == 0x0008) {
|
||||||
|
// printTag("FM11RF008M (FUDAN MIFARE Classic clone)");
|
||||||
|
return FM11RF008M;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ((card->sak & 0x53) == 0x53) {
|
||||||
|
// printTag("FM11RF08SH (FUDAN)");
|
||||||
|
return FM11RF08SH;
|
||||||
|
}
|
||||||
|
return FUDAN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fudan_get_type(iso14a_card_select_t *card, bool verbose) {
|
||||||
|
|
||||||
|
if (card == NULL) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||||
|
PacketResponseNG resp;
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||||
|
PrintAndLogEx(DEBUG, "iso14443a card select failed");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||||
|
|
||||||
|
/*
|
||||||
|
0: couldn't read
|
||||||
|
1: OK, with ATS
|
||||||
|
2: OK, no ATS
|
||||||
|
3: proprietary Anticollision
|
||||||
|
*/
|
||||||
|
uint64_t select_status = resp.oldarg[0];
|
||||||
|
|
||||||
|
if (select_status == 0) {
|
||||||
|
PrintAndLogEx(DEBUG, "iso14443a card select failed");
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select_status == 3) {
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||||
|
PrintAndLogEx(SUCCESS, "ATQA: %02X %02X", card->atqa[1], card->atqa[0]);
|
||||||
|
}
|
||||||
|
DropField();
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card->uid, card->uidlen));
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card->atqa[1], card->atqa[0]);
|
||||||
|
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card->sak, select_status);
|
||||||
|
|
||||||
|
if (card->ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||||
|
if (card->ats_len == card->ats[0] + 2)
|
||||||
|
PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card->ats, card->ats[0]));
|
||||||
|
else {
|
||||||
|
PrintAndLogEx(SUCCESS, " ATS: [%d] " _GREEN_("%s"), card->ats_len, sprint_hex(card->ats, card->ats_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_fudan_uid(bool loop, bool verbose) {
|
||||||
|
|
||||||
|
do {
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
|
||||||
|
int res = fudan_get_type(&card, verbose);
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (res) {
|
||||||
|
case PM3_EFAILED:
|
||||||
|
case PM3_EINVARG:
|
||||||
|
return res;
|
||||||
|
case PM3_ETIMEOUT:
|
||||||
|
PrintAndLogEx(DEBUG, "command execution time out");
|
||||||
|
return res;
|
||||||
|
case PM3_ESOFT:
|
||||||
|
PrintAndLogEx(DEBUG, "fudan card select failed");
|
||||||
|
return PM3_ESOFT;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (loop) {
|
||||||
|
res = handle_hf_plot();
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decoding code
|
||||||
|
if (loop == false) {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (loop && kbd_enter_pressed() == false);
|
||||||
|
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFFudanReader(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf fudan reader",
|
||||||
|
"Read a fudan tag",
|
||||||
|
"hf fudan reader\n"
|
||||||
|
"hf fudan reader -@ -> continuous reader mode"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("v", "verbose", "Verbose scan and output"),
|
||||||
|
arg_lit0("@", NULL, "optional - continuous reader mode"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
bool verbose = arg_get_lit(ctx, 1);
|
||||||
|
bool cm = arg_get_lit(ctx, 2);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (cm) {
|
||||||
|
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||||
|
return read_fudan_uid(cm, verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
DropField();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFFudanDump(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf fudan dump",
|
||||||
|
"Dump FUDAN tag to binary file\n"
|
||||||
|
"If no <name> given, UID will be used as filename",
|
||||||
|
"hf fudan dump -f mydump --> dump using filename\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0("f", "file", "<fn>", "filename of dump"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
int datafnlen = 0;
|
||||||
|
char dataFilename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)dataFilename, FILE_PATH_SIZE, &datafnlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// Select card to get UID/UIDLEN/ATQA/SAK information
|
||||||
|
// leaves the field on
|
||||||
|
iso14a_card_select_t card;
|
||||||
|
int res = fudan_get_type(&card, false);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to select a fudan card. Exiting...");
|
||||||
|
DropField();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validations
|
||||||
|
fudan_type_t t = fudan_detected(&card);
|
||||||
|
if (t == FUDAN_NONE) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to detect a fudan card. Exiting...");
|
||||||
|
DropField();
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect card size
|
||||||
|
// 512b, 8kbits
|
||||||
|
uint8_t num_blocks = MAX_FUDAN_05_BLOCKS;
|
||||||
|
switch(t) {
|
||||||
|
case FM11RF008M:
|
||||||
|
num_blocks = MAX_FUDAN_08_BLOCKS;
|
||||||
|
break;
|
||||||
|
case FM11RF005SH:
|
||||||
|
case FM11RF005M:
|
||||||
|
case FM11RF08SH:
|
||||||
|
case FUDAN_NONE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t carddata[num_blocks * MAX_FUDAN_BLOCK_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -a -b 7 -k 26");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3000");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3001");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3002");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3003");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3004");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3005");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -k -c 3006");
|
||||||
|
PrintAndLogEx(HINT, " hf 14a raw -c 3007");
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
uint16_t flags = (ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS | ISO14A_RAW);
|
||||||
|
uint32_t argtimeout = 0;
|
||||||
|
uint32_t numbits = 0;
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "." NOLF);
|
||||||
|
// dump memory
|
||||||
|
for (uint8_t b = 0; b < num_blocks; b++) {
|
||||||
|
|
||||||
|
// read block
|
||||||
|
uint8_t cmd[4] = {ISO14443A_CMD_READBLOCK, b, 0x00, 0x00};
|
||||||
|
AddCrc14A(cmd, 2);
|
||||||
|
|
||||||
|
for (uint8_t tries = 0; tries < FUDAN_BLOCK_READ_RETRY; tries++) {
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
PacketResponseNG resp;
|
||||||
|
SendCommandOLD(CMD_HF_ISO14443A_READER, flags, sizeof(cmd) | ((uint32_t)(numbits << 16)), argtimeout, cmd, sizeof(cmd));
|
||||||
|
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
if (resp.status == PM3_SUCCESS) {
|
||||||
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
memcpy(carddata + (b * MAX_FUDAN_BLOCK_SIZE), data, MAX_FUDAN_BLOCK_SIZE);
|
||||||
|
PrintAndLogEx(NORMAL, "." NOLF);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(FAILED, "could not read block %2d", b);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d", b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
DropField();
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
|
||||||
|
|
||||||
|
fudan_print_blocks(num_blocks, carddata);
|
||||||
|
|
||||||
|
// create filename if none was given
|
||||||
|
if (strlen(dataFilename) < 1) {
|
||||||
|
char *fptr = GenerateFilename(&card, "hf-fudan-", "-dump");
|
||||||
|
if (fptr == NULL)
|
||||||
|
return PM3_ESOFT;
|
||||||
|
|
||||||
|
strcpy(dataFilename, fptr);
|
||||||
|
free(fptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveFile(dataFilename, ".bin", (uint8_t *)carddata, sizeof(carddata));
|
||||||
|
saveFileEML(dataFilename, (uint8_t *)carddata, sizeof(carddata), MAX_FUDAN_BLOCK_SIZE);
|
||||||
|
|
||||||
|
iso14a_mf_extdump_t xdump;
|
||||||
|
xdump.card_info = card;
|
||||||
|
xdump.dump = (uint8_t *)carddata;
|
||||||
|
xdump.dumplen = sizeof(carddata);
|
||||||
|
saveFileJSON(dataFilename, jsfFudan, (uint8_t *)&xdump, sizeof(xdump), NULL);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHFFudanView(const char *Cmd) {
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "hf fudan view",
|
||||||
|
"Print a FUDAN dump file (bin/eml/json)",
|
||||||
|
"hf fudan view -f hf-fudan-01020304-dump.bin"
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1("f", "file", "<fn>", "filename of dump"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE];
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// read dump file
|
||||||
|
uint8_t *dump = NULL;
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (MAX_FUDAN_BLOCK_SIZE * MAX_FUDAN_08_BLOCKS));
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t block_cnt = MIN(MAX_FUDAN_05_BLOCKS, (bytes_read / MAX_FUDAN_BLOCK_SIZE));
|
||||||
|
|
||||||
|
fudan_print_blocks(block_cnt, dump);
|
||||||
|
|
||||||
|
free(dump);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"reader", CmdHFFudanReader, IfPm3Iso14443a, "Act like a fudan reader"},
|
||||||
|
{"dump", CmdHFFudanDump, IfPm3Iso14443a, "Dump FUDAN tag to binary file"},
|
||||||
|
//{"sim", CmdHFFudanSim, IfPm3Iso14443a, "Simulate a fudan tag"},
|
||||||
|
//{"rdbl", CmdHFFudanRead, IfPm3Iso14443a, "Read a fudan tag"},
|
||||||
|
{"view", CmdHFFudanView, AlwaysAvailable, "Display content from tag dump file"},
|
||||||
|
//{"wrbl", CmdHFFudanWrite, IfPm3Iso14443a, "Write a fudan tag"},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHFFudan(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
29
client/src/cmdhffudan.h
Normal file
29
client/src/cmdhffudan.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// High frequency proximity cards from ISO14443A / FUDAN commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDHFFUDAN_H__
|
||||||
|
#define CMDHFFUDAN_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
|
int CmdHFFudan(const char *Cmd);
|
||||||
|
int read_fudan_uid(bool loop, bool verbose);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -396,6 +396,19 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case jsfFudan: {
|
||||||
|
iso14a_mf_extdump_t *xdump = (iso14a_mf_extdump_t *)(void *) data;
|
||||||
|
JsonSaveStr(root, "FileType", "fudan");
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.UID", xdump->card_info.uid, xdump->card_info.uidlen);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", xdump->card_info.atqa, 2);
|
||||||
|
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &(xdump->card_info.sak), 1);
|
||||||
|
for (size_t i = 0; i < (xdump->dumplen / 4); i++) {
|
||||||
|
char path[PATH_MAX_LENGTH] = {0};
|
||||||
|
snprintf(path, sizeof(path), "$.blocks.%zu", i);
|
||||||
|
JsonSaveBufAsHexCompact(root, path, &xdump->dump[i * 4], 4);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case jsfMfuMemory: {
|
case jsfMfuMemory: {
|
||||||
JsonSaveStr(root, "FileType", "mfu");
|
JsonSaveStr(root, "FileType", "mfu");
|
||||||
|
|
||||||
|
@ -1108,6 +1121,28 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
||||||
*datalen = sptr;
|
*datalen = sptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(ctype, "fudan")) {
|
||||||
|
size_t sptr = 0;
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
if (sptr + 4 > maxdatalen) {
|
||||||
|
retval = PM3_EMALLOC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
char blocks[30] = {0};
|
||||||
|
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
|
||||||
|
if (!len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
sptr += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
*datalen = sptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(ctype, "mfu")) {
|
if (!strcmp(ctype, "mfu")) {
|
||||||
|
|
||||||
mfu_dump_t *mem = (mfu_dump_t *)udata;
|
mfu_dump_t *mem = (mfu_dump_t *)udata;
|
||||||
|
|
|
@ -47,6 +47,7 @@ typedef enum {
|
||||||
jsfEM4x69,
|
jsfEM4x69,
|
||||||
jsfEM4x50,
|
jsfEM4x50,
|
||||||
jsfFido,
|
jsfFido,
|
||||||
|
jsfFudan,
|
||||||
} JSONFileType;
|
} JSONFileType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue