diff --git a/.github/ISSUE_TEMPLATE/checklist-for-release.md b/.github/ISSUE_TEMPLATE/checklist-for-release.md new file mode 100644 index 000000000..aae8ab053 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/checklist-for-release.md @@ -0,0 +1,47 @@ +--- +name: Checklist for release +about: A template when making a release (usage reserved to repo maintainers) +title: "[RELEASE 4.x] Checklist" +labels: Release +assignees: doegox, iceman1001 + +--- + +# Checklist + +- [ ] CHANGELOG.md +- [ ] `make style` +- [ ] `make clean; make client CC=clang CXX=clang++ LD=clang++` on recent Debian or Ubuntu +- [ ] `mymanualchecks.sh` +- [ ] `mycppcheck.sh` no alarming warning? +- [ ] `mymakeclang.sh` no alarming error/warning ? +- [ ] `mystandalone_makes.sh` compile all standalone modes (linux only) +- [ ] [Travis](https://travis-ci.org/github/RfidResearchGroup/proxmark3/builds) green (linux noqt / osx+qt ; with makefile (w/wo bt) / with cmake) +- [ ] [Appveyor](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/history) green (PS) + +# OS compilation and tests + +```bash +make clean && make -j PLATFORM=PM3OTHER && tools/pm3test.sh +make clean && make -j PLATFORM=PM3RDV4 && tools/pm3test.sh +make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3test.sh +make install; pushd /tmp; proxmark3 -c 'data load em4x05.pm3;lf search 1'; popd; make uninstall + +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) +( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3test.sh client ) +``` + +- [ ] RPI Zero +- [ ] WSL +- [ ] PSv3.3 +- [ ] Kali +- [ ] Debian +- [ ] Ubuntu20 +- [ ] ParrotOS +- [ ] Fedora +- [ ] OpenSuse +- [ ] OSX +- [ ] Android +- [ ] Termux + diff --git a/CHANGELOG.md b/CHANGELOG.md index 492c67794..eccad5f86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ 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] + - Add `hf 14a config` to deal with badly configured cards: invalid ATQA/BCC/SAK (@doegox)" + - Mikron JSC Russia Ultralight EV1 41 pages tag type support (@McEloff) + - Add test for Ultralight gen2 magic 'hf search' (@McEloff) + - Add test for Ultralight EV1 gen2 magic 'hf search' (@McEloff) + - Added `hf mf gen3*`magic gen 3 card operations (@McEloff) - Readded verichip command which seems missing (@iceman1001) - Fix missing t55x7 config block detection (@iceman1001) - Fix missing define on proxspace (@mwalker33) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index bd66d538c..eef4ecf6f 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -38,6 +38,9 @@ define KNOWN_STANDALONE_DEFINITIONS | HF_14ASNIFF | 14a sniff to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ +| HF_AVEFUL | Mifare ultralight read/simulation | +| | - Ave Ozkal | ++----------------------------------------------------------+ | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth | | (RDV4 only) | storing in flashmem - Bogito | +----------------------------------------------------------+ @@ -62,7 +65,7 @@ define KNOWN_STANDALONE_DEFINITIONS endef STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN -STANDALONE_MODES += HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG +STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG STANDALONE_MODES_REQ_SMARTCARD := STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 131e26e79..c5730965b 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -37,6 +37,10 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS))) SRC_STANDALONE = hf_14asniff.c endif +# WITH_STANDALONE_HF_AVEFUL +ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS))) + SRC_STANDALONE = hf_aveful.c +endif # WITH_STANDALONE_LF_ICEHID ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS))) SRC_STANDALONE = lf_icehid.c diff --git a/armsrc/Standalone/hf_aveful.c b/armsrc/Standalone/hf_aveful.c new file mode 100644 index 000000000..a619459f5 --- /dev/null +++ b/armsrc/Standalone/hf_aveful.c @@ -0,0 +1,127 @@ +//----------------------------------------------------------------------------- +// A. Ozkal, 2020 +// +// 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. +//----------------------------------------------------------------------------- +// main code for HF Mifare Ultralight read/simulation by Ave Ozkal +//----------------------------------------------------------------------------- + +// Several parts of this code is based on code by Craig Young from HF_YOUNG + +// This code does not: +// - Account for cards with authentication (MFU EV1 etc) +// - Determine if cards have block count that's not the same as the BLOCKS def + +#include "standalone.h" // standalone definitions +#include "proxmark3_arm.h" +#include "appmain.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" + +#include "ticks.h" // SpinDelay +#include "mifareutil.h" +#include "iso14443a.h" + +#define BLOCKS 16 +#define SAK 0x00 +#define ATQA0 0x44 +#define ATQA1 0x00 + +#define STATE_SEARCH 0 +#define STATE_READ 1 +#define STATE_EMUL 2 + +typedef struct { + uint8_t uid[10]; + uint8_t uidlen; + uint8_t atqa[2]; + uint8_t sak; +} PACKED card_clone_t; + +void ModInfo(void) { + DbpString(" HF Mifare Ultralight read/simulation by Ave Ozkal"); +} + +void RunMod(void) { + StandAloneMode(); + Dbprintf("AveFUL (MF Ultralight read/emul) started"); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // the main loop for your standalone mode + for (;;) { + WDT_HIT(); + + // exit from RunMod, send a usbcommand. + if (data_available()) break; + + iso14a_card_select_t card; + + SpinDelay(500); + iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); + + // 0 = search, 1 = read, 2 = emul + int state = STATE_SEARCH; + + DbpString("Scanning..."); + for (;;) { + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(1000); + + if (button_pressed != BUTTON_NO_CLICK || data_available()) + break; + else if (state == STATE_SEARCH) { + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) { + continue; + } else { + if (card.sak == SAK && card.atqa[0] == ATQA0 && card.atqa[1] == ATQA1 && card.uidlen == 7) { + DbpString("Found ultralight with UID: "); + Dbhexdump(card.uidlen, card.uid, 0); + state = STATE_READ; + } else { + DbpString("Found non-ultralight card, ignoring."); + } + } + } else if (state == STATE_READ) { + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + iso14443a_select_card(NULL, NULL, NULL, true, 0, true); + bool read_successful = true; + Dbprintf("Contents:"); + + for (int i = 0; i < BLOCKS; i++) { + uint8_t dataout[4] = {0x00}; + if (mifare_ultra_readblock(i, dataout)) { + // If there's an error reading, go back to search state + read_successful = false; + break; + } + // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on dumptoemul-mfu + // When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00. + emlSetMem_xt(dataout, 14 + i, 1, 4); + Dbhexdump(4, dataout, 0); + } + + if (read_successful) { + Dbprintf("Successfully loaded into emulator memory..."); + state = STATE_EMUL; + } else { + Dbprintf("Read failure, going back to search state."); + state = STATE_SEARCH; + } + } else if (state == 2) { + uint8_t flags = FLAG_7B_UID_IN_DATA; + + Dbprintf("Starting simulation, press pm3-button to stop and go back to search state."); + SimulateIso14443aTag(2, flags, card.uid); + + // Go back to search state if user presses pm3-button + state = STATE_SEARCH; + } + } + } + + DbpString("exiting"); + LEDsoff(); +} diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 82c48b316..2a0ef6236 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -7,6 +7,15 @@ //----------------------------------------------------------------------------- // main code for hf_iceclass by Iceman //----------------------------------------------------------------------------- +// +// Created for the live streamed talk 'DEFCON 28 Wireless Village-Omikron and Iceman - Ghosting the PACS-man: New Tools and Techniques' +// https://www.youtube.com/watch?v=ghiHXK4GEzE +// +// I created a youtube video demostrating the HF_ICECLASS standalone mode +// https://youtu.be/w_1GnAscNIU +// +// + #include "standalone.h" // standalone definitions #include "proxmark3_arm.h" #include "appmain.h" diff --git a/armsrc/Standalone/hf_legic.c b/armsrc/Standalone/hf_legic.c index 73590268e..6ebe6eff6 100644 --- a/armsrc/Standalone/hf_legic.c +++ b/armsrc/Standalone/hf_legic.c @@ -22,7 +22,6 @@ #include "legic.h" // legic_card_select_t struct #include "spiffs.h" // flashmem - /* * To list all dump files from flash: * @@ -106,6 +105,7 @@ void RunMod(void) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); Dbprintf("[=] >> HF Legic Prime Read/Simulate Started <<"); DbpString("[=] press and HOLD button to exit standalone mode"); + for (;;) { WDT_HIT(); @@ -163,7 +163,7 @@ void RunMod(void) { } // The read data is migrated to a MIM1024 card - LegicRfSimulate(ct); + LegicRfSimulate(ct, false); } } diff --git a/armsrc/appmain.c b/armsrc/appmain.c index ebb58a23f..92e9f82f0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -355,8 +355,11 @@ static void SendStatus(void) { I2C_print_status(); #endif #ifdef WITH_LF - printConfig(); // LF Sampling config + printLFConfig(); // LF Sampling config printT55xxConfig(); // LF T55XX Config +#endif +#ifdef WITH_ISO14443a + printHf14aConfig(); // HF 14a config #endif printConnSpeed(); DbpString(_CYAN_("Various")); @@ -739,7 +742,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_SAMPLING_PRINT_CONFIG: { - printConfig(); + printLFConfig(); break; } case CMD_LF_SAMPLING_GET_CONFIG: { @@ -756,7 +759,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_LF_ACQ_RAW_ADC: { struct p { - uint8_t verbose; + bool verbose; uint32_t samples; } PACKED; struct p *payload = (struct p *)packet->data.asBytes; @@ -1058,14 +1061,19 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t uid[8]; } PACKED; struct p *payload = (struct p *) packet->data.asBytes; - SetTag15693Uid(payload->uid); - break; + SetTag15693Uid(payload->uid); + break; } #endif #ifdef WITH_LEGICRF case CMD_HF_LEGIC_SIMULATE: { - LegicRfSimulate(packet->oldarg[0]); + struct p { + uint8_t tagtype; + bool send_reply; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + LegicRfSimulate(payload->tagtype, payload->send_reply); break; } case CMD_HF_LEGIC_WRITER: { @@ -1140,6 +1148,21 @@ static void PacketReceived(PacketCommandNG *packet) { #endif #ifdef WITH_ISO14443a + case CMD_HF_ISO14443A_PRINT_CONFIG: { + printHf14aConfig(); + break; + } + case CMD_HF_ISO14443A_GET_CONFIG: { + hf14a_config *hf14aconfig = getHf14aConfig(); + reply_ng(CMD_HF_ISO14443A_GET_CONFIG, PM3_SUCCESS, (uint8_t *)hf14aconfig, sizeof(hf14a_config)); + break; + } + case CMD_HF_ISO14443A_SET_CONFIG: { + hf14a_config c; + memcpy(&c, packet->data.asBytes, sizeof(hf14a_config)); + setHf14aConfig(&c); + break; + } case CMD_HF_ISO14443A_SNIFF: { SniffIso14443a(packet->data.asBytes[0]); reply_ng(CMD_HF_ISO14443A_SNIFF, PM3_SUCCESS, NULL, 0); @@ -1214,6 +1237,10 @@ static void PacketReceived(PacketCommandNG *packet) { MifareUWriteBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); break; } + case CMD_HF_MIFAREU_WRITEBL_COMPAT: { + MifareUWriteBlockCompat(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + break; + } case CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES: { MifareAcquireEncryptedNonces(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); break; @@ -1248,7 +1275,7 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_MIFARE_CHKKEYS: { - MifareChkKeys(packet->data.asBytes); + MifareChkKeys(packet->data.asBytes, false); break; } case CMD_HF_MIFARE_CHKKEYS_FAST: { @@ -1318,6 +1345,19 @@ static void PacketReceived(PacketCommandNG *packet) { MifareCIdent(); break; } + // Gen 3 magic cards + case CMD_HF_MIFARE_GEN3UID: { + MifareGen3UID(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_HF_MIFARE_GEN3BLK: { + MifareGen3Blk(packet->oldarg[0], packet->data.asBytes); + break; + } + case CMD_HF_MIFARE_GEN3FREEZ: { + MifareGen3Freez(); + break; + } // mifare sniffer // case CMD_HF_MIFARE_SNIFF: { // SniffMifare(packet->oldarg[0]); @@ -1806,12 +1846,9 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t filename[32]; uint8_t *pfilename = packet->data.asBytes; memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN); - if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs dump : %s", filename); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs dump : %s", filename); - //uint32_t size = 0; - //rdv40_spiffs_stat((char *)filename, (uint32_t *)size,RDV40_SPIFFS_SAFETY_SAFE); uint32_t size = packet->oldarg[1]; - //uint8_t buff[size]; uint8_t *buff = BigBuf_malloc(size); rdv40_spiffs_read_as_filetype((char *)filename, (uint8_t *)buff, size, RDV40_SPIFFS_SAFETY_SAFE); @@ -1836,7 +1873,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t filename[32]; uint8_t *pfilename = packet->data.asBytes; memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN); - if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs STAT : %s", filename); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs STAT : %s", filename); int changed = rdv40_spiffs_lazy_mount(); uint32_t size = size_in_spiffs((char *)filename); if (changed) rdv40_spiffs_lazy_unmount(); @@ -1849,7 +1886,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t filename[32]; uint8_t *pfilename = packet->data.asBytes; memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN); - if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs REMOVE : %s", filename); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs REMOVE : %s", filename); rdv40_spiffs_remove((char *) filename, RDV40_SPIFFS_SAFETY_SAFE); LED_B_OFF(); break; @@ -1864,9 +1901,9 @@ static void PacketReceived(PacketCommandNG *packet) { strncpy((char *)src, token, sizeof(src) - 1); token = strtok(NULL, ","); strncpy((char *)dest, token, sizeof(dest) - 1); - if (DBGLEVEL > 1) { - Dbprintf("> Filename received as source for spiffs RENAME : %s", src); - Dbprintf("> Filename received as destination for spiffs RENAME : %s", dest); + if (DBGLEVEL >= DBG_DEBUG) { + Dbprintf("Filename received as source for spiffs RENAME : %s", src); + Dbprintf("Filename received as destination for spiffs RENAME : %s", dest); } rdv40_spiffs_rename((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE); LED_B_OFF(); @@ -1882,9 +1919,9 @@ static void PacketReceived(PacketCommandNG *packet) { strncpy((char *)src, token, sizeof(src) - 1); token = strtok(NULL, ","); strncpy((char *)dest, token, sizeof(dest) - 1); - if (DBGLEVEL > 1) { - Dbprintf("> Filename received as source for spiffs COPY : %s", src); - Dbprintf("> Filename received as destination for spiffs COPY : %s", dest); + if (DBGLEVEL >= DBG_DEBUG) { + Dbprintf("Filename received as source for spiffs COPY : %s", src); + Dbprintf("Filename received as destination for spiffs COPY : %s", dest); } rdv40_spiffs_copy((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE); LED_B_OFF(); @@ -1896,14 +1933,12 @@ static void PacketReceived(PacketCommandNG *packet) { uint32_t append = packet->oldarg[0]; uint32_t size = packet->oldarg[1]; uint8_t *data = packet->data.asBytes; - - //rdv40_spiffs_lazy_mount(); - uint8_t *pfilename = packet->data.asBytes; memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN); data += SPIFFS_OBJ_NAME_LEN; - if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs WRITE : %s with APPEND SET TO : %d", filename, append); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("> Filename received for spiffs WRITE : %s with APPEND SET TO : %d", filename, append); + if (!append) { rdv40_spiffs_write((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE); } else { diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index ab8df0d55..3f0ad9b6b 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -90,6 +90,7 @@ static em4x50_tag_t tag = { #define EM4X50_COMMAND_WRITE_PASSWORD 0x11 #define EM4X50_COMMAND_SELECTIVE_READ 0x0A +#define EM4X50_COMMAND_TIMEOUT 5000 #define FPGA_TIMER_0 0 int gHigh = 0; @@ -99,6 +100,8 @@ int gLow = 0; static void init_tag(void) { + // iceman: memset(tag.sectors, 0x00, sizeof)); + // initialize global tag structure for (int i = 0; i < 34; i++) for (int j = 0; j < 7; j++) @@ -185,10 +188,9 @@ static void em4x50_setup_read(void) { // 50ms for the resonant antenna to settle. SpinDelay(50); + // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); - // start a 1.5ticks is 1us - StartTicks(); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); @@ -255,10 +257,9 @@ static bool get_signalproperties(void) { signal_found = true; break; } - } - if (!signal_found) + if (signal_found == false) return false; // calculate mean maximum value of 32 periods, each period has a length of @@ -312,35 +313,46 @@ static int get_next_bit(void) { static uint32_t get_pulse_length(void) { +// Dbprintf( _CYAN_("4x50 get_pulse_length A") ); + + int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + // iterates pulse length (low -> high -> low) - uint8_t sample = 0; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - while (sample > gLow) + while (sample > gLow && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + } + + if (timeout == 0) + return 0; AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); - while (sample < gHigh) + while (sample < gHigh && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + } - while (sample > gLow) + if (timeout == 0) + return 0; + + timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD); + while (sample > gLow && (timeout--)) { sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + } + + if (timeout == 0) + return 0; return (uint32_t)AT91C_BASE_TC1->TC_CV; + } static bool check_pulse_length(uint32_t pl, int length) { - // check if pulse length corresponds to given length - - if ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) & - (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))) - return true; - else - return false; + return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) & (pl <= T0 * (length + EM4X50_TAG_TOLERANCE))); } static void em4x50_send_bit(int bit) { @@ -428,13 +440,9 @@ static bool find_single_listen_window(void) { // listen window found return true; - } - } else { - - cnt_pulses++; - } + cnt_pulses++; } return false; @@ -494,7 +502,6 @@ static bool find_double_listen_window(bool bcommand) { return true; } } - } else { cnt_pulses++; } } @@ -506,9 +513,7 @@ static bool find_em4x50_tag(void) { // function is used to check wether a tag on the proxmark is an // EM4x50 tag or not -> speed up "lf search" process - - return (find_single_listen_window()); - + return find_single_listen_window(); } static bool request_receive_mode(void) { @@ -516,9 +521,7 @@ static bool request_receive_mode(void) { // To issue a command we have to find a listen window first. // Because identification and sychronization at the same time is not // possible when using pulse lengths a double listen window is used. - bool bcommand = true; - return find_double_listen_window(bcommand); } diff --git a/armsrc/epa.c b/armsrc/epa.c index 777549728..25a70c885 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -229,7 +229,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) { sizeof(apdu_select_binary_cardaccess), response_apdu, sizeof(response_apdu) - ); + ); if (rapdu_length < 6 || response_apdu[rapdu_length - 4] != 0x90 @@ -243,7 +243,7 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) { sizeof(apdu_read_binary), response_apdu, sizeof(response_apdu) - ); + ); if (rapdu_length <= 6 || response_apdu[rapdu_length - 4] != 0x90 @@ -325,11 +325,11 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) { // now get the nonce uint8_t nonce[256] = {0}; - + struct p { uint32_t m; } PACKED; - struct p *packet = (struct p*)c->data.asBytes; + struct p *packet = (struct p *)c->data.asBytes; func_return = EPA_PACE_Get_Nonce(packet->m, nonce); // check if the command succeeded @@ -359,7 +359,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) { // copy the constant part memcpy(apdu, apdu_general_authenticate_pace_get_nonce, sizeof(apdu_general_authenticate_pace_get_nonce)); - + // append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4; @@ -444,8 +444,8 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) // check if the command succeeded if (send_return != 6) // && response_apdu[send_return - 4] != 0x90 -// || response_apdu[send_return - 3] != 0x00) - { +// || response_apdu[send_return - 3] != 0x00) + { return 1; } return 0; @@ -500,7 +500,7 @@ void EPA_PACE_Replay(PacketCommandNG *c) { apdu_lengths_replay[i], response_apdu, sizeof(response_apdu) - ); + ); timings[i] = GetCountUS(); // every step but the last one should succeed if (i < ARRAYLEN(apdu_lengths_replay) - 1 diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d5417f108..061dfe9ae 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -122,6 +122,51 @@ static uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 +/* +Default HF 14a config is set to: + forceanticol = 0 (auto) + forcebcc = 0 (expect valid BCC) + forcecl2 = 0 (auto) + forcecl3 = 0 (auto) + forcerats = 0 (auto) +*/ +static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; + +void printHf14aConfig(void) { + DbpString(_CYAN_("HF 14a config")); + Dbprintf("[a] Anticol override......%s%s%s", (hf14aconfig.forceanticol == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forceanticol == 1) ? _RED_("Yes: Always do anticol") : "", (hf14aconfig.forceanticol == 2) ? _RED_("Yes: Always skip anticol") : ""); + Dbprintf("[b] BCC override..........%s%s%s", (hf14aconfig.forcebcc == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcebcc == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcebcc == 2) ? _RED_("Yes: Always use card BCC") : ""); + Dbprintf("[2] CL2 override..........%s%s%s", (hf14aconfig.forcecl2 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl2 == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcecl2 == 2) ? _RED_("Yes: Always skip CL2") : ""); + Dbprintf("[3] CL3 override..........%s%s%s", (hf14aconfig.forcecl3 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl3 == 1) ? _RED_("Yes: Always do CL3") : "", (hf14aconfig.forcecl3 == 2) ? _RED_("Yes: Always skip CL3") : ""); + Dbprintf("[r] RATS override.........%s%s%s", (hf14aconfig.forcerats == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcerats == 1) ? _RED_("Yes: Always do RATS") : "", (hf14aconfig.forcerats == 2) ? _RED_("Yes: Always skip RATS") : ""); +} + +/** + * Called from the USB-handler to set the 14a configuration + * The 14a config is used for card selection sequence. + * + * Values set to '-1' implies no change + * @brief setSamplingConfig + * @param sc + */ +void setHf14aConfig(hf14a_config *hc) { + + if ((hc->forceanticol >= 0) && (hc->forceanticol <= 2)) + hf14aconfig.forceanticol = hc->forceanticol; + if ((hc->forcebcc >= 0) && (hc->forcebcc <= 2)) + hf14aconfig.forcebcc = hc->forcebcc; + if ((hc->forcecl2 >= 0) && (hc->forcecl2 <= 2)) + hf14aconfig.forcecl2 = hc->forcecl2; + if ((hc->forcecl3 >= 0) && (hc->forcecl3 <= 2)) + hf14aconfig.forcecl3 = hc->forcecl3; + if ((hc->forcerats >= 0) && (hc->forcerats <= 2)) + hf14aconfig.forcerats = hc->forcerats; +} + +hf14a_config *getHf14aConfig(void) { + return &hf14aconfig; +} + void iso14a_set_trigger(bool enable) { g_trigger = enable; } @@ -1832,8 +1877,8 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { for (;;) { WDT_HIT(); - if (check == 1000) { - if (BUTTON_PRESS() || data_available()) + if (check == 2000) { + if (BUTTON_PRESS()) return 1; check = 0; } @@ -1959,7 +2004,6 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR); (void)b; } - if (BUTTON_PRESS()) break; } // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again: @@ -2336,7 +2380,8 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller uint8_t resp_par[MAX_PARITY_SIZE] = {0}; - uint8_t sak = 0x04; // cascade uid + uint8_t sak; // cascade uid + bool do_cascade = 1; int cascade_level = 0; if (p_card) { @@ -2360,26 +2405,32 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 memset(uid_ptr, 0, 10); } - // check for proprietary anticollision: - if ((resp[0] & 0x1F) == 0) return 3; + if (hf14aconfig.forceanticol == 0) { + // check for proprietary anticollision: + if ((resp[0] & 0x1F) == 0) return 3; + } else if (hf14aconfig.forceanticol == 2) { + return 3; // force skipping anticol + } // else force executing // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for (; sak & 0x04; cascade_level++) { + for (; do_cascade; cascade_level++) { // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) uint8_t sel_all[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x20 }; uint8_t sel_uid[] = { ISO14443A_CMD_ANTICOLL_OR_SELECT, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t uid_resp[4] = {0}; + uint8_t uid_resp[5] = {0}; // UID + original BCC sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; if (anticollision) { // SELECT_ALL ReaderTransmit(sel_all, sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) return 0; - + if (!ReaderReceive(resp, resp_par)) { + Dbprintf("Card didn't answer to CL%i select all", cascade_level + 1); + return 0; + } if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit - memset(uid_resp, 0, 4); + memset(uid_resp, 0, 5); uint16_t uid_resp_bits = 0; uint16_t collision_answer_offset = 0; // anti-collision-loop: @@ -2391,7 +2442,7 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 } uid_resp[uid_resp_bits / 8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position uid_resp_bits++; - // construct anticollosion command: + // construct anticollision command: sel_uid[1] = ((2 + uid_resp_bits / 8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits for (uint16_t i = 0; i <= uid_resp_bits / 8; i++) { sel_uid[2 + i] = uid_resp[i]; @@ -2407,7 +2458,7 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 } } else { // no collision, use the response to SELECT_ALL as current uid - memcpy(uid_resp, resp, 4); + memcpy(uid_resp, resp, 5); // UID + original BCC } } else { @@ -2426,18 +2477,51 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 // Construct SELECT UID command sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid + 2, uid_resp, 4); // the UID received during anticollision, or the provided UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + + if (anticollision) { + memcpy(sel_uid + 2, uid_resp, 5); // the UID received during anticollision with original BCC + uint8_t bcc = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate BCC + if (sel_uid[6] != bcc) { + Dbprintf("BCC%d incorrect, got 0x%02x, expected 0x%02x", cascade_level, sel_uid[6], bcc); + if (hf14aconfig.forcebcc == 0) { + Dbprintf("Aborting"); + return 0; + } else if (hf14aconfig.forcebcc == 1) { + sel_uid[6] = bcc; + } // else use card BCC + Dbprintf("Using BCC=" _YELLOW_("0x%02x") " to perform anticollision", sel_uid[6]); + } + } else { + memcpy(sel_uid + 2, uid_resp, 4); // the provided UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + } + AddCrc14A(sel_uid, 7); // calculate and add CRC ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return 0; - + if (!ReaderReceive(resp, resp_par)) { + Dbprintf("Card didn't answer to select"); + return 0; + } sak = resp[0]; // Test if more parts of the uid are coming - if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { + do_cascade = (((sak & 0x04) /* && uid_resp[0] == 0x88 */) > 0); + if (cascade_level == 0) { + if (hf14aconfig.forcecl2 == 2) { + do_cascade = false; + } else if (hf14aconfig.forcecl2 == 1) { + do_cascade = true; + } // else 0==auto + } else if (cascade_level == 1) { + if (hf14aconfig.forcecl3 == 2) { + do_cascade = false; + } else if (hf14aconfig.forcecl3 == 1) { + do_cascade = true; + } // else 0==auto + } + if (do_cascade) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf uid_resp[0] = uid_resp[1]; @@ -2459,8 +2543,12 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 p_card->sak = sak; } - // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) - if ((sak & 0x20) == 0) return 2; + if (hf14aconfig.forcerats == 0) { + // PICC compliant with iso14443a-4 ---> (SAK & 0x20 != 0) + if ((sak & 0x20) == 0) return 2; + } else if (hf14aconfig.forcerats == 2) { + return 2; + } // else force RATS // RATS, Request for answer to select if (!no_rats) { diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 94b1d5a2d..d1df5534c 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -96,6 +96,9 @@ typedef struct { # define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) #endif +void printHf14aConfig(void); +void setHf14aConfig(hf14a_config *hc); +hf14a_config *getHf14aConfig(void); void iso14a_set_timeout(uint32_t timeout); uint32_t iso14a_get_timeout(void); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index f2738f7b4..0844b5e4d 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -44,12 +44,12 @@ # define FWT_TIMEOUT_14B 35312 #endif - // 330/848kHz = 1558us / 4 == 400us, +// 330/848kHz = 1558us / 4 == 400us, #define ISO14443B_READER_TIMEOUT 1700 //330 // 1024/3.39MHz = 302.1us between end of tag response and next reader cmd #define DELAY_ISO14443B_VICC_TO_VCD_READER 600 // 1024 -#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056 +#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056 #ifndef RECEIVE_MASK # define RECEIVE_MASK (DMA_BUFFER_SIZE - 1) @@ -740,7 +740,7 @@ void SimulateIso14443bTag(uint32_t pupi) { */ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { - int v; + int v; // The soft decision on the bit uses an estimate of just the // quadrant of the reference angle, not the exact angle. @@ -761,137 +761,137 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) #define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2)) - switch(Demod.state) { + switch (Demod.state) { - case DEMOD_UNSYNCD: { - if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected - Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = ci; - Demod.sumQ = cq; - Demod.posCount = 1; - } - break; + case DEMOD_UNSYNCD: { + if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected + Demod.state = DEMOD_PHASE_REF_TRAINING; + Demod.sumI = ci; + Demod.sumQ = cq; + Demod.posCount = 1; + } + break; } - case DEMOD_PHASE_REF_TRAINING: { - if (Demod.posCount < 8) { - if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { - // set the reference phase (will code a logic '1') by averaging over 32 1/fs. - // note: synchronization time > 80 1/fs - Demod.sumI += ci; - Demod.sumQ += cq; - Demod.posCount++; - } else { + case DEMOD_PHASE_REF_TRAINING: { + if (Demod.posCount < 8) { + if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { + // set the reference phase (will code a logic '1') by averaging over 32 1/fs. + // note: synchronization time > 80 1/fs + Demod.sumI += ci; + Demod.sumQ += cq; + Demod.posCount++; + } else { // subcarrier lost - Demod.state = DEMOD_UNSYNCD; - } - } else { - Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; - } - break; + Demod.state = DEMOD_UNSYNCD; + } + } else { + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; + } + break; } - case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: { + case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: { - MAKE_SOFT_DECISION(); + MAKE_SOFT_DECISION(); - if (v < 0) { // logic '0' detected - Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; // start of SOF sequence - } else { - if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs - Demod.state = DEMOD_UNSYNCD; - } - } - Demod.posCount++; - break; + if (v < 0) { // logic '0' detected + Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; + Demod.posCount = 0; // start of SOF sequence + } else { + if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs + Demod.state = DEMOD_UNSYNCD; + } + } + Demod.posCount++; + break; } - case DEMOD_GOT_FALLING_EDGE_OF_SOF: { + case DEMOD_GOT_FALLING_EDGE_OF_SOF: { - Demod.posCount++; - MAKE_SOFT_DECISION(); + Demod.posCount++; + MAKE_SOFT_DECISION(); - if (v > 0) { - if (Demod.posCount < 9 * 2) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges - Demod.state = DEMOD_UNSYNCD; - } else { - LED_C_ON(); // Got SOF - Demod.posCount = 0; - Demod.bitCount = 0; - Demod.len = 0; - Demod.state = DEMOD_AWAITING_START_BIT; - } - } else { - if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu) - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - } - } - break; + if (v > 0) { + if (Demod.posCount < 9 * 2) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges + Demod.state = DEMOD_UNSYNCD; + } else { + LED_C_ON(); // Got SOF + Demod.posCount = 0; + Demod.bitCount = 0; + Demod.len = 0; + Demod.state = DEMOD_AWAITING_START_BIT; + } + } else { + if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu) + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } + } + break; } - case DEMOD_AWAITING_START_BIT: { - Demod.posCount++; - MAKE_SOFT_DECISION(); - if (v > 0) { - if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs - LED_C_OFF(); - if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass - return true; - } else { - Demod.state = DEMOD_UNSYNCD; - } - } - } else { // start bit detected - Demod.posCount = 1; // this was the first half - Demod.thisBit = v; - Demod.shiftReg = 0; - Demod.state = DEMOD_RECEIVING_DATA; - } - break; + case DEMOD_AWAITING_START_BIT: { + Demod.posCount++; + MAKE_SOFT_DECISION(); + if (v > 0) { + if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + LED_C_OFF(); + if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass + return true; + } else { + Demod.state = DEMOD_UNSYNCD; + } + } + } else { // start bit detected + Demod.posCount = 1; // this was the first half + Demod.thisBit = v; + Demod.shiftReg = 0; + Demod.state = DEMOD_RECEIVING_DATA; + } + break; } - case DEMOD_RECEIVING_DATA: { + case DEMOD_RECEIVING_DATA: { - MAKE_SOFT_DECISION(); + MAKE_SOFT_DECISION(); - if (Demod.posCount == 0) { // first half of bit - Demod.thisBit = v; - Demod.posCount = 1; - } else { // second half of bit - Demod.thisBit += v; + if (Demod.posCount == 0) { // first half of bit + Demod.thisBit = v; + Demod.posCount = 1; + } else { // second half of bit + Demod.thisBit += v; - Demod.shiftReg >>= 1; - if (Demod.thisBit > 0) { // logic '1' - Demod.shiftReg |= 0x200; - } + Demod.shiftReg >>= 1; + if (Demod.thisBit > 0) { // logic '1' + Demod.shiftReg |= 0x200; + } - Demod.bitCount++; - if (Demod.bitCount == 10) { + Demod.bitCount++; + if (Demod.bitCount == 10) { - uint16_t s = Demod.shiftReg; + uint16_t s = Demod.shiftReg; - if ((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' - Demod.output[Demod.len] = (s >> 1); - Demod.len++; - Demod.bitCount = 0; - Demod.state = DEMOD_AWAITING_START_BIT; - } else { - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - if (s == 0x000) { - // This is EOF (start, stop and all data bits == '0' - return true; - } - } - } - Demod.posCount = 0; - } - break; + if ((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' + Demod.output[Demod.len] = (s >> 1); + Demod.len++; + Demod.bitCount = 0; + Demod.state = DEMOD_AWAITING_START_BIT; + } else { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + if (s == 0x000) { + // This is EOF (start, stop and all data bits == '0' + return true; + } + } + } + Demod.posCount = 0; + } + break; } - default: { - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - break; + default: { + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + break; } - } - return false; + } + return false; } @@ -938,9 +938,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo } volatile int8_t ci = *upTo >> 8; - volatile int8_t cq = *upTo; - upTo++; - + volatile int8_t cq = *upTo; + upTo++; + // we have read all of the DMA buffer content. if (upTo >= dma->buf + DMA_BUFFER_SIZE) { @@ -960,7 +960,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - + WDT_HIT(); if (BUTTON_PRESS()) { DbpString("stopped"); @@ -993,9 +993,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo if (Demod.len > 0) { uint32_t sof_time = *eof_time - - (Demod.len * 8 * 8 * 16) // time for byte transfers - - (32 * 16) // time for SOF transfer - - 0; // time for EOF transfer + - (Demod.len * 8 * 8 * 16) // time for byte transfers + - (32 * 16) // time for SOF transfer + - 0; // time for EOF transfer LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false); } @@ -1006,9 +1006,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- static void TransmitFor14443b_AsReader(uint32_t *start_time) { - + tosend_t *ts = get_tosend(); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); if (*start_time < DELAY_ARM_TO_TAG) { @@ -1016,7 +1016,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { } *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; - + if (GetCountSspClk() > *start_time) { // we may miss the intended time *start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time } @@ -1132,7 +1132,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t tosend_t *ts = get_tosend(); CodeIso14443bAsReader(cmd, len); TransmitFor14443b_AsReader(start_time); - *eof_time = *start_time + (32 * (8 * ts->max)); + *eof_time = *start_time + (32 * (8 * ts->max)); LogTrace(cmd, len, *start_time, *eof_time, NULL, true); } @@ -1152,12 +1152,12 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r memcpy(message_frame + 2, message, message_length); // EDC (CRC) AddCrc14B(message_frame, message_length + 2); - + // send uint32_t start_time = 0; uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time); - + // get response if (response == NULL) { LED_A_OFF(); @@ -1191,7 +1191,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { uint8_t r_init[3] = {0x0}; uint8_t r_select[3] = {0x0}; uint8_t r_papid[10] = {0x0}; - + uint32_t start_time = 0; uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx), &start_time, &eof_time); @@ -1211,7 +1211,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { // SELECT command (with space for CRC) uint8_t select_srx[] = { ISO14443B_SELECT, 0x00, 0x00, 0x00}; select_srx[1] = r_init[0]; - + AddCrc14B(select_srx, 2); start_time = eof_time + DELAY_ISO14443B_VICC_TO_VCD_READER; @@ -1242,7 +1242,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { start_time = eof_time + DELAY_ISO14443B_VICC_TO_VCD_READER; CodeAndTransmit14443bAsReader(select_srx, 3, &start_time, &eof_time); // Only first three bytes for this one - + eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; retlen = Get14443bAnswerFromTag(r_papid, sizeof(r_papid), ISO14443B_READER_TIMEOUT, &eof_time); FpgaDisableTracing(); @@ -1255,7 +1255,7 @@ static uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { if (!check_crc(CRC_14443_B, r_papid, retlen)) { return 3; } - + if (card) { card->uidlen = 8; memcpy(card->uid, r_papid, 8); @@ -1312,7 +1312,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) { AddCrc14B(attrib, 9); start_time = eof_time + DELAY_ISO14443B_VICC_TO_VCD_READER; CodeAndTransmit14443bAsReader(attrib, sizeof(attrib), &start_time, &eof_time); - + eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; retlen = Get14443bAnswerFromTag(r_attrib, sizeof(r_attrib), ISO14443B_READER_TIMEOUT, &eof_time); FpgaDisableTracing(); @@ -1423,10 +1423,10 @@ static bool ReadSTBlock(uint8_t blocknr, uint8_t *block) { } Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", - blocknr, + blocknr, (r_block[3] << 24) + (r_block[2] << 16) + (r_block[1] << 8) + r_block[0], (r_block[4] << 8) + r_block[5]); - + return true; } @@ -1434,7 +1434,7 @@ void ReadSTMemoryIso14443b(uint16_t numofblocks) { iso14443b_setup(); - uint8_t *mem = BigBuf_malloc((numofblocks + 1) * 4 ); + uint8_t *mem = BigBuf_malloc((numofblocks + 1) * 4); iso14b_card_select_t card; uint8_t res = iso14443b_select_srx_card(&card); @@ -1450,15 +1450,15 @@ void ReadSTMemoryIso14443b(uint16_t numofblocks) { for (uint8_t i = 0; i < numofblocks; i++) { - if (ReadSTBlock(i, mem + ( i * 4)) == false) { + if (ReadSTBlock(i, mem + (i * 4)) == false) { isOK = PM3_ETIMEOUT; break; } } - - // System area block (0xFF) - if (ReadSTBlock(0xFF, mem + (numofblocks * 4)) == false) - isOK = PM3_ETIMEOUT; + + // System area block (0xFF) + if (ReadSTBlock(0xFF, mem + (numofblocks * 4)) == false) + isOK = PM3_ETIMEOUT; out: @@ -1535,7 +1535,7 @@ void SniffIso14443b(void) { bool reader_is_active = false; bool expect_tag_answer = false; int dma_start_time = 0; - + // Count of samples received so far, so that we can include timing int samples = 0; @@ -1544,7 +1544,7 @@ void SniffIso14443b(void) { for (;;) { volatile int behind_by = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); - if (behind_by < 1) continue; + if (behind_by < 1) continue; samples++; if (samples == 1) { @@ -1554,7 +1554,7 @@ void SniffIso14443b(void) { volatile int8_t ci = *upTo >> 8; volatile int8_t cq = *upTo; - upTo++; + upTo++; // we have read all of the DMA buffer content. if (upTo >= dma->buf + DMA_BUFFER_SIZE) { @@ -1575,7 +1575,7 @@ void SniffIso14443b(void) { AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - + WDT_HIT(); if (BUTTON_PRESS()) { DbpString("Sniff stopped"); @@ -1600,7 +1600,7 @@ void SniffIso14443b(void) { Uart14bReset(); Demod14bReset(); reader_is_active = false; - expect_tag_answer = true; + expect_tag_answer = true; } if (Handle14443bSampleFromReader(cq & 0x01)) { @@ -1619,20 +1619,20 @@ void SniffIso14443b(void) { reader_is_active = false; expect_tag_answer = true; } - + reader_is_active = (Uart.state > STATE_14B_GOT_FALLING_EDGE_OF_SOF); } // no need to try decoding tag data if the reader is sending - and we cannot afford the time if (reader_is_active == false && expect_tag_answer) { - if (Handle14443bSamplesFromTag((ci >> 1), (cq >> 1))) { + if (Handle14443bSamplesFromTag((ci >> 1), (cq >> 1))) { - uint32_t eof_time = dma_start_time + (samples * 16); // - DELAY_TAG_TO_ARM_SNIFF; // end of EOF + uint32_t eof_time = dma_start_time + (samples * 16); // - DELAY_TAG_TO_ARM_SNIFF; // end of EOF uint32_t sof_time = eof_time - - Demod.len * 8 * 8 * 16 // time for byte transfers - - (32 * 16) // time for SOF transfer - - 0; // time for EOF transfer + - Demod.len * 8 * 8 * 16 // time for byte transfers + - (32 * 16) // time for SOF transfer + - 0; // time for EOF transfer LogTrace(Demod.output, Demod.len, (sof_time * 4), (eof_time * 4), NULL, false); // And ready to receive another response. @@ -1657,7 +1657,7 @@ void SniffIso14443b(void) { Dbprintf(" DecodeTag posCount.....%d", Demod.posCount); Dbprintf(" DecodeReader State.....%d", Uart.state); Dbprintf(" DecodeReader byteCnt...%d", Uart.byteCnt); - Dbprintf(" DecodeReader posCount..%d", Uart.posCnt); + Dbprintf(" DecodeReader posCount..%d", Uart.posCnt); Dbprintf(" Trace length..........." _YELLOW_("%d"), BigBuf_get_traceLen()); DbpString(""); } @@ -1703,17 +1703,17 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { int status; uint32_t sendlen = sizeof(iso14b_card_select_t); iso14b_card_select_t card; - + if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { status = iso14443b_select_card(&card); - reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t*)&card, sendlen); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen); // 0: OK -1: attrib fail, -2:crc fail, if (status != 0) goto out; } if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { status = iso14443b_select_srx_card(&card); - reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t*)&card, sendlen); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&card, sendlen); // 0: OK 2: demod fail, 3:crc fail, if (status > 0) goto out; } @@ -1730,10 +1730,10 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { len += 2; } uint8_t buf[100] = {0}; - + uint32_t start_time = 0; uint32_t eof_time = 0; - CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time); + CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time); eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 428cf80ff..3125f90bf 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -84,7 +84,7 @@ #define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us #define ISO15693_READER_TIMEOUT_WRITE 4700 // 4700/212kHz = 22ms, nominal 20ms -// iceman: This defines below exists in the header file, just here for my easy reading +// iceman: This defines below exists in the header file, just here for my easy reading // Delays in SSP_CLK ticks. // SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag //#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response @@ -700,7 +700,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dma->buf; AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - + WDT_HIT(); if (BUTTON_PRESS()) { DbpString("stopped"); @@ -725,7 +725,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo // timeout if (samples > timeout && dt->state < STATE_TAG_RECEIVING_DATA) { - ret = -3; + ret = -3; break; } @@ -1715,7 +1715,6 @@ void SimTagIso15693(uint8_t *uid) { uint32_t reader_eof_time = 0; int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time); if (cmd_len < 0) { - Dbprintf("button pressed, exiting"); button_pressed = true; exit_loop = true; break; @@ -1736,7 +1735,7 @@ void SimTagIso15693(uint8_t *uid) { if (button_pressed) DbpString("button pressed"); - + reply_ng(CMD_HF_ISO15693_SIMULATE, PM3_SUCCESS, NULL, 0); } @@ -1881,7 +1880,7 @@ SLIx functions from official master forks. void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) { LED_A_ON(); - + uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 }; uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 }; uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1893,7 +1892,7 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) { uint32_t start_time = 0; bool done = false; - // setup 'get random number' command + // setup 'get random number' command crc = Iso15693Crc(cmd_get_rnd, 3); cmd_get_rnd[3] = crc & 0xff; cmd_get_rnd[4] = crc >> 8; @@ -1901,7 +1900,7 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) { Dbprintf("LockPass: Press button lock password, long-press to terminate."); while (!done) { - + LED_D_ON(); switch(BUTTON_HELD(1000)) { case BUTTON_SINGLE_CLICK: @@ -2033,7 +2032,7 @@ void SetTag15693Uid(uint8_t *uid) { SendDataTag(cmd[i], sizeof(cmd[i]), i == 0 ? true : false, true, recvbuf, sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT_WRITE, &eof_time); start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; } - + reply_ng(CMD_HF_ISO15693_CSETUID, PM3_SUCCESS, NULL, 0); switch_off(); -} \ No newline at end of file +} diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 1d2693347..92961fd4a 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -64,11 +64,11 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ //----------------------------------------------------------------------------- // I/O interface abstraction (FPGA -> ARM) //----------------------------------------------------------------------------- -static uint8_t rx_byte_from_fpga(void) { +static uint16_t rx_frame_from_fpga(void) { for (;;) { WDT_HIT(); - // wait for byte be become available in rx holding register + // wait for frame be become available in rx holding register if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { return AT91C_BASE_SSC->SSC_RHR; } @@ -76,48 +76,53 @@ static uint8_t rx_byte_from_fpga(void) { } //----------------------------------------------------------------------------- -// Demodulation +// Demodulation (Reader) //----------------------------------------------------------------------------- -// Returns am aproximated power measurement +// Returns a demedulated bit // -// The FPGA running on the xcorrelation kernel samples the subcarrier at ~3 MHz. -// The kernel was initialy designed to receive BSPK/2-PSK. Hance, it reports an -// I/Q pair every 18.9us (8 bits i and 8 bits q). +// The FPGA running xcorrelation samples the subcarrier at ~13.56 MHz. The mode +// was initialy designed to receive BSPK/2-PSK. Hance, it reports an I/Q pair +// every 4.7us (8 bits i and 8 bits q). // // The subcarrier amplitude can be calculated using Pythagoras sqrt(i^2 + q^2). // To reduce CPU time the amplitude is approximated by using linear functions: // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // -// Note: The SSC receiver is never synchronized the calculation may be performed -// on a i/q pair from two subsequent correlations, but does not matter. -// Note: inlining this function would fail with -Os -static int32_t sample_power(void) { - int32_t q = (int8_t)rx_byte_from_fpga(); - q = ABS(q); - int32_t i = (int8_t)rx_byte_from_fpga(); - i = ABS(i); - - return MAX(i, q) + (MIN(i, q) >> 1); -} - -// Returns a demedulated bit +// The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples +// and averages the next (most stable) 8 samples. The final 8 samples are dropped +// also. // -// An aproximated power measurement is available every 18.9us. The bit time -// is 100us. The code samples 5 times and uses the last (most stable) sample. +// The demodulated should be alligned to the bit period by the caller. This is +// done in rx_bit and rx_ack. // // Note: The demodulator would be drifting (18.9us * 5 != 100us), rx_frame // has a delay loop that aligns rx_bit calls to the TAG tx timeslots. - +// // Note: inlining this function would fail with -Os static bool rx_bit(void) { - int32_t power; + int32_t sum_cq = 0; + int32_t sum_ci = 0; + // skip first 5 I/Q pairs for (size_t i = 0; i < 5; ++i) { - power = sample_power(); + (void)rx_frame_from_fpga(); } - return (power > INPUT_THRESHOLD); + // sample next 8 I/Q pairs + for (uint8_t i = 0; i < 8; ++i) { + uint16_t iq = rx_frame_from_fpga(); + int8_t ci = (int8_t)(iq >> 8); + int8_t cq = (int8_t)(iq & 0xff); + sum_ci += ci; + sum_cq += cq; + } + + // calculate power + int32_t power = (MAX(ABS(sum_ci), ABS(sum_cq)) + (MIN(ABS(sum_ci), ABS(sum_cq)) >> 1)); + + // compare average (power / 8) to threshold + return ((power >> 3) > INPUT_THRESHOLD); } //----------------------------------------------------------------------------- @@ -131,18 +136,18 @@ static bool rx_bit(void) { static void tx_bit(bool bit) { // insert pause - LOW(GPIO_SSC_DOUT); + HIGH(GPIO_SSC_DOUT); last_frame_end += RWD_TIME_PAUSE; while (GET_TICKS < last_frame_end) { }; - HIGH(GPIO_SSC_DOUT); - // return to high, wait for bit periode to end + // return to carrier on, wait for bit periode to end + LOW(GPIO_SSC_DOUT); last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; while (GET_TICKS < last_frame_end) { }; } //----------------------------------------------------------------------------- -// Frame Handling +// Frame Handling (Reader) // // The LEGIC RF protocol from card to reader does not include explicit frame // start/stop information or length information. The reader must know beforehand @@ -169,10 +174,10 @@ static void tx_frame(uint32_t frame, uint8_t len) { }; // add pause to mark end of the frame - LOW(GPIO_SSC_DOUT); + HIGH(GPIO_SSC_DOUT); last_frame_end += RWD_TIME_PAUSE; while (GET_TICKS < last_frame_end) { }; - HIGH(GPIO_SSC_DOUT); + LOW(GPIO_SSC_DOUT); // log uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)}; @@ -267,12 +272,12 @@ static int init_card(uint8_t cardtype, legic_card_select_t *p_card) { p_card->cmdsize = 0; p_card->addrsize = 0; p_card->cardsize = 0; - return 2; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } -static void init_reader(bool clear_mem) { +static void init_reader(void) { // configure FPGA FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); @@ -285,7 +290,7 @@ static void init_reader(bool clear_mem) { // re-claim GPIO_SSC_DOUT as GPIO and enable output AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - HIGH(GPIO_SSC_DOUT); + LOW(GPIO_SSC_DOUT); // reserve a cardmem, meaning we can use the tracelog function in bigbuff easier. legic_mem = BigBuf_get_EM_addr(); @@ -406,11 +411,11 @@ legic_card_select_t *getLegicCardInfo(void) { void LegicRfInfo(void) { // configure ARM and FPGA - init_reader(false); + init_reader(); // establish shared secret and detect card type uint8_t card_type = setup_phase(0x01); - if (init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != PM3_SUCCESS) { reply_mix(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -446,11 +451,11 @@ int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv) { int res = PM3_SUCCESS; // configure ARM and FPGA - init_reader(false); + init_reader(); // establish shared secret and detect card type uint8_t card_type = setup_phase(iv); - if (init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != PM3_SUCCESS) { res = PM3_ESOFT; goto OUT; } @@ -481,11 +486,11 @@ OUT: void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) { // configure ARM and FPGA - init_reader(false); + init_reader(); // establish shared secret and detect card type uint8_t card_type = setup_phase(iv); - if (init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != PM3_SUCCESS) { reply_mix(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -518,7 +523,7 @@ OUT: void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) { // configure ARM and FPGA - init_reader(false); + init_reader(); // uid is not writeable if (offset <= WRITE_LOWERLIMIT) { @@ -528,7 +533,7 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) { // establish shared secret and detect card type uint8_t card_type = setup_phase(iv); - if (init_card(card_type, &card) != 0) { + if (init_card(card_type, &card) != PM3_SUCCESS) { reply_mix(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; } @@ -539,8 +544,8 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) { } // write in reverse order, only then is DCF (decremental field) writable - while (len-- > 0 && !BUTTON_PRESS()) { - if (!write_byte(len + offset, data[len], card.addrsize)) { + while (len-- > 0 && BUTTON_PRESS() == false) { + if (write_byte(len + offset, data[len], card.addrsize) == false) { Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]); reply_mix(CMD_ACK, 0, 0, 0, 0, 0); goto OUT; diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index 2ca65f54a..74609b326 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -15,7 +15,7 @@ #include "crc.h" /* legic crc-4 */ #include "legic_prng.h" /* legic PRNG impl */ #include "legic.h" /* legic_card_select_t struct */ - +#include "cmd.h" #include "proxmark3_arm.h" #include "BigBuf.h" #include "fpgaloader.h" @@ -295,9 +295,9 @@ static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) { p_card->cmdsize = 0; p_card->addrsize = 0; p_card->cardsize = 0; - return 2; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } static void init_tag(void) { @@ -455,23 +455,37 @@ static int32_t connected_phase(legic_card_select_t *p_card) { // Only this function is public / called from appmain.c //----------------------------------------------------------------------------- -void LegicRfSimulate(uint8_t cardtype) { +void LegicRfSimulate(uint8_t tagtype, bool send_reply) { // configure ARM and FPGA init_tag(); + int res = PM3_SUCCESS; // verify command line input - if (init_card(cardtype, &card) != 0) { - DbpString("[!] Unknown tagtype."); + if (init_card(tagtype, &card) != PM3_SUCCESS) { + DbpString("Unknown tagtype to simulate"); + res = PM3_ESOFT; goto OUT; } + uint16_t counter = 0; LED_A_ON(); - DbpString("[=] Starting Legic emulator, press " _YELLOW_("button") " to end"); - while (!BUTTON_PRESS() && !data_available()) { + + Dbprintf("Legic Prime, simulating uid: %02X%02X%02X%02X", legic_mem[0], legic_mem[1], legic_mem[2], legic_mem[3]); + + while (BUTTON_PRESS() == false) { WDT_HIT(); + if (counter >= 2000) { + if (data_available()) { + res = PM3_EOPABORTED; + break; + } + counter = 0; + } + counter++; + // wait for carrier, restart after timeout - if (!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) { + if (wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD) == false) { continue; } @@ -481,13 +495,25 @@ void LegicRfSimulate(uint8_t cardtype) { } // conection is established, process commands until one fails - while (!connected_phase(&card)) { + while (connected_phase(&card) == false) { WDT_HIT(); } } OUT: - DbpString("[=] Sim stopped"); + + if (DBGLEVEL >= DBG_ERROR) { + Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); + } + + if (res == PM3_EOPABORTED) + DbpString("aborted by user"); + switch_off(); StopTicks(); + + if (send_reply) + reply_ng(CMD_HF_LEGIC_SIMULATE, res, NULL, 0); + + BigBuf_free_keep_EM(); } diff --git a/armsrc/legicrfsim.h b/armsrc/legicrfsim.h index f7be94165..0b0bdbd9c 100644 --- a/armsrc/legicrfsim.h +++ b/armsrc/legicrfsim.h @@ -1,7 +1,8 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz // 2018 AntiCat -// +// 2019 Piwi +// 2020 Iceman // 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. @@ -14,6 +15,6 @@ #include "common.h" -void LegicRfSimulate(uint8_t cardtype); +void LegicRfSimulate(uint8_t tagtype, bool send_reply); #endif /* __LEGICRFSIM_H */ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index b29844476..93e9cd230 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2041,7 +2041,7 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, // Acquisition // Now do the acquisition - DoPartialAcquisition(0, false, samples, 0); + DoPartialAcquisition(0, false, samples, 1000); // Turn the field off if (brute_mem == false) { @@ -2084,7 +2084,7 @@ void T55xx_ChkPwds(uint8_t flags) { baseline_faulty >>= 5; if (DBGLEVEL >= DBG_DEBUG) - Dbprintf("Baseline " _YELLOW_("%llu"), baseline_faulty); + Dbprintf("Baseline " _YELLOW_("%llu"), baseline_faulty); uint8_t *pwds = BigBuf_get_EM_addr(); uint16_t pwd_count = 0; @@ -2147,7 +2147,7 @@ void T55xx_ChkPwds(uint8_t flags) { if (DBGLEVEL >= DBG_DEBUG) Dbprintf("%08x has distance " _YELLOW_("%llu"), pwd, curr); - + if (curr > prev) { idx = i; prev = curr; @@ -2165,7 +2165,7 @@ OUT: FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - reply_ng(CMD_LF_T55XX_CHK_PWDS, PM3_SUCCESS, (uint8_t*)&payload, sizeof(payload)); + reply_ng(CMD_LF_T55XX_CHK_PWDS, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); BigBuf_free(); } @@ -2492,36 +2492,37 @@ static void SendForward(uint8_t fwd_bit_count) { } static void EM4xLogin(uint32_t pwd) { - uint8_t len; forward_ptr = forwardLink_data; - len = Prepare_Cmd(FWD_CMD_LOGIN); + uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); SendForward(len); //WaitUS(20); // no wait for login command. // should receive - // 0000 1010 ok. + // 0000 1010 ok // 0000 0001 fail } void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { - LED_A_ON(); - uint8_t len; + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); - //clear buffer now so it does not interfere with timing later + LED_A_ON(); + + // clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); - StartTicks(); /* should we read answer from Logincommand? * * should receive - * 0000 1010 ok. + * 0000 1010 ok * 0000 0001 fail **/ if (usepwd) EM4xLogin(pwd); forward_ptr = forwardLink_data; - len = Prepare_Cmd(FWD_CMD_READ); + uint8_t len = Prepare_Cmd(FWD_CMD_READ); len += Prepare_Addr(addr); SendForward(len); @@ -2530,19 +2531,23 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { DoPartialAcquisition(20, false, 6000, 1000); + StopTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_LF_EM4X_READWORD, PM3_SUCCESS, NULL, 0); - LED_A_OFF(); + LEDsoff(); } void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { - LED_A_ON(); - uint8_t len; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(50); + + LED_A_ON(); + + // clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + /* should we read answer from Logincommand? * * should receive @@ -2552,20 +2557,21 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { if (usepwd) EM4xLogin(pwd); forward_ptr = forwardLink_data; - len = Prepare_Cmd(FWD_CMD_WRITE); + uint8_t len = Prepare_Cmd(FWD_CMD_WRITE); len += Prepare_Addr(addr); len += Prepare_Data(data & 0xFFFF, data >> 16); SendForward(len); - //Wait 20ms for write to complete? + // Wait 20ms for write to complete? WaitMS(7); DoPartialAcquisition(20, false, 6000, 1000); + StopTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); - LED_A_OFF(); + LEDsoff(); } /* @@ -2612,25 +2618,27 @@ void Cotag(uint32_t arg0) { LED_A_ON(); - LFSetupFPGAForADC(LF_DIVISOR_125, true); + LFSetupFPGAForADC(LF_FREQ2DIV(132), true); //132 //clear buffer now so it does not interfere with timing later BigBuf_free(); BigBuf_Clear_ext(false); - //send COTAG start pulse - ON(740) OFF(2035) - ON(3330) OFF(2035) - ON(740) OFF(2035) - ON(1000) - - -/* + // send COTAG start pulse + // http://www.proxmark.org/forum/viewtopic.php?id=4455 + /* + ON(740) OFF(2035) + ON(3330) OFF(2035) + ON(740) OFF(2035) + ON(2000) + */ ON(800) OFF(2200) ON(3600) OFF(2200) ON(800) OFF(2200) - ON(3400) -*/ + ON(2000) // ON(3400) + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_FREQ2DIV(66)); // 66kHz + switch (rawsignal) { case 0: { doCotagAcquisition(); @@ -2658,7 +2666,6 @@ void Cotag(uint32_t arg0) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - } /* diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 6d58250d1..b5e074e5b 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -36,7 +36,7 @@ static BitstreamOut data = {0, 0, 0}; // internal struct to keep track of samples gathered static sampling_t samples = {0, 0, 0, 0}; -void printConfig(void) { +void printLFConfig(void) { uint32_t d = config.divisor; DbpString(_CYAN_("LF Sampling config")); Dbprintf(" [q] divisor.............%d ( "_GREEN_("%d.%02d kHz")" )", d, 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100)); @@ -97,7 +97,7 @@ void setSamplingConfig(sample_config *sc) { config.samples_to_skip = sc->samples_to_skip; if (sc->verbose) - printConfig(); + printLFConfig(); } sample_config *getSamplingConfig(void) { @@ -268,10 +268,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in initSampleBuffer(&sample_size); if (DBGLEVEL >= DBG_DEBUG) { - Dbprintf("lf sampling - after init"); printSamples(); } + bool trigger_hit = false; uint32_t cancel_counter = 0; int16_t checked = 0; @@ -279,7 +279,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in // only every 4000th times, in order to save time when collecting samples. // interruptible only when logging not yet triggered - if ((checked >= 4000) && (trigger_threshold > 0)) { + if ((checked >= 4000) && trigger_hit == false) { if (data_available()) { checked = -1; break; @@ -298,20 +298,22 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - // Testpoint 8 (TP8) can be used to trigger oscilliscope + // Test point 8 (TP8) can be used to trigger oscilloscope LED_D_OFF(); // threshold either high or low values 128 = center 0. if trigger = 178 - if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) { - if (cancel_after > 0) { - cancel_counter++; - if (cancel_after == cancel_counter) - break; + if (trigger_hit == false) { + if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) { + if (cancel_after > 0) { + cancel_counter++; + if (cancel_after == cancel_counter) + break; + } + continue; } - continue; } - trigger_threshold = 0; + trigger_hit = true; if (samples_to_skip > 0) { samples_to_skip--; @@ -324,18 +326,19 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in } } - if (checked == -1 && verbose) { - Dbprintf("lf sampling aborted"); - } - if (verbose) { + if (checked == -1) { + Dbprintf("lf sampling aborted"); + } else if (cancel_counter == cancel_after) { + Dbprintf("lf sampling cancelled after %u", cancel_counter); + } + Dbprintf("Done, saved " _YELLOW_("%d")" out of " _YELLOW_("%d")" seen samples at " _YELLOW_("%d")" bits/sample", samples.total_saved, samples.counter, bits_per_sample); } // Ensure that DC offset removal and noise check is performed for any device-side processing removeSignalOffset(data.buffer, samples.total_saved); computeSignalProperties(data.buffer, samples.total_saved); - return data.numbits; } /** @@ -356,20 +359,28 @@ uint32_t DoAcquisition_config(bool verbose, uint32_t sample_size) { , config.trigger_threshold , verbose , sample_size - , 0 + , 0 // cancel_after , config.samples_to_skip); } uint32_t DoPartialAcquisition(int trigger_threshold, bool verbose, uint32_t sample_size, uint32_t cancel_after) { - return DoAcquisition(1, 8, 0, trigger_threshold, verbose, sample_size, cancel_after, 0); + return DoAcquisition(config.decimation + , config.bits_per_sample + , config.averaging + , trigger_threshold + , verbose + , sample_size + , cancel_after + , 0); // samples to skip } static uint32_t ReadLF(bool reader_field, bool verbose, uint32_t sample_size) { if (verbose) - printConfig(); + printLFConfig(); LFSetupFPGAForADC(config.divisor, reader_field); uint32_t ret = DoAcquisition_config(verbose, sample_size); + StopTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); return ret; } @@ -495,7 +506,7 @@ void doCotagAcquisition(void) { bool firsthigh = false, firstlow = false; uint16_t i = 0, noise_counter = 0; - while ((i < bufsize) && (noise_counter < COTAG_T1 << 1)) { + while ((i < bufsize - 1) && (noise_counter < COTAG_T1 << 1)) { if (BUTTON_PRESS()) break; @@ -527,14 +538,13 @@ void doCotagAcquisition(void) { firstlow = true; } - if (++i < bufsize) { - if (sample > COTAG_ONE_THRESHOLD) { - dest[i] = 255; - } else if (sample < COTAG_ZERO_THRESHOLD) { - dest[i] = 0; - } else { - dest[i] = dest[i - 1]; - } + ++i; + if (sample > COTAG_ONE_THRESHOLD) { + dest[i] = 255; + } else if (sample < COTAG_ZERO_THRESHOLD) { + dest[i] = 0; + } else { + dest[i] = dest[i - 1]; } } } @@ -548,7 +558,7 @@ uint16_t doCotagAcquisitionManchester(uint8_t *dest, uint16_t destlen) { if (dest == NULL) return 0; - + dest[0] = 0; bool firsthigh = false, firstlow = false; diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index 137738163..f60324d70 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -99,7 +99,7 @@ void setSamplingConfig(sample_config *sc); sample_config *getSamplingConfig(void); -void printConfig(void); +void printLFConfig(void); void printSamples(void); #endif // __LFSAMPLING_H diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index d99698ba8..dd2bffedf 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -34,6 +34,7 @@ #include "ticks.h" #include "usb_cdc.h" // usb_poll_validate_length #include "spiffs.h" // spiffs +#include "appmain.h" // print_stack_usage #ifndef HARDNESTED_AUTHENTICATION_TIMEOUT # define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) @@ -369,7 +370,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) countblocks *= 4; - reply_mix(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); + reply_mix(CMD_ACK, 1, countblocks, dataout - BigBuf_get_addr(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); BigBuf_free(); @@ -443,47 +444,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { set_tracing(false); } -/* // Command not needed but left for future testing -void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) -{ - uint8_t blockNo = arg0; - uint8_t blockdata[16] = {0x00}; - - memcpy(blockdata, datain, 16); - - uint8_t uid[10] = {0x00}; - - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - clear_trace(); - set_tracing(true); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - - if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { - if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); - OnError(0); - return; - }; - - if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { - if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); - OnError(0); - return; }; - - if(mifare_ultra_halt()) { - if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); - OnError(0); - return; - }; - - if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - reply_mix(CMD_ACK,1,0,0,0,0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} -*/ - // Arg0 : Block to write to. // Arg1 : 0 = use no authentication. // 1 = use 0x1A authentication. @@ -553,6 +513,75 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { set_tracing(false); } +// Arg0 : Block to write to. +// Arg1 : 0 = use no authentication. +// 1 = use 0x1A authentication. +// 2 = use 0x1B authentication. +// datain : 16 first bytes is data to be written. +// : 4/16 next bytes is authentication key. +void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + uint8_t blockNo = arg0; + bool useKey = (arg1 == 1); //UL_C + bool usePwd = (arg1 == 2); //UL_EV1/NTAG + uint8_t blockdata[16] = {0x00}; + + memcpy(blockdata, datain, 16); + + LEDsoff(); + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + OnError(0); + return; + }; + + // UL-C authentication + if (useKey) { + uint8_t key[16] = {0x00}; + memcpy(key, datain + 16, sizeof(key)); + + if (!mifare_ultra_auth(key)) { + OnError(1); + return; + } + } + + // UL-EV1 / NTAG authentication + if (usePwd) { + uint8_t pwd[4] = {0x00}; + memcpy(pwd, datain + 16, 4); + uint8_t pack[4] = {0, 0, 0, 0}; + if (!mifare_ul_ev1_auth(pwd, pack)) { + OnError(1); + return; + } + } + + if (mifare_ultra_writeblock_compat(blockNo, blockdata)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); + OnError(0); + return; + }; + + if (mifare_ultra_halt()) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); + OnError(0); + return; + }; + + if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} + void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { uint8_t pwd[16] = {0x00}; @@ -905,7 +934,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 set_tracing(true); // statistics on nonce distance - int16_t isOK = 0; + int16_t isOK = PM3_SUCCESS; #define NESTED_MAX_TRIES 12 if (calibrate) { // calibrate: for first call only. Otherwise reuse previous calibration LED_B_ON(); @@ -921,7 +950,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 // Test if the action was cancelled if (BUTTON_PRESS() || data_available()) { - isOK = -2; + isOK = PM3_EOPABORTED; break; } @@ -976,7 +1005,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 } else { unsuccessful_tries++; if (unsuccessful_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) - isOK = -3; + isOK = PM3_EFAILED; } } } @@ -1002,7 +1031,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 // Test if the action was cancelled if (BUTTON_PRESS() || data_available()) { - isOK = -2; + isOK = PM3_EOPABORTED; break; } @@ -1091,12 +1120,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 memcpy(payload.nt_b, &target_nt[1], 4); memcpy(payload.ks_b, &target_ks[1], 4); - LED_B_ON(); reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); - LED_B_OFF(); - - if (DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); set_tracing(false); @@ -1108,13 +1132,10 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint64_t ui64Key = 0; ui64Key = bytes_to_num(key, 6); - - // variables uint16_t len; - uint8_t uid[10] = {0x00}; uint32_t cuid = 0, nt1, nt2; - uint32_t target_nt = {0x00}, target_ks = {0x00}; + uint32_t target_nt = 0, target_ks = 0; uint8_t par[1] = {0x00}; uint8_t receivedAnswer[10] = {0x00}; @@ -1132,7 +1153,6 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, set_tracing(true); int16_t isOK = 0; - LED_C_ON(); for (uint8_t retry = 0; retry < 3 && (isOK == 0); retry++) { @@ -1152,7 +1172,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, continue; }; - // First authenticatoin. Normal auth. + // First authentication. Normal auth. if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Auth1 error"); retry--; @@ -1167,9 +1187,8 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, }; nt2 = bytes_to_num(receivedAnswer, 4); - uint32_t nt_tmp = prng_successor(nt1, 160); - target_ks = nt2 ^ nt_tmp; - target_nt = nt_tmp; + target_nt = prng_successor(nt1, 160); + target_ks = nt2 ^ target_nt; isOK = 1; if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x", nt1, nt2, par[0], target_ks); @@ -1689,7 +1708,7 @@ OUT: DBGLEVEL = oldbg; } -void MifareChkKeys(uint8_t *datain) { +void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1715,7 +1734,12 @@ void MifareChkKeys(uint8_t *datain) { bool clearTrace = datain[2]; uint16_t key_count = (datain[3] << 8) | datain[4]; - uint16_t key_mem_available = MIN((PM3_CMD_DATA_SIZE - 5), key_count * 6); + uint16_t key_mem_available; + if (reserved_mem) + key_mem_available = key_count * 6; + else + key_mem_available = MIN((PM3_CMD_DATA_SIZE - 5), key_count * 6); + key_count = key_mem_available / 6; datain += 5; @@ -1793,6 +1817,8 @@ void MifareChkKeys(uint8_t *datain) { void MifareChkKeys_file(uint8_t *fn) { #ifdef WITH_FLASH + BigBuf_free(); + SpinOff(0); int changed = rdv40_spiffs_lazy_mount(); @@ -1807,7 +1833,7 @@ void MifareChkKeys_file(uint8_t *fn) { SpinOff(0); - MifareChkKeys(mem); + MifareChkKeys(mem, true); BigBuf_free(); #endif @@ -1966,10 +1992,16 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { - retval = PM3_ESOFT; + retval = PM3_EPARTIAL; + if (DBGLEVEL > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); - break; + continue; } + + if (memcmp(dataoutbuf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { + continue; + } + if (blockNo < NumBlocksPerSector(sectorNo) - 1) { emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); } else { // sector trailer, keep the keys, set only the AC @@ -2059,12 +2091,19 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { break; } + uint32_t old_timeout = iso14a_get_timeout(); + + // 2000 ms timeout + // 13560000 / 1000 / (8 * 16) * timeout + iso14a_set_timeout(21190); + ReaderTransmit(wipeC, sizeof(wipeC), NULL); if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("wipeC error"); errormsg = MAGIC_WIPE; break; } + iso14a_set_timeout(old_timeout); mifare_classic_halt_ex(NULL); } @@ -2244,6 +2283,26 @@ void MifareCIdent(void) { if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) { isGen = MAGIC_GEN_2; } + // test for Ultralight magic gen2 + if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) { + isGen = MAGIC_GEN_2; + goto OUT; + } + // test for Ultralight EV1 magic gen2 + if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) { + isGen = MAGIC_GEN_2; + goto OUT; + } + // test for some other Ultralight EV1 magic gen2 + if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) { + isGen = MAGIC_GEN_2; + goto OUT; + } + // test for some other Ultralight magic gen2 + if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) { + isGen = MAGIC_GEN_2; + goto OUT; + } }; OUT: @@ -2315,6 +2374,154 @@ void OnErrorMagic(uint8_t reason) { OnSuccessMagic(); } +int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len) { + int retval = PM3_SUCCESS; + uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); + + LED_B_ON(); + uint32_t save_iso14a_timeout = iso14a_get_timeout(); + iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 2000); // 2 seconds timeout + + ReaderTransmit(cmd, cmd_len, NULL); + int res = ReaderReceive(buf, par); + if (res == 4 && memcmp(buf, "\x90\x00\xfd\x07", 4) == 0) { + // timeout for card memory reset + SpinDelay(1000); + } else { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card operation not completed"); + retval = PM3_ESOFT; + } + iso14a_set_timeout(save_iso14a_timeout); + LED_B_OFF(); + + return retval; +} + +void MifareGen3UID(uint8_t uidlen, uint8_t *uid) { + int retval = PM3_SUCCESS; + uint8_t uid_cmd[5] = { 0x90, 0xfb, 0xcc, 0xcc, 0x07 }; + uint8_t *old_uid = BigBuf_malloc(10); + uint8_t *cmd = BigBuf_malloc(sizeof(uid_cmd) + uidlen + 2); + iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t)); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(old_uid, card_info, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + if (card_info->uidlen != uidlen) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID length"); + retval = PM3_ESOFT; + goto OUT; + } + + memcpy(cmd, uid_cmd, sizeof(uid_cmd)); + memcpy(&cmd[sizeof(uid_cmd)], uid, uidlen); + AddCrc14A(cmd, sizeof(uid_cmd) + uidlen); + + retval = DoGen3Cmd(cmd, sizeof(uid_cmd) + uidlen + 2); + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3UID, retval, old_uid, uidlen); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + +void MifareGen3Blk(uint8_t block_len, uint8_t *block) { +#define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2) + int retval = PM3_SUCCESS; + uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 }; + uint8_t *uid = BigBuf_malloc(10); + uint8_t *cmd = BigBuf_malloc(sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE); + iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t)); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(uid, card_info, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + + bool doReselect = false; + if (block_len < MIFARE_BLOCK_SIZE) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read manufacturer block failed"); + retval = PM3_ESOFT; + goto OUT; + } + doReselect = true; + } + + if (block_len > 0) { + memcpy(cmd, block_cmd, sizeof(block_cmd)); + memcpy(&cmd[sizeof(block_cmd)], block, block_len); + int ofs = sizeof(block_cmd); + if (card_info->uidlen == 4) { + cmd[ofs + 4] = cmd[ofs + 0] ^ cmd[ofs + 1] ^ cmd[ofs + 2] ^ cmd[ofs + 3]; + ofs += 5; + } else if (card_info->uidlen == 7) { + ofs += 7; + } else { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong Card UID length"); + retval = PM3_ESOFT; + goto OUT; + } + cmd[ofs++] = card_info->sak; + cmd[ofs++] = card_info->atqa[0]; + cmd[ofs++] = card_info->atqa[1]; + AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE); + + if (doReselect) { + if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + } + + retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE); + } + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3BLK, retval, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + +void MifareGen3Freez(void) { + int retval = PM3_SUCCESS; + uint8_t freeze_cmd[7] = { 0x90, 0xfd, 0x11, 0x11, 0x00, 0xe7, 0x91 }; + uint8_t *uid = BigBuf_malloc(10); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected"); + retval = PM3_ESOFT; + goto OUT; + } + + retval = DoGen3Cmd(freeze_cmd, sizeof(freeze_cmd)); + +OUT: + reply_ng(CMD_HF_MIFARE_GEN3FREEZ, retval, NULL, 0); + // turns off + OnSuccessMagic(); + BigBuf_free(); +} + void MifareSetMod(uint8_t *datain) { uint8_t mod = datain[0]; diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 2d9a4799a..b024d2d1b 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -20,7 +20,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes); void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); +void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key); @@ -29,7 +29,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); void MifareAcquireNonces(uint32_t arg0, uint32_t flags); -void MifareChkKeys(uint8_t *datain); +void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem); void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareChkKeys_file(uint8_t *fn); @@ -44,6 +44,11 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); void MifareCIdent(void); // is "magic chinese" card? void MifareHasStaticNonce(void); // Has the tag a static nonce? +int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len); +void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block +void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block +void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes + void MifareSetMod(uint8_t *datain); void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 60f9a7810..4eaf711b3 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -85,7 +85,6 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act } } - static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { uint8_t sector_trailer[16]; @@ -243,7 +242,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_ rSAK[0] = block0[7]; memcpy(rATQA, &block0[8], sizeof(rATQA)); } else { - Dbprintf("[-] ERROR: Invalid dump. UID/SAK/ATQA not found"); + Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found")); return false; } } @@ -342,7 +341,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_ // Correct uid size bits in ATQA rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid } else { - Dbprintf("[-] ERROR: UID size not defined"); + Dbprintf("ERROR: " _RED_("UID size not defined")); return false; } if (flags & FLAG_FORCED_ATQA) { @@ -529,12 +528,22 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 LED_D_ON(); ResetSspClk(); + int counter = 0; bool finished = false; bool button_pushed = BUTTON_PRESS(); + while (!button_pushed && !finished) { - while (!button_pushed && !finished && !data_available()) { WDT_HIT(); + if (counter == 2000) { + if (data_available()) { + break; + } + counter = 0; + } else { + counter++; + } + // find reader field if (cardSTATE == MFEMUL_NOFIELD) { diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 71c57a963..5d8989ef8 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -203,14 +203,14 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN iso14a_set_timeout(save_timeout); if (!len) { - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout."); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout"); return 2; } ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0); if (ntpp != bytes_to_num(receivedAnswer, 4)) { - if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response."); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response"); return 3; } return 0; @@ -225,18 +225,18 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { - if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]); return 1; } if (len != 18) { - if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: wrong response len: %x (expected 18)", len); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("wrong response len %d (expected 18)", len); return 2; } memcpy(bt, receivedAnswer + 16, 2); AddCrc14A(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (DBGLEVEL >= DBG_INFO) Dbprintf("Cmd CRC response error."); + if (DBGLEVEL >= DBG_INFO) Dbprintf("CRC response error"); return 3; } @@ -446,37 +446,37 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl return 0; } -/* // command not needed, but left for future testing int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { - uint16_t len; - uint8_t par[3] = {0}; // enough for 18 parity bits - uint8_t d_block[18] = {0x00}; - uint8_t receivedAnswer[MAX_FRAME_SIZE]; - uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; + // variables + uint16_t len = 0; + + uint8_t d_block[18]; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00}; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00}; len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (DBGLEVEL >= DBG_ERROR) - Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]); + Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); return 1; } memcpy(d_block, blockData, 16); AddCrc14A(d_block, 16); - ReaderTransmitPar(d_block, sizeof(d_block), par, NULL); + ReaderTransmit(d_block, sizeof(d_block), NULL); + // Receive the response len = ReaderReceive(receivedAnswer, receivedAnswerPar); - if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK + if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK if (DBGLEVEL >= DBG_ERROR) - Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len); + Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len); return 2; } return 0; } -*/ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) { uint16_t len = 0; @@ -613,7 +613,7 @@ void emlClearMem(void) { memset(emCARD, 0, CARD_MEMORY_SIZE); // fill sectors trailer data - for (uint16_t b = 3; b <= MIFARE_4K_MAXBLOCK; ((b <= MIFARE_2K_MAXBLOCK) ? (b += 4) : (b += 16))) + for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16))) emlSetMem((uint8_t *)trailer, b, 1); // uid diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index b1d6396d5..d444dc81f 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -73,7 +73,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack); int mifare_ultra_auth(uint8_t *keybytes); int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData); -//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData); +int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData); int mifare_ultra_halt(void); diff --git a/armsrc/spiffs.c b/armsrc/spiffs.c index dac1de449..a1b3e8e39 100644 --- a/armsrc/spiffs.c +++ b/armsrc/spiffs.c @@ -67,30 +67,33 @@ static s32_t rdv40_spiffs_llwrite(u32_t addr, u32_t size, u8_t *src) { } static s32_t rdv40_spiffs_llerase(u32_t addr, u32_t size) { - - uint8_t erased = 0; if (!FlashInit()) { return 130; } - if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : Orig addr : %d\n", addr); + + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : Orig addr : %d\n", addr); + uint8_t block, sector = 0; block = addr / RDV40_LLERASE_BLOCKSIZE; if (block) { addr = addr - (block * RDV40_LLERASE_BLOCKSIZE); } - if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : Result addr : %d\n", addr); + + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : Result addr : %d\n", addr); + sector = addr / SPIFFS_CFG_LOG_BLOCK_SZ; Flash_CheckBusy(BUSY_TIMEOUT); Flash_WriteEnable(); - if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : block : %d, sector : %d \n", block, sector); - erased = Flash_Erase4k(block, sector); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : block : %d, sector : %d \n", block, sector); + + erased = Flash_Erase4k(block, sector); Flash_CheckBusy(BUSY_TIMEOUT); FlashStop(); - return SPIFFS_OK == erased ; + return (SPIFFS_OK == erased); } //////////////////////////////////////////////////////////////////////////////// @@ -252,7 +255,7 @@ static RDV40SpiFFSFileType filetype_in_spiffs(const char *filename) { filetype = RDV40_SPIFFS_FILETYPE_SYMLINK; } } - if (DBGLEVEL > 1) { + if (DBGLEVEL >= DBG_DEBUG) { switch (filetype) { case RDV40_SPIFFS_FILETYPE_REAL: Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_REAL"); @@ -472,16 +475,19 @@ int rdv40_spiffs_is_symlink(const char *s) { // ATTENTION : you must NOT provide the whole filename (so please do not include the .lnk extension) // TODO : integrate in read_function int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) { + RDV40_SPIFFS_SAFE_FUNCTION( char linkdest[SPIFFS_OBJ_NAME_LEN]; char linkfilename[SPIFFS_OBJ_NAME_LEN]; sprintf(linkfilename, "%s.lnk", filename); - if (DBGLEVEL > 1) Dbprintf("Linkk real filename is : " _YELLOW_("%s"), linkfilename); + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("Linkk real filename is : " _YELLOW_("%s"), linkfilename); read_from_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN); - if (DBGLEVEL > 1) Dbprintf("Symlink destination is : " _YELLOW_("%s"), linkdest); + if (DBGLEVEL >= DBG_DEBUG) + Dbprintf("Symlink destination is : " _YELLOW_("%s"), linkdest); read_from_spiffs((char *)linkdest, (uint8_t *)dst, size); ) diff --git a/armsrc/spiffs_config.h b/armsrc/spiffs_config.h index 0cf3b96f5..85997903b 100644 --- a/armsrc/spiffs_config.h +++ b/armsrc/spiffs_config.h @@ -58,8 +58,6 @@ typedef uint8_t u8_t; #define SPIFFS_API_DBGF(str) SPIFFS_API_DBG(str,NULL) #endif - - // Defines spiffs debug print formatters // some general signed number #ifndef _SPIPRIi diff --git a/armsrc/usart.c b/armsrc/usart.c index b6ed97310..b3ed42978 100644 --- a/armsrc/usart.c +++ b/armsrc/usart.c @@ -56,7 +56,7 @@ static void usart_fill_rxfifo(void) { rxfifo_free = us_rxfifo_low - us_rxfifo_high; else rxfifo_free = sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low; - + uint16_t available = USART_BUFFLEN - usart_cur_inbuf_off; if (available <= rxfifo_free) { diff --git a/armsrc/util.h b/armsrc/util.h index c6523a813..1d8586c43 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -63,7 +63,7 @@ #endif #ifndef REV64 -#define REV64(x) (REV32(x) + (REV32((x) >> 32) << 32)) +#define REV64(x) (REV32(x) + ((uint64_t)(REV32((x) >> 32) << 32))) #endif #ifndef BIT32 diff --git a/client/cmdscripts/test_psk_clone.cmd b/client/cmdscripts/test_psk_clone.cmd new file mode 100644 index 000000000..f37ddcfea --- /dev/null +++ b/client/cmdscripts/test_psk_clone.cmd @@ -0,0 +1,28 @@ +clear + +rem Test of Motorola clone & read +lf t55xx wipe +lf motorola clone a0000000a0002021 +lf motorola read +lf search + +rem Test of Nexwatch clone & read +lf t55xx wipe +lf nexwatch clone c 1337 m 1 n +lf nexwatch read +lf search + +rem Test of keri clone & read +lf t55xx wipe +lf keri clone 1337 +lf keri read +lf search + +rem Test of Indala clone & read +lf t55xx wipe +lf indala clone --fc 7 --cn 1337 +lf indala read +lf search + +rem done, just wiping your tag. +lf t55xx wipe diff --git a/client/deps/hardnested.cmake b/client/deps/hardnested.cmake index 6ec4f0297..f9248b82d 100644 --- a/client/deps/hardnested.cmake +++ b/client/deps/hardnested.cmake @@ -7,7 +7,8 @@ set_property(TARGET pm3rrg_rdv4_hardnested_nosimd PROPERTY POSITION_INDEPENDENT_ target_include_directories(pm3rrg_rdv4_hardnested_nosimd PRIVATE ../../common - ../../include) + ../../include + ../src) ## CPU-specific code ## These are mostly for x86-based architectures, which is not useful for many Android devices. @@ -34,7 +35,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) target_include_directories(pm3rrg_rdv4_hardnested_mmx PRIVATE ../../common - ../../include) + ../../include + ../src) ## x86 / SSE2 add_library(pm3rrg_rdv4_hardnested_sse2 OBJECT @@ -48,7 +50,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) target_include_directories(pm3rrg_rdv4_hardnested_sse2 PRIVATE ../../common - ../../include) + ../../include + ../src) ## x86 / AVX add_library(pm3rrg_rdv4_hardnested_avx OBJECT @@ -62,7 +65,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) target_include_directories(pm3rrg_rdv4_hardnested_avx PRIVATE ../../common - ../../include) + ../../include + ../src) ## x86 / AVX2 add_library(pm3rrg_rdv4_hardnested_avx2 OBJECT @@ -76,7 +80,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) target_include_directories(pm3rrg_rdv4_hardnested_avx2 PRIVATE ../../common - ../../include) + ../../include + ../src) ## x86 / AVX512 add_library(pm3rrg_rdv4_hardnested_avx512 OBJECT @@ -90,7 +95,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) target_include_directories(pm3rrg_rdv4_hardnested_avx512 PRIVATE ../../common - ../../include) + ../../include + ../src) set(SIMD_TARGETS $ diff --git a/client/deps/hardnested/hardnested_bf_core.c b/client/deps/hardnested/hardnested_bf_core.c index 5f4fcf991..719578331 100644 --- a/client/deps/hardnested/hardnested_bf_core.c +++ b/client/deps/hardnested/hardnested_bf_core.c @@ -59,7 +59,7 @@ THE SOFTWARE. #include #include "crapto1/crapto1.h" #include "parity.h" -//#include "util.h" +#include "ui.h" // PrintAndLogEx //#include "common.h" // bitslice type @@ -238,18 +238,18 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel // bitslice all the even states bitslice_t **restrict bitsliced_even_states = (bitslice_t **)malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof(bitslice_t *)); if (bitsliced_even_states == NULL) { - printf("Out of memory error in brute_force. Aborting..."); + PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting..."); exit(4); } bitslice_value_t *restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof(bitslice_value_t)); if (bitsliced_even_feedback == NULL) { - printf("Out of memory error in brute_force. Aborting..."); + PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting..."); exit(4); } for (uint32_t *restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) { bitslice_t *restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof(bitslice_t)); if (lstate_p == NULL) { - printf("Out of memory error in brute_force. Aborting... \n"); + PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting... \n"); exit(4); } memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof(bitslice_t)); // zero even bits @@ -265,8 +265,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel #ifdef DEBUG_KEY_ELIMINATION if (known_target_key != -1 && e == test_state[EVEN_STATE]) { bucket_contains_test_key[bitsliced_blocks] = true; - // printf("bucket %d contains test key even state\n", bitsliced_blocks); - // printf("in slice %d\n", slice_idx); + // PrintAndLogEx(INFO, "bucket %d contains test key even state", bitsliced_blocks); + // PrintAndLogEx(INFO, "in slice %d", slice_idx); } #endif for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) { @@ -336,8 +336,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel #ifdef DEBUG_KEY_ELIMINATION // if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) { - // printf("Now testing known target key.\n"); - // printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks); + // PrintAndLogEx(INFO, "Now testing known target key."); + // PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks); // } #endif // add the even state bits @@ -444,8 +444,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel #endif #ifdef DEBUG_KEY_ELIMINATION if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) { - printf("Known target key eliminated in brute_force.\n"); - printf("block_idx = %d/%d, nonce = %d/%d\n", block_idx, bitsliced_blocks, tests, nonces_to_bruteforce); + PrintAndLogEx(INFO, "Known target key eliminated in brute_force."); + PrintAndLogEx(INFO, "block_idx = %d/%d, nonce = %d/%d", block_idx, bitsliced_blocks, tests, nonces_to_bruteforce); } #endif goto stop_tests; @@ -495,15 +495,15 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel } #ifdef DEBUG_KEY_ELIMINATION if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) { - printf("Known target key eliminated in brute_force verification.\n"); - printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks); + PrintAndLogEx(INFO, "Known target key eliminated in brute_force verification."); + PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks); } #endif } #ifdef DEBUG_KEY_ELIMINATION if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) { - printf("Known target key eliminated in brute_force (results_bit == 0).\n"); - printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks); + PrintAndLogEx(INFO, "Known target key eliminated in brute_force (results_bit == 0)."); + PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks); } #endif results64 >>= 1; @@ -533,7 +533,7 @@ out: #if defined (DEBUG_BRUTE_FORCE) for (uint32_t i = 0; i < MAX_ELIMINATION_STEP; i++) { - printf("Eliminated after %2u test_bytes: %5.2f%%\n", i + 1, (float)keys_eliminated[i] / bucket_states_tested * 100); + PrintAndLogEx(INFO, "Eliminated after %2u test_bytes: %5.2f%%", i + 1, (float)keys_eliminated[i] / bucket_states_tested * 100); } #endif return key; diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index cc68b0d88..d19c572e9 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1115,3 +1115,21 @@ fe04ecfe5577 C1E51C63B8F5 # RATB key 1DB710648A65 18F34C92A56E # E-GO card key +# +# Library Card MFP - SL1 +4a832584637d +ca679d6291b0 +30d9690fc5bc +5296c26109d4 +e77952748484 +91c2376005a1 +30b7680b2bc9 +e2a9e88bfe16 +43b04995d234 +aade86b1f9c1 +5ea088c824c9 +c67beb41ffbf +5ea088c824c9 +c67beb41ffbf +b84d52971107 +52b0d3f6116e diff --git a/client/luascripts/mfc_gen3_writer.lua b/client/luascripts/mfc_gen3_writer.lua new file mode 100644 index 000000000..9e78b2aee --- /dev/null +++ b/client/luascripts/mfc_gen3_writer.lua @@ -0,0 +1,431 @@ +local utils = require('utils') +local getopt = require('getopt') +local cmds = require('commands') +local read14a = require('read14a') +-- +--- +------------------------------- +-- Notes +------------------------------- +--- +-- +--[[ +---Suggestions of improvement: +--- Add support another types of dumps: BIN, JSON +--- Maybe it will be not only as `mfc_gen3_writer`, like a universal dump manager. +--- Add undependence from the operation system. At the moment code not working in Linux. +--- Hide system messages when you writing a dumps, replace it to some of like [#####----------] 40% + +-- iceman notes: +-- doesn't take consideration filepaths for dump files. +-- doesn't allow A keys for authenticating when writing +-- doesn't verify that card is magic gen3. +-- doesn't take several versions of same dump ( -1, -2, -3 ) styles. +--]] +-- +--- +------------------------------- +-- Script hat +------------------------------- +--- +-- +copyright = 'RRG Team' +author = 'Winds' +version = 'v1.0.0' +desc = [[ + This script gives you an easy way to write your *.eml dumps into normal MIFARE Classic and Magic Gen3 cards. + + Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards. + The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards. + + It supports the following functionality. + + 1. Write it to the same of current card UID. + 2. Write it to magic Gen3 card. + 3. Change uid to match dump on magic Gen3 card. + 4. Permanent lock UID on magic Gen3 card. + 5. Erase all data at the card and set the FF FF FF FF FF FF keys, and Access Conditions to 78778800. + + Script works in a wizard styled way. + + Author Youtube channel: https://yev.ooo/ + + Many Thanks, + Best Regards +]] +example = [[ + 1. script run mfc_gen3_writer +]] +usage = [[ + Give script to know if you uses an Windows OS + Select your *.eml dump from list to write to the card. + Follow the wizard. +]] +-- +--- +------------------------------- +-- Global variables +------------------------------- +--- +-- +local DEBUG = false -- the debug flag +local dumpEML -- Find all *.EML files +local files = {} -- Array for eml files +local b_keys = {} -- Array for B keys +local eml = {} -- Array for data in block 32 +local num_dumps = 0 -- num of found eml dump files +local tab = string.rep('-', 64) +local empty = string.rep('0', 32) -- Writing blocks +local default_key = 'FFFFFFFFFFFF' -- Writing blocks +local default_key_type = '01' --KeyA: 00, KeyB: 01 +local default_key_blk = 'FFFFFFFFFFFF7C378800FFFFFFFFFFFF' -- Writing blocks +local piswords_uid_lock = 'hf 14a raw -s -c -t 2000 90fd111100' +local piswords_uid_change = 'hf 14a raw -s -c -t 2000 90f0cccc10' +local cmd_wrbl_a = 'hf mf wrbl %d A %s %s' -- Writing blocks by A key +local cmd_wrbl_b = 'hf mf wrbl %d B %s %s' -- Writing blocks by B key +-- +--- +------------------------------- +-- A debug printout-function +------------------------------- +--- +-- +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +-- +--- +------------------------------- +-- 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 +-- +--- +------------------------------- +-- GetUID +------------------------------- +--- +-- +local function GetUID() + return read14a.read(true, true).uid +end +-- +local function dropfield() + read14a.disconnect() + core.clearCommandBuffer() +end +-- +--- +------------------------------- +-- Wait for tag (MFC) +------------------------------- +--- +-- +local function wait() + read14a.waitFor14443a() +end +-- +--- +------------------------------- +-- Return key code 00/01 to string +------------------------------- +--- +-- +local function KeyAB() + if default_key_type == '00' then + return 'KeyA' + else + return 'KeyB' + end +end +-- +--- +------------------------------- +-- Check response from Proxmark +------------------------------- +--- +-- +local function getblockdata(response) + if response.Status == 0 then + return true + else + return false + end +end +-- +--- +------------------------------- +-- Check 0xFFFFFFFFFFFF key for tag (MFC) +------------------------------- +--- +-- +local function checkkey() + local status = 0 + for i = 1, #eml do + cmd = Command:newNG{cmd = cmds.CMD_HF_MIFARE_READBL, data = ('%02x%02x%s'):format((i-1), default_key_type, default_key)} + if (getblockdata(cmd:sendNG(false)) == true) then + status = status + 1 + print(('%s %02s %s %s %s'):format(' ', (i-1), KeyAB(), default_key, 'OK')) + else + break + end + end + if status == #eml then + return true + end +end +-- +--- +------------------------------- +-- Check user input A or B for blank tag (MFC) +------------------------------- +--- +-- +local function check_user_key(user_key_type) + if user_key_type == 'A' then + return cmd_wrbl_a + elseif user_key_type == 'B' then + return cmd_wrbl_b + end +end +-- +--- +------------------------------- +-- Main function +------------------------------- +--- +-- +local function main(args) + -- + --- + ------------------------------- + -- Arguments for script + ------------------------------- + --- + -- + for o, a in getopt.getopt(args, 'hd') do + if o == 'h' then return help() end + if o == 'd' then DEBUG = true end + end + -- + wait() + print(tab) + -- + --- + ------------------------------- + -- Detect 7/4 byte card + ------------------------------- + --- + -- + if (utils.confirm(' Are you use a Windwos OS ?') == true) then + dumpEML = 'find "." "*dump.eml"' + if string.len(GetUID()) == 14 then + eml_file_uid_start = 18 + eml_file_uid_end = 31 + eml_file_lengt = 40 + else + eml_file_uid_start = 18 + eml_file_uid_end = 25 + eml_file_lengt = 34 + end + else + dumpEML = "find '.' -iname '*dump.eml' -type f" + if string.len(GetUID()) == 14 then + eml_file_uid_start = 9 + eml_file_uid_end = 22 + eml_file_lengt = 31 + else + eml_file_uid_start = 9 + eml_file_uid_end = 16 + eml_file_lengt = 25 + end + end + print(tab) + dropfield() + -- + --- + ------------------------------- + -- List all EML files in /client + ------------------------------- + --- + -- + local p = assert(io.popen(dumpEML)) + for _ in p:lines() do + -- The length of eml file + if string.len(_) == eml_file_lengt then + num_dumps = num_dumps + 1 + -- cut UID from eml file + files[num_dumps] = string.sub(_, eml_file_uid_start, eml_file_uid_end) -- cut numeretic UID + print(' '..num_dumps..' | '..files[num_dumps]) + end + end + -- + p.close() + -- + if num_dumps == 0 then return oops("Didn't find any dump files") end + -- + print(tab) + print(' Your card has UID '..GetUID()) + print('') + print(' Select which dump to write (1 until '..num_dumps..')') + print(tab) + io.write(' --> ') + -- + local uid_no = tonumber(io.read()) + print(tab) + print(' You have been selected card dump No ' .. uid_no .. ', with UID: ' .. files[uid_no] .. '. Your card UID: ' .. GetUID()) + -- + -- + --- + ------------------------------- + -- Load eml file + ------------------------------- + --- + -- + local dumpfile = assert(io.open('hf-mf-' .. files[uid_no] .. '-dump.eml', 'r')) + for _ in dumpfile:lines() do table.insert(eml, _); end + dumpfile.close() + -- + --- + ------------------------------- + -- Extract B key from EML file + ------------------------------- + --- + -- + local b = 0 + for i = 1, #eml do + if (i % 4 == 0) then + repeat + b = b + 1 + -- Cut key from block + b_keys[b] = string.sub(eml[i], (#eml[i] - 11), #eml[i]) + until b % 4 == 0 + end + end + print(tab) + dbg(b_keys) + dbg(eml) + -- + --- + ------------------------------- + -- Change UID on certain version of magic Gen3 card. + ------------------------------- + --- + -- + if (utils.confirm(' Change UID ?') == true) then + wait() + core.console(piswords_uid_change .. tostring(eml[1])) + print(tab) + print(' The new card UID : ' .. GetUID()) + end + print(tab) + -- + --- + ------------------------------- + -- Lock UID + ------------------------------- + --- + -- + if (utils.confirm(' Permanent lock UID ? (card can never change uid again) ') == true) then + wait() + core.console(piswords_uid_lock) + end + -- + print(tab) + print(' Going to check the all ' .. KeyAB() .. ' by ' .. default_key) + print(tab) + -- + if checkkey() == true then + print(tab) + if (utils.confirm(' Card is Empty. Write selected dump to card ?') == true) then + for i = 1, #eml do + core.console(string.format(cmd_wrbl_b, (i-1), default_key, eml[i])) + end + end + else + print(tab) + if (utils.confirm(' It this is a new blank card ? Do you wishing to change Access Conditions to using B key ' .. default_key .. ' as main ?') == true) then + print(tab) + print(' With one key type we will use, A or B ?') + print(tab) + io.write(' --> ') + local user_key_type = tostring(io.read()) + print(tab) + print(' Enter 12 HEX chars of the key for access to card. By default ' .. default_key .. '.') + print(tab) + io.write(' --> ') + local user_key_input = tostring(io.read()) + wait() + for i = 1, #eml do + if (i % 4 == 0) then + core.console(string.format(check_user_key(user_key_type), (i-1), user_key_input, default_key_blk)) + else + core.console(string.format(check_user_key(user_key_type), (i-1), user_key_input, empty)) + end + end + else + print(tab) + if (utils.confirm(' Write selected dump to card ?') == true) then + print(tab) + wait() + for i = 1, #eml do + core.console(string.format(cmd_wrbl_b, (i-1), b_keys[i], eml[i])) + end + else + print(tab) + if (utils.confirm(' Delete ALL data and write all keys to 0x' .. default_key .. ' ?') == true) then + wait() + for i = 1, #eml do + if (i % 4 == 0) then + core.console(string.format(cmd_wrbl_b, (i-1), b_keys[i], default_key_blk)) + else + core.console(string.format(cmd_wrbl_b, (i-1), b_keys[i], empty)) + end + end + end + end + end + end + dropfield() + print(tab) + print('You are welcome') +end +-- +--- +------------------------------- +-- Start Main function +------------------------------- +--- +-- +main(args) diff --git a/client/luascripts/test_t55x7.lua b/client/luascripts/test_t55x7.lua index 4be0ed4b6..3c4b83441 100644 --- a/client/luascripts/test_t55x7.lua +++ b/client/luascripts/test_t55x7.lua @@ -9,7 +9,7 @@ local floor = math.floor copyright = '' author = "Iceman" -version = 'v1.0.3' +version = 'v1.0.4' desc =[[ This script will program a T55x7 TAG with a configuration and four blocks of data. It will then try to detect and read back those block data and compare if read data matches the expected data. @@ -106,36 +106,93 @@ local function GetConfigs( modulation ) local t = {} t['PSK1'] = { - [1] = '00001040', - [2] = '00041040', - [3] = '00081040', - [4] = '000c1040', - [5] = '00101040', - [6] = '00141040', - [7] = '00181040', - [8] = '001c1040', + -- Rf2 + [1] = '00001040', -- 8 + [2] = '00041040', -- 16 + [3] = '00081040', -- 32 + [4] = '000c1040', -- 40 + [5] = '00101040', -- 50 + [6] = '00141040', -- 64 + [7] = '00181040', -- 100 + [8] = '001c1040', -- 128 + -- Rf4 + [9] = '00001440', -- 8 + [10] = '00041440', -- 16 + [11] = '00081440', -- 32 + [12] = '000c1440', -- 40 +-- [] = '00101440', -- 50 50/4 == 12.5 invalid + [13] = '00141440', -- 64 + [14] = '00181440', -- 100 + [15] = '001c1440', -- 128 + -- Rf8 + [16] = '00001840', -- 8 + [17] = '00041840', -- 16 + [18] = '00081840', -- 32 + [19] = '000c1840', -- 40 +-- [] = '00101840', -- 50 50/8 = 6.25 invalid + [20] = '00141840', -- 64 +-- [] = '00181840', -- 100 100/8 == 12.5 invalid + [21] = '001c1840', -- 128 } t['PSK2'] = { - [1] = '00002040', - [2] = '00042040', - [3] = '00082040', - [4] = '000c2040', - [5] = '00102040', - [6] = '00142040', - [7] = '00182040', - [8] = '001c2040', + -- Rf2 + [1] = '00002040', -- 8 + [2] = '00042040', -- 16 + [3] = '00082040', -- 32 + [4] = '000c2040', -- 40 + [5] = '00102040', -- 50 + [6] = '00142040', -- 64 + [7] = '00182040', -- 100 + [8] = '001c2040', -- 128 + -- Rf4 + [9] = '00002440', -- 8 + [10] = '00042440', -- 16 + [11] = '00082440', -- 32 + [12] = '000c2440', -- 40 +-- [] = '00102440', -- 50 50/4 == 12.5 invalid + [13] = '00142440', -- 64 + [14] = '00182440', -- 100 + [15] = '001c2440', -- 128 + -- Rf8 + [16] = '00002840', -- 8 + [17] = '00042840', -- 16 + [18] = '00082840', -- 32 + [19] = '000c2840', -- 40 +-- [] = '00102840', -- 50 50/8 == 6.25 invalid + [20] = '00142840', -- 64 +-- [] = '00182840', -- 100 100/8 == 12.5 invalid + [21] = '001c2840', -- 128 } t['PSK3'] = { - [1] = '00003040', - [2] = '00043040', - [3] = '00083040', - [4] = '000c3040', - [5] = '00103040', - [6] = '00143040', - [7] = '00183040', - [8] = '001c3040', + -- Rf2 + [1] = '00003040', -- 8 + [2] = '00043040', -- 16 + [3] = '00083040', -- 32 + [4] = '000c3040', -- 40 + [5] = '00103040', -- 50 + [6] = '00143040', -- 64 + [7] = '00183040', -- 100 + [8] = '001c3040', -- 128 + -- Rf4 + [9] = '00003440', -- 8 + [10] = '00043440', -- 16 + [11] = '00083440', -- 32 + [12] = '000c3440', -- 40 +-- [] = '00103440', -- 50 50/4 == 12.5 invalid + [13] = '00143440', -- 64 + [14] = '00183440', -- 100 + [15] = '001c3440', -- 128 + -- Rf2 + [16] = '00003840', -- 8 + [17] = '00043840', -- 16 + [18] = '00083840', -- 32 + [19] = '000c3840', -- 40 +-- [] = '00103840', -- 50 50/8 == 6.25 invalid + [20] = '00143840', -- 64 +-- [] = '00183840', -- 100 100/8 == 12.5 invalid + [21] = '001c3840', -- 128 } t['FSK1'] = { diff --git a/client/src/cmdanalyse.c b/client/src/cmdanalyse.c index c4fe2d795..ecf8e50de 100644 --- a/client/src/cmdanalyse.c +++ b/client/src/cmdanalyse.c @@ -12,7 +12,7 @@ #include // size_t #include #include // tolower -#include // printf +//#include // printf #include "commonutil.h" // reflect... #include "comms.h" // clearCommandBuffer #include "cmdparser.h" // command_t @@ -914,16 +914,33 @@ static int CmdAnalyseDemodBuffer(const char *Cmd) { if (c == '0') DemodBuffer[i] = 0; - printf("%c", c); + PrintAndLogEx(NORMAL, "%c" NOLF, c); } - printf("\n"); + PrintAndLogEx(NORMAL, ""); DemodBufferLen = len; free(data); return PM3_SUCCESS; } +static int CmdAnalyseFreq(const char *Cmd) { + +// char cmdp = tolower(param_getchar(Cmd, 0)); +// if (strlen(Cmd) == 0 || cmdp == 'h') return usage_analyse_freq(); + + const double c = 299792458; + double len_125 = c / 125000; + double len_134 = c / 134000; + double len_1356 = c / 13560000; + + PrintAndLogEx(INFO, "Wavelengths"); + PrintAndLogEx(INFO, " 125 kHz has %f meters", len_125); + PrintAndLogEx(INFO, " 134 kHz has %f meters", len_134); + PrintAndLogEx(INFO, " 13.56 mHz has %f meters", len_1356); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"lcr", CmdAnalyseLCR, AlwaysAvailable, "Generate final byte for XOR LRC"}, @@ -935,6 +952,7 @@ static command_t CommandTable[] = { {"a", CmdAnalyseA, AlwaysAvailable, "num bits test"}, {"nuid", CmdAnalyseNuid, AlwaysAvailable, "create NUID from 7byte UID"}, {"demodbuff", CmdAnalyseDemodBuffer, AlwaysAvailable, "Load binary string to demodbuffer"}, + {"freq", CmdAnalyseFreq, AlwaysAvailable, "Calc wave lengths"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 75179ce5e..d85733370 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -2104,11 +2104,10 @@ static int Cmdhex2bin(const char *Cmd) { else continue; - //Uses printf instead of PrintAndLog since the latter adds linebreaks to each printout for (int i = 0 ; i < 4 ; ++i) - printf("%d", (x >> (3 - i)) & 1); + PrintAndLogEx(NORMAL, "%d" NOLF, (x >> (3 - i)) & 1); } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 5fea3c61e..dd3bf4b51 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -84,7 +84,7 @@ static int usage_hf_tune(void) { return PM3_SUCCESS; } -#define PROMPT_CLEARLINE PrintAndLogEx(INPLACE, " ") +#define PROMPT_CLEARLINE PrintAndLogEx(INPLACE, " \r") int CmdHFSearch(const char *Cmd) { @@ -166,16 +166,16 @@ int CmdHFSearch(const char *Cmd) { } } -/* - PROMPT_CLEARLINE; - PrintAndLogEx(INPLACE, " Searching for FeliCa tag..."); - if (IfPm3Felica()) { - if (readFelicaUid(false) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") " found\n"); - res = PM3_SUCCESS; + /* + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, " Searching for FeliCa tag..."); + if (IfPm3Felica()) { + if (readFelicaUid(false) == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") " found\n"); + res = PM3_SUCCESS; + } } - } -*/ + */ /* PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, " Searching for CryptoRF tag..."); @@ -190,10 +190,10 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; if (res != PM3_SUCCESS) { - PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found")); + PrintAndLogEx(WARNING, _RED_("No known/supported 13.56 MHz tags found")); res = PM3_ESOFT; } - printf("\n"); + return res; } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 6ce4d077e..4a53ef021 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -168,6 +168,24 @@ const char *getTagInfo(uint8_t uid) { static uint16_t frameLength = 0; uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; +static int usage_hf_14a_config(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14a config [a 0|1|2] [b 0|1|2] [2 0|1|2] [3 0|1|2]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " a 0|1|2 ATQA<>anticollision: 0=follow standard 1=execute anticol 2=skip anticol"); + PrintAndLogEx(NORMAL, " b 0|1|2 BCC: 0=follow standard 1=use fixed BCC 2=use card BCC"); + PrintAndLogEx(NORMAL, " 2 0|1|2 SAK<>CL2: 0=follow standard 1=execute CL2 2=skip CL2"); + PrintAndLogEx(NORMAL, " 3 0|1|2 SAK<>CL3: 0=follow standard 1=execute CL3 2=skip CL3"); + PrintAndLogEx(NORMAL, " r 0|1|2 SAK<>ATS: 0=follow standard 1=execute RATS 2=skip RATS"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config ")" Print current configuration"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 ")" Force execution of anticollision"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 ")" Restore ATQA interpretation"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 1 ")" Force fix of bad BCC in anticollision"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 0 ")" Restore BCC check"); + return PM3_SUCCESS; +} + static int usage_hf_14a_sim(void) { // PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"); PrintAndLogEx(NORMAL, "\n Emulating ISO/IEC 14443 type A tag with 4,7 byte UID\n"); @@ -234,6 +252,162 @@ static int CmdHF14AList(const char *Cmd) { return 0; } +int hf14a_getconfig(hf14a_config *config) { + if (!session.pm3_present) return PM3_ENOTTY; + + if (config == NULL) + return PM3_EINVARG; + + clearCommandBuffer(); + + SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000)) { + PrintAndLogEx(WARNING, "command execution time out"); + return PM3_ETIMEOUT; + } + memcpy(config, resp.data.asBytes, sizeof(hf14a_config)); + return PM3_SUCCESS; +} + +int hf14a_setconfig(hf14a_config *config) { + if (!session.pm3_present) return PM3_ENOTTY; + + clearCommandBuffer(); + if (config != NULL) + SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)config, sizeof(hf14a_config)); + else + SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG, NULL, 0); + + return PM3_SUCCESS; +} + +static int CmdHf14AConfig(const char *Cmd) { + + if (!session.pm3_present) return PM3_ENOTTY; + + // if called with no params, just print the device config + if (strlen(Cmd) == 0) { + return hf14a_setconfig(NULL); + } + + hf14a_config config = { + .forceanticol = -1, + .forcebcc = -1, + .forcecl2 = -1, + .forcecl3 = -1, + .forcerats = -1 + }; + + bool errors = false; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (param_getchar(Cmd, cmdp)) { + case 'h': + return usage_hf_14a_config(); + case 'a': + switch (param_getchar(Cmd, cmdp + 1)) { + case '0': + config.forceanticol = 0; + break; + case '1': + config.forceanticol = 1; + break; + case '2': + config.forceanticol = 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); + errors = 1; + break; + } + cmdp += 2; + break; + case 'b': + switch (param_getchar(Cmd, cmdp + 1)) { + case '0': + config.forcebcc = 0; + break; + case '1': + config.forcebcc = 1; + break; + case '2': + config.forcebcc = 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); + errors = 1; + break; + } + cmdp += 2; + break; + case '2': + switch (param_getchar(Cmd, cmdp + 1)) { + case '0': + config.forcecl2 = 0; + break; + case '1': + config.forcecl2 = 1; + break; + case '2': + config.forcecl2 = 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); + errors = 1; + break; + } + cmdp += 2; + break; + case '3': + switch (param_getchar(Cmd, cmdp + 1)) { + case '0': + config.forcecl3 = 0; + break; + case '1': + config.forcecl3 = 1; + break; + case '2': + config.forcecl3 = 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); + errors = 1; + break; + } + cmdp += 2; + break; + case 'r': + switch (param_getchar(Cmd, cmdp + 1)) { + case '0': + config.forcerats = 0; + break; + case '1': + config.forcerats = 1; + break; + case '2': + config.forcerats = 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown value '%c'", param_getchar(Cmd, cmdp + 1)); + errors = 1; + break; + } + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = 1; + break; + } + } + + // validations + if (errors) return usage_hf_14a_config(); + + return hf14a_setconfig(&config); +} + int Hf14443_4aGetCardData(iso14a_card_select_t *card) { SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); @@ -1241,6 +1415,7 @@ static command_t CommandTable[] = { {"chaining", CmdHF14AChaining, IfPm3Iso14443a, "Control ISO 14443-4 input chaining"}, {"raw", CmdHF14ACmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, {"antifuzz", CmdHF14AAntiFuzz, IfPm3Iso14443a, "Fuzzing the anticollision phase. Warning! Readers may react strange"}, + {"config", CmdHf14AConfig, IfPm3Iso14443a, "Configure 14a settings (use with caution)"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index 83fb2c69d..925bf8bef 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -13,7 +13,7 @@ #define CMDHF14A_H__ #include "common.h" - +#include "pm3_cmd.h" //hf14a_config #include "mifare.h" // structs // structure and database for uid -> tagtype lookups @@ -26,6 +26,8 @@ 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 hf14a_getconfig(hf14a_config *config); +int hf14a_setconfig(hf14a_config *config); 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); diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 315ef6cd4..b0ce49f50 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -114,7 +114,7 @@ static int usage_hf_14b_dump(void) { "Example:\n" _YELLOW_("\thf 14b dump f\n") _YELLOW_("\thf 14b dump 2 f mydump") - ); + ); return 0; } @@ -752,7 +752,7 @@ static int CmdHF14BReadSri(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_SRI_READ, blocks, 0, 0, NULL, 0); - + // iceman: should download read data and print in client. return PM3_SUCCESS; } @@ -909,7 +909,7 @@ static int CmdHF14BDump(const char *Cmd) { req[1] = blocknum; clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); + SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APPEND_CRC | ISO14B_RAW, 2, 0, req, sizeof(req)); if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) { @@ -940,17 +940,16 @@ static int CmdHF14BDump(const char *Cmd) { blocknum = 0xFF; } - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); } } + PrintAndLogEx(NORMAL, ""); if (blocknum != 0xFF) { - PrintAndLogEx(NORMAL, "\n Dump failed"); + PrintAndLogEx(NORMAL, "Dump failed"); goto out; } - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "block# | data | ascii"); PrintAndLogEx(NORMAL, "---------+--------------+----------"); diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 49ed24c43..1cba1e6a0 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -420,7 +420,7 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { 0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2 } }; - */ + */ uint8_t i; bool is_valid = false; for (i = 0; i < ARRAYLEN(nxp_15693_public_keys); i++) { @@ -526,7 +526,7 @@ static bool getUID(bool loop, uint8_t *buf) { int resplen = resp.oldarg[0]; if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) { - + if (buf) memcpy(buf, resp.data.asBytes + 2, 8); @@ -990,7 +990,7 @@ static int CmdHF15Sniff(const char *Cmd) { SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0); WaitForResponse(CMD_HF_ISO15693_SNIFF, &resp); - + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save h") "` to save tracelog for later analysing"); return PM3_SUCCESS; @@ -1024,7 +1024,7 @@ static int CmdHF15Sim(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO15693_SIMULATE, (uint8_t*)&payload, sizeof(payload)); + SendCommandNG(CMD_HF_ISO15693_SIMULATE, (uint8_t *)&payload, sizeof(payload)); WaitForResponse(CMD_HF_ISO15693_SIMULATE, &resp); return PM3_SUCCESS; } @@ -1266,8 +1266,7 @@ static int CmdHF15Dump(const char *Cmd) { retry = 0; blocknum++; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); } } @@ -1359,7 +1358,7 @@ static int CmdHF15Raw(const char *Cmd) { } PacketResponseNG resp; - clearCommandBuffer(); + clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO15693_COMMAND, datalen, fast, reply, data, datalen); if (reply) { @@ -1443,7 +1442,7 @@ static int CmdHF15Readmulti(const char *Cmd) { } uint8_t *data = resp.data.asBytes; - + if (CheckCrc15(data, status) == false) { PrintAndLogEx(FAILED, "crc (" _RED_("fail") ")"); return PM3_ESOFT; @@ -1742,7 +1741,7 @@ static int CmdHF15Restore(const char *Cmd) { } free(data); PrintAndLogEx(INFO, "done"); - PrintAndLogEx(HINT, "try `" _YELLOW_("hf 15 dump") "` to read your card to verify" ); + PrintAndLogEx(HINT, "try `" _YELLOW_("hf 15 dump") "` to read your card to verify"); return PM3_SUCCESS; } @@ -1780,10 +1779,10 @@ static int CmdHF15CSetUID(const char *Cmd) { } PrintAndLogEx(INFO, "updating tag uid..."); - + PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t*)&payload, sizeof(payload)); + SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload)); if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); @@ -1800,10 +1799,10 @@ static int CmdHF15CSetUID(const char *Cmd) { uint8_t revuid[8] = {0}; uint8_t i = 0; while (i < sizeof(revuid)) { - revuid[i] = carduid[7-i]; + revuid[i] = carduid[7 - i]; i++; } - + if (memcmp(revuid, payload.uid, 8) != 0) { PrintAndLogEx(FAILED, "setting new UID (" _RED_("failed") ")"); return PM3_ESOFT; diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index cd3bc93a4..98eada2ba 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -59,7 +59,7 @@ static int usage_hf_cryptorf_sniff(void) { } static int usage_hf_cryptorf_sim(void) { PrintAndLogEx(NORMAL, "Emulating CryptoRF tag with emulator memory\n" - "Usage: hf cryptorf sim [h] \n" + "Usage: hf cryptorf sim [h] \n" "Options:\n" " h this help\n" "\n" diff --git a/client/src/cmdhfepa.c b/client/src/cmdhfepa.c index eb4efc9f1..83f347604 100644 --- a/client/src/cmdhfepa.c +++ b/client/src/cmdhfepa.c @@ -26,16 +26,16 @@ static int CmdHelp(const char *Cmd); static int usage_epa_collect(void) { PrintAndLogEx(NORMAL, "Tries to collect nonces when doing part of PACE protocol.\n" - "\n" - "Usage: hf epa cnonces \n" - "Options:\n" - "\t nonce size\n" - "\t number of nonces to collect\n" - "\t delay between\n" - "\n" - "Example:\n" - _YELLOW_("\thf epa cnonces 4 4 1") - ); + "\n" + "Usage: hf epa cnonces \n" + "Options:\n" + "\t nonce size\n" + "\t number of nonces to collect\n" + "\t delay between\n" + "\n" + "Example:\n" + _YELLOW_("\thf epa cnonces 4 4 1") + ); return PM3_SUCCESS; } @@ -60,18 +60,18 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m); PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000); - + struct p { uint32_t m; } PACKED payload; payload.m = m; - + for (uint32_t i = 0; i < n; i++) { // execute PACE PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_EPA_COLLECT_NONCE, (uint8_t*)&payload, sizeof(payload)); + SendCommandNG(CMD_HF_EPA_COLLECT_NONCE, (uint8_t *)&payload, sizeof(payload)); WaitForResponse(CMD_HF_EPA_COLLECT_NONCE, &resp); @@ -92,7 +92,7 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { sleep(d); } } - + PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000); return PM3_SUCCESS; } diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c index f62a9a8ff..9e48f1577 100644 --- a/client/src/cmdhffelica.c +++ b/client/src/cmdhffelica.c @@ -1630,27 +1630,30 @@ static int CmdHFFelicaDumpLite(const char *Cmd) { uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { timeout++; - printf("."); + PrintAndLogEx(NORMAL, "." NOLF); fflush(stdout); if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "aborted via keyboard!\n"); + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); DropField(); return PM3_EOPABORTED; } - if (timeout > 100) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + if (timeout > 10) { + PrintAndLogEx(WARNING, "\ntimeout while waiting for reply."); DropField(); return PM3_ETIMEOUT; } } + + PrintAndLogEx(NORMAL, ""); + if (resp.oldarg[0] == 0) { - PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); + PrintAndLogEx(WARNING, "Button pressed, aborted"); return PM3_EOPABORTED; } uint32_t tracelen = resp.oldarg[1]; if (tracelen == 0) { - PrintAndLogEx(WARNING, "\nNo trace data! Maybe not a FeliCa Lite card?"); + PrintAndLogEx(WARNING, "No trace data! Maybe not a FeliCa Lite card?"); return PM3_ESOFT; } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 4527d2dd5..28b74f422 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -97,6 +97,18 @@ static int usage_hf_iclass_esave(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int usage_hf_iclass_eview(void) { + PrintAndLogEx(NORMAL, "It displays emulator memory"); + PrintAndLogEx(NORMAL, "Number of bytes to download defaults to 256. Other value is 2048\n"); + PrintAndLogEx(NORMAL, " Usage: hf iclass eview [s ] "); + PrintAndLogEx(NORMAL, " s : (256|2048) number of bytes to save (default 256)"); + PrintAndLogEx(NORMAL, " v : verbose output"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf iclass eview")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf iclass eview s 2048 v")); + return PM3_SUCCESS; +} static int usage_hf_iclass_decrypt(void) { PrintAndLogEx(NORMAL, "3DES decrypt data\n"); PrintAndLogEx(NORMAL, "This is naive implementation, it tries to decrypt every block after block 6."); @@ -376,7 +388,7 @@ static int cmp_uint32(const void *a, const void *b) { return mx > my; } -bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key) { +bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key) { iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX, sizeof(iclass_prekey_t)); if (prekey == false) { @@ -387,14 +399,14 @@ bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* memcpy(ccnr, epurse, 8); memcpy(ccnr + 8, rmac, 4); - GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t*)iClass_Key_Table, ICLASS_KEYS_MAX, prekey); + GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t *)iClass_Key_Table, ICLASS_KEYS_MAX, prekey); qsort(prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); iclass_prekey_t lookup; memcpy(lookup.mac, tmac, 4); // binsearch - iclass_prekey_t * item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); + iclass_prekey_t *item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); if (item != NULL) { memcpy(key, item->key, 8); return true; @@ -962,11 +974,10 @@ static int CmdHFiClassReader_Replay(const char *Cmd) { SendCommandNG(CMD_HF_ICLASS_REPLAY, (uint8_t *)&payload, sizeof(payload)); while (true) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); + if (kbd_enter_pressed()) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "aborted via keyboard!\n"); + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); DropField(); return PM3_EOPABORTED; } @@ -975,6 +986,7 @@ static int CmdHFiClassReader_Replay(const char *Cmd) { break; } + PrintAndLogEx(NORMAL, ""); if (resp.status != PM3_SUCCESS) { PrintAndLogEx(ERR, "failed to communicate with card"); return resp.status; @@ -1175,7 +1187,7 @@ static int CmdHFiClassESave(const char *Cmd) { } uint8_t *dump = calloc(bytes, sizeof(uint8_t)); - if (!dump) { + if (dump == NULL) { PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return PM3_EMALLOC; } @@ -1189,7 +1201,7 @@ static int CmdHFiClassESave(const char *Cmd) { // user supplied filename? if (len < 1) { - fnameptr += sprintf(fnameptr, "hf-iclass-"); + fnameptr += snprintf(fnameptr, sizeof(filename), "hf-iclass-"); FillFileNameByUID(fnameptr, dump, "-dump", 8); } @@ -1202,6 +1214,88 @@ static int CmdHFiClassESave(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFiClassEView(const char *Cmd) { + + uint16_t blocks = 32, bytes = 256; + bool errors = false, verbose = false; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_iclass_eview(); + case 's': + bytes = param_get32ex(Cmd, cmdp + 1, 256, 10); + + if (bytes > 4096) { + PrintAndLogEx(WARNING, "Emulator memory is max 4096bytes. Truncating %u to 4096", bytes); + bytes = 4096; + } + + if (bytes % 8 != 0) { + bytes &= 0xFFF8; + PrintAndLogEx(WARNING, "Number not divided by 8, truncating to %u", bytes); + } + + blocks = bytes / 8; + cmdp += 2; + break; + case 'v': + verbose = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors || bytes == 0) { + return usage_hf_iclass_eview(); + } + + uint8_t *dump = calloc(bytes, sizeof(uint8_t)); + if (dump == NULL) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + memset(dump, 0, bytes); + + PrintAndLogEx(INFO, "downloading from emulator memory"); + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(dump); + return PM3_ETIMEOUT; + } + + if (verbose) { + print_picopass_header((picopass_hdr *) dump); + print_picopass_info((picopass_hdr *) dump); + } + + PrintAndLogEx(NORMAL, ""); + uint8_t *csn = dump; + PrintAndLogEx(INFO, "------+----+-------------------------+----------"); + PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8)); + printIclassDumpContents(dump, 1, blocks, bytes); + + /* + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----+-------------------------+---------"); + PrintAndLogEx(INFO, "blk | data | ascii"); + PrintAndLogEx(INFO, "----+-------------------------+---------"); + for (uint16_t i = 0; i < blocks; i++){ + PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 8) , 8) ); + } + PrintAndLogEx(INFO, "----+-------------------------+---------"); + PrintAndLogEx(NORMAL, ""); + */ + free(dump); + return PM3_SUCCESS; +} + + static int CmdHFiClassDecrypt(const char *Cmd) { bool errors = false; @@ -1408,7 +1502,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) { uint64_t pin = bytes_to_num(decrypted + (8 * 9), 5); char tmp[17] = {0}; - sprintf(tmp, "%."PRIu64, BCD2DEC(pin)); + snprintf(tmp, sizeof(tmp), "%."PRIu64, BCD2DEC(pin)); PrintAndLogEx(INFO, "PIN........................ " _GREEN_("%.*s"), pinsize, tmp); } } @@ -1756,11 +1850,10 @@ static int CmdHFiClassDump(const char *Cmd) { SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t *)&payload, sizeof(payload)); while (true) { - printf("."); - fflush(stdout); + + PrintAndLogEx(NORMAL, "." NOLF); if (kbd_enter_pressed()) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "aborted via keyboard!\n"); + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); DropField(); return PM3_EOPABORTED; } @@ -1769,6 +1862,7 @@ static int CmdHFiClassDump(const char *Cmd) { break; } + PrintAndLogEx(NORMAL, ""); if (resp.status != PM3_SUCCESS) { PrintAndLogEx(ERR, "failed to communicate with card"); return resp.status; @@ -1828,11 +1922,9 @@ static int CmdHFiClassDump(const char *Cmd) { SendCommandNG(CMD_HF_ICLASS_DUMP, (uint8_t *)&payload, sizeof(payload)); while (true) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (kbd_enter_pressed()) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "aborted via keyboard!\n"); + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); DropField(); return PM3_EOPABORTED; } @@ -1840,7 +1932,7 @@ static int CmdHFiClassDump(const char *Cmd) { if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) break; } - + PrintAndLogEx(NORMAL, ""); if (resp.status != PM3_SUCCESS) { PrintAndLogEx(ERR, "failed to communicate with card"); goto write_dump; @@ -2155,7 +2247,7 @@ static int CmdHFiClassRestore(const char *Cmd) { if (startblock < 5) { PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); - return PM3_EINVARG; + return PM3_EINVARG; } int total_bytes = (((endblock - startblock) + 1) * 12); @@ -2233,8 +2325,8 @@ static int CmdHFiClassRestore(const char *Cmd) { for (i = 0; i <= endblock - startblock; i++) { memcpy(p, data + (i * 12), 12); char *s = calloc(70, sizeof(uint8_t)); - sprintf(s, "| %s ", sprint_hex(p, 8)); - sprintf(s + strlen(s), "| %s", sprint_hex(p + 8, 4)); + snprintf(s, 70, "| %s ", sprint_hex(p, 8)); + snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4)); PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s); free(s); } @@ -3088,11 +3180,9 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { bool looped = false; while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) { timeout++; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 120) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "No response from Proxmark3. Aborting..."); + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); goto out; } looped = true; @@ -3484,6 +3574,7 @@ static command_t CommandTable[] = { {"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load Picopass / iCLASS dump file into emulator memory"}, {"esave", CmdHFiClassESave, IfPm3Iclass, "[f ] Save emulator memory to file"}, + {"eview", CmdHFiClassEView, IfPm3Iclass, "[options..] View emulator memory"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"}, {"calcnewkey", CmdHFiClassCalcNewKey, AlwaysAvailable, "[options..] Calc diversified keys (blocks 3 & 4) to write new keys"}, diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index afc612c33..d060d1275 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -41,5 +41,5 @@ void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list); void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt); uint8_t get_pagemap(const picopass_hdr *hdr); -bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key); +bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key); #endif diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index a91c1a418..5d9147896 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -145,7 +145,7 @@ static int usage_legic_eload(void) { PrintAndLogEx(NORMAL, " f : filename w/o .bin to load"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf legic eload 2 myfile")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf legic eload 2 f myfile")); return PM3_SUCCESS; } static int usage_legic_esave(void) { @@ -582,13 +582,39 @@ static int CmdLegicRdbl(const char *Cmd) { } static int CmdLegicSim(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); if (strlen(Cmd) == 0 || cmdp == 'h') return usage_legic_sim(); - uint64_t id = 1; - sscanf(Cmd, " %" SCNi64, &id); + struct { + uint8_t tagtype; + bool send_reply; + } PACKED payload; + + payload.send_reply = true; + payload.tagtype = param_get8ex(Cmd, 0, 1, 10); + if (payload.tagtype > 2) { + return usage_legic_sim(); + } + clearCommandBuffer(); - SendCommandMIX(CMD_HF_LEGIC_SIMULATE, id, 0, 0, NULL, 0); + SendCommandNG(CMD_HF_LEGIC_SIMULATE, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + + PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); + bool keypress = kbd_enter_pressed(); + while (keypress == false) { + keypress = kbd_enter_pressed(); + + if (WaitForResponseTimeout(CMD_HF_LEGIC_SIMULATE, &resp, 1500)) { + break; + } + + } + if (keypress) + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + + PrintAndLogEx(INFO, "Done"); return PM3_SUCCESS; } @@ -709,16 +735,17 @@ static int CmdLegicWrbl(const char *Cmd) { char *answer = readline(confirm); overwrite = (answer[0] == 'y' || answer[0] == 'Y'); #else - printf("%s", confirm); + PrintAndLogEx(NORMAL, "%s" NOLF, confirm); char *answer = NULL; size_t anslen = 0; if (getline(&answer, &anslen, stdin) > 0) { overwrite = (answer[0] == 'y' || answer[0] == 'Y'); } + PrintAndLogEx(NORMAL, ""); #endif free(answer); - if (!overwrite) { - PrintAndLogEx(NORMAL, "command cancelled"); + if (overwrite == false) { + PrintAndLogEx(WARNING, "command cancelled"); return PM3_EOPABORTED; } } @@ -731,18 +758,16 @@ static int CmdLegicWrbl(const char *Cmd) { clearCommandBuffer(); SendCommandOLD(CMD_HF_LEGIC_WRITER, offset, len, IV, data, len); - uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { ++timeout; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 7) { PrintAndLogEx(WARNING, "\ncommand execution time out"); return PM3_ETIMEOUT; } } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); uint8_t isOK = resp.oldarg[0] & 0xFF; if (!isOK) { @@ -846,8 +871,7 @@ int legic_read_mem(uint32_t offset, uint32_t len, uint32_t iv, uint8_t *out, uin uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { ++timeout; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 14) { PrintAndLogEx(WARNING, "\ncommand execution time out"); return PM3_ETIMEOUT; @@ -990,14 +1014,13 @@ static int CmdLegicDump(const char *Cmd) { uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { ++timeout; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 7) { PrintAndLogEx(WARNING, "\ncommand execution time out"); return PM3_ETIMEOUT; } } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); uint8_t isOK = resp.oldarg[0] & 0xFF; if (!isOK) { @@ -1025,7 +1048,7 @@ static int CmdLegicDump(const char *Cmd) { // user supplied filename? if (fileNameLen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "hf-legic-"); + fptr += snprintf(fptr, sizeof(filename), "hf-legic-"); FillFileNameByUID(fptr, data, "-dump", 4); } @@ -1134,15 +1157,14 @@ static int CmdLegicRestore(const char *Cmd) { uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { ++timeout; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 7) { PrintAndLogEx(WARNING, "\ncommand execution time out"); free(data); return PM3_ETIMEOUT; } } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); uint8_t isOK = resp.oldarg[0] & 0xFF; if (!isOK) { @@ -1300,7 +1322,7 @@ static int CmdLegicESave(const char *Cmd) { // user supplied filename? if (fileNameLen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); - fptr += sprintf(fptr, "hf-legic-"); + fptr += snprintf(fptr, sizeof(filename), "hf-legic-"); FillFileNameByUID(fptr, data, "-dump", 4); } @@ -1344,8 +1366,8 @@ static int CmdLegicWipe(const char *Cmd) { PacketResponseNG resp; for (size_t i = 7; i < card.cardsize; i += PM3_CMD_DATA_SIZE) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); + size_t len = MIN((card.cardsize - i), PM3_CMD_DATA_SIZE); if (len == card.cardsize - i) { // Disable fast mode on last packet @@ -1357,15 +1379,14 @@ static int CmdLegicWipe(const char *Cmd) { uint8_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { ++timeout; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 7) { PrintAndLogEx(WARNING, "\ncommand execution time out"); free(data); return PM3_ETIMEOUT; } } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); uint8_t isOK = resp.oldarg[0] & 0xFF; if (!isOK) { diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 0e2b40a50..d898e9ab9 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -215,6 +215,9 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { case ISO14443A_CMD_RATS: snprintf(exp, size, "RATS"); break; + case ISO14443A_CMD_PPS: + snprintf(exp, size, "PPS"); + break; case ISO14443A_CMD_OPTS: snprintf(exp, size, "OPTIONAL TIMESLOT"); break; @@ -336,7 +339,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool static uint8_t rmac[4]; static uint8_t tmac[4]; - if ( isResponse == false ) { + if (isResponse == false) { uint8_t c = cmd[0] & 0x0F; uint8_t parity = 0; for (uint8_t i = 0; i < 7; i++) { @@ -406,17 +409,17 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool } } else { - + if (curr_state == PICO_SELECT) { memcpy(csn, cmd, 8); curr_state = PICO_NONE; } else if (curr_state == PICO_AUTH_EPURSE) { memcpy(epurse, cmd, 8); - } else if ( curr_state == PICO_AUTH_MACS) { + } else if (curr_state == PICO_AUTH_MACS) { uint8_t key[8]; if (check_known_default(csn, epurse, rmac, tmac, key)) { - snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8) ); + snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8)); } curr_state = PICO_NONE; } @@ -435,11 +438,11 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { snprintf(exp, size, "STAY_QUIET"); return; case ISO15693_READBLOCK: { - + uint8_t block = 0; if (cmdsize == 13) block = cmd[10]; - + snprintf(exp, size, "READBLOCK(%d)", block); return; } @@ -557,7 +560,7 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { if (cmd[1] > ISO15693_STAYQUIET && cmd[1] < ISO15693_READBLOCK) snprintf(exp, size, "Mandatory RFU"); else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); - // else if (cmd[1] >= 0xA0 && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); + // else if (cmd[1] >= 0xA0 && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); else if (cmd[1] > ISO15693_READ_SIGNATURE && cmd[1] <= 0xDF) snprintf(exp, size, "Cust IC MFG dependent"); else if (cmd[1] >= 0xE0) snprintf(exp, size, "Proprietary IC MFG dependent"); else @@ -608,6 +611,10 @@ void annotateTopaz(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { // iso 7816-3 void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { + + if (cmdsize < 2) + return; + // S-block if ((cmd[0] & 0xC0) && (cmdsize == 3)) { switch ((cmd[0] & 0x3f)) { @@ -715,7 +722,7 @@ void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { snprintf(exp, size, "GET RESPONSE"); break; default: - snprintf(exp, size, "?"); + //snprintf(exp, size, "?"); break; } } @@ -992,13 +999,13 @@ void annotateCryptoRF(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { break; case CRYPTORF_DESELECT: snprintf(exp, size, "DESELECT"); - break; + break; case CRYPTORF_IDLE: snprintf(exp, size, "IDLE"); - break; + break; case CRYPTORF_CHECK_PASSWORD: snprintf(exp, size, "CHECK PWD"); - break; + break; default: snprintf(exp, size, "?"); break; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 011b30033..c42387063 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -9,7 +9,6 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" - #include #include "cmdparser.h" // command_t @@ -55,7 +54,7 @@ static int usage_hf14_ice(void) { static int usage_hf14_dump(void) { PrintAndLogEx(NORMAL, "Usage: hf mf dump [card memory] [k ] [f ]"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLogEx(NORMAL, " k : key filename, if no given, UID will be used as filename"); PrintAndLogEx(NORMAL, " f : data filename, if no given, UID will be used as filename"); PrintAndLogEx(NORMAL, ""); @@ -192,8 +191,9 @@ static int usage_hf14_autopwn(void) { PrintAndLogEx(NORMAL, " [* ] [f [.dic]] [s] [i ] [l] [v]"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Description:"); - PrintAndLogEx(NORMAL, " This command automates the key recovery process on Mifare classic cards."); - PrintAndLogEx(NORMAL, " It uses the darkside, nested and hardnested attack to extract the keys and card content."); + PrintAndLogEx(NORMAL, " This command automates the key recovery process on MIFARE Classic cards."); + PrintAndLogEx(NORMAL, " It uses the darkside, nested, hardnested and staticnested to recover keys."); + PrintAndLogEx(NORMAL, " If all keys are found, try dumping card content."); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); @@ -220,9 +220,9 @@ static int usage_hf14_autopwn(void) { PrintAndLogEx(NORMAL, " i n = none (use CPU regular instruction set)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn")" -- target Mifare classic card with default keys"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn * 1 f mfc_default_keys")" -- target Mifare classic card (size 1k) with default dictionary"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF")" -- target Mifare classic card with Sector0 typeA with known key 'FFFFFFFFFFFF'"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn")" -- target MIFARE Classic card with default keys"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn * 1 f mfc_default_keys")" -- target MIFARE Classic card (size 1k) with default dictionary"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF")" -- target MIFARE Classic card with Sector0 typeA with known key 'FFFFFFFFFFFF'"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf autopwn k 0 A FFFFFFFFFFFF * 1 f mfc_default_keys")" -- this command combines the two above (reduce the need for nested / hardnested attacks, by using a dictionary)"); return PM3_SUCCESS; } @@ -246,7 +246,7 @@ static int usage_hf14_chk(void) { return PM3_SUCCESS; } static int usage_hf14_chk_fast(void) { - PrintAndLogEx(NORMAL, "This is a improved checkkeys method speedwise. It checks Mifare Classic tags sector keys against a dictionary file with keys"); + PrintAndLogEx(NORMAL, "This is a improved checkkeys method speedwise. It checks MIFARE Classic tags sector keys against a dictionary file with keys"); PrintAndLogEx(NORMAL, "Usage: hf mf fchk [h] [t|d|f] [] []"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); @@ -290,7 +290,7 @@ static int usage_hf14_keybrute(void) { static int usage_hf14_restore(void) { PrintAndLogEx(NORMAL, "Usage: hf mf restore [card memory] u k f "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLogEx(NORMAL, " u : uid, try to restore from hf-mf--key.bin and hf-mf--dump.bin"); PrintAndLogEx(NORMAL, " k : key filename, specific the full filename of key file"); PrintAndLogEx(NORMAL, " f : data filename, specific the full filename of data file"); @@ -339,7 +339,7 @@ static int usage_hf14_eset(void) { static int usage_hf14_eload(void) { PrintAndLogEx(NORMAL, "It loads emul dump from the file `filename.eml`"); PrintAndLogEx(NORMAL, "Usage: hf mf eload [card memory] [numblocks]"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K, u = UL"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K, u = UL"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf eload filename")); @@ -349,7 +349,7 @@ static int usage_hf14_eload(void) { static int usage_hf14_esave(void) { PrintAndLogEx(NORMAL, "It saves emul dump into the file `filename.eml` or `cardID.eml`"); PrintAndLogEx(NORMAL, " Usage: hf mf esave [card memory] [file name w/o `.eml`]"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf esave")); @@ -357,11 +357,21 @@ static int usage_hf14_esave(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf mf esave 4 filename")); return PM3_SUCCESS; } +static int usage_hf14_eview(void) { + PrintAndLogEx(NORMAL, "It displays emul memory"); + PrintAndLogEx(NORMAL, " Usage: hf mf eview [card memory]"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf eview")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf eview 4")); + return PM3_SUCCESS; +} static int usage_hf14_ecfill(void) { PrintAndLogEx(NORMAL, "Read card and transfer its data to emulator memory."); PrintAndLogEx(NORMAL, "Keys must be laid in the emulator memory. \n"); PrintAndLogEx(NORMAL, "Usage: hf mf ecfill [card memory]"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" hf mf ecfill A")); @@ -458,7 +468,7 @@ static int usage_hf14_csave(void) { PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " e save data to emulator memory"); PrintAndLogEx(NORMAL, " u save data to file, use carduid as filename"); - PrintAndLogEx(NORMAL, " card memory 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, " card memory 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); PrintAndLogEx(NORMAL, " o save data to file"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -467,8 +477,20 @@ static int usage_hf14_csave(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf mf csave 4 o filename")); return PM3_SUCCESS; } +static int usage_hf14_cview(void) { + PrintAndLogEx(NORMAL, "View `magic Chinese` card "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf cview [h] [card memory]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " card memory 0 = 320 bytes (MIFARE Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf cview 1")); + return PM3_SUCCESS; +} static int usage_hf14_nack(void) { - PrintAndLogEx(NORMAL, "Test a mifare classic based card for the NACK bug."); + PrintAndLogEx(NORMAL, "Test a MIFARE Classic based card for the NACK bug."); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: hf mf nack [h] [v]"); PrintAndLogEx(NORMAL, "Options:"); @@ -478,6 +500,48 @@ static int usage_hf14_nack(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf mf nack")); return PM3_SUCCESS; } +static int usage_hf14_gen3uid(void) { + PrintAndLogEx(NORMAL, "Set UID for magic GEN 3 card without manufacturer block changing"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3uid [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " UID 8/14 hex symbols"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304050607")); + return PM3_SUCCESS; +} +static int usage_hf14_gen3blk(void) { + PrintAndLogEx(NORMAL, "Overwrite full manufacturer block for magic GEN 3 card"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3blk [h] [block data (up to 32 hex symbols)]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " [block] manufacturer block data up to 32 hex symbols to write"); + PrintAndLogEx(NORMAL, " - If block data not specified, it prints current"); + PrintAndLogEx(NORMAL, " data without changes"); + PrintAndLogEx(NORMAL, " - You can specify part of manufacturer block as"); + PrintAndLogEx(NORMAL, " 4/7-bytes for UID change only for example"); + PrintAndLogEx(NORMAL, " NOTE: BCC, SAK, ATQA will be calculated automatically"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304FFFFFFFF0102030405060708")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk 01020304050607")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk")); + return PM3_SUCCESS; +} +static int usage_hf14_gen3freez(void) { + PrintAndLogEx(NORMAL, "Lock further UID changes. No more UID changes available after operation completed"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: hf mf gen3freez [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " confirm UID locks operation"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freez Y")); + return PM3_SUCCESS; +} static int GetHFMF14AUID(uint8_t *uid, int *uidlen) { clearCommandBuffer(); @@ -530,6 +594,26 @@ static int32_t initSectorTable(sector_t **src, int32_t items) { return items; } +static void decode_print_st(uint16_t blockno, uint8_t *data) { + if (mfIsSectorTrailer(blockno)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Sector trailer decoded:"); + PrintAndLogEx(NORMAL, "----------------------------------------------"); + PrintAndLogEx(NORMAL, "Key A " _GREEN_("%s"), sprint_hex_inrow(data, 6)); + PrintAndLogEx(NORMAL, "Key B " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6)); + PrintAndLogEx(NORMAL, "Access rights"); + + int bln = mfFirstBlockOfSector(mfSectorNum(blockno)); + int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, " block %d%s " _YELLOW_("%s"), bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &data[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData " _YELLOW_("0x%02x"), data[9]); + PrintAndLogEx(NORMAL, "----------------------------------------------"); + } +} + static int CmdHF14AMfDarkside(const char *Cmd) { uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA; uint64_t key = 0; @@ -604,7 +688,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) { return 1; } - PrintAndLogEx(NORMAL, "--block no:%d, key type:%c, key:%s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); + PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); PrintAndLogEx(NORMAL, "--data: %s", sprint_hex(bldata, 16)); uint8_t data[26]; @@ -651,7 +735,7 @@ static int CmdHF14AMfRdBl(const char *Cmd) { PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols"); return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "--block no:%d, key type:%c, key:%s ", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); + PrintAndLogEx(NORMAL, "--block no %d, key %c - %s", blockNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); mf_readblock_t payload; payload.blockno = blockNo; @@ -672,15 +756,8 @@ static int CmdHF14AMfRdBl(const char *Cmd) { return PM3_ESOFT; } - if (mfIsSectorTrailer(blockNo) && (data[6] || data[7] || data[8])) { - PrintAndLogEx(NORMAL, "Trailer decoded:"); - int bln = mfFirstBlockOfSector(mfSectorNum(blockNo)); - int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &data[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&data[9], 1)); + if ((data[6] || data[7] || data[8])) { + decode_print_st(blockNo, data); } } else { PrintAndLogEx(WARNING, "Command execute timeout"); @@ -721,7 +798,7 @@ static int CmdHF14AMfRdSc(const char *Cmd) { PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols"); return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "--sector no:%d key type:%c key:%s ", sectorNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); + PrintAndLogEx(NORMAL, "--sector no %d, key %c - %s ", sectorNo, keyType ? 'B' : 'A', sprint_hex(key, 6)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_READSC, sectorNo, keyType, 0, key, 6); @@ -734,19 +811,17 @@ static int CmdHF14AMfRdSc(const char *Cmd) { PrintAndLogEx(NORMAL, "isOk:%02x", isOK); if (isOK) { - for (int i = 0; i < (sectorNo < 32 ? 3 : 15); i++) { - PrintAndLogEx(NORMAL, "data : %s", sprint_hex(data + i * 16, 16)); - } - PrintAndLogEx(NORMAL, "trailer: %s", sprint_hex(data + (sectorNo < 32 ? 3 : 15) * 16, 16)); - PrintAndLogEx(NORMAL, "Trailer decoded:"); - int bln = mfFirstBlockOfSector(sectorNo); - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &(data + (sectorNo < 32 ? 3 : 15) * 16)[6])); - bln += blinc; + uint8_t blocks = 4; + uint8_t start = sectorNo * 4; + if (sectorNo > 32) { + blocks = 16; + start = 128 + (sectorNo - 32) * 16; } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo < 32 ? 3 : 15) * 16)[9], 1)); + for (int i = 0; i < blocks; i++) { + PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16)); + } + decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16)); } } else { PrintAndLogEx(WARNING, "Command execute timeout"); @@ -834,18 +909,30 @@ static int FastDumpWithEcFill(uint8_t numsectors) { clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); - int res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); - if (res != PM3_SUCCESS) { + bool res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + if (res == false) { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; } - // ecfill key B - payload.keytype = 1; + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(INFO, "fast dump reported back failure w KEY A, swapping to KEY B"); - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); - res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); - if (res != PM3_SUCCESS) { + // ecfill key B + payload.keytype = 1; + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); + res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + if (res == false) { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } + + if (resp.status != PM3_SUCCESS) { + PrintAndLogEx(INFO, "fast dump reported back failure w KEY B"); + PrintAndLogEx(INFO, "Dump file is " _RED_("PARTIAL") " complete"); + } } return PM3_SUCCESS; } @@ -938,8 +1025,7 @@ static int CmdHF14AMfDump(const char *Cmd) { mf_readblock_t payload; for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { - printf("."); - fflush(NULL); + PrintAndLogEx(NORMAL, "." NOLF); payload.blockno = FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1; payload.keytype = 0; @@ -958,18 +1044,18 @@ static int CmdHF14AMfDump(const char *Cmd) { rights[sectorNo][3] = ((data[7] & 0x80) >> 5) | ((data[8] & 0x8) >> 2) | ((data[8] & 0x80) >> 7); // C1C2C3 for sector trailer break; } else if (tries == 2) { // on last try set defaults - PrintAndLogEx(FAILED, "could not get access rights for sector %2d. Trying with defaults...", sectorNo); + PrintAndLogEx(FAILED, "\ncould not get access rights for sector %2d. Trying with defaults...", sectorNo); rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; rights[sectorNo][3] = 0x01; } } else { - PrintAndLogEx(FAILED, "command execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); + PrintAndLogEx(FAILED, "\ncommand execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; rights[sectorNo][3] = 0x01; } } } - printf("\n"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Finished reading sector access bits"); PrintAndLogEx(INFO, "Dumping all blocks from card..."); @@ -1286,19 +1372,19 @@ static int CmdHF14AMfNested(const char *Cmd) { if (cmdp == 'o') { int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true); switch (isOK) { - case -1 : + case PM3_ETIMEOUT: PrintAndLogEx(ERR, "Command execute timeout\n"); break; - case -2 : + case PM3_EOPABORTED: PrintAndLogEx(WARNING, "Button pressed. Aborted.\n"); break; - case -3 : + case PM3_EFAILED: PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break; - case -4 : + case PM3_ESOFT: PrintAndLogEx(FAILED, "No valid key found"); break; - case -5 : + case PM3_SUCCESS: key64 = bytes_to_num(keyBlock, 6); // transfer key to the emulator @@ -1346,7 +1432,6 @@ static int CmdHF14AMfNested(const char *Cmd) { PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); if (res == PM3_SUCCESS) { - // all keys found PrintAndLogEx(SUCCESS, "Fast check found all keys"); goto jumptoend; } @@ -1356,7 +1441,6 @@ static int CmdHF14AMfNested(const char *Cmd) { PrintAndLogEx(SUCCESS, "enter nested key recovery"); // nested sectors -// int iterations = 0; bool calibrate = true; for (trgKeyType = 0; trgKeyType < 2; ++trgKeyType) { @@ -1367,28 +1451,26 @@ static int CmdHF14AMfNested(const char *Cmd) { int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate); switch (isOK) { - case -1 : + case PM3_ETIMEOUT: PrintAndLogEx(ERR, "Command execute timeout\n"); break; - case -2 : + case PM3_EOPABORTED: PrintAndLogEx(WARNING, "button pressed. Aborted.\n"); break; - case -3 : + case PM3_EFAILED : PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break; - case -4 : //key not found + case PM3_ESOFT: + //key not found calibrate = false; -// iterations++; continue; - case -5 : + case PM3_SUCCESS: calibrate = false; -// iterations++; e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); continue; - default : PrintAndLogEx(ERR, "Unknown error.\n"); } @@ -1920,6 +2002,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { bool slow = false; bool legacy_mfchk = false; int prng_type = PM3_EUNDEF; + int has_staticnonce = 2; bool verbose = false; bool has_filename = false; bool errors = false; @@ -2034,6 +2117,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { return PM3_EMALLOC; } + // read uid to generate a filename for the key file + char *fptr = GenerateFilename("hf-mf-", "-key.bin"); + // card prng type (weak=1 / hard=0 / select/card comm error = negative value) prng_type = detect_classic_prng(); if (prng_type < 0) { @@ -2042,32 +2128,42 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { return prng_type; } + // check if tag doesn't have static nonce + has_staticnonce = detect_classic_static_nonce(); + // print parameters if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= SETTINGS =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " ======================="); PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sectors_cnt); PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), know_target_key ? "True" : "False"); PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), blockNo); PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), keyType ? 'B' : 'A'); PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key))); - PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD"); + + if (has_staticnonce) + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s & STATIC"), prng_type ? "WEAK" : "HARD"); + else + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD"); + PrintAndLogEx(INFO, " dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "NONE"); PrintAndLogEx(INFO, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk ? "True" : "False"); - PrintAndLogEx(INFO, _YELLOW_("======================= SETTINGS =======================")); + + PrintAndLogEx(INFO, "========================================================================"); } // Start the timer t1 = msclock(); // check the user supplied key - if (know_target_key == false) + if (know_target_key == false) { PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail"); - else { + } else { if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START KNOWN KEY ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START KNOWN KEY ATTACK") " ======================="); } + if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) == PM3_SUCCESS) { - PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -2119,9 +2215,14 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { } } } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP KNOWN KEY ATTACK =======================")); - if (num_found_keys == sectors_cnt * 2) + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP KNOWN KEY ATTACK") " ======================="); + } + + if (num_found_keys == sectors_cnt * 2) { goto all_found; + } } bool load_success = true; @@ -2130,9 +2231,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 6, &key_cnt); if (res != PM3_SUCCESS || key_cnt == 0 || keyBlock == NULL) { PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)"); - if (keyBlock != NULL) + if (keyBlock != NULL) { free(keyBlock); - + } load_success = false; } } @@ -2152,7 +2253,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { } // Use the dictionary to find sector keys on the card - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START DICTIONARY ATTACK =======================")); + if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("START DICTIONARY ATTACK") " ======================="); if (legacy_mfchk) { // Check all the sectors @@ -2161,8 +2262,8 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Check if the key is known if (e_sector[i].foundKey[j] == 0) { for (uint32_t k = 0; k < key_cnt; k++) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); + if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, (keyBlock + (6 * k)), &key64) == PM3_SUCCESS) { e_sector[i].Key[j] = bytes_to_num((keyBlock + (6 * k)), 6); e_sector[i].foundKey[j] = 'D'; @@ -2173,8 +2274,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { } } } - printf("\n"); - fflush(stdout); + PrintAndLogEx(NORMAL, ""); } else { uint32_t chunksize = key_cnt > (PM3_CMD_DATA_SIZE / 6) ? (PM3_CMD_DATA_SIZE / 6) : key_cnt; @@ -2210,7 +2310,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { lastChunk = false; } // end strategy } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP DICTIONARY ATTACK =======================")); + if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DICTIONARY ATTACK") " ======================="); // Analyse the dictionary attack @@ -2226,13 +2326,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { know_target_key = true; blockNo = i; keyType = j; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -2245,10 +2345,17 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Check if at least one sector key was found if (know_target_key == false) { // Check if the darkside attack can be used - if (prng_type) { - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START DARKSIDE ATTACK =======================")); + if (prng_type && has_staticnonce == false) { + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " ======================="); + } + isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64); - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP DARKSIDE ATTACK =======================")); + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DARKSIDE ATTACK") " ======================="); + } + switch (isOK) { case -1 : PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); @@ -2274,7 +2381,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Store the keys e_sector[blockNo].Key[keyType] = key64; e_sector[blockNo].foundKey[keyType] = 'S'; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -2314,7 +2421,7 @@ noValidKeyFound: if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) { e_sector[i].Key[j] = bytes_to_num(tmp_key, 6); e_sector[i].foundKey[j] = 'R'; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -2329,7 +2436,7 @@ noValidKeyFound: if (current_key_type_i == 1) { if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START READ B KEY ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " ======================="); PrintAndLogEx(INFO, "reading B key: sector: %3d key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); @@ -2356,48 +2463,64 @@ noValidKeyFound: e_sector[current_sector_i].foundKey[current_key_type_i] = 'A'; e_sector[current_sector_i].Key[current_key_type_i] = key64; num_to_bytes(key64, 6, tmp_key); - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", current_sector_i, current_key_type_i ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - if (verbose) PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c (reading the B key was not possible, maybe due to insufficient access rights) ", - current_sector_i, - current_key_type_i ? 'B' : 'A' - ); + if (verbose) { + PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c", + current_sector_i, + current_key_type_i ? 'B' : 'A' + ); + PrintAndLogEx(INFO, " -- reading the B key was not possible, maybe due to access rights?"); + + } + + } + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP READ B KEY ATTACK") " ======================="); } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP READ B KEY ATTACK =======================")); } } // Use the nested / hardnested attack skipReadBKey: if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) { - if (prng_type && (! nested_failed)) { + + if (has_staticnonce) + goto tryStaticnested; + + if (prng_type && (nested_failed == false)) { uint8_t retries = 0; if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START NESTED ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); } tryNested: isOK = mfnested(FirstBlockOfSector(blockNo), keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, calibrate); + switch (isOK) { - case -1 : + case PM3_ETIMEOUT: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); free(e_sector); return PM3_ESOFT; - case -2 : + } + case PM3_EOPABORTED: { PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); free(e_sector); - return PM3_ESOFT; - case -3 : + return PM3_EOPABORTED; + } + case PM3_EFAILED: { PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable)."); PrintAndLogEx(FAILED, "Nested attack failed --> try hardnested"); goto tryHardnested; - case -4 : //key not found + } + case PM3_ESOFT: { + // key not found calibrate = false; // this can happen on some old cards, it's worth trying some more before switching to slower hardnested if (retries++ < MIFARE_SECTOR_RETRY) { @@ -2409,21 +2532,27 @@ tryNested: goto tryHardnested; } break; - case -5 : + } + case PM3_SUCCESS: { calibrate = false; e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); e_sector[current_sector_i].foundKey[current_key_type_i] = 'N'; break; - default : + } + default: { PrintAndLogEx(ERR, "unknown Error.\n"); free(e_sector); return PM3_ESOFT; + } } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP NESTED ATTACK =======================")); + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP NESTED ATTACK") " ======================="); + } + } else { tryHardnested: // If the nested attack fails then we try the hardnested attack if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START HARDNESTED ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "sector no: %3d, target key type: %c, Slow: %s", current_sector_i, current_key_type_i ? 'B' : 'A', @@ -2434,14 +2563,17 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack DropField(); if (isOK) { switch (isOK) { - case 1 : + case 1: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); break; - case 2 : + } + case 2: { PrintAndLogEx(NORMAL, "\nButton pressed. Aborted."); break; - default : + } + default: { break; + } } free(e_sector); return PM3_ESOFT; @@ -2452,8 +2584,48 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack e_sector[current_sector_i].Key[current_key_type_i] = foundkey; e_sector[current_sector_i].foundKey[current_key_type_i] = 'H'; - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP HARDNESTED ATTACK =======================")); + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP HARDNESTED ATTACK") " ======================="); + } } + + if (has_staticnonce) { +tryStaticnested: + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " ======================="); + PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", + current_sector_i, + current_key_type_i ? 'B' : 'A'); + } + + isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key); + DropField(); + switch (isOK) { + case PM3_ETIMEOUT: { + PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); + free(e_sector); + return PM3_ESOFT; + } + case PM3_EOPABORTED: { + PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); + free(e_sector); + return PM3_EOPABORTED; + } + case PM3_SUCCESS: { + e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); + e_sector[current_sector_i].foundKey[current_key_type_i] = 'C'; + break; + } + default: { + break; + } + } + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP STATIC NESTED ATTACK") " ======================="); + } + } + // Check if the key was found if (e_sector[current_sector_i].foundKey[current_key_type_i]) { PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", @@ -2478,11 +2650,14 @@ all_found: // Dump the keys PrintAndLogEx(NORMAL, ""); - char *fptr = GenerateFilename("hf-mf-", "-key.bin"); if (createMfcKeyDump(fptr, sectors_cnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); } + // clear emulator mem + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR, NULL, 0); + PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)"); for (current_sector_i = 0; current_sector_i < sectors_cnt; current_sector_i++) { @@ -2535,14 +2710,7 @@ all_found: free(e_sector); return PM3_SUCCESS; } -/* -static int CmdHF14AMfNestedFixed(const char *Cmd){ - if (strlen(Cmd) < 3) return usage_hf14_fixednested(); - - return PM3_SUCCESS; -} -*/ /* static int randInRange(int min, int max) { return min + (int)(rand() / (double)(RAND_MAX) * (max - min + 1)); @@ -3014,8 +3182,8 @@ static int CmdHF14AMfChk(const char *Cmd) { for (uint16_t c = 0; c < keycnt; c += max_keys) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); + if (kbd_enter_pressed()) { PrintAndLogEx(INFO, "\naborted via keyboard!\n"); goto out; @@ -3037,7 +3205,6 @@ static int CmdHF14AMfChk(const char *Cmd) { t1 = msclock() - t1; PrintAndLogEx(INFO, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); - // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? if (keyType != 1) { PrintAndLogEx(INFO, "testing to read key B..."); @@ -3225,22 +3392,22 @@ static int CmdHF14AMfSim(const char *Cmd) { switch (param_get8(Cmd, cmdp + 1)) { case 0: flags |= FLAG_MF_MINI; - sprintf(csize, "MINI"); + snprintf(csize, sizeof(csize), "MINI"); k_sectorsCount = MIFARE_MINI_MAXSECTOR; break; case 1: flags |= FLAG_MF_1K; - sprintf(csize, "1K"); + snprintf(csize, sizeof(csize), "1K"); k_sectorsCount = MIFARE_1K_MAXSECTOR; break; case 2: flags |= FLAG_MF_2K; - sprintf(csize, "2K with RATS"); + snprintf(csize, sizeof(csize), "2K with RATS"); k_sectorsCount = MIFARE_2K_MAXSECTOR; break; case 4: flags |= FLAG_MF_4K; - sprintf(csize, "4K"); + snprintf(csize, sizeof(csize), "4K"); k_sectorsCount = MIFARE_4K_MAXSECTOR; break; default: @@ -3276,15 +3443,15 @@ static int CmdHF14AMfSim(const char *Cmd) { switch (uidlen) { case 10: flags |= FLAG_10B_UID_IN_DATA; - sprintf(uidsize, "10 byte"); + snprintf(uidsize, sizeof(uidsize), "10 byte"); break; case 7: flags |= FLAG_7B_UID_IN_DATA; - sprintf(uidsize, "7 byte"); + snprintf(uidsize, sizeof(uidsize), "7 byte"); break; case 4: flags |= FLAG_4B_UID_IN_DATA; - sprintf(uidsize, "4 byte"); + snprintf(uidsize, sizeof(uidsize), "4 byte"); break; default: return usage_hf14_mfsim(); @@ -3313,7 +3480,7 @@ static int CmdHF14AMfSim(const char *Cmd) { flags |= FLAG_UID_IN_EMUL; } - PrintAndLogEx(INFO, _YELLOW_("Mifare %s") " | %s UID " _YELLOW_("%s") "" + PrintAndLogEx(INFO, _YELLOW_("MIFARE %s") " | %s UID " _YELLOW_("%s") "" , csize , uidsize , (uidlen == 0) ? "N/A" : sprint_hex(uid, uidlen) @@ -3443,6 +3610,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto _YELLOW_("R") ":Reused / " _YELLOW_("N") ":Nested / " _YELLOW_("H") ":Hardnested / " + _YELLOW_("C") ":statiCnested / " _YELLOW_("A") ":keyA " ")" ); @@ -3592,8 +3760,7 @@ int CmdHF14AMfELoad(const char *Cmd) { free(data); return PM3_ESOFT; } - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); blockNum++; counter += blockWidth; @@ -3663,7 +3830,7 @@ static int CmdHF14AMfESave(const char *Cmd) { // user supplied filename? if (len < 1) { - fnameptr += sprintf(fnameptr, "hf-mf-"); + fnameptr += snprintf(fnameptr, sizeof(filename), "hf-mf-"); FillFileNameByUID(fnameptr, dump, "-dump", 4); } @@ -3674,6 +3841,56 @@ static int CmdHF14AMfESave(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14AMfEView(const char *Cmd) { + + uint8_t *dump; + int bytes; + uint16_t blocks; + + char c = tolower(param_getchar(Cmd, 0)); + if (c == 'h') return usage_hf14_eview(); + + if (c != 0) { + blocks = NumOfBlocks(c); + if (blocks == 0) return usage_hf14_eview(); + } else { + blocks = MIFARE_1K_MAXBLOCK; + } + bytes = blocks * MFBLOCK_SIZE; + + dump = calloc(bytes, sizeof(uint8_t)); + if (!dump) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + memset(dump, 0, bytes); + + PrintAndLogEx(INFO, "downloading from emulator memory"); + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { + PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); + free(dump); + return PM3_ETIMEOUT; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + PrintAndLogEx(INFO, "blk | data | ascii"); + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + for (uint16_t i = 0; i < blocks; i++) { + if (i == 0) { + PrintAndLogEx(INFO, "%03d | " _RED_("%s"), i, sprint_hex_ascii(dump + (i * 16), 16)); + } else if (mfIsSectorTrailer(i)) { + PrintAndLogEx(INFO, "%03d | " _YELLOW_("%s"), i, sprint_hex_ascii(dump + (i * 16), 16)); + } else { + PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 16), 16)); + } + } + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + PrintAndLogEx(NORMAL, ""); + free(dump); + return PM3_SUCCESS; +} + static int CmdHF14AMfECFill(const char *Cmd) { uint8_t keyType = 0; uint8_t numSectors = 16; @@ -3783,7 +4000,7 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; - fptr += sprintf(fptr, "hf-mf-"); + fptr += snprintf(fptr, sizeof(filename), "hf-mf-"); FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid)); createMfcKeyDump(filename, sectors_cnt, e_sector); @@ -3968,8 +4185,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) { PrintAndLogEx(WARNING, "Cant set magic card block: %d", blockNum); return PM3_ESOFT; } - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); } PrintAndLogEx(NORMAL, "\n"); return PM3_SUCCESS; @@ -4030,8 +4246,9 @@ static int CmdHF14AMfCLoad(const char *Cmd) { datalen -= 16; - printf("."); + PrintAndLogEx(NORMAL, "." NOLF); fflush(stdout); + blockNum++; // magic card type - mifare 1K @@ -4069,19 +4286,7 @@ static int CmdHF14AMfCGetBlk(const char *Cmd) { PrintAndLogEx(NORMAL, "data: %s", sprint_hex(data, sizeof(data))); - if (mfIsSectorTrailer(blockNo)) { - PrintAndLogEx(NORMAL, "Trailer decoded:"); - PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(data, 6)); - PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&data[10], 6)); - int bln = mfFirstBlockOfSector(mfSectorNum(blockNo)); - int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &data[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&data[9], 1)); - } - + decode_print_st(blockNo, data); return PM3_SUCCESS; } @@ -4097,7 +4302,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "\n # | data | Sector | %02d/ 0x%02X ", sector, sector); + PrintAndLogEx(NORMAL, "\n # | data - sector %02d / 0x%02X ", sector, sector); PrintAndLogEx(NORMAL, "----+------------------------------------------------"); uint8_t blocks = 4; uint8_t start = sector * 4; @@ -4119,6 +4324,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { } PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data, 16)); } + decode_print_st(start + blocks - 1, data); return PM3_SUCCESS; } @@ -4130,7 +4336,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { bool fillEmulator = false; bool errors = false, hasname = false, useuid = false; int i, len, flags; - uint8_t numblocks = 0, cmdp = 0; + uint16_t numblocks = 0, cmdp = 0; uint16_t bytes = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -4149,7 +4355,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { case '4': numblocks = NumOfBlocks(ctmp); bytes = numblocks * MFBLOCK_SIZE; - PrintAndLogEx(SUCCESS, "Saving magic mifare %cK", ctmp); + PrintAndLogEx(SUCCESS, "Saving magic MIFARE %cK", ctmp); cmdp++; break; case 'u': @@ -4225,7 +4431,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { } if (useuid) { - fnameptr += sprintf(fnameptr, "hf-mf-"); + fnameptr += snprintf(fnameptr, sizeof(filename), "hf-mf-"); FillFileNameByUID(fnameptr, card.uid, "-dump", card.uidlen); } @@ -4241,8 +4447,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { if (mfEmlSetMem(dump + (i * MFBLOCK_SIZE), i, 5) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Cant set emul block: %d", i); } - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); } PrintAndLogEx(NORMAL, "\n"); PrintAndLogEx(SUCCESS, "uploaded %d bytes to emulator memory", bytes); @@ -4255,6 +4460,107 @@ static int CmdHF14AMfCSave(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14AMfCView(const char *Cmd) { + + bool errors = false; + int flags; + char ctmp = '1'; + uint8_t cmdp = 0; + uint16_t numblocks = NumOfBlocks(ctmp); + uint16_t bytes = numblocks * MFBLOCK_SIZE; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + ctmp = tolower(param_getchar(Cmd, cmdp)); + switch (ctmp) { + case 'h': + return usage_hf14_cview(); + case '0': + case '1': + case '2': + case '4': + numblocks = NumOfBlocks(ctmp); + bytes = numblocks * MFBLOCK_SIZE; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors) return usage_hf14_cview(); + + PrintAndLogEx(SUCCESS, "View magic MIFARE " _GREEN_("%cK"), ctmp); + + uint8_t *dump = calloc(bytes, sizeof(uint8_t)); + if (!dump) { + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); + return PM3_EMALLOC; + } + + // Select card to get UID/UIDLEN information + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + free(dump); + return PM3_ESOFT; + } + + /* + 0: couldn't read + 1: OK, with ATS + 2: OK, no ATS + 3: proprietary Anticollision + */ + uint64_t select_status = resp.oldarg[0]; + + if (select_status == 0) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + free(dump); + return select_status; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + flags = MAGIC_INIT + MAGIC_WUPC; + for (uint16_t i = 0; i < numblocks; i++) { + if (i == 1) flags = 0; + if (i == numblocks - 1) flags = MAGIC_HALT + MAGIC_OFF; + + if (mfCGetBlock(i, dump + (i * MFBLOCK_SIZE), flags)) { + PrintAndLogEx(WARNING, "Cant get block: %d", i); + free(dump); + return PM3_ESOFT; + } + + PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + PrintAndLogEx(INFO, "blk | data | ascii"); + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + for (uint16_t i = 0; i < numblocks; i++) { + + if (i == 0) { + PrintAndLogEx(INFO, "%03d | " _RED_("%s"), i, sprint_hex_ascii(dump + (i * 16), 16)); + } else if (mfIsSectorTrailer(i)) { + PrintAndLogEx(INFO, "%03d | " _YELLOW_("%s"), i, sprint_hex_ascii(dump + (i * 16), 16)); + } else { + PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 16), 16)); + } + } + PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------"); + PrintAndLogEx(NORMAL, ""); + free(dump); + return PM3_SUCCESS; +} + //needs nt, ar, at, Data to decrypt static int CmdHf14AMfDecryptBytes(const char *Cmd) { @@ -4328,7 +4634,7 @@ static int CmdHf14AMfSetMod(const char *Cmd) { return PM3_SUCCESS; } -// Mifare NACK bug detection +// MIFARE NACK bug detection static int CmdHf14AMfNack(const char *Cmd) { char ctmp = tolower(param_getchar(Cmd, 0)); @@ -4487,7 +4793,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf mad", - "Checks and prints Mifare Application Directory (MAD)", + "Checks and prints MIFARE Application Directory (MAD)", "Usage:\n" _YELLOW_("\thf mf mad") " -> shows MAD if exists\n" _YELLOW_("\thf mf mad --aid e103 -k ffffffffffff -b") " -> shows NDEF data if exists. read card with custom key and key B\n" @@ -4529,7 +4835,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------"); + PrintAndLogEx(INFO, "--- " _CYAN_("MIFARE App Directory Information") " ----------------"); PrintAndLogEx(INFO, "-----------------------------------------------------"); bool haveMAD2 = false; @@ -4745,7 +5051,7 @@ static int CmdHFMFPersonalize(const char *cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf personalize", - "Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.", + "Personalize the UID of a MIFARE Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.", "Usage:\n" _YELLOW_("\thf mf personalize UIDF0") " -> double size UID according to ISO/IEC14443-3\n" _YELLOW_("\thf mf personalize UIDF1") " -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n" @@ -4837,6 +5143,69 @@ static int CmdHF14AMfList(const char *Cmd) { return CmdTraceList("mf"); } +static int CmdHf14AGen3UID(const char *Cmd) { + uint8_t uid[7] = {0x00}; + uint8_t oldUid[10] = {0x00}; + uint8_t uidlen; + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_hf14_gen3uid(); + + if (param_gethex(Cmd, 0, uid, 8)) + if (param_gethex(Cmd, 0, uid, 14)) + return usage_hf14_gen3uid(); + else + uidlen = 7; + else + uidlen = 4; + + int res = mfGen3UID(uid, uidlen, oldUid); + if (res) { + PrintAndLogEx(ERR, "Can't set UID. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, uidlen)); + PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, uidlen)); + return PM3_SUCCESS; +} + +static int CmdHf14AGen3Blk(const char *Cmd) { + uint8_t block[16] = {0x00}; + int blocklen = 0; + uint8_t newBlock[16] = {0x00}; + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_hf14_gen3blk(); + + if (ctmp != '\0' && param_gethex_to_eol(Cmd, 0, block, sizeof(block), &blocklen)) + return usage_hf14_gen3blk(); + + int res = mfGen3Blk(block, blocklen, newBlock); + if (res) { + PrintAndLogEx(ERR, "Can't change manufacturer block data. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Current Block : %s", sprint_hex(newBlock, 16)); + return PM3_SUCCESS; +} + +static int CmdHf14AGen3Freez(const char *Cmd) { + char ctmp = param_getchar(Cmd, 0); + if (tolower(ctmp) == 'h') return usage_hf14_gen3freez(); + if (ctmp != 'Y') return usage_hf14_gen3freez(); + + int res = mfGen3Freez(); + if (res) { + PrintAndLogEx(ERR, "Can't lock UID changes. Error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Gen 3 UID locked"); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"}, @@ -4853,15 +5222,15 @@ static command_t CommandTable[] = { {"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, {"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"}, - {"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE classic tag to binary file"}, + {"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"}, {"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, - {"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"}, - {"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE classic block"}, - {"rdsc", CmdHF14AMfRdSc, IfPm3Iso14443a, "Read MIFARE classic sector"}, - {"restore", CmdHF14AMfRestore, IfPm3Iso14443a, "Restore MIFARE classic binary file to BLANK tag"}, + {"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (MIFARE Classic EV1 only)"}, + {"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE Classic block"}, + {"rdsc", CmdHF14AMfRdSc, IfPm3Iso14443a, "Read MIFARE Classic sector"}, + {"restore", CmdHF14AMfRestore, IfPm3Iso14443a, "Restore MIFARE Classic binary file to BLANK tag"}, {"setmod", CmdHf14AMfSetMod, IfPm3Iso14443a, "Set MIFARE Classic EV1 load modulation strength"}, - {"wrbl", CmdHF14AMfWrBl, IfPm3Iso14443a, "Write MIFARE classic block"}, + {"wrbl", CmdHF14AMfWrBl, IfPm3Iso14443a, "Write MIFARE Classic block"}, // {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"sim", CmdHF14AMfSim, IfPm3Iso14443a, "Simulate MIFARE card"}, @@ -4870,6 +5239,7 @@ static command_t CommandTable[] = { {"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"}, {"eload", CmdHF14AMfELoad, IfPm3Iso14443a, "Load from file emul dump"}, {"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"}, + {"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"}, {"ecfill", CmdHF14AMfECFill, IfPm3Iso14443a, "Fill simulator memory with help of keys from simulator"}, {"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " -----------------------"}, @@ -4880,6 +5250,12 @@ static command_t CommandTable[] = { {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"}, {"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"}, {"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"}, + {"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"}, + {"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block (magic gen3 card)"}, + {"gen3blk", CmdHf14AGen3Blk, IfPm3Iso14443a, "Overwrite full manufacturer block (magic gen 3 card)"}, + {"gen3freez", CmdHf14AGen3Freez, IfPm3Iso14443a, "Lock further UID changes (magic gen 3 card)"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"}, {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"}, {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index c7fa78e0f..a5ecf561b 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -347,9 +347,9 @@ static char *getCardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - sprintf(retStr, "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); else - sprintf(retStr, "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); return buf; } @@ -359,14 +359,14 @@ static char *getProtocolStr(uint8_t id, bool hw) { char *retStr = buf; if (id == 0x04) { - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); } else if (id == 0x05) { if (hw) - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id); else - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id); } else { - sprintf(retStr, "0x%02X (" _YELLOW_("Unknown") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Unknown") ")", id); } return buf; } @@ -377,17 +377,17 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { char *retStr = buf; if (major == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); else if (major == 0x01 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); else if (major == 0x12 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); else if (major == 0x33 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); else if (major == 0x30 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); else - sprintf(retStr, "%x.%x (" _YELLOW_("Unknown") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); return buf; } @@ -3401,6 +3401,7 @@ static void DecodeComSet(uint8_t comset) { } static char *DecodeAccessValue(uint8_t value) { + char *car = (char *)calloc(255, sizeof(char)); if (car == NULL) return NULL; @@ -3413,7 +3414,7 @@ static char *DecodeAccessValue(uint8_t value) { strcat(car, "(Denied Access)"); break; default: - sprintf(car, "(Access Key: %d)", value); + snprintf(car, 255, "(Access Key: %d)", value); break; } return car; @@ -4364,7 +4365,7 @@ static int CmdHF14aDesChk(const char *Cmd) { } if (!verbose) - printf("Search keys:\n"); + PrintAndLogEx(INFO, "Search keys:"); bool result = false; uint8_t app_ids[78] = {0}; @@ -4382,25 +4383,29 @@ static int CmdHF14aDesChk(const char *Cmd) { } for (uint32_t x = 0; x < app_ids_len / 3; x++) { + uint32_t curaid = (app_ids[x * 3] & 0xFF) + ((app_ids[(x * 3) + 1] & 0xFF) << 8) + ((app_ids[(x * 3) + 2] & 0xFF) << 16); PrintAndLogEx(ERR, "Checking aid 0x%06X...", curaid); + res = AuthCheckDesfire(&app_ids[x * 3], deskeyList, deskeyListLen, aeskeyList, aeskeyListLen, k3kkeyList, k3kkeyListLen, foundKeys, &result); if (res == PM3_EOPABORTED) { break; } if (pattern2b && startPattern < 0x10000) { - if (!verbose) - printf("p"); + if (verbose == false) + PrintAndLogEx(NORMAL, "p" NOLF); + aeskeyListLen = 0; deskeyListLen = 0; k3kkeyListLen = 0; DesFill2bPattern(deskeyList, &deskeyListLen, aeskeyList, &aeskeyListLen, k3kkeyList, &k3kkeyListLen, &startPattern); continue; } + if (dict_filenamelen && endFilePosition) { - if (!verbose) - printf("d"); + if (verbose == false) + PrintAndLogEx(NORMAL, "d" NOLF); uint32_t keycnt = 0; res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); @@ -4420,8 +4425,8 @@ static int CmdHF14aDesChk(const char *Cmd) { continue; } } - if (!verbose) - printf("\n"); + if (verbose == false) + PrintAndLogEx(NORMAL, ""); // save keys to json if ((jsonnamelen > 0) && result) { diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 1e1f7aeef..4ee04e781 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -58,9 +58,9 @@ static char *getCardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - sprintf(retStr, "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); else - sprintf(retStr, "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); return buf; } @@ -70,14 +70,14 @@ static char *getProtocolStr(uint8_t id, bool hw) { char *retStr = buf; if (id == 0x04) { - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3 MIFARE, 14443-4") ")", id); } else if (id == 0x05) { if (hw) - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-2, 14443-3") ")", id); else - sprintf(retStr, "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("ISO 14443-3, 14443-4") ")", id); } else { - sprintf(retStr, "0x%02X (" _YELLOW_("Unknown") ")", id); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Unknown") ")", id); } return buf; } @@ -88,20 +88,20 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { char *retStr = buf; if (major == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); else if (major == 0x01 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); else if (major == 0x12 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); -// else if (major == 0x13 && minor == 0x00) -// sprintf(retStr, "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); + else if (major == 0x33 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); else if (major == 0x30 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); else if (major == 0x11 && minor == 0x00) - sprintf(retStr, "%x.%x (" _YELLOW_("Plus EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Plus EV1") ")", major, minor); else - sprintf(retStr, "%x.%x (" _YELLOW_("Unknown") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); return buf; } @@ -112,16 +112,16 @@ static char *getTypeStr(uint8_t type) { switch (type) { case 1: - sprintf(retStr, "0x%02X (" _YELLOW_("DESFire") ")", type); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("DESFire") ")", type); break; case 2: - sprintf(retStr, "0x%02X (" _YELLOW_("Plus") ")", type); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Plus") ")", type); break; case 3: - sprintf(retStr, "0x%02X (" _YELLOW_("Ultralight") ")", type); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("Ultralight") ")", type); break; case 4: - sprintf(retStr, "0x%02X (" _YELLOW_("NTAG") ")", type); + snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("NTAG") ")", type); break; default: break; @@ -144,8 +144,8 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { return DESFIRE_EV2; // DESFire EV3 -// if (major == 0x13 && minor == 0x00 ) -// return DESFIRE_EV3; + if (major == 0x33 && minor == 0x00) + return DESFIRE_EV3; // DESFire Light if (major == 0x30 && minor == 0x00) @@ -969,8 +969,10 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA // main cycle with key check for (int i = 0; i < keyListLen; i++) { if (i % 10 == 0) { - if (!verbose) - printf("."); + + if (verbose == false) + PrintAndLogEx(NORMAL, "." NOLF); + if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); DropField(); @@ -988,9 +990,9 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA break; if (verbose) - PrintAndLogEx(WARNING, "retried[%d]...", retry); + PrintAndLogEx(WARNING, "\nretried[%d]...", retry); else - printf("R"); + PrintAndLogEx(NORMAL, "R" NOLF); DropField(); selectCard = true; @@ -998,14 +1000,15 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA } if (verbose) - PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); // key for [sector,keyAB] found if (res == 0) { if (verbose) - PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + PrintAndLogEx(INFO, "\nFound key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); else - printf("+"); + PrintAndLogEx(NORMAL, "+" NOLF); + foundKeys[keyAB][sector][0] = 0x01; memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); DropField(); @@ -1017,9 +1020,10 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA // 5 - auth error (rnd not equal) if (res != 5) { if (verbose) - PrintAndLogEx(ERR, "Exchange error. Aborted."); + PrintAndLogEx(ERR, "\nExchange error. Aborted."); else - printf("E"); + PrintAndLogEx(NORMAL, "E" NOLF); + DropField(); return PM3_ECARDEXCHANGE; } @@ -1201,23 +1205,25 @@ static int CmdHFMFPChk(const char *Cmd) { PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " keys", keyListLen); } - if (!verbose) - printf("Search keys:"); + if (verbose == false) + PrintAndLogEx(NORMAL, "Search keys"); while (true) { res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); if (res == PM3_EOPABORTED) break; if (pattern2b && startPattern < 0x10000) { - if (!verbose) - printf("p"); + if (verbose == false) + PrintAndLogEx(NORMAL, "p" NOLF); + keyListLen = 0; Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } if (dict_filenamelen && endFilePosition) { - if (!verbose) - printf("d"); + if (verbose == false) + PrintAndLogEx(NORMAL, "d" NOLF); + uint32_t keycnt = 0; res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); keyListLen = keycnt; @@ -1225,8 +1231,8 @@ static int CmdHFMFPChk(const char *Cmd) { } break; } - if (!verbose) - printf("\n"); + if (verbose == false) + PrintAndLogEx(NORMAL, ""); // print result bool printedHeader = false; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index c4a8ce0eb..58dc9a300 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -123,7 +123,7 @@ static int usage_hf_mfu_wrbl(void) { PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b d k l\n"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " b : block to write"); - PrintAndLogEx(NORMAL, " d : block data - (8 hex symbols)"); + PrintAndLogEx(NORMAL, " d : block data - (8 or 32 hex symbols, 32 hex symbols will do a compatibility write)"); PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); PrintAndLogEx(NORMAL, ""); @@ -1096,6 +1096,7 @@ uint32_t GetHF14AMfU_Type(void) { else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { tagtype = UL_EV1_48; break; } else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } + else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { tagtype = UL_EV1_128; break; } // Mikron JSC Russia EV1 41 pages tag else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0B", 7) == 0) { tagtype = NTAG_210; break; } else if (memcmp(version, "\x00\x04\x04\x01\x01\x00\x0E", 7) == 0) { tagtype = NTAG_212; break; } else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213; break; } @@ -1473,8 +1474,9 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { uint8_t cmdp = 0; uint8_t keylen = 0; - uint8_t blockdata[20] = {0x00}; + uint8_t blockdata[16] = {0x00}; uint8_t data[16] = {0x00}; + uint8_t datalen = 4; uint8_t authenticationkey[16] = {0x00}; uint8_t *authKeyPtr = authenticationkey; @@ -1516,9 +1518,13 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { break; case 'd': if (param_gethex(Cmd, cmdp + 1, blockdata, 8)) { - PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols"); - errors = true; - break; + if (param_gethex(Cmd, cmdp + 1, blockdata, 32)) { + PrintAndLogEx(WARNING, "Block data must include 8 or 32 HEX symbols"); + errors = true; + break; + } else { + datalen = 16; + } } cmdp += 2; break; @@ -1558,9 +1564,8 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); //Send write Block - uint8_t cmddata[20]; - memcpy(cmddata, blockdata, 4); - uint8_t datalen = 4; + uint8_t cmddata[32]; + memcpy(cmddata, blockdata, datalen); uint8_t keytype = 0; if (hasAuthKey) { keytype = 1; @@ -1573,7 +1578,11 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { } clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockNo, keytype, 0, cmddata, datalen); + if (datalen == 16) { + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL_COMPAT, blockNo, keytype, 0, cmddata, datalen); + } else { + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockNo, keytype, 0, cmddata, datalen); + } PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.oldarg[0] & 0xff; @@ -1982,7 +1991,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { // not ul_c and not std ul then attempt to collect info like // VERSION, SIGNATURE, COUNTERS, TEARING, PACK, - if (!(tagtype & UL_C || tagtype & UL)) { + if (!(tagtype & UL_C || tagtype & UL || tagtype & MY_D_MOVE || tagtype & MY_D_MOVE_LEAN)) { //attempt to read pack uint8_t get_pack[] = {0, 0}; if (ul_auth_select(&card, tagtype, true, authKeyPtr, get_pack, sizeof(get_pack)) != PM3_SUCCESS) { @@ -2306,8 +2315,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); } PrintAndLogEx(NORMAL, "\n"); diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 64518c3ae..4c93210eb 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -696,7 +696,7 @@ void pm3_version(bool verbose, bool oneliner) { // For "proxmark3 -v", simple printf, avoid logging char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image FormatVersionInformation(temp, sizeof(temp), "Client: ", &version_information); - printf("%s compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH "\n", temp); + PrintAndLogEx(NORMAL, "%s compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH "\n", temp); return; } @@ -705,7 +705,6 @@ void pm3_version(bool verbose, bool oneliner) { PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_VERSION, NULL, 0); if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) { diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index 7d12fa972..7bae8618d 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -364,16 +364,15 @@ int CmdLFCommandRead(const char *Cmd) { uint8_t i = 10; // 20sec wait loop while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); i--; } - printf("\n"); + PrintAndLogEx(NORMAL, ""); if (resp.status == PM3_SUCCESS) { if (i) { PrintAndLogEx(SUCCESS, "downloading response signal data"); - getSamples(0, true); + getSamples(0, false); return PM3_SUCCESS; } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); @@ -596,7 +595,7 @@ int lf_read(bool verbose, uint32_t samples) { if (!session.pm3_present) return PM3_ENOTTY; struct p { - uint8_t verbose; + bool verbose; uint32_t samples; } PACKED; @@ -606,21 +605,19 @@ int lf_read(bool verbose, uint32_t samples) { clearCommandBuffer(); SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; if (g_lf_threshold_set) { WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp); } else { if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) { - PrintAndLogEx(WARNING, "command execution time out"); + PrintAndLogEx(WARNING, "(lf_read) command execution time out"); return PM3_ETIMEOUT; } } - // resp.oldarg[0] is bits read not bytes read. - uint32_t bits = (resp.data.asDwords[0] / 8); - getSamples(bits, verbose); - + // response is number of bits read + uint32_t size = (resp.data.asDwords[0] / 8); + getSamples(size, verbose); return PM3_SUCCESS; } @@ -736,15 +733,13 @@ int CmdLFSim(const char *Cmd) { PrintAndLogEx(INFO, "Bigbuf is full."); break; } - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); payload_up.flag = 0; } // Disable fast mode before last command conn.block_after_ACK = false; - printf("\n"); - + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Simulating"); struct p { @@ -1194,7 +1189,7 @@ static bool CheckChipType(bool getDeviceData) { //check for em4x05/em4x69 chips first uint32_t word = 0; if (EM4x05IsBlock0(&word)) { - PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05/EM4x69")); + PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05 / EM4x69")); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05`") " commands"); retval = true; goto out; @@ -1215,6 +1210,7 @@ static bool CheckChipType(bool getDeviceData) { goto out; } + PrintAndLogEx(NORMAL, "Couldn't identify a chipset"); out: save_restoreGB(GRAPH_RESTORE); save_restoreDB(GRAPH_RESTORE); @@ -1242,6 +1238,7 @@ int CmdLFfind(const char *Cmd) { return PM3_ESOFT; } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "NOTE: some demods output possible binary"); PrintAndLogEx(INFO, "if it finds something that looks like a tag"); PrintAndLogEx(INFO, "False Positives " _YELLOW_("ARE") " possible"); @@ -1270,49 +1267,50 @@ int CmdLFfind(const char *Cmd) { // The improved noise detection will find Cotag. if (getSignalProperties()->isnoise) { + PrintAndLogEx(INPLACE, "Searching for MOTOROLA tag..."); if (readMotorolaUid()) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola FlexPass ID") " found!"); return PM3_SUCCESS; } if (readCOTAGUid()) { + PrintAndLogEx(INPLACE, "Searching for COTAG tag..."); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("COTAG ID") " found!"); return PM3_SUCCESS; } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(FAILED, _RED_("No data found!")); PrintAndLogEx(INFO, "Signal looks like noise. Maybe not an LF tag?"); + PrintAndLogEx(NORMAL, ""); return PM3_ESOFT; } } - if (demodVisa2k() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Visa2000 ID") " found!"); goto out;} - if (demodHID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;} - if (demodAWID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;} - if (demodIOProx() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;} - if (demodParadox() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Paradox ID") " found!"); goto out;} - if (demodNexWatch() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NexWatch ID") " found!"); goto out;} - if (demodIndala() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Indala ID") " found!"); goto out;} + if (demodVisa2k() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Visa2000 ID") " found!"); goto out;} + if (demodHID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;} + if (demodAWID() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;} + if (demodIOProx() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;} + if (demodParadox() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Paradox ID") " found!"); goto out;} + if (demodNexWatch() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NexWatch ID") " found!"); goto out;} + if (demodIndala() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Indala ID") " found!"); goto out;} + if (demodEM410x() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM410x ID") " found!"); goto out;} + if (demodFDX() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;} + if (demodGuard() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Guardall G-Prox II ID") " found!"); goto out; } + if (demodIdteck() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Idteck ID") " found!"); goto out;} + if (demodJablotron() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Jablotron ID") " found!"); goto out;} + if (demodNedap() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NEDAP ID") " found!"); goto out;} + if (demodNoralsy() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Noralsy ID") " found!"); goto out;} + if (demodKeri() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("KERI ID") " found!"); goto out;} + if (demodPac() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("PAC/Stanley ID") " found!"); goto out;} + if (demodPresco() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Presco ID") " found!"); goto out;} + if (demodPyramid() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Pyramid ID") " found!"); goto out;} + if (demodSecurakey() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Securakey ID") " found!"); goto out;} + if (demodViking() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Viking ID") " found!"); goto out;} + if (demodGallagher() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("GALLAGHER ID") " found!"); goto out;} - if (demodEM410x() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM410x ID") " found!"); goto out;} - if (demodFDX() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;} - if (demodGuard() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Guardall G-Prox II ID") " found!"); goto out; } - if (demodIdteck() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Idteck ID") " found!"); goto out;} - - if (demodJablotron() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Jablotron ID") " found!"); goto out;} - if (demodNedap() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NEDAP ID") " found!"); goto out;} - if (demodNoralsy() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Noralsy ID") " found!"); goto out;} - if (demodKeri() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("KERI ID") " found!"); goto out;} - if (demodPac() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("PAC/Stanley ID") " found!"); goto out;} - - if (demodPresco() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Presco ID") " found!"); goto out;} - if (demodPyramid() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Pyramid ID") " found!"); goto out;} - if (demodSecurakey() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Securakey ID") " found!"); goto out;} - if (demodViking() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Viking ID") " found!"); goto out;} - if (demodGallagher() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("GALLAGHER ID") " found!"); goto out;} - -// if (demodTI() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Texas Instrument ID") " found!"); goto out;} - //if (demodFermax() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Fermax ID") " found!"); goto out;} +// if (demodTI() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Texas Instrument ID") " found!"); goto out;} +// if (demodFermax() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Fermax ID") " found!"); goto out;} PrintAndLogEx(FAILED, _RED_("No known 125/134 kHz tags found!")); diff --git a/client/src/cmdlfawid.c b/client/src/cmdlfawid.c index fcabbbd2b..765c7e9c6 100644 --- a/client/src/cmdlfawid.c +++ b/client/src/cmdlfawid.c @@ -60,7 +60,7 @@ static int usage_lf_awid_sim(void) { } static int usage_lf_awid_clone(void) { - PrintAndLogEx(NORMAL, "Enables cloning of AWID card with specified facility-code and card number onto T55x7."); + PrintAndLogEx(NORMAL, "Enables cloning of AWID card with specified facility-code and card number onto T55x7 or Q5/T5555."); PrintAndLogEx(NORMAL, "The T55x7 must be on the antenna when issuing this command. T55x7 blocks are calculated and printed in the process."); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: lf awid clone [h] [Q5]"); @@ -69,7 +69,7 @@ static int usage_lf_awid_clone(void) { PrintAndLogEx(NORMAL, " : format length 26|34|37|50"); PrintAndLogEx(NORMAL, " : 8|16bit value facility code"); PrintAndLogEx(NORMAL, " : 16|32-bit value card number"); - PrintAndLogEx(NORMAL, " Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); + PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf awid clone 26 224 1337")); @@ -405,9 +405,10 @@ static int CmdAWIDClone(const char *Cmd) { uint32_t blocks[4] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 3 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0}; - if (tolower(param_getchar(Cmd, 3)) == 'q') + bool q5 = tolower(param_getchar(Cmd, 3)) == 'q'; + if (q5) //t5555 (Q5) BITRATE = (RF-2)/2 (iceman) - blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT; + blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT; verify_values(&fmtlen, &fc, &cn); @@ -425,7 +426,7 @@ static int CmdAWIDClone(const char *Cmd) { free(bits); - PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn); + PrintAndLogEx(INFO, "Preparing to clone AWID %u to " _YELLOW_("%s") " with FC: %u, CN: %u", fmtlen, (q5) ? "Q5/T5555" : "T55x7", fc, cn); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -532,7 +533,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "this help"}, {"demod", CmdAWIDDemod, AlwaysAvailable, "demodulate an AWID FSK tag from the GraphBuffer"}, {"read", CmdAWIDRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdAWIDClone, IfPm3Lf, "clone AWID tag to T55x7 or Q5/T5555"}, {"sim", CmdAWIDSim, IfPm3Lf, "simulate AWID tag"}, {"brute", CmdAWIDBrute, IfPm3Lf, "Bruteforce card number against reader"}, {"watch", CmdAWIDWatch, IfPm3Lf, "continuously watch for cards. Reader mode"}, diff --git a/client/src/cmdlfcotag.c b/client/src/cmdlfcotag.c index d53a545dd..b0160e335 100644 --- a/client/src/cmdlfcotag.c +++ b/client/src/cmdlfcotag.c @@ -92,19 +92,18 @@ static int CmdCOTAGRead(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_LF_COTAG_READ, (uint8_t*)&payload, sizeof(payload)); + SendCommandNG(CMD_LF_COTAG_READ, (uint8_t *)&payload, sizeof(payload)); uint8_t timeout = 3; while (!WaitForResponseTimeout(CMD_LF_COTAG_READ, &resp, 2000)) { timeout--; - printf("."); - fflush(stdout); - + PrintAndLogEx(NORMAL, "." NOLF); if (timeout == 0) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } } + if (timeout != 3) PrintAndLogEx(NORMAL, ""); diff --git a/client/src/cmdlfem4x.c b/client/src/cmdlfem4x.c index 423c06c58..3b00686b1 100644 --- a/client/src/cmdlfem4x.c +++ b/client/src/cmdlfem4x.c @@ -64,13 +64,13 @@ static int usage_lf_em410x_watch(void) { } static int usage_lf_em410x_write(void) { - PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 / T5555 (Q5) tag"); + PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 or Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: lf em 410x_write [h] [clock]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " - ID number"); - PrintAndLogEx(NORMAL, " - 0|1 T5555 (Q5) / T55x7"); + PrintAndLogEx(NORMAL, " - 0|1 0 = Q5/T5555, 1 = T55x7"); PrintAndLogEx(NORMAL, " - 16|32|40|64, optional, set R/F clock rate, defaults to 64"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_write 0F0368568B 1") " = write ID to t55x7 card"); @@ -630,15 +630,11 @@ static int CmdEM410xWrite(const char *Cmd) { return PM3_EINVARG; } - if (card == 1) { - PrintAndLogEx(SUCCESS, "Writing %s tag with UID 0x%010" PRIx64 " (clock rate: %d)", _GREEN_("T55x7"), id, clock1); - // NOTE: We really should pass the clock in as a separate argument, but to - // provide for backwards-compatibility for older firmware, and to avoid - // having to add another argument to CMD_LF_EM410X_WRITE, we just store - // the clock rate in bits 8-15 of the card value - } else if (card == 0) { - PrintAndLogEx(SUCCESS, "Writing %s tag with UID 0x%010" PRIx64 "(clock rate: %d)", _GREEN_("T5555"), id, clock1); - } + PrintAndLogEx(SUCCESS, "Writing " _YELLOW_("%s") " tag with UID 0x%010" PRIx64 " (clock rate: %d)", (card == 1) ? "T55x7" : "Q5/T5555", id, clock1); + // NOTE: We really should pass the clock in as a separate argument, but to + // provide for backwards-compatibility for older firmware, and to avoid + // having to add another argument to CMD_LF_EM410X_WRITE, we just store + // the clock rate in bits 8-15 of the card value struct { uint8_t card; @@ -695,7 +691,7 @@ static bool downloadSamplesEM(void) { // 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples) uint8_t got[6000]; if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); + PrintAndLogEx(WARNING, "(downloadSamplesEM) command execution time out"); return false; } @@ -859,6 +855,7 @@ static int demodEM4x05resp(uint32_t *word) { } //////////////// 4205 / 4305 commands +#include "util_posix.h" // msclock static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) { struct { @@ -874,14 +871,14 @@ static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X_READWORD, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_LF_EM4X_READWORD, &resp, 2500)) { - PrintAndLogEx(DEBUG, "timeout while waiting for reply."); + if (!WaitForResponseTimeout(CMD_LF_EM4X_READWORD, &resp, 10000)) { + PrintAndLogEx(WARNING, "(EM4x05ReadWord_ext) timeout while waiting for reply."); return PM3_ETIMEOUT; } - if (!downloadSamplesEM()) { + + if (downloadSamplesEM() == false) { return PM3_ESOFT; } - return demodEM4x05resp(word); } @@ -1386,7 +1383,7 @@ static command_t CommandTable[] = { {"410x_brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"}, {"410x_watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"}, {"410x_spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" }, - {"410x_write", CmdEM410xWrite, IfPm3Lf, "write EM410x UID to T5555(Q5) or T55x7 tag"}, + {"410x_write", CmdEM410xWrite, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"}, {"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"}, {"4x05_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"}, {"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"}, diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index 03ec3f5dc..124ffe8c0 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -516,7 +516,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply."); return PM3_ETIMEOUT; } diff --git a/client/src/cmdlffdx.c b/client/src/cmdlffdx.c index 28d3ff12c..496dad691 100644 --- a/client/src/cmdlffdx.c +++ b/client/src/cmdlffdx.c @@ -49,7 +49,7 @@ static int CmdHelp(const char *Cmd); static int usage_lf_fdx_clone(void) { - PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "Usage: lf fdx clone [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); @@ -58,7 +58,7 @@ static int usage_lf_fdx_clone(void) { PrintAndLogEx(NORMAL, " : Extended data"); //reserved/rfu //is animal tag - PrintAndLogEx(NORMAL, " : Specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : Specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone 999 112233")); @@ -292,7 +292,36 @@ static int CmdFdxDemod(const char *Cmd) { } static int CmdFdxRead(const char *Cmd) { - lf_read(false, 10000); + sample_config config; + memset(&config, 0, sizeof(sample_config)); + int retval = lf_getconfig(&config); + if (retval != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to get current device LF config"); + return retval; + } + int16_t tmp_div = config.divisor; + if (tmp_div != LF_DIVISOR_134) { + config.divisor = LF_DIVISOR_134; + config.verbose = false; + retval = lf_config(&config); + if (retval != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to change LF configuration"); + return retval; + } + } + retval = lf_read(false, 10000); + if (retval != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to get LF read from device"); + return retval; + } + if (tmp_div != LF_DIVISOR_134) { + config.divisor = tmp_div; + retval = lf_config(&config); + if (retval != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to restore LF configuration"); + return retval; + } + } return CmdFdxDemod(Cmd); } @@ -321,8 +350,9 @@ static int CmdFdxClone(const char *Cmd) { uint32_t blocks[5] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0, 0}; //Q5 - if (tolower(param_getchar(Cmd, 2)) == 'q') - blocks[0] = T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 2)) == 'q'; + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT; // convert from bit stream to block data blocks[1] = bytebits_to_byte(bits, 32); @@ -332,7 +362,7 @@ static int CmdFdxClone(const char *Cmd) { free(bits); - PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: " _GREEN_("%04u-%"PRIu64)" (extended 0x%X)", countryid, animalid, extended); + PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64)" (extended 0x%X)", (q5) ? "Q5/T5555" : "T55x7", countryid, animalid, extended); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -392,8 +422,8 @@ static int CmdFdxSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "this help"}, {"demod", CmdFdxDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"}, - {"read", CmdFdxRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"clone", CmdFdxClone, IfPm3Lf, "clone animal ID tag to T55x7 (or to q5/T5555)"}, + {"read", CmdFdxRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"}, + {"clone", CmdFdxClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"}, {"sim", CmdFdxSim, IfPm3Lf, "simulate Animal ID tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfgallagher.c b/client/src/cmdlfgallagher.c index 3bd68a89d..3a717bc61 100644 --- a/client/src/cmdlfgallagher.c +++ b/client/src/cmdlfgallagher.c @@ -103,9 +103,9 @@ static int CmdGallagherDemod(const char *Cmd) { for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) { pos = (i * 8) + i; arr[i] = bytebits_to_byte(DemodBuffer + pos, 8); - printf("%d -", pos); + PrintAndLogEx(NORMAL, "%d -" NOLF, pos); } - printf("\n"); + PrintAndLogEx(NORMAL, ""); // crc uint8_t crc = bytebits_to_byte(DemodBuffer + 72, 8); diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c index 746ef7f11..12d39ac71 100644 --- a/client/src/cmdlfguard.c +++ b/client/src/cmdlfguard.c @@ -27,15 +27,16 @@ static int CmdHelp(const char *Cmd); static int usage_lf_guard_clone(void) { - PrintAndLogEx(NORMAL, "clone a Guardall tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Guardall tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); PrintAndLogEx(NORMAL, "Currently work only on 26bit"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf gprox clone [h] "); + PrintAndLogEx(NORMAL, "Usage: lf gprox clone [h] "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " : format length 26|32|36|40"); - PrintAndLogEx(NORMAL, " : 8-bit value facility code"); - PrintAndLogEx(NORMAL, " : 16-bit value card number"); + PrintAndLogEx(NORMAL, " : format length 26|32|36|40"); + PrintAndLogEx(NORMAL, " : 8-bit value facility code"); + PrintAndLogEx(NORMAL, " : 16-bit value card number"); + PrintAndLogEx(NORMAL, " : Specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf gprox clone 26 123 11223")); @@ -175,8 +176,9 @@ static int CmdGuardClone(const char *Cmd) { } // Q5 - if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') - blocks[0] = T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 3)) == 'q'; + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT; blocks[1] = bytebits_to_byte(bs, 32); blocks[2] = bytebits_to_byte(bs + 32, 32); @@ -184,7 +186,7 @@ static int CmdGuardClone(const char *Cmd) { free(bs); - PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); + PrintAndLogEx(INFO, "Preparing to clone Guardall to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -241,7 +243,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "this help"}, {"demod", CmdGuardDemod, AlwaysAvailable, "demodulate a G Prox II tag from the GraphBuffer"}, {"read", CmdGuardRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"}, - {"clone", CmdGuardClone, IfPm3Lf, "clone Guardall tag to T55x7"}, + {"clone", CmdGuardClone, IfPm3Lf, "clone Guardall tag to T55x7 or Q5/T5555"}, {"sim", CmdGuardSim, IfPm3Lf, "simulate Guardall tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index 4e9cf467b..94500dbcf 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -557,7 +557,7 @@ static int CmdIndalaClone(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "lf indala clone", - "clone INDALA tag to T55x7 (or to q5/T5555)", + "clone INDALA UID to T55x7 or Q5/T5555 tag", "Examples:\n" _YELLOW_("\tlf indala clone --heden 888\n") _YELLOW_("\tlf indala clone --fc 123 --cn 1337\n") @@ -566,11 +566,11 @@ static int CmdIndalaClone(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_lit0("lL", "long", "optional - long UID 224 bits"), - arg_int0("cC", "heden", "", "Cardnumber for Heden 2L format"), - arg_strx0("rR", "raw", "", "raw bytes"), - arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"), - arg_int0("", "fc", "", "Facility Code (26 bit format)"), + arg_lit0("lL", "long", "optional - long UID 224 bits"), + arg_int0("cC", "heden", "", "Cardnumber for Heden 2L format"), + arg_strx0("rR", "raw", "", "raw bytes"), + arg_lit0("qQ", "Q5", "optional - specify writing to Q5/T5555 tag"), + arg_int0("", "fc", "", "Facility Code (26 bit format)"), arg_int0("", "cn", "", "Cardnumber (26 bit format)"), arg_param_end }; @@ -604,7 +604,7 @@ static int CmdIndalaClone(const char *Cmd) { PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen)); if (is_t5555) - blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT); + blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT); else blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); @@ -656,7 +656,7 @@ static int CmdIndalaClone(const char *Cmd) { PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen)); if (is_t5555) - blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT); + blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT); else blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT); @@ -677,7 +677,7 @@ static command_t CommandTable[] = { {"demod", CmdIndalaDemod, AlwaysAvailable, "demodulate an indala tag (PSK1) from GraphBuffer"}, {"altdemod", CmdIndalaDemodAlt, AlwaysAvailable, "alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)"}, {"read", CmdIndalaRead, IfPm3Lf, "read an Indala Prox tag from the antenna"}, - {"clone", CmdIndalaClone, IfPm3Lf, "clone Indala tag to T55x7"}, + {"clone", CmdIndalaClone, IfPm3Lf, "clone Indala tag to T55x7 or Q5/T5555"}, {"sim", CmdIndalaSim, IfPm3Lf, "simulate Indala tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfio.c b/client/src/cmdlfio.c index ce49804a3..1c3b676f6 100644 --- a/client/src/cmdlfio.c +++ b/client/src/cmdlfio.c @@ -59,16 +59,16 @@ static int usage_lf_io_sim(void) { } static int usage_lf_io_clone(void) { - PrintAndLogEx(NORMAL, "Enables cloning of IOProx card with specified facility-code and card number onto T55x7."); + PrintAndLogEx(NORMAL, "Enables cloning of IOProx card with specified facility-code and card number onto T55x7 or Q5/T5555 tag"); PrintAndLogEx(NORMAL, "The T55x7 must be on the antenna when issuing this command. T55x7 blocks are calculated and printed in the process."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf io clone [h] [Q5]"); + PrintAndLogEx(NORMAL, "Usage: lf io clone [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : 8bit version (" _YELLOW_("decimal") ")"); PrintAndLogEx(NORMAL, " : 8bit value facility code (" _YELLOW_("hex") ")"); PrintAndLogEx(NORMAL, " : 16bit value card number (" _YELLOW_("decimal") ")"); - PrintAndLogEx(NORMAL, " Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); + PrintAndLogEx(NORMAL, " : optional - specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf io clone 01 101 1337")); @@ -274,13 +274,14 @@ static int CmdIOProxClone(const char *Cmd) { uint32_t blocks[3] = {T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_64 | 2 << T55x7_MAXBLOCK_SHIFT, 0, 0}; - if (tolower(param_getchar(Cmd, 3) == 'q')) - blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 3) == 'q'); + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT; blocks[1] = bytebits_to_byte(bits, 32); blocks[2] = bytebits_to_byte(bits + 32, 32); - PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn); + PrintAndLogEx(INFO, "Preparing to clone IOProx to " _YELLOW_("%s") " with Version: %u FC: %u, CN: %u", (q5) ? "Q5/T5555" : "T55x7", version, fc, cn); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -293,7 +294,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "this help"}, {"demod", CmdIOProxDemod, AlwaysAvailable, "demodulate an IOProx tag from the GraphBuffer"}, {"read", CmdIOProxRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"clone", CmdIOProxClone, IfPm3Lf, "clone IOProx tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdIOProxClone, IfPm3Lf, "clone IOProx tag to T55x7 or Q5/T5555"}, {"sim", CmdIOProxSim, IfPm3Lf, "simulate IOProx tag"}, {"watch", CmdIOProxWatch, IfPm3Lf, "continuously watch for cards. Reader mode"}, {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdlfjablotron.c b/client/src/cmdlfjablotron.c index a2859fbb4..a831436e2 100644 --- a/client/src/cmdlfjablotron.c +++ b/client/src/cmdlfjablotron.c @@ -30,12 +30,12 @@ static int CmdHelp(const char *Cmd); static int usage_lf_jablotron_clone(void) { - PrintAndLogEx(NORMAL, "clone a Jablotron tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Jablotron tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "Usage: lf jablotron clone [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : jablotron card ID"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf jablotron clone 112233")); @@ -153,8 +153,9 @@ static int CmdJablotronClone(const char *Cmd) { fullcode = param_get64ex(Cmd, 0, 0, 16); //Q5 - if (tolower(param_getchar(Cmd, 1)) == 'q') - blocks[0] = T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 1)) == 'q'; + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 2 << T5555_MAXBLOCK_SHIFT; // clearing the topbit needed for the preambl detection. if ((fullcode & 0x7FFFFFFFFF) != fullcode) { @@ -178,7 +179,7 @@ static int CmdJablotronClone(const char *Cmd) { free(bits); - PrintAndLogEx(INFO, "Preparing to clone Jablotron to T55x7 with FullCode: %"PRIx64, fullcode); + PrintAndLogEx(INFO, "Preparing to clone Jablotron to " _YELLOW_("%s") " with FullCode: %"PRIx64, (q5) ? "Q5/T5555" : "T55x7", fullcode); print_blocks(blocks, ARRAYLEN(blocks)); return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -234,7 +235,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdJablotronDemod, AlwaysAvailable, "Demodulate an Jablotron tag from the GraphBuffer"}, {"read", CmdJablotronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdJablotronClone, IfPm3Lf, "clone jablotron tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdJablotronClone, IfPm3Lf, "clone jablotron tag to T55x7 or Q5/T5555"}, {"sim", CmdJablotronSim, IfPm3Lf, "simulate jablotron tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c index 7bf36c18e..a0edff920 100644 --- a/client/src/cmdlfkeri.c +++ b/client/src/cmdlfkeri.c @@ -28,21 +28,21 @@ static int CmdHelp(const char *Cmd); static int usage_lf_keri_clone(void) { - PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 or Q5/T5555 tag\n"); PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] "); - PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t [f ] c [Q5]"); + PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t [f ] [c ] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : Keri Internal ID"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); // New format - PrintAndLogEx(NORMAL, " [m|i] : Type. m - MS, i - Internal ID"); + PrintAndLogEx(NORMAL, " [m|i] : Type m - MS, i - Internal ID"); PrintAndLogEx(NORMAL, " : Facility Code"); PrintAndLogEx(NORMAL, " : Card Number"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone 112233")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone type ms fc 6 cn 12345")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t i fc 6 cn 12345")); PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t m f 6 c 12345")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -212,8 +212,6 @@ int demodKeri(void) { return PM3_SUCCESS; } - - static int CmdKeriRead(const char *Cmd) { lf_read(false, 10000); return CmdKeriDemod(Cmd); @@ -221,6 +219,7 @@ static int CmdKeriRead(const char *Cmd) { static int CmdKeriClone(const char *Cmd) { + bool q5 = false; uint8_t cmdidx = 0; char keritype = 'i'; // default to internalid uint32_t fc = 0; @@ -263,11 +262,8 @@ static int CmdKeriClone(const char *Cmd) { cmdidx += 2; break; case 'q': // q5 - blocks[0] = - T5555_MODULATION_PSK1 | - T5555_SET_BITRATE(128) | - T5555_PSK_RF_2 | - 2 << T5555_MAXBLOCK_SHIFT; + blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; + q5 = true; cmdidx++; break; default: @@ -290,7 +286,7 @@ static int CmdKeriClone(const char *Cmd) { // Prepare and write to card // 3 LSB is ONE uint64_t data = ((uint64_t)internalid << 3) + 7; - PrintAndLogEx(INFO, "Preparing to clone KERI to T55x7 with Internal Id: %" PRIx32, internalid); + PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), (q5) ? "Q5/T5555" : "T55x7", internalid); blocks[1] = data >> 32; blocks[2] = data & 0xFFFFFFFF; @@ -348,7 +344,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdKeriDemod, AlwaysAvailable, "Demodulate an KERI tag from the GraphBuffer"}, {"read", CmdKeriRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdKeriClone, IfPm3Lf, "clone KERI tag to T55x7 or Q5/T5555"}, {"sim", CmdKeriSim, IfPm3Lf, "simulate KERI tag"}, {NULL, NULL, NULL, NULL} }; @@ -370,21 +366,25 @@ int detectKeri(uint8_t *dest, size_t *size, bool *invert) { uint8_t preamble[] = {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; // sanity check. - if (*size < sizeof(preamble) + 100) return -1; + if (*size < sizeof(preamble)) return -1; size_t startIdx = 0; + size_t found_size = *size; - if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) { + if (!preambleSearch(dest, preamble, sizeof(preamble), &found_size, &startIdx)) { + found_size = *size; // if didn't find preamble try again inverting uint8_t preamble_i[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; - if (!preambleSearch(DemodBuffer, preamble_i, sizeof(preamble_i), size, &startIdx)) + if (!preambleSearch(DemodBuffer, preamble_i, sizeof(preamble_i), &found_size, &startIdx)) return -2; *invert ^= 1; } - if (*size < 64) return -3; //wrong demoded size + if (found_size < 64) return -3; //wrong demoded size + + *size = found_size; return (int)startIdx; } diff --git a/client/src/cmdlfmotorola.c b/client/src/cmdlfmotorola.c index 0a52f570a..5cad8028c 100644 --- a/client/src/cmdlfmotorola.c +++ b/client/src/cmdlfmotorola.c @@ -173,7 +173,7 @@ static int CmdMotorolaClone(const char *Cmd) { CLIParserFree(ctx); //TODO add selection of chip for Q5 or T55x7 - // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; + // data[0] = T5555_FIXED | T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; // config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2) PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag with RawID %s", sprint_hex(data, datalen)); diff --git a/client/src/cmdlfnedap.c b/client/src/cmdlfnedap.c index ddd734eb3..8fd01ff9f 100644 --- a/client/src/cmdlfnedap.c +++ b/client/src/cmdlfnedap.c @@ -9,18 +9,21 @@ #include "cmdlfnedap.h" +#define _GNU_SOURCE #include #include #include + #include "cmdparser.h" // command_t #include "comms.h" #include "crc16.h" -#include "cmdlft55xx.h" // verifywrite +#include "cmdlft55xx.h" // verify write #include "ui.h" #include "cmddata.h" #include "cmdlf.h" #include "lfdemod.h" +#include "protocols.h" #define FIXED_71 0x71 #define FIXED_40 0x40 @@ -47,16 +50,16 @@ static int usage_lf_nedap_gen(void) { } static int usage_lf_nedap_clone(void) { - PrintAndLogEx(NORMAL, "clone a Nedap tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Nedap tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf nedap clone [h] [s ] c i [l]"); + PrintAndLogEx(NORMAL, "Usage: lf nedap clone [h] [s ] c i [l] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " s : optional, default=5"); PrintAndLogEx(NORMAL, " c : customerCode"); PrintAndLogEx(NORMAL, " i : ID (max 99999)"); PrintAndLogEx(NORMAL, " l : optional - long (128), default to short (64)"); -// PrintAndLogEx(NORMAL, " Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); + PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf nedap clone s 1 c 123 i 12345")); @@ -399,6 +402,9 @@ static int CmdLfNedapGen(const char *Cmd) { isLong = true; cmdp++; break; + case 'q': + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -449,14 +455,8 @@ static int CmdLFNedapClone(const char *Cmd) { return PM3_ESOFT; } - //CmdPrintDemodBuff("x"); - -// What we had before in commented code: //NEDAP - compat mode, ASK/DIphase, data rate 64, 4 data blocks // DI-phase (CDP) T55x7_MODULATION_DIPHASE -// blocks[0] = T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_64 | 7 << T55x7_MAXBLOCK_SHIFT; -// if (param_getchar(Cmd, 3) == 'Q' || param_getchar(Cmd, 3) == 'q') -// blocks[0] = T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(64) | 7 < "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : Noralsy card ID"); PrintAndLogEx(NORMAL, " : Tag allocation year"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf noralsy clone 112233")); @@ -150,8 +150,9 @@ static int CmdNoralsyClone(const char *Cmd) { year = param_get32ex(Cmd, 1, 2000, 10); //Q5 - if (tolower(param_getchar(Cmd, 2) == 'q')) - blocks[0] = T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 2) == 'q'); + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; uint8_t *bits = calloc(96, sizeof(uint8_t)); if (getnoralsyBits(id, year, bits) != PM3_SUCCESS) { @@ -166,7 +167,7 @@ static int CmdNoralsyClone(const char *Cmd) { free(bits); - PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id); + PrintAndLogEx(INFO, "Preparing to clone Noralsy to " _YELLOW_("%s") " with CardId: %u", (q5) ? "Q5/T5555" : "T55x7", id); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -222,7 +223,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdNoralsyDemod, AlwaysAvailable, "Demodulate an Noralsy tag from the GraphBuffer"}, {"read", CmdNoralsyRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, - {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdNoralsyClone, IfPm3Lf, "clone Noralsy tag to T55x7 or Q5/T5555"}, {"sim", CmdNoralsySim, IfPm3Lf, "simulate Noralsy tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfpresco.c b/client/src/cmdlfpresco.c index c9eb2ce29..051be2126 100644 --- a/client/src/cmdlfpresco.c +++ b/client/src/cmdlfpresco.c @@ -27,13 +27,13 @@ static int CmdHelp(const char *Cmd); static int usage_lf_presco_clone(void) { - PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Presco tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "Usage: lf presco clone [h] d c "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " d : 9 digit presco card ID"); PrintAndLogEx(NORMAL, " c : 8 digit hex card number"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf presco clone d 123456789")); @@ -116,7 +116,7 @@ static int CmdPrescoClone(const char *Cmd) { if (getWiegandFromPresco(Cmd, &sitecode, &usercode, &fullcode, &Q5) == PM3_EINVARG) return usage_lf_presco_clone(); if (Q5) - blocks[0] = T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR; + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT | T5555_ST_TERMINATOR; if ((sitecode & 0xFF) != sitecode) { sitecode &= 0xFF; @@ -133,7 +133,7 @@ static int CmdPrescoClone(const char *Cmd) { blocks[3] = 0x00000000; blocks[4] = fullcode; - PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode); + PrintAndLogEx(INFO, "Preparing to clone Presco to " _YELLOW_("%s") " with SiteCode: %u, UserCode: %u, FullCode: %08x", (Q5) ? "Q5/T5555" : "T55x7", sitecode, usercode, fullcode); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -179,7 +179,7 @@ static int CmdPrescoSim(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"read", CmdPrescoRead, IfPm3Lf, "Attempt to read and Extract tag data"}, - {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdPrescoClone, IfPm3Lf, "clone presco tag to T55x7 or Q5/T5555"}, {"sim", CmdPrescoSim, IfPm3Lf, "simulate presco tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfpyramid.c b/client/src/cmdlfpyramid.c index 71fe1ab7e..b4ad5564f 100644 --- a/client/src/cmdlfpyramid.c +++ b/client/src/cmdlfpyramid.c @@ -31,7 +31,7 @@ static int CmdHelp(const char *Cmd); static int usage_lf_pyramid_clone(void) { - PrintAndLogEx(NORMAL, "clone a Farpointe/Pyramid tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Farpointe/Pyramid tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "The facility-code is 8-bit and the card number is 16-bit. Larger values are truncated. "); PrintAndLogEx(NORMAL, "Currently only works on 26bit"); PrintAndLogEx(NORMAL, ""); @@ -40,7 +40,7 @@ static int usage_lf_pyramid_clone(void) { PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " : 8-bit value facility code"); PrintAndLogEx(NORMAL, " : 16-bit value card number"); - PrintAndLogEx(NORMAL, " Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); + PrintAndLogEx(NORMAL, " Q5 : optional - specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf pyramid clone 123 11223")); @@ -242,8 +242,9 @@ static int CmdPyramidClone(const char *Cmd) { blocks[0] = T55x7_MODULATION_FSK2a | T55x7_BITRATE_RF_50 | 4 << T55x7_MAXBLOCK_SHIFT; // Q5 - if (param_getchar(Cmd, 2) == 'Q' || param_getchar(Cmd, 2) == 'q') - blocks[0] = T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 4 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 2)) == 'q'; + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(50) | 4 << T5555_MAXBLOCK_SHIFT; blocks[1] = bytebits_to_byte(bs, 32); blocks[2] = bytebits_to_byte(bs + 32, 32); @@ -252,7 +253,7 @@ static int CmdPyramidClone(const char *Cmd) { free(bs); - PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber); + PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to " _YELLOW_("%s") " with Facility Code: %u, Card Number: %u", (q5) ? "Q5/T5555" : "T55x7", facilitycode, cardnumber); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -308,7 +309,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "this help"}, {"demod", CmdPyramidDemod, AlwaysAvailable, "demodulate a Pyramid FSK tag from the GraphBuffer"}, {"read", CmdPyramidRead, IfPm3Lf, "attempt to read and extract tag data"}, - {"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdPyramidClone, IfPm3Lf, "clone pyramid tag to T55x7 or Q5/T5555"}, {"sim", CmdPyramidSim, IfPm3Lf, "simulate pyramid tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index dd28071cd..bc84fc3f8 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -86,7 +86,7 @@ static int usage_t55xx_config(void) { PrintAndLogEx(NORMAL, " d - Set demodulation FSK / ASK / PSK / NRZ / Biphase / Biphase A"); PrintAndLogEx(NORMAL, " i [0/1] - Set/reset data signal inversion"); PrintAndLogEx(NORMAL, " o [offset] - Set offset, where data should start decode in bitstream"); - PrintAndLogEx(NORMAL, " Q5 [0/1] - Set/reset as T5555 ( Q5 ) chip instead of T55x7"); + PrintAndLogEx(NORMAL, " Q5 [0/1] - Set/reset as Q5/T5555 chip instead of T55x7"); PrintAndLogEx(NORMAL, " ST [0/1] - Set/reset Sequence Terminator on"); PrintAndLogEx(NORMAL, ""); // layout is a little differnet, so seperate until a better fix print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode); @@ -311,11 +311,11 @@ static int usage_t55xx_wipe(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " c - set configuration from a block0"); - PrintAndLogEx(NORMAL, " q - indicates to use T5555 ( Q5 ) default configuration block"); + PrintAndLogEx(NORMAL, " q - indicates to use Q5/T5555 default configuration block"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wipe") " - wipes a T55x7 tag, config block 0x000880E0"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wipe q") " - wipes a T5555 ( Q5 ) tag, config block 0x6001F004"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx wipe q") " - wipes a Q5/T5555 tag, config block 0x6001F004"); return PM3_SUCCESS; } static int usage_t55xx_deviceconfig(void) { @@ -829,7 +829,7 @@ static int CmdT55xxSetConfig(const char *Cmd) { return printConfiguration(config); } int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode) { - return T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, true); + return T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, false); } int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, bool verbose) { @@ -994,7 +994,7 @@ static int SanityOfflineCheck(bool useGraphBuffer) { static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) { char msg[80]; - sprintf(msg, "Downlink Mode used : "); + snprintf(msg, sizeof(msg), "Downlink Mode used : "); switch (downlink_mode) { case 1 : @@ -1075,7 +1075,7 @@ static int CmdT55xxDetect(const char *Cmd) { continue; found = true; - + break; } } else { @@ -1587,7 +1587,7 @@ int special(const char *Cmd) { } int printConfiguration(t55xx_conf_block_t b) { - PrintAndLogEx(INFO, " Chip Type : " _GREEN_("%s"), (b.Q5) ? "T5555 ( Q5 )" : "T55x7"); + PrintAndLogEx(INFO, " Chip Type : " _GREEN_("%s"), (b.Q5) ? "Q5/T5555" : "T55x7"); PrintAndLogEx(INFO, " Modulation : " _GREEN_("%s"), GetSelectedModulationStr(b.modulation)); PrintAndLogEx(INFO, " Bit Rate : %s", GetBitRateStr(b.bitrate, (b.block0 & T55x7_X_MODE && (b.block0 >> 28 == 6 || b.block0 >> 28 == 9)))); PrintAndLogEx(INFO, " Inverted : %s", (b.inverted) ? _GREEN_("Yes") : "No"); @@ -1864,7 +1864,7 @@ static int CmdT55xxReadTrace(const char *Cmd) { si += 9; if (hdr != 0x1FF) { - PrintAndLogEx(FAILED, "Invalid T555 ( Q5 ) Trace data header (expected 0x1FF, found %X)", hdr); + PrintAndLogEx(FAILED, "Invalid Q5/T5555 Trace data header (expected 0x1FF, found %X)", hdr); return PM3_ESOFT; } @@ -1955,7 +1955,7 @@ static int CmdT55xxReadTrace(const char *Cmd) { } void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat) { - PrintAndLogEx(NORMAL, "-- T55x7 Trace Information ----------------------------------"); + PrintAndLogEx(NORMAL, "--- " _CYAN_("T55x7 Trace Information") " ----------------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, " ACL Allocation class (ISO/IEC 15963-1) : 0x%02X (%d)", data.acl, data.acl); PrintAndLogEx(NORMAL, " MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getTagInfo(data.mfc)); @@ -2002,7 +2002,7 @@ void printT55x7Trace(t55x7_tracedata_t data, uint8_t repeat) { } void printT5555Trace(t5555_tracedata_t data, uint8_t repeat) { - PrintAndLogEx(NORMAL, "-- T5555 ( Q5 ) Trace Information ---------------------------"); + PrintAndLogEx(NORMAL, "--- " _CYAN_("Q5/T5555 Trace Information") " ---------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, " ICR IC Revision : %d", data.icr); PrintAndLogEx(NORMAL, " Lot : %c%d", data.lotidc, data.lotid); @@ -2327,7 +2327,7 @@ static int CmdT55xxDump(const char *Cmd) { strcpy(preferredName, "lf-t55xx"); for (uint8_t i = 1; i <= 7; i++) { if ((cardmem[i].blockdata != 0x00) && (cardmem[i].blockdata != 0xFFFFFFFF)) - sprintf(preferredName + strlen(preferredName), "-%08X", cardmem[i].blockdata); + snprintf(preferredName + strlen(preferredName), sizeof(preferredName) - strlen(preferredName), "-%08X", cardmem[i].blockdata); else break; } @@ -2416,7 +2416,7 @@ static int CmdT55xxRestore(const char *Cmd) { if (success == PM3_SUCCESS) { // Got data, so write to cards if (datalen == T55x7_BLOCK_COUNT * 4) { // 12 blocks * 4 bytes per block if (usepwd) - sprintf(pwdOpt, "p %08X", password); + snprintf(pwdOpt, sizeof(pwdOpt), "p %08X", password); // Restore endien for writing to card for (blockidx = 0; blockidx < 12; blockidx++) @@ -2433,18 +2433,20 @@ static int CmdT55xxRestore(const char *Cmd) { // write out blocks 1-7 page 0 for (blockidx = 1; blockidx <= 7; blockidx++) { - sprintf(writeCmdOpt, "b %d d %08X %s", blockidx, data[blockidx], pwdOpt); + snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b %d d %08X %s", blockidx, data[blockidx], pwdOpt); + if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) PrintAndLogEx(WARNING, "Warning: error writing blk %d", blockidx); } // if password was set on the "blank" update as we may have just changed it if (usepwd) - sprintf(pwdOpt, "p %08X", data[7]); + snprintf(pwdOpt, sizeof(pwdOpt), "p %08X", data[7]); // write out blocks 1-3 page 1 for (blockidx = 9; blockidx <= 11; blockidx++) { - sprintf(writeCmdOpt, "b %d 1 d %08X %s", blockidx - 8, data[blockidx], pwdOpt); + snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b %d 1 d %08X %s", blockidx - 8, data[blockidx], pwdOpt); + if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) PrintAndLogEx(WARNING, "Warning: error writing blk %d", blockidx); } @@ -2453,7 +2455,7 @@ static int CmdT55xxRestore(const char *Cmd) { config.downlink_mode = downlink_mode; // Write the page 0 config - sprintf(writeCmdOpt, "b 0 d %08X %s", data[0], pwdOpt); + snprintf(writeCmdOpt, sizeof(writeCmdOpt), "b 0 d %08X %s", data[0], pwdOpt); if (CmdT55xxWriteBlock(writeCmdOpt) != PM3_SUCCESS) PrintAndLogEx(WARNING, "Warning: error writing blk 0"); } @@ -2811,7 +2813,7 @@ static void t55x7_create_config_block(int tagtype) { snprintf(retStr, sizeof(buf), "%08X - T55X7 Raw", T55X7_RAW_CONFIG_BLOCK); break; case 2: - snprintf(retStr, sizeof(buf), "%08X - T5555 ( Q5 ) Default", T5555_DEFAULT_CONFIG_BLOCK); + snprintf(retStr, sizeof(buf), "%08X - Q5/T5555 Default", T5555_DEFAULT_CONFIG_BLOCK); break; default: break; @@ -2916,7 +2918,7 @@ static int CmdT55xxWipe(const char *Cmd) { if (errors) return usage_t55xx_wipe(); - PrintAndLogEx(INFO, "\nBegin wiping %s", (Q5) ? "T5555 ( Q5 ) tag" : "T55x7 tag"); + PrintAndLogEx(INFO, "\nBegin wiping " _YELLOW_("%s")" tag", (Q5) ? "Q5/T5555" : "T55x7"); // default config blocks. if (gotconf == false) { @@ -3039,18 +3041,18 @@ static int CmdT55xxChkPwds(const char *Cmd) { while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) { timeout++; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 180) { PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); return PM3_ENODATA; } } + PrintAndLogEx(NORMAL, ""); struct p { bool found; uint32_t candidate; } PACKED; - struct p* packet = (struct p*)resp.data.asBytes; + struct p *packet = (struct p *)resp.data.asBytes; if (packet->found) { PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate); @@ -3178,8 +3180,7 @@ static int CmdT55xxBruteForce(const char *Cmd) { while (found == 0) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); if (IsCancelled()) { return PM3_EOPABORTED; @@ -3223,7 +3224,7 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) { if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) { // if (getSignalProperties()->isnoise == false) { // } else { - if (tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0 ,password)) { + if (tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) { return 1 + (dl_mode << 1); } // } diff --git a/client/src/cmdlfviking.c b/client/src/cmdlfviking.c index 445dbc209..205ea94b3 100644 --- a/client/src/cmdlfviking.c +++ b/client/src/cmdlfviking.c @@ -27,15 +27,15 @@ static int CmdHelp(const char *Cmd); static int usage_lf_viking_clone(void) { - PrintAndLogEx(NORMAL, "clone a Viking AM tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Viking AM tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "Usage: lf viking clone "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " : 8 digit hex viking card number"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337 Q5")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf viking clone 1A337 Q5") " - encode for Q5/T5555 tag"); return PM3_SUCCESS; } @@ -114,7 +114,11 @@ static int CmdVikingClone(const char *Cmd) { num_to_bytes(rawID, 8, &payload.blocks[0]); - PrintAndLogEx(INFO, "Preparing to clone Viking tag - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s"), id, sprint_hex(payload.blocks, sizeof(payload.blocks))); + PrintAndLogEx(INFO, "Preparing to clone Viking tag on " _YELLOW_("%s") " - ID " _YELLOW_("%08X")" raw " _YELLOW_("%s") + , (Q5) ? "Q5/T5555" : "T55x7" + , id + , sprint_hex(payload.blocks, sizeof(payload.blocks)) + ); clearCommandBuffer(); @@ -169,7 +173,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdVikingDemod, AlwaysAvailable, "Demodulate a Viking tag from the GraphBuffer"}, {"read", CmdVikingRead, IfPm3Lf, "Attempt to read and Extract tag data from the antenna"}, - {"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdVikingClone, IfPm3Lf, "clone Viking tag to T55x7 or Q5/T5555"}, {"sim", CmdVikingSim, IfPm3Lf, "simulate Viking tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdlfvisa2000.c b/client/src/cmdlfvisa2000.c index 4260fe6d4..bd25d9d89 100644 --- a/client/src/cmdlfvisa2000.c +++ b/client/src/cmdlfvisa2000.c @@ -33,15 +33,16 @@ static int CmdHelp(const char *Cmd); static int usage_lf_visa2k_clone(void) { - PrintAndLogEx(NORMAL, "clone a Visa2000 tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a Visa2000 tag to a T55x7 or Q5/T5555 tag."); PrintAndLogEx(NORMAL, "Usage: lf visa2000 clone [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " : Visa2k card ID"); - PrintAndLogEx(NORMAL, " : specify write to Q5 (t5555 instead of t55x7)"); + PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 q5") " -- encode for Q5/T5555"); return PM3_SUCCESS; } @@ -177,13 +178,14 @@ static int CmdVisa2kClone(const char *Cmd) { id = param_get32ex(Cmd, 0, 0, 10); //Q5 - if (tolower(param_getchar(Cmd, 1)) == 'q') - blocks[0] = T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; + bool q5 = tolower(param_getchar(Cmd, 1)) == 'q'; + if (q5) + blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT; blocks[2] = id; blocks[3] = (visa_parity(id) << 4) | visa_chksum(id); - PrintAndLogEx(INFO, "Preparing to clone Visa2000 to T55x7 with CardId: %"PRIu64, id); + PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, (q5) ? "Q5/T5555" : "T55x7", id); print_blocks(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -233,7 +235,7 @@ static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdVisa2kDemod, AlwaysAvailable, "demodulate an VISA2000 tag from the GraphBuffer"}, {"read", CmdVisa2kRead, IfPm3Lf, "attempt to read and extract tag data from the antenna"}, - {"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 (or to q5/T5555)"}, + {"clone", CmdVisa2kClone, IfPm3Lf, "clone Visa2000 tag to T55x7 or Q5/T5555"}, {"sim", CmdVisa2kSim, IfPm3Lf, "simulate Visa2000 tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index bc4753b6a..69539362f 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -885,7 +885,7 @@ static void smart_brute_prim(void) { static int smart_brute_sfi(bool decodeTLV) { uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); - if (!buf) + if (buf == NULL) return 1; int len; @@ -895,8 +895,7 @@ static int smart_brute_sfi(bool decodeTLV) { for (uint8_t sfi = 1; sfi <= 31; sfi++) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); for (uint16_t rec = 1; rec <= 255; rec++) { @@ -1024,8 +1023,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { for (int i = 0; i < json_array_size(root); i++) { - printf("+"); - fflush(stdout); + PrintAndLogEx(NORMAL, "+" NOLF); if (caid) free(caid); @@ -1033,21 +1031,21 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { json_t *data, *jaid; data = json_array_get(root, i); - if (!json_is_object(data)) { - PrintAndLogEx(ERR, "data %d is not an object\n", i + 1); + if (json_is_object(data) == false) { + PrintAndLogEx(ERR, "\ndata %d is not an object\n", i + 1); json_decref(root); return PM3_ESOFT; } jaid = json_object_get(data, "AID"); - if (!json_is_string(jaid)) { - PrintAndLogEx(ERR, "AID data [%d] is not a string", i + 1); + if (json_is_string(jaid) == false) { + PrintAndLogEx(ERR, "\nAID data [%d] is not a string", i + 1); json_decref(root); return PM3_ESOFT; } const char *aid = json_string_value(jaid); - if (!aid) + if (aid == false) continue; size_t aidlen = strlen(aid); @@ -1069,7 +1067,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { json_t *jvendor, *jname; jvendor = json_object_get(data, "Vendor"); - if (!json_is_string(jvendor)) { + if (json_is_string(jvendor) == false) { PrintAndLogEx(ERR, "Vendor data [%d] is not a string", i + 1); continue; } @@ -1079,7 +1077,7 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { continue; jname = json_object_get(data, "Name"); - if (!json_is_string(jname)) { + if (json_is_string(jname) == false) { PrintAndLogEx(ERR, "Name data [%d] is not a string", i + 1); continue; } diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 04bb64f95..0af9de005 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -245,6 +245,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case ISO_14443A: case MFDES: case LTO: + case ISO_7816_4: crcStatus = iso14443A_CRC_check(hdr->isResponse, frame, data_len); break; case THINFILM: @@ -260,7 +261,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr crcStatus = iso15693_CRC_check(frame, data_len); break; case PROTO_CRYPTORF: - case ISO_7816_4: case PROTO_HITAG1: case PROTO_HITAG2: case PROTO_HITAGS: @@ -334,10 +334,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr // Draw the CRC column const char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); - // mark short bytes (less than 8 Bit + Parity) - if (protocol == ISO_14443A || - protocol == PROTO_MIFARE || - protocol == THINFILM) { + // mark short bytes (less than 8 Bit + Parity) + if (protocol == ISO_14443A || + protocol == PROTO_MIFARE || + protocol == THINFILM) { // approximated with 128 * (9 * data_len); uint16_t bitime = 1056 + 32; @@ -346,17 +346,17 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr uint8_t m = 7; while (m > 0) { - bitime -= 128; - if ( duration > bitime) { + bitime -= 128; + if (duration > bitime) { break; - } + } m--; } - line[(data_len-1)/16][((data_len-1)%16) * 4 + 2] = '('; - line[(data_len-1)/16][((data_len-1)%16) * 4 + 3] = m + 0x30; - line[(data_len-1)/16][((data_len-1)%16) * 4 + 4] = ')'; - } - } + line[(data_len - 1) / 16][((data_len - 1) % 16) * 4 + 2] = '('; + line[(data_len - 1) / 16][((data_len - 1) % 16) * 4 + 3] = m + 0x30; + line[(data_len - 1) / 16][((data_len - 1) % 16) * 4 + 4] = ')'; + } + } uint32_t previous_end_of_transmission_timestamp = 0; @@ -388,8 +388,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); break; case ICLASS: - annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); - break; + annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); + break; default: break; } @@ -413,6 +413,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr annotateTopaz(explanation, sizeof(explanation), frame, data_len); break; case ISO_7816_4: + annotateIso14443a(explanation, sizeof(explanation), frame, data_len); annotateIso7816(explanation, sizeof(explanation), frame, data_len); break; case ISO_15693: diff --git a/client/src/comms.c b/client/src/comms.c index ad82725f3..416225c0f 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -298,13 +298,13 @@ static void PacketResponseReceived(PacketResponseNG *packet) { PrintAndLogEx(NORMAL, "[" _BLUE_("#") "] %s", s); } else { if (flag & FLAG_INPLACE) - printf("\r"); - printf("%s", s); - if (flag & FLAG_NEWLINE) - printf("\r\n"); - } + PrintAndLogEx(NORMAL, "\r" NOLF); - fflush(stdout); + PrintAndLogEx(NORMAL, "%s" NOLF, s); + + if (flag & FLAG_NEWLINE) + PrintAndLogEx(NORMAL, ""); + } break; } case CMD_DEBUG_PRINT_INTEGERS: { diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index a00918b91..2ed0b6bc7 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -24,8 +24,8 @@ #include #include #include -#include - +#include "util.h" +#include "ui.h" // NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) { uint8_t iiv[16] = {0}; @@ -416,10 +416,10 @@ int ecdsa_nist_test(bool verbose) { // NIST ecdsa test if (verbose) - printf(" ECDSA NIST test: "); + PrintAndLogEx(INFO, " ECDSA NIST test: " NOLF); // make signature res = ecdsa_signature_create_test(curveid, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen); -// printf("res: %x signature[%x]: %s\n", (res<0)?-res:res, siglen, sprint_hex(signature, siglen)); +// PrintAndLogEx(INFO, "res: %x signature[%x]: %s", (res < 0)? -res : res, siglen, sprint_hex(signature, siglen)); if (res) goto exit; @@ -436,7 +436,7 @@ int ecdsa_nist_test(bool verbose) { uint8_t sval_s[33] = {0}; param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen); if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) { - printf("R or S check error\n"); + PrintAndLogEx(INFO, "R or S check error"); res = 100; goto exit; } @@ -449,14 +449,14 @@ int ecdsa_nist_test(bool verbose) { // verify wrong signature input[0] ^= 0xFF; res = ecdsa_signature_verify_keystr(curveid, T_Q_X, T_Q_Y, input, length, signature, siglen, true); - if (!res) { + if (res == false) { res = 1; goto exit; } if (verbose) { - printf("passed\n"); - printf(" ECDSA binary signature create/check test: "); + PrintAndLogEx(NORMAL, _GREEN_("passed")); + PrintAndLogEx(INFO, " ECDSA binary signature create/check test: " NOLF); } // random ecdsa test @@ -483,11 +483,11 @@ int ecdsa_nist_test(bool verbose) { goto exit; if (verbose) - printf("passed\n\n"); + PrintAndLogEx(NORMAL, _GREEN_("passed\n")); return 0; exit: if (verbose) - printf("failed\n\n"); + PrintAndLogEx(NORMAL, _RED_("failed\n")); return res; } diff --git a/client/src/emv/emv_roca.c b/client/src/emv/emv_roca.c index 4c42be7e2..0faf59ffb 100644 --- a/client/src/emv/emv_roca.c +++ b/client/src/emv/emv_roca.c @@ -71,7 +71,8 @@ static mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) { if (X->n == 1 && X->s > 0) { return X->p[0]; } - printf("ZERRRRO!!!\n"); + + PrintAndLogEx(WARNING, "ZERRRRO!!!\n"); return 0; } @@ -82,7 +83,7 @@ static void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) { size_t len = 0; mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len); - printf("%s[%zu] %s\n", msg, len, Xchar); + PrintAndLogEx(INFO, "%s[%zu] %s\n", msg, len, Xchar); } */ bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) { diff --git a/client/src/fido/cbortools.c b/client/src/fido/cbortools.c index a7b08e619..7a7a1d25e 100644 --- a/client/src/fido/cbortools.c +++ b/client/src/fido/cbortools.c @@ -11,16 +11,15 @@ // #include "cbortools.h" - #include - #include "emv/emvjson.h" #include "util.h" +#include "ui.h" // PrintAndLogEx( #include "fidocore.h" static void indent(int nestingLevel) { while (nestingLevel--) - printf(" "); + PrintAndLogEx(NORMAL, " " NOLF); } static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { @@ -32,14 +31,14 @@ static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { switch (type) { case CborMapType: case CborArrayType: { - printf(type == CborArrayType ? "Array[" : "Map["); + PrintAndLogEx(NORMAL, "%s" NOLF, (type == CborArrayType) ? "Array[" : "Map["); break; } case CborIntegerType: { int64_t val; cbor_value_get_int64(it, &val); // can't fail - printf("%lld", (long long)val); + PrintAndLogEx(NORMAL, "%lld" NOLF, (long long)val); break; } @@ -50,7 +49,8 @@ static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { *got_next = true; if (err) return err; // parse error - printf("%s", sprint_hex(buf, n)); + + PrintAndLogEx(NORMAL, "%s" NOLF, sprint_hex(buf, n)); free(buf); break; } @@ -62,7 +62,8 @@ static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { *got_next = true; if (err) return err; // parse error - printf("%s", buf); + + PrintAndLogEx(NORMAL, "%s" NOLF, buf); free(buf); break; } @@ -70,29 +71,29 @@ static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { case CborTagType: { CborTag tag; cbor_value_get_tag(it, &tag); - printf("Tag(%lld)", (long long)tag); + PrintAndLogEx(NORMAL, "Tag(%lld)" NOLF, (long long)tag); break; } case CborSimpleType: { uint8_t t; cbor_value_get_simple_type(it, &t); - printf("simple(%u)", t); + PrintAndLogEx(NORMAL, "simple(%u)" NOLF, t); break; } case CborNullType: - printf("null"); + PrintAndLogEx(NORMAL, "null" NOLF); break; case CborUndefinedType: - printf("undefined"); + PrintAndLogEx(NORMAL, "undefined" NOLF); break; case CborBooleanType: { bool val; cbor_value_get_boolean(it, &val); // can't fail - printf("%s", val ? "true" : "false"); + PrintAndLogEx(NORMAL, "%s" NOLF, (val) ? "true" : "false"); break; } @@ -106,18 +107,18 @@ static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { } else { cbor_value_get_double(it, &val); } - printf("%g", val); + PrintAndLogEx(NORMAL, "%g" NOLF, val); break; } case CborHalfFloatType: { uint16_t val; cbor_value_get_half_float(it, &val); - printf("__f16(%04x)", val); + PrintAndLogEx(NORMAL, "__f16(%04x)" NOLF, val); break; } case CborInvalidType: - printf("CborInvalidType!!!"); + PrintAndLogEx(NORMAL, _RED_("CborInvalidType!!!") NOLF); break; } @@ -129,7 +130,7 @@ static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, while (!cbor_value_at_end(it)) { CborError err; CborType type = cbor_value_get_type(it); -//printf("^%x^", type); + bool got_next = false; switch (type) { @@ -140,18 +141,23 @@ static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, assert(cbor_value_is_container(it)); if (!(isMapType && (elmCount % 2))) indent(nestingLevel); - printf(type == CborArrayType ? "Array[\n" : "Map[\n"); + + PrintAndLogEx(NORMAL, "%s" NOLF, (type == CborArrayType) ? "Array[\n" : "Map[\n"); + err = cbor_value_enter_container(it, &recursed); if (err) return err; // parse error + err = dumprecursive(cmdCode, isResponse, &recursed, (type == CborMapType), nestingLevel + 1); if (err) return err; // parse error + err = cbor_value_leave_container(it, &recursed); if (err) return err; // parse error + indent(nestingLevel); - printf("]"); + PrintAndLogEx(NORMAL, "]" NOLF); got_next = true; break; } @@ -170,12 +176,13 @@ static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, err = dumpelm(it, &got_next, (isMapType && (elmCount % 2)) ? 0 : nestingLevel); if (err) return err; + if (cmdCode > 0 && nestingLevel == 1 && isMapType && !(elmCount % 2)) { int64_t val; cbor_value_get_int64(it, &val); const char *desc = fido2GetCmdMemberDescription(cmdCode, isResponse, val); if (desc) - printf(" (%s)", desc); + PrintAndLogEx(NORMAL, " (%s)" NOLF, desc); } break; } @@ -187,9 +194,9 @@ static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, return err; } if (isMapType && !(elmCount % 2)) { - printf(": "); + PrintAndLogEx(NORMAL, ": " NOLF); } else { - printf("\n"); + PrintAndLogEx(NORMAL, ""); } elmCount++; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 0010eae0c..d70fe508d 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -429,18 +429,18 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, } case jsfIclass: { JsonSaveStr(root, "FileType", "iclass"); - + picopass_hdr *hdr = (picopass_hdr *)data; JsonSaveBufAsHexCompact(root, "$.Card.CSN", hdr->csn, sizeof(hdr->csn)); - JsonSaveBufAsHexCompact(root, "$.Card.Configuration",(uint8_t *)&hdr->conf, sizeof(hdr->conf)); + JsonSaveBufAsHexCompact(root, "$.Card.Configuration", (uint8_t *)&hdr->conf, sizeof(hdr->conf)); uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)data; JsonSaveBufAsHexCompact(root, "$.Card.AIA", ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area)); - } else { + } else { JsonSaveBufAsHexCompact(root, "$.Card.Epurse", hdr->epurse, sizeof(hdr->epurse)); - JsonSaveBufAsHexCompact(root, "$.Card.Kd",hdr->key_d, sizeof(hdr->key_d)); + JsonSaveBufAsHexCompact(root, "$.Card.Kd", hdr->key_d, sizeof(hdr->key_d)); JsonSaveBufAsHexCompact(root, "$.Card.Kc", hdr->key_c, sizeof(hdr->key_c)); JsonSaveBufAsHexCompact(root, "$.Card.AIA", hdr->app_issuer_area, sizeof(hdr->app_issuer_area)); } @@ -1483,9 +1483,9 @@ static int filelist(const char *path, const char *ext, uint8_t last, bool tentat char tmp_fullpath[1024] = {0}; strncat(tmp_fullpath, path, sizeof(tmp_fullpath) - 1); strncat(tmp_fullpath, namelist[i]->d_name, strlen(tmp_fullpath) - 1); - + if (is_directory(tmp_fullpath)) { - + char newpath[1024]; if (strcmp(namelist[i]->d_name, ".") == 0 || strcmp(namelist[i]->d_name, "..") == 0) continue; @@ -1496,9 +1496,9 @@ static int filelist(const char *path, const char *ext, uint8_t last, bool tentat filelist(newpath, ext, last + ((i == n - 1) << (indent + 1)), tentative, indent + 1, strlen(path)); } else { - + if ((ext == NULL) || (ext && (str_endswith(namelist[i]->d_name, ext)))) { - + for (uint8_t j = 0; j < indent + 1; j++) { PrintAndLogEx(NORMAL, "%s " NOLF, ((last >> j) & 1) ? " " : "│"); } diff --git a/client/src/loclass/elite_crack.c b/client/src/loclass/elite_crack.c index a811106d3..a559b4e7b 100644 --- a/client/src/loclass/elite_crack.c +++ b/client/src/loclass/elite_crack.c @@ -383,7 +383,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) { // success if (memcmp(calculated_MAC, item.mac, 4) == 0) { - printf("\r\n"); + PrintAndLogEx(NORMAL, ""); for (i = 0 ; i < numbytes_to_recover; i++) { PrintAndLogEx(INFO, "%d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]); } @@ -393,16 +393,15 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) { brute++; if ((brute & 0xFFFF) == 0) { - printf("%3d,", (brute >> 16) & 0xFF); + PrintAndLogEx(NORMAL, "%3d," NOLF, (brute >> 16) & 0xFF); if (((brute >> 16) % 0x10) == 0) - printf("\n"); - fflush(stdout); + PrintAndLogEx(NORMAL, ""); } } int errors = PM3_SUCCESS; - if (!found) { + if (found == false) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Failed to recover %d bytes using the following CSN", numbytes_to_recover); PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8)); diff --git a/client/src/loclass/hash1_brute.c b/client/src/loclass/hash1_brute.c index 1c944b99e..49f2cd3de 100644 --- a/client/src/loclass/hash1_brute.c +++ b/client/src/loclass/hash1_brute.c @@ -7,6 +7,7 @@ #include #include #include "elite_crack.h" +#include "ui.h" static void calc_score(uint8_t *csn, uint8_t *k) { uint8_t score = 0 ; @@ -41,34 +42,33 @@ static void calc_score(uint8_t *csn, uint8_t *k) { } if (score >= 2 && badscore < 2) { - printf("CSN\t%02x%02x%02x%02x%02x%02x%02x%02x\t%02x %02x %02x %02x %02x %02x %02x %02x\t" - , csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7] - , k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7] - ); + PrintAndLogEx(NORMAL, "CSN\t%02x%02x%02x%02x%02x%02x%02x%02x\t%02x %02x %02x %02x %02x %02x %02x %02x\t" NOLF + , csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7] + , k[0], k[1], k[2], k[3], k[4], k[5], k[6], k[7] + ); for (i = 0 ; i < score; i++) { - printf("%d,", uniq_vals[i]); + PrintAndLogEx(NORMAL, "%d," NOLF, uniq_vals[i]); } - printf("\tbadscore: %d (%02x)", badscore, badval); - printf("\r\n"); + PrintAndLogEx(NORMAL, "\tbadscore: %d (%02x)" NOLF, badscore, badval); + PrintAndLogEx(NORMAL, ""); } } void brute_hash1(void) { - uint16_t a, b, c, d; + uint8_t csn[8] = {0, 0, 0, 0, 0xf7, 0xff, 0x12, 0xe0}; uint8_t k[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t testcsn[8] = {0x00, 0x0d, 0x0f, 0xfd, 0xf7, 0xff, 0x12, 0xe0} ; uint8_t testkey[8] = {0x05, 0x01, 0x00, 0x10, 0x45, 0x08, 0x45, 0x56} ; calc_score(testcsn, testkey); - printf("Brute forcing hashones\n"); - //exit(1); - for (a = 0; a < 256; a++) { - //if(a > 0)printf("%d/256 done...\n", a); - for (b = 0; b < 256; b++) - for (c = 0; c < 256; c++) - for (d = 0; d < 256; d++) { + PrintAndLogEx(INFO, "Brute forcing hashones"); + + for (uint16_t a = 0; a < 256; a++) { + for (uint16_t b = 0; b < 256; b++) { + for (uint16_t c = 0; c < 256; c++) { + for (uint16_t d = 0; d < 256; d++) { csn[0] = a; csn[1] = b; csn[2] = c; @@ -80,6 +80,8 @@ void brute_hash1(void) { hash1(csn, k); calc_score(csn, k); } + } + } } } diff --git a/client/src/loclass/ikeys.c b/client/src/loclass/ikeys.c index 3adcd97bb..181f23db1 100644 --- a/client/src/loclass/ikeys.c +++ b/client/src/loclass/ikeys.c @@ -333,7 +333,7 @@ void hash0(uint64_t c, uint8_t k[8]) { uint8_t p_i = p >> i & 0x1; if (k[i]) { // yi = 1 - //printf("k[%d] +1\n", i); + // PrintAndLogEx(NORMAL, "k[%d] + 1", i); k[i] |= ~zTilde_i & 0x7E; k[i] |= p_i & 1; k[i] += 1; @@ -399,7 +399,7 @@ static void testPermute(void) { permute(&p_in, x, 0, 4, &out); uint64_t permuted = x_bytes_to_num(outbuffer, 8); - //printf("zTilde 0x%"PRIX64"\n", zTilde); + // PrintAndLogEx(NORMAL, "zTilde 0x%"PRIX64, zTilde); permuted >>= 16; uint8_t res[8] = { getSixBitByte(permuted, 0), @@ -694,28 +694,21 @@ int doKeyTests(void) { /** -void checkParity2(uint8_t* key) -{ +void checkParity2(uint8_t* key) { uint8_t stored_parity = key[7]; - printf("Parity byte: 0x%02x\n", stored_parity); - int i; - int byte; - int fails =0; + PrintAndLogEx(NORMAL, "Parity byte: 0x%02x", stored_parity); + int i, byte, fails = 0; BitstreamIn bits = {key, 56, 0}; - bool parity = 0; - for(i =0 ; i < 56; i++) - { + for (i = 0; i < 56; i++) { - if ( i > 0 && i % 7 == 0) - { + if ( i > 0 && i % 7 == 0){ parity = !parity; bool pbit = stored_parity & (0x80 >> (byte)); - if(parity != pbit) - { - printf("parity2 fail byte %d, should be %d, was %d\n", (i / 7), parity, pbit); + if (parity != pbit) { + PrintAndLogEx(NORMAL, "parity2 fail byte %d, should be %d, was %d", (i / 7), parity, pbit); fails++; } parity =0 ; @@ -723,35 +716,32 @@ void checkParity2(uint8_t* key) } parity = parity ^ headBit(&bits); } - if(fails) - { - printf("parity2 fails: %d\n", fails); - }else - { - printf("Key syntax is with parity bits grouped in the last byte!\n"); + if (fails) { + PrintAndLogEx(FAILED, "parity2 fails: %d", fails); + } else { + PrintAndLogEx(INFO, "Key syntax is with parity bits grouped in the last byte!"); } } -void modifyKey_put_parity_last(uint8_t * key, uint8_t* output) -{ + +void modifyKey_put_parity_last(uint8_t * key, uint8_t* output) { + uint8_t paritybits = 0; bool parity =0; - BitstreamOut out = { output, 0,0}; + BitstreamOut out = { output, 0, 0}; unsigned int bbyte, bbit; - for(bbyte=0; bbyte <8 ; bbyte++ ) - { - for(bbit =0 ; bbit< 7 ; bbit++) - { - bool bit = *(key+bbyte) & (1 << (7-bbit)); - pushBit(&out,bit); + for (bbyte = 0; bbyte <8; bbyte++ ) { + for(bbit = 0; bbit < 7; bbit++) { + bool bit = *(key + bbyte) & (1 << (7 - bbit)); + pushBit(&out, bit); parity ^= bit; } - bool paritybit = *(key+bbyte) & 1; - paritybits |= paritybit << (7-bbyte); + bool paritybit = *(key + bbyte) & 1; + paritybits |= paritybit << (7 - bbyte); parity = 0; } output[7] = paritybits; - printf("Parity byte: %02x\n", paritybits); + PrintAndLogEx(INFO, "Parity byte: %02x", paritybits); } * @brief Modifies a key with parity bits last, so that it is formed with parity @@ -759,25 +749,24 @@ void modifyKey_put_parity_last(uint8_t * key, uint8_t* output) * @param key * @param output -void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output) -{ +void modifyKey_put_parity_allover(uint8_t * key, uint8_t* output) { bool parity =0; - BitstreamOut out = { output, 0,0}; - BitstreamIn in = {key, 0,0}; + BitstreamOut out = {output, 0, 0}; + BitstreamIn in = {key, 0, 0}; unsigned int bbyte, bbit; - for(bbit =0 ; bbit < 56 ; bbit++) { - if( bbit > 0 && bbit % 7 == 0) { - pushBit(&out,!parity); + for (bbit = 0; bbit < 56; bbit++) { + if (bbit > 0 && bbit % 7 == 0) { + pushBit(&out, !parity); parity = 0; } bool bit = headBit(&in); - pushBit(&out,bit ); + pushBit(&out, bit); parity ^= bit; } pushBit(&out, !parity); - if( des_key_check_key_parity(output)) - printf("modifyKey_put_parity_allover fail, DES key invalid parity!"); + if (des_key_check_key_parity(output)) + PrintAndLogEx(FAILED, "modifyKey_put_parity_allover fail, DES key invalid parity!"); } */ diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 393495152..b33872cdc 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -34,10 +34,10 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { bool first_run = true; // message - PrintAndLogEx(INFO, "--------------------------------------------------------------------------------\n"); - PrintAndLogEx(INFO, "executing Darkside attack. Expected execution time: 25sec on average"); - PrintAndLogEx(INFO, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client."); - PrintAndLogEx(INFO, "--------------------------------------------------------------------------------\n"); + PrintAndLogEx(INFO, "--------------------------------------------------------------------------------"); + PrintAndLogEx(INFO, "Executing darkside attack. Expected execution time: 25sec on average"); + PrintAndLogEx(INFO, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client"); + PrintAndLogEx(INFO, "--------------------------------------------------------------------------------"); while (true) { clearCommandBuffer(); @@ -58,8 +58,8 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { // wait cycle while (true) { - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); + if (kbd_enter_pressed()) { return PM3_EOPABORTED; } @@ -206,8 +206,7 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { timeout++; - printf("."); - fflush(stdout); + PrintAndLogEx(NORMAL, "." NOLF); // max timeout for one chunk of 85keys, 60*3sec = 180seconds // s70 with 40*2 keys to check, 80*85 = 6800 auth. // takes about 97s, still some margin before abort @@ -221,7 +220,7 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, // time to convert the returned data. uint8_t curr_keys = resp.oldarg[0]; - PrintAndLogEx(INFO, "\nChunk: %.1fs | found %u/%u keys (%u)", (float)(t2 / 1000.0), curr_keys, (sectorsCnt << 1), size); + PrintAndLogEx(INFO, "Chunk: %.1fs | found %u/%u keys (%u)", (float)(t2 / 1000.0), curr_keys, (sectorsCnt << 1), size); // all keys? if (curr_keys == sectorsCnt * 2 || lastChunk) { @@ -311,6 +310,7 @@ int mfCheckKeys_file(uint8_t *destfn, uint64_t *key) { } PACKED; struct kr *keyresult = (struct kr *)&resp.data.asBytes; if (!keyresult->found) return PM3_ESOFT; + *key = bytes_to_num(keyresult->key, sizeof(keyresult->key)); return PM3_SUCCESS; } @@ -418,9 +418,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, return PM3_ETIMEOUT; } - if (resp.status != PM3_SUCCESS) - return PM3_ESOFT; - struct p { int16_t isOK; uint8_t block; @@ -433,8 +430,9 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, } PACKED; struct p *package = (struct p *)resp.data.asBytes; - // error during nested - if (package->isOK) return package->isOK; + // error during nested on device side + if (package->isOK != PM3_SUCCESS) + return package->isOK; memcpy(&uid, package->cuid, sizeof(package->cuid)); @@ -450,7 +448,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, memcpy(&statelists[1].nt_enc, package->nt_b, sizeof(package->nt_b)); memcpy(&statelists[1].ks1, package->ks_b, sizeof(package->ks_b)); - // calc keys pthread_t thread_id[2]; @@ -538,32 +535,30 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, free(statelists[1].head.slhead); num_to_bytes(key64, 6, resultKey); - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", package->block, package->keytype ? 'B' : 'A', sprint_hex(resultKey, 6) ); - return -5; + return PM3_SUCCESS; } -// if (i + 1 % 10 == 0) { float bruteforce_per_second = (float)(i + max_keys) / ((msclock() - start_time) / 1000.0); - PrintAndLogEx(INFO, "%6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second); -// } - + PrintAndLogEx(INPLACE, "%6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second); } out: - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", + PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c", package->block, package->keytype ? 'B' : 'A' ); free(statelists[0].head.slhead); free(statelists[1].head.slhead); - return -4; + return PM3_ESOFT; } + int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) { uint32_t uid; @@ -612,7 +607,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl statelists[0].keyType = package->keytype; statelists[0].uid = uid; - memcpy(&statelists[0].nt_enc, package->nt, sizeof(package->nt)); + memcpy(&statelists[0].nt_enc, package->nt, sizeof(package->nt)); memcpy(&statelists[0].ks1, package->ks, sizeof(package->ks)); // calc keys @@ -678,6 +673,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl //flush queue while (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + PrintAndLogEx(NORMAL, ""); free(mem); return PM3_EOPABORTED; } @@ -694,14 +690,17 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl // check a block of generated key candidates. if (IfPm3Flash()) { + + mem[3] = ((chunk >> 8) & 0xFF); + mem[4] = (chunk & 0xFF); + // upload to flash. res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6)); if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "SPIFFS upload failed"); + PrintAndLogEx(WARNING, "\nSPIFFS upload failed"); free(mem); return res; } - res = mfCheckKeys_file(destfn, &key64); } else { res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, chunk, mem, &key64); @@ -714,6 +713,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl num_to_bytes(key64, 6, resultKey); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", package->block, package->keytype ? 'B' : 'A', @@ -721,21 +721,20 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl ); return PM3_SUCCESS; } else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { + PrintAndLogEx(NORMAL, ""); free(mem); return res; } -// if (i%10 == 0) { float bruteforce_per_second = (float)(i + max_keys_chunk) / ((msclock() - start_time) / 1000.0); - PrintAndLogEx(INFO, "%6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second); -// } + PrintAndLogEx(INPLACE, "%6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second); } p_keyblock = NULL; free(mem); out: - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", + PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c", package->block, package->keytype ? 'B' : 'A' ); @@ -865,7 +864,7 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) { uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; - //uint8_t blockD[16] = {0x00}; + uint8_t blockD[16] = {0x00}; uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t params = MAGIC_SINGLE; @@ -887,12 +886,12 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) { PrintAndLogEx(INPLACE, "wipe block %d", blockNo); if (blockNo == 0) { - res = mfCSetBlock(blockNo, block0, NULL, (params | MAGIC_WIPE)); + res = mfCSetBlock(blockNo, block0, NULL, params); } else { if (mfIsSectorTrailer(blockNo)) res = mfCSetBlock(blockNo, blockK, NULL, params); -// else -// res = mfCSetBlock(blockNo, blockD, NULL, params); + else + res = mfCSetBlock(blockNo, blockD, NULL, params); } if (res == PM3_SUCCESS) @@ -916,7 +915,7 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_CSETBL, params, blockNo, 0, data, 16); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 3500)) { uint8_t isOK = resp.oldarg[0] & 0xff; if (uid != NULL) memcpy(uid, resp.data.asBytes, 4); @@ -945,8 +944,47 @@ int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { return PM3_SUCCESS; } -// SNIFFER -// [iceman] so many global variables.... +int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid) { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFARE_GEN3UID, uidlen, 0, 0, uid, uidlen); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3UID, &resp, 3500)) { + if (resp.status == PM3_SUCCESS && oldUid) { + memcpy(oldUid, resp.data.asBytes, uidlen); + } + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} + +int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) { + clearCommandBuffer(); + SendCommandMIX(CMD_HF_MIFARE_GEN3BLK, blockLen, 0, 0, block, 16); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3BLK, &resp, 3500)) { + if (resp.status == PM3_SUCCESS && newBlock) { + memcpy(newBlock, resp.data.asBytes, 16); + } + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} + +int mfGen3Freez(void) { + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_GEN3FREEZ, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_HF_MIFARE_GEN3FREEZ, &resp, 3500)) { + return resp.status; + } else { + PrintAndLogEx(WARNING, "Command execute timeout"); + return PM3_ETIMEOUT; + } +} // variables uint32_t cuid = 0; // uid part used for crypto1. @@ -1037,14 +1075,16 @@ int detect_classic_nackbug(bool verbose) { PrintAndLogEx(SUCCESS, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client.\n"); while (true) { - printf("."); - fflush(stdout); + + PrintAndLogEx(NORMAL, "." NOLF); if (kbd_enter_pressed()) { return PM3_EOPABORTED; } if (WaitForResponseTimeout(CMD_HF_MIFARE_NACK_DETECT, &resp, 500)) { + PrintAndLogEx(NORMAL, ""); + if (resp.status == PM3_EOPABORTED) { PrintAndLogEx(WARNING, "button pressed. Aborted."); return PM3_EOPABORTED; @@ -1053,7 +1093,6 @@ int detect_classic_nackbug(bool verbose) { uint8_t ok = resp.data.asBytes[0]; uint8_t nacks = resp.data.asBytes[1]; uint16_t auths = bytes_to_num(resp.data.asBytes + 2, 2); - PrintAndLogEx(NORMAL, ""); if (verbose) { PrintAndLogEx(SUCCESS, "num of auth requests : %u", auths); @@ -1070,7 +1109,7 @@ int detect_classic_nackbug(bool verbose) { case 97 : { if (verbose) { PrintAndLogEx(FAILED, "card random number generator seems to be based on the well-known generating polynomial"); - PrintAndLogEx(NORMAL, "[- ]with 16 effective bits only, but shows unexpected behavior, try again."); + PrintAndLogEx(FAILED, "with 16 effective bits only, but shows unexpected behavior, try again."); } return PM3_SUCCESS; } diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index f8205732f..4864d9357 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -80,6 +80,10 @@ int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak); int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); +int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid); +int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock); +int mfGen3Freez(void); + int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); int detect_classic_prng(void); diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index a6ac33bd4..1358137bf 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -108,7 +108,7 @@ static void showBanner(void) { #endif // PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/"); // PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001"); -// printf("\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP"); +// PrintAndLogEx(NORMAL, "\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP"); PrintAndLogEx(NORMAL, ""); fflush(stdout); g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; @@ -678,55 +678,8 @@ finish2: return ret; } -// Check if windows AnsiColor Support is enabled in the registery -// [HKEY_CURRENT_USER\Console] -// "VirtualTerminalLevel"=dword:00000001 -// 2nd Key needs to be enabled... This key takes the console out of legacy mode. -// [HKEY_CURRENT_USER\Console] -// "ForceV2"=dword:00000001 - #if defined(_WIN32) static bool DetectWindowsAnsiSupport(void) { - HKEY hKey = NULL; - bool virtualTerminalLevelSet = false; - bool forceV2Set = false; - - if (RegOpenKeyA(HKEY_CURRENT_USER, "Console", &hKey) == ERROR_SUCCESS) { - DWORD dwType = REG_SZ; - BYTE KeyValue[sizeof(dwType)]; - DWORD len = sizeof(KeyValue); - - if (RegQueryValueEx(hKey, "VirtualTerminalLevel", NULL, &dwType, KeyValue, &len) != ERROR_FILE_NOT_FOUND) { - uint8_t i; - uint32_t Data = 0; - for (i = 0; i < 4; i++) - Data += KeyValue[i] << (8 * i); - - if (Data == 1) { // Reg key is set to 1, Ansi Color Enabled - virtualTerminalLevelSet = true; - } - } - RegCloseKey(hKey); - } - - if (RegOpenKeyA(HKEY_CURRENT_USER, "Console", &hKey) == ERROR_SUCCESS) { - DWORD dwType = REG_SZ; - BYTE KeyValue[sizeof(dwType)]; - DWORD len = sizeof(KeyValue); - - if (RegQueryValueEx(hKey, "ForceV2", NULL, &dwType, KeyValue, &len) != ERROR_FILE_NOT_FOUND) { - uint8_t i; - uint32_t Data = 0; - for (i = 0; i < 4; i++) - Data += KeyValue[i] << (8 * i); - - if (Data == 1) { // Reg key is set to 1, Not using legacy Mode. - forceV2Set = true; - } - } - RegCloseKey(hKey); - } - #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif @@ -735,10 +688,8 @@ static bool DetectWindowsAnsiSupport(void) { DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(hOut, dwMode); - // If both VirtualTerminalLevel and ForceV2 is set, AnsiColor should work - return virtualTerminalLevelSet && forceV2Set; + return SetConsoleMode(hOut, dwMode) ? true : false; } #endif diff --git a/client/src/scripting.c b/client/src/scripting.c index a1fdb8a31..64dd0f84a 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -474,14 +474,14 @@ static int l_mfDarkside(lua_State *L) { static int l_foobar(lua_State *L) { //Check number of arguments int n = lua_gettop(L); - printf("foobar called with %d arguments", n); + PrintAndLogEx(INFO, "foobar called with %d arguments", n); lua_settop(L, 0); - printf("Arguments discarded, stack now contains %d elements", lua_gettop(L)); + PrintAndLogEx(INFO, "Arguments discarded, stack now contains %d elements", lua_gettop(L)); // todo: this is not used, where was it intended for? // PacketCommandOLD response = {CMD_HF_MIFARE_READBL, {1337, 1338, 1339}, {{0}}}; - printf("Now returning a uint64_t as a string"); + PrintAndLogEx(INFO, "Now returning a uint64_t as a string"); uint64_t x = 0xDEADC0DE; uint8_t destination[8]; num_to_bytes(x, sizeof(x), destination); @@ -1046,7 +1046,7 @@ static int l_T55xx_detect(lua_State *L) { sscanf(p_gb, "%u", &gb); useGB = (gb) ? true : false; - printf("p_gb size %zu | %c \n", size, useGB ? 'Y' : 'N'); + PrintAndLogEx(INFO, "p_gb size %zu | %c", size, useGB ? 'Y' : 'N'); } case 1: { const char *p_pwd = luaL_checklstring(L, 1, &size); @@ -1129,9 +1129,7 @@ static int l_remark(lua_State *L) { } size_t size; - // data const char *s = luaL_checklstring(L, 1, &size); - int res = CmdRem(s); lua_pushinteger(L, res); return 1; @@ -1199,6 +1197,19 @@ static int l_cwd(lua_State *L) { return 1; } +// ref: https://github.com/RfidResearchGroup/proxmark3/issues/891 +// redirect LUA's print to Proxmark3 PrintAndLogEx +static int l_printandlogex(lua_State *L) { + + int n = lua_gettop(L); + for (int i = 1; i <= n; i++) { + if (lua_isstring(L, i)) { + PrintAndLogEx(NORMAL, "%s", lua_tostring(L, i)); + } + } + return 0; +} + /** * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be * able to do "require('foobar')" if foobar.lua is within lualibs folder. @@ -1269,21 +1280,24 @@ int set_pm3_libraries(lua_State *L) { lua_pushglobaltable(L); // Core library is in this table. Contains ' - //this is 'pm3' table + // this is 'pm3' table lua_newtable(L); - //Put the function into the hash table. + // put the function into the hash table. for (int i = 0; libs[i].name; i++) { lua_pushcfunction(L, libs[i].func); lua_setfield(L, -2, libs[i].name);//set the name, pop stack } - //Name of 'core' + // Name of 'core' lua_setfield(L, -2, "core"); - //-- remove the global environment table from the stack + // remove the global environment table from the stack lua_pop(L, 1); - //--add to the LUA_PATH (package.path in lua) + // print redirect here + lua_register(L, "print", l_printandlogex); + + // add to the LUA_PATH (package.path in lua) // so we can load scripts from various places: const char *exec_path = get_my_executable_directory(); if (exec_path != NULL) { diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index 1a6cf32a0..406bf6d7c 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -359,7 +359,7 @@ void uart_close(const serial_port sp) { int err = fcntl(spu->fd, F_SETLK, &fl); if (err == -1) { //silent error message as it can be called from uart_open failing modes, e.g. when waiting for port to appear - //printf("[!] UART error while closing port\n"); + //PrintAndLogEx(ERR, "UART error while closing port"); } close(spu->fd); free(sp); @@ -401,12 +401,12 @@ int uart_receive(const serial_port sp, uint8_t *pbtRx, uint32_t pszMaxRxLen, uin // Retrieve the count of the incoming bytes res = ioctl(((serial_port_unix *)sp)->fd, FIONREAD, &byteCount); -// printf("UART:: RX ioctl res %d byteCount %u\n", res, byteCount); +// PrintAndLogEx(ERR, "UART:: RX ioctl res %d byteCount %u", res, byteCount); if (res < 0) return PM3_ENOTTY; // Cap the number of bytes, so we don't overrun the buffer if (pszMaxRxLen - (*pszRxLen) < byteCount) { -// printf("UART:: RX prevent overrun (have %u, need %u)\n", pszMaxRxLen - (*pszRxLen), byteCount); +// PrintAndLogEx(ERR, "UART:: RX prevent overrun (have %u, need %u)", pszMaxRxLen - (*pszRxLen), byteCount); byteCount = pszMaxRxLen - (*pszRxLen); } @@ -443,13 +443,13 @@ int uart_send(const serial_port sp, const uint8_t *pbtTx, const uint32_t len) { // Write error if (res < 0) { - printf("UART:: write error (%d)\n", res); + PrintAndLogEx(ERR, "UART:: write error (%d)", res); return PM3_ENOTTY; } // Write time-out if (res == 0) { - printf("UART:: write time-out\n"); + PrintAndLogEx(ERR, "UART:: write time-out"); return PM3_ETIMEOUT; } diff --git a/client/src/ui.h b/client/src/ui.h index b466b9c84..7a5b7911d 100644 --- a/client/src/ui.h +++ b/client/src/ui.h @@ -22,7 +22,6 @@ extern "C" { #define _USE_MATH_DEFINES typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE, HINT} logLevel_t; -#define NOLF "\xff" typedef enum emojiMode {ALIAS, EMOJI, ALTTEXT, ERASE} emojiMode_t; typedef enum clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_t; // typedef enum devicedebugLevel {ddbOFF, ddbERROR, ddbINFO, ddbDEBUG, ddbEXTENDED} devicedebugLevel_t; diff --git a/client/src/util.c b/client/src/util.c index e469dc095..161115993 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -96,6 +96,7 @@ void FillFileNameByUID(char *filenamePrefix, const uint8_t *uid, const char *ext for (int j = 0; j < uidlen; j++) sprintf(filenamePrefix + len + j * 2, "%02X", uid[j]); + strcat(filenamePrefix, ext); } @@ -176,26 +177,27 @@ void print_hex(const uint8_t *data, const size_t len) { if (data == NULL || len == 0) return; for (size_t i = 0; i < len; i++) - printf("%02x ", data[i]); - printf("\n"); + PrintAndLogEx(NORMAL, "%02x " NOLF, data[i]); + + PrintAndLogEx(NORMAL, ""); } void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) { if (data == NULL || len == 0) return; int rownum = 0; - printf("[%02d] | ", rownum); + PrintAndLogEx(NORMAL, "[%02d] | " NOLF, rownum); for (size_t i = 0; i < len; ++i) { - printf("%02X ", data[i]); + PrintAndLogEx(NORMAL, "%02X " NOLF, data[i]); // check if a line break is needed if (breaks > 0 && !((i + 1) % breaks) && (i + 1 < len)) { ++rownum; - printf("\n[%02d] | ", rownum); + PrintAndLogEx(NORMAL, "\n[%02d] | " NOLF, rownum); } } - printf("\n"); + PrintAndLogEx(NORMAL, ""); } char *sprint_hex(const uint8_t *data, const size_t len) { @@ -229,7 +231,7 @@ char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t brea if (breaks > 0 && len % breaks != 0) rowlen = (len + (len / breaks) > MAX_BIN_BREAK_LENGTH) ? MAX_BIN_BREAK_LENGTH : len + (len / breaks); - //printf("(sprint_bin_break) rowlen %d\n", rowlen); + //PrintAndLogEx(NORMAL, "(sprint_bin_break) rowlen %d", rowlen); static char buf[MAX_BIN_BREAK_LENGTH]; // 3072 + end of line characters if broken at 8 bits //clear memory @@ -267,7 +269,7 @@ void sprint_bin_break_ex(uint8_t *src, size_t srclen, char *dest , uint8_t break else rowlen = ( len+(len/breaks) > MAX_BIN_BREAK_LENGTH ) ? MAX_BIN_BREAK_LENGTH : len+(len/breaks); - printf("(sprint_bin_break) rowlen %d\n", rowlen); + PrintAndLogEx(NORMAL, "(sprint_bin_break) rowlen %d", rowlen); // 3072 + end of line characters if broken at 8 bits dest = (char *)calloc(MAX_BIN_BREAK_LENGTH, sizeof(uint8_t)); @@ -307,10 +309,13 @@ char *sprint_hex_ascii(const uint8_t *data, const size_t len) { size_t i = 0; size_t pos = (max_len * 3) + 2; + while (i < max_len) { + char c = data[i]; if ((c < 32) || (c == 127)) c = '.'; + sprintf(tmp + pos + i, "%c", c); ++i; } @@ -682,7 +687,7 @@ int hextobinarray(char *target, char *source) { else if (x >= 'A' && x <= 'F') x -= 'A' - 10; else { - printf("Discovered unknown character %c %d at idx %d of %s\n", x, x, (int16_t)(source - start), start); + PrintAndLogEx(INFO, "(hextobinarray) discovered unknown character %c %d at idx %d of %s", x, x, (int16_t)(source - start), start); return 0; } // output diff --git a/client/src/wiegand_formatutils.c b/client/src/wiegand_formatutils.c index 0d58e9d6f..3879e616e 100644 --- a/client/src/wiegand_formatutils.c +++ b/client/src/wiegand_formatutils.c @@ -134,7 +134,6 @@ static uint8_t get_length_from_header(wiegand_message_t *data) { hfmt = 0; len = 37; } else if ((data->Mid & 0x0000001F) > 0) { // 36-32 bits - printf("a\n"); hfmt = data->Mid & 0x0000001F; len = 32; } else { diff --git a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md index bddb267bd..02e8a2201 100644 --- a/doc/md/Installation_Instructions/Windows-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-Installation-Instructions.md @@ -15,7 +15,7 @@ There are two ways to install, build and use Proxmark3 on Windows: ## Driver Installation Install required drivers for your Windows installation. You may need admin privileges to do this. -Step by step guides are online such as [RiscCorps](https://store.ryscc.com/blogs/news/how-to-install-a-proxmark3-driver-on-windows-10). +Step by step guides are online such as [RyscCorps](https://store.ryscc.com/blogs/news/how-to-install-a-proxmark3-driver-on-windows-10). ## Download / clone ProxSpace repo diff --git a/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md b/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md index 8264e3245..b1c79e27d 100644 --- a/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md +++ b/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md @@ -1,6 +1,13 @@ ### First things on your RDV40 + You will need to run these commands to make sure your rdv4 is prepared ``` +[usb] pm3 --> script run init_rdv4 +``` + + +The lua script actually executes the following commands below. These are here because of documentation, you can jump down to *Verify sim module firmware version* part. +``` [usb] pm3 --> mem load f mfc_default_keys m [usb] pm3 --> mem load f t55xx_default_pwds t [usb] pm3 --> mem load f iclass_default_keys i @@ -13,6 +20,7 @@ Set all t55xx settings to defaults (will set all 4 at once) [usb] pm3 --> lf t55xx deviceconfig z p ``` + ### Verify sim module firmware version To make sure you got the latest sim module firmware. diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 0780ec87b..4b7b665e7 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -80,17 +80,19 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo | STANDALONE | DESCRIPTION | |-----------------|----------------------------------------| | | No standalone mode -| LF_SKELETON | standalone mode skeleton - Iceman +| LF_SKELETON | standalone mode skeleton - Iceman1001 | LF_EM4100EMUL | LF EM4100 simulator standalone mode - temskiy | LF_EM4100RSWB | LF EM4100 read/write/clone/brute mode - Monster1024 | LF_EM4100RWC | LF EM4100 read/write/clone mode - temskiy | LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini -| LF_ICEHID | LF HID collector to flashmem - Iceman +| LF_ICEHID | LF HID collector to flashmem - Iceman1001 | LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz | LF_SAMYRUN | HID26 read/clone/sim - Samy Kamkar | HF_14ASNIFF | 14a sniff storing to flashmem - Micolous +| HF_AVEFUL | MIFARE Ultralight read/simulation - Ave Ozkal | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth storing in flashmem - Bogito | HF_COLIN | Mifare ultra fast sniff/sim/clone - Colin Brigato +| HF_ICECLASS | iCLASS 4-1 mode sim/read & dump/loclass/glitch & config to flashmem - Iceman1001 | HF_LEGIC | HF Legic Prime standalone - uhei | HF_MATTYRUN | Mifare sniff/clone - Matías A. Ré Medina | HF_MSDSAL (def)| EMV Read and emulation - Salvador Mendoza diff --git a/include/ansi.h b/include/ansi.h index 6c808d10e..27d0dc2e7 100644 --- a/include/ansi.h +++ b/include/ansi.h @@ -1,6 +1,9 @@ #ifndef __ANSI_H #define __ANSI_H +// Not ANSI but dirty trick to specify we don't want a \n +#define NOLF "\xff" + #define AEND "\x1b[0m" #define _BLUE_(s) "\x1b[34m" s AEND diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index a7ba0a4d0..dd11d49d5 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -122,6 +122,15 @@ typedef struct { bool verbose; } PACKED sample_config; +// A struct used to send hf14a-configs over USB +typedef struct { + int8_t forceanticol; // 0:auto 1:force executing anticol 2:force skipping anticol + int8_t forcebcc; // 0:expect valid BCC 1:force using computed BCC 2:force using card BCC + int8_t forcecl2; // 0:auto 1:force executing CL2 2:force skipping CL2 + int8_t forcecl3; // 0:auto 1:force executing CL3 2:force skipping CL3 + int8_t forcerats; // 0:auto 1:force executing RATS 2:force skipping RATS +} PACKED hf14a_config; + // Tracelog Header struct typedef struct { uint32_t timestamp; @@ -569,6 +578,11 @@ typedef struct { #define CMD_HF_FELICALITE_DUMP 0x03AA #define CMD_HF_FELICALITE_SIMULATE 0x03AB +// For 14a config +#define CMD_HF_ISO14443A_PRINT_CONFIG 0x03B0 +#define CMD_HF_ISO14443A_GET_CONFIG 0x03B1 +#define CMD_HF_ISO14443A_SET_CONFIG 0x03B2 + // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 #define CMD_MEASURE_ANTENNA_TUNING_HF 0x0401 @@ -604,6 +618,7 @@ typedef struct { #define CMD_HF_MIFAREU_READCARD 0x0721 #define CMD_HF_MIFARE_WRITEBL 0x0622 #define CMD_HF_MIFAREU_WRITEBL 0x0722 +#define CMD_HF_MIFAREU_WRITEBL_COMPAT 0x0723 #define CMD_HF_MIFARE_CHKKEYS 0x0623 #define CMD_HF_MIFARE_SETMOD 0x0624 @@ -648,6 +663,11 @@ typedef struct { //For Atmel CryptoRF #define CMD_HF_CRYPTORF_SIM 0x0820 +// Gen 3 magic cards +#define CMD_HF_MIFARE_GEN3UID 0x0850 +#define CMD_HF_MIFARE_GEN3BLK 0x0851 +#define CMD_HF_MIFARE_GEN3FREEZ 0x0852 + #define CMD_UNKNOWN 0xFFFF //Mifare simulation flags @@ -714,7 +734,7 @@ typedef struct { #define PM3_ETIMEOUT -4 // Operation aborted (by user) client/pm3: kbd/button pressed #define PM3_EOPABORTED -5 -// Not (yet) implemented client/pm3: TBD placeholder +// Not (yet) implemented client/pm3: TBD place holder #define PM3_ENOTIMPL -6 // Error while RF transmission client/pm3: fail between pm3 & card #define PM3_ERFTRANS -7 @@ -732,7 +752,7 @@ typedef struct { #define PM3_EFILE -13 // Generic TTY error #define PM3_ENOTTY -14 -// Initialization error pm3: error related to trying to initalize the pm3 / fpga for different operations +// Initialization error pm3: error related to trying to initialize the pm3 / fpga for different operations #define PM3_EINIT -15 // Expected a different answer error client/pm3: error when expecting one answer and got another one #define PM3_EWRONGANSWER -16 @@ -745,6 +765,12 @@ typedef struct { #define PM3_EAPDU_ENCODEFAIL -19 // APDU responded with a failure code #define PM3_EAPDU_FAIL -20 + +// execute pm3 cmd failed client/pm3: when one of our pm3 cmd tries and fails. opposite from PM3_SUCCESS +#define PM3_EFAILED -21 +// partial success client/pm3: when tring to dump a tag and fails on some blocks. Partial dump. +#define PM3_EPARTIAL -22 + // No data pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98 // Quit program client: reserved, order to quit the program diff --git a/include/protocols.h b/include/protocols.h index add711563..62bb9f276 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -15,6 +15,9 @@ ISO14443A (usually NFC tags) 95 20 = Anticollision of cascade level2 95 70 = Select of cascade level2 50 00 = Halt (usage: 5000+2bytes ISO14443A-CRC - no answer from card) + + E0 = RATS + D0 = PPS Mifare 60 = Authenticate with KeyA 61 = Authenticate with KeyB @@ -148,6 +151,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO14443A_CMD_WRITEBLOCK 0xA0 #define ISO14443A_CMD_HALT 0x50 #define ISO14443A_CMD_RATS 0xE0 +#define ISO14443A_CMD_PPS 0xD0 #define ISO14443A_CMD_NXP_DESELECT 0xC2 #define MIFARE_SELECT_CT 0x88 @@ -519,6 +523,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define T5555_BITRATE_SHIFT 12 //(RF=2n+2) ie 64=2*0x1F+2 or n = (RF-2)/2 #define T5555_FAST_WRITE 0x00004000 #define T5555_PAGE_SELECT 0x00008000 +#define T5555_FIXED 0x60000000 #define T55XX_WRITE_TIMEOUT 1500