Merge branch 'RfidResearchGroup:master' into master

This commit is contained in:
Angel 2023-05-24 21:47:02 -04:00 committed by GitHub
commit ef74541b28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1356 additions and 641 deletions

View file

@ -9,7 +9,7 @@ jobs:
- name: Changelog Reminder - name: Changelog Reminder
uses: peterjgrainger/action-changelog-reminder@v1.2.0 uses: peterjgrainger/action-changelog-reminder@v1.2.0
with: with:
changelog_regex: '/CHANGELOG.md' changelog_regex: 'CHANGELOG.md'
customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well' customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well'
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Changed `hf mf sim` - reduce 6ms threshold to 4ms for reset to idle #1974 (@net147)
- Rebuilt the Spartan-2 `fpga_*.bit` files to include the `hi_iso14443a.v` update (@d18c7db)
- Added minor orphaned change from `hi_iso14443a.v` in `fpga-xc3s100e` to `hi_iso14443a.v` in `fpga-xc2s30` (@d18c7db)
- Added python3 script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3 (@OscarAkaElvis)
- Changed `hf mf restore` - Auth both key A and key B with default password (@wh201906)
- Changed `nfc decode -f` - now can detect and convert MFC dumpfiles to NDEF byte arrays (@iceman1001)
- Changed `nfc decode` - now handles EXTERNAL RECORDS better (@iceman1001)
- Fixed `nfc decode` - now handles NDEF Signature version1 records better (@iceman1001)
- Added new standalone mode `LF_MULTIHID` - HID26 (H1031) multi simulator (@flamebarke)
- Changed `hf 14b dump --ns` - now supports `no save` of card memory (@iceman1001)
- Changed `hf mfu dump --ns` - now supports `no save` of card memory (@iceman1001)
- Changed the PM3 client to honor the preferences dump/trace paths. experimental support (@iceman1001)
- Added the possibility to load `.MCT` dump files (@iceman1001)
- Changed `lf t55xx dump --ns` - now supports `no save` of memory (@iceman1001)
- Fixed the USB enumeration process (@wh201906) - Fixed the USB enumeration process (@wh201906)
- Fixed `hf mf rdsc` - now correctly gets size in bytes when sector is larger than 32 (@iceman1001) - Fixed `hf mf rdsc` - now correctly gets size in bytes when sector is larger than 32 (@iceman1001)
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty) - Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
@ -49,6 +63,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `hf legic einfo` - views emulator menory (@0xdeb) - Added `hf legic einfo` - views emulator menory (@0xdeb)
- Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb) - Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb)
- Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120) - Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120)
- Update documentation for installation on macOS with MacPorts (@linuxgemini)
- Added possible Paxton id to hitag2 tag info output
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
## [Nitride.4.16191][2023-01-29] ## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -50,6 +50,9 @@ define KNOWN_STANDALONE_DEFINITIONS
| LF_ICEHID | LF HID collector to flashmem | | LF_ICEHID | LF HID collector to flashmem |
| (RDV4 only) | | | (RDV4 only) | |
+----------------------------------------------------------+ +----------------------------------------------------------+
| LF_MULTIHID | LF HID 26 Bit (H1031) multi simulator |
| | - Shain Lakin |
+----------------------------------------------------------+
| LF_NEDAP_SIM | LF Nedap ID simple simulator | | LF_NEDAP_SIM | LF Nedap ID simple simulator |
| | | | | |
+----------------------------------------------------------+ +----------------------------------------------------------+
@ -126,7 +129,7 @@ endef
STANDALONE_MODES := LF_SKELETON STANDALONE_MODES := LF_SKELETON
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG
STANDALONE_MODES += DANKARMULTI STANDALONE_MODES += DANKARMULTI
STANDALONE_MODES_REQ_BT := HF_REBLAY STANDALONE_MODES_REQ_BT := HF_REBLAY

View file

@ -49,6 +49,10 @@ endif
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icehid.c SRC_STANDALONE = lf_icehid.c
endif endif
# WITH_STANDALONE_LF_MULTIHID
ifneq (,$(findstring WITH_STANDALONE_LF_MULTIHID,$(APP_CFLAGS)))
SRC_STANDALONE = lf_multihid.c
endif
# WITH_STANDALONE_LF_NEDAP_SIM # WITH_STANDALONE_LF_NEDAP_SIM
ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_LF_NEDAP_SIM,$(APP_CFLAGS)))
SRC_STANDALONE = lf_nedap_sim.c SRC_STANDALONE = lf_nedap_sim.c

View file

@ -189,7 +189,7 @@ void RunMod(void) {
memcpy(data, visauid, 4); memcpy(data, visauid, 4);
// to initialize the emulation // to initialize the emulation
uint8_t tagType = 4; // 4 = ISO/IEC 14443-4 - javacard (JCOP) uint8_t tagType = 11; // 11 = ISO/IEC 14443-4 - javacard (JCOP)
tag_response_info_t *responses; tag_response_info_t *responses;
uint32_t cuid = 0; uint32_t cuid = 0;
uint32_t counters[3] = { 0x00, 0x00, 0x00 }; uint32_t counters[3] = { 0x00, 0x00, 0x00 };
@ -376,7 +376,8 @@ void RunMod(void) {
// dynamic_response_info will be in charge of responses // dynamic_response_info will be in charge of responses
dynamic_response_info.response_n = 0; dynamic_response_info.response_n = 0;
//Dbprintf("receivedCmd: %02x\n", receivedCmd);
// received a REQUEST // received a REQUEST
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) {
odd_reply = !odd_reply; odd_reply = !odd_reply;
@ -386,30 +387,35 @@ void RunMod(void) {
// received a HALT // received a HALT
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { } else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
// DbpString(_YELLOW_("+") "Received a HALT"); //DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL; p_response = NULL;
// received a WAKEUP // received a WAKEUP
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { } else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
// DbpString(_YELLOW_("+") "WAKEUP Received"); //DbpString(_YELLOW_("+") "WAKEUP Received");
prevCmd = 0; prevCmd = 0;
p_response = &responses[RESP_INDEX_ATQA]; p_response = &responses[RESP_INDEX_ATQA];
// received request for UID (cascade 1) // received request for UID (cascade 1)
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { } else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) {
// DbpString(_YELLOW_("+") "Request for UID C1"); //DbpString(_YELLOW_("+") "Request for UID C1");
p_response = &responses[RESP_INDEX_UIDC1]; p_response = &responses[RESP_INDEX_UIDC1];
// received a SELECT (cascade 1) // received a SELECT (cascade 1)
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { } else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) {
// DbpString(_YELLOW_("+") "Request for SELECT S1"); //DbpString(_YELLOW_("+") "Request for SELECT S1");
p_response = &responses[RESP_INDEX_SAKC1]; p_response = &responses[RESP_INDEX_SAKC1];
// received a RATS request // received a RATS request
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { } else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
// DbpString(_YELLOW_("+") "Request for RATS"); DbpString(_YELLOW_("+") "Request for RATS");
prevCmd = 0; prevCmd = 0;
p_response = &responses[RESP_INDEX_RATS]; //p_response = &responses[RESP_INDEX_RATS];
static uint8_t rRATS[] = { 0x13, 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66, 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00, 0x90, 0x00 };
memcpy(&dynamic_response_info.response[0], rRATS, sizeof(rRATS));
dynamic_response_info.response_n = sizeof(rRATS);
} else { } else {
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]")); DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
@ -483,6 +489,7 @@ void RunMod(void) {
} }
} }
} }
if (dynamic_response_info.response_n > 0) { if (dynamic_response_info.response_n > 0) {
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]")); DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false); Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);

View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// Copyright (C) Shain Lakin, 2023
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// LF HID 26 Bit (H10301) multi simulator:
// Simple LF HID26 (H10301) tag simulator
// Short click - select next slot and start simulation
// LEDS = LED ON for selected slot
// Add tags (raw) to the hid26_predefined_raw array
//-----------------------------------------------------------------------------
#include "standalone.h"
#include "proxmark3_arm.h"
#include "appmain.h"
#include "fpgaloader.h"
#include "util.h"
#include "dbprint.h"
#include "ticks.h"
#include "lfops.h"
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
#define MAX_IND 4
void LED_Slot(int i);
static uint64_t hid26_predefined_raw[] = {0x2004ec2e87, 0x2004421807, 0x20064312d6, 0x2006ec0c86};
static uint8_t hid26_slots_count;
void ModInfo(void) {
DbpString("LF HID 26 Bit (H10301) multi simulator - aka MultiHID (Shain Lakin)");
}
void LED_Slot(int i) {
LEDsoff();
if (hid26_slots_count > 4) {
LED(i % MAX_IND, 0);
} else {
LED(1 << i, 0);
}
}
void RunMod(void) {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
Dbprintf(">> LF HID26 multi simulator started - aka MultiHID (Shain Lakin) <<");
int selected = 0; //selected slot after start
hid26_slots_count = ARRAYLEN(hid26_predefined_raw);
for (;;) {
WDT_HIT();
if (data_available()) {
LEDsoff();
break;
}
SpinDelay(100);
SpinUp(100);
LED_Slot(selected);
uint64_t raw_data = hid26_predefined_raw[selected];
CmdHIDsimTAG(0, raw_data >> 32, raw_data & 0xFFFFFFFF, 0, false);
selected = (selected + 1) % hid26_slots_count;
}
}

View file

@ -655,6 +655,7 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
*txlen = 0; *txlen = 0;
if (bPwd && (bAuthenticating == false) && write) { if (bPwd && (bAuthenticating == false) && write) {
SpinDelay(2);
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) { if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
return false; return false;
} }

View file

@ -1151,6 +1151,11 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
sak = 0x20; sak = 0x20;
} }
break; break;
case 11: { // ISO/IEC 14443-4 - javacard (JCOP)
rATQA[0] = 0x04;
sak = 0x20;
}
break;
default: { default: {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType); if (g_dbglevel >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType);
@ -1183,7 +1188,13 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
// Configure the ATQA and SAK accordingly // Configure the ATQA and SAK accordingly
rATQA[0] &= 0xBF; rATQA[0] &= 0xBF;
rSAKc1[0] = sak & 0xFB;
if(tagType == 11){
rSAKc1[0] = sak & 0xFC & 0X70;
}else{
rSAKc1[0] = sak & 0xFB;
}
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2); AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
*cuid = bytes_to_num(data, 4); *cuid = bytes_to_num(data, 4);
@ -2084,8 +2095,8 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
if (timer == 0) { if (timer == 0) {
timer = GetTickCount(); timer = GetTickCount();
} else { } else {
// 50ms no field --> card to idle state // 4ms no field --> card to idle state
if (GetTickCountDelta(timer) > 50) { if (GetTickCountDelta(timer) > 4) {
return 2; return 2;
} }
} }

View file

@ -1194,8 +1194,6 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
LED_B_OFF(); LED_B_OFF();
if (g_dbglevel >= DBG_ERROR) DbpString("AcquireEncryptedNonces finished");
if (field_off) { if (field_off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff(); LEDsoff();

View file

@ -2029,9 +2029,8 @@ D144BD193063
8627C10A7014 8627C10A7014
453857395635 453857395635
# #
# Data from "the more, the marriott" mifare project (colonel borkmundus) # Data from "the more the marriott" mifare project (colonelborkmundus)
# # aka The Horde
# Isn't theirs Saflok ?
# #
# 20230125-01, Elite Member Marriott Rewards # 20230125-01, Elite Member Marriott Rewards
43012BD9EB87 43012BD9EB87
@ -2098,6 +2097,52 @@ C49DAE1C6049
6E029927600D 6E029927600D
3E173F64C01C 3E173F64C01C
C670A9AD6066 C670A9AD6066
# 20230413-69, Westin
487339FA02E0
# 20230413-70, Marriott Bonvoy
DBD5CA4EE467
A0B1F234006C
180DE12B700E
# 20230413-71, Westin
1352C68F7A56
# 20230413-76, Ritz Carlton
318BD98C1CEF
# 20230413-77, Marriott
D23C1CB1216E
# 20230413-78, Caesars
A1D92F808CAF
# 20230413-79, The Cosmopolitan, Vegas
# 96A301BCE267
# 20230413-80, Aria
1153C319B4F8
# 20230413-81, Aria
110C819BBEF8
# 20230413-82, Aria
1332117E8756
# 20230413-83, Kimpton
500AE915F50A
5032E362B484
8B63AB712753
# 20230413-85, Kimpton
06106E187106
2E45C23DC541
D9FF8BEE7550
# 20230413-87, Marriott
42F7A186BF87
# 20230413-88, Meritage Resort
D213B093B79A
# 20230413-89, Meritage Resort
216024C49EDF
# 20230413-90, Gaylord Palms
D201DBB6AB6E
# 20230413-91, Residence Inn
9F4AD875BB30
# 20230413-92, Marriott
3352DB1E8777
# 20230413-94, Marriott
09074A146605
151F3E85EC46
#
# #
# Food GEM # Food GEM
6686FADE5566 6686FADE5566
@ -2105,3 +2150,7 @@ C670A9AD6066
# Data from Discord, French pool # Data from Discord, French pool
9B7C25052FC3 9B7C25052FC3
494446555455 494446555455
#
# Data from Discord, seems to be related to ASSA
427553754D47

View file

@ -55,6 +55,9 @@ amiibo_tools.db =
["0x00000003039bff02"] = { ["0x00000003039bff02"] = {
name = "Mario - Power Up Band" name = "Mario - Power Up Band"
}, },
["0x000000030430ff02"] = {
name = "Golden - Power Up Band"
},
["0x0000010000190002"] = { ["0x0000010000190002"] = {
name = "Dr. Mario" name = "Dr. Mario"
}, },
@ -214,6 +217,9 @@ amiibo_tools.db =
["0x0100000003990902"] = { ["0x0100000003990902"] = {
name = "Link - Link's Awakening" name = "Link - Link's Awakening"
}, },
["0x0100000004180902"] = {
name = "Link - Tears of the Kingdom"
},
["0x0100010000160002"] = { ["0x0100010000160002"] = {
name = "Toon Link" name = "Toon Link"
}, },
@ -1834,6 +1840,9 @@ amiibo_tools.db =
["0x0800010003820002"] = { ["0x0800010003820002"] = {
name = "Inkling" name = "Inkling"
}, },
["0x0800010004150402"] = {
name = "Inkling - Yellow"
},
["0x08000200003f0402"] = { ["0x08000200003f0402"] = {
name = "Inkling Boy" name = "Inkling Boy"
}, },
@ -1870,9 +1879,15 @@ amiibo_tools.db =
["0x08050200038f0402"] = { ["0x08050200038f0402"] = {
name = "Octoling Boy" name = "Octoling Boy"
}, },
["0x08050200041b0402"] = {
name = "Octoling - Blue"
},
["0x0805030003900402"] = { ["0x0805030003900402"] = {
name = "Octoling Octopus" name = "Octoling Octopus"
}, },
["0x08060100041c0402"] = {
name = "Smallfry"
},
["0x09c0010102690e02"] = { ["0x09c0010102690e02"] = {
name = "Mario - Soccer" name = "Mario - Soccer"
}, },
@ -2374,6 +2389,9 @@ amiibo_tools.db =
["0x3380000003781402"] = { ["0x3380000003781402"] = {
name = "Solaire of Astora" name = "Solaire of Astora"
}, },
["0x33c0000004200002"] = {
name = "Kazuya"
},
["0x3480000000310002"] = { ["0x3480000000310002"] = {
name = "Mega Man" name = "Mega Man"
}, },
@ -2455,6 +2473,9 @@ amiibo_tools.db =
["0x3600010003620002"] = { ["0x3600010003620002"] = {
name = "Cloud - Player 2" name = "Cloud - Player 2"
}, },
["0x3601000004210002"] = {
name = "Sephiroth"
},
["0x3640000003a20002"] = { ["0x3640000003a20002"] = {
name = "Hero" name = "Hero"
}, },
@ -2520,6 +2541,12 @@ amiibo_tools.db =
}, },
["0x3c80000003a40002"] = { ["0x3c80000003a40002"] = {
name = "Terry" name = "Terry"
},
["0x3dc0000004220002"] = {
name = "Steve"
},
["0x3dc1000004230002"] = {
name = "Alex"
} }
}, },
game_series = { game_series = {
@ -2621,6 +2648,7 @@ amiibo_tools.db =
["0x324"] = "Bayonetta", ["0x324"] = "Bayonetta",
["0x334"] = "Pac-man", ["0x334"] = "Pac-man",
["0x338"] = "Dark Souls", ["0x338"] = "Dark Souls",
["0x33c"] = "Tekken",
["0x348"] = "Megaman", ["0x348"] = "Megaman",
["0x34c"] = "Street fighter", ["0x34c"] = "Street fighter",
["0x350"] = "Monster Hunter", ["0x350"] = "Monster Hunter",
@ -2635,7 +2663,8 @@ amiibo_tools.db =
["0x38c"] = "Diablo", ["0x38c"] = "Diablo",
["0x3a0"] = "Persona", ["0x3a0"] = "Persona",
["0x3b4"] = "Banjo Kazooie", ["0x3b4"] = "Banjo Kazooie",
["0x3c8"] = "Fatal Fury" ["0x3c8"] = "Fatal Fury",
["0x3dc"] = "Minecraft"
}, },
types = { types = {
["0x00"] = "Figure", ["0x00"] = "Figure",

112
client/pyscripts/pm3_nfc2eml.py Executable file
View file

@ -0,0 +1,112 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3
Date: 18/05/2023
Script Author: OscarAkaElvis
Tested on: Linux and Windows
OscarAkaElvis - https://twitter.com/OscarAkaElvis
"""
import re
import argparse
import os
from os import path
from sys import argv
# Vars
script_name = path.basename(argv[0])
script_version = "1.0"
# Function to print script's version
def print_version():
print()
return 'v{}'.format(script_version)
# Check if the input file is a text file based on its content
def is_text_file(file_path):
with open(file_path, 'rb') as file:
try:
file_content = file.read().decode('utf-8')
return all(ord(char) < 128 for char in file_content)
except UnicodeDecodeError:
return False
# Main script code
def main():
# Text help data
description_text = "Script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3."
epilog_text = 'Example:\n python3 ' + script_name + ' -i file.nfc -o output.eml'
# Create an argument parser
parser = argparse.ArgumentParser(exit_on_error=False, description=description_text, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=epilog_text)
# Add the input file argument
parser.add_argument("-i", "--input", required=True, help="Path to the input nfc file.")
# Add the output file argument
parser.add_argument("-o", "--output", required=True, help="Name of the output eml file.")
# Add the version argument
parser.add_argument('-v', '--version', action='version', version=print_version(), help="Show script's version number and exit")
# Parse the command-line arguments
args = parser.parse_args()
# Extract the file paths from the command-line arguments
file_path = args.input
output_file = args.output
# Check if the target file exists
if not os.path.isfile(file_path):
print(f"[!] The input file '{file_path}' does not exist.")
exit(0)
# Validation to check if the input file is a text file based on its content
if not is_text_file(file_path):
print("[!] The input file does not appear to be a nfc text file.")
# Check if the input file name has the .nfc extension
if not file_path.lower().endswith('.nfc'):
print("[+] Warning. The input file should have the '.nfc' extension.")
# Get the absolute path of the output file
output_file_path = os.path.abspath(output_file)
# Check if the directory of the output file is writable
output_dir = os.path.dirname(output_file_path)
if not os.access(output_dir, os.W_OK):
print(f"[!] The output directory '{output_dir}' is not writable or doesn't exist.")
# Check if the output file name has the .eml extension
if not output_file.lower().endswith('.eml'):
print("[+] Warning. The output file should have the '.eml' extension.")
# Read the target file
with open(file_path, 'r') as file:
file_content = file.read()
# Extract the data from each "Page X" line
matches = re.findall(r'Page \d+:(.*?)$', file_content, re.MULTILINE | re.DOTALL)
if matches:
# Remove spaces and convert to lowercase for each match
extracted_data = [re.sub(r'\s', '', match).lower() for match in matches]
# Join the extracted data with line feeds
result = '\n'.join(extracted_data)
# Write the extracted data to the output file
with open(output_file_path, 'w', newline='\n') as output_file:
output_file.write(result)
print(f"[*] File converted successfully. Output eml file written as '{os.path.basename(output_file.name)}'.")
else:
# If the needed data is not there
print("[!] Provided input file seems to not be a valid nfc file to work with.")
# Application entrypoint
if __name__ == '__main__':
try:
main()
except:
pass

View file

@ -2243,8 +2243,8 @@
"AID": "A0000002480400", "AID": "A0000002480400",
"Vendor": "ISO/IEC JTC1/SC17", "Vendor": "ISO/IEC JTC1/SC17",
"Country": "", "Country": "",
"Name": "Personal identification (mDL)", "Name": "Personal identification (mDL) data transfer",
"Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application.", "Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application data transfer.",
"Type": "identity" "Type": "identity"
}, },
{ {
@ -2259,10 +2259,26 @@
"AID": "A000000809434343444B467631", "AID": "A000000809434343444B467631",
"Vendor": "Car Connectivity Consortium (CCC)", "Vendor": "Car Connectivity Consortium (CCC)",
"Country": "", "Country": "",
"Name": "Digital Car Key Framework",
"Description": "Used during key provisioning and configuration",
"Type": "access"
},
{
"AID": "A000000809434343444B417631",
"Vendor": "Car Connectivity Consortium (CCC)",
"Country": "",
"Name": "Digital Car Key", "Name": "Digital Car Key",
"Description": "", "Description": "",
"Type": "access" "Type": "access"
}, },
{
"AID": "A0000008580102",
"Vendor": "Apple",
"Country": "",
"Name": "Apple Home Key Framework",
"Description": "Home Key configuration applet. Selected after a first transaction on a newely-invited device (allegedly for mailbox sync/attestation exchange)",
"Type": ""
},
{ {
"AID": "A0000008580101", "AID": "A0000008580101",
"Vendor": "Apple", "Vendor": "Apple",
@ -2270,5 +2286,45 @@
"Name": "Apple Home Key", "Name": "Apple Home Key",
"Description": "NFC Home Key for select HomeKit-compatible locks", "Description": "NFC Home Key for select HomeKit-compatible locks",
"Type": "access" "Type": "access"
},
{
"AID": "A000000396564341",
"Vendor": "NXP",
"Country": "",
"Name": "MIFARE 2GO",
"Description": "AID prefix used by MIFARE 2GO-based cards",
"Type": ""
},
{
"AID": "A0000002164954534F2D31",
"Vendor": "ITSO",
"Country": "United Kingdom",
"Name": "ITSO CMD2",
"Description": "AID used by ITSO for smartcard/phone-based transit cards",
"Type": "transit"
},
{
"AID": "A000000632010105",
"Vendor": "CTTIC",
"Country": "China",
"Name": "China T-Union",
"Description": "Universal transit card used by many big public transit operators",
"Type": "transit"
},
{
"AID": "D2760000254D010200",
"Vendor": "Zentraler Kreditausschuss (ZKA)",
"Country": "Germany",
"Name": "Girocard Jugendschutz",
"Description": "Age verification",
"Type": ""
},
{
"AID": "A00000000491",
"Vendor": "MasterCard International",
"Country": "",
"Name": "Mastercard Private Label Transit",
"Description": "AID prefix used by transit cards that use private label mastercards (E.g. Ventra and HOP)",
"Type": "transit"
} }
] ]

View file

@ -41,6 +41,7 @@
#include "atrs.h" // getATRinfo #include "atrs.h" // getATRinfo
#include "desfire.h" // desfire enums #include "desfire.h" // desfire enums
#include "mifare/desfirecore.h" // desfire context #include "mifare/desfirecore.h" // desfire context
#include "mifare/mifaredefault.h"
static bool g_apdu_in_framing_enable = true; static bool g_apdu_in_framing_enable = true;
bool Get_apdu_in_framing(void) { bool Get_apdu_in_framing(void) {
@ -738,9 +739,6 @@ int CmdHF14ASim(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
sector_t *k_sector = NULL;
uint8_t k_sectorsCount = 40;
if (useUIDfromEML) { if (useUIDfromEML) {
flags |= FLAG_UID_IN_EMUL; flags |= FLAG_UID_IN_EMUL;
} }
@ -761,17 +759,24 @@ int CmdHF14ASim(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp; PacketResponseNG resp;
sector_t *k_sector = NULL;
size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR;
PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
bool keypress = kbd_enter_pressed(); bool keypress = kbd_enter_pressed();
while (keypress == false) { while (keypress == false) {
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue; if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
if (resp.status != PM3_SUCCESS) break; continue;
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) break; if (resp.status != PM3_SUCCESS)
break;
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
break;
nonces_t *data = (nonces_t *)resp.data.asBytes; nonces_t *data = (nonces_t *)resp.data.asBytes;
readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose); readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
keypress = kbd_enter_pressed(); keypress = kbd_enter_pressed();
} }
@ -783,7 +788,8 @@ int CmdHF14ASim(const char *Cmd) {
} }
if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) { if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) {
showSectorTable(k_sector, k_sectorsCount); //iceman: readerAttack call frees k_sector , this call is useless.
showSectorTable(k_sector, k_sectors_cnt);
} }
} }

View file

@ -1359,6 +1359,7 @@ static int CmdHF14BDump(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "(optional) filename, if no <name> UID will be used as filename"), arg_str0("f", "file", "<fn>", "(optional) filename, if no <name> UID will be used as filename"),
arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1366,6 +1367,7 @@ static int CmdHF14BDump(const char *Cmd) {
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool nosave = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
@ -1514,15 +1516,17 @@ static int CmdHF14BDump(const char *Cmd) {
print_sr_blocks(data, cardsize, card.uid); print_sr_blocks(data, cardsize, card.uid);
// save to file if (nosave == false) {
if (fnlen < 1) { // save to file
PrintAndLogEx(INFO, "using UID as filename"); if (fnlen < 1) {
char *fptr = filename + snprintf(filename, sizeof(filename), "hf-14b-"); PrintAndLogEx(INFO, "using UID as filename");
FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), "-dump", card.uidlen); char *fptr = filename + snprintf(filename, sizeof(filename), "hf-14b-");
} FillFileNameByUID(fptr, SwapEndian64(card.uid, card.uidlen, 8), "-dump", card.uidlen);
}
size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE; size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE;
pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE); pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE);
}
} }
return switch_off_field_14b(); return switch_off_field_14b();

View file

@ -3836,9 +3836,9 @@ static int CmdHFiClassEncode(const char *Cmd) {
CLIParserInit(&ctx, "hf iclass encode", CLIParserInit(&ctx, "hf iclass encode",
"Encode binary wiegand to block 7,8,9\n" "Encode binary wiegand to block 7,8,9\n"
"Use either --bin or --wiegand/--fc/--cn", "Use either --bin or --wiegand/--fc/--cn",
"hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337\n" "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)\n"
"hf iclass encode --fc 31 --cn 337 --ki 0 -> FC 31 CN 337\n" "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)\n"
"hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key"
); );
void *argtable[] = { void *argtable[] = {

View file

@ -18,7 +18,6 @@
#include "cmdhfmf.h" #include "cmdhfmf.h"
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "comms.h" // clearCommandBuffer #include "comms.h" // clearCommandBuffer
@ -38,23 +37,6 @@
#include "wiegand_formats.h" #include "wiegand_formats.h"
#include "wiegand_formatutils.h" #include "wiegand_formatutils.h"
#define MIFARE_4K_MAXBLOCK 256
#define MIFARE_2K_MAXBLOCK 128
#define MIFARE_1K_MAXBLOCK 64
#define MIFARE_MINI_MAXBLOCK 20
#define MIFARE_4K_MAXSECTOR 40
#define MIFARE_2K_MAXSECTOR 32
#define MIFARE_1K_MAXSECTOR 16
#define MIFARE_MINI_MAXSECTOR 5
#define MIFARE_4K_MAX_BYTES 4096
#define MIFARE_2K_MAX_BYTES 2048
#define MIFARE_1K_MAX_BYTES 1024
#define MIFARE_MINI_MAX_BYTES 320
#define MIFARE_KEY_SIZE 6
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
/* /*
@ -152,21 +134,20 @@ static char *GenerateFilename(const char *prefix, const char *suffix) {
return fptr; return fptr;
} }
static int32_t initSectorTable(sector_t **src, int32_t items) { static int initSectorTable(sector_t **src, size_t items) {
(*src) = calloc(items, sizeof(sector_t)); (*src) = calloc(items, sizeof(sector_t));
if (*src == NULL) if (*src == NULL)
return -1; return PM3_EMALLOC;
// empty e_sector // empty e_sector
for (int i = 0; i < items; ++i) { for (size_t i = 0; i < items; i++) {
for (int j = 0; j < 2; ++j) { for (uint8_t j = 0; j < 2; j++) {
(*src)[i].Key[j] = 0xffffffffffff; (*src)[i].Key[j] = 0xffffffffffff;
(*src)[i].foundKey[j] = false; (*src)[i].foundKey[j] = 0;
} }
} }
return items; return PM3_SUCCESS;
} }
static void decode_print_st(uint16_t blockno, uint8_t *data) { static void decode_print_st(uint16_t blockno, uint8_t *data) {
@ -313,17 +294,21 @@ static int mf_print_keys(uint16_t n, uint8_t *d) {
sectors = MIFARE_4K_MAXSECTOR; sectors = MIFARE_4K_MAXSECTOR;
break; break;
case MIFARE_1K_MAXBLOCK: case MIFARE_1K_MAXBLOCK:
sectors = MIFARE_1K_MAXSECTOR;
break;
default: default:
sectors = MIFARE_1K_MAXSECTOR; sectors = MIFARE_1K_MAXSECTOR;
n = MIFARE_1K_MAXBLOCK;
break; break;
} }
sector_t *e_sector = calloc(sectors, sizeof(sector_t)); sector_t *e_sector = calloc(sectors, sizeof(sector_t));
if (e_sector == NULL) { if (e_sector == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
for (uint16_t i = 0; i < n; i++) { for (uint16_t i = 0; i < n; i++) {
if (mfIsSectorTrailer(i)) { if (mfIsSectorTrailer(i)) {
e_sector[mfSectorNum(i)].foundKey[0] = 1; e_sector[mfSectorNum(i)].foundKey[0] = 1;
e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE); e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE);
@ -1127,7 +1112,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
"Restore MIFARE Classic dump file to tag.\n" "Restore MIFARE Classic dump file to tag.\n"
"\n" "\n"
"The key file and dump file will program the card sector trailers.\n" "The key file and dump file will program the card sector trailers.\n"
"By default we authenticate to card with key B 0xFFFFFFFFFFFF.\n" "By default we authenticate to card with key 0xFFFFFFFFFFFF.\n"
"If access rights in dump file is all zeros, it will be replaced with default values\n" "If access rights in dump file is all zeros, it will be replaced with default values\n"
"\n" "\n"
"`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n" "`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
@ -1339,56 +1324,37 @@ static int CmdHF14AMfRestore(const char *Cmd) {
uint8_t wdata[26]; uint8_t wdata[26];
memcpy(wdata + 10, bldata, sizeof(bldata)); memcpy(wdata + 10, bldata, sizeof(bldata));
if (use_keyfile_for_auth) { for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
for (int8_t kt = MF_KEY_B; kt > -1; kt--) { if (use_keyfile_for_auth) {
if (kt == MF_KEY_A) if (kt == MF_KEY_A)
memcpy(wdata, keyA[s], 6); memcpy(wdata, keyA[s], 6);
else else
memcpy(wdata, keyB[s], 6); memcpy(wdata, keyB[s], 6);
} else {
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata))); // use default key to authenticate for the write command
memcpy(wdata, default_key, 6);
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK == 0) {
if (b == 0) {
PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B');
} else {
PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B');
}
} else {
// if success, skip to next block
break;
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
}
} }
} else {
// use default key to authenticate for the write command
memcpy(wdata, default_key, 6);
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata))); PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, MF_KEY_B, 0, wdata, sizeof(wdata)); SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata));
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff; uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK == 0) { if (isOK == 0) {
if (b == 0) { if (b == 0) {
PrintAndLogEx(INFO, "Writing to manufacture block w key B ( " _RED_("fail") " )"); PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B');
} else { } else {
PrintAndLogEx(FAILED, "Write to block %u w key B ( " _RED_("fail") " )", b); PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B');
} }
} else {
// if success, skip to next block
break;
} }
} else { } else {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
} }
} // end use_keyfile_for_auth }
} // end loop B } // end loop B
} // end loop S } // end loop S
@ -2373,7 +2339,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
// Attack key storage variables // Attack key storage variables
uint8_t *keyBlock = NULL; uint8_t *keyBlock = NULL;
uint32_t key_cnt = 0; uint32_t key_cnt = 0;
sector_t *e_sector;
uint8_t tmp_key[6] = {0}; uint8_t tmp_key[6] = {0};
// Nested and Hardnested returned status // Nested and Hardnested returned status
@ -2408,7 +2373,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
iso14a_card_select_t card; iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
// detect MFC EV1 Signature // detect MFC EV1 Signature
bool is_ev1 = detect_mfc_ev1_signature(); bool is_ev1 = detect_mfc_ev1_signature();
if (is_ev1) { if (is_ev1) {
@ -2417,10 +2381,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
} }
// create/initialize key storage structure // create/initialize key storage structure
uint32_t e_sector_size = sector_cnt > sectorno ? sector_cnt : sectorno + 1; sector_t *e_sector = NULL;
res = initSectorTable(&e_sector, e_sector_size); size_t e_sector_cnt = (sector_cnt > sectorno) ? sector_cnt : sectorno + 1;
if (res != e_sector_size) { if (initSectorTable(&e_sector, e_sector_cnt) != PM3_SUCCESS) {
free(e_sector);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -2859,8 +2822,11 @@ tryNested:
} }
break; break;
} }
case PM3_ESTATIC_NONCE: case PM3_ESTATIC_NONCE: {
PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n");
e_sector[current_sector_i].Key[current_key_type_i] = 0xffffffffffff;;
e_sector[current_sector_i].foundKey[current_key_type_i] = false;
// Show the results to the user // Show the results to the user
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
@ -2869,6 +2835,7 @@ tryNested:
free(e_sector); free(e_sector);
free(fptr); free(fptr);
return isOK; return isOK;
}
case PM3_SUCCESS: { case PM3_SUCCESS: {
calibrate = false; calibrate = false;
e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6);
@ -2893,6 +2860,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
slow ? "Yes" : "No"); slow ? "Yes" : "No");
} }
foundkey = 0;
isOK = mfnestedhard(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL); isOK = mfnestedhard(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
DropField(); DropField();
if (isOK) { if (isOK) {
@ -2907,6 +2875,10 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
} }
case PM3_ESTATIC_NONCE: { case PM3_ESTATIC_NONCE: {
PrintAndLogEx(ERR, "\nError: Static encrypted nonce detected. Aborted\n"); PrintAndLogEx(ERR, "\nError: Static encrypted nonce detected. Aborted\n");
e_sector[current_sector_i].Key[current_key_type_i] = 0xffffffffffff;;
e_sector[current_sector_i].foundKey[current_key_type_i] = false;
// Show the results to the user // Show the results to the user
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
@ -3181,7 +3153,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
m1 = true; m1 = true;
} }
uint8_t sectorsCnt = 1; uint8_t sectorsCnt = MIFARE_1K_MAXSECTOR;
if (m0) { if (m0) {
sectorsCnt = MIFARE_MINI_MAXSECTOR; sectorsCnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) { } else if (m1) {
@ -3204,8 +3176,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
// create/initialize key storage structure // create/initialize key storage structure
sector_t *e_sector = NULL; sector_t *e_sector = NULL;
int32_t res = initSectorTable(&e_sector, sectorsCnt); if (initSectorTable(&e_sector, sectorsCnt) != PM3_SUCCESS) {
if (res != sectorsCnt) {
free(keyBlock); free(keyBlock);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -3240,7 +3211,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
if (size == keycnt - i) if (size == keycnt - i)
lastChunk = true; lastChunk = true;
res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); int res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false);
if (firstChunk) if (firstChunk)
firstChunk = false; firstChunk = false;
@ -3398,42 +3369,42 @@ static int CmdHF14AMfChk(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t SectorsCnt = 1; size_t sectors_cnt = 1;
if (m0) { if (m0) {
SectorsCnt = MIFARE_MINI_MAXSECTOR; sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) { } else if (m1) {
SectorsCnt = MIFARE_1K_MAXSECTOR; sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (m2) { } else if (m2) {
SectorsCnt = MIFARE_2K_MAXSECTOR; sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (m4) { } else if (m4) {
SectorsCnt = MIFARE_4K_MAXSECTOR; sectors_cnt = MIFARE_4K_MAXSECTOR;
} }
if (singleSector) { if (singleSector) {
uint8_t MinSectorsCnt = 0; size_t min_sectors_cnt = 0;
// find a MIFARE type that can accommodate the provided block number // find a MIFARE type that can accommodate the provided block number
uint8_t s = mfSectorNum(blockNo); uint8_t s = mfSectorNum(blockNo);
if (s < MIFARE_MINI_MAXSECTOR) { if (s < MIFARE_MINI_MAXSECTOR) {
MinSectorsCnt = MIFARE_MINI_MAXSECTOR; min_sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (s < MIFARE_1K_MAXSECTOR) { } else if (s < MIFARE_1K_MAXSECTOR) {
MinSectorsCnt = MIFARE_1K_MAXSECTOR; min_sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (s < MIFARE_2K_MAXSECTOR) { } else if (s < MIFARE_2K_MAXSECTOR) {
MinSectorsCnt = MIFARE_2K_MAXSECTOR; min_sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (s < MIFARE_4K_MAXSECTOR) { } else if (s < MIFARE_4K_MAXSECTOR) {
MinSectorsCnt = MIFARE_4K_MAXSECTOR; min_sectors_cnt = MIFARE_4K_MAXSECTOR;
} else { } else {
PrintAndLogEx(WARNING, "Provided block out of possible MIFARE Type memory map"); PrintAndLogEx(WARNING, "Provided block out of possible MIFARE Type memory map");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (SectorsCnt == 1) { if (sectors_cnt == 1) {
SectorsCnt = MinSectorsCnt; sectors_cnt = min_sectors_cnt;
} else if (SectorsCnt < MinSectorsCnt) { } else if (sectors_cnt < min_sectors_cnt) {
PrintAndLogEx(WARNING, "Provided block out of provided MIFARE Type memory map"); PrintAndLogEx(WARNING, "Provided block out of provided MIFARE Type memory map");
return PM3_EINVARG; return PM3_EINVARG;
} }
} }
if (SectorsCnt == 1) { if (sectors_cnt == 1) {
SectorsCnt = MIFARE_1K_MAXSECTOR; sectors_cnt = MIFARE_1K_MAXSECTOR;
} }
uint8_t *keyBlock = NULL; uint8_t *keyBlock = NULL;
@ -3447,8 +3418,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
// create/initialize key storage structure // create/initialize key storage structure
sector_t *e_sector = NULL; sector_t *e_sector = NULL;
int32_t res = initSectorTable(&e_sector, SectorsCnt); if (initSectorTable(&e_sector, sectors_cnt) != PM3_SUCCESS) {
if (res != SectorsCnt) {
free(keyBlock); free(keyBlock);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -3473,7 +3443,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
// loop sectors but block is used as to keep track of from which blocks to test // loop sectors but block is used as to keep track of from which blocks to test
int b = blockNo; int b = blockNo;
for (int i = mfSectorNum(b); i < SectorsCnt; ++i) { for (int i = mfSectorNum(b); i < sectors_cnt; ++i) {
// skip already found keys. // skip already found keys.
if (e_sector[i].foundKey[trgKeyType]) continue; if (e_sector[i].foundKey[trgKeyType]) continue;
@ -3512,7 +3482,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
// loop sectors but block is used as to keep track of from which blocks to test // loop sectors but block is used as to keep track of from which blocks to test
int b = blockNo; int b = blockNo;
for (int i = mfSectorNum(b); i < SectorsCnt; i++) { for (int i = mfSectorNum(b); i < sectors_cnt; i++) {
// KEY A but not KEY B // KEY A but not KEY B
if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
@ -3558,13 +3528,13 @@ out:
if (singleSector) if (singleSector)
printKeyTableEx(1, e_sector, mfSectorNum(blockNo)); printKeyTableEx(1, e_sector, mfSectorNum(blockNo));
else else
printKeyTable(SectorsCnt, e_sector); printKeyTable(sectors_cnt, e_sector);
if (transferToEml) { if (transferToEml) {
// fast push mode // fast push mode
g_conn.block_after_ACK = true; g_conn.block_after_ACK = true;
uint8_t block[16] = {0x00}; uint8_t block[16] = {0x00};
for (int i = 0; i < SectorsCnt; ++i) { for (int i = 0; i < sectors_cnt; ++i) {
uint8_t blockno = mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1; uint8_t blockno = mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1;
mfEmlGetMem(block, blockno, 1); mfEmlGetMem(block, blockno, 1);
@ -3574,7 +3544,7 @@ out:
if (e_sector[i].foundKey[1]) if (e_sector[i].foundKey[1])
num_to_bytes(e_sector[i].Key[1], 6, block + 10); num_to_bytes(e_sector[i].Key[1], 6, block + 10);
if (i == SectorsCnt - 1) { if (i == sectors_cnt - 1) {
// Disable fast mode on last packet // Disable fast mode on last packet
g_conn.block_after_ACK = false; g_conn.block_after_ACK = false;
} }
@ -3585,7 +3555,7 @@ out:
if (createDumpFile) { if (createDumpFile) {
char *fptr = GenerateFilename("hf-mf-", "-key.bin"); char *fptr = GenerateFilename("hf-mf-", "-key.bin");
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, sectors_cnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
} }
free(fptr); free(fptr);
@ -3606,28 +3576,24 @@ out:
return PM3_SUCCESS; return PM3_SUCCESS;
} }
void showSectorTable(sector_t *k_sector, uint8_t k_sectorsCount) { void showSectorTable(sector_t *k_sector, size_t k_sectors_cnt) {
if (k_sector != NULL) { if (k_sector != NULL) {
printKeyTable(k_sectorsCount, k_sector); printKeyTable(k_sectors_cnt, k_sector);
free(k_sector); free(k_sector);
} }
} }
void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, bool setEmulatorMem, bool verbose) { void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose) {
uint64_t key = 0;
bool success = false;
// init if needed
if (k_sector == NULL) { if (k_sector == NULL) {
int32_t res = initSectorTable(&k_sector, k_sectorsCount); if (initSectorTable(&k_sector, k_sectors_cnt) != PM3_SUCCESS) {
if (res != k_sectorsCount) {
free(k_sector);
return; return;
} }
} }
success = mfkey32_moebius(&data, &key); uint64_t key = 0;
if (success) { if (mfkey32_moebius(&data, &key)) {
uint8_t sector = data.sector; uint8_t sector = data.sector;
uint8_t keytype = data.keytype; uint8_t keytype = data.keytype;
@ -3642,7 +3608,7 @@ void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, boo
//set emulator memory for keys //set emulator memory for keys
if (setEmulatorMem) { if (setEmulatorMem) {
uint8_t memBlock[16] = {0, 0, 0, 0, 0, 0, 0xff, 0x0F, 0x80, 0x69, 0, 0, 0, 0, 0, 0}; uint8_t memBlock[16] = {0, 0, 0, 0, 0, 0, 0xFF, 0x07, 0x80, 0x69, 0, 0, 0, 0, 0, 0};
num_to_bytes(k_sector[sector].Key[0], 6, memBlock); num_to_bytes(k_sector[sector].Key[0], 6, memBlock);
num_to_bytes(k_sector[sector].Key[1], 6, memBlock + 10); num_to_bytes(k_sector[sector].Key[1], 6, memBlock + 10);
//iceman, guessing this will not work so well for 4K tags. //iceman, guessing this will not work so well for 4K tags.
@ -3751,22 +3717,19 @@ static int CmdHF14AMfSim(const char *Cmd) {
} }
CLIParserFree(ctx); CLIParserFree(ctx);
sector_t *k_sector = NULL;
//Validations //Validations
if (atqalen > 0) { if (atqalen > 0) {
if (atqalen != 2) { if (atqalen != 2) {
PrintAndLogEx(WARNING, "Wrong ATQA length"); PrintAndLogEx(WARNING, "Wrong ATQA length");
return PM3_EINVARG; return PM3_EINVARG;
} }
flags |= FLAG_FORCED_ATQA; flags |= FLAG_FORCED_ATQA;
} }
if (saklen > 0) { if (saklen > 0) {
if (saklen != 1) { if (saklen != 1) {
PrintAndLogEx(WARNING, "Wrong SAK length"); PrintAndLogEx(WARNING, "Wrong SAK length");
return PM3_EINVARG; return PM3_EINVARG;
} }
flags |= FLAG_FORCED_SAK; flags |= FLAG_FORCED_SAK;
} }
@ -3776,7 +3739,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
flags |= FLAG_UID_IN_EMUL; flags |= FLAG_UID_IN_EMUL;
} }
uint8_t k_sectorsCount = 40; size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR;
char csize[13] = { 0 }; char csize[13] = { 0 };
if ((m0 + m1 + m2 + m4) > 1) { if ((m0 + m1 + m2 + m4) > 1) {
@ -3787,19 +3750,19 @@ static int CmdHF14AMfSim(const char *Cmd) {
if (m0) { if (m0) {
flags |= FLAG_MF_MINI; flags |= FLAG_MF_MINI;
snprintf(csize, sizeof(csize), "MINI"); snprintf(csize, sizeof(csize), "MINI");
k_sectorsCount = MIFARE_MINI_MAXSECTOR; k_sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) { } else if (m1) {
flags |= FLAG_MF_1K; flags |= FLAG_MF_1K;
snprintf(csize, sizeof(csize), "1K"); snprintf(csize, sizeof(csize), "1K");
k_sectorsCount = MIFARE_1K_MAXSECTOR; k_sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (m2) { } else if (m2) {
flags |= FLAG_MF_2K; flags |= FLAG_MF_2K;
snprintf(csize, sizeof(csize), "2K with RATS"); snprintf(csize, sizeof(csize), "2K with RATS");
k_sectorsCount = MIFARE_2K_MAXSECTOR; k_sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (m4) { } else if (m4) {
flags |= FLAG_MF_4K; flags |= FLAG_MF_4K;
snprintf(csize, sizeof(csize), "4K"); snprintf(csize, sizeof(csize), "4K");
k_sectorsCount = MIFARE_4K_MAXSECTOR; k_sectors_cnt = MIFARE_4K_MAXSECTOR;
} else { } else {
PrintAndLogEx(WARNING, "Please specify a MIFARE Type"); PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
return PM3_EINVARG; return PM3_EINVARG;
@ -3837,15 +3800,26 @@ static int CmdHF14AMfSim(const char *Cmd) {
if (flags & FLAG_INTERACTIVE) { if (flags & FLAG_INTERACTIVE) {
PrintAndLogEx(INFO, "Press pm3-button or send another cmd to abort simulation"); PrintAndLogEx(INFO, "Press pm3-button or send another cmd to abort simulation");
while (!kbd_enter_pressed()) { sector_t *k_sector = NULL;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
if (!(flags & FLAG_NR_AR_ATTACK)) break; while (kbd_enter_pressed() == 0) {
if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false)
continue;
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
break;
if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE)
break;
nonces_t data[1]; nonces_t data[1];
memcpy(data, resp.data.asBytes, sizeof(data)); memcpy(data, resp.data.asBytes, sizeof(data));
readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose); readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
} }
showSectorTable(k_sector, k_sectorsCount); //iceman: readerAttack call frees k_sector. this call below is useless.
showSectorTable(k_sector, k_sectors_cnt);
} else { } else {
PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
} }
@ -3885,11 +3859,11 @@ static int CmdHF14AMfKeyBrute(const char *Cmd) {
} }
*/ */
void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) { void printKeyTable(size_t sectorscnt, sector_t *e_sector) {
return printKeyTableEx(sectorscnt, e_sector, 0); return printKeyTableEx(sectorscnt, e_sector, 0);
} }
void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector) { void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector) {
char strA[26 + 1] = {0}; char strA[26 + 1] = {0};
char strB[26 + 1] = {0}; char strB[26 + 1] = {0};
char resA[20 + 1] = {0}; char resA[20 + 1] = {0};
@ -3899,57 +3873,62 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
PrintAndLogEx(SUCCESS, " Sec | Blk | key A |res| key B |res"); PrintAndLogEx(SUCCESS, " Sec | Blk | key A |res| key B |res");
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
for (uint8_t i = 0; i < sectorscnt; i++) {
snprintf(strA, sizeof(strA), "------------"); uint64_t ndef_key = 0xD3F7D3F7D3F7;
snprintf(strB, sizeof(strB), "------------"); bool has_ndef_key = false;
bool extended_legend = false;
for (size_t i = 0; i < sectorscnt; i++) {
if (e_sector[i].foundKey[0]) if ((e_sector[i].foundKey[0] > 1) || (e_sector[i].foundKey[1] > 1)) {
snprintf(strA, sizeof(strA), "%012" PRIX64, e_sector[i].Key[0]); extended_legend = true;
if (e_sector[i].foundKey[1])
snprintf(strB, sizeof(strB), "%012" PRIX64, e_sector[i].Key[1]);
if (e_sector[i].foundKey[0] > 1) {
PrintAndLogEx(SUCCESS, " "_YELLOW_("%03d")" | %03d | " _GREEN_("%s")" | " _BRIGHT_GREEN_("%c")" | " _GREEN_("%s")" | " _BRIGHT_GREEN_("%c")
, i
, mfSectorTrailerOfSector(i)
, strA, e_sector[i].foundKey[0]
, strB, e_sector[i].foundKey[1]
);
} else {
// keep track if we use start_sector or i...
uint8_t s = start_sector;
if (start_sector == 0)
s = i;
if (e_sector[i].foundKey[0]) {
snprintf(strA, sizeof(strA), _GREEN_("%012" PRIX64), e_sector[i].Key[0]);
snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%d"), 1);
} else {
snprintf(strA, sizeof(strA), _RED_("%s"), "------------");
snprintf(resA, sizeof(resA), _RED_("%d"), 0);
}
if (e_sector[i].foundKey[1]) {
snprintf(strB, sizeof(strB), _GREEN_("%012" PRIX64), e_sector[i].Key[1]);
snprintf(resB, sizeof(resB), _BRIGHT_GREEN_("%d"), 1);
} else {
snprintf(strB, sizeof(strB), _RED_("%s"), "------------");
snprintf(resB, sizeof(resB), _RED_("%d"), 0);
}
PrintAndLogEx(SUCCESS, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s"
, s
, mfSectorTrailerOfSector(s)
, strA, resA
, strB, resB
);
} }
if (e_sector[i].Key[0] == ndef_key || e_sector[i].Key[1] == ndef_key) {
has_ndef_key = true;
}
if (e_sector[i].foundKey[0]) {
snprintf(strA, sizeof(strA), _GREEN_("%012" PRIX64), e_sector[i].Key[0]);
if (extended_legend) {
snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%c"), e_sector[i].foundKey[0]);
} else {
snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%d"), e_sector[i].foundKey[0]);
}
} else {
snprintf(strA, sizeof(strA), _RED_("%s"), "------------");
snprintf(resA, sizeof(resA), _RED_("0"));
}
if (e_sector[i].foundKey[1]) {
snprintf(strB, sizeof(strB), _GREEN_("%012" PRIX64), e_sector[i].Key[1]);
if (extended_legend) {
snprintf(resB, sizeof(resB), _BRIGHT_GREEN_("%c"), e_sector[i].foundKey[1]);
} else {
snprintf(resB, sizeof(resB), _BRIGHT_GREEN_("%d"), e_sector[i].foundKey[1]);
}
} else {
snprintf(strB, sizeof(strB), _RED_("%s"), "------------");
snprintf(resB, sizeof(resB), _RED_("0"));
}
// keep track if we use start_sector or i
// show one sector or all.
uint8_t s = start_sector;
if (start_sector == 0) {
s = i;
}
PrintAndLogEx(SUCCESS, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s"
, s
, mfSectorTrailerOfSector(s)
, strA, resA
, strB, resB
);
} }
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
if (e_sector[0].foundKey[0] > 1) {
if (extended_legend) {
PrintAndLogEx(INFO, "( " PrintAndLogEx(INFO, "( "
_YELLOW_("D") ":Dictionary / " _YELLOW_("D") ":Dictionary / "
_YELLOW_("S") ":darkSide / " _YELLOW_("S") ":darkSide / "
@ -3966,9 +3945,13 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
} }
// MAD detection // MAD detection
if (e_sector[MF_MAD1_SECTOR].foundKey[0] && e_sector[MF_MAD1_SECTOR].Key[MF_KEY_A] == 0xA0A1A2A3A4A5) { if (e_sector[MF_MAD1_SECTOR].foundKey[0] && e_sector[MF_MAD1_SECTOR].Key[0] == 0xA0A1A2A3A4A5) {
PrintAndLogEx(HINT, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details"); PrintAndLogEx(HINT, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details");
} }
// NDEF detection
if (has_ndef_key) {
PrintAndLogEx(HINT, "NDEF key detected. Try " _YELLOW_("`hf mf ndefread`") " for more details");
}
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
} }
@ -4572,7 +4555,7 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
m1 = true; m1 = true;
} }
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR; size_t sectors_cnt = MIFARE_1K_MAXSECTOR;
if (m0) { if (m0) {
sectors_cnt = MIFARE_MINI_MAXSECTOR; sectors_cnt = MIFARE_MINI_MAXSECTOR;
@ -4587,12 +4570,9 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
sector_t *e_sector = NULL;
// create/initialize key storage structure // create/initialize key storage structure
int32_t res = initSectorTable(&e_sector, sectors_cnt); sector_t *e_sector = NULL;
if (res != sectors_cnt) { if (initSectorTable(&e_sector, sectors_cnt) != PM3_SUCCESS) {
free(e_sector);
return PM3_EMALLOC; return PM3_EMALLOC;
} }

View file

@ -30,11 +30,10 @@ int CmdHFMFNDEFRead(const char *Cmd); // used by "nfc mf cread"
int CmdHFMFNDEFFormat(const char *Cmd); // used by "nfc mf cformat" int CmdHFMFNDEFFormat(const char *Cmd); // used by "nfc mf cformat"
int CmdHFMFNDEFWrite(const char *Cmd); // used by "nfc mf cwrite" int CmdHFMFNDEFWrite(const char *Cmd); // used by "nfc mf cwrite"
void showSectorTable(sector_t *k_sector, uint8_t k_sectorsCount); void showSectorTable(sector_t *k_sector, size_t k_sectors_cnt);
void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, bool setEmulatorMem, bool verbose); void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose);
void printKeyTable(uint8_t sectorscnt, sector_t *e_sector); void printKeyTable(size_t sectorscnt, sector_t *e_sector);
void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector); void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector);
void printKeyTable_fast(uint8_t sectorscnt, icesector_t *e_sector, uint64_t bar, uint64_t foo);
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len); int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
#endif #endif

View file

@ -1006,15 +1006,17 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) {
// main cycle with key check // main cycle with key check
for (int i = 0; i < keyListLen; i++) { for (int i = 0; i < keyListLen; i++) {
// allow client abort every iteration
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
DropField();
return PM3_EOPABORTED;
}
if (i % 10 == 0) { if (i % 10 == 0) {
if (verbose == false) {
if (verbose == false)
PrintAndLogEx(NORMAL, "." NOLF); PrintAndLogEx(NORMAL, "." NOLF);
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
DropField();
return PM3_EOPABORTED;
} }
} }
@ -1024,7 +1026,7 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
for (int retry = 0; retry < 4; retry++) { for (int retry = 0; retry < 4; retry++) {
res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true);
if (res == PM3_SUCCESS || PM3_EWRONGANSWER) if (res == PM3_SUCCESS || res == PM3_EWRONGANSWER)
break; break;
if (verbose) if (verbose)
@ -1037,9 +1039,6 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
msleep(100); msleep(100);
} }
if (verbose)
PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res);
// key for [sector,keyAB] found // key for [sector,keyAB] found
if (res == PM3_SUCCESS) { if (res == PM3_SUCCESS) {
if (verbose) if (verbose)
@ -1052,9 +1051,14 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
DropField(); DropField();
selectCard = true; selectCard = true;
msleep(50); msleep(50);
// break out from keylist check loop,
break; break;
} }
if (verbose)
PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res);
// RES can be: // RES can be:
// PM3_ERFTRANS -7 // PM3_ERFTRANS -7
// PM3_EWRONGANSWER -16 // PM3_EWRONGANSWER -16

View file

@ -2439,6 +2439,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
arg_lit0("l", NULL, "Swap entered key's endianness"), arg_lit0("l", NULL, "Swap entered key's endianness"),
arg_int0("p", "page", "<dec>", "Manually set start page number to start from"), arg_int0("p", "page", "<dec>", "Manually set start page number to start from"),
arg_int0("q", "qty", "<dec>", "Manually set number of pages to dump"), arg_int0("q", "qty", "<dec>", "Manually set number of pages to dump"),
arg_lit0(NULL, "ns", "no save to file"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2454,6 +2455,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
bool swap_endian = arg_get_lit(ctx, 3); bool swap_endian = arg_get_lit(ctx, 3);
int start_page = arg_get_int_def(ctx, 4, 0); int start_page = arg_get_int_def(ctx, 4, 0);
int pages = arg_get_int_def(ctx, 5, 16); int pages = arg_get_int_def(ctx, 5, 16);
bool nosave = arg_get_lit(ctx, 6);
CLIParserFree(ctx); CLIParserFree(ctx);
bool has_auth_key = false; bool has_auth_key = false;
@ -2649,21 +2651,24 @@ static int CmdHF14AMfUDump(const char *Cmd) {
printMFUdumpEx(&dump_file_data, pages, start_page); printMFUdumpEx(&dump_file_data, pages, start_page);
// user supplied filename? if (nosave == false) {
if (fnlen < 1) { // user supplied filename?
if (fnlen < 1) {
PrintAndLogEx(INFO, "Using UID as filename");
uint8_t uid[7] = {0};
memcpy(uid, (uint8_t *)&dump_file_data.data, 3);
memcpy(uid + 3, (uint8_t *)&dump_file_data.data + 4, 4);
strcat(filename, "hf-mfu-");
FillFileNameByUID(filename, uid, "-dump", sizeof(uid));
}
PrintAndLogEx(INFO, "Using UID as filename"); uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
uint8_t uid[7] = {0}; pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE);
memcpy(uid, (uint8_t *)&dump_file_data.data, 3);
memcpy(uid + 3, (uint8_t *)&dump_file_data.data + 4, 4); if (is_partial) {
strcat(filename, "hf-mfu-"); PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
FillFileNameByUID(filename, uid, "-dump", sizeof(uid)); }
} }
uint16_t datalen = pages * MFU_BLOCK_SIZE + MFU_DUMP_PREFIX_LENGTH;
pm3_save_dump(filename, (uint8_t *)&dump_file_data, datalen, jsfMfuMemory, MFU_BLOCK_SIZE);
if (is_partial)
PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2685,7 +2690,7 @@ static void wait4response(uint8_t b) {
int CmdHF14MfUTamper(const char *Cmd) { int CmdHF14MfUTamper(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu tamper", CLIParserInit(&ctx, "hf mfu tamper",
"Set the congiguration of the NTAG 213TT tamper feature\n" "Set the configuration of the NTAG 213TT tamper feature\n"
"Supports:\n" "Supports:\n"
"NTAG 213TT\n", "NTAG 213TT\n",
"hf mfu tamper -e -> enable tamper feature\n" "hf mfu tamper -e -> enable tamper feature\n"
@ -4692,7 +4697,7 @@ static command_t CommandTable[] = {
{"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"},
{"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"}, {"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"},
{"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"},
{"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Cofigure the tamper feature on an NTAG 213TT"}, {"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Configure the tamper feature on an NTAG 213TT"},
{"---------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"---------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"},
{"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into emulator memory"}, {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into emulator memory"},
{"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save Ultralight dump file from emulator memory"}, {"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save Ultralight dump file from emulator memory"},

View file

@ -324,6 +324,37 @@ static int CmdLFHitagSim(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static void printHitag2PaxtonDowngrade(const uint8_t *data) {
uint64_t bytes = 0;
uint64_t num = 0;
uint64_t paxton_id = 0;
uint16_t skip = 48;
uint16_t digit = 0;
uint64_t mask = 0xF80000000000;
for (int i = 16; i < 22; i++) {
bytes = (bytes * 0x100) + data[i];
}
for (int j = 0; j< 8; j++) {
num = bytes & mask;
skip -= 5;
mask = mask >> 5;
digit = (num >> skip & 15);
paxton_id = (paxton_id * 10) + digit;
if (j == 5) {
skip -= 2;
mask = mask >> 2;
}
}
PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------");
PrintAndLogEx(SUCCESS, "Paxton id: %lu | 0x%lx", paxton_id, paxton_id);
}
static void printHitag2Configuration(uint8_t config) { static void printHitag2Configuration(uint8_t config) {
char msg[100]; char msg[100];
@ -630,6 +661,8 @@ static int CmdLFHitagReader(const char *Cmd) {
// print data // print data
print_hex_break(data, 48, 4); print_hex_break(data, 48, 4);
printHitag2PaxtonDowngrade(data);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -397,7 +397,8 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p
} }
void printT5xxHeader(uint8_t page) { void printT5xxHeader(uint8_t page) {
PrintAndLogEx(SUCCESS, "Reading Page %d:", page); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Page " _YELLOW_("%d"), page);
PrintAndLogEx(SUCCESS, "blk | hex data | binary | ascii"); PrintAndLogEx(SUCCESS, "blk | hex data | binary | ascii");
PrintAndLogEx(SUCCESS, "----+----------+----------------------------------+-------"); PrintAndLogEx(SUCCESS, "----+----------+----------------------------------+-------");
} }
@ -815,7 +816,7 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
break; break;
} }
PrintAndLogEx(NORMAL, msg); PrintAndLogEx(SUCCESS, msg);
} }
static int CmdT55xxWakeUp(const char *Cmd) { static int CmdT55xxWakeUp(const char *Cmd) {
@ -2222,14 +2223,15 @@ static int CmdT55xxDump(const char *Cmd) {
"lf t55xx dump -f my_lf_dump" "lf t55xx dump -f my_lf_dump"
); );
// 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE) // 1 (help) + 4 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
void *argtable[4 + 5] = { void *argtable[5 + 5] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "filename (default is generated on blk 0)"), arg_str0("f", "file", "<fn>", "filename (default is generated on blk 0)"),
arg_lit0("o", "override", "override, force pwd read despite danger to card"), arg_lit0("o", "override", "override, force pwd read despite danger to card"),
arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"), arg_str0("p", "pwd", "<hex>", "password (4 hex bytes)"),
arg_lit0(NULL, "ns", "no save"),
}; };
uint8_t idx = 4; uint8_t idx = 5;
arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, T55XX_DLMODE_SINGLE); arg_add_t55xx_downloadlink(argtable, &idx, T55XX_DLMODE_SINGLE, T55XX_DLMODE_SINGLE);
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2251,10 +2253,12 @@ static int CmdT55xxDump(const char *Cmd) {
usepwd = true; usepwd = true;
} }
bool r0 = arg_get_lit(ctx, 4); bool nosave = arg_get_lit(ctx, 4);
bool r1 = arg_get_lit(ctx, 5);
bool r2 = arg_get_lit(ctx, 6); bool r0 = arg_get_lit(ctx, 5);
bool r3 = arg_get_lit(ctx, 7); bool r1 = arg_get_lit(ctx, 6);
bool r2 = arg_get_lit(ctx, 7);
bool r3 = arg_get_lit(ctx, 8);
CLIParserFree(ctx); CLIParserFree(ctx);
if ((r0 + r1 + r2 + r3) > 1) { if ((r0 + r1 + r2 + r3) > 1) {
@ -2278,8 +2282,9 @@ static int CmdT55xxDump(const char *Cmd) {
// will save the dump file if ALL page 0 is OK // will save the dump file if ALL page 0 is OK
printT5xxHeader(0); printT5xxHeader(0);
for (uint8_t i = 0; i < 8; ++i) { for (uint8_t i = 0; i < 8; ++i) {
if (T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode) != PM3_SUCCESS) if (T55xxReadBlock(i, 0, usepwd, override, password, downlink_mode) != PM3_SUCCESS) {
success = false; success = false;
}
// only show override warning on the first block read // only show override warning on the first block read
if (override == 1) { if (override == 1) {
@ -2287,12 +2292,14 @@ static int CmdT55xxDump(const char *Cmd) {
} }
} }
printT5xxHeader(1); printT5xxHeader(1);
for (uint8_t i = 0; i < 4; i++) for (uint8_t i = 0; i < 4; i++) {
if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS) if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS) {
T55x7_SaveBlockData(8 + i, 0x00); T55x7_SaveBlockData(8 + i, 0x00);
}
}
// all ok, save dump to file // all ok, save dump to file
if (success) { if (success && nosave == false) {
// set default filename, if not set by user // set default filename, if not set by user
if (strlen(filename) == 0) { if (strlen(filename) == 0) {
@ -4019,7 +4026,11 @@ static int CmdT55xxSniff(const char *Cmd) {
// setup and sample data from Proxmark // setup and sample data from Proxmark
// if not directed to existing sample/graphbuffer // if not directed to existing sample/graphbuffer
if (use_graphbuf == false) { if (use_graphbuf == false) {
// make loop to call sniff with skip samples..
// then build it up by adding
CmdLFSniff(""); CmdLFSniff("");
} }
// Headings // Headings

View file

@ -30,6 +30,8 @@
#include "cmdhftopaz.h" #include "cmdhftopaz.h"
#include "cmdnfc.h" #include "cmdnfc.h"
#include "fileutils.h" #include "fileutils.h"
#include "mifare/mifaredefault.h"
#include "mifare/mad.h"
void print_type4_cc_info(uint8_t *d, uint8_t n) { void print_type4_cc_info(uint8_t *d, uint8_t n) {
if (n < 0x0F) { if (n < 0x0F) {
@ -111,6 +113,22 @@ static int CmdNfcDecode(const char *Cmd) {
return res; return res;
} }
// convert from MFC dump file to a pure NDEF byte array
if (HasMADKey(dump)) {
PrintAndLogEx(SUCCESS, "MFC dump file detected. Converting...");
uint8_t ndef[4096] = {0};
uint16_t ndeflen = 0;
if (convert_mad_to_arr(dump, bytes_read, ndef, &ndeflen) != PM3_SUCCESS) {
PrintAndLogEx(FAILED, "Failed converting, aborting...");
free(dump);
return PM3_ESOFT;
}
memcpy(dump, ndef, ndeflen);
bytes_read = ndeflen;
}
res = NDEFDecodeAndPrint(dump, bytes_read, verbose); res = NDEFDecodeAndPrint(dump, bytes_read, verbose);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header"); PrintAndLogEx(INFO, "Trying to parse NDEF records w/o NDEF header");

View file

@ -85,6 +85,8 @@ DumpFileType_t getfiletype(const char *filename) {
o = JSON; o = JSON;
} else if (str_endswith(s, "dic")) { } else if (str_endswith(s, "dic")) {
o = DICTIONARY; o = DICTIONARY;
} else if (str_endswith(s, "mct")) {
o = MCT;
} else { } else {
// mfd, trc, trace is binary // mfd, trc, trace is binary
o = BIN; o = BIN;
@ -112,27 +114,6 @@ int fileExists(const char *filename) {
return result == 0; return result == 0;
} }
/**
* @brief checks if path is file.
* @param filename
* @return
*/
/*
static bool is_regular_file(const char *filename) {
#ifdef _WIN32
struct _stat st;
if (_stat(filename, &st) == -1)
return false;
#else
struct stat st;
// stat(filename, &st);
if (lstat(filename, &st) == -1)
return false;
#endif
return S_ISREG(st.st_mode) != 0;
}
*/
/** /**
* @brief checks if path is directory. * @brief checks if path is directory.
* @param filename * @param filename
@ -152,68 +133,6 @@ static bool is_directory(const char *filename) {
return S_ISDIR(st.st_mode) != 0; return S_ISDIR(st.st_mode) != 0;
} }
/**
* @brief create a new directory.
* @param dirname
* @return
*/
// Not used...
/*
#ifdef _WIN32
#define make_dir(a) _mkdir(a)
#else
#define make_dir(a) mkdir(a,0755) //note 0755 MUST have leading 0 for octal linux file permissions
#endif
bool create_path(const char *dirname) {
if (dirname == NULL) // nothing to do
return false;
if ((strlen(dirname) == 1) && (dirname[0] == '/'))
return true;
if ((strlen(dirname) == 2) && (dirname[1] == ':'))
return true;
if (fileExists(dirname) == 0) {
char *bs = strrchr(dirname, '\\');
char *fs = strrchr(dirname, '/');
if ((bs == NULL) && (fs != NULL)) {
*fs = 0x00;
create_path (dirname);
*fs = '/';
}
if ((bs != NULL) && (fs == NULL)) {
*bs = 0x00;
create_path (dirname);
*bs = '\\';
}
if ((bs != NULL) && (fs != NULL)) {
if (strlen (bs) > strlen (fs)) {
*fs = 0x00; // No slash
create_path (dirname);
*fs = '/';
} else {
*bs = 0x00;
create_path (dirname);
*bs = '\\';
}
}
if (make_dir(dirname) != 0) {
PrintAndLogEx(ERR, "could not create directory.... "_RED_("%s"),dirname);
return false;
}
}
return true;
}
*/
bool setDefaultPath(savePaths_t pathIndex, const char *path) { bool setDefaultPath(savePaths_t pathIndex, const char *path) {
if (pathIndex < spItemCount) { if (pathIndex < spItemCount) {
@ -262,37 +181,55 @@ static size_t path_size(savePaths_t a) {
} }
char *newfilenamemcopy(const char *preferredName, const char *suffix) { char *newfilenamemcopy(const char *preferredName, const char *suffix) {
return newfilenamemcopyEx(preferredName, suffix, spDefault);
}
char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t e_save_path) {
if (preferredName == NULL || suffix == NULL) { if (preferredName == NULL || suffix == NULL) {
return NULL; return NULL;
} }
uint16_t p_namelen = strlen(preferredName); uint16_t p_namelen = strlen(preferredName);
if (str_endswith(preferredName, suffix)) if (str_endswith(preferredName, suffix)) {
p_namelen -= strlen(suffix); p_namelen -= strlen(suffix);
}
// 10: room for filenum to ensure new filename int save_path_len = path_size(e_save_path);
const size_t len = p_namelen + strlen(suffix) + 1 + 10;
int foobar = path_size(spDefault); // 1: null terminator
(void) foobar; // 16: room for filenum to ensure new filename
// save_path_len + strlen(PATHSEP): the user preference save paths
const size_t len = p_namelen + strlen(suffix) + 1 + 16 + save_path_len + strlen(PATHSEP);
char *fileName = (char *) calloc(len, sizeof(uint8_t)); char *fileName = (char *) calloc(len, sizeof(uint8_t));
if (fileName == NULL) { if (fileName == NULL) {
return NULL; return NULL;
} }
char *pfn = fileName;
// user preference save paths
if (save_path_len) {
snprintf(pfn, save_path_len + strlen(PATHSEP) + 1, "%s%s", g_session.defaultPaths[e_save_path], PATHSEP);
pfn += save_path_len + strlen(PATHSEP);
}
int num = 1; int num = 1;
snprintf(fileName, len, "%.*s%s", p_namelen, preferredName, suffix); // modify filename
snprintf(pfn, len, "%.*s%s", p_namelen, preferredName, suffix);
// check complete path/filename if exists
while (fileExists(fileName)) { while (fileExists(fileName)) {
snprintf(fileName, len, "%.*s-%d%s", p_namelen, preferredName, num, suffix); // modify filename
snprintf(pfn, len, "%.*s-%03d%s", p_namelen, preferredName, num, suffix);
num++; num++;
} }
PrintAndLogEx(INFO, "FILE PATH: %s", fileName);
return fileName; return fileName;
} }
// --------- SAVE FILES
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) { int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
@ -321,13 +258,14 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// dump file
int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) { int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".eml"); char *fileName = newfilenamemcopyEx(preferredName, ".eml", spDump);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -371,16 +309,19 @@ out:
return retval; return retval;
} }
// dump file (normally, we also got preference file, etc)
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)) { int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)) {
return saveFileJSONex(preferredName, ftype, data, datalen, true, callback); return saveFileJSONex(preferredName, ftype, data, datalen, true, callback, spDump);
} }
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) { int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path) {
if (ftype != jsfCustom) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
}
char *fileName = newfilenamemcopy(preferredName, ".json"); char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -719,7 +660,7 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
if (overwrite) if (overwrite)
filename = filenamemcopy(preferredName, ".json"); filename = filenamemcopy(preferredName, ".json");
else else
filename = newfilenamemcopy(preferredName, ".json"); filename = newfilenamemcopyEx(preferredName, ".json", spDump);
if (filename == NULL) if (filename == NULL)
return PM3_EMALLOC; return PM3_EMALLOC;
@ -739,13 +680,14 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
return PM3_EFILE; return PM3_EFILE;
} }
// wave file of trace,
int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) { int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".wav"); char *fileName = newfilenamemcopyEx(preferredName, ".wav", spTrace);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -791,13 +733,14 @@ out:
return retval; return retval;
} }
// Signal trace file, PM3
int saveFilePM3(const char *preferredName, int *data, size_t datalen) { int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
if (data == NULL || datalen == 0) { if (data == NULL || datalen == 0) {
return PM3_EINVARG; return PM3_EINVARG;
} }
char *fileName = newfilenamemcopy(preferredName, ".pm3"); char *fileName = newfilenamemcopyEx(preferredName, ".pm3", spTrace);
if (fileName == NULL) { if (fileName == NULL) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -824,11 +767,12 @@ out:
return retval; return retval;
} }
// key file dump
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) { int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) {
if (e_sector == NULL) return PM3_EINVARG; if (e_sector == NULL) return PM3_EINVARG;
char *fileName = newfilenamemcopy(preferredName, ".bin"); char *fileName = newfilenamemcopyEx(preferredName, ".bin", spDump);
if (fileName == NULL) return PM3_EMALLOC; if (fileName == NULL) return PM3_EMALLOC;
FILE *f = fopen(fileName, "wb"); FILE *f = fopen(fileName, "wb");
@ -866,66 +810,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) { // --------- LOAD FILES
if (data == NULL) return 1;
char *fileName = filenamemcopy(preferredName, suffix);
if (fileName == NULL) return PM3_EINVARG;
int retval = PM3_SUCCESS;
FILE *f = fopen(fileName, "rb");
if (!f) {
PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
free(fileName);
return PM3_EFILE;
}
// get filesize in order to malloc memory
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize <= 0) {
PrintAndLogEx(FAILED, "error, when getting filesize");
retval = PM3_EFILE;
goto out;
}
uint8_t *dump = calloc(fsize, sizeof(uint8_t));
if (!dump) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
retval = PM3_EMALLOC;
goto out;
}
size_t bytes_read = fread(dump, 1, fsize, f);
if (bytes_read != fsize) {
PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
free(dump);
retval = PM3_EFILE;
goto out;
}
if (bytes_read > maxdatalen) {
PrintAndLogEx(WARNING, "Warning, bytes read exceed calling array limit. Max bytes is %zu bytes", maxdatalen);
bytes_read = maxdatalen;
}
memcpy((data), dump, bytes_read);
free(dump);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
*datalen = bytes_read;
out:
fclose(f);
free(fileName);
return retval;
}
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) { int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
return loadFile_safeEx(preferredName, suffix, pdata, datalen, true); return loadFile_safeEx(preferredName, suffix, pdata, datalen, true);
} }
@ -975,72 +860,12 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
*datalen = bytes_read; *datalen = bytes_read;
if (verbose) if (verbose) {
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName); PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
if (data == NULL) return PM3_EINVARG;
char *fileName = filenamemcopy(preferredName, ".eml");
if (fileName == NULL) return PM3_EMALLOC;
size_t counter = 0;
int retval = PM3_SUCCESS, hexlen = 0;
FILE *f = fopen(fileName, "r");
if (!f) {
PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
retval = PM3_EFILE;
goto out;
}
// 128 + 2 newline chars + 1 null terminator
char line[131];
memset(line, 0, sizeof(line));
uint8_t buf[64] = {0x00};
uint8_t *udata = (uint8_t *)data;
while (!feof(f)) {
memset(line, 0, sizeof(line));
if (fgets(line, sizeof(line), f) == NULL) {
if (feof(f))
break;
fclose(f);
PrintAndLogEx(FAILED, "File reading error.");
retval = PM3_EFILE;
goto out;
}
if (line[0] == '#')
continue;
strcleanrn(line, sizeof(line));
int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
if (res == 0) {
memcpy(udata + counter, buf, hexlen);
counter += hexlen;
} else {
retval = PM3_ESOFT;
}
}
fclose(f);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from text file " _YELLOW_("%s"), counter, fileName);
if (datalen)
*datalen = counter;
out:
free(fileName);
return retval;
}
int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
char *path; char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
@ -1127,6 +952,93 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
return retval; return retval;
} }
int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) {
char *path;
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
if (res != PM3_SUCCESS) {
return PM3_EFILE;
}
FILE *f = fopen(path, "r");
if (!f) {
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
free(path);
return PM3_EFILE;
}
free(path);
// get filesize in order to malloc memory
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize <= 0) {
PrintAndLogEx(FAILED, "error, when getting filesize");
fclose(f);
return PM3_EFILE;
}
*pdata = calloc(fsize, sizeof(uint8_t));
if (!*pdata) {
PrintAndLogEx(FAILED, "error, cannot allocate memory");
fclose(f);
return PM3_EMALLOC;
}
// 128 + 2 newline chars + 1 null terminator
char line[131];
memset(line, 0, sizeof(line));
uint8_t buf[64] = {0x00};
size_t counter = 0;
int retval = PM3_SUCCESS, hexlen = 0;
uint8_t *tmp = (uint8_t *)*pdata;
while (!feof(f)) {
memset(line, 0, sizeof(line));
if (fgets(line, sizeof(line), f) == NULL) {
if (feof(f))
break;
fclose(f);
PrintAndLogEx(FAILED, "File reading error.");
return PM3_EFILE;
}
// skip lines like "+Sector:"
if (line[0] == '+')
continue;
strcleanrn(line, sizeof(line));
res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
if (res == 0) {
memcpy(tmp + counter, buf, hexlen);
counter += hexlen;
} else {
retval = PM3_ESOFT;
}
}
fclose(f);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from MCT file " _YELLOW_("%s"), counter, preferredName);
uint8_t *newdump = realloc(*pdata, counter);
if (newdump == NULL) {
free(*pdata);
return PM3_EMALLOC;
} else {
*pdata = newdump;
}
if (datalen)
*datalen = counter;
return retval;
}
int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, void (*callback)(json_t *)) { int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, void (*callback)(json_t *)) {
return loadFileJSONex(preferredName, data, maxdatalen, datalen, true, callback); return loadFileJSONex(preferredName, data, maxdatalen, datalen, true, callback);
} }
@ -1903,51 +1815,84 @@ int searchAndList(const char *pm3dir, const char *ext) {
} }
static int searchFinalFile(char **foundpath, const char *pm3dir, const char *searchname, bool silent) { static int searchFinalFile(char **foundpath, const char *pm3dir, const char *searchname, bool silent) {
if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) return PM3_ESOFT;
if ((foundpath == NULL) || (pm3dir == NULL) || (searchname == NULL)) {
return PM3_ESOFT;
}
// explicit absolute (/) or relative path (./) => try only to match it directly // explicit absolute (/) or relative path (./) => try only to match it directly
char *filename = calloc(strlen(searchname) + 1, sizeof(char)); char *filename = calloc(strlen(searchname) + 1, sizeof(char));
if (filename == NULL) return PM3_EMALLOC; if (filename == NULL) {
return PM3_EMALLOC;
}
strcpy(filename, searchname); strcpy(filename, searchname);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", filename); PrintAndLogEx(INFO, "pm3dir...... %s", pm3dir);
PrintAndLogEx(INFO, "Searching... %s", filename);
} }
// try implicit relative path
PrintAndLogEx(DEBUG, "Searching implicit relative paths");
if (fileExists(filename)) {
*foundpath = filename;
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Found %s", *foundpath);
}
return PM3_SUCCESS;
}
if (((strlen(filename) > 1) && (filename[0] == '/')) || if (((strlen(filename) > 1) && (filename[0] == '/')) ||
((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) { ((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
if (fileExists(filename)) { goto out;
*foundpath = filename; }
// try the session paths
PrintAndLogEx(DEBUG, "Searching preferences paths");
for (int i = 0; i < spItemCount; i++) {
size_t sn = strlen(g_session.defaultPaths[i]) + strlen(filename) + strlen(PATHSEP) + 1;
char *default_path = calloc(sn, sizeof(char));
if (default_path == NULL) {
goto out;
}
snprintf(default_path, sn, "%s%s%s", g_session.defaultPaths[i], PATHSEP, filename);
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", default_path);
}
if (fileExists(default_path)) {
free(filename);
*foundpath = default_path;
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Found %s", *foundpath); PrintAndLogEx(INFO, "Found %s", *foundpath);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} else { } else {
goto out; free(default_path);
} }
} }
// else
// try implicit relative path
{
if (fileExists(filename)) {
*foundpath = filename;
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Found %s", *foundpath);
}
return PM3_SUCCESS;
}
}
// try pm3 dirs in user .proxmark3 (user mode) // try pm3 dirs in user .proxmark3 (user mode)
PrintAndLogEx(DEBUG, "Searching user .proxmark3 paths");
const char *user_path = get_my_user_directory(); const char *user_path = get_my_user_directory();
if (user_path != NULL) { if (user_path != NULL) {
char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
if (path == NULL) if (path == NULL) {
goto out; goto out;
}
strcpy(path, user_path); strcpy(path, user_path);
strcat(path, PM3_USER_DIRECTORY); strcat(path, PM3_USER_DIRECTORY);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -1959,7 +1904,9 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in current client workdir (dev mode) // try pm3 dirs in current client workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching current workdir paths");
const char *exec_path = get_my_executable_directory(); const char *exec_path = get_my_executable_directory();
if ((exec_path != NULL) && if ((exec_path != NULL) &&
((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) || ((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) ||
@ -1992,23 +1939,28 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in current repo workdir (dev mode) // try pm3 dirs in current repo workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching PM3 dirs in current workdir");
if ((exec_path != NULL) && if ((exec_path != NULL) &&
((strcmp(TRACES_SUBDIR, pm3dir) == 0) || ((strcmp(TRACES_SUBDIR, pm3dir) == 0) ||
(strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) || (strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) ||
(strcmp(BOOTROM_SUBDIR, pm3dir) == 0) || (strcmp(BOOTROM_SUBDIR, pm3dir) == 0) ||
(strcmp(FULLIMAGE_SUBDIR, pm3dir) == 0))) { (strcmp(FULLIMAGE_SUBDIR, pm3dir) == 0))) {
const char *above = "../"; char *path = calloc(strlen(exec_path) + strlen(ABOVE) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
char *path = calloc(strlen(exec_path) + strlen(above) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); if (path == NULL) {
if (path == NULL)
goto out; goto out;
}
strcpy(path, exec_path); strcpy(path, exec_path);
strcat(path, above); strcat(path, ABOVE);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -2020,18 +1972,24 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path); free(path);
} }
} }
// try pm3 dirs in pm3 installation dir (install mode) // try pm3 dirs in pm3 installation dir (install mode)
PrintAndLogEx(DEBUG, "Searching PM3 installation dir paths");
if (exec_path != NULL) { if (exec_path != NULL) {
char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char)); char *path = calloc(strlen(exec_path) + strlen(PM3_SHARE_RELPATH) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
if (path == NULL) if (path == NULL) {
goto out; goto out;
}
strcpy(path, exec_path); strcpy(path, exec_path);
strcat(path, PM3_SHARE_RELPATH); strcat(path, PM3_SHARE_RELPATH);
strcat(path, pm3dir); strcat(path, pm3dir);
strcat(path, filename); strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) { if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path); PrintAndLogEx(INFO, "Searching %s", path);
} }
if (fileExists(path)) { if (fileExists(path)) {
free(filename); free(filename);
*foundpath = path; *foundpath = path;
@ -2067,15 +2025,15 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
free(filename); free(filename);
return PM3_EFILE; return PM3_EFILE;
} }
int res = searchFinalFile(foundpath, pm3dir, filename, silent); int res = searchFinalFile(foundpath, pm3dir, filename, silent);
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {
if ((res == PM3_EFILE) && (!silent)) if ((res == PM3_EFILE) && (!silent)) {
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename); PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
}
}
free(filename); free(filename);
return res; return res;
}
free(filename);
return PM3_SUCCESS;
} }
int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) { int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) {
@ -2107,6 +2065,10 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed"); PrintAndLogEx(ERR, "Error: Only BIN/EML/JSON formats allowed");
return PM3_EINVARG; return PM3_EINVARG;
} }
case MCT: {
res = loadFileMCT_safe(fn, pdump, dumplen);
break;
}
} }
if (res != PM3_SUCCESS) { if (res != PM3_SUCCESS) {

View file

@ -56,15 +56,16 @@ typedef enum {
EML, EML,
JSON, JSON,
DICTIONARY, DICTIONARY,
MCT,
} DumpFileType_t; } DumpFileType_t;
int fileExists(const char *filename); int fileExists(const char *filename);
//bool create_path(const char *dirname);
// set a path in the path list g_session.defaultPaths // set a path in the path list g_session.defaultPaths
bool setDefaultPath(savePaths_t pathIndex, const char *path); bool setDefaultPath(savePaths_t pathIndex, const char *path);
char *newfilenamemcopy(const char *preferredName, const char *suffix); char *newfilenamemcopy(const char *preferredName, const char *suffix);
char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t save_path);
/** /**
* @brief Utility function to save data to a binary file. This method takes a preferred name, but if that * @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
@ -104,7 +105,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
* @return 0 for ok, 1 for failz * @return 0 for ok, 1 for failz
*/ */
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *)); int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *));
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)); int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path);
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose); int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose);
int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite); int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite);
/** STUB /** STUB
@ -141,20 +142,6 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen);
*/ */
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector); int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector);
/**
* @brief Utility function to load data from a binary file. This method takes a preferred name.
* E.g. dumpdata-15.bin
*
* @param preferredName
* @param suffix the file suffix. Including the ".".
* @param data The data array to store the loaded bytes from file
* @param maxdatalen the number of bytes that your data array has
* @param datalen the number of bytes loaded from file
* @return PM3_SUCCESS for ok, PM3_E* for failz
*/
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen);
/** /**
* @brief Utility function to load data from a binary file. This method takes a preferred name. * @brief Utility function to load data from a binary file. This method takes a preferred name.
* E.g. dumpdata-15.bin, tries to search for it, and allocated memory. * E.g. dumpdata-15.bin, tries to search for it, and allocated memory.
@ -176,9 +163,19 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
* @param datalen the number of bytes loaded from file * @param datalen the number of bytes loaded from file
* @return 0 for ok, 1 for failz * @return 0 for ok, 1 for failz
*/ */
int loadFileEML(const char *preferredName, void *data, size_t *datalen);
int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen); int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen);
/**
* @brief Utility function to load data from a textfile (MCT). This method takes a preferred name.
* E.g. dumpdata-15.mct
*
* @param preferredName
* @param data The data array to store the loaded bytes from file
* @param datalen the number of bytes loaded from file
* @return 0 for ok, 1 for failz
*/
int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen);
/** /**
* @brief Utility function to load data from a JSON textfile. This method takes a preferred name. * @brief Utility function to load data from a JSON textfile. This method takes a preferred name.
* E.g. dumpdata-15.json * E.g. dumpdata-15.json

View file

@ -236,11 +236,14 @@ static int check_segs(flash_file_t *ctx, int can_write_bl, uint32_t flash_size)
} }
static int print_and_validate_version(struct version_information_t *vi) { static int print_and_validate_version(struct version_information_t *vi) {
if (vi->magic != VERSION_INFORMATION_MAGIC) if (vi->magic != VERSION_INFORMATION_MAGIC) {
return PM3_EFILE; return PM3_EFILE;
}
char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image
FormatVersionInformation(temp, sizeof(temp), "", vi); FormatVersionInformation(temp, sizeof(temp), "", vi);
PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp); PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp);
if (strlen(g_version_information.armsrc) == 9) { if (strlen(g_version_information.armsrc) == 9) {
if (strncmp(vi->armsrc, g_version_information.armsrc, 9) != 0) { if (strncmp(vi->armsrc, g_version_information.armsrc, 9) != 0) {
PrintAndLogEx(WARNING, _RED_("ARM firmware does not match the source at the time the client was compiled")); PrintAndLogEx(WARNING, _RED_("ARM firmware does not match the source at the time the client was compiled"));

View file

@ -421,3 +421,51 @@ int DetectHID(uint8_t *d, uint16_t manufacture) {
return -1; return -1;
} }
int convert_mad_to_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen) {
if (in == NULL || out == NULL || ilen == 0 ) {
return PM3_EINVARG;
}
// MAD detection
if (HasMADKey(in) == false) {
PrintAndLogEx(FAILED, "No MAD key was detected in the dump file");
return PM3_ESOFT;
}
uint8_t sector0[MFBLOCK_SIZE * 4] = {0};
uint8_t sector10[MFBLOCK_SIZE * 4] = {0};
memcpy(sector0, in, sizeof(sector0));
if (ilen == MIFARE_4K_MAX_BYTES) {
memcpy(sector10, in + (MF_MAD2_SECTOR * 4 * MFBLOCK_SIZE), sizeof(sector10));
}
uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
size_t madlen = 0;
if (MADDecode(sector0, sector10, mad, &madlen, false)) {
PrintAndLogEx(ERR, "can't decode MAD");
return PM3_ESOFT;
}
uint16_t ndef_aid = 0xE103;
for (int i = 0; i < madlen; i++) {
if (ndef_aid == mad[i]) {
uint8_t tmp[MFBLOCK_SIZE * 4] = {0};
memset(tmp, 0x00, sizeof(tmp));
// sector i dump (skip first sector +1)
memcpy(tmp, in + (i + 1) * sizeof(tmp), sizeof(tmp));
// debug print
// print_hex_noascii_break(tmp, sizeof(tmp) - MFBLOCK_SIZE, MFBLOCK_SIZE);
// copy to out (skip ST)
memcpy(out, tmp, sizeof(tmp) - MFBLOCK_SIZE);
out += sizeof(tmp) - MFBLOCK_SIZE;
*olen += sizeof(tmp) -MFBLOCK_SIZE;
}
}
return PM3_SUCCESS;
}

View file

@ -30,4 +30,5 @@ int MADCardHolderInfoDecode(uint8_t *data, size_t datalen, bool verbose);
void MADPrintHeader(void); void MADPrintHeader(void);
bool HasMADKey(uint8_t *d); bool HasMADKey(uint8_t *d);
int DetectHID(uint8_t *d, uint16_t manufacture); int DetectHID(uint8_t *d, uint16_t manufacture);
int convert_mad_to_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen);
#endif // _MAD_H_ #endif // _MAD_H_

View file

@ -21,15 +21,58 @@
#include "common.h" #include "common.h"
#define MFKEY_SIZE 6 #define MFKEY_SIZE 6
#define MFBLOCK_SIZE 16 #define MFBLOCK_SIZE 16
#define MIFARE_4K_MAXBLOCK 256
#define MIFARE_2K_MAXBLOCK 128
#define MIFARE_1K_MAXBLOCK 64
#define MIFARE_MINI_MAXBLOCK 20
#define MIFARE_4K_MAXSECTOR 40
#define MIFARE_2K_MAXSECTOR 32
#define MIFARE_1K_MAXSECTOR 16
#define MIFARE_MINI_MAXSECTOR 5
#define MIFARE_4K_MAX_BYTES 4096
#define MIFARE_2K_MAX_BYTES 2048
#define MIFARE_1K_MAX_BYTES 1024
#define MIFARE_MINI_MAX_BYTES 320
#define MIFARE_KEY_SIZE 6
static const uint64_t g_mifare_default_keys[] = { static const uint64_t g_mifare_default_keys[] = {
0xffffffffffff, // Default key (first key used by program if no user defined key) 0xffffffffffff, // Default key (first key used by program if no user defined key)
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key 0xa0a1a2a3a4a5, // NFCForum MAD key
0xd3f7d3f7d3f7, // NDEF public key 0xd3f7d3f7d3f7, // NDEF public key
0x4b791bea7bcc, // MFC EV1 Signature B 0x4b791bea7bcc, // MFC EV1 Signature B
0xfc00018778f7, // Public Transport
0x6471a5ef2d1a, // SimonsVoss
0x4E3552426B32, // ID06
0x6A1987C40A21, // Salto
0xef1232ab18a0, // Schlage
0x3B7E4FD575AD, //
0xb7bf0c13066e, // Gallagher
0x135b88a94b8b, // Saflok
0x2A2C13CC242A, // Dorma Kaba
0x5a7a52d5e20d, // Bosch
0x314B49474956, // VIGIK1 A
0x564c505f4d41, // VIGIK1 B
0x021209197591, // BTCINO
0x484558414354, // Intratone
0xEC0A9B1A9E06, // Vingcard
0x66b31e64ca4b, // Vingcard
0x97F5DA640B18, // Bangkok metro key
0xA8844B0BCA06, // Metro Valencia key
0xE4410EF8ED2D, // Armenian metro
0x857464D3AAD1, // HTC Eindhoven key
0x08B386463229, // troika
0xe00000000000, // icopy
0x199404281970, // NSP A
0x199404281998, // NSP B
0x6A1987C40A21, // SALTO
0x7F33625BC129, // SALTO
0x000000000000, // Blank key
0xb0b1b2b3b4b5, 0xb0b1b2b3b4b5,
0xaabbccddeeff, 0xaabbccddeeff,
0x1a2b3c4d5e6f, 0x1a2b3c4d5e6f,
@ -47,29 +90,6 @@ static const uint64_t g_mifare_default_keys[] = {
0x0000014b5c31, 0x0000014b5c31,
0xb578f38a5c61, 0xb578f38a5c61,
0x96a301bce267, 0x96a301bce267,
0xfc00018778f7, // Public Transport
0x6471a5ef2d1a, // SimonsVoss
0x4E3552426B32, // ID06
0x6A1987C40A21, // Salto
0xef1232ab18a0, // Schlage
0x3B7E4FD575AD, //
0xb7bf0c13066e, // Gallagher
0x135b88a94b8b, // Saflock
0x5a7a52d5e20d, // Bosch
0x314B49474956, // VIGIK1 A
0x564c505f4d41, // VIGIK1 B
0x021209197591, // BTCINO
0x484558414354, // Intratone
0xEC0A9B1A9E06, // Vingcard
0x66b31e64ca4b, // Vingcard
0x97F5DA640B18, // Bangkok metro key
0xA8844B0BCA06, // Metro Valencia key
0xE4410EF8ED2D, // Armenian metro
0x857464D3AAD1, // HTC Eindhoven key
0x08B386463229, // troika
0xe00000000000, // icopy
0x199404281970, // NSP A
0x199404281998, // NSP B
}; };
static const uint8_t g_mifare_default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const uint8_t g_mifare_default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

View file

@ -1042,7 +1042,8 @@ int mfCWipe(uint8_t *uid, const uint8_t *atqa, const uint8_t *sak) {
uint8_t block0[16] = {0x00, 0x56, 0x78, 0xBB, 0x95, 0x08, 0x04, 0x00, 0x02, 0xB2, 0x1E, 0x24, 0x23, 0x27, 0x1E, 0x1D}; uint8_t block0[16] = {0x00, 0x56, 0x78, 0xBB, 0x95, 0x08, 0x04, 0x00, 0x02, 0xB2, 0x1E, 0x24, 0x23, 0x27, 0x1E, 0x1D};
// uint8_t block0[16] = {0x04, 0x03, 0x02, 0x01, 0x04, 0x08, 0x04, 0x00, 0x64, 0xB9, 0x95, 0x11, 0x4D, 0x20, 0x42, 0x09}; // uint8_t block0[16] = {0x04, 0x03, 0x02, 0x01, 0x04, 0x08, 0x04, 0x00, 0x64, 0xB9, 0x95, 0x11, 0x4D, 0x20, 0x42, 0x09};
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}; // default transport ACL
uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t params = MAGIC_SINGLE; uint8_t params = MAGIC_SINGLE;
if (uid != NULL) { if (uid != NULL) {
@ -1466,12 +1467,12 @@ int convert_mfc_2_arr(uint8_t *in, uint16_t ilen, uint8_t *out, uint16_t *olen)
if (mfIsSectorTrailer(blockno) == false) { if (mfIsSectorTrailer(blockno) == false) {
memcpy(out, in, MFBLOCK_SIZE); memcpy(out, in, MFBLOCK_SIZE);
out += MFBLOCK_SIZE;
*olen += MFBLOCK_SIZE;
} }
blockno++; blockno++;
out += MFBLOCK_SIZE;
in += MFBLOCK_SIZE; in += MFBLOCK_SIZE;
ilen -= MFBLOCK_SIZE; ilen -= MFBLOCK_SIZE;
*olen += MFBLOCK_SIZE;
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -39,8 +39,6 @@
#define NDEF_VCARDTEXT "text/vcard" #define NDEF_VCARDTEXT "text/vcard"
#define NDEF_XVCARDTEXT "text/x-vcard" #define NDEF_XVCARDTEXT "text/x-vcard"
static const char *TypeNameFormat_s[] = { static const char *TypeNameFormat_s[] = {
"Empty Record", "Empty Record",
"Well Known Record", "Well Known Record",
@ -289,22 +287,35 @@ static int ndef_print_signature(uint8_t *data, uint8_t data_len, uint8_t *signat
} }
static int ndefDecodeSig1(uint8_t *sig, size_t siglen) { static int ndefDecodeSig1(uint8_t *sig, size_t siglen) {
size_t indx = 1;
size_t indx = 1;
uint8_t sigType = sig[indx] & 0x7f; uint8_t sigType = sig[indx] & 0x7f;
bool sigURI = sig[indx] & 0x80; bool sigURI = sig[indx] & 0x80;
indx++;
PrintAndLogEx(SUCCESS, "\tsignature type: %s", ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA])); PrintAndLogEx(SUCCESS, "\tType...... " _YELLOW_("%s"), ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA]));
PrintAndLogEx(SUCCESS, "\tsignature uri: %s", (sigURI ? "present" : "not present")); PrintAndLogEx(SUCCESS, "\tURI....... " _YELLOW_("%s"), (sigURI ? "present" : "not present"));
if (sigType == 0 && sigURI == false) {
PrintAndLogEx(INFO, "\tRecord should be considered a start marker");
}
if (sigType == 0 && sigURI) {
PrintAndLogEx(INFO, _RED_("\tSignature record is invalid"));
}
uint16_t intsiglen = MemBeToUint2byte(sig + indx);
indx += 2;
size_t intsiglen = (sig[indx + 1] << 8) + sig[indx + 2];
// ecdsa 0x04 // ecdsa 0x04
if (sigType == stECDSA_P192 || sigType == stECDSA_P256) { if (sigType == stECDSA_P192 || sigType == stECDSA_P256) {
indx += 3;
int slen = 24; int slen = 24;
if (sigType == stECDSA_P256) if (sigType == stECDSA_P256) {
slen = 32; slen = 32;
PrintAndLogEx(SUCCESS, "\tsignature [%zu]: %s", intsiglen, sprint_hex_inrow(&sig[indx], intsiglen)); }
PrintAndLogEx(SUCCESS, "\tSignature [%u]...", intsiglen);
print_hex_noascii_break(&sig[indx], intsiglen, 32);
uint8_t rval[300] = {0}; uint8_t rval[300] = {0};
uint8_t sval[300] = {0}; uint8_t sval[300] = {0};
@ -313,38 +324,53 @@ static int ndefDecodeSig1(uint8_t *sig, size_t siglen) {
PrintAndLogEx(SUCCESS, "\t\tr: %s", sprint_hex(rval + 32 - slen, slen)); PrintAndLogEx(SUCCESS, "\t\tr: %s", sprint_hex(rval + 32 - slen, slen));
PrintAndLogEx(SUCCESS, "\t\ts: %s", sprint_hex(sval + 32 - slen, slen)); PrintAndLogEx(SUCCESS, "\t\ts: %s", sprint_hex(sval + 32 - slen, slen));
} }
} else {
PrintAndLogEx(SUCCESS, "\tData [%u]...", intsiglen);
print_hex_noascii_break(&sig[indx], intsiglen, 32);
} }
indx += intsiglen; indx += intsiglen;
if (sigURI) { if (sigURI) {
size_t intsigurilen = (sig[indx] << 8) + sig[indx + 1];
uint16_t intsigurilen = MemBeToUint2byte(sig + indx);
indx += 2; indx += 2;
PrintAndLogEx(SUCCESS, "\tsignature uri [%zu]: %.*s", intsigurilen, (int)intsigurilen, &sig[indx]);
PrintAndLogEx(SUCCESS, "\tSignature URI... " _YELLOW_("%.*s"), (int)intsigurilen, &sig[indx]);
indx += intsigurilen; indx += intsigurilen;
} }
// CERTIFICATE SECTION
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, _CYAN_("Certificate"));
uint8_t certFormat = (sig[indx] >> 4) & 0x07; uint8_t certFormat = (sig[indx] >> 4) & 0x07;
uint8_t certCount = sig[indx] & 0x0f; uint8_t certCount = sig[indx] & 0x0f;
bool certURI = sig[indx] & 0x80; bool certURI = sig[indx] & 0x80;
indx++;
PrintAndLogEx(SUCCESS, "\tcertificate format: %s", ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA])); PrintAndLogEx(SUCCESS, "\tFormat............ " _YELLOW_("%s"), ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA]));
PrintAndLogEx(SUCCESS, "\tcertificates count: %d", certCount); if (certCount) {
PrintAndLogEx(SUCCESS, "\tNum of certs#..... " _YELLOW_("%d"), certCount);
}
// print certificates // print certificates
indx++; for (uint8_t i = 0; i < certCount; i++) {
for (int i = 0; i < certCount; i++) { uint16_t intcertlen = MemBeToUint2byte(sig + indx);
size_t intcertlen = (sig[indx + 1] << 8) + sig[indx + 2];
indx += 2; indx += 2;
PrintAndLogEx(SUCCESS, "\tcertificate %d [%zu]: %s", i + 1, intcertlen, sprint_hex_inrow(&sig[indx], intcertlen)); PrintAndLogEx(INFO, "");
PrintAndLogEx(SUCCESS, "\tCertificate %u [%u]...", i + 1, intcertlen);
print_hex_noascii_break(&sig[indx], intcertlen, 32);
indx += intcertlen; indx += intcertlen;
} }
// have certificate uri // print certificate uri
if ((indx <= siglen) && certURI) { if ((indx <= siglen) && certURI) {
size_t inturilen = (sig[indx] << 8) + sig[indx + 1]; uint16_t inturilen = MemBeToUint2byte(sig + indx);
indx += 2; indx += 2;
PrintAndLogEx(SUCCESS, "\tcertificate uri [%zu]: %.*s", inturilen, (int)inturilen, &sig[indx]); PrintAndLogEx(SUCCESS, "\tCertificate URI... " _YELLOW_("%.*s"), (int)inturilen, &sig[indx]);
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -417,9 +443,9 @@ static int ndefDecodeSig2(uint8_t *sig, size_t siglen) {
} }
static int ndefDecodeSig(uint8_t *sig, size_t siglen) { static int ndefDecodeSig(uint8_t *sig, size_t siglen) {
PrintAndLogEx(SUCCESS, "\tsignature version : \t" _GREEN_("0x%02x"), sig[0]); PrintAndLogEx(SUCCESS, "\tVersion... " _GREEN_("0x%02x"), sig[0]);
if (sig[0] != 0x01 && sig[0] != 0x20) { if (sig[0] != 0x01 && sig[0] != 0x20) {
PrintAndLogEx(ERR, "signature version unknown."); PrintAndLogEx(ERR, _RED_("Version unknown"));
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -473,6 +499,51 @@ static int ndefDecodePayloadDeviceInfo(uint8_t *payload, size_t len) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int ndefDecodePayloadHandoverRequest(uint8_t *payload, size_t len) {
if (payload == NULL)
return PM3_EINVARG;
if (len < 1)
return PM3_EINVARG;
PrintAndLogEx(INFO, _CYAN_("Handover Request"));
uint8_t *p = payload;
uint8_t major = (*(p) >> 4) & 0x0F;
uint8_t minor = *(p) & 0x0F;
p++;
PrintAndLogEx(INFO, "Version....... " _YELLOW_("%u.%u"), major, minor);
if (major != 1 && minor != 2) {
PrintAndLogEx(FAILED, "Wrong version numbers");
}
uint16_t collision = MemBeToUint2byte(p);
p += 2;
PrintAndLogEx(INFO, "Collision Resolution... " _YELLOW_("%u"), collision);
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int ndefDecodePayloadHandoverSelect(uint8_t *payload, size_t len) {
if (payload == NULL)
return PM3_EINVARG;
if (len < 1)
return PM3_EINVARG;
PrintAndLogEx(INFO, _CYAN_("Handover select"));
uint8_t *p = payload;
uint8_t major = (*(p) >> 4) & 0x0F;
uint8_t minor = *(p) & 0x0F;
p++;
PrintAndLogEx(INFO, "Version....... " _YELLOW_("%u.%u"), major, minor);
if (major != 1 && minor != 2) {
PrintAndLogEx(FAILED, "Wrong version numbers");
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int ndefDecodePayloadSmartPoster(uint8_t *ndef, size_t ndeflen, bool print, bool verbose) { static int ndefDecodePayloadSmartPoster(uint8_t *ndef, size_t ndeflen, bool print, bool verbose) {
if (print) { if (print) {
PrintAndLogEx(INFO, _YELLOW_("Well Known Record - Smartposter {")); PrintAndLogEx(INFO, _YELLOW_("Well Known Record - Smartposter {"));
@ -789,9 +860,13 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
PrintAndLogEx(INFO, "Type............ " _YELLOW_("%.*s"), (int)ndef->TypeLen, ndef->Type); PrintAndLogEx(INFO, "Type............ " _YELLOW_("%.*s"), (int)ndef->TypeLen, ndef->Type);
uint16_t ooblen = (ndef->Payload[1] << 8 | ndef->Payload[0]); uint16_t ooblen = MemBeToUint2byte(ndef->Payload);
PrintAndLogEx(INFO, "OOB data len.... %u", ooblen); PrintAndLogEx(INFO, "OOB data len.... %u", ooblen);
PrintAndLogEx(INFO, "BT MAC.......... " _YELLOW_("%s"), sprint_hex(ndef->Payload + 2, 6));
uint8_t rev[6] = {0};
reverse_array_copy(ndef->Payload + 2, 6, rev);
PrintAndLogEx(INFO, "BT MAC.......... " _YELLOW_("%s"), sprint_hex(rev, sizeof(rev)));
// Let's check payload[8]. Tells us a bit about the UUID's. If 0x07 then it tells us a service UUID is 128bit // Let's check payload[8]. Tells us a bit about the UUID's. If 0x07 then it tells us a service UUID is 128bit
switch (ndef->Payload[8]) { switch (ndef->Payload[8]) {
case 0x02: case 0x02:
@ -828,6 +903,38 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// https://raw.githubusercontent.com/haldean/ndef/master/docs/NFCForum-TS-RTD_1.0.pdf
static int ndefDecodeExternal_record(NDEFHeader_t *ndef) {
if (ndef->TypeLen == 0) {
PrintAndLogEx(INFO, "no type");
return PM3_SUCCESS;
}
if (ndef->PayloadLen == 0) {
PrintAndLogEx(INFO, "no payload");
return PM3_SUCCESS;
}
PrintAndLogEx(INFO
, " URN... " _GREEN_("urn:nfc:ext:%.*s")
, (int)ndef->TypeLen
, ndef->Type
);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "Payload [%zu]...", ndef->PayloadLen);
print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32);
// do a character check?
if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:2", ndef->TypeLen)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode...");
asn1_print(ndef->Payload, ndef->PayloadLen, " ");
}
return PM3_SUCCESS;
}
static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) { static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
@ -835,7 +942,7 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
case tnfEmptyRecord: case tnfEmptyRecord:
PrintAndLogEx(INFO, "Empty Record"); PrintAndLogEx(INFO, "Empty Record");
if (ndef->TypeLen != 0 || ndef->IDLen != 0 || ndef->PayloadLen != 0) { if (ndef->TypeLen != 0 || ndef->IDLen != 0 || ndef->PayloadLen != 0) {
PrintAndLogEx(FAILED, "unexpected data in TNF_EMPTY record"); PrintAndLogEx(FAILED, "unexpected data in empty record");
break; break;
} }
break; break;
@ -884,13 +991,11 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
} }
if (!strncmp((char *)ndef->Type, "Hr", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "Hr", ndef->TypeLen)) {
PrintAndLogEx(INFO, _CYAN_("Handover request")); ndefDecodePayloadHandoverRequest(ndef->Payload, ndef->PayloadLen);
PrintAndLogEx(INFO, "- decoder to be impl -");
} }
if (!strncmp((char *)ndef->Type, "Hs", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "Hs", ndef->TypeLen)) {
PrintAndLogEx(INFO, _CYAN_("Handover select")); ndefDecodePayloadHandoverSelect(ndef->Payload, ndef->PayloadLen);
PrintAndLogEx(INFO, "- decoder to be impl -");
} }
if (!strncmp((char *)ndef->Type, "ac", ndef->TypeLen)) { if (!strncmp((char *)ndef->Type, "ac", ndef->TypeLen)) {
@ -931,20 +1036,33 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
} }
case tnfAbsoluteURIRecord: case tnfAbsoluteURIRecord:
PrintAndLogEx(INFO, "Absolute URI Record"); PrintAndLogEx(INFO, "Absolute URI Record");
PrintAndLogEx(INFO, " payload : %.*s", (int)ndef->PayloadLen, ndef->Payload); PrintAndLogEx(INFO, " payload : " _YELLOW_("%.*s"), (int)ndef->PayloadLen, ndef->Payload);
break; break;
case tnfExternalRecord: case tnfExternalRecord:
PrintAndLogEx(INFO, "External Record"); PrintAndLogEx(INFO, "External Record");
PrintAndLogEx(INFO, "- decoder to be impl -"); ndefDecodeExternal_record(ndef);
break; break;
case tnfUnknownRecord: case tnfUnknownRecord:
PrintAndLogEx(INFO, "Unknown Record"); PrintAndLogEx(INFO, "Unknown Record");
PrintAndLogEx(INFO, "- decoder to be impl -"); if (ndef->TypeLen != 0) {
PrintAndLogEx(FAILED, "unexpected type field");
break;
}
break; break;
case tnfUnchangedRecord: case tnfUnchangedRecord:
PrintAndLogEx(INFO, "Unchanged Record"); PrintAndLogEx(INFO, "Unchanged Record");
PrintAndLogEx(INFO, "- decoder to be impl -"); PrintAndLogEx(INFO, "- decoder to be impl -");
break; break;
case tnfReservedRecord:
PrintAndLogEx(INFO, "Reserved Record");
if (ndef->TypeLen != 0) {
PrintAndLogEx(FAILED, "unexpected type field");
break;
}
break;
default:
PrintAndLogEx(FAILED, "unexpected tnf value... 0x%02x", ndef->TypeNameFormat);
break;
} }
PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, "");
return PM3_SUCCESS; return PM3_SUCCESS;

View file

@ -31,7 +31,8 @@ typedef enum {
tnfAbsoluteURIRecord = 0x03, tnfAbsoluteURIRecord = 0x03,
tnfExternalRecord = 0x04, tnfExternalRecord = 0x04,
tnfUnknownRecord = 0x05, tnfUnknownRecord = 0x05,
tnfUnchangedRecord = 0x06 tnfUnchangedRecord = 0x06,
tnfReservedRecord = 0x07,
} TypeNameFormat_t; } TypeNameFormat_t;
typedef enum { typedef enum {

View file

@ -122,17 +122,18 @@ int preferences_save(void) {
PrintAndLogEx(INFO, "Saving preferences..."); PrintAndLogEx(INFO, "Saving preferences...");
char *fn = prefGetFilename(); char *fn = prefGetFilename();
int fnLen = strlen(fn) + 5; // .bak\0 int fn_len = strlen(fn) + 5; // .bak\0
// [FILENAME_MAX+sizeof(preferencesFilename)+10] // [FILENAME_MAX+sizeof(preferencesFilename)+10]
char *backupFilename = (char *)calloc(fnLen, sizeof(uint8_t)); char *backupFilename = (char *)calloc(fn_len, sizeof(uint8_t));
if (backupFilename == NULL) { if (backupFilename == NULL) {
PrintAndLogEx(ERR, "failed to allocate memory"); PrintAndLogEx(ERR, "failed to allocate memory");
free(fn); free(fn);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
snprintf(backupFilename, fnLen, "%s.bak", fn); snprintf(backupFilename, fn_len, "%s.bak", fn);
// remove old backup file
if (fileExists(backupFilename)) { if (fileExists(backupFilename)) {
if (remove(backupFilename) != 0) { if (remove(backupFilename) != 0) {
PrintAndLogEx(FAILED, "Error - could not delete old settings backup file \"%s\"", backupFilename); PrintAndLogEx(FAILED, "Error - could not delete old settings backup file \"%s\"", backupFilename);
@ -142,6 +143,7 @@ int preferences_save(void) {
} }
} }
// rename file to backup file
if (fileExists(fn)) { if (fileExists(fn)) {
if (rename(fn, backupFilename) != 0) { if (rename(fn, backupFilename) != 0) {
PrintAndLogEx(FAILED, "Error - could not backup settings file \"%s\" to \"%s\"", fn, backupFilename); PrintAndLogEx(FAILED, "Error - could not backup settings file \"%s\" to \"%s\"", fn, backupFilename);
@ -154,8 +156,9 @@ int preferences_save(void) {
uint8_t dummyData = 0x00; uint8_t dummyData = 0x00;
size_t dummyDL = 0x01; size_t dummyDL = 0x01;
if (saveFileJSON(fn, jsfCustom, &dummyData, dummyDL, &preferences_save_callback) != PM3_SUCCESS) if (saveFileJSONex(fn, jsfCustom, &dummyData, dummyDL, true, &preferences_save_callback, spItemCount) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error saving preferences to \"%s\"", fn); PrintAndLogEx(ERR, "Error saving preferences to \"%s\"", fn);
}
free(fn); free(fn);
free(backupFilename); free(backupFilename);

View file

@ -0,0 +1,114 @@
#!/usr/bin/env python3
"""
-----------------------------------------------------------------------------
Name: update_amiibo_tools_lua.py
Author: Cory Solovewicz
Description:
This is a python script to automate what the updating of the amiibo_tools.lua
file which holds a lua table of all known amiibos. Previously updating the
amiibo_tools.lua was a very manual process.
This script automates the following original command:
curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq 'del(.amiibos[].release)' | jq 'del(.characters)' | pbcopy --> transform to table
And outputs the formatted file as amiibo_tools.lua
If everything goes well, this should be an updated copy of amiibo_tools.lua
which can then be placed in the /lualibs/ directory.
The temporary amiibo.json file is then deleted
Dependencies:
python3 -m pip install jq
How to run:
python update_amiibo_tools_lua.py
The script will create the file amiibo_tools.lua
After running, manually backup the original /lualibs/amiibo_tools.lua and move the
updated amiibo_tools.lua to the /lualibs/ directory.
-----------------------------------------------------------------------------
"""
import os
import re
import subprocess
import json
from jq import jq
def fetch_data():
print("Fetching amiibo.json")
# Perform the curl command
curl_command = "curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json"
curl_process = subprocess.Popen(curl_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = curl_process.communicate()
if curl_process.returncode != 0:
print("Error fetching data: ", error.decode())
return None
return output
def filter_data(data):
print("Filtering downloaded data")
# Convert the output to JSON and use jq to filter data
data_json = json.loads(data)
filtered_data_json = jq('del(.amiibos[].release) | del(.characters)').transform(data_json)
# Convert the filtered JSON data back to a string, preserving Unicode characters
filtered_data = json.dumps(filtered_data_json, indent=2, ensure_ascii=False)
return filtered_data
def save_data(filtered_data, filename):
# Save filtered data to file
with open(filename, 'w', encoding='utf-8') as file:
file.write(filtered_data)
print(f"Data saved to {filename}")
def process_file(filename):
# Open the file
with open(filename, 'r', encoding='utf-8') as file:
data = file.read()
# Perform the replacements
data = data.replace('"name"', 'name')
data = data.replace('"amiibo_series"', 'amiibo_series')
data = data.replace('"amiibos"', 'amiibos')
data = data.replace('"game_series"', 'game_series')
data = data.replace('"types"', 'types')
data = data.replace(':', ' =')
data = re.sub('"0x', '["0x', data)
data = re.sub('" =', '"] =', data)
# Prepend the text
prepend_text = 'local amiibo_tools = {}\n\n-- curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq \'del(.amiibos[].release)\' | jq \'del(.characters)\' | pbcopy --> transform to table\namiibo_tools.db =\n'
data = prepend_text + data
# Append the text
append_text = '\n\nreturn amiibo_tools\n'
data = data + append_text
return data
def write_to_file(data, filename):
# Write the output
with open(filename, 'w', encoding='utf-8') as file:
file.write(data)
print(f"Output written to {filename}")
def delete_file(filename):
try:
os.remove(filename)
print(f"Temporary file {filename} deleted")
except OSError as e:
print(f"Error deleting file {filename}: ", e)
def main():
data = fetch_data()
if data:
filtered_data = filter_data(data)
save_data(filtered_data, 'amiibo.json')
processed_data = process_file('amiibo.json')
write_to_file(processed_data, 'amiibo_tools.lua')
delete_file('amiibo.json')
if __name__ == "__main__":
main()

View file

@ -3100,9 +3100,9 @@
"command": "hf iclass encode", "command": "hf iclass encode",
"description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn", "description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn",
"notes": [ "notes": [
"hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337", "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)",
"hf iclass encode --fc 31 --cn 337 --ki 0 -> FC 31 CN 337", "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)",
"hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key" "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key"
], ],
"offline": true, "offline": true,
"options": [ "options": [
@ -11991,4 +11991,4 @@
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2023-03-26T15:04:49" "extracted_on": "2023-03-26T15:04:49"
} }
} }

View file

@ -2,7 +2,6 @@
<a id="Top"></a> <a id="Top"></a>
# Mac OS X - MacPorts automatic installation # Mac OS X - MacPorts automatic installation
<b><h3>These insturctions won't work on Apple Silicon yet!</h3> An arm64 native build of arm-none-eabi-gcc is still not available (as of 2021-11-26).</b>
# Table of Contents # Table of Contents
- [Mac OS X - MacPorts automatic installation](#mac-os-x---macports-automatic-installation) - [Mac OS X - MacPorts automatic installation](#mac-os-x---macports-automatic-installation)
@ -23,70 +22,82 @@
1. Have MacPorts installed. Visit https://www.macports.org/ for more information. 1. Have MacPorts installed. Visit https://www.macports.org/ for more information.
* MacPorts may require a bit more setup. You first need to set up your PATH variable: ## Installing stable releases directly
```bash
export "/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/local/sbin:$PATH"
```
For a somewhat seamless development environment:
```bash
export C_INCLUDE_PATH="/opt/local/include"
export CPLUS_INCLUDE_PATH="/opt/local/include"
export LIBRARY_PATH="/opt/local/lib"
export LDFLAGS="-L/opt/local/lib"
export CFLAGS="-I/opt/local/include"
export CPPFLAGS="-isystem/opt/local/include -I/opt/local/include"
```
## Installing latest releases
^[Top](#top) ^[Top](#top)
Packaging for latest releases are available on MacPorts with the port name `proxmark3-iceman`, with a variant for PM3GENERIC firmwares available as `+pm3generic`. Packaging for latest releases are available on MacPorts with the port name [`proxmark3-iceman`](https://ports.macports.org/port/proxmark3-iceman/details/), with a variant for PM3GENERIC firmwares available as `+pm3generic`.
Installing is as simple as `sudo port install proxmark3-iceman` and if you want to install for PM3GENERIC, you can run `sudo port install proxmark3-iceman +pm3generic` instead. Installing is as simple as `sudo port install proxmark3-iceman` and if you want to install for PM3GENERIC, you can run `sudo port install proxmark3-iceman +pm3generic` instead.
## Build from source ## Build from source
^[Top](#top) ^[Top](#top)
These instructions will show how to setup the environment on OSX to the point where you'll be able to clone and compile the repo by yourself, as on Linux, Windows, etc. These instructions will show how to setup the environment on OSX to the point where you'll be able to clone and compile the repo by yourself, as on Linux, Windows, etc.
1. Have MacPorts installed. See above for details. 1. Have MacPorts installed. Visit https://www.macports.org/ for more information.
* Since you're going to compile directly; this will require a bit more setup, you first need to set up your PATH variable (we assume your MacPorts prefix is located at its default, which is `/opt/local`) in your shell rc file:
```bash
export MACPORTS_PREFIX="/opt/local"
# we assume you'll use GNU coreutils; which is also a required dependency for proxmark3
# install it with `sudo port install coreutils`
export "$MACPORTS_PREFIX/libexec/gnubin:$MACPORTS_PREFIX/bin:$MACPORTS_PREFIX/sbin:$PATH"
```
For a somewhat seamless development environment, you can use these in your shell rc file:
```bash
export C_INCLUDE_PATH="$MACPORTS_PREFIX/include:$C_INCLUDE_PATH"
export CPLUS_INCLUDE_PATH="$MACPORTS_PREFIX/include:$CPLUS_INCLUDE_PATH"
export LIBRARY_PATH="$MACPORTS_PREFIX/lib:$LIBRARY_PATH"
export LDFLAGS="-L$MACPORTS_PREFIX/lib $LDFLAGS"
export CFLAGS="-I$MACPORTS_PREFIX/include $CFLAGS"
export CPPFLAGS="-isystem$MACPORTS_PREFIX/include -I$MACPORTS_PREFIX/include $CPPFLAGS"
export PKG_CONFIG_PATH="$MACPORTS_PREFIX/lib/pkgconfig:$MACPORTS_PREFIX/share/pkgconfig:$PKG_CONFIG_PATH"
```
2. Install dependencies: 2. Install dependencies:
``` ```bash
sudo port install readline qt5 qt5-qtbase pkgconfig arm-none-eabi-gcc arm-none-eabi-binutils lua52 coreutils openssl@3 sudo port install readline jansson lua52 python311 bzip2 openssl11 arm-none-eabi-gcc arm-none-eabi-binutils coreutils qt5 qt5-qtbase pkgconfig
``` ```
3. Clamp Python version for pkg-config 3. Clamp Python version for pkg-config
MacPorts doesn't handle Python version defaults when it comes to pkg-config. So even if you have done: MacPorts doesn't handle Python version defaults when it comes to pkg-config. So even if you have done:
``` ```bash
sudo port install python39 cython39 sudo port install python311 cython311
sudo port select --set python python39 # this also makes calls to "python" operate on python3.9 sudo port select --set python python311 # this also makes calls to "python" operate on python3.11
sudo port select --set python3 python39 sudo port select --set python3 python311
sudo port select --set cython cython39 sudo port select --set cython cython311
``` ```
This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder. This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder.
To fix that, follow these steps: To fix that, follow these steps:
``` ```bash
cd /opt/local/lib/pkgconfig cd /opt/local/lib/pkgconfig
sudo ln -svf python3.pc python-3.9.pc sudo ln -svf python3.pc python-3.11.pc
sudo ln -svf python3-embed.pc python-3.9-embed.pc sudo ln -svf python3-embed.pc python-3.11-embed.pc
```
_Or_ you can use a framework definition in your shell rc file:
```bash
export MACPORTS_FRAMEWORKS_DIR="$MACPORTS_PREFIX/Library/Frameworks"
export PYTHON_FRAMEWORK_DIR="$MACPORTS_FRAMEWORKS_DIR:/Python.framework/Versions/3.11"
export PKG_CONFIG_PATH="$PYTHON_FRAMEWORK_DIR:$PKG_CONFIG_PATH"
``` ```
4. (optional) Install makefile dependencies: 4. (optional) Install makefile dependencies:
``` ```bash
sudo port install recode sudo port install recode astyle
sudo port install astyle
``` ```
@ -103,7 +114,7 @@ cd proxmark3
Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md). Now you're ready to follow the [compilation instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md).
From there, you can follow the original instructions. From there, you can follow the original instructions.
_Take extra note to instructions if you don't have a Proxmark3 RDV4 device._ _Take extra note to instructions if you **don't** have a Proxmark3 RDV4 device._
To flash on OS X, better to enter the bootloader mode manually, else you may experience errors. To flash on OS X, better to enter the bootloader mode manually, else you may experience errors.
@ -125,4 +136,3 @@ If you want to manually select serial port, remember that the Proxmark3 port is
```sh ```sh
proxmark3 /dev/ttyACM0 => proxmark3 /dev/tty.usbmodemiceman1 proxmark3 /dev/ttyACM0 => proxmark3 /dev/tty.usbmodemiceman1
``` ```

View file

@ -108,6 +108,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo
| LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini | LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini
| LF_HIDFCBRUTE | LF HID facility code bruteforce - ss23 | LF_HIDFCBRUTE | LF HID facility code bruteforce - ss23
| LF_ICEHID | LF HID collector to flashmem - Iceman1001 | LF_ICEHID | LF HID collector to flashmem - Iceman1001
| LF_MULTIHID | LF HID 26 Bit (H1031) multi simulator - Shain Lakin
| LF_NEDAP_SIM | LF Nedap ID simulator | LF_NEDAP_SIM | LF Nedap ID simulator
| LF_NEXID | Nexwatch credentials detection mode - jrjgjk & Zolorah | LF_NEXID | Nexwatch credentials detection mode - jrjgjk & Zolorah
| LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz | LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -222,17 +222,29 @@ reg signed [10:0] rx_mod_falling_edge_max;
reg signed [10:0] rx_mod_rising_edge_max; reg signed [10:0] rx_mod_rising_edge_max;
reg curbit; reg curbit;
`define EDGE_DETECT_THRESHOLD 5 `define EDGE_DETECT_THRESHOLD 3
`define EDGE_DETECT_THRESHOLDHIGH 20
always @(negedge adc_clk) always @(negedge adc_clk)
begin begin
if(negedge_cnt[3:0] == mod_detect_reset_time) if(negedge_cnt[3:0] == mod_detect_reset_time)
begin begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge if (mod_type == `FPGA_HF_ISO14443A_SNIFFER)
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLD) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLD)) begin
curbit <= 1'b1; // modulation // detect modulation signal: if modulating, there must have been a falling AND a rising edge
else if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLDHIGH) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLDHIGH))
curbit <= 1'b0; // no modulation curbit <= 1'b1; // modulation
else
curbit <= 1'b0; // no modulation
end
else
begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLD) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLD))
curbit <= 1'b1; // modulation
else
curbit <= 1'b0; // no modulation
end
// reset modulation detector // reset modulation detector
rx_mod_rising_edge_max <= 0; rx_mod_rising_edge_max <= 0;
rx_mod_falling_edge_max <= 0; rx_mod_falling_edge_max <= 0;

View file

@ -22,8 +22,7 @@ echo "Destination: ${DEST:=firmware}"
echo "Produce stats?: ${STATS:=false}" echo "Produce stats?: ${STATS:=false}"
# Which parts to skip for the 256kb version? # Which parts to skip for the 256kb version?
SKIPS256="SKIP_HITAG=1 SKIP_LEGICRF=1 SKIP_FELICA=1 SKIP_EM4x50=1 SKIP_ISO14443b=1 SKIP_NFCBARCODE=1 SKIP_ZX8211=1" SKIPS256="SKIP_HITAG=1 SKIP_LEGICRF=1 SKIP_FELICA=1 SKIP_EM4x50=1 SKIP_ISO14443b=1 SKIP_NFCBARCODE=1 SKIP_ZX8211=1 SKIP_LF=1"
make $MKFLAGS bootrom || exit 1 make $MKFLAGS bootrom || exit 1
chmod 644 bootrom/obj/bootrom.elf chmod 644 bootrom/obj/bootrom.elf
@ -32,7 +31,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf"
# cf armsrc/Standalone/Makefile.hal # cf armsrc/Standalone/Makefile.hal
STANDALONE_MODES=(LF_SKELETON) STANDALONE_MODES=(LF_SKELETON)
STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE) STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE)
STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG) STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG)
STANDALONE_MODES+=(DANKARMULTI) STANDALONE_MODES+=(DANKARMULTI)
STANDALONE_MODES_REQ_BT=(HF_REBLAY) STANDALONE_MODES_REQ_BT=(HF_REBLAY)

View file

@ -388,6 +388,7 @@ while true; do
if ! CheckExecute "nfc decode test - device info" "$CLIENTBIN -c 'nfc decode -d d1025744690004536f6e79010752432d533338300220426c61636b204e46432052656164657220636f6e6e656374656420746f2050430310123e4567e89b12d3a45642665544000004124e464320506f72742d3130302076312e3032'" "NFC Port-100 v1.02"; then break; fi if ! CheckExecute "nfc decode test - device info" "$CLIENTBIN -c 'nfc decode -d d1025744690004536f6e79010752432d533338300220426c61636b204e46432052656164657220636f6e6e656374656420746f2050430310123e4567e89b12d3a45642665544000004124e464320506f72742d3130302076312e3032'" "NFC Port-100 v1.02"; then break; fi
if ! CheckExecute "nfc decode test - vcard" "$CLIENTBIN -c 'nfc decode -d d20ca3746578742f782d7643617264424547494e3a56434152440a56455253494f4e3a332e300a4e3a43687269733b4963656d616e3b3b3b0a464e3a476f7468656e627572670a5245563a323032312d30362d32345432303a31353a30385a0a6974656d322e582d4142444154453b747970653d707265663a323032302d30362d32340a4954454d322e582d41424c4142454c3a5f24213c416e6e69766572736172793e21245f0a454e443a56434152440a'" "END:VCARD"; then break; fi if ! CheckExecute "nfc decode test - vcard" "$CLIENTBIN -c 'nfc decode -d d20ca3746578742f782d7643617264424547494e3a56434152440a56455253494f4e3a332e300a4e3a43687269733b4963656d616e3b3b3b0a464e3a476f7468656e627572670a5245563a323032312d30362d32345432303a31353a30385a0a6974656d322e582d4142444154453b747970653d707265663a323032302d30362d32340a4954454d322e582d41424c4142454c3a5f24213c416e6e69766572736172793e21245f0a454e443a56434152440a'" "END:VCARD"; then break; fi
if ! CheckExecute "nfc decode test - apple wallet" "$CLIENTBIN -c 'nfc decode -d 031AD10116550077616C6C65743A2F2F61637469766174652F6E6663FE'" "activate/nfc"; then break; fi if ! CheckExecute "nfc decode test - apple wallet" "$CLIENTBIN -c 'nfc decode -d 031AD10116550077616C6C65743A2F2F61637469766174652F6E6663FE'" "activate/nfc"; then break; fi
if ! CheckExecute "nfc decode test - signature" "$CLIENTBIN -c 'nfc decode -d 03FF010194113870696C65742E65653A656B616172743A3266195F26063132303832325904202020205F28033233335F2701316E1B5A13333038363439303039303030323636343030355304EBF2CE704103000000AC536967010200803A2448FCA7D354A654A81BD021150D1A152D1DF4D7A55D2B771F12F094EAB6E5E10F2617A2F8DAD4FD38AFF8EA39B71C19BD42618CDA86EE7E144636C8E0E7CFC4096E19C3680E09C78A0CDBC05DA2D698E551D5D709717655E56FE3676880B897D2C70DF5F06ECE07C71435255144F8EE41AF110E7B180DA0E6C22FB8FDEF61800025687474703A2F2F70696C65742E65652F6372742F33303836343930302D303030312E637274FE'" "30864900-0001.crt"; then break; fi
echo -e "\n${C_BLUE}Testing LF:${C_NC}" echo -e "\n${C_BLUE}Testing LF:${C_NC}"
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi