Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into function/desfire-standalone

This commit is contained in:
Anže Jenšterle 2021-03-13 02:16:26 +01:00
commit 180577695e
67 changed files with 2957 additions and 1897 deletions

View file

@ -251,7 +251,7 @@ print-%: ; @echo $* = $($*)
cliparser:
# Get list of all commands
cat doc/commands.md | grep -e ^\|\` | cut -f 2 -d "\`" | grep -v 'help\|list\|mem spiffs\|quit\|exit' | awk '{$$1=$$1};1' > cliparser_all_commands.tmp
cat doc/commands.md | grep -e ^\|\` | cut -f 2 -d "\`" | grep -v 'help\|list\|script run\|quit\|exit' | awk '{$$1=$$1};1' > cliparser_all_commands.tmp
# Get list of cliparserized commands
grep -r CLIParserInit ./client/src/ | cut -f 2 -d "\"" | awk '{$$1=$$1};1' > cliparser_done.tmp
# Determine commands that still need cliparser conversion

View file

@ -18,13 +18,13 @@
| ------------------- |:-------------------:| -------------------:|
|[What has changed?](#what-has-changed) | **[Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md)** | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|[Development](#development) | **[Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md)** | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|[Proxmark3 GUI](#proxmark3-gui)|**[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)**|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) ||
|[Donations](#Donations)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)|
||[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
||**[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)**|[Complete client command set](/doc/commands.md)|
||**[JTAG](/doc/jtag_notes.md)**|[T55xx Guide](/doc/T5577_Guide.md)|
||**[JTAG](/doc/jtag_notes.md)**|[T5577 Introduction Guide](/doc/T5577_Guide.md)|
## Notes / helpful documents
@ -154,10 +154,6 @@ To all distro, package maintainers, we tried to make your life easier.
`make install` is now available and if you want to know more.
- [Notes for maintainers](/doc/md/Development/Maintainers.md)
## Why didn't you base it on official Proxmark3 Master?
The separation from official Proxmark3 repo gives us a lot of freedom to create a firmware/client that suits the RDV40 features. We don't want to mess up the official Proxmark3 repo with RDV40 specific code.
## Proxmark3 GUI
The official PM3-GUI from Gaucho will not work. Not to mention is quite old and not maintained any longer.

View file

@ -71,13 +71,13 @@
static void DownloadTraceInstructions(void) {
Dbprintf("");
Dbprintf("To get the trace from flash and display it:");
Dbprintf("1. mem spiffs dump o "HF_14ASNIFF_LOGFILE" f trace.trc");
Dbprintf("2. trace load trace.trc");
Dbprintf("3. trace list 14a 1");
Dbprintf("1. mem spiffs dump -s "HF_14ASNIFF_LOGFILE" -d trace.trc");
Dbprintf("2. trace load -f trace.trc");
Dbprintf("3. trace list -t 14a -1");
}
void ModInfo(void) {
DbpString("hf_14asniff: standalone 'hf 14a sniff', storing in flashmem");
DbpString(" ISO14443a sniff, storing in flashmem");
DownloadTraceInstructions();
}

View file

@ -130,27 +130,27 @@ static void download_instructions(uint8_t t) {
switch (t) {
case ICE_STATE_FULLSIM: {
DbpString("The emulator memory was saved to SPIFFS");
DbpString("1. " _YELLOW_("mem spiffs dump o " HF_ICLASS_FULLSIM_MOD_BIN " f " HF_ICLASS_FULLSIM_MOD" e"));
DbpString("1. " _YELLOW_("mem spiffs dump -s " HF_ICLASS_FULLSIM_MOD_BIN " -d " HF_ICLASS_FULLSIM_MOD" -e"));
DbpString("2. " _YELLOW_("hf iclass view -f " HF_ICLASS_FULLSIM_MOD_BIN));
break;
}
case ICE_STATE_ATTACK: {
DbpString("The collected data was saved to SPIFFS. The file names below may differ");
DbpString("1. " _YELLOW_("mem spiffs tree"));
DbpString("2. " _YELLOW_("mem spiffs dump o " HF_ICLASS_ATTACK_BIN " f " HF_ICLASS_ATTACK_BIN));
DbpString("2. " _YELLOW_("mem spiffs dump -s " HF_ICLASS_ATTACK_BIN " -d " HF_ICLASS_ATTACK_BIN));
DbpString("3. " _YELLOW_("hf iclass loclass -f " HF_ICLASS_ATTACK_BIN));
break;
}
case ICE_STATE_READER: {
DbpString("The found tags was saved to SPIFFS");
DbpString("1. " _YELLOW_("mem spiffs tree"));
DbpString("2. " _YELLOW_("mem spiffs dump h"));
DbpString("2. " _YELLOW_("mem spiffs dump -h"));
break;
}
case ICE_STATE_DUMP_SIM: {
DbpString("The found tag will be dumped to " HF_ICALSSS_READSIM_TEMP_BIN);
DbpString("1. " _YELLOW_("mem spiffs tree"));
DbpString("2. " _YELLOW_("mem spiffs dump h"));
DbpString("2. " _YELLOW_("mem spiffs dump -h"));
break;
}
}

View file

@ -39,7 +39,7 @@
*
* To delete a dump file from flash:
*
* 1. mem spiffs remove hf-legic-XXYYZZWW-dump.bin
* 1. mem spiffs remove -f hf-legic-XXYYZZWW-dump.bin
*
*/
@ -50,7 +50,7 @@ static void DownloadLogInstructions(void) {
Dbprintf("[=] " _YELLOW_("-") " mem spiffs tree");
Dbprintf("");
Dbprintf("[=] To save a dump file from flash to client:");
Dbprintf("[=] " _YELLOW_("-") " mem spiffs dump o hf-legic-UID-dump.bin f hf-legic-UID-dump.bin");
Dbprintf("[=] " _YELLOW_("-") " mem spiffs dump -s hf-legic-UID-dump.bin -d hf-legic-UID-dump.bin");
}
#endif

View file

@ -36,7 +36,7 @@
*
* To retrieve log file from flash:
*
* 1. mem spiffs dump o lf_hidcollect.log f lf_hidcollect.log
* 1. mem spiffs dump -s lf_hidcollect.log -d lf_hidcollect.log
* Copies log file from flash to your client.
*
* 2. exit the Proxmark3 client
@ -48,7 +48,7 @@
*
* To delete the log file from flash:
*
* 1. mem spiffs remove lf_hidcollect.log
* 1. mem spiffs remove -f lf_hidcollect.log
*/
#define LF_HIDCOLLECT_LOGFILE "lf_hidcollect.log"
@ -57,7 +57,7 @@
static void DownloadLogInstructions(void) {
Dbprintf("");
Dbprintf("[=] To get the logfile from flash and display it:");
Dbprintf("[=] " _YELLOW_("1.") " mem spiffs dump o "LF_HIDCOLLECT_LOGFILE" f "LF_HIDCOLLECT_LOGFILE);
Dbprintf("[=] " _YELLOW_("1.") " mem spiffs dump -s "LF_HIDCOLLECT_LOGFILE" -d "LF_HIDCOLLECT_LOGFILE);
Dbprintf("[=] " _YELLOW_("2.") " exit proxmark3 client");
Dbprintf("[=] " _YELLOW_("3.") " cat "LF_HIDCOLLECT_LOGFILE);
}

View file

@ -42,25 +42,25 @@
* - LED D: unmounting/sync'ing flash (normally < 100ms)
*
* To upload input file (eml format) to flash:
* - mem spiffs load f <filename> o lf_em4x50_simulate.eml
* - mem spiffs upload -s <filename> -d lf_em4x50_simulate.eml
*
* To retrieve password file from flash:
* - mem spiffs dump o lf_em4x50_passwords.log f <filename>
* - mem spiffs dump -s lf_em4x50_passwords.log
*
* To retrieve log file from flash:
* - mem spiffs dump o lf_em4x50_collect.log f <filename>
* - mem spiffs dump -s lf_em4x50_collect.log
*
* This module emits debug strings during normal operation -- so try it out in
* the lab connected to PM3 client before taking it into the field.
*
* To delete the input file from flash:
* - mem spiffs remove lf_em4x50_simulate.eml
* - mem spiffs remove -f lf_em4x50_simulate.eml
*
* To delete the log file from flash:
* - mem spiffs remove lf_em4x50_passwords.log
* - mem spiffs remove -f lf_em4x50_passwords.log
*
* To delete the log file from flash:
* - mem spiffs remove lf_em4x50_collect.log
* - mem spiffs remove -f lf_em4x50_collect.log
*/
#define STATE_SIM 0
@ -77,14 +77,14 @@ static void LoadDataInstructions(const char *inputfile) {
Dbprintf("To load datafile to flash and display it:");
Dbprintf("1. edit input file %s", inputfile);
Dbprintf("2. start proxmark3 client");
Dbprintf("3. mem spiffs load f <filename> o %s", inputfile);
Dbprintf("3. mem spiffs upload -s <filename> -d %s", inputfile);
Dbprintf("4. start standalone mode");
}
static void DownloadLogInstructions(const char *logfile) {
Dbprintf("");
Dbprintf("To get the logfile from flash and display it:");
Dbprintf("1. mem spiffs dump o %s f <filename>", logfile);
Dbprintf("1. mem spiffs dump -s %s", logfile);
Dbprintf("2. exit proxmark3 client");
Dbprintf("3. cat <filename>");
}

View file

@ -77,6 +77,7 @@ If your mode is using one of the unique features of the RDV4, add it to the prop
```
STANDALONE_MODES_REQ_SMARTCARD :=
STANDALONE_MODES_REQ_FLASH :=
STANDALONE_MODES_REQ_BT :=
```
## Update MAKEFILE.INC

View file

@ -73,8 +73,8 @@ extern uint32_t _stack_start, _stack_end;
struct common_area common_area __attribute__((section(".commonarea")));
static int button_status = BUTTON_NO_CLICK;
static bool allow_send_wtx = false;
static uint16_t tearoff_delay_us = 0;
static bool tearoff_enabled = false;
uint16_t tearoff_delay_us = 0;
bool tearoff_enabled = false;
int tearoff_hook(void) {
if (tearoff_enabled) {
@ -2078,7 +2078,7 @@ static void PacketReceived(PacketCommandNG *packet) {
Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result);
}
// Trigger a finish downloading signal with an ACK frame
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
reply_ng(CMD_SPIFFS_DOWNLOAD, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
@ -2087,78 +2087,94 @@ static void PacketReceived(PacketCommandNG *packet) {
uint8_t filename[32];
uint8_t *pfilename = packet->data.asBytes;
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs STAT : %s", filename);
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("Filename received for spiffs STAT : %s", filename);
}
int changed = rdv40_spiffs_lazy_mount();
uint32_t size = size_in_spiffs((char *)filename);
if (changed) rdv40_spiffs_lazy_unmount();
reply_mix(CMD_ACK, size, 0, 0, 0, 0);
if (changed) {
rdv40_spiffs_lazy_unmount();
}
reply_ng(CMD_SPIFFS_STAT, PM3_SUCCESS, (uint8_t *)&size, sizeof(uint32_t));
LED_B_OFF();
break;
}
case CMD_SPIFFS_REMOVE: {
LED_B_ON();
uint8_t filename[32];
uint8_t *pfilename = packet->data.asBytes;
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs REMOVE : %s", filename);
rdv40_spiffs_remove((char *) filename, RDV40_SPIFFS_SAFETY_SAFE);
struct p {
uint8_t len;
uint8_t fn[32];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("Filename received for spiffs REMOVE : %s", payload->fn);
}
rdv40_spiffs_remove((char *)payload->fn, RDV40_SPIFFS_SAFETY_SAFE);
reply_ng(CMD_SPIFFS_REMOVE, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
case CMD_SPIFFS_RENAME: {
LED_B_ON();
struct p {
uint8_t slen;
uint8_t src[32];
uint8_t dlen;
uint8_t dest[32];
uint8_t *pfilename = packet->data.asBytes;
char *token;
token = strtok((char *)pfilename, ",");
strncpy((char *)src, token, sizeof(src) - 1);
token = strtok(NULL, ",");
strncpy((char *)dest, token, sizeof(dest) - 1);
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("Filename received as source for spiffs RENAME : %s", src);
Dbprintf("Filename received as destination for spiffs RENAME : %s", dest);
Dbprintf("SPIFFS RENAME");
Dbprintf("Source........ %s", payload->src);
Dbprintf("Destination... %s", payload->dest);
}
rdv40_spiffs_rename((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE);
rdv40_spiffs_rename((char *)payload->src, (char *)payload->dest, RDV40_SPIFFS_SAFETY_SAFE);
reply_ng(CMD_SPIFFS_RENAME, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
case CMD_SPIFFS_COPY: {
LED_B_ON();
struct p {
uint8_t slen;
uint8_t src[32];
uint8_t dlen;
uint8_t dest[32];
uint8_t *pfilename = packet->data.asBytes;
char *token;
token = strtok((char *)pfilename, ",");
strncpy((char *)src, token, sizeof(src) - 1);
token = strtok(NULL, ",");
strncpy((char *)dest, token, sizeof(dest) - 1);
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("Filename received as source for spiffs COPY : %s", src);
Dbprintf("Filename received as destination for spiffs COPY : %s", dest);
Dbprintf("SPIFFS COPY");
Dbprintf("Source........ %s", payload->src);
Dbprintf("Destination... %s", payload->dest);
}
rdv40_spiffs_copy((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE);
rdv40_spiffs_copy((char *)payload->src, (char *)payload->dest, RDV40_SPIFFS_SAFETY_SAFE);
reply_ng(CMD_SPIFFS_COPY, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
case CMD_SPIFFS_WRITE: {
LED_B_ON();
uint8_t filename[32];
uint32_t append = packet->oldarg[0];
uint32_t size = packet->oldarg[1];
uint8_t *data = packet->data.asBytes;
uint8_t *pfilename = packet->data.asBytes;
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
data += SPIFFS_OBJ_NAME_LEN;
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("> Filename received for spiffs WRITE : %s with APPEND SET TO : %d", filename, append);
flashmem_write_t *payload = (flashmem_write_t *)packet->data.asBytes;
if (!append) {
rdv40_spiffs_write((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE);
} else {
rdv40_spiffs_append((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE);
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("SPIFFS WRITE, dest `%s` with APPEND set to: %c", payload->fn, payload->append ? 'Y' : 'N');
}
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
if (payload->append) {
rdv40_spiffs_append((char *) payload->fn, payload->data, payload->bytes_in_packet, RDV40_SPIFFS_SAFETY_SAFE);
} else {
rdv40_spiffs_write((char *) payload->fn, payload->data, payload->bytes_in_packet, RDV40_SPIFFS_SAFETY_SAFE);
}
reply_ng(CMD_SPIFFS_WRITE, PM3_SUCCESS, NULL, 0);
LED_B_OFF();
break;
}
@ -2202,6 +2218,10 @@ static void PacketReceived(PacketCommandNG *packet) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(3, 0xB);
} else if (startidx == FLASH_MEM_SIGNATURE_OFFSET) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(3, 0xF);
}
res = Flash_Write(startidx, data, len);

View file

@ -1881,7 +1881,7 @@ void iClass_WriteBlock(uint8_t *msg) {
iclass_send_as_reader(write, write_len, &start_time, &eof_time);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = false;
switch_off();
if (payload->req.send_reply)

View file

@ -2972,7 +2972,7 @@ void ReaderIso14443a(PacketCommandNG *c) {
}
}
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing();
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
} else {

View file

@ -2092,7 +2092,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
FpgaDisableTracing();
reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0);
} else {

View file

@ -1477,7 +1477,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
tosend_t *ts = get_tosend();
TransmitTo15693Tag(ts->buf, ts->max, &start_time);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
res = PM3_ETEAROFF;
@ -1598,7 +1598,7 @@ void ReaderIso15693(uint32_t parameter) {
uint32_t eof_time;
int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time);
if (recvlen == PM3_ETEAROFF) { // tearoff occured
if (recvlen == PM3_ETEAROFF) { // tearoff occurred
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
} else {
@ -1928,7 +1928,7 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
uint32_t start_time = 0;
int recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time);
if (recvlen == PM3_ETEAROFF) { // tearoff occured
if (recvlen == PM3_ETEAROFF) { // tearoff occurred
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
} else {

View file

@ -2639,7 +2639,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
SendForward(len, false);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
StopTicks();
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0);
} else {
@ -2681,7 +2681,7 @@ void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
SendForward(len, false);
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
StopTicks();
reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0);
} else {

View file

@ -2713,20 +2713,15 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
//
// Tear-off attack against MFU.
// - Moebius et al
void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain) {
void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *data_testwrite) {
uint8_t blockNo = blno;
uint8_t data_fullwrite[4] = {0x00};
uint8_t data_testwrite[4] = {0x00};
memcpy(data_fullwrite, datain, 4);
memcpy(data_testwrite, datain + 4, 4);
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
if (tearoff_time > 43000)
tearoff_time = 43000;
MifareUWriteBlockEx(blockNo, 0, data_fullwrite, false);
tearoff_delay_us = tearoff_time;
tearoff_enabled = true;
LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
@ -2750,15 +2745,9 @@ void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain) {
return;
};
// send
ReaderTransmit(cmd, sizeof(cmd), NULL);
// Wait before cutting power. aka tear-off
LED_D_ON();
SpinDelayUsPrecision(tearoff_time);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
switch_off();
ReaderTransmit(cmd, sizeof(cmd), NULL);
tearoff_hook();
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
}

View file

@ -208,15 +208,12 @@ static void remove_from_spiffs(const char *filename) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
}
static spiffs_stat stat_in_spiffs(const char *filename) {
spiffs_stat s;
if (SPIFFS_stat(&fs, filename, &s) < 0)
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
return s;
}
uint32_t size_in_spiffs(const char *filename) {
spiffs_stat s = stat_in_spiffs(filename);
spiffs_stat s;
if (SPIFFS_stat(&fs, filename, &s) < 0) {
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
return 0;
}
return s.size;
}

View file

@ -4639,11 +4639,13 @@ void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) {
/* print GNU style [OPTION] string */
arg_print_gnuswitch(fp, table);
size_t len = 0;
/* print remaining options in abbreviated style */
for (tabindex = 0;
table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR);
tabindex++) {
char syntax[200] = "";
char syntax[400] = "";
const char *shortopts, *longopts, *datatype;
/* skip short options without arg values (they were printed by arg_print_gnu_switch) */
@ -4681,6 +4683,12 @@ void arg_print_syntax(FILE *fp, void * *argtable, const char *suffix) {
break;
}
}
len += strlen(syntax);
if (len > 60) {
fprintf(fp, "\n ");
len = 0;
}
}
if (suffix)

View file

@ -1296,3 +1296,75 @@ ff9a84635bd2
f1a1239a4487
#
b882fd4a9f78
CD7FFFF81C4A
AA0857C641A3
C8AACD7CF3D1
9FFDA233B496
26B85DCA4321
D4B2D140CB2D
A7395CCB42A0
541C417E57C0
D14E615E0545
69D92108C8B5
703265497350
D75971531042
10510049D725
35C649004000
5B0C7EC83645
05F5EC05133C
521B517352C7
94B6A644DFF6
2CA4A4D68B8E
A7765C952DDF
E2F14D0A0E28
DC018FC1D126
4927C97F1D57
046154274C11
155332417E00
6B13935CD550
C151D998C669
D973D917A4C7
130662240200
9386E2A48280
52750A0E592A
541C417E57C0
D14E615E0545
075D1A4DD323
32CA52054416
460661C93045
5429D67E1F57
0C734F230E13
1F0128447C00
411053C05273
42454C4C4147
C428C4550A75
730956C72BC2
28D70900734C
4F75030AD12B
6307417353C1
D65561530174
D1F71E05AD9D
F7FA2F629BB1
0E620691B9FE
43E69C28F08C
735175696421
424C0FFBF657
D01AFEEB890A
75CCB59C9BED
4B791BEA7BCC
51E97FFF51E9
E7316853E731
5C8FF9990DA2
00460740D722
35D152154017
5D0762D13401
0F35D5660653
1170553E4304
0C4233587119
F678905568C3
50240A68D1D8
69D92108C8B5
2E71D3BD262A
540D5E6355CC
D1417E431949
4BF6DE347FB6

View file

@ -76,7 +76,7 @@ local function main(args)
if removeflag then
print('Deleting file '..filename.. ' from SPIFFS if exists')
core.console("mem spiffs remove " ..filename)
core.console("mem spiffs remove -f " ..filename)
return
end

View file

@ -20,7 +20,7 @@ The outlined procedure is as following:
-- manchester
-- bit rate
"lf t55xx write b 0 d 00008040"
"lf t55xx write -b 0 -d 00008040"
"lf t55xx detect"
"lf t55xx info"
@ -118,7 +118,7 @@ local function test()
elseif _ == 1 then
local config = pcmd:format(config1, y, config2)
dbg(('lf t55xx write b 0 d %s'):format(config))
dbg(('lf t55xx write -b 0 -d %s'):format(config))
local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags)
local wc = Command:newNG{cmd = cmds.CMD_LF_T55XX_WRITEBL, data = data}

View file

@ -14,7 +14,7 @@ The outlined procedure is as following:
--BIPHASE 00010040
--
"lf t55xx write b 0 d 00010040"
"lf t55xx write -b 0 -d 00010040"
"lf t55xx detect"
"lf t55xx info"
@ -112,7 +112,7 @@ local function test()
elseif _ == 1 then
local config = pcmd:format(config1, y, config2)
dbg(('lf t55xx write b 0 d %s'):format(config))
dbg(('lf t55xx write -b 0 -d %s'):format(config))
local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags)

View file

@ -17,7 +17,7 @@ The outlined procedure is as following:
-- FSK1
-- bit rate
"lf t55xx write b 0 d 00007040"
"lf t55xx write -b 0 -d 00007040"
"lf t55xx detect"
"lf t55xx info"
@ -114,7 +114,7 @@ local function test(modulation)
elseif _ == 1 then
local config = pcmd:format(config1, y, modulation, config2)
dbg(('lf t55xx write b 0 d %s'):format(config))
dbg(('lf t55xx write -b 0 -d %s'):format(config))
local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags)
local wc = Command:newNG{cmd = cmds.CMD_LF_T55XX_WRITEBL, data = data}

View file

@ -11,7 +11,7 @@ desc = [[
This script will program a T55x7 TAG with the configuration: block 0x00 data 0x00088040
The outlined procedure is as following:
"lf t55xx write b 0 d 00088040"
"lf t55xx write -b 0 -d 00088040"
"lf t55xx detect"
"lf t55xx info"
@ -118,7 +118,7 @@ local function test(modulation)
dbg('Writing to T55x7 TAG')
local config = cmd:format(bitrate, modulation, clockrate)
dbg(('lf t55xx write b 0 d %s'):format(config))
dbg(('lf t55xx write -b 0 -d %s'):format(config))
local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(config, 32), password, block, flags)

View file

@ -17,10 +17,10 @@ It will then try to detect and read back those block data and compare if read da
lf t55xx wipe
lf t55xx detect
lf t55xx write b 1 d 00000000
lf t55xx write b 2 d ffffffff
lf t55xx write b 3 d 80000000
lf t55xx write b 4 d 00000001
lf t55xx write -b 1 -d 00000000
lf t55xx write -b 2 -d ffffffff
lf t55xx write -b 3 -d 80000000
lf t55xx write -b 4 -d 00000001
Loop:
@ -278,7 +278,7 @@ local function WipeCard()
core.console('rem [ERR:DETECT:WIPED] Failed to detect after wipe')
return false
else
local wipe_data_cmd = 'lf t55xx write b %s d %s'
local wipe_data_cmd = 'lf t55xx write -b %s -d %s'
for _ = 1, #data_blocks_cmds do
local val = data_blocks_cmds[_]
local c = string.format(wipe_data_cmd, _, val)
@ -321,7 +321,7 @@ local function test(modulation)
core.clearCommandBuffer()
-- Write Config block
dbg(('lf t55xx write b 0 d %s'):format(p_config_cmd))
dbg(('lf t55xx write -b 0 -d %s'):format(p_config_cmd))
local data = ('%s%s%s%s'):format(utils.SwapEndiannessStr(p_config_cmd, 32), password, block, flags)

View file

@ -251,15 +251,7 @@ static int usage_data_buffclear(void) {
PrintAndLogEx(NORMAL, " h This help");
return PM3_SUCCESS;
}
static int usage_data_fsktonrz(void) {
PrintAndLogEx(NORMAL, "Usage: data fsktonrz c <clock> l <fc_low> f <fc_high>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " c <clock> enter the a clock (omit to autodetect)");
PrintAndLogEx(NORMAL, " l <fc_low> enter a field clock (omit to autodetect)");
PrintAndLogEx(NORMAL, " f <fc_high> enter a field clock (omit to autodetect)");
return PM3_SUCCESS;
}
//set the demod buffer with given array of binary (one bit per byte)
//by marshmellow
@ -2295,36 +2287,27 @@ static int FSKToNRZ(int *data, size_t *dataLen, uint8_t clk, uint8_t LowToneFC,
}
static int CmdFSKToNRZ(const char *Cmd) {
// take clk, fc_low, fc_high
// blank = auto;
bool errors = false;
char cmdp = 0;
int clk = 0, fc_low = 10, fc_high = 8;
while (param_getchar(Cmd, cmdp) != 0x00) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_data_fsktonrz();
case 'c':
clk = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'f':
fc_high = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'l':
fc_low = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
if (errors) break;
}
//Validations
if (errors) return usage_data_fsktonrz();
CLIParserContext *ctx;
CLIParserInit(&ctx, "data fsktonrz",
"Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)\n"
"Omitted values are autodetect instead",
"data fsktonrz\n"
"data fsktonrz -c 32 --low 8 --hi 10");
void *argtable[] = {
arg_param_begin,
arg_int0("c", "clk", "<dec>", "clock"),
arg_int0(NULL, "low", "<dec>", "low field clock"),
arg_int0(NULL, "hi", "<dec>", "high field clock"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int clk = arg_get_int_def(ctx, 1, 0);
int fc_low = arg_get_int_def(ctx, 2, 0);
int fc_high = arg_get_int_def(ctx, 3, 0);
CLIParserFree(ctx);
setClockGrid(0, 0);
DemodBufferLen = 0;
@ -2567,11 +2550,9 @@ static command_t CommandTable[] = {
{"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, "<shift> -- Shift 0 for Graphed wave + or - shift value"},
{"timescale", CmdTimeScale, AlwaysAvailable, "Set a timescale to get a differential reading between the yellow and purple markers as time duration\n"},
{"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
{"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"},
{"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("General") "-------------------------"},
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"},
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},

View file

@ -39,7 +39,10 @@ static int CmdHelp(const char *Cmd);
"9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \
"DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
//-------------------------------------------------------------------------------------
// Sample private RSA Key
// Following example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c)
// private key - Exponent D
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
"66CA472BC44D253102F8B4A9D3BFA750" \
@ -136,14 +139,14 @@ static int rdv4_sign_write(uint8_t *signature, uint8_t slen){
if (!resp.oldarg[0]) {
PrintAndLogEx(FAILED, "Writing signature ( "_RED_("fail") ")");
} else {
PrintAndLogEx(SUCCESS, "Writing signature ( "_GREEN_("ok") " ) at offset %u", FLASH_MEM_SIGNATURE_OFFSET);
PrintAndLogEx(SUCCESS, "Writing signature at offset %u ( "_GREEN_("ok") " )", FLASH_MEM_SIGNATURE_OFFSET);
return PM3_SUCCESS;
}
}
return PM3_EFAILED;
}
static int CmdFlashmemSpiBaudrate(const char *Cmd) {
static int CmdFlashmemSpiBaud(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem baudrate",
@ -352,6 +355,7 @@ static int CmdFlashMemDump(const char *Cmd) {
arg_int0("l", "len", "<dec>", "length"),
arg_lit0("v", "view", "view dump"),
arg_strx0("f", "file", "<filename>", "file name"),
arg_int0("c", "cols", "<dec>", "column breaks (def 32)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
@ -362,6 +366,7 @@ static int CmdFlashMemDump(const char *Cmd) {
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
int breaks = arg_get_int_def(ctx, 5, 32);
CLIParserFree(ctx);
uint8_t *dump = calloc(len, sizeof(uint8_t));
@ -379,7 +384,7 @@ static int CmdFlashMemDump(const char *Cmd) {
if (view) {
PrintAndLogEx(INFO, "---- " _CYAN_("data") " ---------------");
print_hex_break(dump, len, 32);
print_hex_break(dump, len, breaks);
}
if (filename[0] != '\0') {
@ -445,29 +450,39 @@ static int CmdFlashMemInfo(const char *Cmd) {
CLIParserInit(&ctx, "mem info",
"Collect signature and verify it from flash memory",
"mem info"
// "mem info -s"
// "mem info -s -d 0102030405060708"
);
void *argtable[] = {
arg_param_begin,
// arg_lit0("s", NULL, "create a signature"),
// arg_lit0("w", NULL, "write signature to flash memory"),
arg_lit0("s", "sign", "create a signature"),
arg_str0("d", NULL, "<hex>", "flash memory id, 8 hex bytes"),
// arg_lit0("w", "write", "write signature to flash memory"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool shall_sign = false, shall_write = false;
// shall_sign = arg_get_lit(ctx, 1);
// shall_write = arg_get_lit(ctx, 2);
shall_sign = arg_get_lit(ctx, 1);
int dlen = 0;
uint8_t id[8] = {0};
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), id, sizeof(id), &dlen);
// shall_write = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
// validate signature data
if (dlen > 0 && dlen < sizeof(id) ) {
PrintAndLogEx(FAILED, "Error parsing flash memory id, expect 8, got %d", dlen);
return PM3_EINVARG;
}
// validate devicesignature data
rdv40_validation_t mem;
int res = rdv4_get_signature(&mem);
res = rdv4_get_signature(&mem);
if (res != PM3_SUCCESS) {
return res;
}
res = rdv4_validate(&mem);
// Flash ID hash (sha1)
@ -479,6 +494,11 @@ static int CmdFlashMemInfo(const char *Cmd) {
PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------");
PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid)));
PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
PrintAndLogEx(
(res == PM3_SUCCESS) ? SUCCESS : FAILED,
"Signature............ ( %s )",
(res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")
);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------");
for (int i = 0; i < (sizeof(mem.signature) / 32); i++) {
@ -520,13 +540,21 @@ static int CmdFlashMemInfo(const char *Cmd) {
PrintAndLogEx(INFO, " %.64s", str_pk + 192);
PrintAndLogEx(NORMAL, "");
bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0);
bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0);
PrintAndLogEx(
(is_keyok) ? SUCCESS : FAILED,
"RSA key validation... ( %s )",
"RSA public key validation.... ( %s )",
(is_keyok) ? _GREEN_("ok") : _RED_("fail")
);
is_keyok = (mbedtls_rsa_check_privkey(&rsa) == 0);
PrintAndLogEx(
(is_keyok) ? SUCCESS : FAILED,
"RSA private key validation... ( %s )",
(is_keyok) ? _GREEN_("ok") : _RED_("fail")
);
// to be verified
uint8_t from_device[RRG_RSA_KEY_LEN];
memcpy(from_device, mem.signature, RRG_RSA_KEY_LEN);
@ -537,6 +565,13 @@ static int CmdFlashMemInfo(const char *Cmd) {
// Signing (private key)
if (shall_sign) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "--- " _CYAN_("Enter signing") " --------------------");
if (dlen == 8) {
mbedtls_sha1(id, sizeof(id), sha_hash);
}
PrintAndLogEx(INFO, "Signing %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign);
PrintAndLogEx(
@ -555,26 +590,29 @@ static int CmdFlashMemInfo(const char *Cmd) {
}
// Verify (public key)
int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device);
bool is_verified = (mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device) == 0);
mbedtls_rsa_free(&rsa);
PrintAndLogEx(
(is_verified == 0) ? SUCCESS : FAILED,
(is_verified) ? SUCCESS : FAILED,
"RSA verification..... ( %s )",
(is_verified == 0) ? _GREEN_("ok") : _RED_("fail")
(is_verified) ? _GREEN_("ok") : _RED_("fail")
);
if (is_verified) {
PrintAndLogEx(SUCCESS, "Genuine Proxmark3 RDV4 signature detected");
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "{ SPI File system }"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"baudrate", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate"},
{"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "High level SPI FileSystem Flash manipulation"},
{"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"},
{"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory"},
{"baudrate", CmdFlashmemSpiBaud, IfPm3Flash, "Set Flash memory Spi baudrate"},
{"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"},
{"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"},
{"load", CmdFlashMemLoad, IfPm3Flash, "Load data to flash memory"},
{"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory"},
{NULL, NULL, NULL, NULL}
};

View file

@ -8,352 +8,16 @@
// Proxmark3 RDV40 Flash memory commands
//-----------------------------------------------------------------------------
#include "cmdflashmemspiffs.h"
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "pmflash.h"
#include "fileutils.h" //saveFile
#include "comms.h" //getfromdevice
#include "cliparser.h"
static int CmdHelp(const char *Cmd);
static int usage_flashmemspiffs_remove(void) {
PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem\n");
PrintAndLogEx(NORMAL, "Usage: mem spiffs remove <filename>");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs remove lasttag.bin"));
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_rename(void) {
PrintAndLogEx(NORMAL, "Rename/move a file in spiffs filesystem\n");
PrintAndLogEx(NORMAL, "Usage: mem spiffs rename <source> <destination>");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs rename lasttag.bin oldtag.bin"));
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_copy(void) {
PrintAndLogEx(NORMAL, "Copy a file to another (destructively) in spiffs filesystem\n");
PrintAndLogEx(NORMAL, "Usage: mem spiffs copy <source> <destination>");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs copy lasttag.bin lasttag_cpy.bin"));
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_dump(void) {
PrintAndLogEx(NORMAL, "Dumps flash memory on device into a file or in console");
PrintAndLogEx(NORMAL, "Size is handled by first sending a STAT command against file existence\n");
PrintAndLogEx(NORMAL, "Usage: mem spiffs dump o <filename> [f <file name> [e]] [p]");
PrintAndLogEx(NORMAL, " o <filename> - filename in SPIFFS");
PrintAndLogEx(NORMAL, " f <filename> - file name to save to <w/o .bin>");
PrintAndLogEx(NORMAL, " p - print dump in console");
PrintAndLogEx(NORMAL, " e - also save in EML format (good for tags save and dictonnary files)");
PrintAndLogEx(NORMAL, " You must specify at lease option f or option p, both if you wish");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs dump o lasttag.bin f lasttag e"));
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs dump o lasttag.bin p"));
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_load(void) {
PrintAndLogEx(NORMAL, "Uploads binary-wise file into device filesystem");
PrintAndLogEx(NORMAL, "Warning: mem area to be written must have been wiped first");
PrintAndLogEx(NORMAL, "(this is already taken care when loading dictionaries)\n");
PrintAndLogEx(NORMAL, "Usage: mem spiffs load o <filename> f <filename>");
PrintAndLogEx(NORMAL, " o <filename> - destination filename");
PrintAndLogEx(NORMAL, " f <filename> - local filename");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs load f myfile o myapp.conf"));
return PM3_SUCCESS;
}
static int usage_flashmemspiffs_wipe(void) {
PrintAndLogEx(NORMAL, "wipes all files on the device filesystem " _RED_("* Warning *"));
PrintAndLogEx(NORMAL, "Usage: mem spiffs wipe [h]");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" mem spiffs wipe"));
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_remove();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_remove();
}
char filename[32] = {0};
bool errors = false;
if (param_getstr(Cmd, 0, filename, 32) >= 32) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
}
// check null filename ?
if (errors) {
usage_flashmemspiffs_remove();
return PM3_EINVARG;
}
SendCommandMIX(CMD_SPIFFS_REMOVE, 0, 0, 0, (uint8_t *)filename, 32);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSRename(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_rename();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_rename();
}
char srcfilename[32] = {0};
char destfilename[32] = {0};
bool errors = false;
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
}
if (srcfilename[0] == '\0') {
PrintAndLogEx(FAILED, "Source Filename missing or invalid");
errors = true;
}
if (param_getstr(Cmd, 1, destfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
}
if (destfilename[0] == '\0') {
PrintAndLogEx(FAILED, "Source Filename missing or invalid");
errors = true;
}
// check null filename ?
if (errors) {
usage_flashmemspiffs_rename();
return PM3_EINVARG;
}
char data[65];
sprintf(data, "%s,%s", srcfilename, destfilename);
SendCommandMIX(CMD_SPIFFS_RENAME, 0, 0, 0, (uint8_t *)data, 65);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCopy(const char *Cmd) {
int len = strlen(Cmd);
if (len < 1) {
return usage_flashmemspiffs_copy();
}
char ctmp = tolower(param_getchar(Cmd, 0));
if (len == 1 && ctmp == 'h') {
return usage_flashmemspiffs_copy();
}
char srcfilename[32] = {0};
char destfilename[32] = {0};
bool errors = false;
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
}
if (srcfilename[0] == '\0') {
PrintAndLogEx(FAILED, "Source Filename missing or invalid");
errors = true;
}
if (param_getstr(Cmd, 1, destfilename, 32) >= 32) {
PrintAndLogEx(FAILED, "Source Filename too long");
errors = true;
}
if (destfilename[0] == '\0') {
PrintAndLogEx(FAILED, "Source Filename missing or invalid");
errors = true;
}
// check null filename ?
if (errors) {
usage_flashmemspiffs_copy();
return PM3_EINVARG;
}
char data[65];
sprintf(data, "%s,%s", srcfilename, destfilename);
SendCommandMIX(CMD_SPIFFS_COPY, 0, 0, 0, (uint8_t *)data, 65);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSDump(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
uint8_t cmdp = 0;
bool errors = false;
bool print = false;
uint32_t start_index = 0, len = FLASH_MEM_MAX_SIZE;
char destfilename[32] = {0};
bool eml = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_flashmemspiffs_dump();
/*case 'l':
len = param_get32ex(Cmd, cmdp + 1, FLASH_MEM_MAX_SIZE, 10);
cmdp += 2;
break;*/
case 'o':
param_getstr(Cmd, cmdp + 1, destfilename, 32);
cmdp += 2;
break;
case 'p':
print = true;
cmdp += 1;
break;
case 'e':
eml = true;
cmdp += 1;
break;
case 'f':
// File handling
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
break;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if ((filename[0] == '\0') && (!print)) {
PrintAndLogEx(FAILED, "No print asked and local dump filename missing or invalid");
errors = true;
}
if (destfilename[0] == '\0') {
PrintAndLogEx(FAILED, "SPIFFS filename missing or invalid");
errors = true;
}
// Validations
if (errors || cmdp == 0) {
usage_flashmemspiffs_dump();
return PM3_EINVARG;
}
// get size from spiffs itself !
SendCommandMIX(CMD_SPIFFS_STAT, 0, 0, 0, (uint8_t *)destfilename, 32);
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
len = resp.oldarg[0];
uint8_t *dump = calloc(len, sizeof(uint8_t));
if (!dump) {
PrintAndLogEx(ERR, "error, cannot allocate memory ");
return PM3_EMALLOC;
}
PrintAndLogEx(INFO, "downloading "_YELLOW_("%u") " bytes from spiffs (flashmem)", len);
if (!GetFromDevice(SPIFFS, dump, len, start_index, (uint8_t *)destfilename, 32, NULL, -1, true)) {
PrintAndLogEx(FAILED, "ERROR; downloading from spiffs(flashmemory)");
free(dump);
return PM3_EFLASH;
}
if (print) {
print_hex_break(dump, len, 32);
}
if (filename[0] != '\0') {
saveFile(filename, ".bin", dump, len);
if (eml) {
uint8_t eml_len = 16;
if (strstr(filename, "class") != NULL)
eml_len = 8;
else if (strstr(filename, "mfu") != NULL)
eml_len = 4;
saveFileEML(filename, dump, len, eml_len);
}
}
free(dump);
return PM3_SUCCESS;
}
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
int flashmem_spiffs_load(char *destfn, uint8_t *data, size_t datalen) {
int ret_val = PM3_SUCCESS;
@ -364,33 +28,35 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
// Send to device
uint32_t bytes_sent = 0;
uint32_t bytes_remaining = datalen;
uint32_t append = 0;
// fast push mode
conn.block_after_ACK = true;
while (bytes_remaining > 0) {
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
flashmem_write_t *payload = calloc(1, sizeof(flashmem_write_t) + bytes_in_packet);
payload->append = (bytes_sent > 0);
payload->fnlen = strlen(destfn);
memcpy(payload->fn, destfn, strlen(destfn));
payload->bytes_in_packet = bytes_in_packet;
memset(payload->data, 0, bytes_in_packet);
memcpy(payload->data, data + bytes_sent, bytes_in_packet);
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_WRITE, (uint8_t *)payload, sizeof(flashmem_write_t) + bytes_in_packet);
char fdata[32 + bytes_in_packet];
memset(fdata, 0, sizeof(fdata));
memcpy(fdata, destfn, 32);
memcpy(fdata + 32, data + bytes_sent, bytes_in_packet);
if (bytes_sent > 0)
append = 1;
SendCommandOLD(CMD_SPIFFS_WRITE, append, bytes_in_packet, 0, fdata, 32 + bytes_in_packet);
free(payload);
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
PacketResponseNG resp;
uint8_t retry = 3;
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
while (WaitForResponseTimeout(CMD_SPIFFS_WRITE, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
retry--;
if (retry == 0) {
@ -398,13 +64,6 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
goto out;
}
}
uint8_t isok = resp.oldarg[0] & 0xFF;
if (!isok) {
PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
ret_val = PM3_EFLASH;
break;
}
}
out:
@ -416,99 +75,470 @@ out:
// We want to unmount after these to set things back to normal but more than this
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return ret_val;
}
static int CmdFlashMemSpiFFSWipe(const char *Cmd) {
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs mount",
"Mount the SPIFFS file system if not already mounted",
"mem spiffs mount");
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') {
return usage_flashmemspiffs_wipe();
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs unmount",
"Un-mount the SPIFFS file system",
"mem spiffs unmount");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs test",
"Test SPIFFS Operations, require wiping pages 0 and 1",
"mem spiffs test");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs check",
"Check/try to defrag faulty/fragmented SPIFFS file system",
"mem spiffs check");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs tree",
"Print the Flash memory file system tree",
"mem spiffs tree");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs info",
"Print file system info and usage statistics",
"mem spiffs info");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs remove",
"Remove a file from SPIFFS filesystem",
"mem spiffs remove -f lasttag.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "filename", "<fn>", "file to remove"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, 32, &fnlen);
CLIParserFree(ctx);
PrintAndLogEx(DEBUG, "Removing `" _YELLOW_("%s") "`", filename);
struct {
uint8_t len;
uint8_t fn[32];
} PACKED payload;
payload.len = fnlen;
memcpy(payload.fn, filename, fnlen);
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_REMOVE, (uint8_t *)&payload, sizeof(payload));
WaitForResponse(CMD_SPIFFS_REMOVE, &resp);
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(INFO, "Done!");
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSRename(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs rename",
"Rename/move a file from SPIFFS filesystem.",
"mem spiffs rename -s aaa.bin -d bbb.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("s", "src", "<fn>", "source file name"),
arg_str1("d", "dest", "<fn>", "destination file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int slen = 0;
char src[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, 32, &slen);
int dlen = 0;
char dest[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, 32, &dlen);
CLIParserFree(ctx);
PrintAndLogEx(DEBUG, "Rename from `" _YELLOW_("%s") "` -> `" _YELLOW_("%s") "`", src, dest);
struct {
uint8_t slen;
uint8_t src[32];
uint8_t dlen;
uint8_t dest[32];
} PACKED payload;
payload.slen = slen;
payload.dlen = dlen;
memcpy(payload.src, src, slen);
memcpy(payload.dest, dest, dlen);
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_RENAME, (uint8_t *)&payload, sizeof(payload));
WaitForResponse(CMD_SPIFFS_RENAME, &resp);
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(INFO, "Done!");
PrintAndLogEx(HINT, "Try `" _YELLOW_("mem spiffs tree") "` to verify");
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSCopy(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs copy",
"Copy a file to another (destructively) in SPIFFS file system",
"mem spiffs copy -s aaa.bin -d aaa_cpy.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("s", "src", "<fn>", "source file name"),
arg_str1("d", "dest", "<fn>", "destination file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int slen = 0;
char src[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, 32, &slen);
int dlen = 0;
char dest[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, 32, &dlen);
CLIParserFree(ctx);
struct {
uint8_t slen;
uint8_t src[32];
uint8_t dlen;
uint8_t dest[32];
} PACKED payload;
payload.slen = slen;
payload.dlen = dlen;
memcpy(payload.src, src, slen);
memcpy(payload.dest, dest, dlen);
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_COPY, (uint8_t *)&payload, sizeof(payload));
WaitForResponse(CMD_SPIFFS_COPY, &resp);
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(INFO, "Done!");
PrintAndLogEx(HINT, "Try `" _YELLOW_("mem spiffs tree") "` to verify");
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSDump(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs dump",
"Dumps device SPIFFS file to a local file\n"
"Size is handled by first sending a STAT command against file to verify existence",
"mem spiffs dump -s tag.bin --> download binary file from device\n"
"mem spiffs dump -s tag.bin -d aaa -e --> download tag.bin, save as aaa.eml format"
);
void *argtable[] = {
arg_param_begin,
arg_str1("s", "src", "<fn>", "SPIFFS file to save"),
arg_str0("d", "dest", "<fn>", "file name to save to <w/o .bin>"),
arg_lit0("e", "eml", "also save in EML format"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int slen = 0;
char src[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, 32, &slen);
int dlen = 0;
char dest[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, FILE_PATH_SIZE, &dlen);
bool eml = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
// get size from spiffs itself !
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_STAT, (uint8_t *)src, slen);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
PrintAndLogEx(INFO, "Wiping all files from SPIFFS FileSystem");
uint32_t len = resp.data.asDwords[0];
uint8_t *dump = calloc(len, sizeof(uint8_t));
if (!dump) {
PrintAndLogEx(ERR, "error, cannot allocate memory ");
return PM3_EMALLOC;
}
// download from device
uint32_t start_index = 0;
PrintAndLogEx(INFO, "downloading "_YELLOW_("%u") " bytes from `" _YELLOW_("%s") "` (spiffs)", len, src);
if (!GetFromDevice(SPIFFS, dump, len, start_index, (uint8_t *)src, slen, NULL, -1, true)) {
PrintAndLogEx(FAILED, "error, downloading from spiffs");
free(dump);
return PM3_EFLASH;
}
// save to file
char fn[FILE_PATH_SIZE] = {0};
if (dlen == 0) {
strncpy(fn, src, slen);
} else {
strncpy(fn, dest, dlen);
}
saveFile(fn, ".bin", dump, len);
if (eml) {
uint8_t eml_len = 16;
if (strstr(fn, "class") != NULL)
eml_len = 8;
else if (strstr(fn, "mfu") != NULL)
eml_len = 4;
saveFileEML(fn, dump, len, eml_len);
}
free(dump);
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSWipe(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs wipe",
_RED_("* * * Warning * * *") " \n"
_CYAN_("This command wipes all files on the device SPIFFS file system"),
"mem spiffs wipe");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(INFO, "Wiping all files from SPIFFS file system");
PacketResponseNG resp;
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_WIPE, NULL, 0);
WaitForResponse(CMD_SPIFFS_WIPE, &resp);
if (resp.status == PM3_SUCCESS)
PrintAndLogEx(INFO, "Done!");
PrintAndLogEx(HINT, "Try use '" _YELLOW_("mem spiffs tree") "' to verify.");
PrintAndLogEx(HINT, "Try `" _YELLOW_("mem spiffs tree") "` to verify");
return PM3_SUCCESS;
}
static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
static int CmdFlashMemSpiFFSUpload(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs upload",
"Uploads binary-wise file into device file system\n"
"Warning: mem area to be written must have been wiped first.\n"
"This is already taken care when loading dictionaries.\n"
"File names can only be 32 bytes long on device SPIFFS",
"mem spiffs upload -s local.bin -d dest.bin"
);
char filename[FILE_PATH_SIZE] = {0};
uint8_t destfilename[32] = {0};
bool errors = false;
uint8_t cmdp = 0;
void *argtable[] = {
arg_param_begin,
arg_str1("s", "src", "<fn>", "source file name"),
arg_str1("d", "dest", "<fn>", "destination file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_flashmemspiffs_load();
case 'f':
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
PrintAndLogEx(FAILED, "Filename too long");
errors = true;
}
cmdp += 2;
break;
case 'o':
param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32);
if (strlen((char *)destfilename) == 0) {
PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
errors = true;
}
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
int slen = 0;
char src[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, FILE_PATH_SIZE, &slen);
// Validations
if (errors || cmdp == 0)
return usage_flashmemspiffs_load();
int dlen = 0;
char dest[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)dest, 32, &dlen);
CLIParserFree(ctx);
PrintAndLogEx(DEBUG, "Upload `" _YELLOW_("%s") "` -> `" _YELLOW_("%s") "`", src, dest);
size_t datalen = 0;
uint8_t *data = NULL;
int res = loadFile_safe(filename, "", (void **)&data, &datalen);
// int res = loadFileEML( filename, data, &datalen);
int res = loadFile_safe(src, "", (void **)&data, &datalen);
if (res != PM3_SUCCESS) {
free(data);
return PM3_EFILE;
}
res = flashmem_spiffs_load(destfilename, data, datalen);
res = flashmem_spiffs_load(dest, data, datalen);
free(data);
if (res == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") " bytes to file "_GREEN_("%s"), datalen, destfilename);
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") " bytes to file "_GREEN_("%s"), datalen, dest);
PrintAndLogEx(HINT, "Try `" _YELLOW_("mem spiffs tree") "` to verify");
return res;
}
static command_t CommandTable[] = {
static int CmdFlashMemSpiFFSView(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "mem spiffs view",
"View a file on flash memory on devicer in console",
"mem spiffs view -f tag.bin"
);
void *argtable[] = {
arg_param_begin,
arg_str1("f", "file", "<fn>", "SPIFFS file to view"),
arg_int0("c", "cols", "<dec>", "column breaks (def 32)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int slen = 0;
char src[32] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)src, 32, &slen);
int breaks = arg_get_int_def(ctx, 2, 32);
CLIParserFree(ctx);
// get size from spiffs itself !
clearCommandBuffer();
SendCommandNG(CMD_SPIFFS_STAT, (uint8_t *)src, slen);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
uint32_t len = resp.data.asDwords[0];
if (len == 0) {
PrintAndLogEx(ERR, "error, failed to retrieve file stats on SPIFFSS");
return PM3_EFAILED;
}
uint8_t *dump = calloc(len, sizeof(uint8_t));
if (!dump) {
PrintAndLogEx(ERR, "error, cannot allocate memory ");
return PM3_EMALLOC;
}
uint32_t start_index = 0;
PrintAndLogEx(INFO, "downloading "_YELLOW_("%u") " bytes from `" _YELLOW_("%s") "` (spiffs)", len, src);
if (!GetFromDevice(SPIFFS, dump, len, start_index, (uint8_t *)src, slen, NULL, -1, true)) {
PrintAndLogEx(FAILED, "error, downloading from spiffs");
free(dump);
return PM3_EFLASH;
}
PrintAndLogEx(NORMAL, "");
print_hex_break(dump, len, breaks);
PrintAndLogEx(NORMAL, "");
free(dump);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash, "Copy a file to another (destructively) in SPIFFS FileSystem in FlashMEM (spiffs)"},
{"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented Filesystem"},
{"dump", CmdFlashMemSpiFFSDump, IfPm3Flash, "Dump a file from SPIFFS FileSystem in FlashMEM (spiffs)"},
{"info", CmdFlashMemSpiFFSInfo, IfPm3Flash, "Print filesystem info and usage statistics (spiffs)"},
{"load", CmdFlashMemSpiFFSLoad, IfPm3Flash, "Upload file into SPIFFS Filesystem (spiffs)"},
{"mount", CmdFlashMemSpiFFSMount, IfPm3Flash, "Mount the SPIFFS Filesystem if not already mounted (spiffs)"},
{"remove", CmdFlashMemSpiFFSRemove, IfPm3Flash, "Remove a file from SPIFFS FileSystem in FlashMEM (spiffs)"},
{"rename", CmdFlashMemSpiFFSRename, IfPm3Flash, "Rename/move a file in SPIFFS FileSystem in FlashMEM (spiffs)"},
{"test", CmdFlashMemSpiFFSTest, IfPm3Flash, "Test SPIFFS Operations (require wiping pages 0 and 1)"},
{"tree", CmdFlashMemSpiFFSTree, IfPm3Flash, "Print the Flash Memory FileSystem Tree (spiffs)"},
{"unmount", CmdFlashMemSpiFFSUnmount, IfPm3Flash, "Un-mount the SPIFFS Filesystem if not already mounted (spiffs)"},
{"wipe", CmdFlashMemSpiFFSWipe, IfPm3Flash, "Wipe all files from SPIFFS FileSystem." _RED_("* dangerous *") },
{"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash, "Copy a file to another (destructively) in SPIFFS file system"},
{"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented file system"},
{"dump", CmdFlashMemSpiFFSDump, IfPm3Flash, "Dump a file from SPIFFS file system"},
{"info", CmdFlashMemSpiFFSInfo, IfPm3Flash, "Print file system info and usage statistics"},
{"mount", CmdFlashMemSpiFFSMount, IfPm3Flash, "Mount the SPIFFS file system if not already mounted"},
{"remove", CmdFlashMemSpiFFSRemove, IfPm3Flash, "Remove a file from SPIFFS file system"},
{"rename", CmdFlashMemSpiFFSRename, IfPm3Flash, "Rename/move a file in SPIFFS file system"},
{"test", CmdFlashMemSpiFFSTest, IfPm3Flash, "Test SPIFFS Operations"},
{"tree", CmdFlashMemSpiFFSTree, IfPm3Flash, "Print the Flash memory file system tree"},
{"unmount", CmdFlashMemSpiFFSUnmount, IfPm3Flash, "Un-mount the SPIFFS file system"},
{"upload", CmdFlashMemSpiFFSUpload, IfPm3Flash, "Upload file into SPIFFS file system"},
{"view", CmdFlashMemSpiFFSView, IfPm3Flash, "View file on SPIFFS file system"},
{"wipe", CmdFlashMemSpiFFSWipe, IfPm3Flash, "Wipe all files from SPIFFS file system * " _RED_("dangerous") " *" },
{NULL, NULL, NULL, NULL}
};

View file

@ -14,6 +14,6 @@
#include "common.h"
int CmdFlashMemSpiFFS(const char *Cmd);
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen);
int flashmem_spiffs_load(char *destfn, uint8_t *data, size_t datalen);
#endif

View file

@ -103,14 +103,6 @@ static inline uint32_t leadingzeros(uint64_t a) {
#else
return 0;
#endif
}
static inline uint32_t countones(uint64_t a) {
#if defined __GNUC__
return __builtin_popcountll(a);
#else
return 0;
#endif
}
const char *card_types[] = {
@ -2034,7 +2026,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) {
uint64_t a = bytes_to_num(data, 8);
bool starts = (leadingzeros(a) < 12);
bool ones = (countones(a) > 16 && countones(a) < 48);
bool ones = (bitcount64(a) > 16 && bitcount64(a) < 48);
if (starts && ones) {
PrintAndLogEx(INFO, "data looks encrypted, False Positives " _YELLOW_("ARE") " possible");

View file

@ -1290,9 +1290,10 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8
MifareAuthState = masNrAr;
if (AuthData.first_auth) {
AuthData.nt = bytes_to_num(cmd, 4);
AuthData.nt_enc_par = 0;
} else {
AuthData.nt_enc = bytes_to_num(cmd, 4);
AuthData.nt_enc_par = parity[0];
AuthData.nt_enc_par = parity[0] & 0xF0;
}
return;
} else {
@ -1304,6 +1305,7 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8
snprintf(exp, size, "AUTH: nr ar (enc)");
MifareAuthState = masAt;
AuthData.nr_enc = bytes_to_num(cmd, 4);
AuthData.nr_enc_par = parity[0] & 0xF0;
AuthData.ar_enc = bytes_to_num(&cmd[4], 4);
AuthData.ar_enc_par = parity[0] << 4;
return;
@ -1316,7 +1318,7 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8
snprintf(exp, size, "AUTH: at (enc)");
MifareAuthState = masAuthComplete;
AuthData.at_enc = bytes_to_num(cmd, 4);
AuthData.at_enc_par = parity[0];
AuthData.at_enc_par = parity[0] & 0xF0;
return;
} else {
MifareAuthState = masError;
@ -1335,6 +1337,17 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8
}
static void mf_get_paritybinstr(char *s, uint32_t val, uint8_t par) {
uint8_t foo[4] = {0,0,0,0};
num_to_bytes(val, sizeof(uint32_t), foo);
for (uint8_t i = 0; i < 4; i++) {
if (oddparity8(foo[i]) != ((par >> (7 - (i & 0x0007))) & 0x01))
sprintf(s++, "1");
else
sprintf(s++, "0");
}
}
bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen, const uint64_t *dicKeys, uint32_t dicKeysCount) {
static struct Crypto1State *traceCrypto1;
@ -1428,7 +1441,29 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes
//hardnested
if (!traceCrypto1) {
PrintAndLogEx(NORMAL, "hardnested not implemented. uid:%x nt:%x ar_enc:%x at_enc:%x\n", AuthData.uid, AuthData.nt, AuthData.ar_enc, AuthData.at_enc);
//PrintAndLogEx(NORMAL, "hardnested not implemented. uid:%x nt:%x ar_enc:%x at_enc:%x\n", AuthData.uid, AuthData.nt, AuthData.ar_enc, AuthData.at_enc);
char snt[5] = {0,0,0,0,0};
mf_get_paritybinstr(snt, AuthData.nt_enc, AuthData.nt_enc_par);
char sar[5] = {0,0,0,0,0};
mf_get_paritybinstr(sar, AuthData.ar_enc, AuthData.ar_enc_par);
char sat[5] = {0,0,0,0,0};
mf_get_paritybinstr(sat, AuthData.at_enc, AuthData.at_enc_par);
PrintAndLogEx(NORMAL, "Nested authentication detected. ");
PrintAndLogEx(NORMAL, "tools/mf_nonce_brute/mf_nonce_brute %x %x %s %x %x %s %x %s %s\n"
, AuthData.uid
, AuthData.nt_enc
, snt
, AuthData.nr_enc
, AuthData.ar_enc
, sar
, AuthData.at_enc
, sat
, sprint_hex_inrow(cmd, cmdsize)
);
MifareAuthState = masError;
/* TOO SLOW( needs to have more strong filter. with this filter - aprox 4 mln tests

View file

@ -18,6 +18,7 @@ typedef struct {
uint32_t nt_enc; // encrypted tag challenge
uint8_t nt_enc_par; // encrypted tag challenge parity
uint32_t nr_enc; // encrypted reader challenge
uint8_t nr_enc_par; // encrypted reader challenge parity
uint32_t ar_enc; // encrypted reader response
uint8_t ar_enc_par; // encrypted reader response parity
uint32_t at_enc; // encrypted tag response

View file

@ -523,20 +523,21 @@ static int32_t initSectorTable(sector_t **src, int32_t items) {
static void decode_print_st(uint16_t blockno, uint8_t *data) {
if (mfIsSectorTrailer(blockno)) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Sector trailer decoded:");
PrintAndLogEx(NORMAL, "----------------------------------------------");
PrintAndLogEx(NORMAL, "Key A " _GREEN_("%s"), sprint_hex_inrow(data, 6));
PrintAndLogEx(NORMAL, "Key B " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6));
PrintAndLogEx(NORMAL, "Access rights");
PrintAndLogEx(INFO, "--------- " _CYAN_("Sector trailer") " -------------");
PrintAndLogEx(INFO, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data, 6));
PrintAndLogEx(INFO, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data + 6, 3));
PrintAndLogEx(INFO, "user / gdb... " _GREEN_("%02x"), data[9]);
PrintAndLogEx(INFO, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6));
PrintAndLogEx(INFO, "Access rights decoded");
int bln = mfFirstBlockOfSector(mfSectorNum(blockno));
int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1;
for (int i = 0; i < 4; i++) {
PrintAndLogEx(NORMAL, " block %d%s " _YELLOW_("%s"), bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &data[6]));
PrintAndLogEx(INFO, " block %d%s " _YELLOW_("%s"), bln, ((blinc > 1) && (i < 3) ? "+" : ""), mfGetAccessConditionsDesc(i, &data[6]));
bln += blinc;
}
PrintAndLogEx(NORMAL, "UserData " _YELLOW_("0x%02x"), data[9]);
PrintAndLogEx(NORMAL, "----------------------------------------------");
PrintAndLogEx(INFO, "--------------------------------------");
}
}
@ -789,7 +790,7 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
PrintAndLogEx(NORMAL, "Key must include 12 HEX symbols");
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "--sector no %d, key %c - %s ", sectorNo, keyType ? 'B' : 'A', sprint_hex(key, 6));
PrintAndLogEx(NORMAL, "");
uint8_t sc_size = mfNumBlocksPerSector(sectorNo) * 16;
uint8_t *data = calloc(sc_size, sizeof(uint8_t));
@ -804,8 +805,16 @@ static int CmdHF14AMfRdSc(const char *Cmd) {
uint8_t blocks = NumBlocksPerSector(sectorNo);
uint8_t start = FirstBlockOfSector(sectorNo);
PrintAndLogEx(INFO, " # | data - sector %02d / 0x%02X | ascii", sectorNo, sectorNo);
PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
for (int i = 0; i < blocks; i++) {
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16));
if (start + i == 0) {
PrintAndLogEx(INFO, "%3d | " _RED_("%s"), start + i, sprint_hex_ascii(data + (i * 16), 16));
} else if (mfIsSectorTrailer(i)) {
PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), start + i, sprint_hex_ascii(data + (i * 16), 16));
} else {
PrintAndLogEx(INFO, "%3d | %s ", start + i, sprint_hex_ascii(data + (i * 16), 16));
}
}
decode_print_st(start + blocks - 1, data + ((blocks - 1) * 16));
@ -3771,8 +3780,10 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "\n # | data - sector %02d / 0x%02X ", sector, sector);
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " # | data - sector %02d / 0x%02X | ascii", sector, sector);
PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
uint8_t blocks = 4;
uint8_t start = sector * 4;
if (sector >= 32) {
@ -3785,11 +3796,11 @@ static int CmdHF14AMfEGetSc(const char *Cmd) {
int res = mfEmlGetMem(data, start + i, 1);
if (res == PM3_SUCCESS) {
if (start + i == 0) {
PrintAndLogEx(INFO, "%03d | " _RED_("%s"), start + i, sprint_hex_ascii(data, sizeof(data)));
PrintAndLogEx(INFO, "%3d | " _RED_("%s"), start + i, sprint_hex_ascii(data, sizeof(data)));
} else if (mfIsSectorTrailer(i)) {
PrintAndLogEx(INFO, "%03d | " _YELLOW_("%s"), start + i, sprint_hex_ascii(data, sizeof(data)));
PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), start + i, sprint_hex_ascii(data, sizeof(data)));
} else {
PrintAndLogEx(INFO, "%03d | %s ", start + i, sprint_hex_ascii(data, sizeof(data)));
PrintAndLogEx(INFO, "%3d | %s ", start + i, sprint_hex_ascii(data, sizeof(data)));
}
}
}
@ -4467,8 +4478,10 @@ static int CmdHF14AMfCGetSc(const char *Cmd) {
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "\n # | data - sector %02d / 0x%02X ", sector, sector);
PrintAndLogEx(NORMAL, "----+------------------------------------------------");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, " # | data - sector %02d / 0x%02X | ascii", sector, sector);
PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
uint8_t blocks = 4;
uint8_t start = sector * 4;
if (sector >= 32) {
@ -4487,7 +4500,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) {
PrintAndLogEx(ERR, "Can't read block. %d error=%d", start + i, res);
return PM3_ESOFT;
}
PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data, 16));
PrintAndLogEx(INFO, "%3d | %s ", start + i, sprint_hex_ascii(data, sizeof(data)));
}
decode_print_st(start + blocks - 1, data);
return PM3_SUCCESS;

View file

@ -3102,7 +3102,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
"hf mfu otptear -b 3 -i 100 -s 1000\n"
"hf mfu otptear -b 3 -i 1 -e 200\n"
"hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE\n"
"hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000 -> quite when OTP is reset"
"hf mfu otptear -b 3 -i 100 -s 200 -e 2500 -d FFFFFFFF -t EEEEEEEE -m 00000000 -> quit when OTP is reset"
);
void *argtable[] = {
@ -3112,7 +3112,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
arg_u64_0("e", "end", "<dec>", "end time (def 3000 us)"),
arg_u64_0("s", "start", "<dec>", "start time (def 0 us)"),
arg_str0("d", "data", "<hex>", "initialise data before run (4 bytes)"),
arg_str0("t", "test", "<hex>", "test write data (4 bytes)"),
arg_str0("t", "test", "<hex>", "test write data (4 bytes, 00000000 by default)"),
arg_str0("m", "match", "<hex>", "exit criteria, if block matches this value (4 bytes)"),
arg_param_end
};
@ -3126,6 +3126,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
int d_len = 0;
uint8_t data[4] = {0x00};
CLIGetHexWithReturn(ctx, 5, data, &d_len);
bool use_data = (d_len > 0);
int t_len = 0;
uint8_t test[4] = {0x00};
@ -3150,7 +3151,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return PM3_EINVARG;
}
if (start > (end - steps)) {
PrintAndLogEx(WARNING, "Start time larger then (end time + steps)");
PrintAndLogEx(WARNING, "Start time larger than (end time + steps)");
return PM3_EINVARG;
}
@ -3169,26 +3170,34 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return PM3_EINVARG;
}
uint8_t teardata[8] = {0x00};
memcpy(teardata, data, sizeof(data));
memcpy(teardata + sizeof(data), test, sizeof(test));
uint8_t teardata[4] = {0x00};
memcpy(teardata, test, sizeof(test));
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Tear off") " ---------------------");
PrintAndLogEx(INFO, "Starting Tear-off test");
PrintAndLogEx(INFO, "Target block no: %u", blockno);
PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(teardata, 4));
PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata + 4, 4));
if (use_data) {
PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(data, 4));
}
PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata, 4));
if (use_match) {
PrintAndLogEx(INFO, "Target match block data : %s", sprint_hex_inrow(match, 4));
}
PrintAndLogEx(INFO, "----------------------------------------------------");
uint8_t isOK;
bool got_pre = false, got_post = false, lock_on = false;
bool lock_on = false;
uint8_t pre[4] = {0};
uint8_t post[4] = {0};
uint32_t current = start;
int phase_clear = -1;
int phase_newwr = -1;
int phase_begin_clear = -1;
int phase_end_clear = -1;
int phase_begin_newwr = -1;
int phase_end_newwr = -1;
bool skip_phase1 = false;
uint8_t retries = 0;
uint8_t error_retries = 0;
while (current <= (end - steps)) {
while ((current <= (end - steps)) && (error_retries < 10)) {
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
@ -3198,10 +3207,27 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", current);
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0);
PacketResponseNG resp;
got_pre = false;
if (use_data) {
SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, blockno, 0, 0, data, d_len);
bool got_written = false;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
isOK = resp.oldarg[0] & 0xff;
if (isOK) {
got_written = true;
}
}
if (! got_written) {
PrintAndLogEx(FAILED, "Failed to write block BEFORE");
error_retries++;
continue; // try again
}
}
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0);
bool got_pre = false;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
isOK = resp.oldarg[0] & 0xFF;
if (isOK) {
@ -3209,9 +3235,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
got_pre = true;
}
}
if (! got_pre) {
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
error_retries++;
continue; // try again
}
clearCommandBuffer();
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockno, current, 0, teardata, 8);
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockno, current, 0, teardata, sizeof(teardata));
// we be getting ACK that we are silently ignoring here..
@ -3222,10 +3252,11 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Tear off reporting failure to select tag");
error_retries++;
continue;
}
got_post = false;
bool got_post = false;
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockno, 0, 0, NULL, 0);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
@ -3235,9 +3266,12 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
got_post = true;
}
}
if (got_pre && got_post) {
if (! got_post) {
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
error_retries++;
continue; // try again
}
error_retries = 0;
char prestr[20] = {0};
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
char poststr[20] = {0};
@ -3245,18 +3279,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
if (memcmp(pre, post, sizeof(pre)) == 0) {
PrintAndLogEx(INFO, "Current %02d (0x%02X) %s"
PrintAndLogEx(INFO, "Current : %02d (0x%02X) %s"
, blockno
, blockno
, poststr
);
} else {
// skip first message, since its the reset write.
if (current == start) {
PrintAndLogEx(INFO, "Inital write");
} else {
PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %02d (0x%02X) %s vs " _RED_("%s")
PrintAndLogEx(INFO, _CYAN_("Tear off occurred") " : %02d (0x%02X) %s => " _RED_("%s")
, blockno
, blockno
, prestr
@ -3265,27 +3294,27 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
lock_on = true;
if (phase_clear == -1)
phase_clear = current;
if ((phase_begin_clear == -1) && (bitcount32(*(uint32_t*)pre) > bitcount32(*(uint32_t*)post)))
phase_begin_clear = current;
if ((phase_begin_clear > -1) && (phase_end_clear == -1) && (bitcount32(*(uint32_t*)post) == 0))
phase_end_clear = current;
if ((current == start) && (phase_end_clear > -1))
skip_phase1 = true;
// new write phase must be atleast 100us later..
if (phase_clear > -1 && phase_newwr == -1 && current > (phase_clear + 100))
phase_newwr = current;
}
if (((bitcount32(*(uint32_t*)pre) == 0) || (phase_end_clear > -1)) && (phase_begin_newwr == -1) && (bitcount32(*(uint32_t*)post) != 0) && (skip_phase1 || (current > (phase_end_clear + 100))))
phase_begin_newwr = current;
if ((phase_begin_newwr > -1) && (phase_end_newwr == -1) && (memcmp(post, teardata, sizeof(teardata)) == 0))
phase_end_newwr = current;
}
if (use_match && memcmp(pre, match, sizeof(pre)) == 0) {
PrintAndLogEx(SUCCESS, "Block matches!\n");
if (use_match && memcmp(post, match, sizeof(post)) == 0) {
PrintAndLogEx(SUCCESS, "Block matches stop condition!\n");
break;
}
} else {
if (got_pre == false)
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
if (got_post == false)
PrintAndLogEx(FAILED, "Failed to read block AFTER");
}
/* TEMPORALLY DISABLED
uint8_t d0, d1, d2, d3;
d0 = *resp.data.asBytes;
@ -3314,11 +3343,17 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
}
PrintAndLogEx(INFO, "----------------------------------------------------");
if (phase_clear > - 1) {
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_clear);
if ((phase_begin_clear > - 1) && (phase_begin_clear != start)) {
PrintAndLogEx(INFO, "Erase phase start boundary around " _YELLOW_("%5d") " us", phase_begin_clear);
}
if (phase_newwr > - 1) {
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_newwr);
if ((phase_end_clear > - 1) && (phase_end_clear != start)){
PrintAndLogEx(INFO, "Erase phase end boundary around " _YELLOW_("%5d") " us", phase_end_clear);
}
if (phase_begin_newwr > - 1) {
PrintAndLogEx(INFO, "Write phase start boundary around " _YELLOW_("%5d") " us", phase_begin_newwr);
}
if (phase_end_newwr > - 1) {
PrintAndLogEx(INFO, "Write phase end boundary around " _YELLOW_("%5d") " us", phase_end_newwr);
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;

View file

@ -975,7 +975,7 @@ void pm3_version(bool verbose, bool oneliner) {
}
PrintAndLogEx(NORMAL, " device.................... %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _RED_("device / fw mismatch"));
PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("RDV4"));
PrintAndLogEx(NORMAL, " firmware.................. %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _YELLOW_("RDV4"));
PrintAndLogEx(NORMAL, " external flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));

View file

@ -768,6 +768,7 @@ int lfsim_upload_gb(void) {
break;
}
PrintAndLogEx(NORMAL, "." NOLF);
fflush(stdout);
payload_up.flag = 0;
}
PrintAndLogEx(NORMAL, "");
@ -1321,7 +1322,7 @@ static bool CheckChipType(bool getDeviceData) {
goto out;
}
PrintAndLogEx(NORMAL, "Couldn't identify a chipset");
PrintAndLogEx(INFO, "Couldn't identify a chipset");
out:
save_restoreGB(GRAPH_RESTORE);
save_restoreDB(GRAPH_RESTORE);

View file

@ -24,10 +24,10 @@ static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"410x", CmdLFEM410X, AlwaysAvailable, "EM 4102 commands..."},
{"4x05", CmdLFEM4X05, AlwaysAvailable, "EM 4205 / 4305 / 4369 / 4469 commands..."},
{"4x50", CmdLFEM4X50, AlwaysAvailable, "EM 4350 / 4450 commands..."},
{"4x70", CmdLFEM4X70, AlwaysAvailable, "EM 4070 / 4170 commands..."},
{"410x", CmdLFEM410X, AlwaysAvailable, "{ EM 4102 commands... }"},
{"4x05", CmdLFEM4X05, AlwaysAvailable, "{ EM 4205 / 4305 / 4369 / 4469 commands... }"},
{"4x50", CmdLFEM4X50, AlwaysAvailable, "{ EM 4350 / 4450 commands... }"},
{"4x70", CmdLFEM4X70, AlwaysAvailable, "{ EM 4070 / 4170 commands... }"},
{NULL, NULL, NULL, NULL}
};

View file

@ -1692,11 +1692,8 @@ int CmdEM4x05Unlock(const char *Cmd) {
}
// write
res = unlock_write_protect(use_pwd, pwd, write_value, verbose);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "failed unlock write");
return PM3_ESOFT;
}
// don't check the return value. As a tear-off occurred, the write failed.
unlock_write_protect(use_pwd, pwd, write_value, verbose);
// read after trigger
res = em4x05_read_word_ext(14, pwd, use_pwd, &word14);
@ -1962,11 +1959,11 @@ int CmdEM4x05Sniff(const char *Cmd) {
bool haveData, sampleData = true;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x05_sniff",
CLIParserInit(&ctx, "lf em 4x05 sniff",
"Sniff EM4x05 commands sent from a programmer",
"lf em 4x05_sniff -> sniff via lf sniff\n"
"lf em 4x05_sniff -1 -> sniff from data loaded into the buffer\n"
"lf em 4x05_sniff -r -> reverse the bit order when showing block data"
"lf em 4x05 sniff --> sniff via lf sniff\n"
"lf em 4x05 sniff -1 --> sniff from data loaded into the buffer\n"
"lf em 4x05 sniff -r --> reverse the bit order when showing block data"
);
void *argtable[] = {

View file

@ -471,7 +471,7 @@ int CmdEM4x50Chk(const char *Cmd) {
// upload to flash.
datalen = MIN(bytes_remaining, keyblock);
res = flashmem_spiffs_load(destfn, keys, datalen);
res = flashmem_spiffs_load((char*)destfn, keys, datalen);
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "SPIFFS upload failed");
return res;
@ -568,7 +568,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) {
int CmdEM4x50Read(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 read",
CLIParserInit(&ctx, "lf em 4x50 rdbl",
"Reads single EM4x50 block/word.",
"lf em 4x50 rdbl -b 3\n"
"lf em 4x50 rdbl -b 32 -p 12345678 -> reads block 32 with pwd 0x12345678\n"

View file

@ -118,16 +118,6 @@ static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *ext
}
}
static inline uint32_t bitcount(uint32_t a) {
#if defined __GNUC__
return __builtin_popcountl(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
}
// FDX-B ISO11784/85 demod (aka animal tag) BIPHASE, inverted, rf/32, with preamble of 00000000001 (128bits)
// 8 databits + 1 parity (1)
// CIITT 16 chksum
@ -594,7 +584,7 @@ int demodFDXB(bool verbose) {
uint8_t bt_par = (extended & 0x100) >> 8;
uint8_t bt_temperature = extended & 0xff;
uint8_t bt_calc_parity = (bitcount(bt_temperature) & 0x1) ? 0 : 1;
uint8_t bt_calc_parity = (bitcount32(bt_temperature) & 0x1) ? 0 : 1;
uint8_t is_bt_temperature = (bt_calc_parity == bt_par) && !(extended & 0xe00) ;
if (is_bt_temperature) {

View file

@ -113,19 +113,6 @@ static int usage_hitag_writer(void) {
PrintAndLogEx(NORMAL, " 27 <password> <page> <byte0...byte3> Write page, password mode. Default: 4D494B52 (\"MIKR\")");
return PM3_SUCCESS;
}
static int usage_hitag_checkchallenges(void) {
PrintAndLogEx(NORMAL, "Check challenges, load a file with save hitag crypto challenges and test them all.");
PrintAndLogEx(NORMAL, "The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`"));
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf hitag cc [h] f <filename w/o extension>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " f <filename> Load data from BIN file");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges");
return PM3_SUCCESS;
}
static int CmdLFHitagList(const char *Cmd) {
char args[128] = {0};
@ -614,50 +601,46 @@ static int CmdLFHitagReader(const char *Cmd) {
static int CmdLFHitagCheckChallenges(const char *Cmd) {
char filename[FILE_PATH_SIZE] = { 0x00 };
size_t datalen = 0;
int res = 0;
bool file_given = false;
bool errors = false;
uint8_t cmdp = 0;
uint8_t *data = calloc(8 * 60, sizeof(uint8_t));
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag cc",
"Check challenges, load a file with saved hitag crypto challenges and test them all.\n"
"The file should be 8 * 60 bytes long, the file extension defaults to " _YELLOW_("`.cc`") " ",
"lf hitag cc -f my_hitag_challenges"
);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
free(data);
return usage_hitag_checkchallenges();
case 'f':
//file with all the challenges to try
param_getstr(Cmd, cmdp + 1, filename, sizeof(filename));
res = loadFile(filename, ".cc", data, 8 * 60, &datalen);
if (res > 0) {
errors = true;
break;
}
file_given = true;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
void *argtable[] = {
arg_param_begin,
arg_str0("f", "filename", "<fn w/o ext>", "filename to load from"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
//Validations
if (errors || strlen(Cmd) == 0) {
free(data);
return usage_hitag_checkchallenges();
}
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
clearCommandBuffer();
if (file_given)
SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen);
else
SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
if (fnlen > 0) {
uint8_t *data = NULL;
size_t datalen = 0;
int res = loadFile_safe(filename, ".cc", (void **)&data, &datalen);
if (res == PM3_SUCCESS) {
if (datalen == (8 * 60) ) {
SendCommandOLD(CMD_LF_HITAGS_TEST_TRACES, 1, 0, 0, data, datalen);
} else {
PrintAndLogEx(ERR, "Error, file length mismatch. Expected %d, got %d", 8*60, datalen);
}
}
if (data) {
free(data);
}
} else {
SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
}
return PM3_SUCCESS;
}

View file

@ -37,20 +37,10 @@ const uint8_t translateTable[10] = {8, 2, 1, 12, 4, 5, 10, 13, 0, 9};
const uint8_t invTranslateTable[16] = {8, 2, 1, 0xff, 4, 5, 0xff, 0xff, 0, 9, 6, 0xff, 3, 7, 0xff, 0xff};
const uint8_t preamble[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}; // zero inside
static inline uint32_t bitcount(uint32_t a) {
#if defined __GNUC__
return __builtin_popcountl(a);
#else
a = a - ((a >> 1) & 0x55555555);
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
return (((a + (a >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24;
#endif
}
static uint8_t isEven_64_63(const uint8_t *data) { // 8
uint32_t tmp[2];
memcpy(tmp, data, 8);
return (bitcount(tmp[0]) + (bitcount(tmp[1] & 0xfeffffff))) & 1;
return (bitcount32(tmp[0]) + (bitcount32(tmp[1] & 0xfeffffff))) & 1;
}
//NEDAP demod - ASK/Biphase (or Diphase), RF/64 with preamble of 1111111110 (always a 128 bit data stream)
@ -252,25 +242,25 @@ static int CmdLFNedapDemod(const char *Cmd) {
configuration
lf t55xx wr b 0 d 00170082
lf t55xx wr -b 0 -d 00170082
1) uid 049033
lf t55 wr b 1 d FF8B4168
lf t55 wr b 2 d C90B5359
lf t55 wr b 3 d 19A40087
lf t55 wr b 4 d 120115CF
lf t55xx wr -b 1 -d FF8B4168
lf t55xx wr -b 2 -d C90B5359
lf t55xx wr -b 3 -d 19A40087
lf t55xx wr -b 4 -d 120115CF
2) uid 001630
lf t55 wr b 1 d FF8B6B20
lf t55 wr b 2 d F19B84A3
lf t55 wr b 3 d 18058007
lf t55 wr b 4 d 1200857C
lf t55xx wr -b 1 -d FF8B6B20
lf t55xx wr -b 2 -d F19B84A3
lf t55xx wr -b 3 -d 18058007
lf t55xx wr -b 4 -d 1200857C
3) uid 39feff
lf t55xx wr b 1 d ffbfa73e
lf t55xx wr b 2 d 4c0003ff
lf t55xx wr b 3 d ffbfa73e
lf t55xx wr b 4 d 4c0003ff
lf t55xx wr -b 1 -d ffbfa73e
lf t55xx wr -b 2 -d 4c0003ff
lf t55xx wr -b 3 -d ffbfa73e
lf t55xx wr -b 4 -d 4c0003ff
*/
@ -469,7 +459,7 @@ static int CmdLFNedapClone(const char *Cmd) {
if (res == PM3_SUCCESS) {
PrintAndLogEx(INFO, "The block 0 was changed (eXtended) which can be hard to detect.");
PrintAndLogEx(INFO, "Configure it manually " _YELLOW_("`lf t55xx config b 64 d BI i 1 o 32`"));
PrintAndLogEx(INFO, "Configure it manually " _YELLOW_("`lf t55xx config -b 64 --BI -i -o 32`"));
} else {
PrintAndLogEx(NORMAL, "");
}

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@
#define T55X7_NORALSY_CONFIG_BLOCK 0x00088C6A // ASK, compat mode, (NORALSY - KCP3000), data rate 32, 3 data blocks
#define T55X7_PRESCO_CONFIG_BLOCK 0x00088088 // ASK, data rate 32, Manchester, 4 data blocks, STT
#define T55X7_SECURAKEY_CONFIG_BLOCK 0x000C8060 // ASK, Manchester, data rate 40, 3 data blocks
#define T55X7_UNK_CONFIG_BLOCK 0x000880FA // ASK, Manchester, data rate 32, 7 data blocks STT, Inverse ...
// FDXB requires data inversion and BiPhase 57 is simply BiPhase 50 inverted, so we can either do it using the modulation scheme or the inversion flag
// we've done both below to prove that it works either way, and the modulation value for BiPhase 50 in the Atmel data sheet of binary "10001" (17) is a typo,
@ -126,10 +127,10 @@ typedef struct {
uint8_t offset;
uint32_t block0;
enum {
notSet = 0x00,
autoDetect = 0x01,
userSet = 0x02,
tagRead = 0x03,
NOTSET = 0x00,
AUTODETECT = 0x01,
USERSET = 0x02,
TAGREAD = 0x03,
} block0Status;
enum {
RF_8 = 0x00,

View file

@ -298,10 +298,10 @@ static command_t CommandTable[] = {
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"},
{"auto", CmdAuto, IfPm3Present, "Automated detection process for unknown tags"},
{"clear", CmdClear, AlwaysAvailable, "Clear screen"},
{"help", CmdHelp, AlwaysAvailable, "This help. Use " _YELLOW_("'<command> help'") " for details of a particular command."},
{"help", CmdHelp, AlwaysAvailable, "Use " _YELLOW_("'<command> help'") " for details of a particular command."},
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
{"pref", CmdPref, AlwaysAvailable, "Edit preferences"},
{"pref", CmdPref, AlwaysAvailable, "{ Edit preferences... }"},
{"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"},
{"quit", CmdQuit, AlwaysAvailable, ""},
{"exit", CmdQuit, AlwaysAvailable, "Exit program"},

View file

@ -429,9 +429,9 @@ static int CmdScriptRun(const char *Cmd) {
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "Usage info"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdScriptList, AlwaysAvailable, "List available scripts"},
{"run", CmdScriptRun, AlwaysAvailable, "<name> -- execute a script"},
{"run", CmdScriptRun, AlwaysAvailable, "<name> - execute a script"},
{NULL, NULL, NULL, NULL}
};

View file

@ -242,7 +242,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
}
for (int j = 0; j < data_len && j / 18 < 18; j++) {
uint8_t parityBits = parityBytes[j >> 3];
if (protocol != LEGIC
&& protocol != ISO_14443B
@ -256,7 +255,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
&& protocol != FELICA
&& protocol != LTO
&& protocol != PROTO_CRYPTORF
&& (hdr->isResponse || protocol == ISO_14443A)
&& (hdr->isResponse || protocol == ISO_14443A || protocol == PROTO_MIFARE)
&& (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) {
snprintf(line[j / 18] + ((j % 18) * 4), 120, "%02x! ", frame[j]);
@ -280,9 +279,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
if (markCRCBytes) {
//CRC-command
if (crcStatus == 0 || crcStatus == 1) {
char *pos1 = line[(data_len - 2) / 18] + (((data_len - 2) % 18) * 4);
char *pos1 = line[(data_len - 2) / 18] + (((data_len - 2) % 18) * 4) - 1;
(*pos1) = '[';
char *pos2 = line[(data_len) / 18] + (((data_len) % 18) * 4);
char *pos2 = line[(data_len) / 18] + (((data_len) % 18) * 4) - 1;
sprintf(pos2, "%c", ']');
}
}

View file

@ -839,6 +839,9 @@ static bool dl_it(uint8_t *dest, uint32_t bytes, PacketResponseNG *response, siz
if (response->cmd == CMD_ACK)
return true;
// Spiffs download is converted to NG,
if (response->cmd == CMD_SPIFFS_DOWNLOAD)
return true;
// sample_buf is a array pointer, located in data.c
// arg0 = offset in transfer. Startindex of this chunk

View file

@ -412,7 +412,7 @@ static void flash_suggest_update_bootloader(void) {
PrintAndLogEx(ERR, _RED_("reboot the Proxmark3 then only update the main firmware") "\n");
PrintAndLogEx(ERR, "Follow these steps :");
PrintAndLogEx(ERR, " 1) ./pm3-flash-bootrom");
PrintAndLogEx(ERR, " 2) ./pm3-flash-flash-all");
PrintAndLogEx(ERR, " 2) ./pm3-flash-all");
PrintAndLogEx(ERR, " 3) ./pm3");
PrintAndLogEx(INFO, "--------------------------------------------------------");
g_printed_msg = true;

View file

@ -695,7 +695,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
mem[4] = (chunk & 0xFF);
// upload to flash.
res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6));
res = flashmem_spiffs_load((char*)destfn, mem, 5 + (chunk * 6));
if (res != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "\nSPIFFS upload failed");
free(mem);

View file

@ -761,7 +761,7 @@ static int setCmdHint(const char *Cmd) {
static int setCmdPlotSliders(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref set plotsliders ",
CLIParserInit(&ctx, "pref set plotsliders",
"Set presistent preference of showing the plotslider control in the client",
"pref set plotsliders --on"
);
@ -803,7 +803,7 @@ static int setCmdPlotSliders(const char *Cmd) {
static int setCmdSavePaths(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref set savepath",
CLIParserInit(&ctx, "pref set savepaths",
"Set presistent preference of file paths in the client",
"pref set savepaths --dump /home/mydumpfolder -> all dump files will be saved into this folder\n"
"pref set savepaths --def /home/myfolder -c -> create if needed, all files will be saved into this folder"
@ -930,36 +930,113 @@ static int setCmdBarMode(const char *Cmd) {
}
static int getCmdEmoji(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get emoji",
"Get preference of using emojis in the client",
"pref get emoji"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showEmojiState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdHint(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get hints",
"Get preference of showing hint messages in the client",
"pref get hints"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showHintsState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdColor(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get color",
"Get preference of using colors in the client",
"pref get color"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showColorState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdDebug(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get clientdebug",
"Get preference of using clientside debug level",
"pref get clientdebug"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showClientDebugState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdPlotSlider(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get plotsliders",
"Get preference of showing the plotslider control in the client",
"pref get plotsliders"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showPlotSliderState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdBarMode(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get barmode",
"Get preference of HF/LF tune command styled output in the client",
"pref get barmode"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showBarModeState(prefShowNone);
return PM3_SUCCESS;
}
static int getCmdSavePaths(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref get savepaths",
"Get preference of file paths in the client",
"pref get savepaths"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
showSavePathState(spDefault, prefShowNone);
showSavePathState(spDump, prefShowNone);
showSavePathState(spTrace, prefShowNone);
@ -1008,6 +1085,17 @@ static int CmdPrefSet(const char *Cmd) {
}
static int CmdPrefShow(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "pref show",
"Show all persistent preferences",
"pref show"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
if (session.preferences_loaded) {
char *fn = prefGetFilename();
@ -1043,8 +1131,8 @@ static int CmdPrefSave (const char *Cmd) {
*/
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"get", CmdPrefGet, AlwaysAvailable, "Get a preference"},
{"set", CmdPrefSet, AlwaysAvailable, "Set a preference"},
{"get", CmdPrefGet, AlwaysAvailable, "{ Get a preference }"},
{"set", CmdPrefSet, AlwaysAvailable, "{ Set a preference }"},
{"show", CmdPrefShow, AlwaysAvailable, "Show all preferences"},
{NULL, NULL, NULL, NULL}
};

View file

@ -183,45 +183,54 @@ void print_hex(const uint8_t *data, const size_t len) {
}
void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
if (data == NULL || len == 0) return;
if (data == NULL || len == 0 || breaks == 0) return;
int rownum = 0;
PrintAndLogEx(NORMAL, "[%02d] | " NOLF, rownum);
for (size_t i = 0; i < len; ++i) {
PrintAndLogEx(NORMAL, "%02X " NOLF, data[i]);
// check if a line break is needed
if (breaks > 0 && !((i + 1) % breaks) && (i + 1 < len)) {
++rownum;
PrintAndLogEx(NORMAL, "\n[%02d] | " NOLF, rownum);
uint16_t rownum = 0;
int i;
for (i = 0; i < len; i += breaks, rownum++) {
if (len - i < breaks) { // incomplete block, will be treated out of the loop
break;
}
PrintAndLogEx(INFO, "%02u | %s", rownum, sprint_hex_ascii(data + i, breaks));
}
// the last odd bytes
uint8_t mod = len % breaks;
if (mod) {
char buf[UTIL_BUFFER_SIZE_SPRINT + 3];
memset(buf, 0, sizeof(buf));
hex_to_buffer((uint8_t *)buf, data + i, mod, (sizeof(buf) - 1), 0, 1, true);
// add the spaces...
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((breaks - mod) * 3), " ");
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, mod));
PrintAndLogEx(INFO, "%02u | %s", rownum, buf);
}
PrintAndLogEx(NORMAL, "");
}
void print_buffer(const uint8_t *data, const size_t len, int level) {
static void print_buffer_ex(const uint8_t *data, const size_t len, int level, uint8_t breaks) {
if (len < 1)
return;
char buf[UTIL_BUFFER_SIZE_SPRINT + 3];
int i;
for (i = 0; i < len; i += 16) {
if (len - i < 16) { // incomplete block, will be treated out of the loop
for (i = 0; i < len; i += breaks) {
if (len - i < breaks) { // incomplete block, will be treated out of the loop
break;
}
// (16 * 3) + (16) + + 1
memset(buf, 0, sizeof(buf));
sprintf(buf, "%*s%02x: ", (level * 4), " ", i);
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, 16, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, 16));
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, breaks, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, breaks));
PrintAndLogEx(INFO, "%s", buf);
}
// the last odd bytes
uint8_t mod = len % 16;
uint8_t mod = len % breaks;
if (mod) {
memset(buf, 0, sizeof(buf));
@ -229,13 +238,17 @@ void print_buffer(const uint8_t *data, const size_t len, int level) {
hex_to_buffer((uint8_t *)(buf + strlen(buf)), data + i, mod, (sizeof(buf) - strlen(buf) - 1), 0, 1, true);
// add the spaces...
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((16 - mod) * 3), " ");
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%*s", ((breaks - mod) * 3), " ");
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "| %s", sprint_ascii(data + i, mod));
PrintAndLogEx(INFO, "%s", buf);
}
}
void print_buffer(const uint8_t *data, const size_t len, int level) {
print_buffer_ex(data, len, level, 16);
}
void print_blocks(uint32_t *data, size_t len) {
PrintAndLogEx(SUCCESS, "Blk | Data ");
PrintAndLogEx(SUCCESS, "----+------------");

View file

@ -1,8 +1,9 @@
# T5577 Introduction Guide
### Based on RRG proxmark3 fork.
### Based on RRG/Iceman Proxmark3 repo
### Ver.1 8 Sep 2019
### Ver.2 7 March 2021
| Contents |
| ----------------------------------------------------------------------------------- |
@ -23,17 +24,17 @@
## Introduction
The T5577 is a generic LF (Low Frequency) RFID card the is used in the
The T5577 is a generic LF (Low Frequency) RFID card that is used in the
125 Khz frequency space. It is a good card to use to learn about RFID and
learn how to use the proxmark3.
It is highly recommend that when learning about RFID that learning how
It is highly recommended that when learning about RFID that learning how
to read the data sheets be near the top of the list. It can be very hard
as the data sheet will hold the information you need, but you dont yet
know what it means. As such, I will attempt to point to sections of the
data sheet and would highly advise that you look at the data sheet as
you go. Overtime the data sheet may change, as a result things may not
always be reference correctly.
always be referenced correctly.
As at writing this guide, the data sheet can be found at :
@ -63,9 +64,9 @@ the chip how to behave.
## What data is on my T5577
Lets have a look and see what a card might look in the proxmark3
Lets have a look and see what a card might look like in the proxmark3
software. Since we can change the configuration of how the T5577 will
output data, the proxmark3 software need to work out how to interpreted
output data, the proxmark3 software needs to work out how to interpret
the data it receives, we do this with the following command.
It should be noted that the T5577 has many clones. As such the default
@ -77,16 +78,18 @@ examples shown, it will be assumed you have run the detect command.
```
[usb] pm3 --> lf t55xx detect
```
You should see a results simular to the following:
You should see a results similar to the following:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x000880E0
Downlink Mode : default/fixed bit length
[=] Chip type......... T55x7
[=] Modulation........ ASK
[=] Bit rate.......... 2 - RF/32
[=] Inverted.......... No
[=] Offset............ 33
[=] Seq. terminator... Yes
[=] Block0............ 000880E0 (auto detect)
[=] Downlink mode..... default/fixed bit length
[=] Password set...... No
```
Now that the proxmark3 has detected a T55x7 chip, and found some
information about it, we should be able to see all the data on the chip.
@ -99,20 +102,20 @@ Your results should look similar to the following:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
[+] 04 | 00000000 | 00000000000000000000000000000000 | ....
[+] 05 | 00000000 | 00000000000000000000000000000000 | ....
[+] 06 | 00000000 | 00000000000000000000000000000000 | ....
[+] 07 | 00000000 | 00000000000000000000000000000000 | ....
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
```
I will cover the meaning of this data as we go, but for now, lets keep
it simple.
@ -123,7 +126,7 @@ The basic function of using the proxmark3 with rfid cards is to read and
write data. This reading and writing must be done in the correct way
needed for the chip (and its configuration). Lucky for us, the
developers have done a great job and gave us commands. What we need to
know is that with the T5577 data is read/written one complete block at a
know is that with the T5577, data is read/written one complete block at a
time. Each block holds 32 bits of data (hence the binary output shown)
Since we know that the card has data and configuration blocks, lets say
@ -140,23 +143,23 @@ can see the card)
as, run a low frequency (lf) command for the T55xx chip (t55xx) and
read block (b) number 1.
```
[usb] pm3 --> lf t55xx read b 1
[usb] pm3 --> lf t55xx read -b 1
```
result:
```
[+] Reading Page 0:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
```
Note: Depending on the history of your card your data may vary, but
Note: Depending on the history of your card, your data may vary, but
should match the dump data.
2) Write some new data into block 1 on the card.
We use the d option to supply the data 12345678
We use the -d option to supply the data 12345678
```
[usb] pm3 --> lf t55xx write b 1 d 12345678
[usb] pm3 --> lf t55xx write -b 1 -d 12345678
```
result:
```
@ -164,7 +167,7 @@ can see the card)
```
3) Now, lets check if the data was written.
```
[usb] pm3 --> lf t55xx read b 1
[usb] pm3 --> lf t55xx read -b 1
```
result:
```
@ -174,8 +177,8 @@ can see the card)
[+] 01 | 12345678 | 00010010001101000101011001111000 | .4Vx
```
4) The data is written in Hexadecimal. A single hex digit holds 4 bits
of data. So to store 32 bits in a block we need to supply 8 hex
digits (8 \* 4 = 32). If you are familiar with hex and binary do a
of data. So to store 32 bits in a block, we need to supply 8 hex
digits (8 \* 4 = 32). If you are not familiar with hex and binary do a
little bit of home work to learn. The following is a quick start.
| Hex | Binary | Decimal |
@ -202,7 +205,7 @@ can see the card)
Lets try and write 89ABCDEF
```
[usb] pm3 --> lf t55xx write b 1 d 89abcdef
[usb] pm3 --> lf t55xx write -b 1 -d 89abcdef
```
result:
```
@ -210,7 +213,7 @@ can see the card)
```
and check
```
[usb] pm3 --> lf t55xx read b 1
[usb] pm3 --> lf t55xx read -b 1
```
result:
```
@ -235,31 +238,34 @@ result:
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | 89ABCDEF | 10001001101010111100110111101111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 07 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
[+] 04 | 00000000 | 00000000000000000000000000000000 | ....
[+] 05 | 00000000 | 00000000000000000000000000000000 | ....
[+] 06 | 00000000 | 00000000000000000000000000000000 | ....
[+] 07 | 00000000 | 00000000000000000000000000000000 | ....
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
```
Practice reading and writing to blocks 1 to 7 until you are happy you
Practice reading and writing to blocks 1 to 6 until you are happy you
can do it and get the results you wanted (i.e. the data you want stored
is written to the block you want it stored in).
is written to the block you want it stored in). I recommend staying
away from block 7 as this is where the password is stored, if used.
If you forget this data/password, you wont be able to read or write
to the card.
## How do I use a password
This can be a little tricky for beginners.
***If you forget your password you will lose access to your card***.
To tell the T5577 to use a password we have to change the data in the
To tell the T5577 to use a password, we have to change the data in the
configuration block (0). To help learn this and make it as simple as I
can, please read and follow exactly. If your results DONT match 100% as
required, please do not proceed.
@ -272,9 +278,10 @@ required, please do not proceed.
```
Result:
```
[=] Begin wiping T55x7 tag
[=] Target T55x7 tag
[=] Default configuration block 000880E0
[=] Default configation block 000880E0
[=] Begin wiping...
[=] Writing page 0 block: 00 data: 0x000880E0
[=] Writing page 0 block: 01 data: 0x00000000
[=] Writing page 0 block: 02 data: 0x00000000
@ -291,14 +298,15 @@ required, please do not proceed.
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x000880E0
Downlink Mode : default/fixed bit length
[=] Chip type......... T55x7
[=] Modulation........ ASK
[=] Bit rate.......... 2 - RF/32
[=] Inverted.......... No
[=] Offset............ 33
[=] Seq. terminator... Yes
[=] Block0............ 000880E0 (auto detect)
[=] Downlink mode..... default/fixed bit length
[=] Password set...... No
```
If block 0 does not hold the hex data **0x00088040 resolve this
@ -309,7 +317,7 @@ required, please do not proceed.
The password is saved in block 7 of page 0.
```
[usb] pm3 --> lf t55xx write b 7 d 12345678
[usb] pm3 --> lf t55xx write -b 7 -d 12345678
```
result:
```
@ -326,20 +334,20 @@ required, please do not proceed.
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 02 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 04 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 05 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 06 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
[+] 04 | 00000000 | 00000000000000000000000000000000 | ....
[+] 05 | 00000000 | 00000000000000000000000000000000 | ....
[+] 06 | 00000000 | 00000000000000000000000000000000 | ....
[+] 07 | 12345678 | 00010010001101000101011001111000 | .4Vx
[+] Reading Page 1:
[+] blk | hex data | binary | ascii
[+] ----+----------+----------------------------------+-------
[+] 00 | 000880E0 | 00000000000010001000000011100000 | ....
[+] 01 | E0150A48 | 11100000000101010000101001001000 | ...H
[+] 02 | 2D782308 | 00101101011110000010001100001000 | -x#.
[+] 03 | FFFFFFFF | 11111111111111111111111111111111 | ....
[+] 01 | 00000000 | 00000000000000000000000000000000 | ....
[+] 02 | 00000000 | 00000000000000000000000000000000 | ....
[+] 03 | 00000000 | 00000000000000000000000000000000 | ....
```
***Important : If block 0 and block 7 dont match exactly, do not continue.***
@ -353,7 +361,7 @@ required, please do not proceed.
![](./t55xx_block0.png)
We will cover other things in the configuration later. But the key
note here is we ONLY want to change bit 28 and nothing else.
note here, is we ONLY want to change bit 28 and nothing else.
Current Block 0 : ***00088040***
New Block 0 : ***00088050***
@ -361,7 +369,7 @@ required, please do not proceed.
To understand what happened to get from 00088040 to 00088050 we need
to look at the binary data.
While this can be confusing it is important to understand this as we
While this can be confusing, it is important to understand this as we
do more advanced things.
Bit Location (28)
@ -375,7 +383,7 @@ required, please do not proceed.
See how in the above we change the bit in location 28 from a 0 to 1
See how in the above we changed the bit in location 28 from a 0 to 1
0 = No Password, 1 = Use Password
Note how we did NOT change any other part of the configuration, only bit 28.
@ -389,7 +397,7 @@ required, please do not proceed.
If you have completed all steps and have the exact same results, we are
ready to apply the new configuration.
```
[usb] pm3 --> lf t55xx write b 0 d 00088050
[usb] pm3 --> lf t55xx write -b 0 -d 00088050
```
result:
```
@ -410,25 +418,27 @@ required, please do not proceed.
card.
Lets try again, but this time supply the password. We use the option
p followed by the password.
-p followed by the password.
```
[usb] pm3 --> lf t55 detect p 12345678
[usb] pm3 --> lf t55 detect -p 12345678
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00088050
Downlink Mode : default/fixed bit length
[=] Chip type......... T55x7
[=] Modulation........ ASK
[=] Bit rate.......... 2 - RF/32
[=] Inverted.......... No
[=] Offset............ 33
[=] Seq. terminator... Yes
[=] Block0............ 00088050 (auto detect)
[=] Downlink mode..... default/fixed bit length
[=] Password set...... Yes
[=] Password.......... 12345678
```
7) Write a block of data with a password
```
[usb] pm3 --> lf t55xx write b 1 d 1234abcd p 12345678
[usb] pm3 --> lf t55xx write -b 1 -d 1234abcd -p 12345678
```
result:
```
@ -445,7 +455,7 @@ required, please do not proceed.
The proxmark3 has a safety check\!
```
[usb] pm3 --> lf t55xx read b 1 p 12345678
[usb] pm3 --> lf t55xx read -b 1 -p 12345678
```
result:
```
@ -455,12 +465,12 @@ required, please do not proceed.
[!] Safety check: Could not detect if PWD bit is set in config block. Exits.
```
Note that the proxmark3 did not read the block, the safty kicked in
and wants us to confirm by supply the override option o.
Note that the proxmark3 did not read the block, the safety kicked in
and wants us to confirm by supply the override option -o.
Lets try again with the o option as we know the password is set.
Lets try again with the -o option as we know the password is set.
```
[usb] pm3 --> lf t55xx read b 1 p 12345678 o
[usb] pm3 --> lf t55xx read -b 1 -p 12345678 -o
```
result:
```
@ -479,14 +489,14 @@ required, please do not proceed.
this from above.
Remember if we dont know the config and write this config to the
card, it will over write all other settings. This can recoved the
card, it will overwrite all other settings. This can recover the
card, but will lose any settings you may want. So its a good idea
to read the config, and set bit 28 to 0, rather than just overwrite
the config and change the way the card works.
In our examples we know what it should be : 00088040
```
[usb] pm3 --> lf t55xx write b 0 d 00088040 p 12345678
[usb] pm3 --> lf t55xx write -b 0 -d 00088040 -p 12345678
```
result:
```
@ -498,16 +508,17 @@ required, please do not proceed.
```
result:
```
Chip Type : T55x7
Modulation : ASK
Bit Rate : 2 - RF/32
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00088040
Downlink Mode : default/fixed bit length
[=] Chip type......... T55x7
[=] Modulation........ ASK
[=] Bit rate.......... 2 - RF/32
[=] Inverted.......... No
[=] Offset............ 33
[=] Seq. terminator... Yes
[=] Block0............ 00088040 (auto detect)
[=] Downlink mode..... default/fixed bit length
[=] Password set...... No
```
Yes we can and we can see Block 0 is the correct config 00088040
Yes we can! We can see Block 0 is the correct config 00088040
# Part 2 Configuration Blocks
@ -523,7 +534,7 @@ from Block 0 in Page 0. It will use this in both default read mode
(where is sends out the blocks from 1 to x on power up), as well as when
it responds to commands.
In the Read To Card, the T5577 will encode the data using the settings
In the Reader To Card, the T5577 will encode the data using the settings
from Block 3 Page 1. If the command is not encoded correctly it will
ignore the command and revert back to default read mode.
@ -533,10 +544,10 @@ For this configuration the settings chosen will be for the purpose of
the card when used in production. E.G. If you want the card to act like
an EM4100, then we need to choose the settings that work like the
EM4100; same goes for others like HID. I am not going to cover these
here, rather use an example. Others have collect these and posted on the
forum.
here, rather use an example. Others have collected these and posted on the
forum or can be found by searching the web.
To get started lets look back at the tech sheet.
To get started lets look back at the data sheet.
![](./t55xx_clock0_cfg.png)
@ -571,14 +582,15 @@ password set (if not, review and get you card back to this state).
1) Lets turn you T5577 into an EM4100 with ID 1122334455
```
[usb] pm3 --> lf em 410x_write 1122334455 1
[usb] pm3 --> lf em 410x clone --id 1122334455
```
result:
```
[+] Writing T55x7 tag with UID 0x1122334455 (clock rate: 64)
#db# Started writing T55x7 tag ...
#db# Clock rate: 64
#db# Tag T55x7 written with 0xff8c65298c94a940
[+] Preparing to clone EM4102 to T55x7 tag with ID 1122334455 (RF/64)
[#] Clock rate: 64
[#] Tag T55x7 written with 0xff8c65298c94a940
[+] Done
```
2) Check this has work.
@ -592,54 +604,50 @@ password set (if not, review and get you card back to this state).
[=] False Positives ARE possible
[=]
[=] Checking for known tags...
[+] EM410x pattern found
EM TAG ID : 1122334455
Possible de-scramble patterns
Unique TAG ID : 8844CC22AA
HoneyWell IdentKey {
DEZ 8 : 03359829
DEZ 10 : 0573785173
DEZ 5.5 : 08755.17493
DEZ 3.5A : 017.17493
DEZ 3.5B : 034.17493
DEZ 3.5C : 051.17493
DEZ 14/IK2 : 00073588229205
DEZ 15/IK3 : 000585269781162
DEZ 20/ZK : 08080404121202021010
}
Other : 17493_051_03359829
Pattern Paxton : 289899093 [0x11478255]
Pattern 1 : 5931804 [0x5A831C]
Pattern Sebury : 17493 51 3359829 [0x4455 0x33 0x334455]
[=]
[+] EM 410x ID 0F0368568B
[+] EM410x ( RF/64 )
[=] -------- Possible de-scramble patterns ---------
[+] Unique TAG ID : F0C0166AD1
[=] HoneyWell IdentKey
[+] DEZ 8 : 06837899
[+] DEZ 10 : 0057169547
[+] DEZ 5.5 : 00872.22155
[+] DEZ 3.5A : 015.22155
[+] DEZ 3.5B : 003.22155
[+] DEZ 3.5C : 104.22155
[+] DEZ 14/IK2 : 00064481678987
[+] DEZ 15/IK3 : 001034014845649
[+] DEZ 20/ZK : 15001200010606101301
[=]
[+] Other : 22155_104_06837899
[+] Pattern Paxton : 259822731 [0xF7C948B]
[+] Pattern 1 : 9750181 [0x94C6A5]
[+] Pattern Sebury : 22155 104 6837899 [0x568B 0x68 0x68568B]
[=] ------------------------------------------------
[+] Valid EM410x ID found!
[+] Chipset detection : T55xx found
[+] Try `lf t55xx` commands
[+] Chipset detection: T55xx
[?] Hint: try `lf t55xx` commands
```
Looks good.
3) Now lest see what the T5577 detect and info shows
3) Now lets see what the T5577 detect and info shows
```
[usb] pm3 --> lf t55 detect
```
result:
```
[usb] pm3 --> lf t55 detect
Chip Type : T55x7
Modulation : ASK
Bit Rate : 5 - RF/64
Inverted : No
Offset : 32
Seq. Term. : Yes
Block0 : 0x00148040
Downlink Mode : default/fixed bit length
[=] Chip type......... T55x7
[=] Modulation........ ASK
[=] Bit rate.......... 5 - RF/64
[=] Inverted.......... No
[=] Offset............ 33
[=] Seq. terminator... Yes
[=] Block0............ 00148040 (auto detect)
[=] Downlink mode..... default/fixed bit length
[=] Password set...... No
```
```
[usb] pm3 --> lf t55xx info
@ -647,28 +655,27 @@ password set (if not, review and get you card back to this state).
result:
```
-- T55x7 Configuration & Tag Information --------------------
-------------------------------------------------------------
Safer key : 0
reserved : 0
Data bit rate : 5 - RF/64
eXtended mode : No
Modulation : 8 - Manchester
PSK clock frequency : 0 - RF/2
AOR - Answer on Request : No
OTP - One Time Pad : No
Max block : 2
Password mode : No
Sequence Terminator : No
Fast Write : No
Inverse data : No
POR-Delay : No
-------------------------------------------------------------
Raw Data - Page 0
Block 0 : 0x00148040 00000000000101001000000001000000
[=] --- T55x7 Configuration & Information ---------
[=] Safer key : 0
[=] reserved : 0
[=] Data bit rate : 5 - RF/64
[=] eXtended mode : No
[=] Modulation : 8 - Manchester
[=] PSK clock frequency : 0 - RF/2
[=] AOR - Answer on Request : No
[=] OTP - One Time Pad : No
[=] Max block : 2
[=] Password mode : No
[=] Sequence Terminator : No
[=] Fast Write : No
[=] Inverse data : No
[=] POR-Delay : No
[=] -------------------------------------------------------------
[=] Raw Data - Page 0, block 0
[=] 00148040 - 00000000000101001000000001000000
[=] --- Fingerprint ------------
[+] Config block match : EM unique, Paxton
Config block match : EM unique, Paxton
-------------------------------------------------------------
```
We can see that the info gave us more information and confirmed what
we decoded by hand. But remember, the detect is still needed so the

View file

@ -561,7 +561,7 @@ EM is ASK
HID Prox is FSK
Indala is PSK
pm3 --> lf t55xx config FSK
pm3 --> lf t55xx config --FSK
```
Set timings to default
@ -579,7 +579,7 @@ Write to T55xx block
b <block> : block number to write. Between 0-7
d <data> : 4 bytes of data to write (8 hex characters)
pm3 --> lf t55xx wr b 0 d 00081040
pm3 --> lf t55xx wr -b 0 -d 00081040
```
Wipe a T55xx tag and set defaults

View file

@ -1,5 +1,4 @@
clear
pref
analyse foo
data biphaserawdecode
data detectclock
@ -32,7 +31,6 @@ data print
data samples
data setdebugmode
data tune
hf 14b sriwrite
hf 15 dump
hf 15 info
hf 15 raw
@ -85,21 +83,6 @@ hf mf cview
hf mf gen3uid
hf mf gen3blk
hf mf gen3freeze
lf em 410x
lf em 4x05
lf em 4x50
lf em 4x70
lf hitag reader
lf hitag sim
lf hitag writer
lf hitag dump
lf hitag cc
lf t55xx config
lf t55xx dump
lf t55xx info
lf t55xx read
lf t55xx resetread
lf t55xx restore
lf t55xx trace
lf t55xx write
script run

View file

@ -60,8 +60,8 @@ Standard password is normally (for T55xx): AA55BBBB
# Restore page1 data
```
lf t55xx write b 1 d E0150A48 1
If t55xx write b 2 d 2D782308 1
lf t55xx write -b 1 -d E0150A48 --pg1
If t55xx write -b 2 -d 2D782308 --pg1
```
# Sniffing the comms
@ -69,12 +69,12 @@ The T55x7 protocol uses a pwm based protocol for writing to tags. In order to m
```
-- after threshold limit 20 is triggered, skip 10000 samples before collecting samples.
lf config s 10000 t 20
lf config -s 10000 -t 20
lf t55xx sniff
-- if you have a save trace from before, try
data load -f xxxxxxx.pm3
lf t55xx sniff 1
lf t55xx sniff -1
```
It uses the existing `lf sniff` command to collect the data, so setting that first as per normal sniffing is recommended. Once you have a sniff, you can "re-sniff" from the stored sniffed data and try different settings, if you think the data is not clean.

View file

@ -12,10 +12,9 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`auto `|N |`Automated detection process for unknown tags`
|`clear `|Y |`Clear screen`
|`help `|Y |`This help. Use '<command> help' for details of a particular command.`
|`help `|Y |`Use '<command> help' for details of a particular command.`
|`hints `|Y |`Turn hints on / off`
|`msleep `|Y |`Add a pause in milliseconds`
|`pref `|Y |`Edit preferences`
|`rem `|Y |`Add a text line in log file`
|`quit `|Y |``
|`exit `|Y |`Exit program`
@ -606,10 +605,80 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`lf em help `|Y |`This help`
|`lf em 410x `|Y |`EM 4102 commands...`
|`lf em 4x05 `|Y |`EM 4205 / 4305 / 4369 / 4469 commands...`
|`lf em 4x50 `|Y |`EM 4350 / 4450 commands...`
|`lf em 4x70 `|Y |`EM 4070 / 4170 commands...`
### lf em 410x
{ EM 4102 commands... }
|command |offline |description
|------- |------- |-----------
|`lf em 410x help `|Y |`This help`
|`lf em 410x demod `|Y |`demodulate a EM410x tag from the GraphBuffer`
|`lf em 410x reader `|N |`attempt to read and extract tag data`
|`lf em 410x sim `|N |`simulate EM410x tag`
|`lf em 410x brute `|N |`reader bruteforce attack by simulating EM410x tags`
|`lf em 410x watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)`
|`lf em 410x spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)`
|`lf em 410x clone `|N |`write EM410x UID to T55x7 or Q5/T5555 tag`
### lf em 4x05
{ EM 4205 / 4305 / 4369 / 4469 commands... }
|command |offline |description
|------- |------- |-----------
|`lf em 4x05 help `|Y |`This help`
|`lf em 4x05 brute `|N |`Bruteforce password`
|`lf em 4x05 chk `|N |`Check passwords from dictionary`
|`lf em 4x05 demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer`
|`lf em 4x05 dump `|N |`dump EM4x05/EM4x69 tag`
|`lf em 4x05 info `|N |`tag information EM4x05/EM4x69`
|`lf em 4x05 read `|N |`read word data from EM4x05/EM4x69`
|`lf em 4x05 sniff `|Y |`Attempt to recover em4x05 commands from sample buffer`
|`lf em 4x05 unlock `|N |`execute tear off against EM4x05/EM4x69`
|`lf em 4x05 wipe `|N |`wipe EM4x05/EM4x69 tag`
|`lf em 4x05 write `|N |`write word data to EM4x05/EM4x69`
### lf em 4x50
{ EM 4350 / 4450 commands... }
|command |offline |description
|------- |------- |-----------
|`lf em 4x50 help `|Y |`This help`
|`lf em 4x50 brute `|N |`guess password of EM4x50`
|`lf em 4x50 chk `|N |`check passwords from dictionary`
|`lf em 4x50 dump `|N |`dump EM4x50 tag`
|`lf em 4x50 info `|N |`tag information EM4x50`
|`lf em 4x50 login `|N |`login into EM4x50`
|`lf em 4x50 rdbl `|N |`read word data from EM4x50`
|`lf em 4x50 wrbl `|N |`write word data to EM4x50`
|`lf em 4x50 writepwd `|N |`change password of EM4x50`
|`lf em 4x50 wipe `|N |`wipe EM4x50 tag`
|`lf em 4x50 reader `|N |`show standard read mode data of EM4x50`
|`lf em 4x50 restore `|N |`restore EM4x50 dump to tag`
|`lf em 4x50 sim `|N |`simulate EM4x50 tag`
|`lf em 4x50 eload `|N |`upload dump of EM4x50 to emulator memory`
|`lf em 4x50 esave `|N |`save emulator memory to file`
|`lf em 4x50 eview `|N |`view EM4x50 content in emulator memory`
### lf em 4x70
{ EM 4070 / 4170 commands... }
|command |offline |description
|------- |------- |-----------
|`lf em 4x70 help `|Y |`This help`
|`lf em 4x70 info `|N |`Tag information EM4x70`
|`lf em 4x70 write `|N |`Write EM4x70`
|`lf em 4x70 unlock `|N |`Unlock EM4x70 for writing`
|`lf em 4x70 auth `|N |`Authenticate EM4x70`
|`lf em 4x70 writepin `|N |`Write PIN`
|`lf em 4x70 writekey `|N |`Write Crypt Key`
### lf fdxb
@ -673,6 +742,7 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`lf hitag help `|Y |`This help`
|`lf hitag eload `|N |`Load Hitag dump file into emulator memory`
|`lf hitag list `|N |`List Hitag trace history`
|`lf hitag info `|N |`Tag information`
|`lf hitag reader `|N |`Act like a Hitag Reader`
@ -905,7 +975,7 @@ Check column "offline" for their availability.
|`lf t55xx info `|Y |`Show T55x7 configuration data (page 0/ blk 0)`
|`lf t55xx p1detect `|N |`Try detecting if this is a t55xx tag by reading page 1`
|`lf t55xx read `|N |`Read T55xx block data`
|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)`
|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it`
|`lf t55xx restore `|N |`Restore T55xx card Page 0 / Page 1 blocks`
|`lf t55xx trace `|Y |`Show T55x7 traceability data (page 1/ blk 0-1)`
|`lf t55xx wakeup `|N |`Send AOR wakeup command`
@ -953,13 +1023,34 @@ Check column "offline" for their availability.
|------- |------- |-----------
|`mem help `|Y |`This help`
|`mem baudrate `|N |`Set Flash memory Spi baudrate`
|`mem spiffs `|N |`High level SPI FileSystem Flash manipulation`
|`mem info `|N |`Flash memory information`
|`mem load `|N |`Load data into flash memory`
|`mem dump `|N |`Dump data from flash memory`
|`mem info `|N |`Flash memory information`
|`mem load `|N |`Load data to flash memory`
|`mem wipe `|N |`Wipe data from flash memory`
### mem spiffs
{ SPI File system }
|command |offline |description
|------- |------- |-----------
|`mem spiffs help `|Y |`This help`
|`mem spiffs copy `|N |`Copy a file to another (destructively) in SPIFFS file system`
|`mem spiffs check `|N |`Check/try to defrag faulty/fragmented file system`
|`mem spiffs dump `|N |`Dump a file from SPIFFS file system`
|`mem spiffs info `|N |`Print file system info and usage statistics`
|`mem spiffs mount `|N |`Mount the SPIFFS file system if not already mounted`
|`mem spiffs remove `|N |`Remove a file from SPIFFS file system`
|`mem spiffs rename `|N |`Rename/move a file in SPIFFS file system`
|`mem spiffs test `|N |`Test SPIFFS Operations`
|`mem spiffs tree `|N |`Print the Flash memory file system tree`
|`mem spiffs unmount `|N |`Un-mount the SPIFFS file system`
|`mem spiffs upload `|N |`Upload file into SPIFFS file system`
|`mem spiffs view `|N |`View file on SPIFFS file system`
|`mem spiffs wipe `|N |`Wipe all files from SPIFFS file system * dangerous *`
### reveng
{ CRC calculations from RevEng software... }
@ -988,9 +1079,9 @@ Check column "offline" for their availability.
|command |offline |description
|------- |------- |-----------
|`script help `|Y |`Usage info`
|`script help `|Y |`This help`
|`script list `|Y |`List available scripts`
|`script run `|Y |`<name> -- execute a script`
|`script run `|Y |`<name> - execute a script`
### trace
@ -1034,3 +1125,44 @@ Check column "offline" for their availability.
|`wiegand decode `|Y |`Convert raw hex to decoded wiegand format (currently for HID Prox)`
### pref
{ Edit preferences... }
|command |offline |description
|------- |------- |-----------
|`pref help `|Y |`This help`
|`pref show `|Y |`Show all preferences`
### pref get
{ Get a preference }
|command |offline |description
|------- |------- |-----------
|`pref get barmode `|Y |`Get bar mode preference`
|`pref get clientdebug `|Y |`Get client debug level preference`
|`pref get color `|Y |`Get color support preference`
|`pref get savepaths `|Y |`Get file folder `
|`pref get emoji `|Y |`Get emoji display preference`
|`pref get hints `|Y |`Get hint display preference`
|`pref get plotsliders `|Y |`Get plot slider display preference`
### pref set
{ Set a preference }
|command |offline |description
|------- |------- |-----------
|`pref set help `|Y |`This help`
|`pref set barmode `|Y |`Set bar mode`
|`pref set clientdebug `|Y |`Set client debug level`
|`pref set color `|Y |`Set color support`
|`pref set emoji `|Y |`Set emoji display`
|`pref set hints `|Y |`Set hint display`
|`pref set savepaths `|Y |`... to be adjusted next ... `
|`pref set plotsliders `|Y |`Set plot slider display`

View file

@ -39,8 +39,8 @@ Page 3:
* used by Proxmark3 RDV4 specific functions: flash signature and keys dictionaries, see below for details
* to dump it: `mem dump f page3_dump o 196608 l 65536`
* to erase it:
* **Beware** it will erase your flash signature (see below) so better to back it up first as you won't be able to regenerate it by yourself!
* It's possible to erase completely page 3 by erase the entire flash memory with the voluntarily undocumented command `mem wipe i`.
* **Beware** it will erase your flash signature so better to back it up first as you won't be able to regenerate it by yourself!
* edit the source code to enable Page 3 as a valid input in the `mem wipe` command.
* Updating keys dictionaries doesn't require to erase page 3.
## Page3 Layout
@ -64,7 +64,7 @@ Page3 is used as follows by the Proxmark3 RDV4 firmware:
* length: 1 sector (actually only a few bytes are used to store `t55xx_config` structure)
* **RSA SIGNATURE**, see below for details
* offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F
* offset: page 3 sector 15 (0xF) offset 0xF7F @ 3*0x10000+15*0x1000+0xF7F=0x3FF7F (decimal 262015)
* length: 128 bytes
* offset should have been 0x3FF80 but historically it's one byte off and therefore the last byte of the flash is unused
@ -73,23 +73,39 @@ Page3 is used as follows by the Proxmark3 RDV4 firmware:
To ensure your Proxmark3 RDV4 is not a counterfeit product, its external flash contains a RSA signature of the flash unique ID.
You can verify it with: `mem info`
Here below is a sample output of a RDV4 device.
```
[usb] pm3 --> mem info
[=] --- Flash memory Information ---------
[=] ID................... 25AD99A782A867D5
[=] SHA1................. 67C3B9BA2FA90AD4B283926B70017066C082C156
[+] Signature............ ( ok )
[=] -------------------------------------------------------------
[=] ID | xx xx xx xx xx xx xx xx
[=] SHA1 | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
[=] RSA SIGNATURE |
[00] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
[01] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
[02] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
[03] | xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
[=] KEY length | 128
[+] RSA key validation ok
[+] RSA Verification ok
[=] --- RDV4 RSA signature ---------------
[=] C7C7DF7FA3A2391A2B36E97D227C746ED8BB475E8766F54A13BAA9AAB29299BE
[=] 37546AACCC29157ABF8AFBF3A1CFB24275442D565F7E996C6B08090528ADE25E
[=] ED1498E3089C72C68348D83CBD13F1247327BDBC9D75B09ECE3E051E19FE19BB
[=] 98CB038757F2EDFD2DC5060D05C3296BC19A6F768290D555DFD50407E0E13A70
[=] --- RDV4 RSA Public key --------------
[=] Len.................. 128
[=] Exponent............. 010001
[=] Public key modulus N
[=] E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF
[=] 4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F
[=] 9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33
[=] DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5
[+] RSA public key validation.... ( ok )
[+] RSA private key validation... ( ok )
[+] RSA verification..... ( ok )
[+] Genuine Proxmark3 RDV4 signature detected
```
For a backup of the signature: `mem dump p f flash_signature_dump o 262015 l 128`
# backup first!
To make a backup of the signature to file:
`mem dump p f flash_signature_dump o 262015 l 128`

View file

@ -61,7 +61,7 @@ GND | 6
3.3 | 1
# Where to find more information?
There has been lots of articles and blogposts about recoving, debricking, JTAG your Proxmark3 and you find here below a sortiment of resources that will be of help.
There has been lots of articles and blogposts about recovering, debricking, JTAG your Proxmark3 and you find here below an assortiment of resources that will be of help.
## Third party notes on using a BusPirate

View file

@ -373,9 +373,9 @@ It was needed to tune pm3 RX usart `maxtry` :
time client/proxmark3 -p /dev/ttyUSB0 -b 115200 -c "lf read"
6.28s
time client/proxmark3 -p /dev/ttyACM0 -c "mem dump f foo_usb"
time client/proxmark3 -p /dev/ttyACM0 -c "mem dump -f foo_usb"
1.48s
time client/proxmark3 -p /dev/ttyUSB0 -b 115200 -c "mem dump f foo_fpc"
time client/proxmark3 -p /dev/ttyUSB0 -b 115200 -c "mem dump -f foo_fpc"
25.34s

View file

@ -65,7 +65,7 @@ Dictionaries used by the client will be copied to
```
Here you find the default dictionaries used for commands like `hf mf chk`, `hf mf fchk`, `lf t55xx chk`
A dictionary file is a text based file with one key per line in hexdecimal form.
A dictionary file is a text based file with one key per line in hexadecimal form.
The length of the key is decided by the Proxmark3 client for the different commands. All chars afterwards on line is ignored.
if key isn't a hex number, the key is ignored.

View file

@ -56,6 +56,10 @@ struct version_information {
#define DBG_EXTENDED 4 // errors + info + debug + breaking debug messages
extern int DBGLEVEL;
// tear-off
extern uint16_t tearoff_delay_us;
extern bool tearoff_enabled;
// reader voltage field detector
#define MF_MINFIELDV 4000

View file

@ -384,6 +384,15 @@ typedef struct {
bool off;
} PACKED tearoff_params_t;
// when writing to SPIFFS
typedef struct {
bool append : 1;
uint16_t bytes_in_packet : 15;
uint8_t fnlen;
uint8_t fn[32];
uint8_t data[];
} PACKED flashmem_write_t;
// For the bootloader
#define CMD_DEVICE_INFO 0x0000
//#define CMD_SETUP_WRITE 0x0001
@ -565,6 +574,8 @@ typedef struct {
#define CMD_LF_HITAGS_READ 0x0373
#define CMD_LF_HITAGS_WRITE 0x0375
#define CMD_LF_HITAG_ELOAD 0x0376
#define CMD_HF_ISO14443A_ANTIFUZZ 0x0380
#define CMD_HF_ISO14443B_SIMULATE 0x0381
#define CMD_HF_ISO14443B_SNIFF 0x0382

View file

@ -8,7 +8,7 @@ ifneq ($(SKIPPTHREAD),1)
MYLDLIBS += -lpthread
endif
BINS = mf_nonce_brute
BINS = mf_nonce_brute mf_trace_brute
INSTALLTOOLS = $(BINS)
include ../../Makefile.host
@ -21,3 +21,5 @@ ifneq (,$(findstring MINGW,$(platform)))
endif
mf_nonce_brute : $(OBJDIR)/mf_nonce_brute.o $(MYOBJS)
mf_trace_brute : $(OBJDIR)/mf_trace_brute.o $(MYOBJS)

View file

@ -85,7 +85,7 @@ Example with parity (from this trace http://www.proxmark.org/forum/viewtopic.php
```
=>
```
./mf_nonce_brute 9c599b32 82a4166c 0000 a1e458ce 6eea41e0 0101 5cadf439 1001 3e709c8a
./mf_nonce_brute 9c599b32 82a4166c 0000 a1e458ce 6eea41e0 0101 5cadf439 1001 8e0e5db9
| | | | | | | | |
+UID +nt_enc | +nr_enc +ar_enc | +at_enc | +encrypted next cmd
+nt_par_err +at_par_err +at_par_err

View file

@ -14,10 +14,17 @@
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <ctype.h>
#include "crapto1/crapto1.h"
#include "protocol.h"
#include "iso14443crc.h"
#define AEND "\x1b[0m"
#define _RED_(s) "\x1b[31m" s AEND
#define _GREEN_(s) "\x1b[32m" s AEND
#define _YELLOW_(s) "\x1b[33m" s AEND
#define _CYAN_(s) "\x1b[36m" s AEND
#define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01)
// a global mutex to prevent interlaced printing from different threads
@ -42,24 +49,149 @@ typedef struct thread_args {
bool ev1;
} targs;
#define ENC_LEN (200)
typedef struct thread_key_args {
int thread;
int idx;
uint32_t uid;
uint32_t part_key;
uint32_t nt_enc;
uint32_t nr_enc;
uint16_t enc_len;
uint8_t enc[ENC_LEN]; // next encrypted command + a full read/write
} targs_key;
//------------------------------------------------------------------
uint8_t cmds[] = {
ISO14443A_CMD_READBLOCK,
ISO14443A_CMD_WRITEBLOCK,
MIFARE_AUTH_KEYA,
MIFARE_AUTH_KEYB,
MIFARE_CMD_INC,
MIFARE_CMD_DEC,
MIFARE_CMD_RESTORE,
MIFARE_CMD_TRANSFER
uint8_t cmds[8][2] = {
{ISO14443A_CMD_READBLOCK, 18},
{ISO14443A_CMD_WRITEBLOCK, 18},
{MIFARE_AUTH_KEYA, 0},
{MIFARE_AUTH_KEYB, 0},
{MIFARE_CMD_INC, 6},
{MIFARE_CMD_DEC, 6},
{MIFARE_CMD_RESTORE, 6},
{MIFARE_CMD_TRANSFER, 0}
};
int global_counter = 0;
int global_fin_flag = 0;
int global_found = 0;
int global_found_candidate = 0;
uint64_t global_candiate_key = 0;
size_t thread_count = 2;
static int param_getptr(const char *line, int *bg, int *en, int paramnum) {
int i;
int len = strlen(line);
*bg = 0;
*en = 0;
// skip spaces
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
if (*bg >= len) {
return 1;
}
for (i = 0; i < paramnum; i++) {
while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0')(*bg)++;
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
if (line[*bg] == '\0') return 1;
}
*en = *bg;
while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0')(*en)++;
(*en)--;
return 0;
}
static int param_gethex_to_eol(const char *line, int paramnum, uint8_t *data, int maxdatalen, int *datalen) {
int bg, en;
uint32_t temp;
char buf[5] = {0};
if (param_getptr(line, &bg, &en, paramnum)) return 1;
*datalen = 0;
int indx = bg;
while (line[indx]) {
if (line[indx] == '\t' || line[indx] == ' ') {
indx++;
continue;
}
if (isxdigit(line[indx])) {
buf[strlen(buf) + 1] = 0x00;
buf[strlen(buf)] = line[indx];
} else {
// if we have symbols other than spaces and hex
return 1;
}
if (*datalen >= maxdatalen) {
// if we dont have space in buffer and have symbols to translate
return 2;
}
if (strlen(buf) >= 2) {
sscanf(buf, "%x", &temp);
data[*datalen] = (uint8_t)(temp & 0xff);
*buf = 0;
(*datalen)++;
}
indx++;
}
if (strlen(buf) > 0)
//error when not completed hex bytes
return 3;
return 0;
}
static void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len,
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
if (buf == NULL) return;
char *tmp = (char *)buf;
size_t i;
memset(tmp, 0x00, hex_max_len);
size_t max_len = (hex_len > hex_max_len) ? hex_max_len : hex_len;
for (i = 0; i < max_len; ++i, tmp += 2 + spaces_between) {
sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]);
for (size_t j = 0; j < spaces_between; j++)
sprintf(tmp + 2 + j, " ");
}
i *= (2 + spaces_between);
size_t mlen = min_str_len > i ? min_str_len : 0;
if (mlen > hex_max_len)
mlen = hex_max_len;
for (; i < mlen; i++, tmp += 1)
sprintf(tmp, " ");
// remove last space
*tmp = '\0';
return;
}
static char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
static char buf[100] = {0};
hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, true);
return buf;
}
static uint16_t parity_from_err(uint32_t data, uint16_t par_err) {
uint16_t par = 0;
@ -196,13 +328,33 @@ static bool candidate_nonce(uint32_t xored, uint32_t nt, bool ev1) {
static bool checkValidCmd(uint32_t decrypted) {
uint8_t cmd = (decrypted >> 24) & 0xFF;
for (int i = 0; i < sizeof(cmds); ++i) {
if (cmd == cmds[i])
for (int i = 0; i < 8; ++i) {
if (cmd == cmds[i][0])
return true;
}
return false;
}
static bool checkValidCmdByte(uint8_t *cmd, uint16_t n) {
bool ok = false;
for (int i = 0; i < 8; ++i) {
if (cmd[0] == cmds[i][0]) {
if (n >= 4)
ok = CheckCrc14443(CRC_14443_A, cmd, 4);
if (cmds[i][1] > 0 && n >= cmds[i][1])
ok = CheckCrc14443(CRC_14443_A, cmd + 4, cmds[i][1]);
if (ok) {
return true;
}
}
}
return false;
}
static bool checkCRC(uint32_t decrypted) {
uint8_t data[] = {
(decrypted >> 24) & 0xFF,
@ -227,14 +379,12 @@ static void *brute_thread(void *arguments) {
uint32_t p64 = 0;
uint32_t count;
int found = 0;
// TC == 4 (
// threads calls 0 ev1 == false
// threads calls 0,1,2 ev1 == true
for (count = args->idx; count < 0xFFFF; count += thread_count - 1) {
found = global_found;
if (found) {
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
break;
}
@ -265,8 +415,8 @@ static void *brute_thread(void *arguments) {
#endif
if (cmd_enc) {
uint32_t decrypted = ks4 ^ cmd_enc;
printf("CMD enc(%08x)\n", cmd_enc);
printf(" dec(%08x)\t", decrypted);
printf("CMD enc( %08x )\n", cmd_enc);
printf(" dec( %08x ) ", decrypted);
// check if cmd exists
uint8_t isOK = checkValidCmd(decrypted);
@ -275,12 +425,12 @@ static void *brute_thread(void *arguments) {
// Add a crc-check.
isOK = checkCRC(decrypted);
if (isOK == false) {
printf("<-- not a valid cmd\n");
printf(_RED_("<-- not a valid cmd\n"));
pthread_mutex_unlock(&print_lock);
free(revstate);
continue;
} else {
printf("<-- Valid cmd\n");
printf("<-- valid cmd\n");
}
}
@ -293,32 +443,97 @@ static void *brute_thread(void *arguments) {
free(revstate);
if (args->ev1) {
printf("\nKey candidate: [%012" PRIx64 "]\n\n", key);
// if it was EV1, we know for sure xxxAAAAAAAA recovery
printf("\nKey candidate [ " _YELLOW_("....%08" PRIx64 )" ]\n\n", key & 0xFFFFFFFF);
__sync_fetch_and_add(&global_found_candidate, 1);
} else {
printf("\nValid Key found: [%012" PRIx64 "]\n\n", key);
printf("\nKey candidate [ " _GREEN_("....%08" PRIx64) " ]\n\n", key & 0xFFFFFFFF);
__sync_fetch_and_add(&global_found, 1);
}
__sync_fetch_and_add(&global_candiate_key, key);
//release lock
pthread_mutex_unlock(&print_lock);
break;
}
}
free(args);
return NULL;
}
static void *brute_key_thread(void *arguments) {
struct thread_key_args *args = (struct thread_key_args *) arguments;
uint64_t key;
uint8_t local_enc[args->enc_len];
memcpy(local_enc, args->enc, args->enc_len);
for (uint64_t count = args->idx; count < 0xFFFF; count += thread_count) {
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
break;
}
key = (count << 32 | args->part_key);
// Init cipher with key
struct Crypto1State *pcs = crypto1_create(key);
// NESTED decrypt nt with help of new key
crypto1_word(pcs, args->nt_enc ^ args->uid, 1);
crypto1_word(pcs, args->nr_enc, 1);
crypto1_word(pcs, 0, 0);
crypto1_word(pcs, 0, 0);
// decrypt 22 bytes
uint8_t dec[args->enc_len];
for (int i = 0; i < args->enc_len; i++)
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
crypto1_deinit(pcs);
// check if cmd exists
uint8_t isOK = checkValidCmdByte(dec, args->enc_len);
if (isOK == false) {
continue;
}
// lock this section to avoid interlacing prints from different threats
pthread_mutex_lock(&print_lock);
printf("\nenc: %s\n", sprint_hex_inrow_ex(local_enc, args->enc_len, 0));
printf("dec: %s\n", sprint_hex_inrow_ex(dec, args->enc_len, 0));
printf("\nValid Key found [ " _GREEN_("%012" PRIx64) " ]\n\n", key);
pthread_mutex_unlock(&print_lock);
__sync_fetch_and_add(&global_found, 1);
break;
}
free(args);
return NULL;
}
static int usage(void) {
printf(" syntax: mf_nonce_brute <uid> <nt> <nt_par_err> <nr> <ar> <ar_par_err> <at> <at_par_err> [<next_command>]\n\n");
printf(" example: nt in trace = 8c! 42 e6! 4e!\n");
printf("\n");
printf("syntax: mf_nonce_brute <uid> <nt> <nt_par_err> <nr> <ar> <ar_par_err> <at> <at_par_err> [<next_command>]\n\n");
printf("how to convert trace data to needed input:\n");
printf(" nt in trace = 8c! 42 e6! 4e!\n");
printf(" nt = 8c42e64e\n");
printf(" nt_par_err = 1011\n\n");
printf("\n expected outcome:\n");
printf(" KEY 0xFFFFFFFFFFFF == fa247164 fb47c594 0000 71909d28 0c254817 1000 0dc7cfbd 1110\n");
printf("samples:\n");
printf("\n");
printf(" ./mf_nonce_brute fa247164 fb47c594 0000 71909d28 0c254817 1000 0dc7cfbd 1110\n");
printf("\n");
printf("**** Possible key candidate ****\n");
printf("Key candidate: [ffffffffffff]\n");
printf("\n");
printf(" ./mf_nonce_brute 96519578 d7e3c6ac 0011 cd311951 9da49e49 0010 2bb22e00 0100 a4f7f398ebdb4e484d1cb2b174b939d18b469f3fa5d9caab\n");
printf("\n");
printf("enc: A4F7F398EBDB4E484D1CB2B174B939D18B469F3FA5D9CAABBFA018EC7E0CC5721DE2E590F64BD0A5B4EFCE71\n");
printf("dec: 30084A24302F8102F44CA5020500A60881010104763930084A24302F8102F44CA5020500A608810101047639\n");
printf("Valid Key found: [3b7e4fd575ad]\n\n");
return 1;
}
int main(int argc, char *argv[]) {
printf("Mifare classic nested auth key recovery. Phase 1.\n");
printf("\nMifare classic nested auth key recovery\n\n");
if (argc < 9) return usage();
@ -331,21 +546,27 @@ int main(int argc, char *argv[]) {
sscanf(argv[7], "%x", &at_enc);
sscanf(argv[8], "%x", &at_par_err);
if (argc > 9)
sscanf(argv[9], "%x", &cmd_enc);
int enc_len = 0;
uint8_t enc[ENC_LEN] = {0}; // next encrypted command + a full read/write
if (argc > 9) {
// sscanf(argv[9], "%x", &cmd_enc);
param_gethex_to_eol(argv[9], 0, enc, sizeof(enc), &enc_len);
cmd_enc = (enc[0] << 24 | enc[1] << 16 | enc[2] << 8 | enc[3]);
}
printf("-------------------------------------------------\n");
printf("uid:\t\t%08x\n", uid);
printf("nt encrypted:\t%08x\n", nt_enc);
printf("nt parity err:\t%04x\n", nt_par_err);
printf("nr encrypted:\t%08x\n", nr_enc);
printf("ar encrypted:\t%08x\n", ar_enc);
printf("ar parity err:\t%04x\n", ar_par_err);
printf("at encrypted:\t%08x\n", at_enc);
printf("at parity err:\t%04x\n", at_par_err);
printf("----------- " _CYAN_("Phase 1") " ------------------------\n");
printf("uid.................. %08x\n", uid);
printf("nt encrypted......... %08x\n", nt_enc);
printf("nt parity err........ %04x\n", nt_par_err);
printf("nr encrypted......... %08x\n", nr_enc);
printf("ar encrypted......... %08x\n", ar_enc);
printf("ar parity err........ %04x\n", ar_par_err);
printf("at encrypted......... %08x\n", at_enc);
printf("at parity err........ %04x\n", at_par_err);
if (argc > 9)
printf("next cmd enc:\t%08x\n\n", cmd_enc);
if (argc > 9) {
printf("next encrypted cmd... %s\n", sprint_hex_inrow_ex(enc, enc_len ,0));
}
clock_t t1 = clock();
uint16_t nt_par = parity_from_err(nt_enc, nt_par_err);
@ -361,7 +582,7 @@ int main(int argc, char *argv[]) {
thread_count = 2;
#endif /* _WIN32 */
printf("\nBruteforce using %zu threads to find encrypted tagnonce last bytes\n", thread_count);
printf("\nBruteforce using " _YELLOW_("%zu") " threads to find encrypted tagnonce last bytes\n", thread_count);
pthread_t threads[thread_count];
@ -386,6 +607,51 @@ int main(int argc, char *argv[]) {
pthread_create(&threads[i + 1], NULL, brute_thread, (void *)b);
}
// wait for threads to terminate:
for (int i = 0; i < thread_count; ++i)
pthread_join(threads[i], NULL);
t1 = clock() - t1;
printf("execution time %.2f sec\n", (float)t1 / 1000000.0);
if (!global_found && !global_found_candidate) {
printf("\nFailed to find a key\n\n");
goto out;
}
if (enc_len < 4) {
printf("Too few next cmd bytes, skipping phase 2\n");
goto out;
}
// reset thread signals
global_found = 0;
global_found_candidate = 0;
printf("\n----------- " _CYAN_("Phase 2") " ------------------------\n");
printf("uid.......... %08x\n", uid);
printf("partial key.. %08x\n", (uint32_t)(global_candiate_key & 0xFFFFFFFF));
printf("nt enc....... %08x\n", nt_enc);
printf("nr enc....... %08x\n", nr_enc);
printf("next encrypted cmd: %s\n", sprint_hex_inrow_ex(enc, enc_len ,0));
printf("\nStart bruteforce to find upper 16 bits of key\n");
fflush(stdout);
// threads
for (int i = 0; i < thread_count; ++i) {
struct thread_key_args *b = malloc(sizeof(struct thread_key_args));
b->thread = i;
b->idx = i;
b->uid = uid;
b->part_key = (uint32_t)(global_candiate_key & 0xFFFFFFFF);
b->nt_enc = nt_enc;
b->nr_enc = nr_enc;
b->enc_len = enc_len;
memcpy(b->enc, enc, enc_len);
pthread_create(&threads[i], NULL, brute_key_thread, (void *)b);
}
// wait for threads to terminate:
for (int i = 0; i < thread_count; ++i)
pthread_join(threads[i], NULL);
@ -394,10 +660,7 @@ int main(int argc, char *argv[]) {
printf("\nFailed to find a key\n\n");
}
t1 = clock() - t1;
if (t1 > 0)
printf("Execution time: %.0f ticks\n", (float)t1);
out:
// clean up mutex
pthread_mutex_destroy(&print_lock);
return 0;

View file

@ -0,0 +1,315 @@
//
// bruteforce the upper 16bits of a partial key recovered from mf_nonce_brute.
// J-run's original idea was a two part recovery vector with first a offline trace and then online for 2 bytes.
//
// This idea is two use only offline, to recover a nested authentication key.
// Assumption, we get a read/write command after a nested auth, we need 22 bytes of data.
// Iceman, 2021,
//
#define __STDC_FORMAT_MACROS
#if !defined(_WIN64)
#if defined(_WIN32) || defined(__WIN32__)
# define _USE_32BIT_TIME_T 1
#endif
#endif
#include <inttypes.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include "ctype.h"
#include <time.h>
#include "crapto1/crapto1.h"
#include "protocol.h"
#include "iso14443crc.h"
// a global mutex to prevent interlaced printing from different threads
pthread_mutex_t print_lock;
#define ENC_LEN (4 + 16 + 2)
//--------------------- define options here
typedef struct thread_args {
int thread;
int idx;
uint32_t uid;
uint32_t part_key;
uint32_t nt_enc;
uint32_t nr_enc;
uint8_t enc[ENC_LEN]; // next encrypted command + a full read/write
} targs;
//------------------------------------------------------------------
uint8_t cmds[] = {
ISO14443A_CMD_READBLOCK,
ISO14443A_CMD_WRITEBLOCK,
MIFARE_AUTH_KEYA,
MIFARE_AUTH_KEYB,
MIFARE_CMD_INC,
MIFARE_CMD_DEC,
MIFARE_CMD_RESTORE,
MIFARE_CMD_TRANSFER
};
int global_counter = 0;
int global_fin_flag = 0;
int global_found = 0;
int global_found_candidate = 0;
size_t thread_count = 2;
static int param_getptr(const char *line, int *bg, int *en, int paramnum) {
int i;
int len = strlen(line);
*bg = 0;
*en = 0;
// skip spaces
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
if (*bg >= len) {
return 1;
}
for (i = 0; i < paramnum; i++) {
while (line[*bg] != ' ' && line[*bg] != '\t' && line[*bg] != '\0')(*bg)++;
while (line[*bg] == ' ' || line[*bg] == '\t')(*bg)++;
if (line[*bg] == '\0') return 1;
}
*en = *bg;
while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0')(*en)++;
(*en)--;
return 0;
}
static int param_gethex_to_eol(const char *line, int paramnum, uint8_t *data, int maxdatalen, int *datalen) {
int bg, en;
uint32_t temp;
char buf[5] = {0};
if (param_getptr(line, &bg, &en, paramnum)) return 1;
*datalen = 0;
int indx = bg;
while (line[indx]) {
if (line[indx] == '\t' || line[indx] == ' ') {
indx++;
continue;
}
if (isxdigit(line[indx])) {
buf[strlen(buf) + 1] = 0x00;
buf[strlen(buf)] = line[indx];
} else {
// if we have symbols other than spaces and hex
return 1;
}
if (*datalen >= maxdatalen) {
// if we dont have space in buffer and have symbols to translate
return 2;
}
if (strlen(buf) >= 2) {
sscanf(buf, "%x", &temp);
data[*datalen] = (uint8_t)(temp & 0xff);
*buf = 0;
(*datalen)++;
}
indx++;
}
if (strlen(buf) > 0)
//error when not completed hex bytes
return 3;
return 0;
}
static void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len,
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
if (buf == NULL) return;
char *tmp = (char *)buf;
size_t i;
memset(tmp, 0x00, hex_max_len);
size_t max_len = (hex_len > hex_max_len) ? hex_max_len : hex_len;
for (i = 0; i < max_len; ++i, tmp += 2 + spaces_between) {
sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]);
for (size_t j = 0; j < spaces_between; j++)
sprintf(tmp + 2 + j, " ");
}
i *= (2 + spaces_between);
size_t mlen = min_str_len > i ? min_str_len : 0;
if (mlen > hex_max_len)
mlen = hex_max_len;
for (; i < mlen; i++, tmp += 1)
sprintf(tmp, " ");
// remove last space
*tmp = '\0';
return;
}
static char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
static char buf[100] = {0};
hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, true);
return buf;
}
static void *brute_thread(void *arguments) {
//int shift = (int)arg;
struct thread_args *args = (struct thread_args *) arguments;
uint64_t key; // recovered key candidate
int found = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs = &mpcs;
uint8_t local_enc[ENC_LEN] = {0};
memcpy(local_enc, args->enc, sizeof(local_enc));
for (uint64_t count = args->idx; count < 0xFFFF; count += thread_count) {
found = global_found;
if (found) {
break;
}
key = (count << 32 | args->part_key);
// Init cipher with key
pcs = crypto1_create(key);
// NESTED decrypt nt with help of new key
// if (args->use_nested)
// crypto1_word(pcs, args->nt_enc ^ args->uid, 1) ^ args->nt_enc;
// else
crypto1_word(pcs, args->nt_enc ^ args->uid, 1);
crypto1_word(pcs, args->nr_enc, 1);
crypto1_word(pcs, 0, 0);
crypto1_word(pcs, 0, 0);
// decrypt 22 bytes
uint8_t dec[ENC_LEN] = {0};
for (int i = 0; i < ENC_LEN; i++)
dec[i] = crypto1_byte(pcs, 0x00, 0) ^ local_enc[i];
crypto1_deinit(pcs);
if (CheckCrc14443(CRC_14443_A, dec , 4)) {
// check crc-16 in the end
if (CheckCrc14443(CRC_14443_A, dec + 4, 18)) {
// lock this section to avoid interlacing prints from different threats
pthread_mutex_lock(&print_lock);
printf("\nValid Key found: [%012" PRIx64 "]\n", key);
printf("enc: %s\n", sprint_hex_inrow_ex(local_enc, ENC_LEN, 0));
printf(" xx crcA crcA\n");
printf("dec: %s\n", sprint_hex_inrow_ex(dec, ENC_LEN, 0));
pthread_mutex_unlock(&print_lock);
__sync_fetch_and_add(&global_found, 1);
}
}
}
free(args);
return NULL;
}
static int usage(void) {
printf(" syntax: mf_trace_brute <uid> <partial key> <nt enc> <nr enc> [<next_command + 18 bytes>]\n\n");
return 1;
}
int main(int argc, char *argv[]) {
printf("Mifare classic nested auth key recovery. Phase 2.\n");
if (argc < 3) return usage();
uint32_t uid = 0; // serial number
uint32_t part_key = 0; // last 4 keys of key
uint32_t nt_enc = 0; // noncce tag
uint32_t nr_enc = 0; // nonce reader encrypted
sscanf(argv[1], "%x", &uid);
sscanf(argv[2], "%x", &part_key);
sscanf(argv[3], "%x", &nt_enc);
sscanf(argv[4], "%x", &nr_enc);
int enc_len = 0;
uint8_t enc[ENC_LEN] = {0}; // next encrypted command + a full read/write
param_gethex_to_eol(argv[5], 0, enc, sizeof(enc), &enc_len);
printf("-------------------------------------------------\n");
printf("uid.......... %08x\n", uid);
printf("partial key.. %08x\n", part_key);
printf("nt enc....... %08x\n", nt_enc);
printf("nr enc....... %08x\n", nr_enc);
printf("next encrypted cmd: %s\n", sprint_hex_inrow_ex(enc, ENC_LEN ,0));
clock_t t1 = clock();
#if !defined(_WIN32) || !defined(__WIN32__)
thread_count = sysconf(_SC_NPROCESSORS_CONF);
if (thread_count < 2)
thread_count = 2;
#endif /* _WIN32 */
printf("\nBruteforce using %zu threads to find upper 16bits of key\n", thread_count);
pthread_t threads[thread_count];
// create a mutex to avoid interlacing print commands from our different threads
pthread_mutex_init(&print_lock, NULL);
// threads
for (int i = 0; i < thread_count; ++i) {
struct thread_args *a = malloc(sizeof(struct thread_args));
a->thread = i;
a->idx = i;
a->uid = uid;
a->part_key = part_key;
a->nt_enc = nt_enc;
a->nr_enc = nr_enc;
memcpy(a->enc, enc, sizeof(a->enc));
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
}
// wait for threads to terminate:
for (int i = 0; i < thread_count; ++i)
pthread_join(threads[i], NULL);
if (!global_found && !global_found_candidate) {
printf("\nFailed to find a key\n\n");
}
t1 = clock() - t1;
if (t1 > 0)
printf("Execution time: %.0f ticks\n", (float)t1);
// clean up mutex
pthread_mutex_destroy(&print_lock);
return 0;
}

View file

@ -102,7 +102,8 @@ def selftests():
'pk': "040E98E117AAA36457F43173DC920A8757267F44CE4EC5ADD3C54075571AEBBF7B942A9774A1D94AD02572427E5AE0A2DD36591B1FB34FCF3D"},
{'name': "DESFire EV2",
'samples': ["042A41CAE45380", "B2769F8DDB575AEA2A680ADCA8FFED4FAB81A1E9908E2B82FE0FABB697BBD9B23835C416970E75768F12902ACA491349E94E6589EAF4F508",
"045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33"],
"045640CAE45380", "D34B53A8C2C100D700DEA1C4C0D0DE4409F3A418CD8D57C4F41F146E42AD9A55F014199ABBF5CA259C7799DB0AE20D5E77D4950AC7E95D33",
"040D259A965B80","B158073A7100C88C3726F4299FA58311FC3CB18744686DE3F234928AD74578F5CAD7FCEC1DCB962ECC7CC000B8557B37F45B76DC6573A58F"],
'pk': "04B304DC4C615F5326FE9383DDEC9AA892DF3A57FA7FFB3276192BC0EAA252ED45A865E3B093A3D0DCE5BE29E92F1392CE7DE321E3E5C52B3A"},
{'name': "DESFire EV3",
'samples': ["04448BD2DB6B80", "5CBB5632795C8F15263FEFB095B51C7B541AFD914A1AE44EF6FB8AF605EDF13DBFEE6C3A2DB372245E671DFE0D42CB1F0D0B8FE67A89D2F6",
@ -146,6 +147,7 @@ def selftests():
for c in curvenames:
for h in [None, "md5", "sha1", "sha256", "sha512"]:
recovered |= recover_multiple(t['samples'][::2], t['samples'][1::2], c, alghash=h)
if (len(recovered) == 1):
pk = recovered.pop()
pk = binascii.hexlify(pk).decode('utf8')