Merge remote-tracking branch 'upstream/master' into em4x70_support

This commit is contained in:
Christian Molson 2020-12-09 10:00:42 -05:00
commit 011b585b0d
27 changed files with 2584 additions and 1482 deletions

View file

@ -3,7 +3,26 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim
- Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re)
- EM4x50: changed cli parameter from w (word) to d (data) (@tharexde)
- EM4x50: new function 4x50 login: authenticate against tag (@tharexde)
- EM4x50: new function 4x50 brute: guess password within a given password range (@tharexde)
- EM4x50: new function 4x50 chk: try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde)
- EM4x50: new function 4x50 reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde)
- EM4x50: new function 4x50 sim: simulate dump from file or emulator/flash (@tharexde)
- EM4x50: new function 4x50 restore: restore dump file (bin, eml, json) onto tag (@tharexde)
- EM4x50: new function 4x50 esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde)
- EM4x50: new function 4x50 eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde)
- EM4x50: added LED signals (@tharexde)
- EM4x50: added json format for 4x50 dump (@tharexde)
- EM4x50: relocated write requests in function 4x50 wipe from device to client (@tharexde)
- EM4x50: renamed 4x50_write_password to 4x50 writepwd (@tharexde)
- EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde)
- EM4x50: changed cli parameter from a (address) to b (block) (@tharexde)
- EM4x50: switched to cliparser for all functions (@tharexde)
- EM4x50: stabilized and accelerated tag detection (@tharexde)
- EM4x50: removed global tag structure on device side (@tharexde)
- Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim (@cyberpunk-re)
- Added `mf mfu sim t 7 n <numreads>` - MFU emulation now supports automatic exit after <num> blocks read. (@cyberpunk-re)
- Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33)
- Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)

View file

@ -0,0 +1,359 @@
//-----------------------------------------------------------------------------
// Tharexde, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for EM4x50 simulator and collector aka THAREXDE
//-----------------------------------------------------------------------------
#include <inttypes.h>
#include "standalone.h"
#include "proxmark3_arm.h"
#include "appmain.h"
#include "BigBuf.h"
#include "fpgaloader.h"
#include "util.h"
#include "dbprint.h"
#include "spiffs.h"
#include "../em4x50.h"
/*
* `lf_tharexde` simulates hardcoded words/blocks, reads words of standard read
* mode of EM4x50 tags and stores them in internal flash.
* It requires RDV4 hardware (for flash and battery).
*
* On entering stand-alone mode, this module will start reading/record EM4x50 data.
* Every found / collected data will be written/appended to the logfile in flash
* as a text string.
*
* LEDs:
* - LED A: simulating
* - LED B: reading / record
* - LED C: writing to flash
* - LED D: unmounting/sync'ing flash (normally < 100ms)
*
* To retrieve log file from flash:
*
* 1. mem spiffs dump o lf_em4x50collect.log f lf_em4x50collect.log
* Copies log file from flash to your client.
*
* 2. exit the Proxmark3 client
*
* 3. more lf_tharexdecollect.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 log file from flash:
*
* 1. mem spiffs remove lf_tharexdecollect.log
*/
#define STATE_SIM 0
#define STATE_READ 1
#define STATE_BRUTE 2
#define EM4X50_TAG_WORD 45
#define EM4X50_PWD_SPEED 27
#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml"
#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log"
#define LF_EM4X50BRUTE_INPUTFILE "lf_em4x50brute.eml"
#define LF_EM4X50BRUTE_LOGFILE "lf_em4x50brute.log"
bool input_exists;
bool log_exists;
static void LoadDataInstructions(const char *inputfile) {
Dbprintf("");
Dbprintf("To load datafile into flash and display it:");
Dbprintf(_YELLOW_("1.") " edit inputfile %s", inputfile);
Dbprintf(_YELLOW_("2.") " start proxmark3 client");
Dbprintf(_YELLOW_("3.") " mem spiffs load f %s o %s", inputfile, inputfile);
Dbprintf(_YELLOW_("4.") " start standalone mode");
}
static void DownloadLogInstructions(const char *logfile) {
Dbprintf("");
Dbprintf("To get the logfile from flash and display it:");
Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f %s", logfile, logfile);
Dbprintf(_YELLOW_("2.") " exit proxmark3 client");
Dbprintf(_YELLOW_("3.") " cat %s", logfile);
}
static int get_input_data_from_file(uint32_t *words, char *inputfile) {
size_t now = 0;
if (exists_in_spiffs(inputfile)) {
uint32_t size = size_in_spiffs(inputfile);
uint8_t *mem = BigBuf_malloc(size);
Dbprintf(_YELLOW_("found input file %s"), inputfile);
rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE);
now = size / 9;
for (int i = 0; i < now; i++)
for (int j = 0; j < 4; j++)
words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
Dbprintf(_YELLOW_("read data from input file"));
}
BigBuf_free();
return (now > 0) ? now : 0;
}
static void append(const char *filename, uint8_t *entry, size_t entry_len) {
LED_D_ON();
if (log_exists == false) {
rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
log_exists = true;
} else {
rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
}
LED_D_OFF();
}
void ModInfo(void) {
DbpString(_YELLOW_(" LF EM4x50 sim/collector/bruteforce mode") " - a.k.a tharexde");
}
void RunMod(void) {
bool state_change = true;//, password_found = false;
int pwd_found = false;
uint8_t state = STATE_SIM;
// declarations for simulating
uint32_t words[33] = {0x0};
uint32_t pwd = 0x0;
uint32_t passwords[2] = {0x0};
size_t now = 0;
// declarations for reading
int no_words = 0;
//uint32_t words[EM4X50_TAG_WORD];
uint8_t entry[81];
rdv40_spiffs_lazy_mount();
StandAloneMode();
Dbprintf(_YELLOW_("Standalone mode THAREXDE started"));
for (;;) {
WDT_HIT();
if (data_available()) break;
// press button - toggle between SIM, READ and BRUTE
// hold button - exit
int button_pressed = BUTTON_CLICKED(1000);
if (button_pressed == BUTTON_SINGLE_CLICK) {
SpinUp(100);
switch (state) {
case STATE_SIM:
state = STATE_READ;
break;
case STATE_READ:
state = STATE_BRUTE;
break;
case STATE_BRUTE:
state = STATE_SIM;
break;
default:
break;
}
state_change = true;
} else if (button_pressed == BUTTON_HOLD) {
SpinDown(100);
break;
}
if (state == STATE_SIM) {
if (state_change) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125);
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
LEDsoff();
LED_A_ON();
Dbprintf("");
Dbprintf(_YELLOW_("switched to EM4x50 simulating mode"));
now = get_input_data_from_file(words, LF_EM4X50SIMULATE_INPUTFILE);
if (now > 0) {
Dbprintf(_YELLOW_("simulating %i blocks"), now);
for (int i = 0; i < now; i++)
Dbprintf("%2i -> %lx", i + 1, words[i]);
} else {
Dbprintf(_RED_("error in input data"));
}
state_change = false;
}
em4x50_sim_send_listen_window();
for (int i = 0; i < now; i++) {
em4x50_sim_send_listen_window();
em4x50_sim_send_word(words[i]);
}
} else if (state == STATE_READ) {
if (state_change) {
LEDsoff();
LED_B_ON();
Dbprintf("");
Dbprintf(_YELLOW_("switched to EM4x50 reading mode"));
memset(entry, 0, sizeof(entry));
memset(words, 0, sizeof(words));
log_exists = exists_in_spiffs(LF_EM4X50COLLECT_LOGFILE);
state_change = false;
}
no_words = em4x50_standalone_read(words);
if (no_words > 0) {
memset(entry, 0, sizeof(entry));
sprintf((char *)entry, "found new EM4x50 tag:");
Dbprintf("%s", entry);
strcat((char *)entry, "\n");
append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry));
for (int i = 0; i < no_words; i++) {
sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, words[i]);
Dbprintf("%s", entry);
strcat((char *)entry, "\n");
append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry));
}
}
} else if (state == STATE_BRUTE) {
if (state_change) {
LEDsoff();
LED_C_ON();
Dbprintf("");
Dbprintf(_YELLOW_("switched to EM4x50 brute force mode"));
log_exists = exists_in_spiffs(LF_EM4X50BRUTE_LOGFILE);
now = get_input_data_from_file(passwords, LF_EM4X50BRUTE_INPUTFILE);
if (now == 2) {
// print some information
int no_iter = passwords[1] - passwords[0] + 1;
int dur_s = no_iter / EM4X50_PWD_SPEED;
int dur_h = dur_s / 3600;
int dur_m = (dur_s - dur_h * 3600) / 60;
dur_s -= dur_h * 3600 + dur_m * 60;
//iterprint = no_iter/10;
Dbprintf(_YELLOW_("trying %i passwords in range [0x%08x, 0x%08x]"),
no_iter, passwords[0], passwords[1]);
Dbprintf(_YELLOW_("estimated duration: %ih%im%is"),
dur_h, dur_m, dur_s);
} else {
Dbprintf(_RED_("error in input data"));
break;
}
state_change = false;
}
pwd_found = em4x50_standalone_brute(passwords[0], passwords[1], &pwd);
if (pwd_found == PM3_ETIMEOUT) {
// timeout -> no EM4x50 tag on reader?
Dbprintf(_YELLOW_("timeout - no EM4x50 tag detected"));
} else if (pwd_found == true) {
// password found -> write to logfile
sprintf((char *)entry, "password found: 0x%08"PRIx32, pwd);
Dbprintf(_YELLOW_("%s"), entry);
strcat((char *)entry, "\n");
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
break;
} else {
if (pwd == passwords[1] + 1) {
// finished without success -> write to logfile
sprintf((char *)entry, "no password found");
Dbprintf(_YELLOW_("%s"), entry);
strcat((char *)entry, "\n");
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
} else {
// stopped -> write to logfile
sprintf((char *)entry, "stopped search - last password: 0x%08"PRIx32, pwd);
Dbprintf(_YELLOW_("%s"), entry);
strcat((char *)entry, "\n");
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
// replace start password by last tested password in
// inputfile (spiffs) so that brute forcing process will
// be continued when envoking brute force mode again
sprintf((char *)entry, "%08"PRIx32"\n%08"PRIx32"\n", pwd, passwords[1]);
rdv40_spiffs_write(LF_EM4X50BRUTE_INPUTFILE,
entry,
strlen((char *)entry),
RDV40_SPIFFS_SAFETY_SAFE);
}
break;
}
}
}
if (state == STATE_READ) {
DownloadLogInstructions(LF_EM4X50COLLECT_LOGFILE);
} else if (state == STATE_BRUTE) {
LoadDataInstructions(LF_EM4X50BRUTE_INPUTFILE);
DownloadLogInstructions(LF_EM4X50BRUTE_LOGFILE);
} else {
LoadDataInstructions(LF_EM4X50SIMULATE_INPUTFILE);
}
LED_D_ON();
rdv40_spiffs_lazy_unmount();
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
Dbprintf("");
Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped"));
}

View file

@ -1113,16 +1113,54 @@ static void PacketReceived(PacketCommandNG *packet) {
em4x50_write((em4x50_data_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_WRITE_PASSWORD: {
em4x50_write_password((em4x50_data_t *)packet->data.asBytes);
case CMD_LF_EM4X50_WRITEPWD: {
em4x50_writepwd((em4x50_data_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_READ: {
em4x50_read((em4x50_data_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_WIPE: {
em4x50_wipe((em4x50_data_t *)packet->data.asBytes);
case CMD_LF_EM4X50_BRUTE: {
em4x50_brute((em4x50_data_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_LOGIN: {
em4x50_login((uint32_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_SIM: {
//-----------------------------------------------------------------------------
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
//-----------------------------------------------------------------------------
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
em4x50_sim((uint8_t *)packet->data.asBytes);
break;
}
case CMD_LF_EM4X50_READER: {
em4x50_reader();
break;
}
case CMD_LF_EM4X50_ESET: {
//-----------------------------------------------------------------------------
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
//-----------------------------------------------------------------------------
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
emlSet(packet->data.asBytes, packet->oldarg[0], packet->oldarg[1]);
break;
}
case CMD_LF_EM4X50_CHK: {
//-----------------------------------------------------------------------------
// Note: we call FpgaDownloadAndGo(FPGA_BITSTREAM_LF) here although FPGA is not
// involved in dealing with emulator memory. But if it is called later, it might
// destroy the Emulator Memory.
//-----------------------------------------------------------------------------
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
em4x50_chk((uint8_t *)packet->data.asBytes);
break;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -13,14 +13,19 @@
#include "../include/em4x50.h"
typedef struct {
uint8_t sectors[34][7];
} em4x50_tag_t;
int em4x50_standalone_read(uint32_t *words);
int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd);
bool em4x50_sim_send_listen_window(void);
bool em4x50_sim_send_word(uint32_t word);
void em4x50_info(em4x50_data_t *etd);
void em4x50_write(em4x50_data_t *etd);
void em4x50_write_password(em4x50_data_t *etd);
void em4x50_writepwd(em4x50_data_t *etd);
void em4x50_read(em4x50_data_t *etd);
void em4x50_wipe(em4x50_data_t *etd);
void em4x50_brute(em4x50_data_t *etd);
void em4x50_login(uint32_t *password);
void em4x50_sim(uint8_t *filename);
void em4x50_reader(void);
void em4x50_chk(uint8_t *filename);
#endif /* EM4X50_H */

View file

@ -31,6 +31,7 @@ void lf_wait_periods(size_t periods);
void lf_init(bool reader, bool simulate);
void lf_finalize(void);
size_t lf_detect_field_drop(size_t max);
bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len);
void lf_modulation(bool modulation);

View file

@ -4066,6 +4066,13 @@
"service_provider": "PAYCULT",
"system_integrator": "PAYCULT"
},
{
"application": "Access Control (SIO)",
"company": "HID Global",
"mad": "0x3D01",
"service_provider": "HID Corporation",
"system_integrator": "HID Corporation"
},
{
"application": "City transport bus, ferry, administration",
"company": "VFJ Technology Pty Ltd",

View file

@ -709,7 +709,7 @@ static int Cmdmandecoderaw(const char *Cmd) {
if (Em410xDecode(bits, &size, &idx, &hi, &id) == 1) {
//need to adjust to set bitstream back to manchester encoded data
//setDemodBuff(bits, size, idx);
printEM410x(hi, id);
printEM410x(hi, id, false);
}
}
return PM3_SUCCESS;

View file

@ -1696,7 +1696,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
CLIParserInit(&ctx, "hf iclass restore",
"Restore data from dumpfile onto a iCLASS tag",
"hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0\n"
"hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite"
"hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 --ki 0 --elite\n"
"hf iclass restore -f hf-iclass-AA162D30F8FF12F1-dump.bin --first 6 --last 18 -k 1122334455667788 --elite\n"
);

View file

@ -12,7 +12,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "cliparser.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "cmdtrace.h"
@ -22,28 +22,6 @@
static int CmdHelp(const char *Cmd);
static int usage_thinfilm_info(void) {
PrintAndLogEx(NORMAL, "Usage: hf thinfilm info [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf thinfilm info");
return PM3_SUCCESS;
}
static int usage_thinfilm_sim(void) {
PrintAndLogEx(NORMAL, "Usage: hf thinfilm sim [h] [d <data>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " d <bytes> bytes to send, in hex");
PrintAndLogEx(NORMAL, " r raw, provided bytes should include CRC");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf thinfilm sim d B70470726f786d61726b2e636f6d");
return PM3_SUCCESS;
}
// Printing function based upon the code in libnfc
// ref
// https://github.com/nfc-tools/libnfc/blob/master/utils/nfc-barcode.c
@ -119,26 +97,17 @@ static int print_barcode(uint8_t *barcode, const size_t barcode_len, bool verbos
}
static int CmdHfThinFilmInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf thinfilm info",
"Get info from Thinfilm tags",
"hf thinfilm info");
uint8_t cmdp = 0;
bool errors = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_thinfilm_info();
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
//Validations
if (errors) {
usage_thinfilm_info();
return PM3_EINVARG;
}
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
return infoThinFilm(true);
}
@ -168,45 +137,40 @@ int infoThinFilm(bool verbose) {
}
static int CmdHfThinFilmSim(const char *Cmd) {
uint8_t cmdp = 0;
uint8_t data[512];
int datalen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf thinfilm sim",
"Simulate Thinfilm tag",
"hf thinfilm sim -d B70470726f786d61726b2e636f6d");
void *argtable[] = {
arg_param_begin,
arg_str1("d", "data", "<hex>", "bytes to send"),
arg_lit0(NULL, "raw", "raw, provided bytes should include CRC"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int data_len = 0;
uint8_t data[512] = {0};
CLIGetHexWithReturn(ctx, 1, data, &data_len);
bool addcrc = true;
bool errors = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_thinfilm_sim();
case 'd':
// Retrieve the data
param_gethex_ex(Cmd, cmdp + 1, data, &datalen);
datalen >>= 1;
cmdp += 2;
break;
case 'r':
addcrc = false;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
if (arg_get_lit(ctx, 2)) {
addcrc = false;
}
//Validations
if (errors || cmdp == 0 || datalen == 0 || datalen > 512) return usage_thinfilm_sim();
if (addcrc && datalen <= 510) {
CLIParserFree(ctx);
if (addcrc && data_len <= 510) {
uint8_t b1, b2;
compute_crc(CRC_14443_A, data, datalen, &b1, &b2);
data[datalen++] = b2;
data[datalen++] = b1;
compute_crc(CRC_14443_A, data, data_len, &b1, &b2);
data[data_len++] = b2;
data[data_len++] = b1;
}
clearCommandBuffer();
SendCommandNG(CMD_HF_THINFILM_SIMULATE, (uint8_t *)&data, datalen);
SendCommandNG(CMD_HF_THINFILM_SIMULATE, (uint8_t *)&data, data_len);
PacketResponseNG resp;
PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation");

View file

@ -14,6 +14,7 @@
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "cliparser.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "cmdtrace.h"
@ -393,21 +394,42 @@ static int topaz_print_NDEF(uint8_t *data, size_t maxsize) {
}
static int CmdHFTopazReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz reader",
"Read UID from Topaz tags",
"hf topaz reader");
bool verbose = true;
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 's') verbose = false;
void *argtable[] = {
arg_param_begin,
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool verbose = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
return readTopazUid(verbose);
}
// read a Topaz tag and print some useful information
static int CmdHFTopazInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz info",
"Get info from Topaz tags",
"hf topaz info");
bool verbose = true;
char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 's') verbose = false;
void *argtable[] = {
arg_param_begin,
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
bool verbose = arg_get_lit(ctx, 1);
CLIParserFree(ctx);
int status = readTopazUid(verbose);
if (status != PM3_SUCCESS)
@ -469,13 +491,34 @@ static int CmdHFTopazInfo(const char *Cmd) {
}
static int CmdHFTopazSim(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz sim",
"Simulate a Topaz tag",
"hf topaz sim <- Not yet implemented");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(INFO, "not yet implemented");
return PM3_SUCCESS;
}
static int CmdHFTopazCmdRaw(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz raw",
"Send raw hex data to Topaz tags",
"hf topaz raw <- Not yet implemented");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(INFO, "not yet implemented. Use hf 14 raw with option -T.");
return PM3_SUCCESS;
}
@ -490,6 +533,25 @@ static int CmdHFTopazList(const char *Cmd) {
return CmdTraceList(args);
}
static int CmdHFTopazSniff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf topaz sniff",
"Sniff Topaz reader-tag communication",
"hf topaz sniff");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
uint8_t param = 0;
SendCommandNG(CMD_HF_ISO14443A_SNIFF, (uint8_t *)&param, sizeof(uint8_t));
return PM3_SUCCESS;
}
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] = {
@ -498,7 +560,7 @@ static command_t CommandTable[] = {
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "<UID> -- Simulate Topaz tag"},
{"sniff", CmdHF14ASniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
{"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
{"raw", CmdHFTopazCmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
{NULL, NULL, 0, NULL}
};

View file

@ -1,5 +1,8 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// modified marshmellow
// modified Iceman, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -10,13 +13,11 @@
#include "cmdlfem410x.h"
#include "cmdlfem4x50.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <stdlib.h>
#include "fileutils.h"
#include "cmdparser.h" // command_t
#include "comms.h"
@ -37,88 +38,6 @@
static uint64_t g_em410xid = 0;
static int CmdHelp(const char *Cmd);
//////////////// 410x commands
static int usage_lf_em410x_demod(void) {
PrintAndLogEx(NORMAL, "Usage: lf em 410x_demod [h] [clock] <0|1> [maxError]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " clock - set clock as integer, optional, if not set, autodetect.");
PrintAndLogEx(NORMAL, " <0|1> - 0 normal output, 1 for invert output");
PrintAndLogEx(NORMAL, " maxerror - set maximum allowed errors, default = 100.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod") " = demod an EM410x Tag ID from GraphBuffer");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 32 1") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 1") " = demod an EM410x Tag ID from GraphBuffer while inverting data");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_demod 64 1 0") " = demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors");
return PM3_SUCCESS;
}
static int usage_lf_em410x_watch(void) {
PrintAndLogEx(NORMAL, "Enables IOProx compatible reader mode printing details of scanned tags.");
PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_watch");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_watch"));
return PM3_SUCCESS;
}
static int usage_lf_em410x_clone(void) {
PrintAndLogEx(NORMAL, "Writes EM410x ID to a T55x7 or Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_clone [h] <id> <card> [clock]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " <id> - ID number");
PrintAndLogEx(NORMAL, " <card> - 0|1 0 = Q5/T5555, 1 = T55x7");
PrintAndLogEx(NORMAL, " <clock> - 16|32|40|64, optional, set R/F clock rate, defaults to 64");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_clone 0F0368568B 1") " = write ID to t55x7 card");
return PM3_SUCCESS;
}
static int usage_lf_em410x_ws(void) {
PrintAndLogEx(NORMAL, "Watch 'nd Spoof, activates reader, waits until a EM410x tag gets presented then it starts simulating the found UID");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_spoof [h]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_spoof"));
return PM3_SUCCESS;
}
static int usage_lf_em410x_sim(void) {
PrintAndLogEx(NORMAL, "Simulating EM410x tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_sim [h] <uid> <clock>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " uid - uid (10 HEX symbols)");
PrintAndLogEx(NORMAL, " clock - clock (32|64) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_sim 0F0368568B 32"));
return PM3_SUCCESS;
}
static int usage_lf_em410x_brute(void) {
PrintAndLogEx(NORMAL, "Bruteforcing by emulating EM410x tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 410x_brute [h] ids.txt [d 2000] [c clock]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " ids.txt - file with UIDs in HEX format, one per line");
PrintAndLogEx(NORMAL, " d (2000) - pause delay in milliseconds between UIDs simulation, default 1000 ms (optional)");
PrintAndLogEx(NORMAL, " c (32) - clock (32|64), default 64 (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt c 32"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 410x_brute ids.txt d 3000 c 32"));
return PM3_SUCCESS;
}
/* Read the ID of an EM410x tag.
* Format:
* 1111 1111 1 <-- standard non-repeatable header
@ -129,63 +48,62 @@ static int usage_lf_em410x_brute(void) {
*/
// Construct the graph for emulating an EM410X tag
static void ConstructEM410xEmulGraph(const char *uid, const uint8_t clock) {
static void em410x_construct_emul_graph(uint8_t *uid, uint8_t clock) {
int i, j, binary[4], parity[4];
uint32_t n;
/* clear our graph */
// clear our graph
ClearGraph(true);
/* write 16 zero bit sledge */
for (i = 0; i < 20; i++)
// write 16 zero bit sledge
for (uint8_t i = 0; i < 20; i++)
AppendGraph(false, clock, 0);
/* write 9 start bits */
for (i = 0; i < 9; i++)
// write 9 start bits
for (uint8_t i = 0; i < 9; i++)
AppendGraph(false, clock, 1);
/* for each hex char */
parity[0] = parity[1] = parity[2] = parity[3] = 0;
for (i = 0; i < 10; i++) {
/* read each hex char */
sscanf(&uid[i], "%1x", &n);
for (j = 3; j >= 0; j--, n /= 2)
binary[j] = n % 2;
uint8_t bs[8], parity[8];
memset(parity, 0, sizeof(parity));
/* append each bit */
AppendGraph(false, clock, binary[0]);
AppendGraph(false, clock, binary[1]);
AppendGraph(false, clock, binary[2]);
AppendGraph(false, clock, binary[3]);
for (uint8_t i = 0; i < 5; i++) {
/* append parity bit */
AppendGraph(false, clock, binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
for (uint8_t j = 0; j < 8; j++) {
bs[j] = (uid[i] >> (7 - j) & 1);
}
PrintAndLogEx(DEBUG, "uid[%d] 0x%02x (%s)", i, uid[i], sprint_bin(bs, 4));
/* keep track of column parity */
parity[0] ^= binary[0];
parity[1] ^= binary[1];
parity[2] ^= binary[2];
parity[3] ^= binary[3];
for (uint8_t j = 0; j < 2; j++) {
// append each bit
AppendGraph(false, clock, bs[0 + (4 * j)]);
AppendGraph(false, clock, bs[1 + (4 * j)]);
AppendGraph(false, clock, bs[2 + (4 * j)]);
AppendGraph(false, clock, bs[3 + (4 * j)]);
// append parity bit
AppendGraph(false, clock, bs[0 + (4 * j)] ^ bs[1 + (4 * j)] ^ bs[2 + (4 * j)] ^ bs[3 + (4 * j)]);
// keep track of column parity
parity[0] ^= bs[0 + (4 * j)];
parity[1] ^= bs[1 + (4 * j)];
parity[2] ^= bs[2 + (4 * j)];
parity[3] ^= bs[3 + (4 * j)];
}
}
/* parity columns */
// parity columns
AppendGraph(false, clock, parity[0]);
AppendGraph(false, clock, parity[1]);
AppendGraph(false, clock, parity[2]);
AppendGraph(false, clock, parity[3]);
/* stop bit */
// stop bit
AppendGraph(true, clock, 0);
}
//by marshmellow
//print 64 bit EM410x ID in multiple formats
void printEM410x(uint32_t hi, uint64_t id) {
void printEM410x(uint32_t hi, uint64_t id, bool verbose) {
if (!id && !hi) return;
PrintAndLogEx(SUCCESS, "EM410x%s pattern found", (hi) ? " XL" : "");
uint64_t n = 1;
uint64_t id2lo = 0;
uint8_t m, i;
@ -195,26 +113,36 @@ void printEM410x(uint32_t hi, uint64_t id) {
}
}
if (verbose == false) {
if (hi) {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id);
} else {
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
}
return;
}
if (hi) {
//output 88 bit em id
PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%06X%016" PRIX64), hi, id);
PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock);
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%06X%016" PRIX64), hi, id);
PrintAndLogEx(SUCCESS, "EM410x XL ( RF/%d )", g_DemodClock);
} else {
//output 40 bit em id
PrintAndLogEx(NORMAL, "\nEM TAG ID : "_YELLOW_("%010" PRIX64), id);
PrintAndLogEx(NORMAL, "Clock rate : "_YELLOW_("RF/%d"), g_DemodClock);
PrintAndLogEx(NORMAL, "\nPossible de-scramble patterns\n");
PrintAndLogEx(NORMAL, "Unique TAG ID : %010" PRIX64, id2lo);
PrintAndLogEx(NORMAL, "HoneyWell IdentKey {");
PrintAndLogEx(NORMAL, "DEZ 8 : %08" PRIu64, id & 0xFFFFFF);
PrintAndLogEx(NORMAL, "DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF);
PrintAndLogEx(NORMAL, "DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF));
PrintAndLogEx(NORMAL, "DEZ 14/IK2 : %014" PRIu64, id);
PrintAndLogEx(NORMAL, "DEZ 15/IK3 : %015" PRIu64, id2lo);
PrintAndLogEx(NORMAL, "DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64,
PrintAndLogEx(SUCCESS, "EM 410x ID "_GREEN_("%010" PRIX64), id);
PrintAndLogEx(SUCCESS, "EM410x ( RF/%d )", g_DemodClock);
PrintAndLogEx(INFO, "-------- " _CYAN_("Possible de-scramble patterns") " ---------");
PrintAndLogEx(SUCCESS, "Unique TAG ID : %010" PRIX64, id2lo);
PrintAndLogEx(INFO, "HoneyWell IdentKey");
PrintAndLogEx(SUCCESS, " DEZ 8 : %08" PRIu64, id & 0xFFFFFF);
PrintAndLogEx(SUCCESS, " DEZ 10 : %010" PRIu64, id & 0xFFFFFFFF);
PrintAndLogEx(SUCCESS, " DEZ 5.5 : %05" PRIu64 ".%05" PRIu64, (id >> 16LL) & 0xFFFF, (id & 0xFFFF));
PrintAndLogEx(SUCCESS, " DEZ 3.5A : %03" PRIu64 ".%05" PRIu64, (id >> 32ll), (id & 0xFFFF));
PrintAndLogEx(SUCCESS, " DEZ 3.5B : %03" PRIu64 ".%05" PRIu64, (id & 0xFF000000) >> 24, (id & 0xFFFF));
PrintAndLogEx(SUCCESS, " DEZ 3.5C : %03" PRIu64 ".%05" PRIu64, (id & 0xFF0000) >> 16, (id & 0xFFFF));
PrintAndLogEx(SUCCESS, " DEZ 14/IK2 : %014" PRIu64, id);
PrintAndLogEx(SUCCESS, " DEZ 15/IK3 : %015" PRIu64, id2lo);
PrintAndLogEx(SUCCESS, " DEZ 20/ZK : %02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64 "%02" PRIu64,
(id2lo & 0xf000000000) >> 36,
(id2lo & 0x0f00000000) >> 32,
(id2lo & 0x00f0000000) >> 28,
@ -226,9 +154,11 @@ void printEM410x(uint32_t hi, uint64_t id) {
(id2lo & 0x00000000f0) >> 4,
(id2lo & 0x000000000f)
);
PrintAndLogEx(INFO, "");
uint64_t paxton = (((id >> 32) << 24) | (id & 0xffffff)) + 0x143e00;
PrintAndLogEx(NORMAL, "}\nOther : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF));
PrintAndLogEx(NORMAL, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton);
PrintAndLogEx(SUCCESS, "Other : %05" PRIu64 "_%03" PRIu64 "_%08" PRIu64, (id & 0xFFFF), ((id >> 16LL) & 0xFF), (id & 0xFFFFFF));
PrintAndLogEx(SUCCESS, "Pattern Paxton : %" PRIu64 " [0x%" PRIX64 "]", paxton, paxton);
uint32_t p1id = (id & 0xFFFFFF);
uint8_t arr[32] = {0x00};
@ -268,12 +198,13 @@ void printEM410x(uint32_t hi, uint64_t id) {
p1 |= arr[2] << 4;
p1 |= arr[1] << 5;
p1 |= arr[0] << 9;
PrintAndLogEx(NORMAL, "Pattern 1 : %d [0x%X]", p1, p1);
PrintAndLogEx(SUCCESS, "Pattern 1 : %d [0x%X]", p1, p1);
uint16_t sebury1 = id & 0xFFFF;
uint8_t sebury2 = (id >> 16) & 0x7F;
uint32_t sebury3 = id & 0x7FFFFF;
PrintAndLogEx(NORMAL, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3);
PrintAndLogEx(SUCCESS, "Pattern Sebury : %d %d %d [0x%X 0x%X 0x%X]", sebury1, sebury2, sebury3, sebury1, sebury2, sebury3);
PrintAndLogEx(INFO, "------------------------------------------------");
}
}
/* Read the ID of an EM410x tag.
@ -321,9 +252,8 @@ int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo) {
printDemodBuff(0, false, false, true);
}
if (verbose)
printEM410x(*hi, *lo);
printEM410x(*hi, *lo, verbose);
g_em410xid = *lo;
return PM3_SUCCESS;
}
@ -342,8 +272,19 @@ int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify,
// this read loops on device side.
// uses the demod in lfops.c
static int CmdEM410xWatch(const char *Cmd) {
uint8_t c = tolower(param_getchar(Cmd, 0));
if (c == 'h') return usage_lf_em410x_watch();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x watch",
"Enables Electro Marine (EM) compatible reader mode printing details of scanned tags.\n"
"Run until the button is pressed or another USB command is issued.",
"lf em 410x watch"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
PrintAndLogEx(SUCCESS, "Watching for EM410x cards - place tag on antenna");
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards");
@ -367,111 +308,189 @@ int demodEM410x(bool verbose) {
}
static int CmdEM410xDemod(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x demod",
"Try to find EM 410x preamble, if found decode / descramble data",
"lf em 410x demod -> demod an EM410x Tag ID from GraphBuffer\n"
"lf em 410x demod --clk 32 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32\n"
"lf em 410x demod --clk 32 -i -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/32 and inverting data\n"
"lf em 410x demod -i -> demod an EM410x Tag ID from GraphBuffer while inverting data\n"
"lf em 410x demod --clk 64 -i --err 0 -> demod an EM410x Tag ID from GraphBuffer using a clock of RF/64 and inverting data and allowing 0 demod errors"
);
void *argtable[] = {
arg_param_begin,
arg_u64_0(NULL, "clk", "<dec>", "optional - clock (default autodetect)"),
arg_u64_0(NULL, "err", "<dec>", "optional - maximum allowed errors (default 100)"),
arg_u64_0(NULL, "len", "<dec>", "optional - maximum length"),
arg_lit0("i", "invert", "optional - invert output"),
arg_lit0("a", "amp", "optional - amplify signal"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int clk = arg_get_u32_def(ctx, 1, 0);
int max_err = arg_get_u32_def(ctx, 2, 100);
size_t max_len = arg_get_u32_def(ctx, 3, 0);
bool invert = arg_get_lit(ctx, 4);
bool amplify = arg_get_lit(ctx, 5);
CLIParserFree(ctx);
uint32_t hi = 0;
uint64_t lo = 0;
int clk = 0;
int invert = 0;
int maxErr = 100;
size_t maxLen = 0;
char amp = tolower(param_getchar(Cmd, 0));
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &amp);
bool amplify = amp == 'a';
if (AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true) != PM3_SUCCESS)
if (AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, true) != PM3_SUCCESS)
return PM3_ESOFT;
g_em410xid = lo;
return PM3_SUCCESS;
}
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdEM410xRead(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 10 || cmdp == 'h') return usage_lf_em410x_demod();
static int CmdEM410xReader(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x reader",
"read EM 410x tag",
"lf em 410x reader -> reader\n"
"lf em 410x reader -@ -> continuous reader mode\n"
"lf em 410x reader --clk 32 -> reader using a clock of RF/32\n"
"lf em 410x reader --clk 32 -i -> reader using a clock of RF/32 and inverting data\n"
"lf em 410x reader -i -> reader while inverting data\n"
"lf em 410x reader --clk 64 -i --err 0 -> reader using a clock of RF/64 and inverting data and allowing 0 demod errors"
);
uint32_t hi = 0;
uint64_t lo = 0;
int clk = 0;
int invert = 0;
int maxErr = 100;
size_t maxLen = 0;
char amp = tolower(param_getchar(Cmd, 0));
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &amp);
bool amplify = amp == 'a';
lf_read(false, 12288);
return AskEm410xDemod(clk, invert, maxErr, maxLen, amplify, &hi, &lo, true);
void *argtable[] = {
arg_param_begin,
arg_u64_0(NULL, "clk", "<dec>", "optional - clock (default autodetect)"),
arg_u64_0(NULL, "err", "<dec>", "optional - maximum allowed errors (default 100)"),
arg_u64_0(NULL, "len", "<dec>", "optional - maximum length"),
arg_lit0("i", "invert", "optional - invert output"),
arg_lit0("a", "amp", "optional - amplify signal"),
arg_lit0("@", NULL, "optional - continuous reader mode"),
arg_lit0("v", "verbose", "verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int clk = arg_get_u32_def(ctx, 1, 0);
int max_err = arg_get_u32_def(ctx, 2, 100);
size_t max_len = arg_get_u32_def(ctx, 3, 0);
bool invert = arg_get_lit(ctx, 4);
bool amplify = arg_get_lit(ctx, 5);
bool cm = arg_get_lit(ctx, 6);
bool verbose = arg_get_lit(ctx, 7);
CLIParserFree(ctx);
if (cm) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
}
do {
uint32_t hi = 0;
uint64_t lo = 0;
lf_read(false, 12288);
AskEm410xDemod(clk, invert, max_err, max_len, amplify, &hi, &lo, verbose);
} while (cm && !kbd_enter_pressed());
return PM3_SUCCESS;
}
// emulate an EM410X tag
static int CmdEM410xSim(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_lf_em410x_sim();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x sim",
"Enables simulation of EM 410x card.\n"
"Simulation runs until the button is pressed or another USB command is issued.",
"lf em 410x sim --id 0F0368568B\n"
"lf em 410x sim --id 0F0368568B --clk 32"
);
uint8_t uid[5] = {0x00};
void *argtable[] = {
arg_param_begin,
arg_u64_0(NULL, "clk", "<dec>", "optional - clock [32|64] (default 64)"),
arg_str1("i", "id", "<hex>", "ID number (5 hex bytes)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
/* clock is 64 in EM410x tags */
uint8_t clk = 64;
// clock is 64 in EM410x tags
int clk = arg_get_u32_def(ctx, 1, 64);
int uid_len = 0;
uint8_t uid[5] = {0};
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
CLIParserFree(ctx);
if (param_gethex(Cmd, 0, uid, 10)) {
PrintAndLogEx(FAILED, "UID must include 10 HEX symbols");
if (uid_len != 5) {
PrintAndLogEx(FAILED, "UID must include 5 hex bytes (%u)", uid_len);
return PM3_EINVARG;
}
param_getdec(Cmd, 1, &clk);
PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%02X%02X%02X%02X%02X")" clock: "_YELLOW_("%d"), uid[0], uid[1], uid[2], uid[3], uid[4], clk);
PrintAndLogEx(SUCCESS, "Starting simulating UID "_YELLOW_("%s")" clock: "_YELLOW_("%d"), sprint_hex_inrow(uid, sizeof(uid)), clk);
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
ConstructEM410xEmulGraph(Cmd, clk);
em410x_construct_emul_graph(uid, clk);
CmdLFSim("0"); //240 start_gap.
CmdLFSim("0"); // 240 start_gap.
return PM3_SUCCESS;
}
static int CmdEM410xBrute(const char *Cmd) {
static int CmdEM410xBrute(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x brute",
"bruteforcing by emulating EM 410x tag",
"lf em 410x brute -f ids.txt\n"
"lf em 410x brute -f ids.txt --clk 32\n"
"lf em 410x brute -f ids.txt --delay 3000\n"
"lf em 410x brute -f ids.txt --delay 3000 --clk 32\n"
);
void *argtable[] = {
arg_param_begin,
arg_u64_1(NULL, "clk", "<dec>", "optional - clock [32|64] (default 64)"),
arg_u64_1(NULL, "delay", "<dec>", "optional - pause delay in milliseconds between UIDs simulation (default 1000ms)"),
arg_str1("f", "file", "<hex>", "file with UIDs in HEX format, one per line"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
// clock default 64 in EM410x
uint32_t clk = arg_get_u32_def(ctx, 1, 64);
// default pause time: 1 second
uint32_t delay = arg_get_u32_def(ctx, 2, 1000);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
FILE *f = NULL;
char buf[11];
uint32_t uidcnt = 0;
uint8_t stUidBlock = 20;
uint8_t *uidBlock = NULL, *p = NULL;
uint8_t uid[5] = {0x00};
/* clock is 64 in EM410x tags */
uint8_t clock1 = 64;
/* default pause time: 1 second */
uint32_t delay = 1000;
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_lf_em410x_brute();
cmdp = tolower(param_getchar(Cmd, 1));
if (cmdp == 'd') {
delay = param_get32ex(Cmd, 2, 1000, 10);
param_getdec(Cmd, 4, &clock1);
} else if (cmdp == 'c') {
param_getdec(Cmd, 2, &clock1);
delay = param_get32ex(Cmd, 4, 1000, 10);
}
int filelen = param_getstr(Cmd, 0, filename, FILE_PATH_SIZE);
if (filelen == 0) {
if (fnlen == 0) {
PrintAndLogEx(ERR, "Error: Please specify a filename");
return PM3_EINVARG;
}
uint32_t uidcnt = 0;
uint8_t stUidBlock = 20;
uint8_t *p = NULL;
uint8_t uid[5] = {0x00};
// open file
FILE *f = NULL;
if ((f = fopen(filename, "r")) == NULL) {
PrintAndLogEx(ERR, "Error: Could not open UIDs file ["_YELLOW_("%s")"]", filename);
return PM3_EFILE;
}
uidBlock = calloc(stUidBlock, 5);
if (uidBlock == NULL) {
// allocate mem for file contents
uint8_t *uidblock = calloc(stUidBlock, 5);
if (uidblock == NULL) {
fclose(f);
return PM3_ESOFT;
PrintAndLogEx(ERR, "Error: can't allocate memory");
return PM3_EMALLOC;
}
// read file into memory
char buf[11];
while (fgets(buf, sizeof(buf), f)) {
if (strlen(buf) < 10 || buf[9] == '\n') continue;
while (fgetc(f) != '\n' && !feof(f)); //goto next line
@ -481,7 +500,7 @@ static int CmdEM410xBrute(const char *Cmd) {
if (param_gethex(buf, 0, uid, 10)) {
PrintAndLogEx(FAILED, "UIDs must include 10 HEX symbols");
free(uidBlock);
free(uidblock);
fclose(f);
return PM3_ESOFT;
}
@ -489,109 +508,118 @@ static int CmdEM410xBrute(const char *Cmd) {
buf[10] = 0;
if (stUidBlock - uidcnt < 2) {
p = realloc(uidBlock, 5 * (stUidBlock += 10));
p = realloc(uidblock, 5 * (stUidBlock += 10));
if (!p) {
PrintAndLogEx(WARNING, "Cannot allocate memory for UIDs");
free(uidBlock);
free(uidblock);
fclose(f);
return PM3_ESOFT;
}
uidBlock = p;
uidblock = p;
}
memset(uidBlock + 5 * uidcnt, 0, 5);
num_to_bytes(strtoll(buf, NULL, 16), 5, uidBlock + 5 * uidcnt);
memset(uidblock + 5 * uidcnt, 0, 5);
num_to_bytes(strtoll(buf, NULL, 16), 5, uidblock + 5 * uidcnt);
uidcnt++;
memset(buf, 0, sizeof(buf));
}
fclose(f);
if (uidcnt == 0) {
PrintAndLogEx(FAILED, "No UIDs found in file");
free(uidBlock);
free(uidblock);
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Loaded "_YELLOW_("%d")" UIDs from "_YELLOW_("%s")", pause delay:"_YELLOW_("%d")" ms", uidcnt, filename, delay);
// loop
uint8_t testuid[5];
for (uint32_t c = 0; c < uidcnt; ++c) {
char testuid[11];
testuid[10] = 0;
if (kbd_enter_pressed()) {
PrintAndLogEx(WARNING, "\nAborted via keyboard!\n");
free(uidBlock);
free(uidblock);
return PM3_EOPABORTED;
}
sprintf(testuid, "%010" PRIX64, bytes_to_num(uidBlock + 5 * c, 5));
PrintAndLogEx(NORMAL, "Bruteforce %d / %d: simulating UID %s, clock %d", c + 1, uidcnt, testuid, clock1);
memcpy(testuid, uidblock + 5 * c, 5);
PrintAndLogEx(INFO, "Bruteforce %d / %d: simulating UID " _YELLOW_("%s")
, c + 1
, uidcnt
, sprint_hex_inrow(testuid, sizeof(testuid))
);
ConstructEM410xEmulGraph(testuid, clock1);
em410x_construct_emul_graph(testuid, clk);
CmdLFSim("0"); //240 start_gap.
msleep(delay);
}
free(uidBlock);
free(uidblock);
return PM3_SUCCESS;
}
//currently only supports manchester modulations
static int CmdEM410xWatchnSpoof(const char *Cmd) {
static int CmdEM410xSpoof(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x spoof",
"Watch 'nd Spoof, activates reader\n"
"Waits until a EM 410x tag gets presented then Proxmark3 starts simulating the found UID",
"lf em 410x spoof"
);
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_lf_em410x_ws();
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
// loops if the captured ID was in XL-format.
CmdEM410xWatch(Cmd);
CmdEM410xReader("-@");
PrintAndLogEx(SUCCESS, "# Replaying captured ID: "_YELLOW_("%010" PRIx64), g_em410xid);
CmdLFaskSim("");
return PM3_SUCCESS;
}
static int CmdEM410xClone(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 0x00 || cmdp == 'h') return usage_lf_em410x_clone();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 410x clone",
"Writes EM410x ID to a T55x7 or Q5/T5555 tag",
"lf em 410x clone --id 0F0368568B -> write id to T55x7 tag\n"
"lf em 410x clone --id 0F0368568B --q5 -> write id to Q5/T5555 tag"
);
uint64_t id = param_get64ex(Cmd, 0, -1, 16);
uint8_t card = param_get8ex(Cmd, 1, 0xFF, 10);
uint8_t clock1 = param_get8ex(Cmd, 2, 0, 10);
void *argtable[] = {
arg_param_begin,
arg_u64_0(NULL, "clk", "<dec>", "optional - clock <16|32|40|64> (default 64)"),
arg_str1("u", "uid", "<hex>", "ID number (5 hex bytes)"),
arg_lit0(NULL, "q5", "optional - specify writing to Q5/T5555 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
// Check ID
if (id == 0xFFFFFFFFFFFFFFFF) {
PrintAndLogEx(ERR, "error, ID is required\n");
usage_lf_em410x_clone();
return PM3_EINVARG;
}
if (id >= 0x10000000000) {
PrintAndLogEx(ERR, "error, given EM410x ID is longer than 40 bits\n");
usage_lf_em410x_clone();
return PM3_EINVARG;
}
// clock default 64 in EM410x
uint32_t clk = arg_get_u32_def(ctx, 1, 64);
int uid_len = 0;
uint8_t uid[5] = {0};
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
bool q5 = arg_get_lit(ctx, 3);
CLIParserFree(ctx);
// Check Card
if (card > 1) {
PrintAndLogEx(FAILED, "error, bad card type selected\n");
usage_lf_em410x_clone();
return PM3_EINVARG;
}
// Check Clock
if (clock1 == 0)
clock1 = 64;
uint64_t id = bytes_to_num(uid, uid_len);
// Allowed clock rates: 16, 32, 40 and 64
if ((clock1 != 16) && (clock1 != 32) && (clock1 != 64) && (clock1 != 40)) {
PrintAndLogEx(FAILED, "error, clock rate" _RED_("%d")" not valid", clock1);
PrintAndLogEx(INFO, "supported clock rates: " _YELLOW_("16, 32, 40, 60") "\n");
usage_lf_em410x_clone();
if ((clk != 16) && (clk != 32) && (clk != 64) && (clk != 40)) {
PrintAndLogEx(FAILED, "supported clock rates are " _YELLOW_("16, 32, 40, 64") " got " _RED_("%d") "\n", clk);
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "Writing " _YELLOW_("%s") " tag with UID 0x%010" PRIx64 " (clock rate: %d)", (card == 1) ? "T55x7" : "Q5/T5555", id, clock1);
char cardtype[16] = {"T55x7"};
if (q5) {
snprintf(cardtype, sizeof(cardtype), "Q5/T5555");
}
PrintAndLogEx(SUCCESS, "Preparing to clone EM4102 to " _YELLOW_("%s") " tag with ID " _GREEN_("%010" PRIX64) " (RF/%d)", cardtype, id, clk);
// NOTE: We really should pass the clock in as a separate argument, but to
// provide for backwards-compatibility for older firmware, and to avoid
// having to add another argument to CMD_LF_EM410X_WRITE, we just store
@ -604,8 +632,8 @@ static int CmdEM410xClone(const char *Cmd) {
uint32_t low;
} PACKED params;
params.card = card;
params.clock = clock1;
params.card = (q5) ? 0 : 1;
params.clock = clk;
params.high = (uint32_t)(id >> 32);
params.low = (uint32_t)id;
@ -617,7 +645,7 @@ static int CmdEM410xClone(const char *Cmd) {
switch (resp.status) {
case PM3_SUCCESS: {
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x reader`") " to verify");
break;
}
default: {
@ -629,15 +657,15 @@ static int CmdEM410xClone(const char *Cmd) {
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
//{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"},
{"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"},
{"read", CmdEM410xRead, IfPm3Lf, "attempt to read and extract tag data"},
{"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"},
{"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"},
{"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
{"help", CmdHelp, AlwaysAvailable, "This help"},
//{"demod", CmdEMdemodASK, IfPm3Lf, "Extract ID from EM410x tag on antenna)"},
{"demod", CmdEM410xDemod, AlwaysAvailable, "demodulate a EM410x tag from the GraphBuffer"},
{"reader", CmdEM410xReader, IfPm3Lf, "attempt to read and extract tag data"},
{"sim", CmdEM410xSim, IfPm3Lf, "simulate EM410x tag"},
{"brute", CmdEM410xBrute, IfPm3Lf, "reader bruteforce attack by simulating EM410x tags"},
{"watch", CmdEM410xWatch, IfPm3Lf, "watches for EM410x 125/134 kHz tags (option 'h' for 134)"},
{"spoof", CmdEM410xSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
{NULL, NULL, NULL, NULL}
};

View file

@ -16,7 +16,7 @@
int CmdLFEM410X(const char *Cmd);
int demodEM410x(bool verbose);
void printEM410x(uint32_t hi, uint64_t id);
void printEM410x(uint32_t hi, uint64_t id, bool verbose);
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);

File diff suppressed because it is too large Load diff

View file

@ -11,20 +11,27 @@
#ifndef CMDLFEM4X50_H__
#define CMDLFEM4X50_H__
#include"common.h"
#include "em4x50.h"
int CmdLFEM4X50(const char *Cmd);
int read_em4x50_uid(void);
bool detect_4x50_block(void);
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose);
int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out);
int CmdEM4x50Info(const char *Cmd);
int CmdEM4x50Write(const char *Cmd);
int CmdEM4x50WritePassword(const char *Cmd);
int CmdEM4x50WritePwd(const char *Cmd);
int CmdEM4x50Read(const char *Cmd);
int CmdEM4x50Dump(const char *Cmd);
int CmdEM4x50Wipe(const char *Cmd);
int CmdEM4x50Brute(const char *Cmd);
int CmdEM4x50Login(const char *Cmd);
int CmdEM4x50Restore(const char *Cmd);
int CmdEM4x50Sim(const char *Cmd);
int CmdEM4x50Reader(const char *Cmd);
int CmdEM4x50ELoad(const char *Cmd);
int CmdEM4x50ESave(const char *Cmd);
int CmdEM4x50Chk(const char *Cmd);
#endif

View file

@ -51,6 +51,7 @@ t55xx_conf_block_t config = {
.inverted = false,
.offset = 0x00,
.block0 = 0x00,
.block0Status = notSet,
.Q5 = false,
.usepwd = false,
.downlink_mode = refFixedBit
@ -739,6 +740,7 @@ static int CmdT55xxSetConfig(const char *Cmd) {
for (; i < 9; i++) {
if (rates[i] == bitRate) {
config.bitrate = i;
config.block0 = ((config.block0 & ~(0x1c0000)) | (i << 18));
break;
}
}
@ -789,6 +791,7 @@ static int CmdT55xxSetConfig(const char *Cmd) {
PrintAndLogEx(WARNING, "Unknown modulation '%s'", modulation);
errors = true;
}
config.block0 = ((config.block0 & ~(0x1f000)) | (config.modulation << 12));
break;
case 'i':
if ((param_getchar(Cmd, cmdp + 1) == '0') || (param_getchar(Cmd, cmdp + 1) == '1')) {
@ -822,6 +825,7 @@ static int CmdT55xxSetConfig(const char *Cmd) {
config.ST = true;
cmdp += 1;
}
config.block0 = ((config.block0 & ~(0x8)) | (config.ST << 3));
break;
case 'r':
errors = param_getdec(Cmd, cmdp + 1, &downlink_mode);
@ -841,10 +845,9 @@ static int CmdT55xxSetConfig(const char *Cmd) {
//Validations
if (errors) return usage_t55xx_config();
config.block0Status = userSet;
if (gotconf) {
SetConfigWithBlock0Ex(block0, config.offset, config.Q5);
} else {
config.block0 = 0;
}
return printConfiguration(config);
@ -1335,6 +1338,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32
config.pwd = pwd & 0xffffffff;
}
config.block0Status = autoDetect;
if (print_config)
printConfiguration(config);
@ -1370,6 +1374,7 @@ bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32
PrintAndLogEx(NORMAL, "--[%d]---------------", i + 1);
}
config.block0Status = autoDetect;
if (print_config)
printConfiguration(tests[i]);
}
@ -1640,7 +1645,7 @@ int printConfiguration(t55xx_conf_block_t b) {
PrintAndLogEx(INFO, " Inverted : %s", (b.inverted) ? _GREEN_("Yes") : "No");
PrintAndLogEx(INFO, " Offset : %d", b.offset);
PrintAndLogEx(INFO, " Seq. Term. : %s", (b.ST) ? _GREEN_("Yes") : "No");
PrintAndLogEx(INFO, " Block0 : 0x%08X", b.block0);
PrintAndLogEx(INFO, " Block0 : 0x%08X %s", b.block0, GetConfigBlock0Source(b.block0Status));
PrintAndLogEx(INFO, " Downlink Mode : %s", GetDownlinkModeStr(b.downlink_mode));
PrintAndLogEx(INFO, " Password Set : %s", (b.usepwd) ? _RED_("Yes") : _GREEN_("No"));
if (b.usepwd) {
@ -2800,6 +2805,28 @@ char *GetModelStrFromCID(uint32_t cid) {
return buf;
}
char *GetConfigBlock0Source(uint8_t id) {
static char buf[40];
char *retStr = buf;
switch (id) {
case autoDetect:
snprintf(retStr, sizeof(buf), _YELLOW_("(Auto detect)"));
break;
case userSet:
snprintf(retStr, sizeof(buf), _YELLOW_("(User set)"));
break;
case tagRead:
snprintf(retStr, sizeof(buf), _GREEN_("(Tag read)"));
break;
default:
snprintf(retStr, sizeof(buf), _RED_("(Unknown)"));
break;
}
return buf;
}
char *GetSelectedModulationStr(uint8_t id) {
static char buf[20];

View file

@ -125,6 +125,12 @@ typedef struct {
bool inverted;
uint8_t offset;
uint32_t block0;
enum {
notSet = 0x00,
autoDetect = 0x01,
userSet = 0x02,
tagRead = 0x03,
} block0Status;
enum {
RF_8 = 0x00,
RF_16 = 0x01,
@ -166,6 +172,7 @@ char *GetSaferStr(uint32_t id);
char *GetQ5ModulationStr(uint32_t id);
char *GetModulationStr(uint32_t id, bool xmode);
char *GetModelStrFromCID(uint32_t cid);
char *GetConfigBlock0Source(uint8_t id);
char *GetSelectedModulationStr(uint8_t id);
char *GetDownlinkModeStr(uint8_t downlink_mode);
void printT5xxHeader(uint8_t page);

View file

@ -123,7 +123,7 @@ int CmdWiegandDecode(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_lit0("p", "parity", "ignore invalid parity"),
arg_strx1(NULL, "raw", "<hex>", "raw hex to be decoded"),
arg_strx1("r", "raw", "<hex>", "raw hex to be decoded"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -521,6 +521,20 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
}
break;
}
case jsfEM4x50: {
JsonSaveStr(root, "FileType", "EM4X50");
JsonSaveBufAsHexCompact(root, "$.Card.Protection", data + (1 * 4), 4);
JsonSaveBufAsHexCompact(root, "$.Card.Config", data + (2 * 4), 4);
JsonSaveBufAsHexCompact(root, "$.Card.Serial", data + (32 * 4), 4);
JsonSaveBufAsHexCompact(root, "$.Card.UID", data + (33 * 4), 4);
for (size_t i = 0; i < (datalen / 4); i++) {
char path[PATH_MAX_LENGTH] = {0};
sprintf(path, "$.blocks.%zu", i);
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
}
break;
}
case jsfMfPlusKeys: {
JsonSaveStr(root, "FileType", "mfp");
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
@ -1139,6 +1153,27 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
*datalen = sptr;
}
if (!strcmp(ctype, "EM4X50")) {
size_t sptr = 0;
for (size_t i = 0; i < (maxdatalen / 4); i++) {
if (sptr + 4 > maxdatalen) {
retval = PM3_EMALLOC;
goto out;
}
char blocks[30] = {0};
sprintf(blocks, "$.blocks.%zu", i);
size_t len = 0;
JsonLoadBufAsHex(root, blocks, &udata[sptr], 4, &len);
if (!len)
break;
sptr += len;
}
*datalen = sptr;
}
out:
if (callback != NULL) {

View file

@ -66,6 +66,7 @@ typedef enum {
jsfMfDesfireKeys,
jsfEM4x05,
jsfEM4x69,
jsfEM4x50,
} JSONFileType;
typedef enum {

View file

@ -1146,8 +1146,7 @@ static int l_em4x50_read(lua_State *L) {
em4x50_data_t etd;
memset(&etd, 0x00, sizeof(em4x50_data_t));
etd.addr_given = true;
etd.address = addr & 0xFF;
etd.newpwd_given = false;
etd.addresses = addr & 0xFF;
// get password
const char *p_pwd = luaL_checkstring(L, 2);
@ -1162,31 +1161,29 @@ static int l_em4x50_read(lua_State *L) {
PrintAndLogEx(DEBUG, " Pwd %08X", pwd);
etd.password[0] = pwd & 0xFF;
etd.password[1] = (pwd >> 8) & 0xFF;
etd.password[2] = (pwd >> 16) & 0xFF;
etd.password[3] = (pwd >> 24) & 0xFF;
etd.password1 = pwd;
etd.pwd_given = true;
}
PrintAndLogEx(DEBUG, "Addr %u", etd.address);
PrintAndLogEx(DEBUG, "Addr %u", etd.addresses & 0xFF);
if (etd.pwd_given)
PrintAndLogEx(DEBUG, " Pwd %s", sprint_hex(etd.password, sizeof(etd.password)));
PrintAndLogEx(DEBUG, " Pwd %08x", etd.password1);
em4x50_word_t words[EM4X50_NO_WORDS];
int res = em4x50_read(&etd, words, false);
int res = em4x50_read(&etd, words);
if (res != PM3_SUCCESS) {
return returnToLuaWithError(L, "Failed to read EM4x50 data");
}
uint32_t word = (
words[etd.address].byte[0] << 24 |
words[etd.address].byte[1] << 16 |
words[etd.address].byte[2] << 8 |
words[etd.address].byte[3]
words[etd.addresses & 0xFF].byte[0] << 24 |
words[etd.addresses & 0xFF].byte[1] << 16 |
words[etd.addresses & 0xFF].byte[2] << 8 |
words[etd.addresses & 0xFF].byte[3]
);
lua_pushinteger(L, word);
return 1;
}

View file

@ -97,6 +97,22 @@ uint16_t reflect16(uint16_t b) {
return v;
}
uint32_t reflect32(uint32_t b) {
// https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
uint32_t v = b; // 32-bit word to reverse bit order
// swap odd and even bits
v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
// swap consecutive pairs
v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
// swap nibbles ...
v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
// swap bytes
v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
// swap 2-byte long pairs
v = ( v >> 16 ) | ( v << 16);
return v;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t *dest) {
while (len--) {
dest[len] = (uint8_t) n;

View file

@ -47,6 +47,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
uint32_t reflect(uint32_t v, int b); // used in crc.c ...
uint8_t reflect8(uint8_t b); // dedicated 8bit reversal
uint16_t reflect16(uint16_t b); // dedicated 16bit reversal
uint32_t reflect32(uint32_t b); // dedicated 32bit reversal
void num_to_bytes(uint64_t n, size_t len, uint8_t *dest);
uint64_t bytes_to_num(uint8_t *src, size_t len);

View file

@ -141,13 +141,6 @@ hf mfu otptear
hf mfdes enum
hf mfdes getuid
hf mfdes info
hf thinfilm info
hf thinfilm sim
hf topaz info
hf topaz reader
hf topaz sim
hf topaz sniff
hf topaz raw
hw connect
hw dbg
hw detectreader
@ -174,11 +167,14 @@ lf simfsk
lf simpsk
lf simbidir
lf sniff
lf tune
lf em 410x
lf em 4x05
lf em 4x50
lf hitag info
lf hitag reader
lf hitag sim
lf hitag sniff
lf hitag writer
lf hitag dump
lf hitag cc

View file

@ -34,32 +34,20 @@
#define LAST_WORD_WRITE_INHIBITED 3 // fourth byte
// misc
#define STATUS_NO_WORDS 0xfc
#define STATUS_SUCCESS 0x2
#define STATUS_LOGIN 0x1
#define NO_CHARS_MAX 400
#define TIMEOUT 2000
#define DUMP_FILESIZE 136
typedef struct {
bool addr_given;
bool pwd_given;
bool newpwd_given;
uint8_t password[4];
uint8_t new_password[4];
uint8_t addresses[4];
uint8_t address;
uint8_t word[4];
uint32_t password1;
uint32_t password2;
uint32_t word;
uint32_t addresses;
} PACKED em4x50_data_t;
typedef struct {
uint8_t byte[4];
uint8_t row_parity[4];
uint8_t col_parity;
uint8_t stopbit;
bool rparity[4];
bool cparity[8];
bool stopparity;
bool parity;
} PACKED em4x50_word_t;
#endif /* EM4X50_H__ */

View file

@ -508,11 +508,15 @@ typedef struct {
#define CMD_LF_EM410X_WATCH 0x021C
#define CMD_LF_EM4X50_INFO 0x0240
#define CMD_LF_EM4X50_WRITE 0x0241
#define CMD_LF_EM4X50_WRITE_PASSWORD 0x0242
#define CMD_LF_EM4X50_WRITEPWD 0x0242
#define CMD_LF_EM4X50_READ 0x0243
#define CMD_LF_EM4X50_WIPE 0x0244
#define CMD_LF_EM4X70_INFO 0x0250
#define CMD_LF_EM4X50_BRUTE 0x0245
#define CMD_LF_EM4X50_LOGIN 0x0246
#define CMD_LF_EM4X50_SIM 0x0250
#define CMD_LF_EM4X50_READER 0x0251
#define CMD_LF_EM4X50_ESET 0x0252
#define CMD_LF_EM4X50_CHK 0x0253
#define CMD_LF_EM4X70_INFO 0x0260
// Sampling configuration for LF reader/sniffer
#define CMD_LF_SAMPLING_SET_CONFIG 0x021D
#define CMD_LF_FSK_SIMULATE 0x021E

View file

@ -391,7 +391,7 @@ while true; do
"Fmt 26 FC: 123 Card: 1337 checksum: 10"; then break; fi
if ! CheckExecute slow "lf T55 indala_224 test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf search 1'" "Indala ID found"; then break; fi
if ! CheckExecute slow "lf T55 indala_224 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_224.pm3; lf indala demod'" \
"Indala - len 224 Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi
"Indala (len 224) Raw: 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"; then break; fi
if ! CheckExecute slow "lf T55 io test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf search 1'" "IO Prox ID found"; then break; fi
if ! CheckExecute slow "lf T55 io test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_io.pm3; lf io demod'" \
"IO Prox - XSF(01)01:01337, Raw: 007840603059cf3f (ok)"; then break; fi