next step (half duplex simulation): all commands seem to work

This commit is contained in:
tharexde 2021-01-07 01:22:46 +01:00
commit 12071080a6
4 changed files with 212 additions and 59 deletions

View file

@ -1136,7 +1136,7 @@ static void PacketReceived(PacketCommandNG *packet) {
// destroy the Emulator Memory. // destroy the Emulator Memory.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
em4x50_sim(); em4x50_sim((uint32_t *)packet->data.asBytes);
break; break;
} }
case CMD_LF_EM4X50_READER: { case CMD_LF_EM4X50_READER: {

View file

@ -61,6 +61,8 @@ int gLow = 60;
// a global parameter is needed to indicate whether a previous login was // a global parameter is needed to indicate whether a previous login was
// successful, so operations that require authentication may be performed // successful, so operations that require authentication may be performed
bool gLogin = 0; bool gLogin = 0;
// additionally a global variable to identify the WritePassword process
bool gWritePasswordProcess = 0;
int gcount = 0; int gcount = 0;
int gcycles = 0; int gcycles = 0;
@ -218,6 +220,9 @@ static void em4x50_setup_sim(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// Watchdog hit
WDT_HIT();
} }
// calculate signal properties (mean amplitudes) from measured data: // calculate signal properties (mean amplitudes) from measured data:
@ -840,7 +845,7 @@ static uint8_t em4x50_sim_read_byte_with_parity_check(void) {
return (parity == pval) ? byte : 0; return (parity == pval) ? byte : 0;
} }
static uint32_t em4x50_sim_read_word(void) { static bool em4x50_sim_read_word(uint32_t *word) {
uint8_t parities = 0, parities_calculated = 0, stop_bit = 0; uint8_t parities = 0, parities_calculated = 0, stop_bit = 0;
uint8_t bytes[4] = {0}; uint8_t bytes[4] = {0};
@ -864,10 +869,11 @@ static uint32_t em4x50_sim_read_word(void) {
// check parities // check parities
if ((parities == parities_calculated) && (stop_bit == 0)) { if ((parities == parities_calculated) && (stop_bit == 0)) {
return BYTES2UINT32(bytes); *word = BYTES2UINT32(bytes);
return true;
} }
return 0; return false;
} }
static void em4x50_sim_send_ack(void) { static void em4x50_sim_send_ack(void) {
@ -969,10 +975,9 @@ static bool em4x50_sim_send_listen_window(void) {
static void em4x50_sim_handle_login_command(uint32_t *tag) { static void em4x50_sim_handle_login_command(uint32_t *tag) {
uint32_t password = 0;
// read password // read password
password = em4x50_sim_read_word(); uint32_t password = 0;
bool pwd_ok = em4x50_sim_read_word(&password);
// processing pause time (corresponds to a "1" bit) // processing pause time (corresponds to a "1" bit)
em4x50_sim_send_bit(1); em4x50_sim_send_bit(1);
@ -980,7 +985,7 @@ static void em4x50_sim_handle_login_command(uint32_t *tag) {
// empirically determined delay (to be examined seperately) // empirically determined delay (to be examined seperately)
wait_cycles(1); wait_cycles(1);
if (password == tag[0]) { if (pwd_ok && (password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) {
em4x50_sim_send_ack(); em4x50_sim_send_ack();
gLogin = true; gLogin = true;
} else { } else {
@ -1010,43 +1015,87 @@ static void em4x50_sim_handle_reset_command(uint32_t *tag) {
static void em4x50_sim_handle_write_command(uint32_t *tag) { static void em4x50_sim_handle_write_command(uint32_t *tag) {
uint8_t address = 0;
uint32_t data = 0;
// read address // read address
uint8_t address = 0;
address = em4x50_sim_read_byte_with_parity_check(); address = em4x50_sim_read_byte_with_parity_check();
// read data // read data
data = em4x50_sim_read_word(); uint32_t data = 0;
bool word_ok = em4x50_sim_read_word(&data);
// extract necessary control data
bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE;
// extract protection data
int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected
int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected
// save data to tag
tag[address] = data;
// write access time // write access time
wait_cycles(EM4X50_T_TAG_TWA); wait_cycles(EM4X50_T_TAG_TWA);
if ((address >= fwrp) && (address <= lwrp)) { if (word_ok == false) {
em4x50_sim_send_nak(); em4x50_sim_send_nak();
} else if ((address == EM4X50_DEVICE_SERIAL) em4x50_sim_handle_command(0, tag);
&& (address == EM4X50_DEVICE_ID) }
&& (address == 0)
) { // extract necessary control data
em4x50_sim_send_nak(); bool raw = (tag[EM4X50_CONTROL] >> CONFIG_BLOCK) & READ_AFTER_WRITE;
} else { // extract protection data:
em4x50_sim_send_ack(); // first word write protected
int fwwp = reflect8((tag[EM4X50_PROTECTION] >> 24) & 0xFF);
// last word write protected
int lwwp = reflect8((tag[EM4X50_PROTECTION] >> 16) & 0xFF);
switch (address) {
case EM4X50_DEVICE_PASSWORD:
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
break;
case EM4X50_PROTECTION:
if (gLogin) {
tag[address] = reflect32(data);
em4x50_sim_send_ack();
} else {
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
}
break;
case EM4X50_CONTROL:
if (gLogin) {
tag[address] = reflect32(data);
em4x50_sim_send_ack();
} else {
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
}
break;
case EM4X50_DEVICE_SERIAL:
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
break;
case EM4X50_DEVICE_ID:
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
break;
default:
if ((address >= fwwp) && (address <= lwwp) && (gLogin == false)) {
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
} else {
tag[address] = reflect32(data);
em4x50_sim_send_ack();
}
break;
} }
// EEPROM write time // EEPROM write time
wait_cycles(EM4X50_T_TAG_TWEE); wait_cycles(EM4X50_T_TAG_TWEE);
// strange: need some sort of 'waveform correction', otherwise ack signal
// will not be detected; sending a single "1" seems to solve the problem
em4x50_sim_send_bit(1);
em4x50_sim_send_ack(); em4x50_sim_send_ack();
// if "read after write" (raw) bit is set, repeat written data once // if "read after write" (raw) bit is set, send written data once
if (raw) { if (raw) {
em4x50_sim_send_listen_window(tag); em4x50_sim_send_listen_window(tag);
em4x50_sim_send_listen_window(tag); em4x50_sim_send_listen_window(tag);
@ -1057,25 +1106,90 @@ static void em4x50_sim_handle_write_command(uint32_t *tag) {
em4x50_sim_handle_command(0, tag); em4x50_sim_handle_command(0, tag);
} }
static void em4x50_sim_handle_writepwd_command(uint32_t *tag) {
bool pwd_ok = false;
if (gWritePasswordProcess == false) {
gWritePasswordProcess = true;
// read password
uint32_t act_password = 0;
pwd_ok = em4x50_sim_read_word(&act_password);
// processing pause time (corresponds to a "1" bit)
em4x50_sim_send_bit(1);
if (pwd_ok && (act_password == reflect32(tag[EM4X50_DEVICE_PASSWORD]))) {
em4x50_sim_send_ack();
gLogin = true;
} else {
em4x50_sim_send_nak();
gLogin = false;
em4x50_sim_handle_command(0, tag);
}
em4x50_sim_send_listen_window(tag);
} else {
gWritePasswordProcess = false;
// read new password
uint32_t new_password = 0;
pwd_ok = em4x50_sim_read_word(&new_password);
// write access time
wait_cycles(EM4X50_T_TAG_TWA);
if (pwd_ok) {
em4x50_sim_send_ack();
tag[EM4X50_DEVICE_PASSWORD] = reflect32(new_password);
} else {
em4x50_sim_send_ack();
em4x50_sim_handle_command(0, tag);
}
// EEPROM write time
wait_cycles(EM4X50_T_TAG_TWEE);
// strange: need some sort of 'waveform correction', otherwise ack signal
// will not be detected; sending a single "1" seems to solve the problem
em4x50_sim_send_bit(1);
em4x50_sim_send_ack();
// continue with standard read mode
em4x50_sim_handle_command(0, tag);
}
}
static void em4x50_sim_handle_selective_read_command(uint32_t *tag) { static void em4x50_sim_handle_selective_read_command(uint32_t *tag) {
uint32_t address = 0;
// read password // read password
address = em4x50_sim_read_word(); uint32_t address = 0;
bool addr_ok = em4x50_sim_read_word(&address);
// processing pause time (corresponds to a "1" bit)
em4x50_sim_send_bit(1);
if (addr_ok) {
em4x50_sim_send_ack();
} else {
em4x50_sim_send_nak();
em4x50_sim_handle_command(0, tag);
}
// extract control data // extract control data
int fwr = address & 0xFF; // first word read int fwr = address & 0xFF; // first word read
int lwr = (address >> 8) & 0xFF; // last word read int lwr = (address >> 8) & 0xFF; // last word read
// extract protection data // extract protection data:
int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected // first word read protected
int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF;
// last word read protected
// processing pause time (corresponds to a "1" bit) int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF;
em4x50_sim_send_bit(1);
em4x50_sim_send_ack();
// iceman, will need a usb cmd check to break as well // iceman, will need a usb cmd check to break as well
while (BUTTON_PRESS() == false) { while (BUTTON_PRESS() == false) {
@ -1090,7 +1204,7 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) {
if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) { if ((gLogin == false) && (i >= fwrp) && (i <= lwrp)) {
em4x50_sim_send_word(0x00); em4x50_sim_send_word(0x00);
} else { } else {
em4x50_sim_send_word(tag[i]); em4x50_sim_send_word(reflect32(tag[i]));
} }
} }
} }
@ -1099,11 +1213,13 @@ static void em4x50_sim_handle_selective_read_command(uint32_t *tag) {
static void em4x50_sim_handle_standard_read_command(uint32_t *tag) { static void em4x50_sim_handle_standard_read_command(uint32_t *tag) {
// extract control data // extract control data
int fwr = tag[CONFIG_BLOCK] & 0xFF; // first word read int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read
int lwr = (tag[CONFIG_BLOCK] >> 8) & 0xFF; // last word read int lwr = (reflect32(tag[EM4X50_CONTROL]) >> 8) & 0xFF; // last word read
// extract protection data // extract protection data:
int fwrp = tag[EM4X50_PROTECTION] & 0xFF; // first word read protected // first word read protected
int lwrp = (tag[EM4X50_PROTECTION] >> 8) & 0xFF; // last word read protected int fwrp = reflect32(tag[EM4X50_PROTECTION]) & 0xFF;
// last word read protected
int lwrp = (reflect32(tag[EM4X50_PROTECTION]) >> 8) & 0xFF;
// iceman, will need a usb cmd check to break as well // iceman, will need a usb cmd check to break as well
while (BUTTON_PRESS() == false) { while (BUTTON_PRESS() == false) {
@ -1117,7 +1233,7 @@ static void em4x50_sim_handle_standard_read_command(uint32_t *tag) {
if ((i >= fwrp) && (i <= lwrp)) { if ((i >= fwrp) && (i <= lwrp)) {
em4x50_sim_send_word(0x00); em4x50_sim_send_word(0x00);
} else { } else {
em4x50_sim_send_word(tag[i]); em4x50_sim_send_word(reflect32(tag[i]));
} }
} }
} }
@ -1140,7 +1256,7 @@ static void em4x50_sim_handle_command(uint8_t command, uint32_t *tag) {
break; break;
case EM4X50_COMMAND_WRITE_PASSWORD: case EM4X50_COMMAND_WRITE_PASSWORD:
Dbprintf("Command = write_password"); em4x50_sim_handle_writepwd_command(tag);
break; break;
case EM4X50_COMMAND_SELECTIVE_READ: case EM4X50_COMMAND_SELECTIVE_READ:
@ -1164,9 +1280,15 @@ static void check_rm_request(uint32_t *tag) {
// look for second zero // look for second zero
if (get_cycles() < cond) { if (get_cycles() < cond) {
// read mode request detected, get command from reader // if command before was EM4X50_COMMAND_WRITE_PASSWORD
uint8_t command = em4x50_sim_read_byte_with_parity_check(); // switch to separate process
em4x50_sim_handle_command(command, tag); if (gWritePasswordProcess) {
em4x50_sim_handle_command(EM4X50_COMMAND_WRITE_PASSWORD, tag);
} else {
// read mode request detected, get command from reader
uint8_t command = em4x50_sim_read_byte_with_parity_check();
em4x50_sim_handle_command(command, tag);
}
} }
} }
} }
@ -1514,8 +1636,13 @@ static int write(uint32_t word, uint32_t addresses) {
// now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time)
// for saving data and should return with ACK // for saving data and should return with ACK
if (check_ack(false)) for (int i = 0; i < 50; i++) {
wait_timer(T0 * EM4X50_T_TAG_FULL_PERIOD);
}
if (check_ack(false)) {
return PM3_SUCCESS; return PM3_SUCCESS;
}
} }
} }
} else { } else {
@ -1554,9 +1681,12 @@ static int write_password(uint32_t password, uint32_t new_password) {
// wait for T0 * EM4X50_T_TAG_TWA (write access time) // wait for T0 * EM4X50_T_TAG_TWA (write access time)
wait_timer(T0 * EM4X50_T_TAG_TWA); wait_timer(T0 * EM4X50_T_TAG_TWA);
if (check_ack(false)) if (check_ack(false)) {
if (check_ack(false)) //Dbprintf("zweites ack");
if (check_ack(false)) {
return PM3_SUCCESS; return PM3_SUCCESS;
}
}
} }
} }
} else { } else {
@ -1646,13 +1776,18 @@ void em4x50_writepwd(em4x50_data_t *etd) {
} }
// simulate uploaded data in emulator memory // simulate uploaded data in emulator memory
void em4x50_sim() { void em4x50_sim(uint32_t *password) {
int status = PM3_SUCCESS; int status = PM3_SUCCESS;
uint8_t *em4x50_mem = BigBuf_get_EM_addr(); uint8_t *em4x50_mem = BigBuf_get_EM_addr();
uint32_t tag[EM4X50_NO_WORDS] = {0x0}; uint32_t tag[EM4X50_NO_WORDS] = {0x0};
for (int i = 0; i < EM4X50_NO_WORDS; i++) for (int i = 0; i < EM4X50_NO_WORDS; i++)
tag[i] = reflect32(bytes_to_num(em4x50_mem + (i * 4), 4)); tag[i] = bytes_to_num(em4x50_mem + (i * 4), 4);
// via eload uploaded dump usually does not contain a password
if (tag[EM4X50_DEVICE_PASSWORD] == 0) {
tag[EM4X50_DEVICE_PASSWORD] = reflect32(*password);
}
// only if valid em4x50 data (e.g. uid == serial) // only if valid em4x50 data (e.g. uid == serial)
if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) { if (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]) {

View file

@ -19,7 +19,7 @@ void em4x50_writepwd(em4x50_data_t *etd);
void em4x50_read(em4x50_data_t *etd); void em4x50_read(em4x50_data_t *etd);
void em4x50_brute(em4x50_data_t *etd); void em4x50_brute(em4x50_data_t *etd);
void em4x50_login(uint32_t *password); void em4x50_login(uint32_t *password);
void em4x50_sim(void); void em4x50_sim(uint32_t *password);
void em4x50_reader(void); void em4x50_reader(void);
void em4x50_chk(uint8_t *filename); void em4x50_chk(uint8_t *filename);
void em4x50_test(em4x50_test_t *ett); void em4x50_test(em4x50_test_t *ett);

View file

@ -1211,25 +1211,43 @@ int CmdEM4x50Restore(const char *Cmd) {
} }
int CmdEM4x50Sim(const char *Cmd) { int CmdEM4x50Sim(const char *Cmd) {
uint32_t password = 0;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf em 4x50 sim", CLIParserInit(&ctx, "lf em 4x50 sim",
"Simulates a EM4x50 tag.\n" "Simulates a EM4x50 tag.\n"
"Upload using `lf em 4x50 eload`", "Upload using `lf em 4x50 eload`",
"lf em 4x50 sim" "lf em 4x50 sim"
"lf em 4x50 sim -p 27182818 -> uses password for eload data"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("p", "passsword", "<hex>", "password, 4 bytes, lsb"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
int pwd_len = 0;
uint8_t pwd[4] = {0};
CLIGetHexWithReturn(ctx, 1, pwd, &pwd_len);
CLIParserFree(ctx);
if (pwd_len) {
if (pwd_len != 4) {
PrintAndLogEx(FAILED, "password length must be 4 bytes instead of %d", pwd_len);
return PM3_EINVARG;
} else {
password = BYTES2UINT32(pwd);
}
}
CLIParserFree(ctx); CLIParserFree(ctx);
PrintAndLogEx(INFO, "Simulating data from emulator memory"); PrintAndLogEx(INFO, "Simulating data from emulator memory");
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_SIM, NULL, 0); SendCommandNG(CMD_LF_EM4X50_SIM, (uint8_t *)&password, sizeof(password));
PacketResponseNG resp; PacketResponseNG resp;
WaitForResponse(CMD_LF_EM4X50_SIM, &resp); WaitForResponse(CMD_LF_EM4X50_SIM, &resp);
if (resp.status == PM3_SUCCESS) if (resp.status == PM3_SUCCESS)