mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
4x50 standalone mode
This commit is contained in:
parent
2829e20d4b
commit
1ca5d3c53c
6 changed files with 450 additions and 100 deletions
|
@ -35,6 +35,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| LF_SAMYRUN | HID26 read/clone/sim |
|
||||
| | - Samy Kamkar |
|
||||
+----------------------------------------------------------+
|
||||
| LF_THAREXDE | Simulate/read EM4x50 tags |
|
||||
| (RDV4 only) | storing in flashmem |
|
||||
+----------------------------------------------------------+
|
||||
| HF_14ASNIFF | 14a sniff to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -67,10 +70,10 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_TCPRST HF_YOUNG
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID LF_THAREXDE HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)
|
||||
|
|
|
@ -73,3 +73,7 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_iceclass.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_THAREXDE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_tharexde.c
|
||||
endif
|
||||
|
|
271
armsrc/Standalone/lf_tharexde.c
Normal file
271
armsrc/Standalone/lf_tharexde.c
Normal file
|
@ -0,0 +1,271 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// tharexde, 2021
|
||||
//
|
||||
// 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 "ticks.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 EM4x50 dumps uploaded 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 simulating EM4x50 data.
|
||||
* Data is read from eml dump file uploaded to flash memory.
|
||||
*
|
||||
* On switching to read/record mode by pressing pm3 button, module will start
|
||||
* reading/recording 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 upload input file (eml format) to flash:
|
||||
* - mem spiffs load f <filename> o lf_em4x50_simulate.eml
|
||||
*
|
||||
* To retrieve log file from flash:
|
||||
* - mem spiffs dump o lf_em4x50_collect.log f <filename>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* To delete the log file from flash:
|
||||
* - mem spiffs remove lf_em4x50_collect.log
|
||||
*/
|
||||
|
||||
#define STATE_SIM 0
|
||||
#define STATE_READ 1
|
||||
#define EM4X50_TAG_WORD 45
|
||||
#define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml"
|
||||
#define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log"
|
||||
|
||||
bool input_exists;
|
||||
bool log_exists;
|
||||
|
||||
static void LoadDataInstructions(const char *inputfile) {
|
||||
Dbprintf("");
|
||||
Dbprintf("To load datafile to flash and display it:");
|
||||
Dbprintf(_YELLOW_("1.") " edit input file %s", inputfile);
|
||||
Dbprintf(_YELLOW_("2.") " start proxmark3 client");
|
||||
Dbprintf(_YELLOW_("3.") " mem spiffs load f <filename> o %s", 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 <filename>", logfile);
|
||||
Dbprintf(_YELLOW_("2.") " exit proxmark3 client");
|
||||
Dbprintf(_YELLOW_("3.") " cat <filename>");
|
||||
}
|
||||
|
||||
static bool get_input_data_from_file(uint32_t *tag, 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++)
|
||||
tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
|
||||
|
||||
Dbprintf(_YELLOW_("read tag data from input file"));
|
||||
}
|
||||
|
||||
BigBuf_free();
|
||||
|
||||
return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]));
|
||||
}
|
||||
|
||||
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 mode") " - a.k.a tharexde");
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
|
||||
bool state_change = true;
|
||||
int no_words = 0, command = 0;
|
||||
uint8_t entry[81], state = STATE_SIM;
|
||||
uint32_t tag[EM4X50_NO_WORDS] = {0x0};
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
StandAloneMode();
|
||||
Dbprintf(_YELLOW_("Standalone mode THAREXDE started"));
|
||||
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
if (data_available()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// press button - toggle between SIM and READ
|
||||
// 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_SIM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
state_change = true;
|
||||
|
||||
} else if (button_pressed == BUTTON_HOLD) {
|
||||
SpinDown(100);
|
||||
break;
|
||||
}
|
||||
|
||||
if (state == STATE_SIM) {
|
||||
|
||||
if (state_change) {
|
||||
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("switched to EM4x50 simulating mode"));
|
||||
|
||||
if (get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM)) {
|
||||
Dbprintf(_YELLOW_("tag data ok"));
|
||||
} else {
|
||||
Dbprintf(_RED_("error in tag data"));
|
||||
}
|
||||
|
||||
// init; start with command = standard read mode
|
||||
em4x50_setup_sim();
|
||||
gLogin = false;
|
||||
gWritePasswordProcess = false;
|
||||
command = EM4X50_COMMAND_STANDARD_READ;
|
||||
|
||||
state_change = false;
|
||||
}
|
||||
|
||||
em4x50_handle_commands(&command, tag);
|
||||
|
||||
// stop if key (pm3 button or enter key) has been pressed
|
||||
if (command == PM3_EOPABORTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
// if timeout (e.g. no reader field) continue with standard read
|
||||
// mode and reset former authentication
|
||||
if (command == PM3_ETIMEOUT) {
|
||||
command = EM4X50_COMMAND_STANDARD_READ;
|
||||
gLogin = false;
|
||||
}
|
||||
|
||||
} 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(tag, 0, sizeof(tag));
|
||||
|
||||
log_exists = exists_in_spiffs(LF_EM4X50_LOGFILE_COLLECT);
|
||||
|
||||
em4x50_setup_read();
|
||||
|
||||
state_change = false;
|
||||
}
|
||||
|
||||
standard_read(&no_words, tag);
|
||||
|
||||
// reset timers
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
|
||||
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
|
||||
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
|
||||
|
||||
if (no_words > 0) {
|
||||
|
||||
memset(entry, 0, sizeof(entry));
|
||||
|
||||
Dbprintf("");
|
||||
sprintf((char *)entry, "found new EM4x50 tag:");
|
||||
Dbprintf("%s", entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry));
|
||||
|
||||
for (int i = 0; i < no_words; i++) {
|
||||
|
||||
sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, tag[i]);
|
||||
Dbprintf("%s", entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry));
|
||||
}
|
||||
}
|
||||
|
||||
memset(tag, 0, sizeof(tag));
|
||||
no_words = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == STATE_READ) {
|
||||
DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT);
|
||||
} else {
|
||||
LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM);
|
||||
}
|
||||
|
||||
LED_D_ON();
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_D_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped"));
|
||||
}
|
249
armsrc/em4x50.c
249
armsrc/em4x50.c
|
@ -24,11 +24,17 @@
|
|||
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
|
||||
// EM4x50 units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier)
|
||||
// T0 = TIMER_CLOCK1 / 125000 = 192
|
||||
|
||||
#ifndef T0
|
||||
#define T0 192
|
||||
#endif
|
||||
|
||||
// the following terms are used (for carrier frequency of 125 kHz):
|
||||
// 1 us = 1.5 ticks
|
||||
// 1 cycle = 1 period = 8 us = 12 ticks
|
||||
// 1 bit = 64 cycles = 768 ticks = 512 us
|
||||
#define CYCLES2TICKS 12
|
||||
|
||||
// given in cycles/periods
|
||||
#define EM4X50_T_TAG_QUARTER_PERIOD 16
|
||||
#define EM4X50_T_TAG_HALF_PERIOD 32
|
||||
#define EM4X50_T_TAG_THREE_QUARTER_PERIOD 48
|
||||
|
@ -40,27 +46,21 @@
|
|||
#define EM4X50_T_TAG_WAITING_FOR_SIGNAL 75
|
||||
#define EM4X50_T_WAITING_FOR_DBLLIW 1550
|
||||
#define EM4X50_T_WAITING_FOR_ACK 4
|
||||
#define EM4X50_TAG_TOLERANCE 8
|
||||
#define EM4X50_ZERO_DETECTION 3
|
||||
|
||||
// timeout values for simulation mode (may vary with regard to reader)
|
||||
// timeout values (empirical) for simulation mode (may vary with regard to reader)
|
||||
#define EM4X50_T_SIMULATION_TIMEOUT_READ 600
|
||||
#define EM4X50_T_SIMULATION_TIMEOUT_WAIT 50
|
||||
|
||||
// the following value seems to be critical; if it's too low (e.g. < 120)
|
||||
// some cards are no longer readable although they're ok
|
||||
// the following value (pulses) seems to be critical; if it's too low
|
||||
//(e.g. < 120) some cards are no longer readable although they're ok
|
||||
#define EM4X50_T_WAITING_FOR_SNGLLIW 140
|
||||
|
||||
#define EM4X50_TAG_TOLERANCE 8
|
||||
#define EM4X50_ZERO_DETECTION 3
|
||||
// div
|
||||
#define EM4X50_TAG_WORD 45
|
||||
#define EM4X50_TAG_MAX_NO_BYTES 136
|
||||
|
||||
#define EM4X50_COMMAND_LOGIN 0x01
|
||||
#define EM4X50_COMMAND_RESET 0x80
|
||||
#define EM4X50_COMMAND_WRITE 0x12
|
||||
#define EM4X50_COMMAND_WRITE_PASSWORD 0x11
|
||||
#define EM4X50_COMMAND_SELECTIVE_READ 0x0A
|
||||
#define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command
|
||||
|
||||
int gHigh = 190;
|
||||
int gLow = 60;
|
||||
|
||||
|
@ -74,11 +74,15 @@ bool gWritePasswordProcess = false;
|
|||
|
||||
// do nothing for <period> using timer0
|
||||
static void wait_timer(uint32_t period) {
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV < period);
|
||||
|
||||
int timeout = period;
|
||||
uint32_t tval = GetTicks();
|
||||
|
||||
//AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
//while (AT91C_BASE_TC0->TC_CV < period);
|
||||
while ((timeout--) && (GetTicks() - tval < period));
|
||||
}
|
||||
|
||||
|
||||
// extract and check parities
|
||||
// return result of parity check and extracted plain data
|
||||
static bool extract_parities(uint64_t word, uint32_t *data) {
|
||||
|
@ -130,13 +134,16 @@ static bool extract_parities(uint64_t word, uint32_t *data) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static void em4x50_setup_read(void) {
|
||||
void em4x50_setup_read(void) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
StartTicks();
|
||||
|
||||
// 50ms for the resonant antenna to settle.
|
||||
SpinDelay(50);
|
||||
//SpinDelay(50);
|
||||
WaitMS(50);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
|
||||
|
@ -154,6 +161,7 @@ static void em4x50_setup_read(void) {
|
|||
// Disable modulation at default, which means enable the field
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
||||
/*
|
||||
// Enable Peripheral Clock for
|
||||
// TIMER_CLOCK0, used to measure exact timing before answering
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);// | (1 << AT91C_ID_TC1);
|
||||
|
@ -172,12 +180,13 @@ static void em4x50_setup_read(void) {
|
|||
|
||||
// synchronized startup procedure
|
||||
while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero
|
||||
|
||||
*/
|
||||
|
||||
// Watchdog hit
|
||||
WDT_HIT();
|
||||
}
|
||||
|
||||
static void em4x50_setup_sim(void) {
|
||||
void em4x50_setup_sim(void) {
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125);
|
||||
|
@ -186,12 +195,15 @@ static void em4x50_setup_sim(void) {
|
|||
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
|
||||
|
||||
StartTicks();
|
||||
/*
|
||||
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0);
|
||||
AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
*/
|
||||
|
||||
// Watchdog hit
|
||||
WDT_HIT();
|
||||
|
||||
|
@ -200,7 +212,7 @@ static void em4x50_setup_sim(void) {
|
|||
|
||||
// calculate signal properties (mean amplitudes) from measured data:
|
||||
// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow
|
||||
static bool get_signalproperties(void) {
|
||||
bool get_signalproperties(void) {
|
||||
|
||||
bool signal_found = false;
|
||||
int no_periods = 32, pct = 75, noise = 140;
|
||||
|
@ -208,6 +220,7 @@ static bool get_signalproperties(void) {
|
|||
uint8_t sample_max_mean = 0;
|
||||
uint8_t sample_max[no_periods];
|
||||
uint32_t sample_max_sum = 0;
|
||||
uint32_t tval = 0;
|
||||
memset(sample_max, 0x00, sizeof(sample_max));
|
||||
|
||||
LED_A_ON();
|
||||
|
@ -218,7 +231,8 @@ static bool get_signalproperties(void) {
|
|||
if (BUTTON_PRESS()) return false;
|
||||
|
||||
// about 2 samples per bit period
|
||||
wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
|
||||
// ignore first samples
|
||||
if ((i > SIGNAL_IGNORE_FIRST_SAMPLES) && (AT91C_BASE_SSC->SSC_RHR > noise)) {
|
||||
|
@ -236,8 +250,10 @@ static bool get_signalproperties(void) {
|
|||
// 3 single "full periods" to eliminate the influence of a listen window
|
||||
for (int i = 0; i < no_periods; i++) {
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) {
|
||||
//AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
//while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) {
|
||||
tval = GetTicks();
|
||||
while (GetTicks() - tval < 12 * 3 * EM4X50_T_TAG_FULL_PERIOD) {
|
||||
|
||||
if (BUTTON_PRESS()) return false;
|
||||
|
||||
|
@ -268,12 +284,14 @@ static bool get_signalproperties(void) {
|
|||
static bool invalid_bit(void) {
|
||||
|
||||
// get sample at 3/4 of bit period
|
||||
wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_THREE_QUARTER_PERIOD);
|
||||
|
||||
uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// wait until end of bit period
|
||||
wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_QUARTER_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_QUARTER_PERIOD);
|
||||
|
||||
// bit in "undefined" state?
|
||||
if (sample <= gHigh && sample >= gLow)
|
||||
|
@ -284,7 +302,7 @@ static bool invalid_bit(void) {
|
|||
|
||||
static uint32_t get_pulse_length(void) {
|
||||
|
||||
int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD), tval = 0;
|
||||
|
||||
// iterates pulse length (low -> high -> low)
|
||||
|
||||
|
@ -296,7 +314,8 @@ static uint32_t get_pulse_length(void) {
|
|||
if (timeout == 0)
|
||||
return 0;
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
//AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
tval = GetTicks();
|
||||
timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
while (sample < gHigh && (timeout--))
|
||||
|
@ -312,41 +331,59 @@ static uint32_t get_pulse_length(void) {
|
|||
if (timeout == 0)
|
||||
return 0;
|
||||
|
||||
return (uint32_t)AT91C_BASE_TC0->TC_CV;
|
||||
//return (uint32_t)AT91C_BASE_TC0->TC_CV;
|
||||
return GetTicks() - tval;
|
||||
|
||||
}
|
||||
|
||||
// check if pulse length <pl> corresponds to given length <length>
|
||||
static bool check_pulse_length(uint32_t pl, int length) {
|
||||
return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE)));
|
||||
//return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= T0 * (length + EM4X50_TAG_TOLERANCE)));
|
||||
return ((pl >= 12 * (length - EM4X50_TAG_TOLERANCE)) && (pl <= 12 * (length + EM4X50_TAG_TOLERANCE)));
|
||||
}
|
||||
|
||||
// send single bit according to EM4x50 application note and datasheet
|
||||
static void em4x50_reader_send_bit(int bit) {
|
||||
int timeout = 500;
|
||||
|
||||
// reset clock for the next bit
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
//AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
uint32_t tval = GetTicks();
|
||||
|
||||
if (bit == 0) {
|
||||
|
||||
// disable modulation (activate the field) for 7 cycles of carrier
|
||||
// period (Opt64)
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 7);
|
||||
|
||||
//while (AT91C_BASE_TC0->TC_CV < T0 * 7);
|
||||
while ((timeout--) && (GetTicks() - tval < 12 * 7));
|
||||
if (timeout <= 0)
|
||||
return;
|
||||
timeout = 500;
|
||||
|
||||
// enable modulation (drop the field) for remaining first
|
||||
// half of bit period
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
//while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD);
|
||||
while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_HALF_PERIOD));
|
||||
if (timeout <= 0)
|
||||
return;
|
||||
timeout = 500;
|
||||
|
||||
// disable modulation for second half of bit period
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD));
|
||||
if (timeout <= 0)
|
||||
return;
|
||||
timeout = 500;
|
||||
|
||||
} else {
|
||||
|
||||
// bit = "1" means disable modulation for full bit period
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
while ((timeout--) && (GetTicks() - tval < 12 * EM4X50_T_TAG_FULL_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,7 +483,8 @@ static int find_double_listen_window(bool bcommand) {
|
|||
// second window follows - sync on this to issue a command
|
||||
|
||||
// skip the next bit...
|
||||
wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
// ...and check if the following bit does make sense
|
||||
// (if not it is the correct position within the second
|
||||
|
@ -484,7 +522,7 @@ static int find_double_listen_window(bool bcommand) {
|
|||
|
||||
// function is used to check wether a tag on the proxmark is an
|
||||
// EM4x50 tag or not -> speed up "lf search" process
|
||||
static bool find_em4x50_tag(void) {
|
||||
bool find_em4x50_tag(void) {
|
||||
return find_single_listen_window();
|
||||
}
|
||||
|
||||
|
@ -524,7 +562,8 @@ static bool check_ack(bool bliw) {
|
|||
|
||||
// wait for 2 bits (remaining "bit" of ACK signal + first
|
||||
// "bit" of listen window)
|
||||
wait_timer(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//wait_timer(T0 * 2 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
wait_timer(12 * 2 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
// check for listen window (if first bit cannot be interpreted
|
||||
// as a valid bit it must belong to a listen window)
|
||||
|
@ -655,7 +694,8 @@ static bool login(uint32_t password) {
|
|||
// send password
|
||||
em4x50_reader_send_word(password);
|
||||
|
||||
wait_timer(T0 * EM4X50_T_TAG_TPP);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_TPP);
|
||||
wait_timer(12 * EM4X50_T_TAG_TPP);
|
||||
|
||||
// check if ACK is returned
|
||||
if (check_ack(false))
|
||||
|
@ -815,7 +855,7 @@ static int reset(void) {
|
|||
|
||||
// reads data that tag transmits when exposed to reader field
|
||||
// (standard read mode); number of read words is saved in <now>
|
||||
static int standard_read(int *now, uint32_t *words) {
|
||||
int standard_read(int *now, uint32_t *words) {
|
||||
|
||||
int fwr = *now, res = PM3_EFAILED;
|
||||
|
||||
|
@ -823,8 +863,11 @@ static int standard_read(int *now, uint32_t *words) {
|
|||
if ((res = find_double_listen_window(false)) == PM3_SUCCESS) {
|
||||
|
||||
// read and save words until following double listen window is detected
|
||||
while ((res = get_word_from_bitstream(&words[*now])) == EM4X50_TAG_WORD)
|
||||
res = get_word_from_bitstream(&words[*now]);
|
||||
while (res == EM4X50_TAG_WORD) {
|
||||
(*now)++;
|
||||
res = get_word_from_bitstream(&words[*now]);
|
||||
}
|
||||
|
||||
// number of detected words
|
||||
*now -= fwr;
|
||||
|
@ -957,7 +1000,8 @@ static int write(uint32_t word, uint32_t addresses) {
|
|||
} else {
|
||||
|
||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||
wait_timer(T0 * EM4X50_T_TAG_TWA);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_TWA);
|
||||
wait_timer(12 * EM4X50_T_TAG_TWA);
|
||||
|
||||
// look for ACK sequence
|
||||
if (check_ack(false)) {
|
||||
|
@ -965,7 +1009,8 @@ static int write(uint32_t word, uint32_t addresses) {
|
|||
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods)
|
||||
// for saving data and should return with ACK
|
||||
for (int i = 0; i < 50; i++) {
|
||||
wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
}
|
||||
|
||||
if (check_ack(false))
|
||||
|
@ -996,7 +1041,8 @@ static int write_password(uint32_t password, uint32_t new_password) {
|
|||
} else {
|
||||
|
||||
// wait for T0 * EM4x50_T_TAG_TPP (processing pause time)
|
||||
wait_timer(T0 * EM4X50_T_TAG_TPP);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_TPP);
|
||||
wait_timer(12 * EM4X50_T_TAG_TPP);
|
||||
|
||||
// look for ACK sequence and send rm request
|
||||
// during following listen window
|
||||
|
@ -1006,14 +1052,16 @@ static int write_password(uint32_t password, uint32_t new_password) {
|
|||
em4x50_reader_send_word(new_password);
|
||||
|
||||
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
|
||||
wait_timer(T0 * EM4X50_T_TAG_TWA);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_TWA);
|
||||
wait_timer(12 * EM4X50_T_TAG_TWA);
|
||||
|
||||
if (check_ack(false)) {
|
||||
|
||||
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time = 3.2ms = 50 * 64 periods)
|
||||
// for saving data and should return with ACK
|
||||
for (int i = 0; i < 50; i++) {
|
||||
wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
//wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
wait_timer(12 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
}
|
||||
|
||||
if (check_ack(false))
|
||||
|
@ -1216,23 +1264,23 @@ static int em4x50_sim_read_bit(void) {
|
|||
|
||||
int cycles = 0;
|
||||
int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ;
|
||||
uint32_t tval = 0;
|
||||
|
||||
while (cycles < EM4X50_T_TAG_FULL_PERIOD) {
|
||||
|
||||
// wait until reader field disappears
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK));
|
||||
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
// now check until reader switches on carrier field
|
||||
tval = GetTicks();
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
|
||||
|
||||
// check if cycle (i.e. off -> on -> off) takes longer than T0
|
||||
if (AT91C_BASE_TC0->TC_CV > T0 * EM4X50_ZERO_DETECTION) {
|
||||
// check if current cycle takes longer than "usual""
|
||||
if (GetTicks() - tval > EM4X50_ZERO_DETECTION * CYCLES2TICKS) {
|
||||
|
||||
// gap detected; wait until reader field is switched on again
|
||||
while ((timeout--) && (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK));
|
||||
|
||||
|
||||
if (timeout <= 0) {
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
@ -1727,13 +1775,61 @@ static int em4x50_sim_handle_writepwd_command(uint32_t *tag) {
|
|||
return EM4X50_COMMAND_WRITE_PASSWORD;
|
||||
}
|
||||
|
||||
void em4x50_handle_commands(int *command, uint32_t *tag) {
|
||||
|
||||
switch (*command) {
|
||||
|
||||
case EM4X50_COMMAND_LOGIN:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
*command = em4x50_sim_handle_login_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_RESET:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
*command = em4x50_sim_handle_reset_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_WRITE:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
*command = em4x50_sim_handle_write_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_WRITE_PASSWORD:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
*command = em4x50_sim_handle_writepwd_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_SELECTIVE_READ:
|
||||
LED_B_OFF();
|
||||
LED_C_ON();
|
||||
*command = em4x50_sim_handle_selective_read_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_STANDARD_READ:
|
||||
LED_B_ON();
|
||||
LED_C_OFF();
|
||||
*command = em4x50_sim_handle_standard_read_command(tag);
|
||||
break;
|
||||
|
||||
// bit errors during reading may lead to unknown commands
|
||||
// -> continue with standard read mode
|
||||
default:
|
||||
*command = EM4X50_COMMAND_STANDARD_READ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// simulate uploaded data in emulator memory
|
||||
// LED A -> operations that require authentication are possible
|
||||
// LED B -> standard read mode is active
|
||||
// LED C -> command has been transmitted by reader
|
||||
void em4x50_sim(uint32_t *password) {
|
||||
|
||||
int command = PM3_ENODATA;
|
||||
int command = 0;
|
||||
|
||||
uint8_t *em4x50_mem = BigBuf_get_EM_addr();
|
||||
uint32_t tag[EM4X50_NO_WORDS] = {0x0};
|
||||
|
@ -1759,50 +1855,7 @@ void em4x50_sim(uint32_t *password) {
|
|||
|
||||
for (;;) {
|
||||
|
||||
switch (command) {
|
||||
|
||||
case EM4X50_COMMAND_LOGIN:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
command = em4x50_sim_handle_login_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_RESET:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
command = em4x50_sim_handle_reset_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_WRITE:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
command = em4x50_sim_handle_write_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_WRITE_PASSWORD:
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
command = em4x50_sim_handle_writepwd_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_SELECTIVE_READ:
|
||||
LED_B_OFF();
|
||||
LED_C_ON();
|
||||
command = em4x50_sim_handle_selective_read_command(tag);
|
||||
break;
|
||||
|
||||
case EM4X50_COMMAND_STANDARD_READ:
|
||||
LED_B_ON();
|
||||
LED_C_OFF();
|
||||
command = em4x50_sim_handle_standard_read_command(tag);
|
||||
break;
|
||||
|
||||
// bit errors during reading may lead to unknown commands
|
||||
// -> continue with standard read mode
|
||||
default:
|
||||
command = EM4X50_COMMAND_STANDARD_READ;
|
||||
break;
|
||||
}
|
||||
em4x50_handle_commands(&command, tag);
|
||||
|
||||
// stop if key (pm3 button or enter key) has been pressed
|
||||
if (command == PM3_EOPABORTED) {
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
|
||||
#include "../include/em4x50.h"
|
||||
|
||||
void em4x50_setup_read(void);
|
||||
bool get_signalproperties(void);
|
||||
bool find_em4x50_tag(void);
|
||||
int standard_read(int *now, uint32_t *words);
|
||||
|
||||
void em4x50_setup_sim(void);
|
||||
void em4x50_handle_commands(int *command, uint32_t *tag);
|
||||
|
||||
void em4x50_info(em4x50_data_t *etd);
|
||||
void em4x50_write(em4x50_data_t *etd);
|
||||
void em4x50_writepwd(em4x50_data_t *etd);
|
||||
|
|
|
@ -33,6 +33,14 @@
|
|||
#define FIRST_WORD_WRITE_INHIBITED 2 // third byte
|
||||
#define LAST_WORD_WRITE_INHIBITED 3 // fourth byte
|
||||
|
||||
// commands
|
||||
#define EM4X50_COMMAND_LOGIN 0x01
|
||||
#define EM4X50_COMMAND_RESET 0x80
|
||||
#define EM4X50_COMMAND_WRITE 0x12
|
||||
#define EM4X50_COMMAND_WRITE_PASSWORD 0x11
|
||||
#define EM4X50_COMMAND_SELECTIVE_READ 0x0A
|
||||
#define EM4X50_COMMAND_STANDARD_READ 0x02 // virtual command
|
||||
|
||||
// misc
|
||||
#define TIMEOUT 2000
|
||||
#define DUMP_FILESIZE 136
|
||||
|
@ -52,4 +60,7 @@ typedef struct {
|
|||
uint8_t byte[4];
|
||||
} PACKED em4x50_word_t;
|
||||
|
||||
extern bool gLogin;
|
||||
extern bool gWritePasswordProcess;
|
||||
|
||||
#endif /* EM4X50_H__ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue