1 //-----------------------------------------------------------------------------
2 // Copyright (C) A. Ozkal, 2020
3 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // See LICENSE.txt for the text of the license.
16 //-----------------------------------------------------------------------------
17 // main code for HF Mifare Ultralight read/simulation by Ave Ozkal
18 //-----------------------------------------------------------------------------
20 // Several parts of this code is based on code by Craig Young from HF_YOUNG
22 // This code does not:
23 // - Account for cards with non-default keys on authentication (MFU EV1 etc)
25 // This code is designed to work with:
26 // - MIFARE Ultralight
27 // - MIFARE Ultralight EV1 (default keys)
28 // - MIFARE Ultralight Nano (untested, but should work)
29 // - Infineon My-d Move (without password set)
30 // - Infineon My-d Move Lean
31 // - Any other Ultralight clones that have no auth and MAX_DEFAULT_BLOCKS (16) blocks
33 #include "standalone.h" // standalone definitions
34 #include "proxmark3_arm.h"
36 #include "fpgaloader.h"
40 #include "ticks.h" // SpinDelay
41 #include "protocols.h" // MIFARE_ULEV1_VERSION, MIFARE_ULEV1_READSIG, MIFARE_ULEV1_READ_CNT, MIFARE_ULEV1_CHECKTEAR
42 #include <string.h> // memcmp
43 #include "mifareutil.h"
44 #include "iso14443a.h"
50 #define STATE_SEARCH 0
54 // Taken from cmdhfmfu.c, increased by 01h to be 1 indexed
55 #define MAX_UL_BLOCKS 0x10
56 #define MAX_UL_NANO_40 0x0B
57 #define MAX_ULEV1a_BLOCKS 0x14
58 #define MAX_ULEV1b_BLOCKS 0x29
59 #define MAX_MY_D_MOVE 0x26
60 #define MAX_MY_D_MOVE_LEAN 0x10
61 #define MAX_DEFAULT_BLOCKS 0x10
68 } PACKED card_clone_t
;
70 int get_block_count(iso14a_card_select_t card
, uint8_t *version
, uint16_t version_len
);
71 uint16_t get_ev1_version(iso14a_card_select_t card
, uint8_t *version
, uint16_t version_len
);
72 uint16_t get_ev1_signature(iso14a_card_select_t card
, uint8_t *signature
, uint16_t sign_len
);
73 uint16_t get_ev1_counter(iso14a_card_select_t card
, uint8_t counter
, uint8_t *response
, uint16_t resp_len
);
74 uint16_t get_ev1_tearing(iso14a_card_select_t card
, uint8_t counter
, uint8_t *response
, uint16_t resp_len
);
76 uint16_t get_ev1_version(iso14a_card_select_t card
, uint8_t *version
, uint16_t version_len
) {
77 return mifare_sendcmd(MIFARE_ULEV1_VERSION
, NULL
, 0, version
, version_len
, NULL
, NULL
);
80 uint16_t get_ev1_signature(iso14a_card_select_t card
, uint8_t *signature
, uint16_t sign_len
) {
81 uint8_t cmd
[4] = {MIFARE_ULEV1_READSIG
, 0x00, 0x00, 0x00};
83 ReaderTransmit(cmd
, sizeof(cmd
), NULL
);
84 return ReaderReceive(signature
, sign_len
, NULL
);
87 uint16_t get_ev1_counter(iso14a_card_select_t card
, uint8_t counter
, uint8_t *response
, uint16_t resp_len
) {
88 uint8_t cmd
[4] = {MIFARE_ULEV1_READ_CNT
, counter
, 0x00, 0x00};
90 ReaderTransmit(cmd
, sizeof(cmd
), NULL
);
91 return ReaderReceive(response
, resp_len
, NULL
);
94 uint16_t get_ev1_tearing(iso14a_card_select_t card
, uint8_t counter
, uint8_t *response
, uint16_t resp_len
) {
95 uint8_t cmd
[4] = {MIFARE_ULEV1_CHECKTEAR
, counter
, 0x00, 0x00};
97 ReaderTransmit(cmd
, sizeof(cmd
), NULL
);
98 return ReaderReceive(response
, resp_len
, NULL
);
101 int get_block_count(iso14a_card_select_t card
, uint8_t *version
, uint16_t version_len
) {
102 // Default to MAX_DEFAULT_BLOCKS blocks
103 int block_count
= MAX_DEFAULT_BLOCKS
;
104 // Most of this code is from cmdhfmfu.c
105 // Infineon manufacturer ID
106 if (card
.uid
[0] == 0x05) {
107 // Infinition MY-D tests Exam high nibble
108 uint8_t nib
= (card
.uid
[1] & 0xf0) >> 4;
111 block_count
= MAX_MY_D_MOVE
;
112 break; // or SLE 66R01P // 38 pages of 4 bytes
114 block_count
= MAX_MY_D_MOVE_LEAN
;
115 break; // or SLE 66R01L // 16 pages of 4 bytes
118 // Moved this from case to if as I only care about non-ultralight ev0.
119 if (version_len
== 0x0A) {
120 if (memcmp(version
, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { block_count
= MAX_ULEV1a_BLOCKS
; }
121 else if (memcmp(version
, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { block_count
= MAX_UL_NANO_40
; }
122 else if (memcmp(version
, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { block_count
= MAX_ULEV1a_BLOCKS
; }
123 else if (memcmp(version
, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { block_count
= MAX_ULEV1b_BLOCKS
; }
124 else if (memcmp(version
, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { block_count
= MAX_ULEV1b_BLOCKS
; }
125 else if (memcmp(version
, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count
= MAX_ULEV1b_BLOCKS
; } // Mikron JSC Russia EV1 41 pages tag
126 else if (version
[2] == 0x03) { block_count
= MAX_ULEV1a_BLOCKS
; }
134 DbpString(" HF Mifare Ultralight read/simulation by Ave Ozkal");
139 Dbprintf("AveFUL (MF Ultralight read/emul) started");
140 FpgaDownloadAndGo(FPGA_BITSTREAM_HF
);
142 // the main loop for your standalone mode
146 // exit from RunMod, send a usbcommand.
147 if (data_available()) break;
149 iso14a_card_select_t card
;
152 iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD
);
154 // 0 = search, 1 = read, 2 = emul
155 int state
= STATE_SEARCH
;
157 DbpString("Scanning...");
158 int button_pressed
= BUTTON_NO_CLICK
;
160 // Was our button held down or pressed?
161 button_pressed
= BUTTON_HELD(1000);
163 if (button_pressed
!= BUTTON_NO_CLICK
|| data_available())
165 else if (state
== STATE_SEARCH
) {
166 if (!iso14443a_select_card(NULL
, &card
, NULL
, true, 0, true)) {
167 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
);
172 if (card
.sak
== SAK
&& card
.atqa
[0] == ATQA0
&& card
.atqa
[1] == ATQA1
&& card
.uidlen
== 7) {
173 DbpString("Found ultralight with UID: ");
174 Dbhexdump(card
.uidlen
, card
.uid
, 0);
177 DbpString("Found non-ultralight card, ignoring.");
180 } else if (state
== STATE_READ
) {
181 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN
);
182 iso14443a_select_card(NULL
, NULL
, NULL
, true, 0, true);
183 bool read_successful
= true;
185 // Get version and re-select card as UL EV0s like to shut off after a 0x60
186 uint8_t version
[10] = {0x00};
187 uint16_t version_len
= 0;
188 version_len
= get_ev1_version(card
, version
, sizeof(version
));
189 iso14443a_select_card(NULL
, NULL
, NULL
, true, 0, true);
191 int block_count
= get_block_count(card
, version
, version_len
);
192 Dbprintf("Card was determined as having %d blocks.", block_count
);
193 Dbprintf("Contents:");
195 for (int i
= 0; i
< block_count
; i
++) {
196 uint8_t dataout
[16] = {0x00};
197 if (mifare_ultra_readblock(i
, dataout
)) {
198 // If there's an error reading, go back to search state
199 read_successful
= false;
202 // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on data_mfu_bin2eml
203 // When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00.
204 emlSetMem_xt(dataout
, 14 + i
, 1, 4);
205 Dbhexdump(4, dataout
, 0);
208 // It's not the best way to determine this,
209 // but with what I'm trying to support It Should Be Okay
210 bool is_ev1
= (version_len
!= 0) && (block_count
!= 16);
212 if (read_successful
) {
213 uint8_t signature
[34] = {0x00};
215 get_ev1_signature(card
, signature
, sizeof(signature
));
217 Dbprintf("Preparing emulator memory with:");
218 // Fill first 14 blocks with 0x00 (see comment above)
219 for (int i
= 0; i
< 14; i
++) {
220 uint8_t dataout
[4] = {0x00, 0x00, 0x00, 0x00};
222 if (is_ev1
&& (i
== 0 || i
== 1)) {
223 // On block 0 and 1, set version on EV1
224 memcpy(dataout
, version
+ (i
* 4), 4);
226 // On block 2, set last byte to the card's block count
227 dataout
[3] = block_count
;
228 } else if (is_ev1
&& ((i
> 2 && i
< 11))) {
229 // On 3-10 add signature on EV1
230 memcpy(dataout
, signature
+ ((i
- 3) * 4), 4);
231 } else if (is_ev1
&& (i
> 10)) {
232 // On 11-14 read and set counter and tearing on EV1
235 get_ev1_counter(card
, i
- 11, counter
, sizeof(counter
));
236 get_ev1_tearing(card
, i
- 11, tearing
, sizeof(tearing
));
237 memcpy(dataout
, counter
, 3);
238 memcpy(dataout
+ 3, tearing
, 1);
241 Dbhexdump(4, dataout
, 0);
242 emlSetMem_xt(dataout
, i
, 1, 4);
244 Dbprintf("Successfully loaded into emulator memory...");
247 Dbprintf("Read failure, going back to search state.");
248 state
= STATE_SEARCH
;
250 } else if (state
== STATE_EMUL
) {
252 FLAG_SET_UID_IN_DATA(flags
, 7);
254 Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
255 SimulateIso14443aTag(7, flags
, card
.uid
, 0, NULL
, 0);
257 // Go back to search state if user presses pm3-button
258 state
= STATE_SEARCH
;
261 if (button_pressed
== BUTTON_HOLD
) //Holding down the button
265 DbpString("exiting");