mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
Merge pull request #2269 from lnv42/master
iso15 sim & sniff improvments & HF_15SIM standalone
This commit is contained in:
commit
52bacab60c
14 changed files with 1010 additions and 375 deletions
|
@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added `HF_15SIM` standalone mode that dump then simulate iso15 tags (@lnv42)
|
||||
- Changed `iso15 simulation`, reworked, added support for lot of features (@lnv42)
|
||||
- Changed `hf 15 sniff` quality while low signal (@lnv42)
|
||||
- Fixed `hf sniff` broken since 17ab86c52 (@nvx)
|
||||
- Added `--dumpmem` to proxmark3 client for memory dumping to file (@martian01010)
|
||||
- Changed `hw readmem` to allow larger reads, write to file and better hex viewer (@martian01010)
|
||||
|
|
|
@ -80,6 +80,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| HF_15SNIFF | 15693 sniff to flashmem (rdv4) or ram |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| HF_15SIM | 15693 tag simulator |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| HF_AVEFUL | Mifare ultralight read/simulation |
|
||||
| | - Ave Ozkal |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -136,7 +139,7 @@ endef
|
|||
|
||||
STANDALONE_MODES := LF_SKELETON
|
||||
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG
|
||||
STANDALONE_MODES += DANKARMULTI
|
||||
STANDALONE_MODES_REQ_BT := HF_CARDHOPPER HF_REBLAY
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
|
|
|
@ -89,6 +89,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_15SNIFF,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_15sniff.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_15SIM
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_15SIM,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_15sim.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_AVEFUL
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_aveful.c
|
||||
|
|
238
armsrc/Standalone/hf_15sim.c
Normal file
238
armsrc/Standalone/hf_15sim.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) lnv42 2024
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main code for standalone HF/iso15693 Simulation
|
||||
// This code is trying to dump an iso15 tag, then simulate it
|
||||
// It doesn't support any password protected/authenticated features
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "iso15693.h"
|
||||
#include "iso15.h"
|
||||
#include "protocols.h"
|
||||
#include "iso15693tools.h"
|
||||
#include "util.h"
|
||||
#include "spiffs.h"
|
||||
#include "appmain.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "BigBuf.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
//#define CalculateCrc15(data, len) Crc16ex(CRC_15693, (data), (len) + 2);
|
||||
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
|
||||
|
||||
#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us
|
||||
#define HF_15693SIM_LOGFILE "hf_15693sim.trace"
|
||||
|
||||
static void DownloadTraceInstructions(void) {
|
||||
Dbprintf("");
|
||||
#ifdef WITH_FLASH
|
||||
Dbprintf("To get the trace from flash and display it:");
|
||||
Dbprintf("1. mem spiffs dump -s "HF_15693SIM_LOGFILE" -d hf_15693sim.trace");
|
||||
Dbprintf("2. trace load -f hf_15693sim.trace");
|
||||
Dbprintf("3. trace list -t 15 -1");
|
||||
#else
|
||||
Dbprintf("To get the trace from PM3 memory:");
|
||||
Dbprintf("trace list -t 15");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF 15693 SIM, a ISO15693 simulator - lnv42");
|
||||
DownloadTraceInstructions();
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
StandAloneMode();
|
||||
|
||||
Dbprintf(_YELLOW_("HF 15693 SIM started"));
|
||||
#ifdef WITH_FLASH
|
||||
rdv40_spiffs_lazy_mount();
|
||||
#endif
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_15);
|
||||
|
||||
iso15_tag_t *tag = (iso15_tag_t*) BigBuf_get_EM_addr();
|
||||
if (tag == NULL) return;
|
||||
|
||||
uint8_t cmd[8] = {0};
|
||||
int res;
|
||||
uint16_t recvLen;
|
||||
uint8_t recv[32];
|
||||
uint32_t eof_time = 0, start_time;
|
||||
|
||||
cmd[0] = ISO15_REQ_DATARATE_HIGH;
|
||||
cmd[1] = ISO15693_GET_SYSTEM_INFO;
|
||||
AddCrc15(cmd, 2);
|
||||
uint8_t i;
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
Dbprintf("Wait for a dumpable tag");
|
||||
|
||||
while (1) {
|
||||
SpinDelay(200);
|
||||
LED_B_OFF();
|
||||
if (BUTTON_HELD(500) > 0)
|
||||
{
|
||||
LEDsoff();
|
||||
Dbprintf("Quiting");
|
||||
return;
|
||||
}
|
||||
start_time = 0;//eof_time;
|
||||
res = SendDataTag(cmd, 4, true, true, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time, &recvLen);
|
||||
if (res < 0)
|
||||
continue;
|
||||
if (recvLen<10) // error: recv too short
|
||||
{
|
||||
Dbprintf("recvLen<10");
|
||||
continue;
|
||||
}
|
||||
if (!CheckCrc15(recv,recvLen)) // error crc not valid
|
||||
{
|
||||
Dbprintf("crc failed");
|
||||
continue;
|
||||
}
|
||||
if (recv[0] & ISO15_RES_ERROR) // received error from tag
|
||||
{
|
||||
Dbprintf("error received");
|
||||
continue;
|
||||
}
|
||||
|
||||
Dbprintf("Start dumping tag");
|
||||
|
||||
memset(tag, 0, sizeof(iso15_tag_t));
|
||||
memcpy(tag->uid, &recv[2], 8);
|
||||
|
||||
i=10;
|
||||
if (recv[1] & 0x01)
|
||||
tag->dsfid = recv[i++];
|
||||
if (recv[1] & 0x02)
|
||||
tag->afi = recv[i++];
|
||||
if (recv[1] & 0x04)
|
||||
{
|
||||
tag->pagesCount = recv[i++]+1;
|
||||
tag->bytesPerPage = recv[i++]+1;
|
||||
}
|
||||
else
|
||||
{ // Set default tag values (if can't be readed in SYSINFO)
|
||||
tag->bytesPerPage = 4;
|
||||
tag->pagesCount = 128;
|
||||
}
|
||||
if (recv[1] & 0x08)
|
||||
tag->ic = recv[i++];
|
||||
break;
|
||||
}
|
||||
|
||||
cmd[0] = ISO15_REQ_DATARATE_HIGH | ISO15_REQ_OPTION;
|
||||
cmd[1] = ISO15693_READBLOCK;
|
||||
|
||||
uint8_t blocknum = 0;
|
||||
int retry;
|
||||
|
||||
for (retry = 0; retry < 8; retry++) {
|
||||
if (blocknum >= tag->pagesCount)
|
||||
break;
|
||||
|
||||
cmd[2] = blocknum;
|
||||
AddCrc15(cmd, 3);
|
||||
|
||||
start_time = eof_time;
|
||||
res = SendDataTag(cmd, 5, false, true, recv, sizeof(recv), start_time, ISO15693_READER_TIMEOUT, &eof_time, &recvLen);
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
SpinDelay(100);
|
||||
continue;
|
||||
}
|
||||
if (recvLen < 4 + tag->bytesPerPage) // error: recv too short
|
||||
{
|
||||
Dbprintf("recvLen < 4 + tag->bytesPerPage");
|
||||
continue;
|
||||
}
|
||||
if (!CheckCrc15(recv,recvLen)) // error crc not valid
|
||||
{
|
||||
Dbprintf("crc failed");
|
||||
continue;
|
||||
}
|
||||
if (recv[0] & ISO15_RES_ERROR) // received error from tag
|
||||
{
|
||||
Dbprintf("error received");
|
||||
continue;
|
||||
}
|
||||
|
||||
tag->locks[blocknum] = recv[1];
|
||||
memcpy(&tag->data[blocknum * tag->bytesPerPage], recv + 2, tag->bytesPerPage);
|
||||
retry = 0;
|
||||
blocknum++;
|
||||
}
|
||||
|
||||
LEDsoff();
|
||||
if (retry >= 8)
|
||||
{
|
||||
Dbprintf("Max retry attemps exeeded");
|
||||
Dbprintf("-=[ exit ]=-");
|
||||
return;
|
||||
}
|
||||
|
||||
Dbprintf("Tag dumped");
|
||||
Dbprintf("Start simulation");
|
||||
|
||||
SimTagIso15693(0, 0);
|
||||
|
||||
Dbprintf("Simulation stopped");
|
||||
SpinDelay(200);
|
||||
|
||||
uint32_t trace_len = BigBuf_get_traceLen();
|
||||
#ifndef WITH_FLASH
|
||||
// Keep stuff in BigBuf for USB/BT dumping
|
||||
if (trace_len > 0)
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
#else
|
||||
// Write stuff to spiffs logfile
|
||||
if (trace_len > 0) {
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
|
||||
uint8_t *trace_buffer = BigBuf_get_addr();
|
||||
if (!exists_in_spiffs(HF_15693SSIM_LOGFILE)) {
|
||||
rdv40_spiffs_write(
|
||||
HF_15693SIM_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
Dbprintf("[!] Wrote trace to "HF_15693SIM_LOGFILE);
|
||||
} else {
|
||||
rdv40_spiffs_append(
|
||||
HF_15693SIM_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
Dbprintf("[!] Appended trace to "HF_15693SIM_LOGFILE);
|
||||
}
|
||||
} else {
|
||||
Dbprintf("[!] Trace buffer is empty, nothing to write!");
|
||||
}
|
||||
|
||||
LED_D_ON();
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_D_OFF();
|
||||
|
||||
SpinErr(LED_A, 200, 5);
|
||||
SpinDelay(100);
|
||||
#endif
|
||||
|
||||
Dbprintf("-=[ exit ]=-");
|
||||
LEDsoff();
|
||||
DownloadTraceInstructions();
|
||||
}
|
|
@ -107,7 +107,7 @@
|
|||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
// buffers
|
||||
#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet
|
||||
#define ISO15693_MAX_RESPONSE_LENGTH 2116 // allows read multiple block with the maximum block size of 256bits and a maximum block number of 64 with REQ_OPTION (lock status for each block).
|
||||
#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet
|
||||
|
||||
// 32 + 2 crc + 1
|
||||
|
@ -120,6 +120,7 @@
|
|||
//#define Crc(data, len) Crc(CRC_15693, (data), (len))
|
||||
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
|
||||
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#define CalculateCrc15(data, len) Crc16ex(CRC_15693, (data), (len))
|
||||
|
||||
static void BuildIdentifyRequest(uint8_t *cmd);
|
||||
|
||||
|
@ -1200,42 +1201,39 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader)
|
|||
break;
|
||||
|
||||
case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF:
|
||||
reader->posCount++;
|
||||
if (bit) { // detected rising edge
|
||||
if (reader->posCount < 4) { // rising edge too early (nominally expected at 5)
|
||||
if (reader->posCount < 2) { // rising edge too early (nominally expected at 4)
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
} else { // SOF
|
||||
reader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF;
|
||||
reader->posCount = 1;
|
||||
}
|
||||
} else {
|
||||
if (reader->posCount > 5) { // stayed low for too long
|
||||
reader->posCount++;
|
||||
if (reader->posCount > 6) { // stayed low for too long
|
||||
DecodeReaderReset(reader);
|
||||
} else {
|
||||
// do nothing, keep waiting
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF:
|
||||
|
||||
reader->posCount++;
|
||||
|
||||
if (bit == false) { // detected a falling edge
|
||||
|
||||
if (reader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest)
|
||||
if (!bit) { // detected a falling edge
|
||||
if (reader->posCount < 14) { // falling edge too early (nominally expected at 16 earliest)
|
||||
DecodeReaderReset(reader);
|
||||
} else if (reader->posCount < 23) { // SOF for 1 out of 4 coding
|
||||
} else if (reader->posCount <= 18) { // SOF for 1 out of 4 coding
|
||||
reader->Coding = CODING_1_OUT_OF_4;
|
||||
reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF;
|
||||
} else if (reader->posCount < 28) { // falling edge too early (nominally expected at 29 latest)
|
||||
reader->posCount = 1;
|
||||
} else if (reader->posCount < 22) { // falling edge too early (nominally expected at 24 latest)
|
||||
DecodeReaderReset(reader);
|
||||
} else { // SOF for 1 out of 256 coding
|
||||
reader->Coding = CODING_1_OUT_OF_256;
|
||||
reader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF;
|
||||
reader->posCount = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (reader->posCount > 29) { // stayed high for too long
|
||||
reader->posCount++;
|
||||
if (reader->posCount > 26) { // stayed high for too long
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
} else {
|
||||
// do nothing, keep waiting
|
||||
|
@ -1244,60 +1242,42 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader)
|
|||
break;
|
||||
|
||||
case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF:
|
||||
|
||||
reader->posCount++;
|
||||
|
||||
if (bit) { // detected rising edge
|
||||
if (reader->Coding == CODING_1_OUT_OF_256) {
|
||||
if (reader->posCount < 32) { // rising edge too early (nominally expected at 33)
|
||||
if (reader->posCount < 2) { // rising edge too early (nominally expected at 8)
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
} else {
|
||||
reader->posCount = 1;
|
||||
reader->bitCount = 0;
|
||||
if (reader->Coding == CODING_1_OUT_OF_256) {
|
||||
reader->bitCount = 1;
|
||||
reader->byteCount = 0;
|
||||
reader->sum1 = 1;
|
||||
reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256;
|
||||
LED_B_ON();
|
||||
}
|
||||
reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256;
|
||||
} else { // CODING_1_OUT_OF_4
|
||||
if (reader->posCount < 24) { // rising edge too early (nominally expected at 25)
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
} else {
|
||||
reader->posCount = 1;
|
||||
reader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (reader->Coding == CODING_1_OUT_OF_256) {
|
||||
if (reader->posCount > 34) { // signal stayed low for too long
|
||||
reader->posCount++;
|
||||
if (reader->posCount > 6) { // signal stayed low for too long
|
||||
DecodeReaderReset(reader);
|
||||
} else {
|
||||
// do nothing, keep waiting
|
||||
}
|
||||
} else { // CODING_1_OUT_OF_4
|
||||
if (reader->posCount > 26) { // signal stayed low for too long
|
||||
DecodeReaderReset(reader);
|
||||
} else {
|
||||
// do nothing, keep waiting
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4:
|
||||
|
||||
if (bit) {
|
||||
reader->posCount++;
|
||||
|
||||
if (bit) {
|
||||
if (reader->posCount == 9) {
|
||||
reader->posCount = 1;
|
||||
if (reader->posCount == 8) {
|
||||
reader->posCount = 0;
|
||||
reader->bitCount = 0;
|
||||
reader->byteCount = 0;
|
||||
reader->sum1 = 1;
|
||||
reader->sum1 = 0;
|
||||
reader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4;
|
||||
LED_B_ON();
|
||||
} else {
|
||||
// do nothing, keep waiting
|
||||
}
|
||||
} else { // unexpected falling edge
|
||||
DecodeReaderReset(reader);
|
||||
|
@ -1305,43 +1285,55 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader)
|
|||
break;
|
||||
|
||||
case STATE_READER_RECEIVE_DATA_1_OUT_OF_4:
|
||||
|
||||
reader->posCount++;
|
||||
|
||||
if (reader->posCount == 1) {
|
||||
|
||||
reader->sum1 = bit ? 1 : 0;
|
||||
|
||||
} else if (reader->posCount <= 4) {
|
||||
|
||||
if (bit)
|
||||
if (!bit) {
|
||||
reader->sum1++;
|
||||
|
||||
} else if (reader->posCount == 5) {
|
||||
|
||||
reader->sum2 = bit ? 1 : 0;
|
||||
|
||||
} else {
|
||||
if (bit)
|
||||
reader->sum2++;
|
||||
}
|
||||
|
||||
if (reader->posCount == 8) {
|
||||
reader->posCount = 0;
|
||||
if (reader->sum1 <= 1 && reader->sum2 >= 3) { // EOF
|
||||
if (reader->sum1 == 1) { // first low bit
|
||||
if (reader->posCount <= 6) { // bits : 00
|
||||
reader->shiftReg >>= 2;
|
||||
//reader->shiftReg |= (0 << 6);
|
||||
reader->bitCount += 2;
|
||||
reader->posCount = -28;
|
||||
} else if (reader->posCount <= 9) { // EOF
|
||||
LED_B_OFF(); // Finished receiving
|
||||
DecodeReaderReset(reader);
|
||||
if (reader->byteCount != 0) {
|
||||
if (reader->byteCount > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (reader->sum1 >= 3 && reader->sum2 <= 1) { // detected a 2bit position
|
||||
} else if (reader->posCount <= 14) { // bits : 01
|
||||
reader->shiftReg >>= 2;
|
||||
reader->shiftReg |= (reader->bitCount << 6);
|
||||
reader->shiftReg |= (1 << 6);
|
||||
reader->bitCount += 2;
|
||||
reader->posCount = -20;
|
||||
} else if (reader->posCount < 18) { // unexpected falling edge
|
||||
DecodeReaderReset(reader);
|
||||
if (reader->byteCount >= 0) {
|
||||
reader->output[reader->byteCount++] = reader->posCount;
|
||||
reader->output[reader->byteCount++] = reader->bitCount;
|
||||
reader->output[reader->byteCount++] = 0x42;
|
||||
return true;
|
||||
}
|
||||
} else if (reader->posCount <= 22) { // bits : 10
|
||||
reader->shiftReg >>= 2;
|
||||
reader->shiftReg |= (2 << 6);
|
||||
reader->bitCount += 2;
|
||||
reader->posCount = -12;
|
||||
} else if (reader->posCount < 26) { // unexpected falling edge
|
||||
DecodeReaderReset(reader);
|
||||
if (reader->byteCount >= 0) {
|
||||
reader->output[reader->byteCount++] = reader->posCount;
|
||||
reader->output[reader->byteCount++] = reader->bitCount;
|
||||
reader->output[reader->byteCount++] = 0x43;
|
||||
return true;
|
||||
}
|
||||
} else { // bits : 11
|
||||
reader->shiftReg >>= 2;
|
||||
reader->shiftReg |= (3 << 6);
|
||||
reader->bitCount += 2;
|
||||
reader->posCount = -4;
|
||||
}
|
||||
|
||||
if (reader->bitCount == 15) { // we have a full byte
|
||||
|
||||
if (reader->bitCount == 8)
|
||||
{
|
||||
reader->output[reader->byteCount++] = reader->shiftReg;
|
||||
if (reader->byteCount > reader->byteCountMax) {
|
||||
// buffer overflow, give up
|
||||
|
@ -1358,9 +1350,38 @@ static int RAMFUNC Handle15693SampleFromReader(bool bit, DecodeReader_t *reader)
|
|||
reader->state = STATE_READER_RECEIVE_JAMMING;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (reader->sum1 > 6) { // too long low bit
|
||||
DecodeReaderReset(reader);
|
||||
if (reader->byteCount >= 0) {
|
||||
reader->output[reader->byteCount++] = reader->posCount;
|
||||
reader->output[reader->byteCount++] = reader->bitCount;
|
||||
reader->output[reader->byteCount++] = 0x44;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reader->bitCount++;
|
||||
reader->posCount++;
|
||||
if (reader->posCount > 30) {
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
if (reader->byteCount >= 0) {
|
||||
reader->output[reader->byteCount++] = reader->posCount;
|
||||
reader->output[reader->byteCount++] = reader->bitCount;
|
||||
reader->output[reader->byteCount++] = 0x45;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (reader->sum1 == 1) {
|
||||
reader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF;
|
||||
if (reader->byteCount >= 0) {
|
||||
reader->output[reader->byteCount++] = reader->posCount;
|
||||
reader->output[reader->byteCount++] = reader->bitCount;
|
||||
reader->output[reader->byteCount++] = 0x46;
|
||||
return true;
|
||||
}
|
||||
} else if (reader->sum1 > 1) {
|
||||
reader->posCount += reader->sum1;
|
||||
reader->sum1 = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2111,20 +2132,61 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
// free eventually allocated BigBuf memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
Iso15693InitTag();
|
||||
iso15_tag_t *tag = (iso15_tag_t*) BigBuf_get_EM_addr();
|
||||
if (tag == NULL)
|
||||
{
|
||||
Dbprintf("Can't allocate emulator memory");
|
||||
reply_ng(CMD_HF_ISO15693_SIMULATE, PM3_EFAILED, NULL, 0);
|
||||
return;
|
||||
}
|
||||
if (uid != NULL) { // new tag (need initialization)
|
||||
uint8_t nullUid[8] = { 0 };
|
||||
if (memcmp(uid, nullUid, 8) != 0)
|
||||
{ // simulate a new tag bazed on client parameters
|
||||
memcpy(tag->uid, uid, 8);
|
||||
tag->dsfid = 0;
|
||||
tag->dsfidLock = false;
|
||||
tag->afi = 0;
|
||||
tag->afiLock = false;
|
||||
tag->bytesPerPage = (block_size > 0) ? block_size : 4;
|
||||
tag->pagesCount = 64;
|
||||
tag->ic = 0;
|
||||
memset(tag->locks, 0, sizeof(tag->locks));
|
||||
memset(tag->data, 0, sizeof(tag->data));
|
||||
}
|
||||
}
|
||||
if (tag->pagesCount > ISO15693_TAG_MAX_PAGES || \
|
||||
tag->pagesCount * tag->bytesPerPage > ISO15693_TAG_MAX_SIZE ||
|
||||
tag->pagesCount == 0 || tag->bytesPerPage == 0) {
|
||||
Dbprintf("Tag size error: pagesCount = %d, bytesPerPage=%d", tag->pagesCount, tag->bytesPerPage);
|
||||
reply_ng(CMD_HF_ISO15693_SIMULATE, PM3_EOPABORTED, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Iso15693InitTag(); // init simulator
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X block size %d", uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7], block_size);
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("ISO-15963 Simulating uid: %02X%02X%02X%02X%02X%02X%02X%02X, %u bytes/blocks x %u blocks", tag->uid[7], tag->uid[6], tag->uid[5], tag->uid[4], tag->uid[3], tag->uid[2], tag->uid[1], tag->uid[0], tag->bytesPerPage, tag->pagesCount);
|
||||
|
||||
LED_C_ON();
|
||||
|
||||
enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD;
|
||||
|
||||
bool button_pressed = false;
|
||||
int vHf; // in mV
|
||||
|
||||
bool exit_loop = false;
|
||||
uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH] = {0};
|
||||
uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH] = {0};
|
||||
uint8_t mask_len = 0;
|
||||
uint8_t maskCpt = 0;
|
||||
uint8_t cmdCpt = 0;
|
||||
uint16_t recvLen = 0;
|
||||
uint8_t error = 0;
|
||||
uint8_t pageNum = 0;
|
||||
uint8_t nbPages = 0;
|
||||
uint8_t pwdId = 0;
|
||||
|
||||
while (exit_loop == false) {
|
||||
|
||||
button_pressed = BUTTON_PRESS();
|
||||
|
@ -2134,11 +2196,11 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
WDT_HIT();
|
||||
|
||||
// find reader field
|
||||
if (chip_state == NO_FIELD) {
|
||||
if (tag->state == TAG_STATE_NO_FIELD) {
|
||||
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15;
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
chip_state = IDLE;
|
||||
tag->state = TAG_STATE_READY;
|
||||
LED_A_ON();
|
||||
} else {
|
||||
continue;
|
||||
|
@ -2146,7 +2208,6 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
}
|
||||
|
||||
// Listen to reader
|
||||
uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH];
|
||||
uint32_t reader_eof_time = 0;
|
||||
int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time);
|
||||
if (cmd_len < 0) {
|
||||
|
@ -2154,171 +2215,365 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO: check more flags
|
||||
if ((cmd_len >= 5) && (cmd[0] & ISO15_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
if (cmd_len <= 3)
|
||||
continue;
|
||||
|
||||
// Shorten 0 terminated msgs
|
||||
// (Some times received commands are prolonged with a random number of 0 bytes...)
|
||||
while (cmd[cmd_len-1] == 0) {
|
||||
cmd_len--;
|
||||
if (cmd_len <= 3)
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("%d bytes read from reader:", cmd_len);
|
||||
Dbhexdump(cmd_len, cmd, false);
|
||||
}
|
||||
|
||||
if (cmd_len < 3)
|
||||
continue;
|
||||
|
||||
// Check CRC and drop received cmd with bad CRC
|
||||
uint16_t crc = CalculateCrc15(cmd, cmd_len - 2);
|
||||
if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) {
|
||||
crc = CalculateCrc15(cmd, ++cmd_len - 2); // if crc end with 00
|
||||
if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) {
|
||||
crc = CalculateCrc15(cmd, ++cmd_len - 2); // if crc end with 00 00
|
||||
if ((( crc & 0xff ) != cmd[cmd_len - 2]) || (( crc >> 8 ) != cmd[cmd_len - 1])) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("CrcFail!, expected CRC=%02X%02X", crc & 0xff, crc >> 8);
|
||||
continue;
|
||||
}
|
||||
else if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("CrcOK");
|
||||
}
|
||||
else if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("CrcOK");
|
||||
}
|
||||
else if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("CrcOK");
|
||||
|
||||
cmd_len -= 2; // remove the CRC from the cmd
|
||||
recvLen = 0;
|
||||
|
||||
tag->expectFast = ((cmd[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH);
|
||||
tag->expectFsk = ((cmd[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO);
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
if (tag->expectFsk)
|
||||
Dbprintf("ISO15_REQ_SUBCARRIER_TWO support is currently experimental!");
|
||||
if ((cmd[0] & ISO15_REQ_PROTOCOL_EXT) == ISO15_REQ_PROTOCOL_EXT)
|
||||
Dbprintf("ISO15_REQ_PROTOCOL_EXT not supported!");
|
||||
if ((cmd[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION)
|
||||
Dbprintf("ISO15_REQ_OPTION not supported!");
|
||||
}
|
||||
|
||||
if (((cmd[0] & ISO15_REQ_INVENTORY) == ISO15_REQ_INVENTORY) && tag->state != TAG_STATE_SILENCED) {
|
||||
// REQ_INVENTORY flaged requests are interpreted as a INVENTORY no matter
|
||||
// what is the CMD (as observed from various actual tags)
|
||||
|
||||
// TODO: support colision avoidances
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
Dbprintf("Inventory req");
|
||||
if ((cmd[0] & ISO15_REQINV_SLOT1) == ISO15_REQINV_SLOT1)
|
||||
Dbprintf("ISO15_REQINV_SLOT1/SLOT16 not supported!");
|
||||
}
|
||||
|
||||
cmdCpt = 2;
|
||||
|
||||
// Check AFI
|
||||
if ((cmd[0] & ISO15_REQINV_AFI) == ISO15_REQINV_AFI) {
|
||||
if (cmd[cmdCpt] != tag->afi && cmd[cmdCpt] != 0)
|
||||
continue; // bad AFI : drop request
|
||||
cmdCpt++;
|
||||
}
|
||||
|
||||
// Check mask
|
||||
if (cmdCpt >= cmd_len)
|
||||
continue; // mask is not present : drop request
|
||||
mask_len = cmd[cmdCpt++];
|
||||
|
||||
maskCpt = 0;
|
||||
|
||||
while (mask_len >= 8 && cmdCpt < (uint8_t)cmd_len && maskCpt < 8) { // Byte comparison
|
||||
if (cmd[cmdCpt++] != tag->uid[maskCpt++]) {
|
||||
error++; // mask don't match : drop request
|
||||
break;
|
||||
}
|
||||
mask_len -= 8;
|
||||
}
|
||||
|
||||
if (mask_len > 0 && cmdCpt >= cmd_len)
|
||||
continue; // mask is shorter than declared mask lenght: drop request
|
||||
|
||||
while (mask_len > 0) { // Bit comparison
|
||||
mask_len--;
|
||||
if (((cmd[cmdCpt] >> mask_len) & 1) != ((tag->uid[maskCpt] >> mask_len) & 1)) {
|
||||
error++; // mask don't match : drop request
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error > 0)
|
||||
continue;
|
||||
|
||||
// No error: Answer
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recv[1] = tag->dsfid;
|
||||
memcpy(&recv[2], tag->uid, 8);
|
||||
recvLen = 10;
|
||||
}
|
||||
else {
|
||||
if ((cmd[0] & ISO15_REQ_SELECT) == ISO15_REQ_SELECT) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Selected Request");
|
||||
if (tag->state != TAG_STATE_SELECTED)
|
||||
continue; // drop selected request if not selected
|
||||
tag->state = TAG_STATE_READY; // Select flag set if already selected : unselect
|
||||
}
|
||||
|
||||
cmdCpt = 2;
|
||||
if ((cmd[0] & ISO15_REQ_ADDRESS) == ISO15_REQ_ADDRESS) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Addressed Request");
|
||||
if (cmd_len < cmdCpt+8)
|
||||
continue;
|
||||
if (memcmp(&cmd[cmdCpt], tag->uid, 8) != 0)
|
||||
{
|
||||
if (cmd_len < cmdCpt+9 || memcmp(&cmd[cmdCpt+1], tag->uid, 8) != 0)
|
||||
{ // check uid even if manifacturer byte is present
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Address don't match tag uid");
|
||||
if (cmd[1] == ISO15693_SELECT)
|
||||
tag->state = TAG_STATE_READY; // we are not anymore the selected TAG
|
||||
continue; // drop addressed request with other uid
|
||||
}
|
||||
cmdCpt++;
|
||||
}
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Address match tag uid");
|
||||
cmdCpt+=8;
|
||||
}
|
||||
else if (tag->state == TAG_STATE_SILENCED)
|
||||
{
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Unaddressed request in quiet state: drop");
|
||||
continue; // drop unadressed request in quiet state
|
||||
}
|
||||
|
||||
switch(cmd[1]) {
|
||||
case ISO15693_INVENTORY:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Inventory cmd");
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recv[1] = tag->dsfid;
|
||||
memcpy(&recv[2], tag->uid, 8);
|
||||
recvLen = 10;
|
||||
break;
|
||||
case ISO15693_STAYQUIET:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("StayQuiet cmd");
|
||||
tag->state = TAG_STATE_SILENCED;
|
||||
break;
|
||||
case ISO15693_READBLOCK:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadBlock cmd");
|
||||
pageNum = cmd[cmdCpt++];
|
||||
if (pageNum >= tag->pagesCount)
|
||||
error = ISO15_ERROR_BLOCK_UNAVAILABLE;
|
||||
else {
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
if ((cmd[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION) { // ask for lock status
|
||||
recv[1] = tag->locks[pageNum];
|
||||
recvLen++;
|
||||
}
|
||||
for (uint8_t i = 0 ; i < tag->bytesPerPage ; i++)
|
||||
recv[recvLen+i] = tag->data[(pageNum * tag->bytesPerPage) + i];
|
||||
recvLen += tag->bytesPerPage;
|
||||
}
|
||||
break;
|
||||
case ISO15693_WRITEBLOCK:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteBlock cmd");
|
||||
pageNum = cmd[cmdCpt++];
|
||||
if (pageNum >= tag->pagesCount)
|
||||
error = ISO15_ERROR_BLOCK_UNAVAILABLE;
|
||||
else {
|
||||
for (uint8_t i = 0 ; i < tag->bytesPerPage ; i++)
|
||||
tag->data[(pageNum*tag->bytesPerPage) + i] = cmd[i + cmdCpt];
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_LOCKBLOCK:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockBlock cmd");
|
||||
pageNum = cmd[cmdCpt++];
|
||||
if (pageNum >= tag->pagesCount)
|
||||
error = ISO15_ERROR_BLOCK_UNAVAILABLE;
|
||||
else if (tag->locks[pageNum])
|
||||
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY;
|
||||
else {
|
||||
tag->locks[pageNum] = 1;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_READ_MULTI_BLOCK:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadMultiBlock cmd");
|
||||
pageNum = cmd[cmdCpt++];
|
||||
nbPages = cmd[cmdCpt++];
|
||||
if (pageNum+nbPages >= tag->pagesCount)
|
||||
error = ISO15_ERROR_BLOCK_UNAVAILABLE;
|
||||
else {
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
for (int i = 0 ; i < (nbPages + 1) * tag->bytesPerPage && \
|
||||
recvLen + 3 < ISO15693_MAX_RESPONSE_LENGTH ; i++) {
|
||||
if ((i % tag->bytesPerPage) == 0 && (cmd[0] & ISO15_REQ_OPTION))
|
||||
recv[recvLen++] = tag->locks[pageNum + (i / tag->bytesPerPage)];
|
||||
recv[recvLen++] = tag->data[(pageNum * tag->bytesPerPage) + i];
|
||||
}
|
||||
if (recvLen + 3 > ISO15693_MAX_RESPONSE_LENGTH) // limit response size
|
||||
recvLen = ISO15693_MAX_RESPONSE_LENGTH - 3; // to avoid overflow
|
||||
}
|
||||
break;
|
||||
case ISO15693_WRITE_AFI:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteAFI cmd");
|
||||
if (tag->afiLock)
|
||||
error = ISO15_ERROR_BLOCK_LOCKED;
|
||||
else {
|
||||
tag->afi = cmd[cmdCpt++];
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_LOCK_AFI:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockAFI cmd");
|
||||
if (tag->afiLock)
|
||||
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY;
|
||||
else {
|
||||
tag->afiLock = true;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_WRITE_DSFID:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("WriteDSFID cmd");
|
||||
if (tag->dsfidLock)
|
||||
error = ISO15_ERROR_BLOCK_LOCKED;
|
||||
else {
|
||||
tag->dsfid = cmd[cmdCpt++];
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_LOCK_DSFID:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("LockDSFID cmd");
|
||||
if (tag->dsfidLock)
|
||||
error = ISO15_ERROR_BLOCK_LOCKED_ALREADY;
|
||||
else {
|
||||
tag->dsfidLock = true;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
}
|
||||
break;
|
||||
case ISO15693_SELECT:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Select cmd");
|
||||
tag->state = TAG_STATE_SELECTED;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
break;
|
||||
case ISO15693_RESET_TO_READY:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("ResetToReady cmd");
|
||||
tag->state = TAG_STATE_READY;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
break;
|
||||
case ISO15693_GET_SYSTEM_INFO:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("GetSystemInfo cmd");
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recv[1] = 0x0f; // sysinfo contain all info
|
||||
memcpy(&recv[2], tag->uid, 8);
|
||||
recv[10] = tag->dsfid;
|
||||
recv[11] = tag->afi;
|
||||
recv[12] = tag->pagesCount - 1;
|
||||
recv[13] = tag->bytesPerPage - 1;
|
||||
recv[14] = tag->ic;
|
||||
recvLen = 15;
|
||||
break;
|
||||
case ISO15693_READ_MULTI_SECSTATUS:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("ReadMultiSecStatus cmd");
|
||||
pageNum = cmd[cmdCpt++];
|
||||
nbPages = cmd[cmdCpt++];
|
||||
if (pageNum + nbPages >= tag->pagesCount)
|
||||
error = ISO15_ERROR_BLOCK_UNAVAILABLE;
|
||||
else {
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
for (uint8_t i = 0 ; i < nbPages + 1 ; i++)
|
||||
recv[recvLen++] = tag->locks[pageNum + i];
|
||||
}
|
||||
break;
|
||||
case ISO15693_GET_RANDOM_NUMBER:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("GetRandomNumber cmd");
|
||||
tag->random[0] = (uint8_t)(reader_eof_time) ^ 0xFF; // poor random number
|
||||
tag->random[1] = (uint8_t)(reader_eof_time >> 8) ^ 0xFF;
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recv[1] = tag->random[0]; // poor random number
|
||||
recv[2] = tag->random[1];
|
||||
recvLen = 3;
|
||||
break;
|
||||
case ISO15693_SET_PASSWORD:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("SetPassword cmd");
|
||||
if (cmd_len > cmdCpt+5)
|
||||
cmdCpt++; // skip manifacturer code
|
||||
if (cmd_len > cmdCpt+4)
|
||||
{
|
||||
pwdId = cmd[cmdCpt++];
|
||||
if (pwdId == 4) // Privacy password
|
||||
{
|
||||
tag->privacyPasswd[0] = cmd[cmdCpt] ^ tag->random[0];
|
||||
tag->privacyPasswd[1] = cmd[cmdCpt+1] ^ tag->random[1];
|
||||
tag->privacyPasswd[2] = cmd[cmdCpt+2] ^ tag->random[0];
|
||||
tag->privacyPasswd[3] = cmd[cmdCpt+3] ^ tag->random[1];
|
||||
}
|
||||
}
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
break;
|
||||
case ISO15693_ENABLE_PRIVACY:
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("EnablePrivacy cmd");
|
||||
// not realy entering privacy mode
|
||||
// just return NOERROR
|
||||
recv[0] = ISO15_NOERROR;
|
||||
recvLen = 1;
|
||||
break;
|
||||
default:
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("ISO15693 CMD 0x%2X not supported", cmd[1]);
|
||||
|
||||
error = ISO15_ERROR_CMD_NOT_SUP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (error != 0) { // Error happened
|
||||
recv[0] = ISO15_RES_ERROR;
|
||||
recv[1] = error;
|
||||
recvLen = 2;
|
||||
error = 0;
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("ERROR 0x%2X in received request", error);
|
||||
}
|
||||
}
|
||||
|
||||
if (recvLen > 0) { // We need to answer
|
||||
AddCrc15(recv, recvLen);
|
||||
recvLen += 2;
|
||||
CodeIso15693AsTag(recv, recvLen);
|
||||
tosend_t *ts = get_tosend();
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
// Build INVENTORY command
|
||||
uint8_t resp_inv[CMD_INV_RESP] = {0};
|
||||
|
||||
resp_inv[0] = 0; // No error, no protocol format extension
|
||||
resp_inv[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported
|
||||
|
||||
// 64-bit UID
|
||||
resp_inv[2] = uid[7];
|
||||
resp_inv[3] = uid[6];
|
||||
resp_inv[4] = uid[5];
|
||||
resp_inv[5] = uid[4];
|
||||
resp_inv[6] = uid[3];
|
||||
resp_inv[7] = uid[2];
|
||||
resp_inv[8] = uid[1];
|
||||
resp_inv[9] = uid[0];
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_inv, 10);
|
||||
CodeIso15693AsTag(resp_inv, CMD_INV_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_inv, CMD_INV_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
|
||||
chip_state = SELECTED;
|
||||
if (tag->expectFsk) { // Not suppoted yet
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("%ERROR: FSK answers are not supported yet");
|
||||
//TransmitTo15693ReaderFSK(ts->buf,ts->max, &response_time, 0, !tag->expectFast);
|
||||
}
|
||||
else
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, !tag->expectFast);
|
||||
|
||||
// GET_SYSTEM_INFO
|
||||
if ((cmd[1] == ISO15693_GET_SYSTEM_INFO)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
// Build GET_SYSTEM_INFO response
|
||||
uint8_t resp_sysinfo[CMD_SYSINFO_RESP] = {0};
|
||||
|
||||
resp_sysinfo[0] = 0; // Response flags.
|
||||
resp_sysinfo[1] = 0x0F; // Information flags (0x0F - DSFID, AFI, Mem size, IC)
|
||||
|
||||
// 64-bit UID
|
||||
resp_sysinfo[2] = uid[7];
|
||||
resp_sysinfo[3] = uid[6];
|
||||
resp_sysinfo[4] = uid[5];
|
||||
resp_sysinfo[5] = uid[4];
|
||||
resp_sysinfo[6] = uid[3];
|
||||
resp_sysinfo[7] = uid[2];
|
||||
resp_sysinfo[8] = uid[1];
|
||||
resp_sysinfo[9] = uid[0];
|
||||
|
||||
resp_sysinfo[10] = 0; // DSFID
|
||||
resp_sysinfo[11] = 0; // AFI
|
||||
|
||||
resp_sysinfo[12] = 0x1F; // Block count
|
||||
resp_sysinfo[13] = block_size - 1; // Block size.
|
||||
resp_sysinfo[14] = 0x01; // IC reference.
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_sysinfo, 15);
|
||||
CodeIso15693AsTag(resp_sysinfo, CMD_SYSINFO_RESP);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_sysinfo, CMD_SYSINFO_RESP, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
}
|
||||
|
||||
// READ_BLOCK and READ_MULTI_BLOCK
|
||||
if ((cmd[1] == ISO15693_READBLOCK) || (cmd[1] == ISO15693_READ_MULTI_BLOCK)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
bool addressed = cmd[0] & ISO15_REQ_ADDRESS;
|
||||
bool option = cmd[0] & ISO15_REQ_OPTION;
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
uint8_t address_offset = 0;
|
||||
if (addressed) {
|
||||
address_offset = 8;
|
||||
}
|
||||
|
||||
uint8_t block_idx = cmd[2 + address_offset];
|
||||
uint8_t block_count = 1;
|
||||
if (cmd[1] == ISO15693_READ_MULTI_BLOCK) {
|
||||
block_count = cmd[3 + address_offset] + 1;
|
||||
}
|
||||
|
||||
// Build READ_(MULTI_)BLOCK response
|
||||
int response_length = 3 + block_size * block_count;
|
||||
int security_offset = 0;
|
||||
if (option) {
|
||||
response_length += block_count;
|
||||
security_offset = 1;
|
||||
}
|
||||
uint8_t resp_readblock[response_length];
|
||||
memset(resp_readblock, 0, response_length);
|
||||
|
||||
resp_readblock[0] = 0; // Response flags
|
||||
for (int j = 0; j < block_count; j++) {
|
||||
// where to put the data of the current block
|
||||
int work_offset = 1 + j * (block_size + security_offset);
|
||||
if (option) {
|
||||
resp_readblock[work_offset] = 0; // Security status
|
||||
}
|
||||
// Block data
|
||||
if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) {
|
||||
emlGet(
|
||||
resp_readblock + (work_offset + security_offset),
|
||||
block_size * (block_idx + j),
|
||||
block_size
|
||||
);
|
||||
} else {
|
||||
memset(resp_readblock + work_offset + security_offset, 0, block_size);
|
||||
}
|
||||
}
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_readblock, response_length - 2);
|
||||
CodeIso15693AsTag(resp_readblock, response_length);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_readblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
}
|
||||
|
||||
// WRITE_BLOCK and WRITE_MULTI_BLOCK
|
||||
if ((cmd[1] == ISO15693_WRITEBLOCK) || (cmd[1] == ISO15693_WRITE_MULTI_BLOCK)) {
|
||||
bool slow = !(cmd[0] & ISO15_REQ_DATARATE_HIGH);
|
||||
bool addressed = cmd[0] & ISO15_REQ_ADDRESS;
|
||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||
|
||||
uint8_t address_offset = 0;
|
||||
if (addressed) {
|
||||
address_offset = 8;
|
||||
}
|
||||
|
||||
uint8_t block_idx = cmd[2 + address_offset];
|
||||
uint8_t block_count = 1;
|
||||
uint8_t multi_offset = 0;
|
||||
if (cmd[1] == ISO15693_WRITE_MULTI_BLOCK) {
|
||||
block_count = cmd[3 + address_offset] + 1;
|
||||
multi_offset = 1;
|
||||
}
|
||||
uint8_t *data = cmd + 3 + address_offset + multi_offset;
|
||||
|
||||
// write data
|
||||
emlSet(data, (block_idx * block_size), (block_count * block_size));
|
||||
|
||||
// Build WRITE_(MULTI_)BLOCK response
|
||||
int response_length = 3;
|
||||
uint8_t resp_writeblock[response_length];
|
||||
memset(resp_writeblock, 0, response_length);
|
||||
resp_writeblock[0] = 0; // Response flags
|
||||
|
||||
// CRC
|
||||
AddCrc15(resp_writeblock, response_length - 2);
|
||||
CodeIso15693AsTag(resp_writeblock, response_length);
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
TransmitTo15693Reader(ts->buf, ts->max, &response_time, 0, slow);
|
||||
LogTrace_ISO15693(resp_writeblock, response_length, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
LogTrace_ISO15693(recv, recvLen, response_time * 32, (response_time * 32) + (ts->max * 32 * 64), NULL, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -532,15 +532,13 @@ static uint8_t arg_add_default(void *at[]) {
|
|||
}
|
||||
static uint16_t arg_get_raw_flag(uint8_t uidlen, bool unaddressed, bool scan, bool add_option) {
|
||||
uint16_t flags = 0;
|
||||
if (unaddressed) {
|
||||
// unaddressed mode may not be supported by all vendors
|
||||
flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY);
|
||||
;
|
||||
if (uidlen == 8 || scan || unaddressed) {
|
||||
flags = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY);
|
||||
}
|
||||
if (uidlen == 8) {
|
||||
flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS);
|
||||
}
|
||||
if (scan) {
|
||||
flags |= (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS);
|
||||
if ((!unaddressed) || scan)
|
||||
{
|
||||
flags |= ISO15_REQ_ADDRESS;
|
||||
}
|
||||
if (add_option) {
|
||||
flags |= (ISO15_REQ_OPTION);
|
||||
|
@ -1176,7 +1174,7 @@ static int CmdHF15ELoad(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
if (bytes_read > CARD_MEMORY_SIZE) {
|
||||
if (bytes_read > CARD_MEMORY_SIZE || bytes_read > sizeof(iso15_tag_t)) {
|
||||
PrintAndLogEx(FAILED, "Memory image too large.");
|
||||
free(data);
|
||||
return PM3_EINVARG;
|
||||
|
@ -1232,13 +1230,10 @@ static int CmdHF15ESave(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 15 esave",
|
||||
"Save emulator memory into two files (bin/json) ",
|
||||
"hf 15 esave -f hf-15-01020304"
|
||||
"hf 15 esave -b 8 -c 42 -f hf-15-01020304"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
|
||||
arg_int0(NULL, "bsize", "<dec>", "block size (def 4)"),
|
||||
arg_int0("c", "count", "<dec>", "number of blocks to export (def all)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -1246,20 +1241,9 @@ static int CmdHF15ESave(const char *Cmd) {
|
|||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
int blocksize = arg_get_int_def(ctx, 2, 4);
|
||||
int count = arg_get_int_def(ctx, 3, -1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// sanity checks
|
||||
if (blocksize < 4) {
|
||||
PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes");
|
||||
blocksize = 4;
|
||||
}
|
||||
|
||||
int bytes = CARD_MEMORY_SIZE;
|
||||
if (count > 0 && count * blocksize <= bytes) {
|
||||
bytes = count * blocksize;
|
||||
}
|
||||
int bytes = sizeof(iso15_tag_t);
|
||||
|
||||
// reserve memory
|
||||
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
|
||||
|
@ -1275,11 +1259,7 @@ static int CmdHF15ESave(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (blocksize == 8) {
|
||||
pm3_save_dump(filename, dump, bytes, jsf15_v3);
|
||||
} else {
|
||||
pm3_save_dump(filename, dump, bytes, jsf15_v2);
|
||||
}
|
||||
pm3_save_dump(filename, dump, bytes, jsf15_v4);
|
||||
|
||||
free(dump);
|
||||
return PM3_SUCCESS;
|
||||
|
@ -1297,6 +1277,13 @@ static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize, boo
|
|||
PrintAndLogEx(INFO, "----------- " _CYAN_("Tag Memory") " ---------------");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (blocksize == 0 || bytes == 0)
|
||||
{
|
||||
PrintAndLogEx(INFO, "Tag is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
print_hrule(blocksize);
|
||||
|
||||
char spaces[] = " ";
|
||||
|
@ -1354,38 +1341,46 @@ static void print_blocks_15693(uint8_t *data, uint16_t bytes, int blocksize, boo
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
static void print_emltag_info_15693(iso15_tag_t *tag) {
|
||||
PrintAndLogEx(SUCCESS, " TYPE... " _YELLOW_("%s"), getTagInfo_15(tag->uid));
|
||||
PrintAndLogEx(SUCCESS, " UID... " _GREEN_("%s"), iso15693_sprintUID(NULL, tag->uid));
|
||||
PrintAndLogEx(SUCCESS, " - DSFID [0x%02X]", tag->dsfid);
|
||||
PrintAndLogEx(SUCCESS, " - AFI [0x%02X]", tag->afi);
|
||||
PrintAndLogEx(SUCCESS, " - IC reference [0x%02X]", tag->ic);
|
||||
PrintAndLogEx(SUCCESS, " - Tag memory layout");
|
||||
PrintAndLogEx(SUCCESS, " %u bytes/blocks x %u blocks", tag->bytesPerPage, tag->pagesCount);
|
||||
}
|
||||
|
||||
static void print_emltag_15693(iso15_tag_t *tag, bool dense_output) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Emulator Tag Information") " ---------------------------");
|
||||
|
||||
print_emltag_info_15693(tag);
|
||||
|
||||
print_blocks_15693(tag->data, (tag->pagesCount * tag->bytesPerPage),
|
||||
tag->bytesPerPage, dense_output);
|
||||
}
|
||||
|
||||
static int CmdHF15EView(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 eview",
|
||||
"It displays emulator memory",
|
||||
"hf 15 eview\n"
|
||||
"hf 15 eview -b 8 -c 60\n"
|
||||
"hf 15 eview -z\n"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0("b", "blocksize", "<dec>", "block size (def 4)"),
|
||||
arg_int0("c", "count", "<dec>", "number of blocks to display (def all)"),
|
||||
arg_lit0("z", "dense", "dense dump output style"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
int blocksize = arg_get_int_def(ctx, 1, 4);
|
||||
int count = arg_get_int_def(ctx, 2, -1);
|
||||
bool dense_output = (g_session.dense_output || arg_get_lit(ctx, 3));
|
||||
bool dense_output = (g_session.dense_output || arg_get_lit(ctx, 1));
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// santity checks
|
||||
if (blocksize < 4) {
|
||||
PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes");
|
||||
blocksize = 4;
|
||||
}
|
||||
|
||||
int bytes = CARD_MEMORY_SIZE;
|
||||
if (count > 0 && count * blocksize <= bytes) {
|
||||
bytes = count * blocksize;
|
||||
}
|
||||
int bytes = sizeof(iso15_tag_t);
|
||||
|
||||
// reserve memory
|
||||
uint8_t *dump = calloc(bytes, sizeof(uint8_t));
|
||||
if (dump == NULL) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
|
@ -1399,7 +1394,8 @@ static int CmdHF15EView(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
print_blocks_15693(dump, bytes, blocksize, dense_output);
|
||||
print_emltag_15693((iso15_tag_t *)dump, dense_output);
|
||||
|
||||
free(dump);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1411,39 +1407,49 @@ static int CmdHF15Sim(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 15 sim",
|
||||
"Simulate a ISO-15693 tag\n",
|
||||
"hf 15 sim\n"
|
||||
"hf 15 sim -u E011223344556677");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<hex>", "UID, 8 hex bytes"),
|
||||
arg_str0("u", "uid", "<hex>", "UID, 8 hex bytes"),
|
||||
arg_int0("b", "blocksize", "<dec>", "block size (def 4)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
struct {
|
||||
uint8_t uid[HF15_UID_LENGTH];
|
||||
uint8_t block_size;
|
||||
} PACKED payload;
|
||||
memset(&payload, 0, sizeof(payload));
|
||||
|
||||
int uidlen = 0;
|
||||
CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen);
|
||||
if (uidlen != HF15_UID_LENGTH) {
|
||||
if (uidlen != 0 && uidlen != HF15_UID_LENGTH) {
|
||||
PrintAndLogEx(WARNING, "UID must include 8 hex bytes");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
payload.block_size = arg_get_int_def(ctx, 2, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
// santity checks
|
||||
if (payload.block_size < 4) {
|
||||
PrintAndLogEx(WARNING, "Blocksize too small, using default 4 bytes");
|
||||
payload.block_size = 4;
|
||||
if (uidlen == 0) // get UID from emulator
|
||||
{
|
||||
// reserve memory
|
||||
iso15_tag_t *tag = calloc(1, sizeof(iso15_tag_t));
|
||||
if (tag == NULL) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid));
|
||||
if (GetFromDevice(BIG_BUF_EML, (uint8_t*)tag, sizeof(iso15_tag_t), 0, NULL, 0, NULL, 2500, false) == false) {
|
||||
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
|
||||
free(tag);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, tag->uid));
|
||||
free(tag);
|
||||
}
|
||||
PrintAndLogEx(INFO, "Press " _YELLOW_("`pm3-button`") " to abort simulation");
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
@ -1748,7 +1754,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
// sanity checks
|
||||
if ((scan + unaddressed + uidlen) > 1) {
|
||||
if ((scan + unaddressed + (uidlen > 0)) > 1) {
|
||||
PrintAndLogEx(WARNING, "Select only one option /scan/unaddress/uid");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1759,8 +1765,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
}
|
||||
|
||||
// default fallback to scan for tag.
|
||||
// overriding unaddress parameter :)
|
||||
if (uidlen != HF15_UID_LENGTH) {
|
||||
if (uidlen != HF15_UID_LENGTH && !unaddressed) {
|
||||
scan = true;
|
||||
}
|
||||
|
||||
|
@ -1772,9 +1777,16 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
iso15_tag_t *tag = (iso15_tag_t *)calloc(1, sizeof(iso15_tag_t));
|
||||
|
||||
if (tag == NULL) {
|
||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
};
|
||||
|
||||
// ISO15693 Protocol params
|
||||
packet->raw[packet->rawlen++] = arg_get_raw_flag(uidlen, unaddressed, scan, add_option);
|
||||
packet->raw[packet->rawlen++] = ISO15693_READBLOCK;
|
||||
packet->raw[packet->rawlen++] = ISO15693_GET_SYSTEM_INFO;
|
||||
|
||||
bool used_uid = false;
|
||||
if (unaddressed == false) {
|
||||
|
@ -1796,9 +1808,8 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "Using unaddressed mode");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Using block size... " _YELLOW_("%d"), blocksize);
|
||||
}
|
||||
AddCrc15(packet->raw, packet->rawlen);
|
||||
packet->rawlen += 2;
|
||||
|
||||
// PM3 params
|
||||
packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT);
|
||||
|
@ -1806,31 +1817,69 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
packet->flags |= ISO15_HIGH_SPEED;
|
||||
}
|
||||
|
||||
// add CRC length (2) to packet and blockno (1)
|
||||
packet->rawlen += 3;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Reading memory");
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
|
||||
PrintAndLogEx(DEBUG, "iso15693 timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
int blocknum = 0;
|
||||
// memory.
|
||||
t15memory_t mem[256];
|
||||
if (resp.status == PM3_ETEAROFF) {
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
uint8_t data[256 * 4];
|
||||
memset(data, 0, sizeof(data));
|
||||
if (resp.length < 2) {
|
||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", resp.length);
|
||||
PrintAndLogEx(WARNING, "%%d)", resp.length);
|
||||
return PM3_EWRONGANSWER;
|
||||
}
|
||||
|
||||
// keep track of which block length tag returned?
|
||||
uint8_t blklen = blocksize;
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
uint8_t dCpt = 10;
|
||||
|
||||
ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length);
|
||||
|
||||
for (int retry = 0; (retry < 2 && blocknum < 0x100); retry++) {
|
||||
memcpy(tag->uid, &d[2], 8);
|
||||
|
||||
if (d[1] & 0x01)
|
||||
tag->dsfid = d[dCpt++];
|
||||
if (d[1] & 0x02)
|
||||
tag->afi = d[dCpt++];
|
||||
if (d[1] & 0x04)
|
||||
{
|
||||
tag->pagesCount = d[dCpt++]+1;
|
||||
tag->bytesPerPage = d[dCpt++]+1;
|
||||
}
|
||||
else
|
||||
{ // Set tag memory layout values (if can't be readed in SYSINFO)
|
||||
tag->bytesPerPage = blocksize;
|
||||
tag->pagesCount = 128;
|
||||
}
|
||||
if (d[1] & 0x08)
|
||||
tag->ic = d[dCpt++];
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
print_emltag_info_15693(tag);
|
||||
}
|
||||
|
||||
// add lenght for blockno (1)
|
||||
packet->rawlen++;
|
||||
packet->raw[0] |= ISO15_REQ_OPTION; // Add option to dump lock status
|
||||
packet->raw[1] = ISO15693_READBLOCK;
|
||||
|
||||
if (blocknum > 0) {
|
||||
packet->flags = (ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT);
|
||||
if (fast) {
|
||||
packet->flags |= ISO15_HIGH_SPEED;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Reading memory");
|
||||
|
||||
int blocknum = 0;
|
||||
|
||||
for (int retry = 0; (retry < 2 && blocknum < tag->pagesCount); retry++) {
|
||||
if (used_uid) {
|
||||
packet->raw[10] = (uint8_t)blocknum & 0xFF;
|
||||
AddCrc15(packet->raw, 11);
|
||||
|
@ -1841,7 +1890,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO15693_COMMAND, (uint8_t *)packet, ISO15_RAW_LEN(packet->rawlen));
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000)) {
|
||||
|
||||
if (resp.length < 2) {
|
||||
|
@ -1850,7 +1899,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
d = resp.data.asBytes;
|
||||
|
||||
if (CheckCrc15(d, resp.length) == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -1870,21 +1919,10 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
|
||||
// is tag responding with 4 or 8 bytes?
|
||||
if (resp.length > 8) {
|
||||
blklen = 8;
|
||||
}
|
||||
|
||||
uint8_t offset = 0;
|
||||
if (add_option) {
|
||||
offset = 1;
|
||||
}
|
||||
// lock byte value
|
||||
mem[blocknum].lock = d[0 + offset];
|
||||
tag->locks[blocknum] = d[1];
|
||||
|
||||
// copy read data
|
||||
memcpy(mem[blocknum].block, d + 1 + offset, blklen);
|
||||
memcpy(data + (blocknum * 4), d + 1 + offset, 4);
|
||||
memcpy(&tag->data[blocknum * tag->bytesPerPage], d + 2, tag->bytesPerPage);
|
||||
|
||||
retry = 0;
|
||||
blocknum++;
|
||||
|
@ -1896,9 +1934,9 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
free(packet);
|
||||
DropField();
|
||||
|
||||
if (blklen != blocksize) {
|
||||
if (tag->bytesPerPage != blocksize) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, _YELLOW_("%u") " byte block length detected, called with " _YELLOW_("%d"), blklen, blocksize);
|
||||
PrintAndLogEx(INFO, _YELLOW_("%u") " byte block length detected, called with " _YELLOW_("%d"), tag->bytesPerPage, blocksize);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -1910,18 +1948,18 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
for (int i = 0; i < blocknum; i++) {
|
||||
|
||||
char lck[16] = {0};
|
||||
if (mem[i].lock) {
|
||||
snprintf(lck, sizeof(lck), _RED_("%d"), mem[i].lock);
|
||||
if (tag->locks[i]) {
|
||||
snprintf(lck, sizeof(lck), _RED_("%d"), tag->locks[i]);
|
||||
} else {
|
||||
snprintf(lck, sizeof(lck), "%d", mem[i].lock);
|
||||
snprintf(lck, sizeof(lck), "%d", tag->locks[i]);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "%3d/0x%02X | %s| %s | %s"
|
||||
, i
|
||||
, i
|
||||
, sprint_hex(mem[i].block, blklen)
|
||||
, sprint_hex(&tag->data[i*tag->bytesPerPage], tag->bytesPerPage)
|
||||
, lck
|
||||
, sprint_ascii(mem[i].block, blklen)
|
||||
, sprint_ascii(&tag->data[i*tag->bytesPerPage], tag->bytesPerPage)
|
||||
);
|
||||
}
|
||||
PrintAndLogEx(INFO, "---------+-------------+---+-------");
|
||||
|
@ -1941,11 +1979,8 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
FillFileNameByUID(fptr, SwapEndian64(uid, sizeof(uid), 8), "-dump", sizeof(uid));
|
||||
}
|
||||
|
||||
if (blklen == 8) {
|
||||
pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v3);
|
||||
} else {
|
||||
pm3_save_dump(filename, data, (size_t)(blocknum * blklen), jsf15_v2);
|
||||
}
|
||||
pm3_save_dump(filename, (uint8_t*)tag, sizeof(iso15_tag_t), jsf15_v4);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "util.h"
|
||||
#include "cmdhficlass.h" // pagemap
|
||||
#include "iclass_cmd.h"
|
||||
#include "iso15.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "scandir.h"
|
||||
|
@ -518,6 +519,33 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
}
|
||||
break;
|
||||
}
|
||||
// handles ISO15693 in iso15_tag_t format
|
||||
case jsf15_v4: {
|
||||
JsonSaveStr(root, "FileType", "15693 v4");
|
||||
iso15_tag_t *tag = (iso15_tag_t *)data;
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.uid", tag->uid, 8);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.dsfid", &tag->dsfid, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.dsfidLock", (uint8_t*)&tag->dsfidLock, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.afi", &tag->afi, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.afiLock", (uint8_t*)&tag->afiLock, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.bytesPerPage", &tag->bytesPerPage, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.pagesCount", &tag->pagesCount, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.IC", &tag->ic, 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.locks", tag->locks, tag->pagesCount);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.random", tag->random, 2);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.privacyPasswd", tag->privacyPasswd, 4);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.state", (uint8_t*)&tag->state, 1);
|
||||
|
||||
for (size_t i = 0 ; i < tag->pagesCount ; i++) {
|
||||
if (((i+1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE)
|
||||
break;
|
||||
snprintf(path, sizeof(path), "$.blocks.%zu", i);
|
||||
JsonSaveBufAsHexCompact(root, path,
|
||||
&tag->data[i * tag->bytesPerPage],
|
||||
tag->bytesPerPage);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case jsfLegic_v2: {
|
||||
JsonSaveStr(root, "FileType", "legic v2");
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.UID", data, 4);
|
||||
|
@ -1673,6 +1701,41 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "15693 v4")) {
|
||||
iso15_tag_t *tag = (iso15_tag_t *)udata.bytes;
|
||||
JsonLoadBufAsHex(root, "$.Card.UID", tag->uid, 8, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.dsfid", &tag->dsfid, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.dsfidLock", (uint8_t*)&tag->dsfidLock, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.afi", &tag->afi, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.afiLock", (uint8_t*)&tag->afiLock, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.bytesPerPage", &tag->bytesPerPage, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.pagesCount", &tag->pagesCount, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.IC", &tag->ic, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.locks", tag->locks, tag->pagesCount, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.random", tag->random, 2, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.privacyPasswd", tag->privacyPasswd, 4, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.state", (uint8_t*)&tag->state, 1, datalen);
|
||||
|
||||
size_t sptr = 0;
|
||||
for (int i = 0; i < tag->pagesCount ; i++) {
|
||||
if (((i+1) * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) {
|
||||
PrintAndLogEx(ERR, "loadFileJSONex: maxdatalen=%zu (%04zx) block (i)=%4d (%04x) sptr=%zu (%04zx) -- exceeded maxdatalen", maxdatalen, maxdatalen, i, i, sptr, sptr);
|
||||
retval = PM3_EMALLOC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
|
||||
JsonLoadBufAsHex(root, blocks, &tag->data[sptr], tag->bytesPerPage, &len);
|
||||
if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
|
||||
break;
|
||||
}
|
||||
sptr += len;
|
||||
}
|
||||
|
||||
*datalen = sptr;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "legic v2")) {
|
||||
size_t sptr = 0;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef enum {
|
|||
jsf15,
|
||||
jsf15_v2,
|
||||
jsf15_v3,
|
||||
jsf15_v4,
|
||||
jsfLegic,
|
||||
jsfLegic_v2,
|
||||
jsfT55x7,
|
||||
|
|
|
@ -127,6 +127,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo
|
|||
| HF_14ASNIFF | 14a sniff storing to flashmem - Micolous
|
||||
| HF_14BSNIFF | 14b sniff - jacopo-j
|
||||
| HF_15SNIFF | 15693 sniff storing to flashmem - Glaser
|
||||
| HF_15SNIFF | 15693 simulator - lnv42
|
||||
| HF_AVEFUL | MIFARE Ultralight read/simulation - Ave Ozkal
|
||||
| HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth storing in flashmem - Bogito
|
||||
| HF_CARDHOPPER | Long distance (over IP) relay of 14a protocols - Sam Haskins
|
||||
|
|
|
@ -67,7 +67,7 @@ TARGET1_OPTIONS = -define \{WITH_LF WITH_LF0 WITH_LF1 WITH_LF2 WITH_LF3\}
|
|||
# RDV40/Generic - Enable all HF modules except Felica
|
||||
TARGET2_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF2 WITH_HF3 WITH_HF5\}
|
||||
# RDV40/Generic - Enable all HF modules except Felica and ISO14443, select HF_15 instead of HF
|
||||
TARGET3_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF5 WITH_HF_15\}
|
||||
TARGET3_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF5 WITH_HF_15 WITH_HF_15_LOWSIGNAL\}
|
||||
# RDV40/Generic - Enable all HF modules except ISO14443
|
||||
TARGET4_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF4 WITH_HF5\}
|
||||
# ICOPYX
|
||||
|
|
Binary file not shown.
|
@ -44,8 +44,13 @@ reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev;
|
|||
reg [11:0] has_been_low_for;
|
||||
always @(negedge adc_clk)
|
||||
begin
|
||||
`ifdef WITH_HF_15_LOWSIGNAL
|
||||
if (& adc_d[7:4]) after_hysteresis <= 1'b1;
|
||||
else if (~(| adc_d[7:6])) after_hysteresis <= 1'b0;
|
||||
`else
|
||||
if (& adc_d[7:0]) after_hysteresis <= 1'b1;
|
||||
else if (~(| adc_d[7:0])) after_hysteresis <= 1'b0;
|
||||
`endif
|
||||
|
||||
if (after_hysteresis)
|
||||
begin
|
||||
|
|
|
@ -44,4 +44,31 @@ typedef struct {
|
|||
uint8_t raw[]; // First byte in raw, raw[0] is ISO15693 protocol flag byte
|
||||
} PACKED iso15_raw_cmd_t;
|
||||
|
||||
#define ISO15693_TAG_MAX_PAGES 64 // in page
|
||||
#define ISO15693_TAG_MAX_SIZE 2048 // in byte (64 pages of 256 bits)
|
||||
|
||||
typedef struct {
|
||||
uint8_t uid[8];
|
||||
uint8_t dsfid;
|
||||
bool dsfidLock;
|
||||
uint8_t afi;
|
||||
bool afiLock;
|
||||
uint8_t bytesPerPage;
|
||||
uint8_t pagesCount;
|
||||
uint8_t ic;
|
||||
uint8_t locks[ISO15693_TAG_MAX_PAGES];
|
||||
uint8_t data[ISO15693_TAG_MAX_SIZE];
|
||||
uint8_t random[2];
|
||||
uint8_t privacyPasswd[4];
|
||||
enum {
|
||||
TAG_STATE_NO_FIELD,
|
||||
TAG_STATE_READY,
|
||||
TAG_STATE_ACTIVATED, // useless ?
|
||||
TAG_STATE_SELECTED,
|
||||
TAG_STATE_SILENCED
|
||||
} state;
|
||||
bool expectFast;
|
||||
bool expectFsk;
|
||||
} PACKED iso15_tag_t;
|
||||
|
||||
#endif // _ISO15_H_
|
||||
|
|
|
@ -32,7 +32,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf"
|
|||
# cf armsrc/Standalone/Makefile.hal
|
||||
STANDALONE_MODES=(LF_SKELETON)
|
||||
STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE)
|
||||
STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG)
|
||||
STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG)
|
||||
STANDALONE_MODES+=(DANKARMULTI)
|
||||
STANDALONE_MODES_REQ_BT=(HF_CARDHOPPER HF_REBLAY)
|
||||
STANDALONE_MODES_REQ_SMARTCARD=()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue