mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-04-02 18:39:57 +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 ability to execute commands from stdin (pipe) (Merlok)
|
||||
- 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
|
||||
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)
|
||||
|
|
|
@ -114,6 +114,11 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
graph.c \
|
||||
cmddata.c \
|
||||
lfdemod.c \
|
||||
emv/apduinfo.c\
|
||||
emv/dump.c\
|
||||
emv/tlv.c\
|
||||
emv/emv_tags.c\
|
||||
emv/emvcore.c\
|
||||
cmdanalyse.c \
|
||||
cmdhf.c \
|
||||
cmdhf14a.c \
|
||||
|
@ -328,3 +333,4 @@ $(DEPENDENCY_FILES): ;
|
|||
.PRECIOUS: $(DEPENDENCY_FILES)
|
||||
|
||||
-include $(DEPENDENCY_FILES)
|
||||
|
||||
|
|
|
@ -12,13 +12,7 @@
|
|||
#include "cmdhf14a.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static void waitCmd(uint8_t iLen);
|
||||
|
||||
// structure and database for uid -> tagtype lookups
|
||||
typedef struct {
|
||||
uint8_t uid;
|
||||
char* desc;
|
||||
} manufactureName;
|
||||
static int waitCmd(uint8_t iLen);
|
||||
|
||||
const manufactureName manufactureMapping[] = {
|
||||
// ID, "Vendor Country"
|
||||
|
@ -94,7 +88,6 @@ const manufactureName manufactureMapping[] = {
|
|||
{ 0x00, "no tag-info available" } // must be the last entry
|
||||
};
|
||||
|
||||
|
||||
// get a product description based on the UID
|
||||
// uid[8] tag uid
|
||||
// returns description of the best match
|
||||
|
@ -593,6 +586,160 @@ int CmdHF14ASniff(const char *Cmd) {
|
|||
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) {
|
||||
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
|
||||
bool reply = 1;
|
||||
|
@ -600,11 +747,11 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
|||
bool power = false;
|
||||
bool active = false;
|
||||
bool active_select = false;
|
||||
bool no_rats = false;
|
||||
uint16_t numbits = 0;
|
||||
bool bTimeout = false;
|
||||
uint32_t timeout = 0;
|
||||
bool topazmode = false;
|
||||
bool no_rats = false;
|
||||
char buf[5]="";
|
||||
int i = 0;
|
||||
uint8_t data[USB_CMD_DATA_SIZE];
|
||||
|
@ -740,15 +887,16 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
|||
SendCommand(&c);
|
||||
|
||||
if (reply) {
|
||||
int res = 0;
|
||||
if (active_select)
|
||||
waitCmd(1);
|
||||
if (datalen > 0)
|
||||
res = waitCmd(1);
|
||||
if (!res && datalen > 0)
|
||||
waitCmd(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void waitCmd(uint8_t iSelect) {
|
||||
static int waitCmd(uint8_t iSelect) {
|
||||
UsbCommand resp;
|
||||
uint16_t len = 0;
|
||||
|
||||
|
@ -766,12 +914,14 @@ static void waitCmd(uint8_t iSelect) {
|
|||
}
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
return 1;
|
||||
|
||||
PrintAndLog("%s", sprint_hex(resp.d.asBytes, len) );
|
||||
} else {
|
||||
PrintAndLog("timeout while waiting for reply.");
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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"},
|
||||
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443-a tag"},
|
||||
{"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"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
|
|
@ -30,6 +30,14 @@
|
|||
#include "cmdhfmfu.h"
|
||||
#include "cmdhf.h" // list cmd
|
||||
#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 CmdHF14AList(const char *Cmd);
|
||||
|
@ -41,6 +49,9 @@ extern int CmdHF14ACmdRaw(const char *Cmd);
|
|||
extern int CmdHF14ACUIDs(const char *Cmd);
|
||||
|
||||
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_sniff(void);
|
||||
|
|
|
@ -379,11 +379,19 @@ int param_getlength(const char *line, int paramnum)
|
|||
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;
|
||||
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)
|
||||
|
@ -487,6 +495,51 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt)
|
|||
|
||||
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 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 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 uint8_t param_get8(const char *line, int paramnum);
|
||||
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 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_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 hextobinarray( char *target, char *source);
|
||||
|
|
Loading…
Add table
Reference in a new issue