Merge pull request #26 from RfidResearchGroup/master

update
This commit is contained in:
mwalker33 2019-11-12 20:51:36 +11:00 committed by GitHub
commit d7144d1422
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 3283 additions and 929 deletions

2
.github/FUNDING.yml vendored
View file

@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] custom: ["https://www.paypal.me/iceman1001"]

View file

@ -3,6 +3,8 @@ 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... 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] ## [unreleased][unreleased]
- Fix hf list felica and hf felica sniff (@7homasSutter)
- Added hf felica wrunencrypted (@7homasSutter)
- Added hf felica rdunencrypted (@7homasSutter) - Added hf felica rdunencrypted (@7homasSutter)
- Added hf felica rqresponse (@7homasSutter) - Added hf felica rqresponse (@7homasSutter)
- Added hf felica rqservice (@7homasSutter) - Added hf felica rqservice (@7homasSutter)

View file

@ -216,13 +216,11 @@ void RAMFUNC SniffAndStore(uint8_t param) {
if (auth_attempts > 0) { if (auth_attempts > 0) {
if (DBGLEVEL > 1) if (DBGLEVEL > 1)
Dbprintf("[!] Authentication attempts = %u", auth_attempts); Dbprintf("[!] Authentication attempts = %u", auth_attempts);
size_t size = 4 * auth_attempts;
uint8_t *buf = BigBuf_malloc(size);
if (!exists_in_spiffs((char *)HF_BOG_LOGFILE)) { if (!exists_in_spiffs((char *)HF_BOG_LOGFILE)) {
rdv40_spiffs_write((char *)HF_BOG_LOGFILE, buf, size, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_write((char *)HF_BOG_LOGFILE, capturedPwds, 4 * auth_attempts, RDV40_SPIFFS_SAFETY_SAFE);
} else { } else {
rdv40_spiffs_append((char *)HF_BOG_LOGFILE, buf, size, RDV40_SPIFFS_SAFETY_SAFE); rdv40_spiffs_append((char *)HF_BOG_LOGFILE, capturedPwds, 4 * auth_attempts, RDV40_SPIFFS_SAFETY_SAFE);
} }
} }
@ -251,5 +249,5 @@ void RunMod() {
LEDsoff(); LEDsoff();
SpinDelay(300); SpinDelay(300);
Dbprintf("- [ End ] -> You can take shell back ..."); Dbprintf("- [ End ] -> You can take shell back ...");
Dbprintf("- [ ! ] -> use 'script run read_pwd_mem' to print passwords"); Dbprintf("- [ ! ] -> use 'script run read_pwd_mem_spiffs' to print passwords");
} }

View file

@ -696,10 +696,23 @@ static void PacketReceived(PacketCommandNG *packet) {
*/ */
switch (packet->cmd) { switch (packet->cmd) {
case CMD_QUIT_SESSION: case CMD_QUIT_SESSION: {
reply_via_fpc = false; reply_via_fpc = false;
reply_via_usb = false; reply_via_usb = false;
break; break;
}
// emulator
case CMD_SET_DBGMODE: {
DBGLEVEL = packet->data.asBytes[0];
Dbprintf("Debug level: %d", DBGLEVEL);
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
break;
}
// always available
case CMD_HF_DROPFIELD: {
hf_field_off();
break;
}
#ifdef WITH_LF #ifdef WITH_LF
case CMD_LF_T55XX_SET_CONFIG: { case CMD_LF_T55XX_SET_CONFIG: {
setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes); setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes);
@ -1034,12 +1047,6 @@ static void PacketReceived(PacketCommandNG *packet) {
} }
#endif #endif
// always available
case CMD_HF_DROPFIELD: {
hf_field_off();
break;
}
#ifdef WITH_ISO14443a #ifdef WITH_ISO14443a
case CMD_HF_ISO14443A_SNIFF: { case CMD_HF_ISO14443A_SNIFF: {
SniffIso14443a(packet->data.asBytes[0]); SniffIso14443a(packet->data.asBytes[0]);
@ -1155,13 +1162,6 @@ static void PacketReceived(PacketCommandNG *packet) {
Mifare1ksim(payload->flags, payload->exitAfter, payload->uid, payload->atqa, payload->sak); Mifare1ksim(payload->flags, payload->exitAfter, payload->uid, payload->atqa, payload->sak);
break; break;
} }
// emulator
case CMD_SET_DBGMODE: {
DBGLEVEL = packet->data.asBytes[0];
Dbprintf("Debug level: %d", DBGLEVEL);
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
break;
}
case CMD_HF_MIFARE_EML_MEMCLR: { case CMD_HF_MIFARE_EML_MEMCLR: {
MifareEMemClr(); MifareEMemClr();
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0); reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
@ -1245,6 +1245,10 @@ static void PacketReceived(PacketCommandNG *packet) {
DetectNACKbug(); DetectNACKbug();
break; break;
} }
case CMD_HF_MFU_OTP_TEAROFF: {
MifareU_Otp_Tearoff();
break;
}
#endif #endif
#ifdef WITH_NFCBARCODE #ifdef WITH_NFCBARCODE

View file

@ -410,8 +410,6 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
// clear RXRDY: // clear RXRDY:
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
uint32_t timeout = iso18092_get_timeout(); uint32_t timeout = iso18092_get_timeout();
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("timeout set: %i", timeout);
for (;;) { for (;;) {
WDT_HIT(); WDT_HIT();
@ -420,8 +418,8 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
Process18092Byte(b); Process18092Byte(b);
if (FelicaFrame.state == STATE_FULL) { if (FelicaFrame.state == STATE_FULL) {
felica_nexttransfertime = MAX(felica_nexttransfertime, felica_nexttransfertime = MAX(felica_nexttransfertime,
(GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME (GetCountSspClk() & 0xfffffff8) - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER) / 16 + FELICA_FRAME_DELAY_TIME);
);
LogTrace( LogTrace(
FelicaFrame.framebytes, FelicaFrame.framebytes,
FelicaFrame.len, FelicaFrame.len,
@ -453,7 +451,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
BigBuf_Clear_ext(false); BigBuf_Clear_ext(false);
// Initialize Demod and Uart structs // Initialize Demod and Uart structs
//DemodInit(BigBuf_malloc(MAX_FRAME_SIZE)); // DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE)); FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER; felica_nexttransfertime = 2 * DELAY_ARM2AIR_AS_READER;
@ -573,69 +571,57 @@ void felica_sendraw(PacketCommandNG *c) {
} }
void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
int remFrames = (samplesToSkip) ? samplesToSkip : 0; int remFrames = (samplesToSkip) ? samplesToSkip : 0;
Dbprintf("Sniff Felica: Getting first %d frames, Skipping after %d triggers.\n", samplesToSkip, triggersToSkip);
Dbprintf("Sniff FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip); clear_trace();
set_tracing(true);
iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD); iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD);
LED_D_ON();
//the frame bits are slow enough. uint16_t numbts = 0;
int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory int trigger_cnt = 0;
int numbts = 0; uint32_t timeout = iso18092_get_timeout();
uint8_t *dest = (uint8_t *)BigBuf_get_addr(); bool isReaderFrame = true;
uint8_t *destend = dest + n - 2; while (!BUTTON_PRESS()) {
uint32_t endframe = GetCountSspClk();
while (dest <= destend) {
WDT_HIT(); WDT_HIT();
if (BUTTON_PRESS()) break;
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
Process18092Byte(dist); Process18092Byte(dist);
if ((MAX(dist & 0xff, dist >> 8) >= 178) && (++trigger_cnt > triggersToSkip)) {
//to be sure we are in frame Dbprintf("triggersToSkip kicked %d", dist);
if (FelicaFrame.state == STATE_GET_LENGTH) { break;
//length is after 48 (PRE)+16 (SYNC) - 64 ticks +maybe offset? not 100%
uint16_t distance = GetCountSspClk() - endframe - 64 + (FelicaFrame.byte_offset > 0 ? (8 - FelicaFrame.byte_offset) : 0);
*dest = distance >> 8;
dest++;
*dest = (distance & 0xff);
dest++;
} }
//crc NOT checked
if (FelicaFrame.state == STATE_FULL) { if (FelicaFrame.state == STATE_FULL) {
endframe = GetCountSspClk(); if ((FelicaFrame.framebytes[3] % 2) == 0) {
// *dest = FelicaFrame.crc_ok; //kind of wasteful isReaderFrame = true; // All Reader Frames are even and all Tag frames are odd
dest++; } else {
for (int i = 0; i < FelicaFrame.len; i++) { isReaderFrame = false;
*dest = FelicaFrame.framebytes[i];
dest++;
if (dest >= destend) break;
} }
remFrames--; remFrames--;
if (remFrames <= 0) break; if (remFrames <= 0) {
if (dest >= destend) break; Dbprintf("Stop Sniffing - samplesToSkip reached!");
break;
}
LogTrace(FelicaFrame.framebytes,
FelicaFrame.len,
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER - timeout,
((GetCountSspClk() & 0xfffffff8) << 4) - DELAY_AIR2ARM_AS_READER,
NULL,
isReaderFrame
);
numbts += FelicaFrame.len; numbts += FelicaFrame.len;
FelicaFrameReset(); FelicaFrameReset();
} }
} }
} }
switch_off(); switch_off();
//reset framing //reset framing
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
set_tracelen(numbts); set_tracelen(numbts);
set_tracelen(BigBuf_max_traceLen());
Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen()); Dbprintf("Felica sniffing done, tracelen: %i, use hf list felica for annotations", BigBuf_get_traceLen());
reply_old(CMD_ACK, 1, numbts, 0, 0, 0); reply_old(CMD_ACK, 1, numbts, 0, 0, 0);
LED_D_OFF();
} }
#define R_POLL0_LEN 0x16 #define R_POLL0_LEN 0x16

View file

@ -1306,6 +1306,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
AddCrc(csn_data, 8); AddCrc(csn_data, 8);
uint8_t diversified_key[8] = { 0 }; uint8_t diversified_key[8] = { 0 };
// e-Purse // e-Purse
uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
//uint8_t card_challenge_data[8] = { 0 }; //uint8_t card_challenge_data[8] = { 0 };
@ -1316,6 +1317,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
//Card challenge, a.k.a e-purse is on block 2 //Card challenge, a.k.a e-purse is on block 2
memcpy(card_challenge_data, emulator + (8 * 2), 8); memcpy(card_challenge_data, emulator + (8 * 2), 8);
//Precalculate the cipher state, feeding it the CC //Precalculate the cipher state, feeding it the CC
cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key);
} }
@ -1351,7 +1353,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
uint8_t *resp_csn = BigBuf_malloc(28); uint8_t *resp_csn = BigBuf_malloc(28);
int resp_csn_len; int resp_csn_len;
// configuration picopass 2ks // configuration Picopass 2ks
uint8_t *resp_conf = BigBuf_malloc(28); uint8_t *resp_conf = BigBuf_malloc(28);
int resp_conf_len; int resp_conf_len;
uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00};
@ -1366,6 +1368,14 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
uint8_t *resp_aia = BigBuf_malloc(28); uint8_t *resp_aia = BigBuf_malloc(28);
int resp_aia_len; int resp_aia_len;
uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
if (simulationMode == MODE_FULLSIM) {
// (iceman) this only works for 2KS / 16KS tags.
// Use application data from block 5
memcpy(aia_data, emulator + (8 * 5), 8);
// older 2K / 16K tags has its application issuer data on block 2
}
AddCrc(aia_data, 8); AddCrc(aia_data, 8);
// receive command // receive command

View file

@ -1045,6 +1045,16 @@ static void leadingZeroAskSimBits(int *n, uint8_t clock) {
memset(dest + (*n), 0, clock * 8); memset(dest + (*n), 0, clock * 8);
*n += clock * 8; *n += clock * 8;
} }
/*
static void leadingZeroBiphaseSimBits(int *n, uint8_t clock, uint8_t *phase) {
uint8_t *dest = BigBuf_get_addr();
for (uint8_t i = 0; i < 8; i++) {
memset(dest + (*n), 0 ^ *phase, clock);
*phase ^= 1;
*n += clock;
}
}
*/
// args clock, ask/man or askraw, invert, transmission separator // args clock, ask/man or askraw, invert, transmission separator
@ -1054,10 +1064,14 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
int n = 0, i = 0; int n = 0, i = 0;
leadingZeroAskSimBits(&n, clk);
if (encoding == 2) { //biphase if (encoding == 2) { //biphase
uint8_t phase = 0; uint8_t phase = 0;
// iceman, if I add this, the demod includes these extra zero and detection fails.
// now, I only need to figure out just to add carrier without modulation
// the old bug, with adding ask zeros messed up the phase variable and deteion failed because of it in LF FDX
// leadingZeroBiphaseSimBits(&n, clk, &phase);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
biphaseSimBit(bits[i] ^ invert, &n, clk, &phase); biphaseSimBit(bits[i] ^ invert, &n, clk, &phase);
} }
@ -1067,6 +1081,9 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
} }
} }
} else { // ask/manchester || ask/raw } else { // ask/manchester || ask/raw
leadingZeroAskSimBits(&n, clk);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
askSimBit(bits[i] ^ invert, &n, clk, encoding); askSimBit(bits[i] ^ invert, &n, clk, encoding);
} }
@ -1083,7 +1100,14 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
WDT_HIT(); WDT_HIT();
Dbprintf("Simulating with clk: %d, invert: %d, encoding: %d, separator: %d, n: %d", clk, invert, encoding, separator, n); Dbprintf("Simulating with clk: %d, invert: %d, encoding: %s (%d), separator: %d, n: %d"
, clk
, invert
, (encoding == 2) ? "BI" : (encoding == 1) ? "ASK" : "RAW"
, encoding
, separator
, n
);
if (ledcontrol) LED_A_ON(); if (ledcontrol) LED_A_ON();
SimulateTagLowFrequency(n, 0, ledcontrol); SimulateTagLowFrequency(n, 0, ledcontrol);
@ -2466,7 +2490,7 @@ void Cotag(uint32_t arg0) {
switch (rawsignal) { switch (rawsignal) {
case 0: case 0:
doCotagAcquisition(50000); doCotagAcquisition(40000);
break; break;
case 1: case 1:
doCotagAcquisitionManchester(); doCotagAcquisitionManchester();
@ -2478,7 +2502,7 @@ void Cotag(uint32_t arg0) {
// Turn the field off // Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
reply_mix(CMD_ACK, 0, 0, 0, 0, 0); reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
LEDsoff(); LEDsoff();
} }

View file

@ -374,8 +374,8 @@ void doT55x7Acquisition(size_t sample_size) {
#define COTAG_T1 384 #define COTAG_T1 384
#define COTAG_T2 (COTAG_T1>>1) #define COTAG_T2 (COTAG_T1>>1)
#define COTAG_ONE_THRESHOLD 128+30 #define COTAG_ONE_THRESHOLD 128+10
#define COTAG_ZERO_THRESHOLD 128-30 #define COTAG_ZERO_THRESHOLD 128-10
#ifndef COTAG_BITS #ifndef COTAG_BITS
#define COTAG_BITS 264 #define COTAG_BITS 264
#endif #endif
@ -437,6 +437,11 @@ void doCotagAcquisition(size_t sample_size) {
dest[i] = dest[i - 1]; dest[i] = dest[i - 1];
} }
} }
// Ensure that DC offset removal and noise check is performed for any device-side processing
removeSignalOffset(dest, bufsize);
computeSignalProperties(dest, bufsize);
} }
uint32_t doCotagAcquisitionManchester() { uint32_t doCotagAcquisitionManchester() {

View file

@ -2173,3 +2173,70 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
LEDsoff(); LEDsoff();
set_tracing(false); set_tracing(false);
} }
//
// Tear-off attack against MFU.
// - Moebius et al
void MifareU_Otp_Tearoff() {
// should the
// optional time be configurable via client side?
// optional authentication before?
// optional data to be written?
if (DBGLEVEL >= DBG_ERROR) DbpString("Preparing OTP tear-off");
LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
StartTicks();
#define OTP_TEAR_OFF_TIME 1000
#define OTP_BLK_NO 3
// write cmd to send, include CRC
// 1b write, 1b block, 4b data, 2 crc
uint8_t cmd[] = {MIFARE_ULC_WRITE, OTP_BLK_NO, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0};
// User specific data to write?
// memcpy(block + 2, blockData, 4);
AddCrc14A(cmd, sizeof(cmd) - 2);
if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting");
// anticollision / select card
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
OnError(1);
return;
};
/*
// UL-EV1 / NTAG authentication
if (usePwd) {
uint8_t pwd[4] = {0x00};
memcpy(pwd, datain + 4, 4);
uint8_t pack[4] = {0, 0, 0, 0};
if (!mifare_ul_ev1_auth(pwd, pack)) {
OnError(1);
return;
}
}
*/
// send
ReaderTransmit(cmd, sizeof(cmd), NULL);
// Wait before cutting power. aka tear-off
LED_D_ON();
WaitUS(OTP_TEAR_OFF_TIME);
switch_off();
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
StopTicks();
if (DBGLEVEL >= DBG_ERROR) DbpString("Done");
}

View file

@ -52,4 +52,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype);
void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain); void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain);
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// Tear-off test for MFU
void MifareU_Otp_Tearoff();
#endif #endif

View file

@ -186,6 +186,7 @@ CMDSRCS = crapto1/crapto1.c \
cmdanalyse.c \ cmdanalyse.c \
cmdhf.c \ cmdhf.c \
cmdhflist.c \ cmdhflist.c \
aidsearch.c \
cmdhf14a.c \ cmdhf14a.c \
cmdhf14b.c \ cmdhf14b.c \
cmdhf15.c \ cmdhf15.c \

180
client/aidsearch.c Normal file
View file

@ -0,0 +1,180 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2019 merlokk
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Proxmark3 RDV40 AID list library
//-----------------------------------------------------------------------------
#include "aidsearch.h"
#include <ctype.h>
#include <string.h>
#include "fileutils.h"
#include "pm3_cmd.h"
int openAIDFile(json_t **root, bool verbose) {
json_error_t error;
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, "aidlist", ".json", false);
if (res != PM3_SUCCESS) {
return PM3_EFILE;
}
int retval = PM3_SUCCESS;
*root = json_load_file(path, 0, &error);
if (!*root) {
PrintAndLogEx(ERR, "json (%s) error on line %d: %s", path, error.line, error.text);
retval = PM3_ESOFT;
goto out;
}
if (!json_is_array(*root)) {
PrintAndLogEx(ERR, "Invalid json (%s) format. root must be an array.", path);
retval = PM3_ESOFT;
goto out;
}
if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %d records.", path, json_array_size(*root));
out:
free(path);
return retval;
}
int closeAIDFile(json_t *root) {
json_decref(root);
return PM3_SUCCESS;
}
json_t *AIDSearchInit(bool verbose) {
json_t *root = NULL;
int res = openAIDFile(&root, verbose);
if (res != PM3_SUCCESS)
return NULL;
return root;
}
json_t *AIDSearchGetElm(json_t *root, int elmindx) {
json_t *data = json_array_get(root, elmindx);
if (!json_is_object(data)) {
PrintAndLogEx(ERR, "data [%d] is not an object\n", elmindx);
return NULL;
}
return data;
}
int AIDSearchFree(json_t *root) {
return closeAIDFile(root);
}
const char *jsonStrGet(json_t *data, char *name) {
json_t *jstr;
jstr = json_object_get(data, name);
if (jstr == NULL)
return NULL;
if (!json_is_string(jstr)) {
PrintAndLogEx(ERR, "`%s` is not a string", name);
return NULL;
}
const char *cstr = json_string_value(jstr);
if (strlen(cstr) == 0)
return NULL;
return cstr;
}
bool aidCompare(const char *aidlarge, const char *aidsmall) {
if (strcmp(aidlarge, aidsmall) == 0)
return true;
if (strlen(aidlarge) > strlen(aidsmall))
if (strncmp(aidlarge, aidsmall, strlen(aidsmall)) == 0)
return true;
return false;
}
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen) {
*aidlen = 0;
const char *hexaid = jsonStrGet(data, "AID");
if (hexaid == NULL || strlen(hexaid) == 0)
return false;
int res = param_gethex_to_eol(hexaid, 0, aid, aidmaxlen, aidlen);
if (res)
return false;
return true;
}
int PrintAIDDescription(json_t *xroot, char *aid, bool verbose) {
int retval = PM3_SUCCESS;
json_t *root = xroot;
if (root == NULL)
root = AIDSearchInit(verbose);
if (root == NULL)
goto out;
json_t *elm = NULL;
int maxaidlen = 0;
for (int elmindx = 0; elmindx < json_array_size(root); elmindx++) {
json_t *data = AIDSearchGetElm(root, elmindx);
if (data == NULL)
continue;
const char *dictaid = jsonStrGet(data, "AID");
if (aidCompare(aid, dictaid)) { // dictaid may be less length than requested aid
if (maxaidlen < strlen(dictaid) && strlen(dictaid) <= strlen(aid)) {
maxaidlen = strlen(dictaid);
elm = data;
}
}
}
if (elm == NULL)
goto out;
// print here
const char *vaid = jsonStrGet(elm, "AID");
const char *vendor = jsonStrGet(elm, "Vendor");
const char *name = jsonStrGet(elm, "Name");
const char *country = jsonStrGet(elm, "Country");
const char *description = jsonStrGet(elm, "Description");
const char *type = jsonStrGet(elm, "Type");
if (!verbose) {
PrintAndLogEx(SUCCESS, "AID %s | %s | %s", vaid, vendor, name);
} else {
PrintAndLogEx(SUCCESS, "Input AID: %s", aid);
if (aid)
PrintAndLogEx(SUCCESS, "Found AID: %s", vaid);
if (vendor)
PrintAndLogEx(SUCCESS, "Vendor: %s", vendor);
if (type)
PrintAndLogEx(SUCCESS, "Type: %s", type);
if (name)
PrintAndLogEx(SUCCESS, "Name: %s", name);
if (country)
PrintAndLogEx(SUCCESS, "Country: %s", country);
if (description)
PrintAndLogEx(SUCCESS, "Description: %s", description);
}
out:
if (xroot == NULL)
AIDSearchFree(root);
return retval;
}
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose) {
return PrintAIDDescription(root, sprint_hex_inrow(aid, aidlen), verbose);
}

28
client/aidsearch.h Normal file
View file

@ -0,0 +1,28 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2019 merlokk
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Proxmark3 RDV40 AID list library
//-----------------------------------------------------------------------------
#ifndef AIDSEARCH_H__
#define AIDSEARCH_H__
#include "common.h"
#include <stdint.h>
#include <stdbool.h>
#include <jansson.h>
int PrintAIDDescription(json_t *root, char *aid, bool verbose);
int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose);
json_t *AIDSearchInit(bool verbose);
json_t *AIDSearchGetElm(json_t *root, int elmindx);
bool AIDGetFromElm(json_t *data, uint8_t *aid, size_t aidmaxlen, int *aidlen);
int AIDSearchFree();
#endif

View file

@ -812,7 +812,7 @@ int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveG
// sanity check // sanity check
if (window > len) window = len; if (window > len) window = len;
if (verbose) PrintAndLogEx(INFO, "performing " _YELLOW_("%zu")" correlations", GraphTraceLen - window); if (verbose) PrintAndLogEx(INFO, "performing " _YELLOW_("%zu") "correlations", GraphTraceLen - window);
//test //test
double autocv = 0.0; // Autocovariance value double autocv = 0.0; // Autocovariance value
@ -868,9 +868,9 @@ int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveG
if (verbose && foo < bar) { if (verbose && foo < bar) {
distance = idx_1 - idx; distance = idx_1 - idx;
PrintAndLogEx(SUCCESS, "possible visible correlation %4d samples", distance); PrintAndLogEx(SUCCESS, "possible visible correlation "_YELLOW_("%4d") "samples", distance);
} else if (verbose && (correlation > 1)) { } else if (verbose && (correlation > 1)) {
PrintAndLogEx(SUCCESS, "possible correlation %4zu samples", correlation); PrintAndLogEx(SUCCESS, "possible correlation " _YELLOW_("%4zu") "samples", correlation);
} else { } else {
PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size"); PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size");
} }

View file

@ -91,7 +91,7 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag..."); PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag...");
if (IfPm3Iso14443a()) { if (IfPm3Iso14443a()) {
if (infoHF14A(false, false) > 0) { if (infoHF14A(false, false, false) > 0) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -26,6 +26,7 @@
#include "ui.h" #include "ui.h"
#include "crc16.h" #include "crc16.h"
#include "util_posix.h" // msclock #include "util_posix.h" // msclock
#include "aidsearch.h"
bool APDUInFramingEnable = true; bool APDUInFramingEnable = true;
@ -226,13 +227,6 @@ static int usage_hf_14a_reader(void) {
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)"); PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
return 0; return 0;
} }
static int usage_hf_14a_info(void) {
PrintAndLogEx(NORMAL, "This command makes more extensive tests against a ISO14443a tag in order to collect information");
PrintAndLogEx(NORMAL, "Usage: hf 14a info [h|s]");
PrintAndLogEx(NORMAL, " s silent (no messages)");
PrintAndLogEx(NORMAL, " n test for nack bug");
return 0;
}
static int CmdHF14AList(const char *Cmd) { static int CmdHF14AList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
@ -367,12 +361,30 @@ static int CmdHF14AReader(const char *Cmd) {
} }
static int CmdHF14AInfo(const char *Cmd) { static int CmdHF14AInfo(const char *Cmd) {
bool verbose = false;
bool do_nack_test = false;
bool do_aid_search = false;
if (Cmd[0] == 'h' || Cmd[0] == 'H') return usage_hf_14a_info(); CLIParserInit("hf 14a info",
"This command makes more extensive tests against a ISO14443a tag in order to collect information",
"Sample:\n\thf 14a info -nsv - shows full information about the card\n");
bool verbose = !(Cmd[0] == 's' || Cmd[0] == 'S'); void *argtable[] = {
bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N'); arg_param_begin,
infoHF14A(verbose, do_nack_test); arg_lit0("vV", "verbose", "adds some information to results"),
arg_lit0("nN", "nacktest", "test for nack bug"),
arg_lit0("sS", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
arg_param_end
};
CLIExecWithReturn(Cmd, argtable, true);
verbose = arg_get_lit(1);
do_nack_test = arg_get_lit(2);
do_aid_search = arg_get_lit(3);
CLIParserFree();
infoHF14A(verbose, do_nack_test, do_aid_search);
return 0; return 0;
} }
@ -1225,7 +1237,7 @@ int CmdHF14A(const char *Cmd) {
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
int infoHF14A(bool verbose, bool do_nack_test) { int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
@ -1493,6 +1505,72 @@ int infoHF14A(bool verbose, bool do_nack_test) {
} }
} }
} }
if (do_aid_search) {
int elmindx = 0;
json_t *root = AIDSearchInit(verbose);
if (root != NULL) {
bool ActivateField = true;
for (elmindx = 0; elmindx < json_array_size(root); elmindx++) {
json_t *data = AIDSearchGetElm(root, elmindx);
uint8_t vaid[200] = {0};
int vaidlen = 0;
if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen)
continue;
uint16_t sw = 0;
uint8_t result[1024] = {0};
size_t resultlen = 0;
int res = EMVSelect(ECC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw, NULL);
ActivateField = false;
if (res)
continue;
uint8_t dfname[200] = {0};
size_t dfnamelen = 0;
if (resultlen > 3) {
struct tlvdb *tlv = tlvdb_parse_multi(result, resultlen);
if (tlv) {
// 0x84 Dedicated File (DF) Name
const struct tlv *dfnametlv = tlvdb_get_tlv(tlvdb_find_full(tlv, 0x84));
if (dfnametlv) {
dfnamelen = dfnametlv->len;
memcpy(dfname, dfnametlv->value, dfnamelen);
}
tlvdb_free(tlv);
}
}
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
if (sw == 0x9000) {
if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------");
} else {
if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------");
}
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
if (dfnamelen) {
if (dfnamelen == vaidlen) {
if (memcmp(dfname, vaid, vaidlen) == 0) {
if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID");
} else {
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
}
} else {
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
}
} else {
if (verbose) PrintAndLogEx(INFO, "(DF) Name not found");
}
}
}
DropField();
}
}
} else { } else {
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
} }

View file

@ -26,7 +26,7 @@ int CmdHF14A(const char *Cmd);
int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
int CmdHF14ASim(const char *Cmd); // used by hf mfu sim int CmdHF14ASim(const char *Cmd); // used by hf mfu sim
int infoHF14A(bool verbose, bool do_nack_test); int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
const char *getTagInfo(uint8_t uid); const char *getTagInfo(uint8_t uid);
int Hf14443_4aGetCardData(iso14a_card_select_t *card); int Hf14443_4aGetCardData(iso14a_card_select_t *card);
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);

View file

@ -47,15 +47,19 @@ static int usage_hf_felica_sim(void) {
*/ */
static int usage_hf_felica_sniff(void) { static int usage_hf_felica_sniff(void) {
PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer."); PrintAndLogEx(NORMAL, "\nInfo: It get data from the field and saves it into command buffer. ");
PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list felica'"); PrintAndLogEx(NORMAL, " Buffer accessible from command 'hf list felica'");
PrintAndLogEx(NORMAL, "Usage: hf felica sniff <s> <t>"); PrintAndLogEx(NORMAL, "\nUsage: hf felica sniff [-h] [-s] [-t]");
PrintAndLogEx(NORMAL, " s samples to skip (decimal)"); PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " t triggers to skip (decimal)"); PrintAndLogEx(NORMAL, " -s samples to skip (decimal) max 9999");
PrintAndLogEx(NORMAL, " -t triggers to skip (decimal) max 9999");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf felica sniff s 1000"); PrintAndLogEx(NORMAL, " hf felica sniff");
PrintAndLogEx(NORMAL, " hf felica sniff -s 10 -t 10");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_felica_simlite(void) { static int usage_hf_felica_simlite(void) {
PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa Lite tag \n"); PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa Lite tag \n");
PrintAndLogEx(NORMAL, "Usage: hf felica litesim [h] u <uid>"); PrintAndLogEx(NORMAL, "Usage: hf felica litesim [h] u <uid>");
@ -66,6 +70,7 @@ static int usage_hf_felica_simlite(void) {
PrintAndLogEx(NORMAL, " hf felica litesim 11223344556677"); PrintAndLogEx(NORMAL, " hf felica litesim 11223344556677");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_felica_dumplite(void) { static int usage_hf_felica_dumplite(void) {
PrintAndLogEx(NORMAL, "\n Dump ISO/18092 FeliCa Lite tag \n"); PrintAndLogEx(NORMAL, "\n Dump ISO/18092 FeliCa Lite tag \n");
PrintAndLogEx(NORMAL, "press button to abort run, otherwise it will loop for 200sec."); PrintAndLogEx(NORMAL, "press button to abort run, otherwise it will loop for 200sec.");
@ -76,6 +81,7 @@ static int usage_hf_felica_dumplite(void) {
PrintAndLogEx(NORMAL, " hf felica litedump"); PrintAndLogEx(NORMAL, " hf felica litedump");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_felica_raw(void) { static int usage_hf_felica_raw(void) {
PrintAndLogEx(NORMAL, "Usage: hf felica raw [-h] [-r] [-c] [-p] [-a] <0A 0B 0C ... hex>"); PrintAndLogEx(NORMAL, "Usage: hf felica raw [-h] [-r] [-c] [-p] [-a] <0A 0B 0C ... hex>");
PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -h this help");
@ -218,13 +224,61 @@ static int usage_hf_felica_write_without_encryption() {
PrintAndLogEx(NORMAL, " - Un-/Successful read: Card responses with Status Flag1 and Flag2"); PrintAndLogEx(NORMAL, " - Un-/Successful read: Card responses with Status Flag1 and Flag2");
print_status_flag1_interpretation(); print_status_flag1_interpretation();
print_status_flag2_interpration(); print_status_flag2_interpration();
PrintAndLogEx(NORMAL, "\nUsage: hf felica wrunencrypted [-h] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex> <0A0B0C0D0E0F... Data hex (16-Byte)>"); PrintAndLogEx(NORMAL, "\nUsage: hf felica wrunencrypted [-h][-i] <01 Number of Service hex> <0A0B Service Code List (Little Endian) hex> <01 Number of Block hex> <0A0B Block List Element hex> <0A0B0C0D0E0F... Data hex (16-Byte)>");
PrintAndLogEx(NORMAL, " -h this help"); PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use\n"); PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use\n");
PrintAndLogEx(NORMAL, " hf felica wrunencrypted 01 CB10 01 8001 0102030405060708090A0B0C0D0E0F10\n\n");
PrintAndLogEx(NORMAL, "\nExamples: "); PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica wrunencrypted "); PrintAndLogEx(NORMAL, " hf felica wrunencrypted 01 CB10 01 8001 0102030405060708090A0B0C0D0E0F10");
PrintAndLogEx(NORMAL, " hf felica wrunencrypted -i 11100910C11BC407 01 CB10 01 8001 0102030405060708090A0B0C0D0E0F10\n\n");
return PM3_SUCCESS;
}
static int usage_hf_felica_request_system_code() {
PrintAndLogEx(NORMAL, "\nInfo: Use this command to acquire System Code registered to the card.");
PrintAndLogEx(NORMAL, " - If a card is divided into more than one System, this command acquires System Code of each System existing in the card.");
PrintAndLogEx(NORMAL, "\nUsage: hf felica rqsyscode [-h] [-i]");
PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use");
PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica rqsyscode ");
PrintAndLogEx(NORMAL, " hf felica rqsyscode -i 11100910C11BC407\n\n");
return PM3_SUCCESS;
}
static int usage_hf_felica_reset_mode() {
PrintAndLogEx(NORMAL, "\nInfo: Use this command to reset Mode to Mode 0.");
print_status_flag1_interpretation();
print_status_flag2_interpration();
PrintAndLogEx(NORMAL, "\nUsage: hf felica resetmode [-h][-i][-r]");
PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use");
PrintAndLogEx(NORMAL, " -r <0A0B hex> set custom reserve to use");
PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica resetmode ");
PrintAndLogEx(NORMAL, " hf felica resetmode -r 0001");
PrintAndLogEx(NORMAL, " hf felica resetmode -i 11100910C11BC407\n\n");
return PM3_SUCCESS;
}
static int usage_hf_felica_request_specification_version() {
PrintAndLogEx(NORMAL, "\nInfo: Use this command to acquire the version of card OS.");
PrintAndLogEx(NORMAL, " - Response:");
PrintAndLogEx(NORMAL, " - Format Version: Fixed value 00h. Provided only if Status Flag1 = 00h.");
PrintAndLogEx(NORMAL, " - Basic Version: Each value of version is expressed in BCD notation <Little Endian>. Provided only if Status Flag1 = 00h.");
PrintAndLogEx(NORMAL, " - Number of Option: value = 0: AES card, value = 1: AES/DES card. Provided only if Status Flag1 = 00h.");
PrintAndLogEx(NORMAL, " - Option Version List: Provided only if Status Flag1 = 00h.");
PrintAndLogEx(NORMAL, " - For AES card: not added.");
PrintAndLogEx(NORMAL, " - For AES/DES card: DES option version is added - BCD notation <Little Endian>.");
print_status_flag1_interpretation();
print_status_flag2_interpration();
PrintAndLogEx(NORMAL, "\nUsage: hf felica rqspecver [-h][-i][-r]");
PrintAndLogEx(NORMAL, " -h this help");
PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use");
PrintAndLogEx(NORMAL, " -r <0A0B hex> set custom reserve to use");
PrintAndLogEx(NORMAL, "\nExamples: ");
PrintAndLogEx(NORMAL, " hf felica rqspecver ");
PrintAndLogEx(NORMAL, " hf felica rqspecver -r 0001");
PrintAndLogEx(NORMAL, " hf felica rqspecver -i 11100910C11BC407\n\n");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -240,6 +294,7 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose)
PrintAndLogEx(NORMAL, "Client Received %i octets", len); PrintAndLogEx(NORMAL, "Client Received %i octets", len);
if (!len || len < 2) { if (!len || len < 2) {
PrintAndLogEx(ERR, "Could not receive data correctly!"); PrintAndLogEx(ERR, "Could not receive data correctly!");
return false;
} }
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len)); PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len));
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
@ -466,7 +521,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
switch (Cmd[i + 1]) { switch (Cmd[i + 1]) {
case 'H': case 'H':
case 'h': case 'h':
return usage_hf_felica_request_response(); return usage_hf_felica_write_without_encryption();
case 'i': case 'i':
paramCount++; paramCount++;
custom_IDm = true; custom_IDm = true;
@ -476,6 +531,8 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
paramCount++; paramCount++;
i += 16; i += 16;
break; break;
default:
return usage_hf_felica_write_without_encryption();
} }
} }
i++; i++;
@ -535,7 +592,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
switch (Cmd[i + 1]) { switch (Cmd[i + 1]) {
case 'H': case 'H':
case 'h': case 'h':
return usage_hf_felica_request_response(); return usage_hf_felica_read_without_encryption();
case 'i': case 'i':
paramCount++; paramCount++;
custom_IDm = true; custom_IDm = true;
@ -553,6 +610,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
paramCount++; paramCount++;
long_block_numbers = true; long_block_numbers = true;
break; break;
default:
return usage_hf_felica_read_without_encryption();
} }
} }
i++; i++;
@ -641,6 +700,8 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
paramCount++; paramCount++;
i += 16; i += 16;
break; break;
default:
return usage_hf_felica_request_response();
} }
} }
i++; i++;
@ -672,6 +733,234 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
} }
/**
* Command parser for rqspecver
* @param Cmd input data of the user.
* @return client result code.
*/
static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) {
uint8_t data[PM3_CMD_DATA_SIZE];
bool custom_IDm = false;
bool custom_reserve = false;
strip_cmds(Cmd);
uint16_t datalen = 12; // Length (1), Command ID (1), IDm (8), Reserved (2)
uint8_t paramCount = 0;
uint8_t flags = 0;
int i = 0;
while (Cmd[i] != '\0') {
if (Cmd[i] == '-') {
switch (Cmd[i + 1]) {
case 'H':
case 'h':
return usage_hf_felica_request_specification_version();
case 'i':
paramCount++;
custom_IDm = true;
if (!add_param(Cmd, paramCount, data, 2, 16)) {
return PM3_EINVARG;
}
paramCount++;
i += 16;
break;
case 'r':
paramCount++;
custom_reserve = true;
if (!add_param(Cmd, paramCount, data, 10, 4)) {
return PM3_EINVARG;
}
paramCount++;
i += 4;
break;
default:
return usage_hf_felica_request_specification_version();
}
}
i++;
}
data[0] = 0x0C; // Static length
data[1] = 0x3C; // Command ID
if (!custom_reserve) {
data[10] = 0x00; // Reserved Value
data[11] = 0x00; // Reserved Value
}
if (!custom_IDm && !check_last_idm(data, datalen)) {
return PM3_EINVARG;
}
AddCrc(data, datalen);
datalen += 2;
flags |= FELICA_APPEND_CRC;
flags |= FELICA_RAW;
clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card");
return PM3_ERFTRANS;
} else {
felica_request_spec_response_t spec_response;
memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t));
if (spec_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm)));
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1)));
PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2)));
if (spec_response.status_flags.status_flag1[0] == 0x00) {
PrintAndLogEx(NORMAL, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version)));
PrintAndLogEx(NORMAL, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version)));
PrintAndLogEx(NORMAL, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option)));
if (spec_response.number_of_option[0] == 0x01) {
PrintAndLogEx(NORMAL, "Option Version List:");
for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) {
PrintAndLogEx(NORMAL, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2));
}
}
}
}
}
return PM3_SUCCESS;
}
/**
* Command parser for resetmode
* @param Cmd input data of the user.
* @return client result code.
*/
static int CmdHFFelicaResetMode(const char *Cmd) {
uint8_t data[PM3_CMD_DATA_SIZE];
bool custom_IDm = false;
bool custom_reserve = false;
strip_cmds(Cmd);
uint16_t datalen = 12; // Length (1), Command ID (1), IDm (8), Reserved (2)
uint8_t paramCount = 0;
uint8_t flags = 0;
int i = 0;
while (Cmd[i] != '\0') {
if (Cmd[i] == '-') {
switch (Cmd[i + 1]) {
case 'H':
case 'h':
return usage_hf_felica_reset_mode();
case 'i':
paramCount++;
custom_IDm = true;
if (!add_param(Cmd, paramCount, data, 2, 16)) {
return PM3_EINVARG;
}
paramCount++;
i += 16;
break;
case 'r':
paramCount++;
custom_reserve = true;
if (!add_param(Cmd, paramCount, data, 10, 4)) {
return PM3_EINVARG;
}
paramCount++;
i += 4;
break;
default:
return usage_hf_felica_reset_mode();
}
}
i++;
}
data[0] = 0x0C; // Static length
data[1] = 0x3E; // Command ID
if (!custom_reserve) {
data[10] = 0x00; // Reserved Value
data[11] = 0x00; // Reserved Value
}
if (!custom_IDm && !check_last_idm(data, datalen)) {
return PM3_EINVARG;
}
AddCrc(data, datalen);
datalen += 2;
flags |= FELICA_APPEND_CRC;
flags |= FELICA_RAW;
clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card");
return PM3_ERFTRANS;
} else {
felica_status_response_t reset_mode_response;
memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t));
if (reset_mode_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm)));
PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1)));
PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2)));
}
}
return PM3_SUCCESS;
}
/**
* Command parser for rqsyscode
* @param Cmd input data of the user.
* @return client result code.
*/
static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
uint8_t data[PM3_CMD_DATA_SIZE];
bool custom_IDm = false;
strip_cmds(Cmd);
uint16_t datalen = 10; // Length (1), Command ID (1), IDm (8)
uint8_t paramCount = 0;
uint8_t flags = 0;
int i = 0;
while (Cmd[i] != '\0') {
if (Cmd[i] == '-') {
switch (Cmd[i + 1]) {
case 'H':
case 'h':
return usage_hf_felica_request_system_code();
case 'i':
paramCount++;
custom_IDm = true;
if (!add_param(Cmd, paramCount, data, 2, 16)) {
return PM3_EINVARG;
}
paramCount++;
i += 16;
break;
default:
return usage_hf_felica_request_system_code();
}
}
i++;
}
data[0] = 0x0A; // Static length
data[1] = 0x0C; // Command ID
if (!custom_IDm && !check_last_idm(data, datalen)) {
return PM3_EINVARG;
}
AddCrc(data, datalen);
datalen += 2;
flags |= FELICA_APPEND_CRC;
flags |= FELICA_RAW;
clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card");
return PM3_ERFTRANS;
} else {
felica_syscode_response_t rq_syscode_response;
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t));
if (rq_syscode_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:");
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm)));
PrintAndLogEx(NORMAL, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems)));
PrintAndLogEx(NORMAL, " - System Codes: enumerated in ascending order starting from System 0.");
for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) {
PrintAndLogEx(NORMAL, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2));
}
}
}
return PM3_SUCCESS;
}
/** /**
* Command parser for rqservice. * Command parser for rqservice.
* @param Cmd input data of the user. * @param Cmd input data of the user.
@ -766,103 +1055,57 @@ static int CmdHFFelicaNotImplementedYet(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// simulate iso18092 / FeliCa tag
// Commented, there is no counterpart in ARM at the moment
/*
static int CmdHFFelicaSim(const char *Cmd) {
bool errors = false;
uint8_t flags = 0;
uint8_t tagtype = 1;
uint8_t cmdp = 0;
uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int uidlen = 0;
bool verbose = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (param_getchar(Cmd, cmdp)) {
case 'h':
case 'H':
return usage_hf_felica_sim();
case 't':
case 'T':
// Retrieve the tag type
tagtype = param_get8ex(Cmd, cmdp + 1, 0, 10);
if (tagtype == 0)
errors = true;
cmdp += 2;
break;
case 'u':
case 'U':
// Retrieve the full 4,7,10 byte long uid
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
if (!errors) {
PrintAndLogEx(NORMAL, "Emulating ISO18092/FeliCa tag with %d byte UID (%s)", uidlen >> 1, sprint_hex(uid, uidlen >> 1));
}
cmdp += 2;
break;
case 'v':
case 'V':
verbose = true;
cmdp++;
break;
case 'e':
case 'E':
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors || cmdp == 0) return usage_hf_felica_sim();
clearCommandBuffer();
SendCommandOLD(CMD_HF_FELICA_SIMULATE, tagtype, flags, 0, uid, uidlen >> 1);
PacketResponseNG resp;
if (verbose)
PrintAndLogEx(NORMAL, "Press pm3-button to abort simulation");
while (!kbd_enter_pressed()) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
}
return PM3_SUCCESS;
}
*/
static int CmdHFFelicaSniff(const char *Cmd) { static int CmdHFFelicaSniff(const char *Cmd) {
uint8_t cmdp = 0; uint8_t paramCount = 0;
uint64_t samples2skip = 0; uint64_t samples2skip = 0;
uint64_t triggers2skip = 0; uint64_t triggers2skip = 0;
bool errors = false; strip_cmds(Cmd);
int i = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (Cmd[i] != '\0') {
switch (param_getchar(Cmd, cmdp)) { if (Cmd[i] == '-') {
case 'h': switch (Cmd[i + 1]) {
case 'H': case 'h':
return usage_hf_felica_sniff(); case 'H':
case 's': return usage_hf_felica_sniff();
case 'S': case 's':
samples2skip = param_get32ex(Cmd, cmdp + 1, 0, 10); case 'S':
cmdp += 2; paramCount++;
break; if (param_getlength(Cmd, paramCount) < 5) {
case 't': samples2skip = param_get32ex(Cmd, paramCount++, 0, 10);
case 'T': } else {
triggers2skip = param_get32ex(Cmd, cmdp + 1, 0, 10); PrintAndLogEx(ERR, "Invalid samples number!");
cmdp += 2; return PM3_EINVARG;
break; }
default: break;
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); case 't':
errors = true; case 'T':
break; paramCount++;
if (param_getlength(Cmd, paramCount) < 5) {
triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10);
} else {
PrintAndLogEx(ERR, "Invalid triggers number!");
return PM3_EINVARG;
}
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, paramCount));
return usage_hf_felica_sniff();
}
i += 2;
} }
i++;
}
if (samples2skip <= 0) {
samples2skip = 10;
PrintAndLogEx(INFO, "Set default samples2skip: %i", samples2skip);
}
if (triggers2skip <= 0) {
triggers2skip = 5000;
PrintAndLogEx(INFO, "Set default triggers2skip: %i", triggers2skip);
} }
//Validations
if (errors || cmdp == 0) return usage_hf_felica_sniff();
PrintAndLogEx(INFO, "Start Sniffing now. You can stop sniffing with clicking the PM3 Button");
PrintAndLogEx(INFO, "During sniffing, other pm3 commands may not response.");
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_FELICA_SNIFF, samples2skip, triggers2skip, 0, NULL, 0); SendCommandMIX(CMD_HF_FELICA_SNIFF, samples2skip, triggers2skip, 0, NULL, 0);
return PM3_SUCCESS; return PM3_SUCCESS;
@ -1277,15 +1520,15 @@ static command_t CommandTable[] = {
{"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."},
{"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."},
{"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."},
//{"rqsyscode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire System Code registered to the card."}, {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."},
//{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, //{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
//{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, //{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
//{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
//{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."},
//{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."},
//{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."}, //{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."},
//{"rqspecver", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the version of card OS."}, {"rqspecver", CmdHFFelicaRequestSpecificationVersion, IfPm3Felica, "acquire the version of card OS."},
//{"resetmode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "reset Mode to Mode 0."}, {"resetmode", CmdHFFelicaResetMode, IfPm3Felica, "reset Mode to Mode 0."},
//{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, //{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
//{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, //{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
//{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, //{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},

View file

@ -47,7 +47,7 @@ static int CmdHFFidoInfo(const char *cmd) {
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n"); PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n");
// info about 14a part // info about 14a part
infoHF14A(false, false); infoHF14A(false, false, false);
// FIDO info // FIDO info
PrintAndLogEx(NORMAL, "--------------------------------------------"); PrintAndLogEx(NORMAL, "--------------------------------------------");

View file

@ -97,6 +97,10 @@ uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n) {
return check_crc(CRC_15693, d, n); return check_crc(CRC_15693, d, n);
} }
uint8_t felica_CRC_check(uint8_t *d, uint8_t n) {
return check_crc(CRC_FELICA, d, n);
}
/** /**
* @brief iclass_CRC_Ok Checks CRC in command or response * @brief iclass_CRC_Ok Checks CRC in command or response
* @param isResponse * @param isResponse
@ -889,8 +893,7 @@ void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
} }
void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
switch (cmd[3]) {
switch (cmd[0]) {
case FELICA_POLL_REQ: case FELICA_POLL_REQ:
snprintf(exp, size, "POLLING"); snprintf(exp, size, "POLLING");
break; break;

View file

@ -31,6 +31,7 @@ void ClearAuthData(void);
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n); uint8_t iso14443A_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
uint8_t iso14443B_CRC_check(uint8_t *d, uint8_t n); uint8_t iso14443B_CRC_check(uint8_t *d, uint8_t n);
uint8_t felica_CRC_check(uint8_t *d, uint8_t n);
uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len); uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len);
uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n); uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n);
uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n); uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);

View file

@ -533,7 +533,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
if (strlen(Cmd) < 3) { if (strlen(Cmd) < 3) {
PrintAndLogEx(NORMAL, "Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>"); PrintAndLogEx(NORMAL, "Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); PrintAndLogEx(NORMAL, " hf mf wrbl 1 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
return 0; return 0;
} }
@ -1967,7 +1967,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
// Store valid credentials for the nested / hardnested attack if none exist // Store valid credentials for the nested / hardnested attack if none exist
if (know_target_key == false) { if (know_target_key == false) {
num_to_bytes(e_sector[i].Key[j], 6, tmp_key); num_to_bytes(e_sector[i].Key[j], 6, key);
know_target_key = true; know_target_key = true;
blockNo = i; blockNo = i;
keyType = j; keyType = j;

View file

@ -24,100 +24,7 @@ uint8_t key_defa_data[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x
uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; uint8_t key_picc_data[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/*
static int CmdHF14ADesWb(const char *Cmd) {
uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLogEx(NORMAL, "Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
PrintAndLogEx(NORMAL, " sample: hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
return 0;
}
blockNo = param_get8(Cmd, 0);
cmdp = param_getchar(Cmd, 1);
if (cmdp == 0x00) {
PrintAndLogEx(NORMAL, "Key type must be A or B");
return 1;
}
if (cmdp != 'A' && cmdp != 'a') keyType = 1;
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols");
return 1;
}
if (param_gethex(Cmd, 3, bldata, 32)) {
PrintAndLogEx(NORMAL, "Block data must include 32 HEX symbols");
return 1;
}
PrintAndLogEx(NORMAL, "--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6));
PrintAndLogEx(NORMAL, "--data: %s", sprint_hex(bldata, 16));
uint8_t data[26];
memcpy(data, key, 6);
memcpy(data + 10, bldata, 16);
SendCommandOLD(CMD_HF_MIFARE_WRITEBL, blockNo, keyType, 0, data, sizeof(data));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
} else {
PrintAndLogEx(NORMAL, "Command execute timeout");
}
return 0;
}
static int CmdHF14ADesRb(const char *Cmd) {
uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
char cmdp = 0x00;
if (strlen(Cmd)<3) {
PrintAndLogEx(NORMAL, "Usage: hf mf rdbl <block number> <key A/B> <key (12 hex symbols)>");
PrintAndLogEx(NORMAL, " sample: hf mf rdbl 0 A FFFFFFFFFFFF ");
return 0;
}
blockNo = param_get8(Cmd, 0);
cmdp = param_getchar(Cmd, 1);
if (cmdp == 0x00) {
PrintAndLogEx(NORMAL, "Key type must be A or B");
return 1;
}
if (cmdp != 'A' && cmdp != 'a') keyType = 1;
if (param_gethex(Cmd, 2, key, 12)) {
PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols");
return 1;
}
PrintAndLogEx(NORMAL, "--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6));
mf_readblock_t payload = { blockNo, keyType, key };
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)payload, sizeof(mf_readblock_t) );
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) {
uint8_t * data = resp.data.asBytes;
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(NORMAL, "isOk:%02x data:%s", isOK, sprint_hex(data, 16));
else
PrintAndLogEx(NORMAL, "isOk:%02x", isOK);
} else {
PrintAndLogEx(NORMAL, "Command execute timeout");
}
return 0;
}
*/
static int CmdHF14ADesInfo(const char *Cmd) { static int CmdHF14ADesInfo(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far

View file

@ -36,7 +36,7 @@ static int CmdHFMFPInfo(const char *cmd) {
PrintAndLogEx(WARNING, "command don't have any parameters.\n"); PrintAndLogEx(WARNING, "command don't have any parameters.\n");
// info about 14a part // info about 14a part
infoHF14A(false, false); infoHF14A(false, false, false);
// Mifare Plus info // Mifare Plus info
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);

View file

@ -221,6 +221,16 @@ static int usage_hf_mfu_pwdgen(void) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_hf_mfu_otp_tearoff(void) {
PrintAndLogEx(NORMAL, "Tear-off test against OTP block on MFU tags - More help sooner or later\n");
PrintAndLogEx(NORMAL, "Usage: hf mfu otptear [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : this help");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu otptear");
return PM3_SUCCESS;
}
uint8_t default_3des_keys[][16] = { uint8_t default_3des_keys[][16] = {
{ 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key
@ -2740,6 +2750,38 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
PrintAndLogEx(NORMAL, "--------------------"); PrintAndLogEx(NORMAL, "--------------------");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
//
// MFU TearOff against OTP
// Moebius et al
//
static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
uint8_t cmdp = 0;
bool errors = 0;
uint32_t len = strtol(Cmd, NULL, 0);
uint8_t data[PM3_CMD_DATA_SIZE] = {0};
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_hf_mfu_otp_tearoff();
default:
break;
}
}
if (errors) return usage_hf_mfu_otp_tearoff();
clearCommandBuffer();
SendCommandNG(CMD_HF_MFU_OTP_TEAROFF, data, len);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 4000)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
return PM3_SUCCESS;
}
//------------------------------------ //------------------------------------
// Menu Stuff // Menu Stuff
//------------------------------------ //------------------------------------
@ -2757,6 +2799,7 @@ static command_t CommandTable[] = {
{"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate Ultralight from emulator memory"}, {"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate Ultralight from emulator memory"},
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"}, {"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"}, {"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -86,7 +86,7 @@ static int CmdCOTAGRead(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_COTAG_READ, rawsignal, 0, 0, NULL, 0); SendCommandMIX(CMD_LF_COTAG_READ, rawsignal, 0, 0, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, NULL, 7000)) { if (!WaitForResponseTimeout(CMD_LF_COTAG_READ, NULL, 7000)) {
PrintAndLogEx(WARNING, "command execution time out"); PrintAndLogEx(WARNING, "command execution time out");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }

View file

@ -243,7 +243,7 @@ static int CmdFdxDemod(const char *Cmd) {
uint8_t c[] = {0, 0}; uint8_t c[] = {0, 0};
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]); compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
PrintAndLogEx(SUCCESS, "CRC-16 0x%04X [ %s] ", crc, (crc == (c[1] << 8 | c[0]) ) ? _GREEN_("OK") : _RED_("Fail")); PrintAndLogEx(SUCCESS, "CRC-16 0x%04X [ %s] ", crc, (crc == (c[1] << 8 | c[0])) ? _GREEN_("OK") : _RED_("Fail"));
if (g_debugMode) { if (g_debugMode) {
PrintAndLogEx(DEBUG, "Start marker %d; Size %zu", preambleIndex, size); PrintAndLogEx(DEBUG, "Start marker %d; Size %zu", preambleIndex, size);
@ -313,7 +313,7 @@ static int CmdFdxSim(const char *Cmd) {
countryid = param_get32ex(Cmd, 0, 0, 10); countryid = param_get32ex(Cmd, 0, 0, 10);
animalid = param_get64ex(Cmd, 1, 0, 10); animalid = param_get64ex(Cmd, 1, 0, 10);
extended = param_get32ex(Cmd, 2, 0 , 10); extended = param_get32ex(Cmd, 2, 0, 10);
verify_values(&animalid, &countryid); verify_values(&animalid, &countryid);

View file

@ -6,7 +6,8 @@
// the license. // the license.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Low frequency GALLAGHER tag commands // Low frequency GALLAGHER tag commands
// NRZ, RF/32, 128 bits long (unknown cs) // ASK/MAN, RF/32, 96 bits long (unknown cs) (0x00088060)
// sample Q5 , ASK RF/32, STT, 96 bits (3blocks) ( 0x9000F006)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlfgallagher.h" #include "cmdlfgallagher.h"
@ -157,10 +158,11 @@ int detectGallagher(uint8_t *dest, size_t *size) {
if (*size < 96) return -1; //make sure buffer has data if (*size < 96) return -1; //make sure buffer has data
size_t startIdx = 0; size_t startIdx = 0;
uint8_t preamble[] = { uint8_t preamble[] = {
0, 0, 0, 0, 1, 1, 1, 1, //0, 0, 0, 0,
1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1,
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
0, 1, 1, 0, 0, 0, 0, 1 0, 1, 1, 0, 0, 0
}; };
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
return -2; //preamble not found return -2; //preamble not found

View file

@ -26,6 +26,8 @@
#include "lfdemod.h" // parityTest #include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
#define JABLOTRON_ARR_LEN 64
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_lf_jablotron_clone(void) { static int usage_lf_jablotron_clone(void) {
@ -103,7 +105,7 @@ static int CmdJablotronDemod(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
setDemodBuff(DemodBuffer, 64, ans); setDemodBuff(DemodBuffer, JABLOTRON_ARR_LEN, ans);
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock)); setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
//got a good demod //got a good demod
@ -117,9 +119,12 @@ static int CmdJablotronDemod(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2); PrintAndLogEx(SUCCESS, "Jablotron Tag Found: Card ID: %"PRIx64" :: Raw: %08X%08X", id, raw1, raw2);
uint8_t chksum = raw2 & 0xFF; uint8_t chksum = raw2 & 0xFF;
PrintAndLogEx(INFO, "Checksum: %02X [%s]", bool isok = (chksum == jablontron_chksum(DemodBuffer));
PrintAndLogEx(isok ? SUCCESS : INFO,
"Checksum: %02X [ %s]",
chksum, chksum,
(chksum == jablontron_chksum(DemodBuffer)) ? _GREEN_("OK") : _RED_("Fail") isok ? _GREEN_("OK") : _RED_("Fail")
); );
id = DEC2BCD(id); id = DEC2BCD(id);
@ -142,16 +147,13 @@ static int CmdJablotronClone(const char *Cmd) {
uint64_t fullcode = 0; uint64_t fullcode = 0;
uint32_t blocks[3] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0}; uint32_t blocks[3] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0};
uint8_t bits[64];
memset(bits, 0, sizeof(bits));
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone(); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
fullcode = param_get64ex(Cmd, 0, 0, 16); fullcode = param_get64ex(Cmd, 0, 0, 16);
//Q5 //Q5
if (param_getchar(Cmd, 1) == 'Q' || param_getchar(Cmd, 1) == 'q') if (tolower(param_getchar(Cmd, 1)) == 'q')
blocks[0] = T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT; blocks[0] = T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT;
// clearing the topbit needed for the preambl detection. // clearing the topbit needed for the preambl detection.
@ -160,6 +162,12 @@ static int CmdJablotronClone(const char *Cmd) {
PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode); PrintAndLogEx(INFO, "Card Number Truncated to 39bits: %"PRIx64, fullcode);
} }
uint8_t *bits = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
if (bits == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
if (getJablotronBits(fullcode, bits) != PM3_SUCCESS) { if (getJablotronBits(fullcode, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
return PM3_ESOFT; return PM3_ESOFT;
@ -168,6 +176,8 @@ static int CmdJablotronClone(const char *Cmd) {
blocks[1] = bytebits_to_byte(bits, 32); blocks[1] = bytebits_to_byte(bits, 32);
blocks[2] = bytebits_to_byte(bits + 32, 32); blocks[2] = bytebits_to_byte(bits + 32, 32);
free(bits);
PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode); PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode);
print_blocks(blocks, ARRAYLEN(blocks)); print_blocks(blocks, ARRAYLEN(blocks));
@ -190,18 +200,25 @@ static int CmdJablotronSim(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode); PrintAndLogEx(SUCCESS, "Simulating Jablotron - FullCode: %"PRIx64, fullcode);
uint8_t bs[64]; uint8_t *bs = calloc(JABLOTRON_ARR_LEN, sizeof(uint8_t));
if (bs == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory");
return PM3_EMALLOC;
}
getJablotronBits(fullcode, bs); getJablotronBits(fullcode, bs);
lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + sizeof(bs)); lf_asksim_t *payload = calloc(1, sizeof(lf_asksim_t) + JABLOTRON_ARR_LEN);
payload->encoding = 2; payload->encoding = 2;
payload->invert = 1; payload->invert = 1;
payload->separator = 0; payload->separator = 0;
payload->clock = 64; payload->clock = 64;
memcpy(payload->data, bs, sizeof(bs)); memcpy(payload->data, bs, JABLOTRON_ARR_LEN);
free(bs);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + sizeof(bs)); SendCommandNG(CMD_LF_ASK_SIMULATE, (uint8_t *)payload, sizeof(lf_asksim_t) + JABLOTRON_ARR_LEN);
free(payload); free(payload);
PacketResponseNG resp; PacketResponseNG resp;
@ -251,12 +268,12 @@ int getJablotronBits(uint64_t fullcode, uint8_t *bits) {
// the parameter *bits needs to be demoded before call // the parameter *bits needs to be demoded before call
// 0xFFFF preamble, 64bits // 0xFFFF preamble, 64bits
int detectJablotron(uint8_t *bits, size_t *size) { int detectJablotron(uint8_t *bits, size_t *size) {
if (*size < 64 * 2) return -1; //make sure buffer has enough data if (*size < JABLOTRON_ARR_LEN * 2) return -1; //make sure buffer has enough data
size_t startIdx = 0; size_t startIdx = 0;
uint8_t preamble[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; uint8_t preamble[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0};
if (preambleSearch(bits, preamble, sizeof(preamble), size, &startIdx) == 0) if (preambleSearch(bits, preamble, sizeof(preamble), size, &startIdx) == 0)
return -2; //preamble not found return -2; //preamble not found
if (*size != 64) return -3; // wrong demoded size if (*size != JABLOTRON_ARR_LEN) return -3; // wrong demoded size
uint8_t checkchksum = jablontron_chksum(bits + startIdx); uint8_t checkchksum = jablontron_chksum(bits + startIdx);
uint8_t crc = bytebits_to_byte(bits + startIdx + 56, 8); uint8_t crc = bytebits_to_byte(bits + startIdx + 56, 8);

View file

@ -257,7 +257,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
case ISO_14443B: case ISO_14443B:
case TOPAZ: case TOPAZ:
case FELICA: case FELICA:
crcStatus = iso14443B_CRC_check(frame, data_len); crcStatus = !felica_CRC_check(frame + 2, data_len - 4);
break; break;
case PROTO_MIFARE: case PROTO_MIFARE:
crcStatus = mifare_CRC_check(isResponse, frame, data_len); crcStatus = mifare_CRC_check(isResponse, frame, data_len);
@ -301,6 +301,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
&& protocol != ISO_7816_4 && protocol != ISO_7816_4
&& protocol != PROTO_HITAG && protocol != PROTO_HITAG
&& protocol != THINFILM && protocol != THINFILM
&& protocol != FELICA
&& (isResponse || protocol == ISO_14443A) && (isResponse || protocol == ISO_14443A)
&& (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) { && (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) {
@ -349,6 +350,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
if (protocol == PROTO_MIFARE) if (protocol == PROTO_MIFARE)
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
if (protocol == FELICA)
annotateFelica(explanation, sizeof(explanation), frame, data_len);
if (!isResponse) { if (!isResponse) {
switch (protocol) { switch (protocol) {
case ICLASS: case ICLASS:
@ -408,7 +412,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
sprint_hex_inrow_spaces(mfData, mfDataLen, 2), sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
explanation); explanation);
}; }
if (is_last_record(tracepos, trace, traceLen)) return traceLen; if (is_last_record(tracepos, trace, traceLen)) return traceLen;
@ -424,195 +428,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
return tracepos; return tracepos;
} }
static void printFelica(uint16_t traceLen, uint8_t *trace) {
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
PrintAndLogEx(NORMAL, " Gap | Src | Data | CRC | Annotation |");
PrintAndLogEx(NORMAL, "--------|-----|---------------------------------|----------|-------------------|");
uint16_t tracepos = 0;
while (tracepos < traceLen) {
if (tracepos + 3 >= traceLen) break;
uint16_t gap = *((uint16_t *)(trace + tracepos));
uint8_t crc_ok = trace[tracepos + 2];
tracepos += 3;
if (tracepos + 3 >= traceLen) break;
uint16_t len = trace[tracepos + 2];
//I am stripping SYNC
tracepos += 3; //skip SYNC
if (tracepos + len + 1 >= traceLen) break;
uint8_t cmd = trace[tracepos];
uint8_t isResponse = cmd & 1;
char line[32][110] = {{0}};
for (int j = 0; j < len + 1 && j / 8 < 32; j++) {
snprintf(line[j / 8] + ((j % 8) * 4), 110, " %02x ", trace[tracepos + j]);
}
char expbuf[50];
switch (cmd) {
case FELICA_POLL_REQ:
snprintf(expbuf, 49, "Poll Req");
break;
case FELICA_POLL_ACK:
snprintf(expbuf, 49, "Poll Resp");
break;
case FELICA_REQSRV_REQ:
snprintf(expbuf, 49, "Request Srvc Req");
break;
case FELICA_REQSRV_ACK:
snprintf(expbuf, 49, "Request Srv Resp");
break;
case FELICA_RDBLK_REQ:
snprintf(expbuf, 49, "Read block(s) Req");
break;
case FELICA_RDBLK_ACK:
snprintf(expbuf, 49, "Read block(s) Resp");
break;
case FELICA_WRTBLK_REQ:
snprintf(expbuf, 49, "Write block(s) Req");
break;
case FELICA_WRTBLK_ACK:
snprintf(expbuf, 49, "Write block(s) Resp");
break;
case FELICA_SRCHSYSCODE_REQ:
snprintf(expbuf, 49, "Search syscode Req");
break;
case FELICA_SRCHSYSCODE_ACK:
snprintf(expbuf, 49, "Search syscode Resp");
break;
case FELICA_REQSYSCODE_REQ:
snprintf(expbuf, 49, "Request syscode Req");
break;
case FELICA_REQSYSCODE_ACK:
snprintf(expbuf, 49, "Request syscode Resp");
break;
case FELICA_AUTH1_REQ:
snprintf(expbuf, 49, "Auth1 Req");
break;
case FELICA_AUTH1_ACK:
snprintf(expbuf, 49, "Auth1 Resp");
break;
case FELICA_AUTH2_REQ:
snprintf(expbuf, 49, "Auth2 Req");
break;
case FELICA_AUTH2_ACK:
snprintf(expbuf, 49, "Auth2 Resp");
break;
case FELICA_RDSEC_REQ:
snprintf(expbuf, 49, "Secure read Req");
break;
case FELICA_RDSEC_ACK:
snprintf(expbuf, 49, "Secure read Resp");
break;
case FELICA_WRTSEC_REQ:
snprintf(expbuf, 49, "Secure write Req");
break;
case FELICA_WRTSEC_ACK:
snprintf(expbuf, 49, "Secure write Resp");
break;
case FELICA_REQSRV2_REQ:
snprintf(expbuf, 49, "Request Srvc v2 Req");
break;
case FELICA_REQSRV2_ACK:
snprintf(expbuf, 49, "Request Srvc v2 Resp");
break;
case FELICA_GETSTATUS_REQ:
snprintf(expbuf, 49, "Get status Req");
break;
case FELICA_GETSTATUS_ACK:
snprintf(expbuf, 49, "Get status Resp");
break;
case FELICA_OSVER_REQ:
snprintf(expbuf, 49, "Get OS Version Req");
break;
case FELICA_OSVER_ACK:
snprintf(expbuf, 49, "Get OS Version Resp");
break;
case FELICA_RESET_MODE_REQ:
snprintf(expbuf, 49, "Reset mode Req");
break;
case FELICA_RESET_MODE_ACK:
snprintf(expbuf, 49, "Reset mode Resp");
break;
case FELICA_AUTH1V2_REQ:
snprintf(expbuf, 49, "Auth1 v2 Req");
break;
case FELICA_AUTH1V2_ACK:
snprintf(expbuf, 49, "Auth1 v2 Resp");
break;
case FELICA_AUTH2V2_REQ:
snprintf(expbuf, 49, "Auth2 v2 Req");
break;
case FELICA_AUTH2V2_ACK:
snprintf(expbuf, 49, "Auth2 v2 Resp");
break;
case FELICA_RDSECV2_REQ:
snprintf(expbuf, 49, "Secure read v2 Req");
break;
case FELICA_RDSECV2_ACK:
snprintf(expbuf, 49, "Secure read v2 Resp");
break;
case FELICA_WRTSECV2_REQ:
snprintf(expbuf, 49, "Secure write v2 Req");
break;
case FELICA_WRTSECV2_ACK:
snprintf(expbuf, 49, "Secure write v2 Resp");
break;
case FELICA_UPDATE_RNDID_REQ:
snprintf(expbuf, 49, "Update IDr Req");
break;
case FELICA_UPDATE_RNDID_ACK:
snprintf(expbuf, 49, "Update IDr Resp");
break;
default:
snprintf(expbuf, 49, "Unknown");
break;
}
int num_lines = MIN((len) / 16 + 1, 16);
for (int j = 0; j < num_lines ; j++) {
if (j == 0) {
PrintAndLogEx(NORMAL, "%7d | %s |%-32s |%02x %02x %s| %s",
gap,
(isResponse ? "Tag" : "Rdr"),
line[j],
trace[tracepos + len],
trace[tracepos + len + 1],
(crc_ok) ? "OK" : "NG",
expbuf);
} else {
PrintAndLogEx(NORMAL, " | |%-32s | | ", line[j]);
}
}
tracepos += len + 1;
}
PrintAndLogEx(NORMAL, "");
}
// sanity check. Don't use proxmark if it is offline and you didn't specify useTraceBuffer // sanity check. Don't use proxmark if it is offline and you didn't specify useTraceBuffer
/* /*
static int SanityOfflineCheck( bool useTraceBuffer ){ static int SanityOfflineCheck( bool useTraceBuffer ){
@ -819,9 +634,13 @@ int CmdTraceList(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes)", traceLen); PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes)", traceLen);
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
/*
if (protocol == FELICA) { if (protocol == FELICA) {
printFelica(traceLen, trace); printFelica(traceLen, trace);
} else if (showHex) { } */
if (showHex) {
while (tracepos < traceLen) { while (tracepos < traceLen) {
tracepos = printHexLine(tracepos, traceLen, trace, protocol); tracepos = printHexLine(tracepos, traceLen, trace, protocol);
} }
@ -844,6 +663,8 @@ int CmdTraceList(const char *Cmd) {
PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet"); PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet");
if (protocol == PROTO_HITAG) if (protocol == PROTO_HITAG)
PrintAndLogEx(NORMAL, "Hitag2 / HitagS - Timings in ETU (8us)"); PrintAndLogEx(NORMAL, "Hitag2 / HitagS - Timings in ETU (8us)");
if (protocol == FELICA)
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation");

View file

@ -22,7 +22,7 @@ a0478cc39091
# #
d2ece8b9395e # lib d2ece8b9395e # lib
# NSCP default key # NSCP default key
1494E81663D7 1494E81663D7
# #
# more Keys from mfc_default_keys.lua # more Keys from mfc_default_keys.lua
000000000001 000000000001
@ -126,6 +126,13 @@ fb0b20df1f34 # S6 B
# #
a9f953def0a3 a9f953def0a3
# #
# Data from forum
74a386ad0a6d
3f7a5c2dbd81
21edf95e7433
c121ff19f681
3d5d9996359a
#
# Here be BIP keys... # Here be BIP keys...
3A42F33AF429 3A42F33AF429
1FC235AC1309 1FC235AC1309

Binary file not shown.

View file

@ -1,90 +0,0 @@
local luamiibo_open, err = package.loadlib("./libluamiibo.so", "luaopen_luamiibo")
if err then
print(err)
return
end
local luamiibo = luamiibo_open()
local FLAG_SETTINGS_INITIALIZED = 4
local FLAG_APPDATA_INITIALIZED = 3
local Amiibo = {}
Amiibo.__index = Amiibo
function Amiibo:new (o)
o = o or {}
setmetatable(o, self)
if o.tag ~= nil then
o:load_tag(o.tag)
end
return o
end
function Amiibo:load_tag (tag)
self.plain = luamiibo.unpack(tag)
-- UID
local raw_uid = string.sub(self.plain, 469, 469 + 8)
self.uid = string.sub(raw_uid, 1, 3) .. string.sub(raw_uid, 5, 8)
-- Settings
local count, flags = bin.unpack('C', string.sub(self.plain, 45, 45))
self.setting_flags = flags
self.settings_initialized = self:check_flag(FLAG_SETTINGS_INITIALIZED)
self.appdata_initialized = self:check_flag(FLAG_APPDATA_INITIALIZED)
local _, appdatacounter = bin.unpack('>S', string.sub(self.plain, 49, 50))
self.appdata_counter = appdatacounter
self.figure_id = string.sub(self.plain, 477, 477 + 8)
-- UTF-16 nickname string
self.nickname = string.sub(self.plain, 57, 76)
end
function Amiibo:export_tag ()
return luamiibo.pack(self.plain)
end
function Amiibo:check_flag (power)
local flag = math.pow(2, power)
return flag == bit32.band(self.setting_flags, flag)
end
function Amiibo:get_pwd ()
local xorkey = "\xaa\x55\xaa\x55"
local result = ''
for i = 1, 4 do
result = result ..
bin.pack('C',
bit32.bxor(self.uid:byte(i+1),
self.uid:byte(i+3),
xorkey:byte(i)))
end
return result
end
-- Hack to make UTF-16 nicknames into regular char string
-- Only works for ASCII nicknames
function Amiibo:display_nickname()
local nickname_tmp = self.nickname
local nickname = ''
for i = 1, nickname_tmp:len() do
if i % 2 == 0 then
nickname = nickname .. nickname_tmp:sub(i, i)
end
end
return nickname
end
return Amiibo

View file

@ -1,84 +0,0 @@
local cmds = require('commands')
local utils = require('utils')
local reader = require('read14a')
local Emulator = {
_VERSION = 'emulator.lua 0.1.0',
_DESCRIPTION = 'emulator memory interface',
BLOCK_SZ = 512,
BLOCK_COUNT = 512 / 16
}
function Emulator:set_mem (data, clear_first)
if clear_first then
-- Clear out the emulator memory first
local memclrCmd = Command:newMIX{cmd = cmds.CMD_HF_MIFARE_EML_MEMCLR}
local _, err = memclrCmd:sendMIX()
if err then
print('Failed to clear emulator memory:', err)
return false
else
print('Cleared emulator memory')
end
end
-- Can fit 32 16 byte blocks per command (512 total bytes max)
for i = 0, (data:len() / self.BLOCK_SZ) do
local cur_out_block = data:sub((i*self.BLOCK_SZ) + 1, (i*self.BLOCK_SZ) + self.BLOCK_SZ)
print(string.format('Transmission #%u: %u bytes', i, cur_out_block:len()))
-- arg1: start block number
-- arg2: block count
local memsetCmd = Command:newMIX{cmd = cmds.CMD_HF_MIFARE_EML_MEMSET,
data = utils.hexlify(cur_out_block),
arg1 = i * self.BLOCK_COUNT,
arg2 = self.BLOCK_COUNT}
-- Send command and wait for response
local _, err = memsetCmd:sendMIX()
if err then
print('Failed setting memory', err)
return false
end
end
print('Emulator memory set')
return true
end
-- Read <size> bytes from emulator memory
function Emulator:get_mem (size)
local MAX_BLOCKS = 4
local result = ''
-- We can request a maximum of 4 blocks (16 bytes each) per command,
-- according to mifarecmd.c
for i = 0, (size / (MAX_BLOCKS * 16)) do
-- arg1: start block number
-- arg2: block count (max 4)
local getmemCmd = Command:newMIX{cmd = cmds.CMD_HF_MIFARE_EML_MEMGET,
arg1 = i * MAX_BLOCKS,
arg2 = MAX_BLOCKS,
arg3 = 0}
local response, err = getmemCmd:sendMIX()
if err then
print('Failed getting memory:', err)
return false
end
-- USB data begins after four 64-bit values
local data_begin = ((64/8) * 4) + 1
response = string.sub(response, data_begin)
-- Truncate to the received 16 byte blocks
response = string.sub(response, 1, 16 * MAX_BLOCKS)
result = result .. response
end
return string.sub(result, 1, size)
end
return Emulator

View file

@ -1,235 +0,0 @@
local utils = require('utils')
local cmds = require('commands')
local Amiibo = require('amiibolib')
local reader = require('read14a')
local bin = require('bin')
local emu = require('emulator')
local luamiibo_open, err = package.loadlib("./libluamiibo.so", "luaopen_luamiibo")
if err then
print(err)
return
end
local luamiibo = luamiibo_open()
local function nfc_read_amiibo ()
local command = Command:newMIX{
cmd = cmds.CMD_HF_MIFAREU_READCARD,
arg1 = 0,
arg2 = 135
}
local result, err = command:sendMIX()
if result then
-- Do Mifare Ultralight read
local count, cmd, arg0, data_len, offset = bin.unpack('LLLL', result)
if arg0 == 0 then
return nil, "Card select failed"
end
-- Do GetFromBigBuf
local data = core.GetFromBigBuf(offset, data_len)
return data, err
else
return nil, "Couldn't read Amiibo"
end
end
local function emulate_amiibo (amiibo_data)
-- Make UID args
-- Use known ID/sig for known ECDSA signature - REPLACE ME!
local uid_bytes = '\x00\x04\xFF\xFF\xFF\xFF\xFF\xFF'
local ecc_sig = ''
.. '\x00\x00\x00\x00\x00\x00\x00\x00'
.. '\x00\x00\x00\x00\x00\x00\x00\x00'
.. '\x00\x00\x00\x00\x00\x00\x00\x00'
.. '\x00\x00\x00\x00\x00\x00\x00\x00'
if amiibo_data:len() == 520 then
-- Add common ending bytes
print('Added missing ending bytes')
amiibo_data = amiibo_data
.. '\x01\x00\x0F\xBD\x00\x00\x00\x04'
.. '\x5F\x00\x00\x00\x00\x00\x00\x00'
.. '\x00\x00\x00\x00'
end
if amiibo_data:len() == 572 then
-- Get ECC signature and use original serial
uid_bytes = '\x00' .. amiibo_data:sub(1,3) .. amiibo_data:sub(5,8)
ecc_sig = amiibo_data:sub(541, 572)
print('Amiibo image contains ECC signature', hexlify(ecc_sig))
--amiibo_data = amiibo_data:sub(1,540)
elseif amiibo_data:len() == 540 then
if uid_bytes ~= '\x00\x04\xFF\xFF\xFF\xFF\xFF\xFF' then
print('Using known ECC sig pair')
else
print('No known ECC/sig pair; using null signature')
uid_bytes = '\x00' .. amiibo_data:sub(1,3) .. amiibo_data:sub(5,8)
end
amiibo_data = amiibo_data .. ecc_sig
else
print('Unusual Amiibo image size', amiibo_data:len())
end
-- Send amiibo data to emulator memory. If the Amiibo was just scanned, this
-- is already set!
if not emu:set_mem(amiibo_data, false) then
print('Failed to set emulator card memory')
return
end
-- Get UID parts
local count, uid_first, uid_second = bin.unpack('>I>I', uid_bytes)
print(string.format('Simulating with UID: 0x%04x 0x%04x', uid_first, uid_second))
-- Begin simulating NTAG215
local simCmd = Command:newMIX{
cmd = cmds.CMD_HF_ISO14443A_SIMULATE,
arg1 = 7,
arg2 = uid_first,
arg3 = uid_second
}
local _, err = simCmd:sendMIX()
if err then
print('Failed to start simulator', err)
return
else
print('Starting simulator')
end
end
local function test_packing()
-- Load Pikachu dump instead
local dumpfile = io.open("pika.bin", "rb")
local pikachu = dumpfile:read("*all")
local unpacked_pika = luamiibo.unpack(pikachu)
local packed_data = luamiibo.pack(unpacked_pika)
print('Original', utils.hexlify(pikachu))
print('Unpacked', utils.hexlify(unpacked_pika))
print('Packed', utils.hexlify(packed_data))
end
local function load_sim(argv)
local tag = assert(io.open(argv[2], "rb"))
local data = tag:read("*all")
tag:close()
emulate_amiibo(data)
return
end
local function dump_sim(argv)
local keypath = argv[2]
if keypath == nil then
keypath = 'amiitool_keys.bin'
end
luamiibo.load_keys(keypath)
-- Read all 135 pages
dump = emu:get_mem(540)
if dump == false then
print('Failed to read emulator memory')
else
local amiiboData = Amiibo:new{tag = dump}
print('Dumped ' .. dump:len() .. ' bytes')
print(hexlify(dump))
print('Nickname: ' .. utils.hexlify(amiiboData:display_nickname()))
-- Write dump to file
local filename = argv[2]
if filename ~= nil then
local outfile = assert(io.open(filename, "wb"))
outfile:write(dump)
outfile:close()
print('Wrote to ' .. filename)
else
print('No output file specified')
end
end
end
local function main(args)
argv = {}
for arg in string.gmatch(args, "%S+") do
table.insert(argv, arg)
end
-- Load and emulate Amiibo from image
if argv[1] == 'help' then
print('read - scan amiibo')
print('load <amiibo.bin> - load and simulate amiibo')
print('dump [output_file] - dump card memory')
print('help - print this help')
return
elseif argv[1] == 'load' then
load_sim(argv)
return
elseif argv[1] == 'dump' then
dump_sim(argv)
return
elseif argv[1] ~= 'read' and argv[1] ~= nil then
print('Unknown command')
end
local keypath = argv[2]
if keypath == nil then
keypath = 'amiitool_keys.bin'
end
if luamiibo.load_keys(keypath) then
print('Loaded retail keys from ' .. keypath)
else
print('Failed to load retail keys from ' .. keypath)
return
end
local tag, err = nfc_read_amiibo()
if err then
print(err)
return
elseif tag:len() ~= 540 then
print('Incorrect tag data size ' .. tag:len())
return
end
parsed_tag = reader.parse14443a(tag)
print('Tag type:', parsed_tag.name)
print('Tag UID:', parsed_tag.uid)
print('Tag len:', tag:len())
--print('Tag data:', utils.hexlify(tag))
local amiiboData = Amiibo:new{tag = tag}
--print('Unpacked:', utils.hexlify(amiiboData.plain))
--print('Repacked:', utils.hexlify(amiiboData:export_tag()))
print('Figure ID:', utils.hexlify(amiiboData.figure_id))
print('Settings init:', amiiboData.settings_initialized)
if amiiboData.settings_initialized then
print('Nickname:', amiiboData:display_nickname())
print('Appdata writes:', amiiboData.appdata_counter)
end
print('UID:', utils.hexlify(amiiboData.uid))
print('Write key:', utils.hexlify(amiiboData:get_pwd()))
--print('Attempting emulation...')
--emulate_amiibo(amiiboData:export_tag())
return
end
main(args)

View file

@ -3,11 +3,13 @@ local bin = require('bin')
copyright = 'Copyright (c) 2018 Bogito. All rights reserved.' copyright = 'Copyright (c) 2018 Bogito. All rights reserved.'
author = 'Bogito' author = 'Bogito'
version = 'v1.0.2' version = 'v1.0.3'
desc = desc =
[[ [[
This script will read the flash memory of RDV4 and print the stored passwords. This script will read the flash memory of RDV4 and print the stored passwords/keys.
It was meant to be used as a help tool after using the BogRun standalone mode.
It was meant to be used as a help tool after using the BogRun standalone mode before SPIFFS.
You should now use read_pwd_mem_spiffs instead after the updated BogRun standalone mode.
(Iceman) script adapted to read and print keys in the default dictionary flashmemory sections. (Iceman) script adapted to read and print keys in the default dictionary flashmemory sections.
]] ]]
@ -22,8 +24,14 @@ example =
-- This will scan 32 bytes of flash memory at offset 64 for stored passwords -- This will scan 32 bytes of flash memory at offset 64 for stored passwords
script run read_pwd_mem -o 64 -l 32 script run read_pwd_mem -o 64 -l 32
-- This will print found -- This will print the stored Mifare dictionary keys
script run read_pwd_mem -o 241664 -k 6 script run read_pwd_mem -m
-- This will print the stored t55xx dictionary passwords
script run read_pwd_mem -t
-- This will print the stored iClass dictionary keys
script run read_pwd_mem -i
]] ]]
usage = usage =
[[ [[
@ -66,7 +74,6 @@ local function main(args)
print() print()
local data, err, quadlet local data, err, quadlet
local cnt = 0
local offset = 0 local offset = 0
local length = 256 local length = 256
local keylength = 4 local keylength = 4

View file

@ -0,0 +1,102 @@
local getopt = require('getopt')
local bin = require('bin')
copyright = 'Copyright (c) 2019 Bogito. All rights reserved.'
author = 'Bogito'
version = 'v1.1.1'
desc =
[[
This script will read the flash memory of RDV4 using SPIFFS and print the stored passwords.
It was meant to be used as a help tool after using the BogRun standalone mode.
]]
example =
[[
-- This will read the hf_bog.log file in SPIFFS and print the stored passwords
script run read_pwd_mem_spiffs
-- This will read the other.log file in SPIFFS and print the stored passwords
script run read_pwd_mem_spiffs -f other.log
-- This will delete the hf_bog.log file from SPIFFS
script run read_pwd_mem_spiffs -r
]]
usage =
[[
Usage:
script run read_pwd_mem_spiffs -h -f <filename> -r
Arguments:
-h : this help
-f <filename> : filename in SPIFFS
-r : delete filename from SPIFFS
]]
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print('Example usage')
print(example)
print(usage)
end
---
-- The main entry point
local function main(args)
print( string.rep('--',20) )
print('Read passwords stored in memory (SPIFFS)')
print( string.rep('--',20) )
print()
local data, length, err, removeflag
local filename = 'hf_bog.log'
local keylength = 4
for o, a in getopt.getopt(args, 'rf:h') do
-- help
if o == 'h' then return help() end
-- offset
if o == 'f' then filename = a end
-- remove
if o == 'r' then removeflag = true end
end
if removeflag then
print('Deleting file '..filename.. ' from SPIFFS if exists')
core.console("mem spiffs remove " ..filename)
return
end
data, length, err = core.GetFromFlashMemSpiffs(filename)
if data == nil then return oops('Problem while reading file from SPIFFS') end
--print('Filename', filename)
--print('Filesize (B)', length)
_, s = bin.unpack('H'..length, data)
local cnt = 0, i
for i = 1, length/keylength do
key = string.sub(s, (i-1)*8+1, i*8)
print(string.format('[%02d] %s',i, key))
cnt = cnt + 1
end
print( string.rep('--',20) )
print( ('[+] found %d passwords'):format(cnt))
end
main(args)

File diff suppressed because one or more lines are too long

View file

@ -304,6 +304,61 @@ static int l_GetFromFlashMem(lua_State *L) {
} }
/**
* @brief The following params expected:
* uint8_t *destfilename
* @param L
* @return
*/
static int l_GetFromFlashMemSpiffs(lua_State *L) {
if (IfPm3Flash()) {
uint32_t start_index = 0, len = 0x40000; //FLASH_MEM_MAX_SIZE
char destfilename[32] = {0};
size_t size;
int n = lua_gettop(L);
if (n == 0)
return returnToLuaWithError(L, "You need to supply the destination filename");
if (n >= 1) {
const char *p_filename = luaL_checklstring(L, 1, &size);
if (size != 0)
memcpy(destfilename, p_filename, 31);
}
if (destfilename[0] == '\0')
return returnToLuaWithError(L, "Filename missing or invalid");
// get size from spiffs itself !
SendCommandMIX(CMD_SPIFFS_STAT, 0, 0, 0, (uint8_t *)destfilename, 32);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000))
return returnToLuaWithError(L, "No response from the device");
len = resp.oldarg[0];
if (len <= 0)
return returnToLuaWithError(L, "Filename invalid or empty");
uint8_t *data = calloc(len, sizeof(uint8_t));
if (!data)
return returnToLuaWithError(L, "Allocating memory failed");
if (!GetFromDevice(SPIFFS, data, len, start_index, (uint8_t *)destfilename, 32, NULL, -1, true)) {
free(data);
return returnToLuaWithError(L, "ERROR; downloading from spiffs(flashmemory)");
}
lua_pushlstring(L, (const char *)data, len);
lua_pushunsigned(L, len);
free(data);
return 2;
} else {
return returnToLuaWithError(L, "No FLASH MEM support");
}
}
/** /**
* @brief The following params expected: * @brief The following params expected:
* uint32_t cmd * uint32_t cmd
@ -1128,6 +1183,7 @@ int set_pm3_libraries(lua_State *L) {
{"SendCommandNG", l_SendCommandNG}, {"SendCommandNG", l_SendCommandNG},
{"GetFromBigBuf", l_GetFromBigBuf}, {"GetFromBigBuf", l_GetFromBigBuf},
{"GetFromFlashMem", l_GetFromFlashMem}, {"GetFromFlashMem", l_GetFromFlashMem},
{"GetFromFlashMemSpiffs", l_GetFromFlashMemSpiffs},
{"WaitForResponseTimeout", l_WaitForResponseTimeout}, {"WaitForResponseTimeout", l_WaitForResponseTimeout},
{"mfDarkside", l_mfDarkside}, {"mfDarkside", l_mfDarkside},
{"foobar", l_foobar}, {"foobar", l_foobar},

View file

@ -52,11 +52,7 @@ pacman -S mingw-w64-x86_64-astyle
## Compile and use the project ## Compile and use the project
To use the compiled client, the only differences are that executables end with `.exe` (e.g. `proxmark3.exe`) and that the Proxmark3 port is one of your `comX` ports where "X" is the com port number assigned to proxmark3 under Windows, so commands become: To use the compiled client, the only differences are that executables end with `.exe` (e.g. `proxmark3.exe`) and that the Proxmark3 port is one of your `comX` ports where "X" is the com port number assigned to proxmark3 under Windows, so commands like `proxmark3 /dev/ttyACMX` become `proxmark3.exe comX`.
```sh
proxmark3 /dev/ttyACM0 => proxmark3.exe comX
```
Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md).

View file

@ -48,6 +48,7 @@ Known issues:
* 256kb Arm chip devices: The compiled firmware image from this repo may/will be too large for your device. * 256kb Arm chip devices: The compiled firmware image from this repo may/will be too large for your device.
* PM3 Evo: it has a different led/button pin assignment. It tends to be messed up. * PM3 Evo: it has a different led/button pin assignment. It tends to be messed up.
* Proxmark Pro: it has different fpga and unknown pin assignments. Will most certainly mess up
## PLATFORM_EXTRAS ## PLATFORM_EXTRAS

View file

@ -205,6 +205,21 @@ typedef struct {
felica_status_flags_t status_flags; felica_status_flags_t status_flags;
} PACKED felica_status_response_t; } PACKED felica_status_response_t;
typedef struct {
felica_frame_response_t frame_response;
uint8_t number_of_systems[1];
uint8_t system_code_list[32];
} PACKED felica_syscode_response_t;
typedef struct {
felica_frame_response_t frame_response;
felica_status_flags_t status_flags;
uint8_t format_version[1];
uint8_t basic_version[2];
uint8_t number_of_option[1];
uint8_t option_version_list[4];
} PACKED felica_request_spec_response_t;
typedef enum FELICA_COMMAND { typedef enum FELICA_COMMAND {
FELICA_CONNECT = (1 << 0), FELICA_CONNECT = (1 << 0),
FELICA_NO_DISCONNECT = (1 << 1), FELICA_NO_DISCONNECT = (1 << 1),

View file

@ -507,6 +507,9 @@ typedef struct {
#define CMD_HF_MIFARE_NACK_DETECT 0x0730 #define CMD_HF_MIFARE_NACK_DETECT 0x0730
// MFU OTP TearOff
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
#define CMD_HF_SNIFF 0x0800 #define CMD_HF_SNIFF 0x0800
// For ThinFilm Kovio // For ThinFilm Kovio