mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
commit
d7144d1422
43 changed files with 3283 additions and 929 deletions
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
|
|||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt 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"]
|
||||
|
|
|
@ -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...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Fix hf list felica and hf felica sniff (@7homasSutter)
|
||||
- Added hf felica wrunencrypted (@7homasSutter)
|
||||
- Added hf felica rdunencrypted (@7homasSutter)
|
||||
- Added hf felica rqresponse (@7homasSutter)
|
||||
- Added hf felica rqservice (@7homasSutter)
|
||||
|
|
|
@ -216,13 +216,11 @@ void RAMFUNC SniffAndStore(uint8_t param) {
|
|||
if (auth_attempts > 0) {
|
||||
if (DBGLEVEL > 1)
|
||||
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)) {
|
||||
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 {
|
||||
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();
|
||||
SpinDelay(300);
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -696,10 +696,23 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
*/
|
||||
|
||||
switch (packet->cmd) {
|
||||
case CMD_QUIT_SESSION:
|
||||
case CMD_QUIT_SESSION: {
|
||||
reply_via_fpc = false;
|
||||
reply_via_usb = false;
|
||||
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
|
||||
case CMD_LF_T55XX_SET_CONFIG: {
|
||||
setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes);
|
||||
|
@ -1034,12 +1047,6 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// always available
|
||||
case CMD_HF_DROPFIELD: {
|
||||
hf_field_off();
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef WITH_ISO14443a
|
||||
case CMD_HF_ISO14443A_SNIFF: {
|
||||
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);
|
||||
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: {
|
||||
MifareEMemClr();
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
|
||||
|
@ -1245,6 +1245,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
DetectNACKbug();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MFU_OTP_TEAROFF: {
|
||||
MifareU_Otp_Tearoff();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NFCBARCODE
|
||||
|
|
|
@ -410,8 +410,6 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
// clear RXRDY:
|
||||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
uint32_t timeout = iso18092_get_timeout();
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("timeout set: %i", timeout);
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
@ -420,8 +418,8 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
|
|||
Process18092Byte(b);
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
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(
|
||||
FelicaFrame.framebytes,
|
||||
FelicaFrame.len,
|
||||
|
@ -453,7 +451,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
|||
BigBuf_Clear_ext(false);
|
||||
|
||||
// Initialize Demod and Uart structs
|
||||
//DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||
// DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
|
||||
FelicaFrameinit(BigBuf_malloc(FELICA_MAX_FRAME_SIZE));
|
||||
|
||||
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) {
|
||||
|
||||
int remFrames = (samplesToSkip) ? samplesToSkip : 0;
|
||||
|
||||
Dbprintf("Sniff FelicaLiteS: Getting first %d frames, Skipping %d triggers.\n", samplesToSkip, triggersToSkip);
|
||||
|
||||
Dbprintf("Sniff Felica: Getting first %d frames, Skipping after %d triggers.\n", samplesToSkip, triggersToSkip);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||
|
||||
//the frame bits are slow enough.
|
||||
int n = BigBuf_max_traceLen() / sizeof(uint8_t); // take all memory
|
||||
int numbts = 0;
|
||||
uint8_t *dest = (uint8_t *)BigBuf_get_addr();
|
||||
uint8_t *destend = dest + n - 2;
|
||||
|
||||
uint32_t endframe = GetCountSspClk();
|
||||
|
||||
while (dest <= destend) {
|
||||
LED_D_ON();
|
||||
uint16_t numbts = 0;
|
||||
int trigger_cnt = 0;
|
||||
uint32_t timeout = iso18092_get_timeout();
|
||||
bool isReaderFrame = true;
|
||||
while (!BUTTON_PRESS()) {
|
||||
WDT_HIT();
|
||||
if (BUTTON_PRESS()) break;
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
Process18092Byte(dist);
|
||||
|
||||
//to be sure we are in frame
|
||||
if (FelicaFrame.state == STATE_GET_LENGTH) {
|
||||
//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++;
|
||||
if ((MAX(dist & 0xff, dist >> 8) >= 178) && (++trigger_cnt > triggersToSkip)) {
|
||||
Dbprintf("triggersToSkip kicked %d", dist);
|
||||
break;
|
||||
}
|
||||
//crc NOT checked
|
||||
if (FelicaFrame.state == STATE_FULL) {
|
||||
endframe = GetCountSspClk();
|
||||
// *dest = FelicaFrame.crc_ok; //kind of wasteful
|
||||
dest++;
|
||||
for (int i = 0; i < FelicaFrame.len; i++) {
|
||||
*dest = FelicaFrame.framebytes[i];
|
||||
dest++;
|
||||
if (dest >= destend) break;
|
||||
|
||||
if ((FelicaFrame.framebytes[3] % 2) == 0) {
|
||||
isReaderFrame = true; // All Reader Frames are even and all Tag frames are odd
|
||||
} else {
|
||||
isReaderFrame = false;
|
||||
}
|
||||
|
||||
remFrames--;
|
||||
if (remFrames <= 0) break;
|
||||
if (dest >= destend) break;
|
||||
|
||||
if (remFrames <= 0) {
|
||||
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;
|
||||
|
||||
FelicaFrameReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_off();
|
||||
|
||||
//reset framing
|
||||
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(BigBuf_max_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);
|
||||
LED_D_OFF();
|
||||
}
|
||||
|
||||
#define R_POLL0_LEN 0x16
|
||||
|
|
|
@ -1306,6 +1306,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) {
|
|||
AddCrc(csn_data, 8);
|
||||
|
||||
uint8_t diversified_key[8] = { 0 };
|
||||
|
||||
// e-Purse
|
||||
uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
//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
|
||||
memcpy(card_challenge_data, emulator + (8 * 2), 8);
|
||||
|
||||
//Precalculate the cipher state, feeding it the CC
|
||||
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);
|
||||
int resp_csn_len;
|
||||
|
||||
// configuration picopass 2ks
|
||||
// configuration Picopass 2ks
|
||||
uint8_t *resp_conf = BigBuf_malloc(28);
|
||||
int resp_conf_len;
|
||||
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);
|
||||
int resp_aia_len;
|
||||
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);
|
||||
|
||||
// receive command
|
||||
|
|
|
@ -1045,6 +1045,16 @@ static void leadingZeroAskSimBits(int *n, uint8_t clock) {
|
|||
memset(dest + (*n), 0, 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
|
||||
|
@ -1054,10 +1064,14 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
|
|||
|
||||
int n = 0, i = 0;
|
||||
|
||||
leadingZeroAskSimBits(&n, clk);
|
||||
|
||||
if (encoding == 2) { //biphase
|
||||
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++) {
|
||||
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
|
||||
|
||||
leadingZeroAskSimBits(&n, clk);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
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();
|
||||
|
||||
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();
|
||||
SimulateTagLowFrequency(n, 0, ledcontrol);
|
||||
|
@ -2466,7 +2490,7 @@ void Cotag(uint32_t arg0) {
|
|||
|
||||
switch (rawsignal) {
|
||||
case 0:
|
||||
doCotagAcquisition(50000);
|
||||
doCotagAcquisition(40000);
|
||||
break;
|
||||
case 1:
|
||||
doCotagAcquisitionManchester();
|
||||
|
@ -2478,7 +2502,7 @@ void Cotag(uint32_t arg0) {
|
|||
|
||||
// Turn the 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -374,8 +374,8 @@ void doT55x7Acquisition(size_t sample_size) {
|
|||
|
||||
#define COTAG_T1 384
|
||||
#define COTAG_T2 (COTAG_T1>>1)
|
||||
#define COTAG_ONE_THRESHOLD 128+30
|
||||
#define COTAG_ZERO_THRESHOLD 128-30
|
||||
#define COTAG_ONE_THRESHOLD 128+10
|
||||
#define COTAG_ZERO_THRESHOLD 128-10
|
||||
#ifndef COTAG_BITS
|
||||
#define COTAG_BITS 264
|
||||
#endif
|
||||
|
@ -437,6 +437,11 @@ void doCotagAcquisition(size_t sample_size) {
|
|||
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() {
|
||||
|
|
|
@ -2173,3 +2173,70 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
|
|||
LEDsoff();
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -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_Auth2(uint32_t arg0, uint8_t *datain);
|
||||
|
||||
// Tear-off test for MFU
|
||||
void MifareU_Otp_Tearoff();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -186,6 +186,7 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
cmdanalyse.c \
|
||||
cmdhf.c \
|
||||
cmdhflist.c \
|
||||
aidsearch.c \
|
||||
cmdhf14a.c \
|
||||
cmdhf14b.c \
|
||||
cmdhf15.c \
|
||||
|
|
180
client/aidsearch.c
Normal file
180
client/aidsearch.c
Normal 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
28
client/aidsearch.h
Normal 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
|
|
@ -812,7 +812,7 @@ int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveG
|
|||
// sanity check
|
||||
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
|
||||
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) {
|
||||
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)) {
|
||||
PrintAndLogEx(SUCCESS, "possible correlation %4zu samples", correlation);
|
||||
PrintAndLogEx(SUCCESS, "possible correlation " _YELLOW_("%4zu") "samples", correlation);
|
||||
} else {
|
||||
PrintAndLogEx(FAILED, "no repeating pattern found, try increasing window size");
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag...");
|
||||
if (IfPm3Iso14443a()) {
|
||||
if (infoHF14A(false, false) > 0) {
|
||||
if (infoHF14A(false, false, false) > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "ui.h"
|
||||
#include "crc16.h"
|
||||
#include "util_posix.h" // msclock
|
||||
#include "aidsearch.h"
|
||||
|
||||
bool APDUInFramingEnable = true;
|
||||
|
||||
|
@ -226,13 +227,6 @@ static int usage_hf_14a_reader(void) {
|
|||
PrintAndLogEx(NORMAL, " 3 ISO14443-3 select only (skip RATS)");
|
||||
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) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
|
@ -367,12 +361,30 @@ static int CmdHF14AReader(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');
|
||||
bool do_nack_test = (Cmd[0] == 'n' || Cmd[0] == 'N');
|
||||
infoHF14A(verbose, do_nack_test);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1225,7 +1237,7 @@ int CmdHF14A(const char *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();
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
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 {
|
||||
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ int CmdHF14A(const char *Cmd);
|
|||
int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
|
||||
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);
|
||||
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);
|
||||
|
|
|
@ -47,15 +47,19 @@ static int usage_hf_felica_sim(void) {
|
|||
*/
|
||||
|
||||
static int usage_hf_felica_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "It get data from the field and saves it into command buffer.");
|
||||
PrintAndLogEx(NORMAL, "Buffer accessible from command 'hf list felica'");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf felica sniff <s> <t>");
|
||||
PrintAndLogEx(NORMAL, " s samples to skip (decimal)");
|
||||
PrintAndLogEx(NORMAL, " t triggers to skip (decimal)");
|
||||
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, "\nUsage: hf felica sniff [-h] [-s] [-t]");
|
||||
PrintAndLogEx(NORMAL, " -h this help");
|
||||
PrintAndLogEx(NORMAL, " -s samples to skip (decimal) max 9999");
|
||||
PrintAndLogEx(NORMAL, " -t triggers to skip (decimal) max 9999");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int usage_hf_felica_simlite(void) {
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ISO/18092 FeliCa Lite tag \n");
|
||||
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");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_felica_dumplite(void) {
|
||||
PrintAndLogEx(NORMAL, "\n Dump ISO/18092 FeliCa Lite tag \n");
|
||||
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");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_felica_raw(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf felica raw [-h] [-r] [-c] [-p] [-a] <0A 0B 0C ... hex>");
|
||||
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");
|
||||
print_status_flag1_interpretation();
|
||||
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, " -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, " 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;
|
||||
}
|
||||
|
||||
|
@ -240,6 +294,7 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose)
|
|||
PrintAndLogEx(NORMAL, "Client Received %i octets", len);
|
||||
if (!len || len < 2) {
|
||||
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len));
|
||||
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]) {
|
||||
case 'H':
|
||||
case 'h':
|
||||
return usage_hf_felica_request_response();
|
||||
return usage_hf_felica_write_without_encryption();
|
||||
case 'i':
|
||||
paramCount++;
|
||||
custom_IDm = true;
|
||||
|
@ -476,6 +531,8 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
|
|||
paramCount++;
|
||||
i += 16;
|
||||
break;
|
||||
default:
|
||||
return usage_hf_felica_write_without_encryption();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
@ -535,7 +592,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
|
|||
switch (Cmd[i + 1]) {
|
||||
case 'H':
|
||||
case 'h':
|
||||
return usage_hf_felica_request_response();
|
||||
return usage_hf_felica_read_without_encryption();
|
||||
case 'i':
|
||||
paramCount++;
|
||||
custom_IDm = true;
|
||||
|
@ -553,6 +610,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
|
|||
paramCount++;
|
||||
long_block_numbers = true;
|
||||
break;
|
||||
default:
|
||||
return usage_hf_felica_read_without_encryption();
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
@ -641,6 +700,8 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
|
|||
paramCount++;
|
||||
i += 16;
|
||||
break;
|
||||
default:
|
||||
return usage_hf_felica_request_response();
|
||||
}
|
||||
}
|
||||
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.
|
||||
* @param Cmd input data of the user.
|
||||
|
@ -766,103 +1055,57 @@ static int CmdHFFelicaNotImplementedYet(const char *Cmd) {
|
|||
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) {
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t paramCount = 0;
|
||||
uint64_t samples2skip = 0;
|
||||
uint64_t triggers2skip = 0;
|
||||
bool errors = false;
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (param_getchar(Cmd, cmdp)) {
|
||||
strip_cmds(Cmd);
|
||||
int i = 0;
|
||||
while (Cmd[i] != '\0') {
|
||||
if (Cmd[i] == '-') {
|
||||
switch (Cmd[i + 1]) {
|
||||
case 'h':
|
||||
case 'H':
|
||||
return usage_hf_felica_sniff();
|
||||
case 's':
|
||||
case 'S':
|
||||
samples2skip = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
paramCount++;
|
||||
if (param_getlength(Cmd, paramCount) < 5) {
|
||||
samples2skip = param_get32ex(Cmd, paramCount++, 0, 10);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Invalid samples number!");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
triggers2skip = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
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, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
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();
|
||||
SendCommandMIX(CMD_HF_FELICA_SNIFF, samples2skip, triggers2skip, 0, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
|
@ -1277,15 +1520,15 @@ static command_t CommandTable[] = {
|
|||
{"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from 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."},
|
||||
//{"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."},
|
||||
//{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
|
||||
//{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from 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."},
|
||||
//{"getsysstatus", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the setup information in System."},
|
||||
//{"rqspecver", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire the version of card OS."},
|
||||
//{"resetmode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "reset Mode to Mode 0."},
|
||||
{"rqspecver", CmdHFFelicaRequestSpecificationVersion, IfPm3Felica, "acquire the version of card OS."},
|
||||
{"resetmode", CmdHFFelicaResetMode, IfPm3Felica, "reset Mode to Mode 0."},
|
||||
//{"auth1v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."},
|
||||
//{"auth2v2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."},
|
||||
//{"readv2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
|
||||
|
|
|
@ -47,7 +47,7 @@ static int CmdHFFidoInfo(const char *cmd) {
|
|||
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false);
|
||||
infoHF14A(false, false, false);
|
||||
|
||||
// FIDO info
|
||||
PrintAndLogEx(NORMAL, "--------------------------------------------");
|
||||
|
|
|
@ -97,6 +97,10 @@ uint8_t iso15693_CRC_check(uint8_t *d, uint8_t 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
|
||||
* @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) {
|
||||
|
||||
switch (cmd[0]) {
|
||||
switch (cmd[3]) {
|
||||
case FELICA_POLL_REQ:
|
||||
snprintf(exp, size, "POLLING");
|
||||
break;
|
||||
|
|
|
@ -31,6 +31,7 @@ void ClearAuthData(void);
|
|||
|
||||
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 felica_CRC_check(uint8_t *d, uint8_t n);
|
||||
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 iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
||||
|
|
|
@ -533,7 +533,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) {
|
|||
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, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
|
||||
PrintAndLogEx(NORMAL, " hf mf wrbl 1 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1967,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
|
||||
// Store valid credentials for the nested / hardnested attack if none exist
|
||||
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;
|
||||
blockNo = i;
|
||||
keyType = j;
|
||||
|
|
|
@ -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 };
|
||||
|
||||
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) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ static int CmdHFMFPInfo(const char *cmd) {
|
|||
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false);
|
||||
infoHF14A(false, false, false);
|
||||
|
||||
// Mifare Plus info
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
|
|
@ -221,6 +221,16 @@ static int usage_hf_mfu_pwdgen(void) {
|
|||
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] = {
|
||||
{ 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, "--------------------");
|
||||
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
|
||||
//------------------------------------
|
||||
|
@ -2757,6 +2799,7 @@ static command_t CommandTable[] = {
|
|||
{"sim", CmdHF14AMfUSim, IfPm3Iso14443a, "Simulate Ultralight from emulator memory"},
|
||||
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
|
||||
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
|
||||
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ static int CmdCOTAGRead(const char *Cmd) {
|
|||
|
||||
clearCommandBuffer();
|
||||
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");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
|
|
@ -243,7 +243,7 @@ static int CmdFdxDemod(const char *Cmd) {
|
|||
|
||||
uint8_t c[] = {0, 0};
|
||||
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) {
|
||||
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);
|
||||
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);
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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"
|
||||
|
||||
|
@ -157,10 +158,11 @@ int detectGallagher(uint8_t *dest, size_t *size) {
|
|||
if (*size < 96) return -1; //make sure buffer has data
|
||||
size_t startIdx = 0;
|
||||
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,
|
||||
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))
|
||||
return -2; //preamble not found
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "lfdemod.h" // parityTest
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
|
||||
#define JABLOTRON_ARR_LEN 64
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_jablotron_clone(void) {
|
||||
|
@ -103,7 +105,7 @@ static int CmdJablotronDemod(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
setDemodBuff(DemodBuffer, 64, ans);
|
||||
setDemodBuff(DemodBuffer, JABLOTRON_ARR_LEN, ans);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
|
||||
|
||||
//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);
|
||||
|
||||
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 == jablontron_chksum(DemodBuffer)) ? _GREEN_("OK") : _RED_("Fail")
|
||||
isok ? _GREEN_("OK") : _RED_("Fail")
|
||||
);
|
||||
|
||||
id = DEC2BCD(id);
|
||||
|
@ -142,16 +147,13 @@ static int CmdJablotronClone(const char *Cmd) {
|
|||
uint64_t fullcode = 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));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_jablotron_clone();
|
||||
|
||||
fullcode = param_get64ex(Cmd, 0, 0, 16);
|
||||
|
||||
//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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
|
@ -168,6 +176,8 @@ static int CmdJablotronClone(const char *Cmd) {
|
|||
blocks[1] = bytebits_to_byte(bits, 32);
|
||||
blocks[2] = bytebits_to_byte(bits + 32, 32);
|
||||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
|
@ -190,18 +200,25 @@ static int CmdJablotronSim(const char *Cmd) {
|
|||
|
||||
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);
|
||||
|
||||
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->invert = 1;
|
||||
payload->separator = 0;
|
||||
payload->clock = 64;
|
||||
memcpy(payload->data, bs, sizeof(bs));
|
||||
memcpy(payload->data, bs, JABLOTRON_ARR_LEN);
|
||||
|
||||
free(bs);
|
||||
|
||||
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);
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
@ -251,12 +268,12 @@ int getJablotronBits(uint64_t fullcode, uint8_t *bits) {
|
|||
// the parameter *bits needs to be demoded before call
|
||||
// 0xFFFF preamble, 64bits
|
||||
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;
|
||||
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)
|
||||
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 crc = bytebits_to_byte(bits + startIdx + 56, 8);
|
||||
|
|
|
@ -257,7 +257,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
case ISO_14443B:
|
||||
case TOPAZ:
|
||||
case FELICA:
|
||||
crcStatus = iso14443B_CRC_check(frame, data_len);
|
||||
crcStatus = !felica_CRC_check(frame + 2, data_len - 4);
|
||||
break;
|
||||
case PROTO_MIFARE:
|
||||
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 != PROTO_HITAG
|
||||
&& protocol != THINFILM
|
||||
&& protocol != FELICA
|
||||
&& (isResponse || protocol == ISO_14443A)
|
||||
&& (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)
|
||||
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
|
||||
|
||||
if (protocol == FELICA)
|
||||
annotateFelica(explanation, sizeof(explanation), frame, data_len);
|
||||
|
||||
if (!isResponse) {
|
||||
switch (protocol) {
|
||||
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),
|
||||
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
|
||||
explanation);
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
/*
|
||||
static int SanityOfflineCheck( bool useTraceBuffer ){
|
||||
|
@ -819,9 +634,13 @@ int CmdTraceList(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes)", traceLen);
|
||||
PrintAndLogEx(INFO, "");
|
||||
|
||||
/*
|
||||
if (protocol == FELICA) {
|
||||
printFelica(traceLen, trace);
|
||||
} else if (showHex) {
|
||||
} */
|
||||
|
||||
if (showHex) {
|
||||
while (tracepos < traceLen) {
|
||||
tracepos = printHexLine(tracepos, traceLen, trace, protocol);
|
||||
}
|
||||
|
@ -844,6 +663,8 @@ int CmdTraceList(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet");
|
||||
if (protocol == PROTO_HITAG)
|
||||
PrintAndLogEx(NORMAL, "Hitag2 / HitagS - Timings in ETU (8us)");
|
||||
if (protocol == FELICA)
|
||||
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation");
|
||||
|
|
|
@ -22,7 +22,7 @@ a0478cc39091
|
|||
#
|
||||
d2ece8b9395e # lib
|
||||
# NSCP default key
|
||||
☻1494E81663D7
|
||||
1494E81663D7
|
||||
#
|
||||
# more Keys from mfc_default_keys.lua
|
||||
000000000001
|
||||
|
@ -126,6 +126,13 @@ fb0b20df1f34 # S6 B
|
|||
#
|
||||
a9f953def0a3
|
||||
#
|
||||
# Data from forum
|
||||
74a386ad0a6d
|
||||
3f7a5c2dbd81
|
||||
21edf95e7433
|
||||
c121ff19f681
|
||||
3d5d9996359a
|
||||
#
|
||||
# Here be BIP keys...
|
||||
3A42F33AF429
|
||||
1FC235AC1309
|
||||
|
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -3,11 +3,13 @@ local bin = require('bin')
|
|||
|
||||
copyright = 'Copyright (c) 2018 Bogito. All rights reserved.'
|
||||
author = 'Bogito'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc =
|
||||
[[
|
||||
This script will read the flash memory of RDV4 and print the stored passwords.
|
||||
It was meant to be used as a help tool after using the BogRun standalone mode.
|
||||
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 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.
|
||||
]]
|
||||
|
@ -22,8 +24,14 @@ example =
|
|||
-- This will scan 32 bytes of flash memory at offset 64 for stored passwords
|
||||
script run read_pwd_mem -o 64 -l 32
|
||||
|
||||
-- This will print found
|
||||
script run read_pwd_mem -o 241664 -k 6
|
||||
-- This will print the stored Mifare dictionary keys
|
||||
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 =
|
||||
[[
|
||||
|
@ -66,7 +74,6 @@ local function main(args)
|
|||
print()
|
||||
|
||||
local data, err, quadlet
|
||||
local cnt = 0
|
||||
local offset = 0
|
||||
local length = 256
|
||||
local keylength = 4
|
||||
|
|
102
client/luascripts/read_pwd_mem_spiffs.lua
Normal file
102
client/luascripts/read_pwd_mem_spiffs.lua
Normal 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
|
@ -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:
|
||||
* uint32_t cmd
|
||||
|
@ -1128,6 +1183,7 @@ int set_pm3_libraries(lua_State *L) {
|
|||
{"SendCommandNG", l_SendCommandNG},
|
||||
{"GetFromBigBuf", l_GetFromBigBuf},
|
||||
{"GetFromFlashMem", l_GetFromFlashMem},
|
||||
{"GetFromFlashMemSpiffs", l_GetFromFlashMemSpiffs},
|
||||
{"WaitForResponseTimeout", l_WaitForResponseTimeout},
|
||||
{"mfDarkside", l_mfDarkside},
|
||||
{"foobar", l_foobar},
|
||||
|
|
|
@ -52,11 +52,7 @@ pacman -S mingw-w64-x86_64-astyle
|
|||
|
||||
## 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:
|
||||
|
||||
```sh
|
||||
proxmark3 /dev/ttyACM0 => proxmark3.exe comX
|
||||
```
|
||||
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`.
|
||||
|
||||
Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md).
|
||||
|
||||
|
|
|
@ -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.
|
||||
* 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
|
||||
|
||||
|
|
|
@ -205,6 +205,21 @@ typedef struct {
|
|||
felica_status_flags_t status_flags;
|
||||
} 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 {
|
||||
FELICA_CONNECT = (1 << 0),
|
||||
FELICA_NO_DISCONNECT = (1 << 1),
|
||||
|
|
|
@ -507,6 +507,9 @@ typedef struct {
|
|||
|
||||
#define CMD_HF_MIFARE_NACK_DETECT 0x0730
|
||||
|
||||
// MFU OTP TearOff
|
||||
#define CMD_HF_MFU_OTP_TEAROFF 0x0740
|
||||
|
||||
#define CMD_HF_SNIFF 0x0800
|
||||
|
||||
// For ThinFilm Kovio
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue