mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-04-08 13:30:22 +08:00
ADD: 'hf 14a apdu' @merlokk
This commit is contained in:
parent
a3e923c529
commit
8b83db2c1b
6 changed files with 242 additions and 17 deletions
|
@ -8,6 +8,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (Merlok)
|
- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (Merlok)
|
||||||
- Added to proxmark ability to execute commands from stdin (pipe) (Merlok)
|
- Added to proxmark ability to execute commands from stdin (pipe) (Merlok)
|
||||||
- Added new standalone mode "HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN" (@cjbrigato)
|
- Added new standalone mode "HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN" (@cjbrigato)
|
||||||
|
- Added to `hf 14a apdu` - exchange apdu via iso1443-4 (Merlok)
|
||||||
|
- Added to `hf 14a apdu` - apdu and tlv results parser (Merlok)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)
|
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)
|
||||||
|
|
|
@ -114,6 +114,11 @@ CMDSRCS = crapto1/crapto1.c \
|
||||||
graph.c \
|
graph.c \
|
||||||
cmddata.c \
|
cmddata.c \
|
||||||
lfdemod.c \
|
lfdemod.c \
|
||||||
|
emv/apduinfo.c\
|
||||||
|
emv/dump.c\
|
||||||
|
emv/tlv.c\
|
||||||
|
emv/emv_tags.c\
|
||||||
|
emv/emvcore.c\
|
||||||
cmdanalyse.c \
|
cmdanalyse.c \
|
||||||
cmdhf.c \
|
cmdhf.c \
|
||||||
cmdhf14a.c \
|
cmdhf14a.c \
|
||||||
|
@ -328,3 +333,4 @@ $(DEPENDENCY_FILES): ;
|
||||||
.PRECIOUS: $(DEPENDENCY_FILES)
|
.PRECIOUS: $(DEPENDENCY_FILES)
|
||||||
|
|
||||||
-include $(DEPENDENCY_FILES)
|
-include $(DEPENDENCY_FILES)
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,7 @@
|
||||||
#include "cmdhf14a.h"
|
#include "cmdhf14a.h"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
static void waitCmd(uint8_t iLen);
|
static int waitCmd(uint8_t iLen);
|
||||||
|
|
||||||
// structure and database for uid -> tagtype lookups
|
|
||||||
typedef struct {
|
|
||||||
uint8_t uid;
|
|
||||||
char* desc;
|
|
||||||
} manufactureName;
|
|
||||||
|
|
||||||
const manufactureName manufactureMapping[] = {
|
const manufactureName manufactureMapping[] = {
|
||||||
// ID, "Vendor Country"
|
// ID, "Vendor Country"
|
||||||
|
@ -94,7 +88,6 @@ const manufactureName manufactureMapping[] = {
|
||||||
{ 0x00, "no tag-info available" } // must be the last entry
|
{ 0x00, "no tag-info available" } // must be the last entry
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// get a product description based on the UID
|
// get a product description based on the UID
|
||||||
// uid[8] tag uid
|
// uid[8] tag uid
|
||||||
// returns description of the best match
|
// returns description of the best match
|
||||||
|
@ -593,6 +586,160 @@ int CmdHF14ASniff(const char *Cmd) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DropField() {
|
||||||
|
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommand(&c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen) {
|
||||||
|
uint16_t cmdc = 0;
|
||||||
|
|
||||||
|
if (activateField) {
|
||||||
|
cmdc |= ISO14A_CONNECT;
|
||||||
|
}
|
||||||
|
if (leaveSignalON)
|
||||||
|
cmdc |= ISO14A_NO_DISCONNECT;
|
||||||
|
|
||||||
|
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
|
||||||
|
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
|
||||||
|
// here length USB_CMD_DATA_SIZE=512
|
||||||
|
// timeout timeout14a * 1.06 / 100, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106
|
||||||
|
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_SET_TIMEOUT | cmdc, (datainlen & 0xFFFF), 1000 * 1000 * 1.06 / 100}};
|
||||||
|
memcpy(c.d.asBytes, datain, datainlen);
|
||||||
|
SendCommand(&c);
|
||||||
|
|
||||||
|
uint8_t *recv;
|
||||||
|
UsbCommand resp;
|
||||||
|
|
||||||
|
if (activateField) {
|
||||||
|
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
PrintAndLog("APDU ERROR: Proxmark connection timeout.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (resp.arg[0] != 1) {
|
||||||
|
PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||||
|
recv = resp.d.asBytes;
|
||||||
|
int iLen = resp.arg[0];
|
||||||
|
|
||||||
|
*dataoutlen = iLen - 2;
|
||||||
|
if (*dataoutlen < 0)
|
||||||
|
*dataoutlen = 0;
|
||||||
|
memcpy(dataout, recv, *dataoutlen);
|
||||||
|
|
||||||
|
if(!iLen) {
|
||||||
|
PrintAndLog("APDU ERROR: No APDU response.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check block TODO
|
||||||
|
if (iLen == -2) {
|
||||||
|
PrintAndLog("APDU ERROR: Block type mismatch.");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRC Check
|
||||||
|
if (iLen == -1) {
|
||||||
|
PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check apdu length
|
||||||
|
if (iLen < 4) {
|
||||||
|
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PrintAndLog("APDU ERROR: Reply timeout.");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdHF14AAPDU(const char *cmd) {
|
||||||
|
uint8_t data[USB_CMD_DATA_SIZE];
|
||||||
|
int datalen = 0;
|
||||||
|
bool activateField = false;
|
||||||
|
bool leaveSignalON = false;
|
||||||
|
bool decodeTLV = false;
|
||||||
|
|
||||||
|
if (strlen(cmd) < 2) {
|
||||||
|
PrintAndLog("Usage: hf 14a apdu [-s] [-k] [-t] <APDU (hex)>");
|
||||||
|
PrintAndLog(" -s activate field and select card");
|
||||||
|
PrintAndLog(" -k leave the signal field ON after receive response");
|
||||||
|
PrintAndLog(" -t executes TLV decoder if it possible. TODO!!!!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmdp = 0;
|
||||||
|
while(param_getchar(cmd, cmdp) != 0x00) {
|
||||||
|
char c = param_getchar(cmd, cmdp);
|
||||||
|
if ((c == '-') && (param_getlength(cmd, cmdp) == 2))
|
||||||
|
switch (param_getchar_indx(cmd, 1, cmdp)) {
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
activateField = true;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
case 'K':
|
||||||
|
leaveSignalON = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
decodeTLV = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isxdigit(c)) {
|
||||||
|
// len = data + PCB(1b) + CRC(2b)
|
||||||
|
switch(param_gethex_to_eol(cmd, cmdp, data, sizeof(data) - 1 - 2, &datalen)) {
|
||||||
|
case 1:
|
||||||
|
PrintAndLog("Invalid HEX value.");
|
||||||
|
return 1;
|
||||||
|
case 2:
|
||||||
|
PrintAndLog("APDU too large.");
|
||||||
|
return 1;
|
||||||
|
case 3:
|
||||||
|
PrintAndLog("Hex must have even number of digits.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we get all the hex to end of line with spaces
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
|
||||||
|
|
||||||
|
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, &datalen);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
PrintAndLog("<<<< %s", sprint_hex(data, datalen));
|
||||||
|
|
||||||
|
PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
|
||||||
|
|
||||||
|
// TLV decoder
|
||||||
|
if (decodeTLV && datalen > 4) {
|
||||||
|
TLVPrintFromBuffer(data, datalen - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int CmdHF14ACmdRaw(const char *cmd) {
|
int CmdHF14ACmdRaw(const char *cmd) {
|
||||||
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
|
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
|
||||||
bool reply = 1;
|
bool reply = 1;
|
||||||
|
@ -600,11 +747,11 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
||||||
bool power = false;
|
bool power = false;
|
||||||
bool active = false;
|
bool active = false;
|
||||||
bool active_select = false;
|
bool active_select = false;
|
||||||
|
bool no_rats = false;
|
||||||
uint16_t numbits = 0;
|
uint16_t numbits = 0;
|
||||||
bool bTimeout = false;
|
bool bTimeout = false;
|
||||||
uint32_t timeout = 0;
|
uint32_t timeout = 0;
|
||||||
bool topazmode = false;
|
bool topazmode = false;
|
||||||
bool no_rats = false;
|
|
||||||
char buf[5]="";
|
char buf[5]="";
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint8_t data[USB_CMD_DATA_SIZE];
|
uint8_t data[USB_CMD_DATA_SIZE];
|
||||||
|
@ -740,15 +887,16 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
|
int res = 0;
|
||||||
if (active_select)
|
if (active_select)
|
||||||
waitCmd(1);
|
res = waitCmd(1);
|
||||||
if (datalen > 0)
|
if (!res && datalen > 0)
|
||||||
waitCmd(0);
|
waitCmd(0);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void waitCmd(uint8_t iSelect) {
|
static int waitCmd(uint8_t iSelect) {
|
||||||
UsbCommand resp;
|
UsbCommand resp;
|
||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
|
|
||||||
|
@ -766,12 +914,14 @@ static void waitCmd(uint8_t iSelect) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
return;
|
return 1;
|
||||||
|
|
||||||
PrintAndLog("%s", sprint_hex(resp.d.asBytes, len) );
|
PrintAndLog("%s", sprint_hex(resp.d.asBytes, len) );
|
||||||
} else {
|
} else {
|
||||||
PrintAndLog("timeout while waiting for reply.");
|
PrintAndLog("timeout while waiting for reply.");
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
|
@ -782,6 +932,7 @@ static command_t CommandTable[] = {
|
||||||
{"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443-a UIDs in one go"},
|
{"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443-a UIDs in one go"},
|
||||||
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"},
|
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"},
|
||||||
{"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"},
|
{"sniff", CmdHF14ASniff, 0, "sniff ISO 14443-a traffic"},
|
||||||
|
{"apdu", CmdHF14AAPDU, 0, "Send ISO 14443-4 APDU to tag"},
|
||||||
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
|
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,14 @@
|
||||||
#include "cmdhfmfu.h"
|
#include "cmdhfmfu.h"
|
||||||
#include "cmdhf.h" // list cmd
|
#include "cmdhf.h" // list cmd
|
||||||
#include "mifarehost.h"
|
#include "mifarehost.h"
|
||||||
|
#include "emv/apduinfo.h"
|
||||||
|
#include "emv/emvcore.h"
|
||||||
|
|
||||||
|
// structure and database for uid -> tagtype lookups
|
||||||
|
typedef struct {
|
||||||
|
uint8_t uid;
|
||||||
|
char* desc;
|
||||||
|
} manufactureName;
|
||||||
|
|
||||||
extern int CmdHF14A(const char *Cmd);
|
extern int CmdHF14A(const char *Cmd);
|
||||||
extern int CmdHF14AList(const char *Cmd);
|
extern int CmdHF14AList(const char *Cmd);
|
||||||
|
@ -41,6 +49,9 @@ extern int CmdHF14ACmdRaw(const char *Cmd);
|
||||||
extern int CmdHF14ACUIDs(const char *Cmd);
|
extern int CmdHF14ACUIDs(const char *Cmd);
|
||||||
|
|
||||||
extern char* getTagInfo(uint8_t uid);
|
extern char* getTagInfo(uint8_t uid);
|
||||||
|
extern void DropField();
|
||||||
|
extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int *dataoutlen);
|
||||||
|
|
||||||
|
|
||||||
extern int usage_hf_14a_sim(void);
|
extern int usage_hf_14a_sim(void);
|
||||||
extern int usage_hf_14a_sniff(void);
|
extern int usage_hf_14a_sniff(void);
|
||||||
|
|
|
@ -379,11 +379,19 @@ int param_getlength(const char *line, int paramnum)
|
||||||
return en - bg + 1;
|
return en - bg + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char param_getchar(const char *line, int paramnum)
|
char param_getchar(const char *line, int paramnum) {
|
||||||
{
|
return param_getchar_indx(line, 0, paramnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
char param_getchar_indx(const char *line, int indx, int paramnum) {
|
||||||
int bg, en;
|
int bg, en;
|
||||||
if (param_getptr(line, &bg, &en, paramnum)) return 0;
|
|
||||||
return line[bg];
|
if (param_getptr(line, &bg, &en, paramnum)) return 0x00;
|
||||||
|
|
||||||
|
if (bg + indx > en)
|
||||||
|
return '\0';
|
||||||
|
|
||||||
|
return line[bg + indx];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t param_get8(const char *line, int paramnum)
|
uint8_t param_get8(const char *line, int paramnum)
|
||||||
|
@ -487,6 +495,51 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen) {
|
||||||
|
int bg, en;
|
||||||
|
uint32_t temp;
|
||||||
|
char buf[5] = {0};
|
||||||
|
|
||||||
|
if (param_getptr(line, &bg, &en, paramnum)) return 1;
|
||||||
|
|
||||||
|
*datalen = 0;
|
||||||
|
|
||||||
|
int indx = bg;
|
||||||
|
while (line[indx]) {
|
||||||
|
if (line[indx] == '\t' || line[indx] == ' ')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (isxdigit(line[indx])) {
|
||||||
|
buf[strlen(buf) + 1] = 0x00;
|
||||||
|
buf[strlen(buf)] = line[indx];
|
||||||
|
} else {
|
||||||
|
// if we have symbols other than spaces and hex
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*datalen >= maxdatalen) {
|
||||||
|
// if we dont have space in buffer and have symbols to translate
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(buf) >= 2) {
|
||||||
|
sscanf(buf, "%x", &temp);
|
||||||
|
data[*datalen] = (uint8_t)(temp & 0xff);
|
||||||
|
*buf = 0;
|
||||||
|
(*datalen)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
indx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(buf) > 0)
|
||||||
|
//error when not completed hex bytes
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int param_getstr(const char *line, int paramnum, char * str)
|
int param_getstr(const char *line, int paramnum, char * str)
|
||||||
{
|
{
|
||||||
int bg, en;
|
int bg, en;
|
||||||
|
|
|
@ -114,6 +114,7 @@ extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t b
|
||||||
|
|
||||||
extern int param_getlength(const char *line, int paramnum);
|
extern int param_getlength(const char *line, int paramnum);
|
||||||
extern char param_getchar(const char *line, int paramnum);
|
extern char param_getchar(const char *line, int paramnum);
|
||||||
|
extern char param_getchar_indx(const char *line, int indx, int paramnum);
|
||||||
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
|
extern int param_getptr(const char *line, int *bg, int *en, int paramnum);
|
||||||
extern uint8_t param_get8(const char *line, int paramnum);
|
extern uint8_t param_get8(const char *line, int paramnum);
|
||||||
extern uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
|
extern uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base);
|
||||||
|
@ -123,6 +124,7 @@ extern uint8_t param_getdec(const char *line, int paramnum, uint8_t *destination
|
||||||
extern uint8_t param_isdec(const char *line, int paramnum);
|
extern uint8_t param_isdec(const char *line, int paramnum);
|
||||||
extern int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
|
extern int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt);
|
||||||
extern int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt);
|
extern int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt);
|
||||||
|
extern int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxdatalen, int *datalen);
|
||||||
extern int param_getstr(const char *line, int paramnum, char * str);
|
extern int param_getstr(const char *line, int paramnum, char * str);
|
||||||
|
|
||||||
extern int hextobinarray( char *target, char *source);
|
extern int hextobinarray( char *target, char *source);
|
||||||
|
|
Loading…
Add table
Reference in a new issue