mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
Merge branch 'RfidResearchGroup:master' into master
This commit is contained in:
commit
ef74541b28
44 changed files with 1356 additions and 641 deletions
2
.github/workflows/rebase.yml
vendored
2
.github/workflows/rebase.yml
vendored
|
@ -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 }}
|
||||
|
|
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
76
armsrc/Standalone/lf_multihid.c
Normal file
76
armsrc/Standalone/lf_multihid.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
112
client/pyscripts/pm3_nfc2eml.py
Executable 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
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -31,7 +31,8 @@ typedef enum {
|
|||
tnfAbsoluteURIRecord = 0x03,
|
||||
tnfExternalRecord = 0x04,
|
||||
tnfUnknownRecord = 0x05,
|
||||
tnfUnchangedRecord = 0x06
|
||||
tnfUnchangedRecord = 0x06,
|
||||
tnfReservedRecord = 0x07,
|
||||
} TypeNameFormat_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -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);
|
||||
|
|
114
client/update_amiibo_tools_lua.py
Normal file
114
client/update_amiibo_tools_lua.py
Normal 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()
|
|
@ -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": [
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
||||
|
|
|
@ -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.
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue