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
uses: peterjgrainger/action-changelog-reminder@v1.2.0
with:
changelog_regex: '/CHANGELOG.md'
changelog_regex: 'CHANGELOG.md'
customPrMessage: 'You are welcome to add an entry to the CHANGELOG.md as well'
env:
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...
## [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 `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)
@ -49,6 +63,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `hf legic einfo` - views emulator menory (@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)
- 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]
- 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 |
| (RDV4 only) | |
+----------------------------------------------------------+
| LF_MULTIHID | LF HID 26 Bit (H1031) multi simulator |
| | - Shain Lakin |
+----------------------------------------------------------+
| LF_NEDAP_SIM | LF Nedap ID simple simulator |
| | |
+----------------------------------------------------------+
@ -126,7 +129,7 @@ endef
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 += DANKARMULTI
STANDALONE_MODES_REQ_BT := HF_REBLAY

View file

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

View file

@ -189,7 +189,7 @@ void RunMod(void) {
memcpy(data, visauid, 4);
// 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;
uint32_t cuid = 0;
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
@ -377,6 +377,7 @@ void RunMod(void) {
// dynamic_response_info will be in charge of responses
dynamic_response_info.response_n = 0;
//Dbprintf("receivedCmd: %02x\n", receivedCmd);
// received a REQUEST
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) {
odd_reply = !odd_reply;
@ -386,30 +387,35 @@ void RunMod(void) {
// received a HALT
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
// DbpString(_YELLOW_("+") "Received a HALT");
//DbpString(_YELLOW_("+") "Received a HALT");
p_response = NULL;
// received a WAKEUP
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
// DbpString(_YELLOW_("+") "WAKEUP Received");
//DbpString(_YELLOW_("+") "WAKEUP Received");
prevCmd = 0;
p_response = &responses[RESP_INDEX_ATQA];
// received request for UID (cascade 1)
} 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];
// received a SELECT (cascade 1)
} 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];
// received a RATS request
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
// DbpString(_YELLOW_("+") "Request for RATS");
DbpString(_YELLOW_("+") "Request for RATS");
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 {
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
@ -483,6 +489,7 @@ void RunMod(void) {
}
}
}
if (dynamic_response_info.response_n > 0) {
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
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;
if (bPwd && (bAuthenticating == false) && write) {
SpinDelay(2);
if (hitag2_write_page(rx, rxlen, tx, txlen) == false) {
return false;
}

View file

@ -1151,6 +1151,11 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, tag_r
sak = 0x20;
}
break;
case 11: { // ISO/IEC 14443-4 - javacard (JCOP)
rATQA[0] = 0x04;
sak = 0x20;
}
break;
default: {
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
rATQA[0] &= 0xBF;
if(tagType == 11){
rSAKc1[0] = sak & 0xFC & 0X70;
}else{
rSAKc1[0] = sak & 0xFB;
}
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
*cuid = bytes_to_num(data, 4);
@ -2084,8 +2095,8 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
if (timer == 0) {
timer = GetTickCount();
} else {
// 50ms no field --> card to idle state
if (GetTickCountDelta(timer) > 50) {
// 4ms no field --> card to idle state
if (GetTickCountDelta(timer) > 4) {
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));
LED_B_OFF();
if (g_dbglevel >= DBG_ERROR) DbpString("AcquireEncryptedNonces finished");
if (field_off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();

View file

@ -2029,9 +2029,8 @@ D144BD193063
8627C10A7014
453857395635
#
# Data from "the more, the marriott" mifare project (colonel borkmundus)
#
# Isn't theirs Saflok ?
# Data from "the more the marriott" mifare project (colonelborkmundus)
# aka The Horde
#
# 20230125-01, Elite Member Marriott Rewards
43012BD9EB87
@ -2098,6 +2097,52 @@ C49DAE1C6049
6E029927600D
3E173F64C01C
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
6686FADE5566
@ -2105,3 +2150,7 @@ C670A9AD6066
# Data from Discord, French pool
9B7C25052FC3
494446555455
#
# Data from Discord, seems to be related to ASSA
427553754D47

View file

@ -55,6 +55,9 @@ amiibo_tools.db =
["0x00000003039bff02"] = {
name = "Mario - Power Up Band"
},
["0x000000030430ff02"] = {
name = "Golden - Power Up Band"
},
["0x0000010000190002"] = {
name = "Dr. Mario"
},
@ -214,6 +217,9 @@ amiibo_tools.db =
["0x0100000003990902"] = {
name = "Link - Link's Awakening"
},
["0x0100000004180902"] = {
name = "Link - Tears of the Kingdom"
},
["0x0100010000160002"] = {
name = "Toon Link"
},
@ -1834,6 +1840,9 @@ amiibo_tools.db =
["0x0800010003820002"] = {
name = "Inkling"
},
["0x0800010004150402"] = {
name = "Inkling - Yellow"
},
["0x08000200003f0402"] = {
name = "Inkling Boy"
},
@ -1870,9 +1879,15 @@ amiibo_tools.db =
["0x08050200038f0402"] = {
name = "Octoling Boy"
},
["0x08050200041b0402"] = {
name = "Octoling - Blue"
},
["0x0805030003900402"] = {
name = "Octoling Octopus"
},
["0x08060100041c0402"] = {
name = "Smallfry"
},
["0x09c0010102690e02"] = {
name = "Mario - Soccer"
},
@ -2374,6 +2389,9 @@ amiibo_tools.db =
["0x3380000003781402"] = {
name = "Solaire of Astora"
},
["0x33c0000004200002"] = {
name = "Kazuya"
},
["0x3480000000310002"] = {
name = "Mega Man"
},
@ -2455,6 +2473,9 @@ amiibo_tools.db =
["0x3600010003620002"] = {
name = "Cloud - Player 2"
},
["0x3601000004210002"] = {
name = "Sephiroth"
},
["0x3640000003a20002"] = {
name = "Hero"
},
@ -2520,6 +2541,12 @@ amiibo_tools.db =
},
["0x3c80000003a40002"] = {
name = "Terry"
},
["0x3dc0000004220002"] = {
name = "Steve"
},
["0x3dc1000004230002"] = {
name = "Alex"
}
},
game_series = {
@ -2621,6 +2648,7 @@ amiibo_tools.db =
["0x324"] = "Bayonetta",
["0x334"] = "Pac-man",
["0x338"] = "Dark Souls",
["0x33c"] = "Tekken",
["0x348"] = "Megaman",
["0x34c"] = "Street fighter",
["0x350"] = "Monster Hunter",
@ -2635,7 +2663,8 @@ amiibo_tools.db =
["0x38c"] = "Diablo",
["0x3a0"] = "Persona",
["0x3b4"] = "Banjo Kazooie",
["0x3c8"] = "Fatal Fury"
["0x3c8"] = "Fatal Fury",
["0x3dc"] = "Minecraft"
},
types = {
["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",
"Vendor": "ISO/IEC JTC1/SC17",
"Country": "",
"Name": "Personal identification (mDL)",
"Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application.",
"Name": "Personal identification (mDL) data transfer",
"Description": "ISO/IEC 18013-5:2021 compliant Mobile driving licence (mDL) application data transfer.",
"Type": "identity"
},
{
@ -2259,10 +2259,26 @@
"AID": "A000000809434343444B467631",
"Vendor": "Car Connectivity Consortium (CCC)",
"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",
"Description": "",
"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",
"Vendor": "Apple",
@ -2270,5 +2286,45 @@
"Name": "Apple Home Key",
"Description": "NFC Home Key for select HomeKit-compatible locks",
"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 "desfire.h" // desfire enums
#include "mifare/desfirecore.h" // desfire context
#include "mifare/mifaredefault.h"
static bool g_apdu_in_framing_enable = true;
bool Get_apdu_in_framing(void) {
@ -738,9 +739,6 @@ int CmdHF14ASim(const char *Cmd) {
return PM3_EINVARG;
}
sector_t *k_sector = NULL;
uint8_t k_sectorsCount = 40;
if (useUIDfromEML) {
flags |= FLAG_UID_IN_EMUL;
}
@ -761,17 +759,24 @@ int CmdHF14ASim(const char *Cmd) {
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
sector_t *k_sector = NULL;
size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR;
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
bool keypress = kbd_enter_pressed();
while (keypress == false) {
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue;
if (resp.status != PM3_SUCCESS) break;
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
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;
readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose);
readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
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)) {
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[] = {
arg_param_begin,
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
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -1366,6 +1367,7 @@ static int CmdHF14BDump(const char *Cmd) {
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
bool nosave = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
@ -1514,6 +1516,7 @@ static int CmdHF14BDump(const char *Cmd) {
print_sr_blocks(data, cardsize, card.uid);
if (nosave == false) {
// save to file
if (fnlen < 1) {
PrintAndLogEx(INFO, "using UID as filename");
@ -1524,6 +1527,7 @@ static int CmdHF14BDump(const char *Cmd) {
size_t datalen = (lastblock + 2) * ST25TB_SR_BLOCK_SIZE;
pm3_save_dump(filename, data, datalen, jsf14b, ST25TB_SR_BLOCK_SIZE);
}
}
return switch_off_field_14b();
}

View file

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

View file

@ -18,7 +18,6 @@
#include "cmdhfmf.h"
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN
#include "comms.h" // clearCommandBuffer
@ -38,23 +37,6 @@
#include "wiegand_formats.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);
/*
@ -152,21 +134,20 @@ static char *GenerateFilename(const char *prefix, const char *suffix) {
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));
if (*src == NULL)
return -1;
return PM3_EMALLOC;
// empty e_sector
for (int i = 0; i < items; ++i) {
for (int j = 0; j < 2; ++j) {
for (size_t i = 0; i < items; i++) {
for (uint8_t j = 0; j < 2; j++) {
(*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) {
@ -313,8 +294,11 @@ static int mf_print_keys(uint16_t n, uint8_t *d) {
sectors = MIFARE_4K_MAXSECTOR;
break;
case MIFARE_1K_MAXBLOCK:
sectors = MIFARE_1K_MAXSECTOR;
break;
default:
sectors = MIFARE_1K_MAXSECTOR;
n = MIFARE_1K_MAXBLOCK;
break;
}
@ -324,6 +308,7 @@ static int mf_print_keys(uint16_t n, uint8_t *d) {
}
for (uint16_t i = 0; i < n; i++) {
if (mfIsSectorTrailer(i)) {
e_sector[mfSectorNum(i)].foundKey[0] = 1;
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"
"\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"
"\n"
"`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
@ -1339,14 +1324,16 @@ static int CmdHF14AMfRestore(const char *Cmd) {
uint8_t wdata[26];
memcpy(wdata + 10, bldata, sizeof(bldata));
if (use_keyfile_for_auth) {
for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
if (use_keyfile_for_auth) {
if (kt == MF_KEY_A)
memcpy(wdata, keyA[s], 6);
else
memcpy(wdata, keyB[s], 6);
} 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)));
clearCommandBuffer();
@ -1368,27 +1355,6 @@ static int CmdHF14AMfRestore(const char *Cmd) {
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)));
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, MF_KEY_B, 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 B ( " _RED_("fail") " )");
} else {
PrintAndLogEx(FAILED, "Write to block %u w key B ( " _RED_("fail") " )", b);
}
}
} else {
PrintAndLogEx(WARNING, "Command execute timeout");
}
} // end use_keyfile_for_auth
} // end loop B
} // end loop S
@ -2373,7 +2339,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
// Attack key storage variables
uint8_t *keyBlock = NULL;
uint32_t key_cnt = 0;
sector_t *e_sector;
uint8_t tmp_key[6] = {0};
// Nested and Hardnested returned status
@ -2408,7 +2373,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
// detect MFC EV1 Signature
bool is_ev1 = detect_mfc_ev1_signature();
if (is_ev1) {
@ -2417,10 +2381,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
}
// create/initialize key storage structure
uint32_t e_sector_size = sector_cnt > sectorno ? sector_cnt : sectorno + 1;
res = initSectorTable(&e_sector, e_sector_size);
if (res != e_sector_size) {
free(e_sector);
sector_t *e_sector = NULL;
size_t e_sector_cnt = (sector_cnt > sectorno) ? sector_cnt : sectorno + 1;
if (initSectorTable(&e_sector, e_sector_cnt) != PM3_SUCCESS) {
return PM3_EMALLOC;
}
@ -2859,8 +2822,11 @@ tryNested:
}
break;
}
case PM3_ESTATIC_NONCE:
case PM3_ESTATIC_NONCE: {
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
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
@ -2869,6 +2835,7 @@ tryNested:
free(e_sector);
free(fptr);
return isOK;
}
case PM3_SUCCESS: {
calibrate = false;
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");
}
foundkey = 0;
isOK = mfnestedhard(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
DropField();
if (isOK) {
@ -2907,6 +2875,10 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
}
case PM3_ESTATIC_NONCE: {
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
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
@ -3181,7 +3153,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
m1 = true;
}
uint8_t sectorsCnt = 1;
uint8_t sectorsCnt = MIFARE_1K_MAXSECTOR;
if (m0) {
sectorsCnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) {
@ -3204,8 +3176,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
// create/initialize key storage structure
sector_t *e_sector = NULL;
int32_t res = initSectorTable(&e_sector, sectorsCnt);
if (res != sectorsCnt) {
if (initSectorTable(&e_sector, sectorsCnt) != PM3_SUCCESS) {
free(keyBlock);
return PM3_EMALLOC;
}
@ -3240,7 +3211,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
if (size == keycnt - i)
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)
firstChunk = false;
@ -3398,42 +3369,42 @@ static int CmdHF14AMfChk(const char *Cmd) {
return PM3_EINVARG;
}
uint8_t SectorsCnt = 1;
size_t sectors_cnt = 1;
if (m0) {
SectorsCnt = MIFARE_MINI_MAXSECTOR;
sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) {
SectorsCnt = MIFARE_1K_MAXSECTOR;
sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (m2) {
SectorsCnt = MIFARE_2K_MAXSECTOR;
sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (m4) {
SectorsCnt = MIFARE_4K_MAXSECTOR;
sectors_cnt = MIFARE_4K_MAXSECTOR;
}
if (singleSector) {
uint8_t MinSectorsCnt = 0;
size_t min_sectors_cnt = 0;
// find a MIFARE type that can accommodate the provided block number
uint8_t s = mfSectorNum(blockNo);
if (s < MIFARE_MINI_MAXSECTOR) {
MinSectorsCnt = MIFARE_MINI_MAXSECTOR;
min_sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (s < MIFARE_1K_MAXSECTOR) {
MinSectorsCnt = MIFARE_1K_MAXSECTOR;
min_sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (s < MIFARE_2K_MAXSECTOR) {
MinSectorsCnt = MIFARE_2K_MAXSECTOR;
min_sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (s < MIFARE_4K_MAXSECTOR) {
MinSectorsCnt = MIFARE_4K_MAXSECTOR;
min_sectors_cnt = MIFARE_4K_MAXSECTOR;
} else {
PrintAndLogEx(WARNING, "Provided block out of possible MIFARE Type memory map");
return PM3_EINVARG;
}
if (SectorsCnt == 1) {
SectorsCnt = MinSectorsCnt;
} else if (SectorsCnt < MinSectorsCnt) {
if (sectors_cnt == 1) {
sectors_cnt = min_sectors_cnt;
} else if (sectors_cnt < min_sectors_cnt) {
PrintAndLogEx(WARNING, "Provided block out of provided MIFARE Type memory map");
return PM3_EINVARG;
}
}
if (SectorsCnt == 1) {
SectorsCnt = MIFARE_1K_MAXSECTOR;
if (sectors_cnt == 1) {
sectors_cnt = MIFARE_1K_MAXSECTOR;
}
uint8_t *keyBlock = NULL;
@ -3447,8 +3418,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
// create/initialize key storage structure
sector_t *e_sector = NULL;
int32_t res = initSectorTable(&e_sector, SectorsCnt);
if (res != SectorsCnt) {
if (initSectorTable(&e_sector, sectors_cnt) != PM3_SUCCESS) {
free(keyBlock);
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
int b = blockNo;
for (int i = mfSectorNum(b); i < SectorsCnt; ++i) {
for (int i = mfSectorNum(b); i < sectors_cnt; ++i) {
// skip already found keys.
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
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
if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
@ -3558,13 +3528,13 @@ out:
if (singleSector)
printKeyTableEx(1, e_sector, mfSectorNum(blockNo));
else
printKeyTable(SectorsCnt, e_sector);
printKeyTable(sectors_cnt, e_sector);
if (transferToEml) {
// fast push mode
g_conn.block_after_ACK = true;
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;
mfEmlGetMem(block, blockno, 1);
@ -3574,7 +3544,7 @@ out:
if (e_sector[i].foundKey[1])
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
g_conn.block_after_ACK = false;
}
@ -3585,7 +3555,7 @@ out:
if (createDumpFile) {
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");
}
free(fptr);
@ -3606,28 +3576,24 @@ out:
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) {
printKeyTable(k_sectorsCount, k_sector);
printKeyTable(k_sectors_cnt, k_sector);
free(k_sector);
}
}
void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, bool setEmulatorMem, bool verbose) {
uint64_t key = 0;
bool success = false;
void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose) {
// init if needed
if (k_sector == NULL) {
int32_t res = initSectorTable(&k_sector, k_sectorsCount);
if (res != k_sectorsCount) {
free(k_sector);
if (initSectorTable(&k_sector, k_sectors_cnt) != PM3_SUCCESS) {
return;
}
}
success = mfkey32_moebius(&data, &key);
if (success) {
uint64_t key = 0;
if (mfkey32_moebius(&data, &key)) {
uint8_t sector = data.sector;
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
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[1], 6, memBlock + 10);
//iceman, guessing this will not work so well for 4K tags.
@ -3751,22 +3717,19 @@ static int CmdHF14AMfSim(const char *Cmd) {
}
CLIParserFree(ctx);
sector_t *k_sector = NULL;
//Validations
if (atqalen > 0) {
if (atqalen != 2) {
PrintAndLogEx(WARNING, "Wrong ATQA length");
return PM3_EINVARG;
}
flags |= FLAG_FORCED_ATQA;
}
if (saklen > 0) {
if (saklen != 1) {
PrintAndLogEx(WARNING, "Wrong SAK length");
return PM3_EINVARG;
}
flags |= FLAG_FORCED_SAK;
}
@ -3776,7 +3739,7 @@ static int CmdHF14AMfSim(const char *Cmd) {
flags |= FLAG_UID_IN_EMUL;
}
uint8_t k_sectorsCount = 40;
size_t k_sectors_cnt = MIFARE_4K_MAXSECTOR;
char csize[13] = { 0 };
if ((m0 + m1 + m2 + m4) > 1) {
@ -3787,19 +3750,19 @@ static int CmdHF14AMfSim(const char *Cmd) {
if (m0) {
flags |= FLAG_MF_MINI;
snprintf(csize, sizeof(csize), "MINI");
k_sectorsCount = MIFARE_MINI_MAXSECTOR;
k_sectors_cnt = MIFARE_MINI_MAXSECTOR;
} else if (m1) {
flags |= FLAG_MF_1K;
snprintf(csize, sizeof(csize), "1K");
k_sectorsCount = MIFARE_1K_MAXSECTOR;
k_sectors_cnt = MIFARE_1K_MAXSECTOR;
} else if (m2) {
flags |= FLAG_MF_2K;
snprintf(csize, sizeof(csize), "2K with RATS");
k_sectorsCount = MIFARE_2K_MAXSECTOR;
k_sectors_cnt = MIFARE_2K_MAXSECTOR;
} else if (m4) {
flags |= FLAG_MF_4K;
snprintf(csize, sizeof(csize), "4K");
k_sectorsCount = MIFARE_4K_MAXSECTOR;
k_sectors_cnt = MIFARE_4K_MAXSECTOR;
} else {
PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
return PM3_EINVARG;
@ -3837,15 +3800,26 @@ static int CmdHF14AMfSim(const char *Cmd) {
if (flags & FLAG_INTERACTIVE) {
PrintAndLogEx(INFO, "Press pm3-button or send another cmd to abort simulation");
while (!kbd_enter_pressed()) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
if (!(flags & FLAG_NR_AR_ATTACK)) break;
if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break;
sector_t *k_sector = NULL;
while (kbd_enter_pressed() == 0) {
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];
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 {
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);
}
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 strB[26 + 1] = {0};
char resA[20 + 1] = {0};
@ -3899,45 +3873,49 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
PrintAndLogEx(SUCCESS, " Sec | Blk | key A |res| key B |res");
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
for (uint8_t i = 0; i < sectorscnt; i++) {
snprintf(strA, sizeof(strA), "------------");
snprintf(strB, sizeof(strB), "------------");
uint64_t ndef_key = 0xD3F7D3F7D3F7;
bool has_ndef_key = false;
bool extended_legend = false;
for (size_t i = 0; i < sectorscnt; i++) {
if (e_sector[i].foundKey[0])
snprintf(strA, sizeof(strA), "%012" PRIX64, e_sector[i].Key[0]);
if ((e_sector[i].foundKey[0] > 1) || (e_sector[i].foundKey[1] > 1)) {
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].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]);
snprintf(resA, sizeof(resA), _BRIGHT_GREEN_("%d"), 1);
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_("%d"), 0);
snprintf(resA, sizeof(resA), _RED_("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);
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_("%d"), 0);
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"
@ -3947,9 +3925,10 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
, strB, resB
);
}
}
PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----");
if (e_sector[0].foundKey[0] > 1) {
if (extended_legend) {
PrintAndLogEx(INFO, "( "
_YELLOW_("D") ":Dictionary / "
_YELLOW_("S") ":darkSide / "
@ -3966,9 +3945,13 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
}
// 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");
}
// NDEF detection
if (has_ndef_key) {
PrintAndLogEx(HINT, "NDEF key detected. Try " _YELLOW_("`hf mf ndefread`") " for more details");
}
PrintAndLogEx(NORMAL, "");
}
@ -4572,7 +4555,7 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
m1 = true;
}
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
size_t sectors_cnt = MIFARE_1K_MAXSECTOR;
if (m0) {
sectors_cnt = MIFARE_MINI_MAXSECTOR;
@ -4587,12 +4570,9 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
return PM3_EINVARG;
}
sector_t *e_sector = NULL;
// create/initialize key storage structure
int32_t res = initSectorTable(&e_sector, sectors_cnt);
if (res != sectors_cnt) {
free(e_sector);
sector_t *e_sector = NULL;
if (initSectorTable(&e_sector, sectors_cnt) != PM3_SUCCESS) {
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 CmdHFMFNDEFWrite(const char *Cmd); // used by "nfc mf cwrite"
void showSectorTable(sector_t *k_sector, uint8_t k_sectorsCount);
void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, bool setEmulatorMem, bool verbose);
void printKeyTable(uint8_t sectorscnt, sector_t *e_sector);
void printKeyTableEx(uint8_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);
void showSectorTable(sector_t *k_sector, size_t k_sectors_cnt);
void readerAttack(sector_t *k_sector, size_t k_sectors_cnt, nonces_t data, bool setEmulatorMem, bool verbose);
void printKeyTable(size_t sectorscnt, sector_t *e_sector);
void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector);
int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len);
#endif

View file

@ -1006,16 +1006,18 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) {
// main cycle with key check
for (int i = 0; i < keyListLen; i++) {
if (i % 10 == 0) {
if (verbose == false)
PrintAndLogEx(NORMAL, "." NOLF);
// allow client abort every iteration
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
DropField();
return PM3_EOPABORTED;
}
if (i % 10 == 0) {
if (verbose == false) {
PrintAndLogEx(NORMAL, "." NOLF);
}
}
uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB;
@ -1024,7 +1026,7 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
for (int retry = 0; retry < 4; retry++) {
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;
if (verbose)
@ -1037,9 +1039,6 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
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
if (res == PM3_SUCCESS) {
if (verbose)
@ -1052,9 +1051,14 @@ static int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyA
DropField();
selectCard = true;
msleep(50);
// break out from keylist check loop,
break;
}
if (verbose)
PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res);
// RES can be:
// PM3_ERFTRANS -7
// 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_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_lit0(NULL, "ns", "no save to file"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2454,6 +2455,7 @@ static int CmdHF14AMfUDump(const char *Cmd) {
bool swap_endian = arg_get_lit(ctx, 3);
int start_page = arg_get_int_def(ctx, 4, 0);
int pages = arg_get_int_def(ctx, 5, 16);
bool nosave = arg_get_lit(ctx, 6);
CLIParserFree(ctx);
bool has_auth_key = false;
@ -2649,9 +2651,9 @@ static int CmdHF14AMfUDump(const char *Cmd) {
printMFUdumpEx(&dump_file_data, pages, start_page);
if (nosave == false) {
// 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);
@ -2659,11 +2661,14 @@ static int CmdHF14AMfUDump(const char *Cmd) {
strcat(filename, "hf-mfu-");
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)
if (is_partial) {
PrintAndLogEx(WARNING, "Partial dump created. (%d of %d blocks)", pages, card_mem_size);
}
}
return PM3_SUCCESS;
}
@ -2685,7 +2690,7 @@ static void wait4response(uint8_t b) {
int CmdHF14MfUTamper(const char *Cmd) {
CLIParserContext *ctx;
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"
"NTAG 213TT\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"},
{"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"},
{"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") " -----------------------"},
{"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into 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;
}
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) {
char msg[100];
@ -630,6 +661,8 @@ static int CmdLFHitagReader(const char *Cmd) {
// print data
print_hex_break(data, 48, 4);
printHitag2PaxtonDowngrade(data);
}
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) {
PrintAndLogEx(SUCCESS, "Reading Page %d:", page);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "Page " _YELLOW_("%d"), page);
PrintAndLogEx(SUCCESS, "blk | hex data | binary | ascii");
PrintAndLogEx(SUCCESS, "----+----------+----------------------------------+-------");
}
@ -815,7 +816,7 @@ static void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
break;
}
PrintAndLogEx(NORMAL, msg);
PrintAndLogEx(SUCCESS, msg);
}
static int CmdT55xxWakeUp(const char *Cmd) {
@ -2222,14 +2223,15 @@ static int CmdT55xxDump(const char *Cmd) {
"lf t55xx dump -f my_lf_dump"
);
// 1 (help) + 3 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
void *argtable[4 + 5] = {
// 1 (help) + 4 (two user specified params) + (5 T55XX_DLMODE_SINGLE)
void *argtable[5 + 5] = {
arg_param_begin,
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_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);
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -2251,10 +2253,12 @@ static int CmdT55xxDump(const char *Cmd) {
usepwd = true;
}
bool r0 = arg_get_lit(ctx, 4);
bool r1 = arg_get_lit(ctx, 5);
bool r2 = arg_get_lit(ctx, 6);
bool r3 = arg_get_lit(ctx, 7);
bool nosave = arg_get_lit(ctx, 4);
bool r0 = arg_get_lit(ctx, 5);
bool r1 = arg_get_lit(ctx, 6);
bool r2 = arg_get_lit(ctx, 7);
bool r3 = arg_get_lit(ctx, 8);
CLIParserFree(ctx);
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
printT5xxHeader(0);
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;
}
// only show override warning on the first block read
if (override == 1) {
@ -2287,12 +2292,14 @@ static int CmdT55xxDump(const char *Cmd) {
}
}
printT5xxHeader(1);
for (uint8_t i = 0; i < 4; i++)
if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS)
for (uint8_t i = 0; i < 4; i++) {
if (T55xxReadBlock(i, 1, usepwd, override, password, downlink_mode) != PM3_SUCCESS) {
T55x7_SaveBlockData(8 + i, 0x00);
}
}
// all ok, save dump to file
if (success) {
if (success && nosave == false) {
// set default filename, if not set by user
if (strlen(filename) == 0) {
@ -4019,7 +4026,11 @@ static int CmdT55xxSniff(const char *Cmd) {
// setup and sample data from Proxmark
// if not directed to existing sample/graphbuffer
if (use_graphbuf == false) {
// make loop to call sniff with skip samples..
// then build it up by adding
CmdLFSniff("");
}
// Headings

View file

@ -30,6 +30,8 @@
#include "cmdhftopaz.h"
#include "cmdnfc.h"
#include "fileutils.h"
#include "mifare/mifaredefault.h"
#include "mifare/mad.h"
void print_type4_cc_info(uint8_t *d, uint8_t n) {
if (n < 0x0F) {
@ -111,6 +113,22 @@ static int CmdNfcDecode(const char *Cmd) {
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);
if (res != PM3_SUCCESS) {
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;
} else if (str_endswith(s, "dic")) {
o = DICTIONARY;
} else if (str_endswith(s, "mct")) {
o = MCT;
} else {
// mfd, trc, trace is binary
o = BIN;
@ -112,27 +114,6 @@ int fileExists(const char *filename) {
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.
* @param filename
@ -152,68 +133,6 @@ static bool is_directory(const char *filename) {
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) {
if (pathIndex < spItemCount) {
@ -262,37 +181,55 @@ static size_t path_size(savePaths_t a) {
}
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) {
return NULL;
}
uint16_t p_namelen = strlen(preferredName);
if (str_endswith(preferredName, suffix))
if (str_endswith(preferredName, suffix)) {
p_namelen -= strlen(suffix);
}
// 10: room for filenum to ensure new filename
const size_t len = p_namelen + strlen(suffix) + 1 + 10;
int save_path_len = path_size(e_save_path);
int foobar = path_size(spDefault);
(void) foobar;
// 1: null terminator
// 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));
if (fileName == 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;
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)) {
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++;
}
PrintAndLogEx(INFO, "FILE PATH: %s", fileName);
return fileName;
}
// --------- SAVE FILES
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
if (data == NULL || datalen == 0) {
@ -321,13 +258,14 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
return PM3_SUCCESS;
}
// dump file
int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".eml");
char *fileName = newfilenamemcopyEx(preferredName, ".eml", spDump);
if (fileName == NULL) {
return PM3_EMALLOC;
}
@ -371,16 +309,19 @@ out:
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 *)) {
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) {
return PM3_EINVARG;
}
}
char *fileName = newfilenamemcopy(preferredName, ".json");
char *fileName = newfilenamemcopyEx(preferredName, ".json", e_save_path);
if (fileName == NULL) {
return PM3_EMALLOC;
}
@ -719,7 +660,7 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
if (overwrite)
filename = filenamemcopy(preferredName, ".json");
else
filename = newfilenamemcopy(preferredName, ".json");
filename = newfilenamemcopyEx(preferredName, ".json", spDump);
if (filename == NULL)
return PM3_EMALLOC;
@ -739,13 +680,14 @@ int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool
return PM3_EFILE;
}
// wave file of trace,
int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) {
if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".wav");
char *fileName = newfilenamemcopyEx(preferredName, ".wav", spTrace);
if (fileName == NULL) {
return PM3_EMALLOC;
}
@ -791,13 +733,14 @@ out:
return retval;
}
// Signal trace file, PM3
int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
if (data == NULL || datalen == 0) {
return PM3_EINVARG;
}
char *fileName = newfilenamemcopy(preferredName, ".pm3");
char *fileName = newfilenamemcopyEx(preferredName, ".pm3", spTrace);
if (fileName == NULL) {
return PM3_EMALLOC;
}
@ -824,11 +767,12 @@ out:
return retval;
}
// key file dump
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) {
if (e_sector == NULL) return PM3_EINVARG;
char *fileName = newfilenamemcopy(preferredName, ".bin");
char *fileName = newfilenamemcopyEx(preferredName, ".bin", spDump);
if (fileName == NULL) return PM3_EMALLOC;
FILE *f = fopen(fileName, "wb");
@ -866,66 +810,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
return PM3_SUCCESS;
}
int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) {
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;
}
// --------- LOAD FILES
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen) {
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;
if (verbose)
if (verbose) {
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
}
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) {
char *path;
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;
}
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 *)) {
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) {
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
char *filename = calloc(strlen(searchname) + 1, sizeof(char));
if (filename == NULL) return PM3_EMALLOC;
if (filename == NULL) {
return PM3_EMALLOC;
}
strcpy(filename, searchname);
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", filename);
PrintAndLogEx(INFO, "pm3dir...... %s", pm3dir);
PrintAndLogEx(INFO, "Searching... %s", filename);
}
if (((strlen(filename) > 1) && (filename[0] == '/')) ||
((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
// 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] == '/')) ||
((strlen(filename) > 2) && (filename[0] == '.') && (filename[1] == '/'))) {
goto out;
}
// 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)) {
PrintAndLogEx(INFO, "Found %s", *foundpath);
}
return PM3_SUCCESS;
} 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)
PrintAndLogEx(DEBUG, "Searching user .proxmark3 paths");
const char *user_path = get_my_user_directory();
if (user_path != NULL) {
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;
}
strcpy(path, user_path);
strcat(path, PM3_USER_DIRECTORY);
strcat(path, pm3dir);
strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path);
}
if (fileExists(path)) {
free(filename);
*foundpath = path;
@ -1959,7 +1904,9 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path);
}
}
// try pm3 dirs in current client workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching current workdir paths");
const char *exec_path = get_my_executable_directory();
if ((exec_path != NULL) &&
((strcmp(DICTIONARIES_SUBDIR, pm3dir) == 0) ||
@ -1992,23 +1939,28 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path);
}
}
// try pm3 dirs in current repo workdir (dev mode)
PrintAndLogEx(DEBUG, "Searching PM3 dirs in current workdir");
if ((exec_path != NULL) &&
((strcmp(TRACES_SUBDIR, pm3dir) == 0) ||
(strcmp(FIRMWARES_SUBDIR, pm3dir) == 0) ||
(strcmp(BOOTROM_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));
if (path == NULL)
char *path = calloc(strlen(exec_path) + strlen(ABOVE) + strlen(pm3dir) + strlen(filename) + 1, sizeof(char));
if (path == NULL) {
goto out;
}
strcpy(path, exec_path);
strcat(path, above);
strcat(path, ABOVE);
strcat(path, pm3dir);
strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path);
}
if (fileExists(path)) {
free(filename);
*foundpath = path;
@ -2020,18 +1972,24 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea
free(path);
}
}
// try pm3 dirs in pm3 installation dir (install mode)
PrintAndLogEx(DEBUG, "Searching PM3 installation dir paths");
if (exec_path != NULL) {
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;
}
strcpy(path, exec_path);
strcat(path, PM3_SHARE_RELPATH);
strcat(path, pm3dir);
strcat(path, filename);
if ((g_debugMode == 2) && (!silent)) {
PrintAndLogEx(INFO, "Searching %s", path);
}
if (fileExists(path)) {
free(filename);
*foundpath = path;
@ -2067,15 +2025,15 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con
free(filename);
return PM3_EFILE;
}
int res = searchFinalFile(foundpath, pm3dir, filename, silent);
if (res != PM3_SUCCESS) {
if ((res == PM3_EFILE) && (!silent))
if ((res == PM3_EFILE) && (!silent)) {
PrintAndLogEx(FAILED, "Error - can't find `" _YELLOW_("%s") "`", filename);
free(filename);
return res;
}
}
free(filename);
return PM3_SUCCESS;
return res;
}
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");
return PM3_EINVARG;
}
case MCT: {
res = loadFileMCT_safe(fn, pdump, dumplen);
break;
}
}
if (res != PM3_SUCCESS) {

View file

@ -56,15 +56,16 @@ typedef enum {
EML,
JSON,
DICTIONARY,
MCT,
} DumpFileType_t;
int fileExists(const char *filename);
//bool create_path(const char *dirname);
// set a path in the path list g_session.defaultPaths
bool setDefaultPath(savePaths_t pathIndex, const char *path);
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
@ -104,7 +105,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
* @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 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 saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite);
/** 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);
/**
* @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.
* 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
* @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);
/**
* @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.
* 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) {
if (vi->magic != VERSION_INFORMATION_MAGIC)
if (vi->magic != VERSION_INFORMATION_MAGIC) {
return PM3_EFILE;
}
char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image
FormatVersionInformation(temp, sizeof(temp), "", vi);
PrintAndLogEx(SUCCESS, _CYAN_("ELF file version") _YELLOW_(" %s"), temp);
if (strlen(g_version_information.armsrc) == 9) {
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"));

View file

@ -421,3 +421,51 @@ int DetectHID(uint8_t *d, uint16_t manufacture) {
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);
bool HasMADKey(uint8_t *d);
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_

View file

@ -24,12 +24,55 @@
#define MFKEY_SIZE 6
#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[] = {
0xffffffffffff, // Default key (first key used by program if no user defined key)
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key
0xd3f7d3f7d3f7, // NDEF public key
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,
0xaabbccddeeff,
0x1a2b3c4d5e6f,
@ -47,29 +90,6 @@ static const uint64_t g_mifare_default_keys[] = {
0x0000014b5c31,
0xb578f38a5c61,
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};

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] = {0x04, 0x03, 0x02, 0x01, 0x04, 0x08, 0x04, 0x00, 0x64, 0xB9, 0x95, 0x11, 0x4D, 0x20, 0x42, 0x09};
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;
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) {
memcpy(out, in, MFBLOCK_SIZE);
out += MFBLOCK_SIZE;
*olen += MFBLOCK_SIZE;
}
blockno++;
out += MFBLOCK_SIZE;
in += MFBLOCK_SIZE;
ilen -= MFBLOCK_SIZE;
*olen += MFBLOCK_SIZE;
}
return PM3_SUCCESS;
}

View file

@ -39,8 +39,6 @@
#define NDEF_VCARDTEXT "text/vcard"
#define NDEF_XVCARDTEXT "text/x-vcard"
static const char *TypeNameFormat_s[] = {
"Empty 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) {
size_t indx = 1;
size_t indx = 1;
uint8_t sigType = sig[indx] & 0x7f;
bool sigURI = sig[indx] & 0x80;
indx++;
PrintAndLogEx(SUCCESS, "\tsignature type: %s", ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA]));
PrintAndLogEx(SUCCESS, "\tsignature uri: %s", (sigURI ? "present" : "not present"));
PrintAndLogEx(SUCCESS, "\tType...... " _YELLOW_("%s"), ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA]));
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
if (sigType == stECDSA_P192 || sigType == stECDSA_P256) {
indx += 3;
int slen = 24;
if (sigType == stECDSA_P256)
if (sigType == stECDSA_P256) {
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 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\ts: %s", sprint_hex(sval + 32 - slen, slen));
}
} else {
PrintAndLogEx(SUCCESS, "\tData [%u]...", intsiglen);
print_hex_noascii_break(&sig[indx], intsiglen, 32);
}
indx += intsiglen;
if (sigURI) {
size_t intsigurilen = (sig[indx] << 8) + sig[indx + 1];
uint16_t intsigurilen = MemBeToUint2byte(sig + indx);
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;
}
// CERTIFICATE SECTION
PrintAndLogEx(INFO, "");
PrintAndLogEx(INFO, _CYAN_("Certificate"));
uint8_t certFormat = (sig[indx] >> 4) & 0x07;
uint8_t certCount = sig[indx] & 0x0f;
bool certURI = sig[indx] & 0x80;
indx++;
PrintAndLogEx(SUCCESS, "\tcertificate format: %s", ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA]));
PrintAndLogEx(SUCCESS, "\tcertificates count: %d", certCount);
PrintAndLogEx(SUCCESS, "\tFormat............ " _YELLOW_("%s"), ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA]));
if (certCount) {
PrintAndLogEx(SUCCESS, "\tNum of certs#..... " _YELLOW_("%d"), certCount);
}
// print certificates
indx++;
for (int i = 0; i < certCount; i++) {
size_t intcertlen = (sig[indx + 1] << 8) + sig[indx + 2];
for (uint8_t i = 0; i < certCount; i++) {
uint16_t intcertlen = MemBeToUint2byte(sig + indx);
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;
}
// have certificate uri
// print certificate uri
if ((indx <= siglen) && certURI) {
size_t inturilen = (sig[indx] << 8) + sig[indx + 1];
uint16_t inturilen = MemBeToUint2byte(sig + indx);
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;
@ -417,9 +443,9 @@ static int ndefDecodeSig2(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) {
PrintAndLogEx(ERR, "signature version unknown.");
PrintAndLogEx(ERR, _RED_("Version unknown"));
return PM3_ESOFT;
}
@ -473,6 +499,51 @@ static int ndefDecodePayloadDeviceInfo(uint8_t *payload, size_t len) {
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) {
if (print) {
PrintAndLogEx(INFO, _YELLOW_("Well Known Record - Smartposter {"));
@ -789,9 +860,13 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
return PM3_SUCCESS;
}
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, "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
switch (ndef->Payload[8]) {
case 0x02:
@ -828,6 +903,38 @@ static int ndefDecodeMime_bt(NDEFHeader_t *ndef) {
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) {
PrintAndLogEx(INFO, "");
@ -835,7 +942,7 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
case tnfEmptyRecord:
PrintAndLogEx(INFO, "Empty Record");
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;
@ -884,13 +991,11 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
}
if (!strncmp((char *)ndef->Type, "Hr", ndef->TypeLen)) {
PrintAndLogEx(INFO, _CYAN_("Handover request"));
PrintAndLogEx(INFO, "- decoder to be impl -");
ndefDecodePayloadHandoverRequest(ndef->Payload, ndef->PayloadLen);
}
if (!strncmp((char *)ndef->Type, "Hs", ndef->TypeLen)) {
PrintAndLogEx(INFO, _CYAN_("Handover select"));
PrintAndLogEx(INFO, "- decoder to be impl -");
ndefDecodePayloadHandoverSelect(ndef->Payload, ndef->PayloadLen);
}
if (!strncmp((char *)ndef->Type, "ac", ndef->TypeLen)) {
@ -931,20 +1036,33 @@ static int ndefDecodePayload(NDEFHeader_t *ndef, bool verbose) {
}
case tnfAbsoluteURIRecord:
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;
case tnfExternalRecord:
PrintAndLogEx(INFO, "External Record");
PrintAndLogEx(INFO, "- decoder to be impl -");
ndefDecodeExternal_record(ndef);
break;
case tnfUnknownRecord:
PrintAndLogEx(INFO, "Unknown Record");
PrintAndLogEx(INFO, "- decoder to be impl -");
if (ndef->TypeLen != 0) {
PrintAndLogEx(FAILED, "unexpected type field");
break;
}
break;
case tnfUnchangedRecord:
PrintAndLogEx(INFO, "Unchanged Record");
PrintAndLogEx(INFO, "- decoder to be impl -");
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, "");
return PM3_SUCCESS;

View file

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

View file

@ -122,17 +122,18 @@ int preferences_save(void) {
PrintAndLogEx(INFO, "Saving preferences...");
char *fn = prefGetFilename();
int fnLen = strlen(fn) + 5; // .bak\0
int fn_len = strlen(fn) + 5; // .bak\0
// [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) {
PrintAndLogEx(ERR, "failed to allocate memory");
free(fn);
return PM3_EMALLOC;
}
snprintf(backupFilename, fnLen, "%s.bak", fn);
snprintf(backupFilename, fn_len, "%s.bak", fn);
// remove old backup file
if (fileExists(backupFilename)) {
if (remove(backupFilename) != 0) {
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 (rename(fn, backupFilename) != 0) {
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;
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);
}
free(fn);
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",
"description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn",
"notes": [
"hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337",
"hf iclass encode --fc 31 --cn 337 --ki 0 -> FC 31 CN 337",
"hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337, writing w elite key"
"hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)",
"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 (H10301), writing w elite key"
],
"offline": true,
"options": [

View file

@ -2,7 +2,6 @@
<a id="Top"></a>
# 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
- [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.
* MacPorts may require a bit more setup. You first need to set up your PATH variable:
```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
## Installing stable releases directly
^[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.
## Build from source
^[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.
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:
```
sudo port install readline qt5 qt5-qtbase pkgconfig arm-none-eabi-gcc arm-none-eabi-binutils lua52 coreutils openssl@3
```bash
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
MacPorts doesn't handle Python version defaults when it comes to pkg-config. So even if you have done:
```
sudo port install python39 cython39
```bash
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 python3 python39
sudo port select --set cython cython39
sudo port select --set python python311 # this also makes calls to "python" operate on python3.11
sudo port select --set python3 python311
sudo port select --set cython cython311
```
This won't set a default python3.pc (and python3-embed.pc) under the MacPorts pkgconfig includes folder.
To fix that, follow these steps:
```
```bash
cd /opt/local/lib/pkgconfig
sudo ln -svf python3.pc python-3.9.pc
sudo ln -svf python3-embed.pc python-3.9-embed.pc
sudo ln -svf python3.pc python-3.11.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:
```
sudo port install recode
sudo port install astyle
```bash
sudo port install recode 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).
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.
@ -125,4 +136,3 @@ If you want to manually select serial port, remember that the Proxmark3 port is
```sh
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_HIDFCBRUTE | LF HID facility code bruteforce - ss23
| 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_NEXID | Nexwatch credentials detection mode - jrjgjk & Zolorah
| 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 curbit;
`define EDGE_DETECT_THRESHOLD 5
`define EDGE_DETECT_THRESHOLD 3
`define EDGE_DETECT_THRESHOLDHIGH 20
always @(negedge adc_clk)
begin
if(negedge_cnt[3:0] == mod_detect_reset_time)
begin
if (mod_type == `FPGA_HF_ISO14443A_SNIFFER)
begin
// detect modulation signal: if modulating, there must have been a falling AND a rising edge
if ((rx_mod_falling_edge_max > `EDGE_DETECT_THRESHOLDHIGH) && (rx_mod_rising_edge_max < -`EDGE_DETECT_THRESHOLDHIGH))
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
rx_mod_rising_edge_max <= 0;
rx_mod_falling_edge_max <= 0;

View file

@ -22,8 +22,7 @@ echo "Destination: ${DEST:=firmware}"
echo "Produce stats?: ${STATS:=false}"
# 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
chmod 644 bootrom/obj/bootrom.elf
@ -32,7 +31,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf"
# cf armsrc/Standalone/Makefile.hal
STANDALONE_MODES=(LF_SKELETON)
STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_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+=(DANKARMULTI)
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 - 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 - signature" "$CLIENTBIN -c 'nfc decode -d 03FF010194113870696C65742E65653A656B616172743A3266195F26063132303832325904202020205F28033233335F2701316E1B5A13333038363439303039303030323636343030355304EBF2CE704103000000AC536967010200803A2448FCA7D354A654A81BD021150D1A152D1DF4D7A55D2B771F12F094EAB6E5E10F2617A2F8DAD4FD38AFF8EA39B71C19BD42618CDA86EE7E144636C8E0E7CFC4096E19C3680E09C78A0CDBC05DA2D698E551D5D709717655E56FE3676880B897D2C70DF5F06ECE07C71435255144F8EE41AF110E7B180DA0E6C22FB8FDEF61800025687474703A2F2F70696C65742E65652F6372742F33303836343930302D303030312E637274FE'" "30864900-0001.crt"; then break; fi
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