This commit is contained in:
iceman1001 2025-03-18 08:11:06 +01:00
parent 0446509d1e
commit a776f9a0bd
10 changed files with 231 additions and 187 deletions

View file

@ -108,13 +108,13 @@ static bool command_parity = true;
//
// Four of the commands send a predetermined bitstream, immediately synchronize
// on the tag sending the header, and then receive a number of bits from the tag:
//
//
// #define EM4X70_COMMAND_ID 0x01 // 0b0001 --> 0b001'1
// Tag: [LIW] [Header][ID₃₁..ID₀][LIW]
// Reader: [RM][Command]
// Bits Sent: RM + 4 bits
// Bits Recv: Header + 32 bits
//
//
// #define EM4X70_COMMAND_UM1 0x02 // 0b0010 --> 0b010'1
// Tag: [LIW] [Header][LB₁, LB₀, UM1₂₉..UM1₀][LIW]
// Reader: [RM][Command]
@ -171,7 +171,7 @@ static bool command_parity = true;
// Auto-detect tag variant and command parity?
// EM4070/V4070 does not contain UM2 or PIN, and UM1 may be OTP (one-time programmable)
// EM4170 added Pin and UM2, and UM1
//
//
// Thus, to check for overlap, need only check the first three commands with parity:
// | CMD | P? | Bits | Safe? | Overlaps With | Notes
// |-------|-----|----------|-------|------------------|------------
@ -182,7 +182,7 @@ static bool command_parity = true;
// | PIN | No | `0b0100` | N/A | | DO NOT USE ... just in case
// | UM2 | No | `0b0111` | Yes | None! | Safe ... indicates no parity AND EM4170 tag type
// | ID | Yes | `0b0011` | Yes | Auth w/o Parity | Safe to try ... indicates parity if successful
// | UM1 | Yes | `0b0101` | Yes | Write w/o Parity |
// | UM1 | Yes | `0b0101` | Yes | Write w/o Parity |
// | AUTH | Yes | `0b0110` | Yes | None! | Not testable
// | WRITE | Yes | `0b1010` | NO | None! | DO NOT USE ... just in case
// | PIN | Yes | `0b1001` | N/A | None! | DO NOT USE ... just in case
@ -359,15 +359,15 @@ typedef struct _em4x70_transmit_log_t {
em4x70_sublog_t receive;
} em4x70_transmitted_data_log_t;
em4x70_transmitted_data_log_t g_not_used_directly; // change to bigbuff allocation?
em4x70_transmitted_data_log_t* g_Log = &g_not_used_directly;
em4x70_transmitted_data_log_t *g_Log = &g_not_used_directly;
static void log_reset(void) {
if (g_Log != NULL) {
memset(g_Log, 0, sizeof(em4x70_transmitted_data_log_t));
}
}
static void log_dump_helper(em4x70_sublog_t * part, bool is_transmit) {
static void log_dump_helper(em4x70_sublog_t *part, bool is_transmit) {
if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) {
char const * const direction = is_transmit ? "sent >>>" : "recv <<<";
char const *const direction = is_transmit ? "sent >>>" : "recv <<<";
if (part->bits_used == 0) {
DPRINTF_EXTENDED(("%s: no data", direction));
} else {
@ -377,12 +377,12 @@ static void log_dump_helper(em4x70_sublog_t * part, bool is_transmit) {
bitstring[i] = part->bit[i] ? '1' : '0';
}
DPRINTF_EXTENDED((
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s",
direction,
part->start_tick, part->end_tick,
part->end_tick - part->start_tick,
part->bits_used, bitstring
));
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s",
direction,
part->start_tick, part->end_tick,
part->end_tick - part->start_tick,
part->bits_used, bitstring
));
}
}
}
@ -390,7 +390,7 @@ static void log_dump(void) {
if (g_dbglevel >= DBG_INFO || FORCE_ENABLE_LOGGING) {
bool hasContent = false;
if (g_Log != NULL) {
uint8_t * check_for_data = (uint8_t *)g_Log;
uint8_t *check_for_data = (uint8_t *)g_Log;
for (size_t i = 0; i < sizeof(em4x70_transmitted_data_log_t); ++i) {
if (check_for_data[i] != 0) {
hasContent = true;
@ -419,7 +419,7 @@ static void log_sent_bit_end(uint32_t end_tick) {
}
}
static void log_received_bit_start(uint32_t start_tick) {
if (g_Log != NULL && g_Log->receive.start_tick == 0) {
if (g_Log != NULL && g_Log->receive.start_tick == 0) {
g_Log->receive.start_tick = start_tick;
}
}
@ -475,7 +475,7 @@ static bool check_ack(void) {
// ACK 64 + 64
// NAK 64 + 48
if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) {
check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) {
// ACK
return true;
}
@ -516,12 +516,12 @@ typedef struct _em4x70_command_bitstream {
uint8_t received_data_converted_to_bytes[(EM4X70_MAX_BITSTREAM_BITS / 8) + (EM4X70_MAX_BITSTREAM_BITS % 8 ? 1 : 0)];
} em4x70_command_bitstream_t;
typedef bool (*bitstream_command_generator_id_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um1_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um2_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_auth_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t * rnd, const uint8_t * frnd);
typedef bool (*bitstream_command_generator_pin_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t * tag_id, const uint32_t pin_little_endian);
typedef bool (*bitstream_command_generator_write_t)(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, uint16_t data_little_endian, uint8_t address);
typedef bool (*bitstream_command_generator_id_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um1_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_um2_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity);
typedef bool (*bitstream_command_generator_auth_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd);
typedef bool (*bitstream_command_generator_pin_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin_little_endian);
typedef bool (*bitstream_command_generator_write_t)(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, uint16_t data_little_endian, uint8_t address);
typedef struct _em4x70_command_generators_t {
bitstream_command_generator_id_t id;
@ -534,9 +534,9 @@ typedef struct _em4x70_command_generators_t {
#endif // #pragma endregion // Bitstream structures / enumerations
#if 1 // #pragma region // Functions to dump bitstreams to debug output
static void bitstream_dump_helper(const em4x70_bitstream_t * bitstream, bool is_transmit) {
static void bitstream_dump_helper(const em4x70_bitstream_t *bitstream, bool is_transmit) {
// mimic the log's output format to make comparisons easier
char const * const direction = is_transmit ? "sent >>>" : "recv <<<";
char const *const direction = is_transmit ? "sent >>>" : "recv <<<";
if (bitstream->bitcount == 0) {
if (g_dbglevel >= DBG_INFO || true) {
DPRINTF_EXTENDED(("%s: no data", direction));
@ -550,17 +550,17 @@ static void bitstream_dump_helper(const em4x70_bitstream_t * bitstream, bool is_
bitstring[i] = bitstream->one_bit_per_byte[i] ? '1' : '0';
}
DPRINTF_EXTENDED((
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s%s",
direction,
0, 0, 0,
bitstream->bitcount + (is_transmit ? 2u : 0u), // add the two RM bits to transmitted data
is_transmit ? "00" : "", // add the two RM bits to transmitted data
bitstring
));
"%s: [ %8d .. %8d ] ( %6d ) %2d bits: %s%s",
direction,
0, 0, 0,
bitstream->bitcount + (is_transmit ? 2u : 0u), // add the two RM bits to transmitted data
is_transmit ? "00" : "", // add the two RM bits to transmitted data
bitstring
));
}
}
static void bitstream_dump(const em4x70_command_bitstream_t * cmd_bitstream) {
bitstream_dump_helper(&cmd_bitstream->to_send, true );
static void bitstream_dump(const em4x70_command_bitstream_t *cmd_bitstream) {
bitstream_dump_helper(&cmd_bitstream->to_send, true);
bitstream_dump_helper(&cmd_bitstream->to_receive, false);
}
#endif // #pragma region // Functions to dump bitstreams to debug output
@ -569,14 +569,14 @@ static void bitstream_dump(const em4x70_command_bitstream_t * cmd_bitstream) {
/// @brief Internal function to send a bitstream to the tag.
/// @details This function presumes a validated structure, and sends the bitstream without delays, to support timing-sensitive operations.
/// @param send The details on the bitstream to send to the tag.
/// @return
static bool send_bitstream_internal(const em4x70_bitstream_t * send) {
/// @return
static bool send_bitstream_internal(const em4x70_bitstream_t *send) {
// similar to original send_command_and_read, but using provided bitstream
int retries = EM4X70_COMMAND_RETRIES;
// TIMING SENSITIVE FUNCTION ... Minimize delays after finding the listen window
while (retries) {
const uint8_t * s = send->one_bit_per_byte;
const uint8_t *s = send->one_bit_per_byte;
uint8_t sent = 0;
retries--;
if (find_listen_window(true)) { // `true` will automatically send the two `RM` zero bits
@ -597,9 +597,9 @@ static bool send_bitstream_internal(const em4x70_bitstream_t * send) {
/// @param recv Buffer to store received data from the tag.
/// `recv->expected_bitcount` must be initialized to indicate expected bits to receive from the tag.
/// @return true only if the bitstream was sent and the expected count of bits were received from the tag.
static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive;
static bool send_bitstream_and_read(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding
bool parameters_valid = true;
@ -614,7 +614,7 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
(command_bitstream->command == EM4X70_COMMAND_UM1) ||
(command_bitstream->command == EM4X70_COMMAND_UM2) ||
(command_bitstream->command == EM4X70_COMMAND_AUTH)
) {
) {
// These are the four commands that are supported by this function.
// Allow these to proceed.
} else {
@ -665,7 +665,7 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
// similar to original send_command_and_read, but using provided bitstream
int bits_received = 0;
// NOTE: reset of log does not track the time first bit is sent. That occurs
// when the first sent bit is recorded in the log.
log_reset();
@ -694,9 +694,9 @@ static bool send_bitstream_and_read(em4x70_command_bitstream_t * command_bitstre
// finally return the result of the operation
return result;
}
static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t * command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive;
static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding
bool parameters_valid = true;
@ -769,10 +769,10 @@ static bool send_bitstream_wait_ack_wait_read(em4x70_command_bitstream_t * comma
return result;
}
static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t * command_bitstream) {
static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t *command_bitstream) {
const em4x70_bitstream_t * send = &command_bitstream->to_send;
em4x70_bitstream_t * recv = &command_bitstream->to_receive;
const em4x70_bitstream_t *send = &command_bitstream->to_send;
em4x70_bitstream_t *recv = &command_bitstream->to_receive;
// Validate the parameters before proceeding
bool parameters_valid = true;
@ -835,7 +835,7 @@ static bool send_bitstream_wait_ack_wait_ack(em4x70_command_bitstream_t * comman
#endif // #pragma region // Functions to send bitstreams, with options to receive data
#if 1 // #pragma region // Create bitstreams for each type of EM4x70 command
static bool add_bit_to_bitstream(em4x70_bitstream_t * s, bool b) {
static bool add_bit_to_bitstream(em4x70_bitstream_t *s, bool b) {
uint8_t i = s->bitcount;
uint8_t bits_to_add = 1u;
@ -848,10 +848,10 @@ static bool add_bit_to_bitstream(em4x70_bitstream_t * s, bool b) {
s->bitcount++;
return true;
}
static bool add_nibble_to_bitstream(em4x70_bitstream_t * s, uint8_t nibble, bool add_fifth_parity_bit) {
static bool add_nibble_to_bitstream(em4x70_bitstream_t *s, uint8_t nibble, bool add_fifth_parity_bit) {
uint8_t i = s->bitcount;
uint8_t bits_to_add = add_fifth_parity_bit ? 5u : 4u;
if (i > EM4X70_MAX_BITSTREAM_BITS - bits_to_add) {
DPRINTF_ERROR(("Too many bits to add to bitstream: %d, %d", i, bits_to_add));
return false;
@ -875,7 +875,7 @@ static bool add_nibble_to_bitstream(em4x70_bitstream_t * s, uint8_t nibble, bool
s->bitcount += bits_to_add;
return true;
}
static bool add_byte_to_bitstream(em4x70_bitstream_t * s, uint8_t b) {
static bool add_byte_to_bitstream(em4x70_bitstream_t *s, uint8_t b) {
uint8_t i = s->bitcount;
uint8_t bits_to_add = 8u;
@ -897,7 +897,7 @@ static bool add_byte_to_bitstream(em4x70_bitstream_t * s, uint8_t b) {
}
static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) {
static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u;
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -911,7 +911,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t
}
return result;
}
static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) {
static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u;
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -925,7 +925,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_
}
return result;
}
static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity) {
static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity) {
const uint8_t expected_bits_to_send = 4u;
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
@ -939,14 +939,14 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_
}
return true;
}
static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd) {
static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *rnd, const uint8_t *frnd) {
const uint8_t expected_bits_to_send = 96u;
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_AUTH;
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send;
em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior
@ -994,12 +994,12 @@ static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream
return result;
}
static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin) {
static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, const uint8_t *tag_id, const uint32_t pin) {
const uint8_t expected_bits_to_send = 69; // normally 68 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send;
em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
out_cmd_bitstream->command = EM4X70_COMMAND_PIN;
@ -1015,7 +1015,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_
// Send tag's ID ... indexes 4 .. 35
// e.g., tag_id points to &tag.data[4] ... &tag.data[7]
for (uint_fast8_t i = 0; i < 4; i++) {
uint8_t b = tag_id[3-i];
uint8_t b = tag_id[3 - i];
result = result && add_byte_to_bitstream(s, b);
}
@ -1033,13 +1033,13 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_
}
return result;
}
static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstream_t * out_cmd_bitstream, bool with_command_parity, uint16_t new_data, uint8_t address) {
static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstream_t *out_cmd_bitstream, bool with_command_parity, uint16_t new_data, uint8_t address) {
const uint8_t expected_bits_to_send = 35u; // normally 34 bits, but legacy hack inserts an extra RM bit, and always adds a command parity bit
bool result = true;
memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t));
out_cmd_bitstream->command = EM4X70_COMMAND_WRITE;
em4x70_bitstream_t * s = &out_cmd_bitstream->to_send;
em4x70_bitstream_t *s = &out_cmd_bitstream->to_send;
// *********************************************************************************
// HACK -- Insert an extra zero bit to match legacy behavior
@ -1105,7 +1105,7 @@ const em4x70_command_generators_t legacy_em4x70_command_generators = {
static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) {
em4x70_command_bitstream_t auth_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->auth(&auth_cmd, command_parity, rnd, frnd);
bool result = send_bitstream_and_read(&auth_cmd);
@ -1193,7 +1193,7 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *
// log entry/exit point
static int send_pin(const uint32_t pin) {
em4x70_command_bitstream_t send_pin_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->pin(&send_pin_cmd, command_parity, &tag.data[4], pin);
bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd);
@ -1204,7 +1204,7 @@ static int send_pin(const uint32_t pin) {
static int write(const uint16_t word, const uint8_t address) {
em4x70_command_bitstream_t write_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->write(&write_cmd, command_parity, word, address);
bool result = send_bitstream_wait_ack_wait_ack(&write_cmd);
@ -1226,10 +1226,10 @@ static bool find_listen_window(bool command) {
96 ( 64 + 32 )
64 ( 32 + 16 +16 )*/
if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (1 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) {
if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) &&
check_pulse_length(get_pulse_length(FALLING_EDGE), (1 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD)) {
if (command) {
/* Here we are after the 64 duration edge.
@ -1238,7 +1238,7 @@ static bool find_listen_window(bool command) {
*
* I've found 32-40 field cycles works best
* Allow user adjustment in range: 24-48 field cycles?
* On PM3Easy I've seen success at 24..40 field
* On PM3Easy I've seen success at 24..40 field
*/
WaitTicks(40 * TICKS_PER_FC);
// Send RM Command
@ -1291,7 +1291,7 @@ static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits)
*/
static bool em4x70_read_id(void) {
em4x70_command_bitstream_t read_id_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->id(&read_id_cmd, command_parity);
bool result = send_bitstream_and_read(&read_id_cmd);
@ -1308,7 +1308,7 @@ static bool em4x70_read_id(void) {
*/
static bool em4x70_read_um1(void) {
em4x70_command_bitstream_t read_um1_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um1(&read_um1_cmd, command_parity);
bool result = send_bitstream_and_read(&read_um1_cmd);
@ -1327,7 +1327,7 @@ static bool em4x70_read_um1(void) {
*/
static bool em4x70_read_um2(void) {
em4x70_command_bitstream_t read_um2_cmd;
const em4x70_command_generators_t * generator = &legacy_em4x70_command_generators;
const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators;
generator->um2(&read_um2_cmd, command_parity);
bool result = send_bitstream_and_read(&read_um2_cmd);

View file

@ -43,7 +43,7 @@
#define _64T0 (CLOCK)
// calculating the two possible pmc lengths, based on the clock. -4 at the end is to make sure not to increment too far
#define PMC_16T0_LEN ((128 + 127 + 16 + 32 + 33 + 16) * CLOCK/64);
#define PMC_16T0_LEN ((128 + 127 + 16 + 32 + 33 + 16) * CLOCK/64);
#define PMC_32T0_LEN ((128 + 127 + 16 + 32 + 33 ) * CLOCK/64);
// theshold for recognition of positive/negative slope
@ -54,13 +54,13 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr();
uint16_t g_GraphTraceLen = BigBuf_max_traceLen();
// limit g_GraphTraceLen to a little more than 2 data frames.
// limit g_GraphTraceLen to a little more than 2 data frames.
// To make sure a complete dataframe is in the dataset.
// 1 Frame is 16 Byte -> 128byte. at a T0 of 64 -> 8129 Samples per frame.
// + PMC -> 384T0 --> 8576 samples required for one block
// to make sure that one complete block is definitely being sampled, we need 2 times that
// which is ~17.xxx samples. round up. and clamp to this value.
// TODO: Doublecheck why this is being limited? - seems not to be needed.
// g_GraphTraceLen = (g_GraphTraceLen > 18000) ? 18000 : g_GraphTraceLen;
@ -87,15 +87,15 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
samplePosLastEdge = 0;
block_done = 0;
bitPos = 0;
lastClockDuration=0;
for (sample = 1 ; sample < g_GraphTraceLen-4; sample++) {
// condition is searching for the next edge, in the expected diretion.
//todo: without flouz
dest[sample] = (uint8_t)(dest[sample-1] * IIR_CONST1 + dest[sample] * IIR_CONST2); // apply IIR filter
lastClockDuration = 0;
if ( ((dest[sample] + THRESHOLD) < dest[sample-1] && expectedNextEdge == FALLING ) ||
((dest[sample] - THRESHOLD) > dest[sample-1] && expectedNextEdge == RISING )) {
for (sample = 1 ; sample < g_GraphTraceLen - 4; sample++) {
// condition is searching for the next edge, in the expected diretion.
//todo: without flouz
dest[sample] = (uint8_t)(dest[sample - 1] * IIR_CONST1 + dest[sample] * IIR_CONST2); // apply IIR filter
if (((dest[sample] + THRESHOLD) < dest[sample - 1] && expectedNextEdge == FALLING) ||
((dest[sample] - THRESHOLD) > dest[sample - 1] && expectedNextEdge == RISING)) {
//okay, next falling/rising edge found
expectedNextEdge = (expectedNextEdge == FALLING) ? RISING : FALLING; //toggle the next expected edge
@ -104,14 +104,14 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
lastClockDuration = samplePosCurrentEdge - samplePosLastEdge;
samplePosLastEdge = sample;
// Dbprintf("%d, %d, edge found, len: %d, nextEdge: %d", sample, dest[sample], lastClockDuration*DECIMATION, expectedNextEdge);
// Dbprintf("%d, %d, edge found, len: %d, nextEdge: %d", sample, dest[sample], lastClockDuration*DECIMATION, expectedNextEdge);
// Switch depending on lastClockDuration length:
// 16T0
// 16T0
if (ABS(lastClockDuration - _16T0) < TOLERANCE) {
// if the clock before also was 16T0, it is a PMC!
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
// It's a PMC
Dbprintf(_GREEN_("PMC 16T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
sample += PMC_16T0_LEN; // move to the sample after PMC
@ -120,44 +120,44 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
samplePosLastEdge = sample;
block_done = 1;
}
// 32TO
// 32TO
} else if (ABS(lastClockDuration - _32T0) < TOLERANCE) {
// if the clock before also was 16T0, it is a PMC!
if (ABS(beforeLastClockDuration - _16T0) < TOLERANCE) {
// It's a PMC !
Dbprintf(_GREEN_("PMC 32T0 FOUND:") " bitPos: %d, sample: %d", bitPos, sample);
sample += PMC_32T0_LEN; // move to the sample after PMC
expectedNextEdge = FALLING;
samplePosLastEdge = sample;
block_done = 1;
// if no pmc, then its a normal bit.
// Check if its the second time, the edge changed if yes, then the bit is 0
// if no pmc, then its a normal bit.
// Check if its the second time, the edge changed if yes, then the bit is 0
} else if (half_switch == 1) {
bits[bitPos] = 0;
// reset the edge counter to 0
half_switch = 0;
bitPos++;
// if it is the first time the edge changed. No bit value will be set here, bit if the
// edge changes again, it will be. see case above.
// if it is the first time the edge changed. No bit value will be set here, bit if the
// edge changes again, it will be. see case above.
} else
half_switch++;
// 64T0
// 64T0
} else if (ABS(lastClockDuration - _64T0) < TOLERANCE) {
// this means, bit here is 1
bits[bitPos] = 1;
bitPos++;
// Error
// Error
} else {
// some Error. maybe check tolerances.
// some Error. maybe check tolerances.
// likeley to happen in the first block.
// In an Ideal world, this can be enabled. However, if only bad antenna field, this print will flood the output
// and one might miss some "good" frames.
//Dbprintf(_RED_("ERROR in demodulation") " Length last clock: %d - check threshold/tolerance/signal. Toss block", lastClockDuration*DECIMATION);
@ -168,7 +168,7 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
if (block_done == 1) {
// Dbprintf(_YELLOW_("Block Done") " bitPos: %d, sample: %d", bitPos, sample);
// check if it is a complete block. If bitpos <128, it means that we did not receive
// a complete block. E.g. at the first start of a transmission.
// only save if a complete block is being received.
@ -187,14 +187,14 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
}
num_blocks++;
}
// now start over for the next block / first complete block.
// now start over for the next block / first complete block.
bitPos = 0;
block_done = 0;
half_switch = 0;
}
}else {
// Dbprintf("%d, %d", sample, dest[sample]);
} else {
// Dbprintf("%d, %d", sample, dest[sample]);
}
// one block only holds 16byte (=128 bit) and then comes the PMC. so if more bit are found than 129, there must be an issue and PMC has not been identfied...
@ -204,8 +204,8 @@ size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
bitPos = 0;
}
}
}
memcpy(outBlocks, blocks, 16 * num_blocks);
return num_blocks;
}
@ -251,10 +251,10 @@ bool IsBlock1PCF7931(const uint8_t *block) {
}
void ReadPCF7931(bool ledcontrol) {
uint8_t maxBlocks = 8; // readable blocks
int found_blocks = 0; // successfully read blocks
// TODO: Why 17 byte len? 16 should be good.
uint8_t memory_blocks[maxBlocks][17]; // PCF content
uint8_t single_blocks[maxBlocks][17]; // PFC blocks with unknown position
@ -263,7 +263,7 @@ void ReadPCF7931(bool ledcontrol) {
int single_blocks_cnt = 0;
size_t n; // transmitted blocks
//uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
int errors = 0; // error counter
int tries = 0; // tries counter
@ -300,7 +300,7 @@ void ReadPCF7931(bool ledcontrol) {
goto end;
}
// This part was not working properly.
// This part was not working properly.
// So currently the blocks are not being sorted, but at least printed.
// // our logic breaks if we don't get at least two blocks
@ -403,28 +403,28 @@ void ReadPCF7931(bool ledcontrol) {
end:
/*
Dbprintf("-----------------------------------------");
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for (i = 0; i < maxBlocks; ++i) {
if (memory_blocks[i][ALLOC])
print_result("Block", memory_blocks[i], 16);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
/*
Dbprintf("-----------------------------------------");
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for (i = 0; i < maxBlocks; ++i) {
if (memory_blocks[i][ALLOC])
print_result("Block", memory_blocks[i], 16);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
if (found_blocks < maxBlocks) {
Dbprintf("-----------------------------------------");
Dbprintf("Blocks with unknown position:");
Dbprintf("-----------------------------------------");
for (i = 0; i < single_blocks_cnt; ++i)
print_result("Block", single_blocks[i], 16);
if (found_blocks < maxBlocks) {
Dbprintf("-----------------------------------------");
Dbprintf("Blocks with unknown position:");
Dbprintf("-----------------------------------------");
for (i = 0; i < single_blocks_cnt; ++i)
print_result("Block", single_blocks[i], 16);
Dbprintf("-----------------------------------------");
}
*/
Dbprintf("-----------------------------------------");
}
*/
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
}
@ -434,7 +434,7 @@ static void RealWritePCF7931(
uint16_t init_delay,
int8_t offsetPulseWidth, int8_t offsetPulsePosition,
uint8_t address, uint8_t byte, uint8_t data,
bool ledcontrol){
bool ledcontrol) {
uint32_t tab[1024] = {0}; // data times frame
uint32_t u = 0;
@ -512,10 +512,10 @@ static void RealWritePCF7931(
* @param data : data to write
*/
void WritePCF7931(
uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7,
uint16_t init_delay,
int8_t offsetPulseWidth, int8_t offsetPulsePosition,
uint8_t address, uint8_t byte, uint8_t data,
uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7,
uint16_t init_delay,
int8_t offsetPulseWidth, int8_t offsetPulsePosition,
uint8_t address, uint8_t byte, uint8_t data,
bool ledcontrol) {
if (g_dbglevel >= DBG_INFO) {
@ -550,7 +550,7 @@ void SendCmdPCF7931(uint32_t *tab, bool ledcontrol) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
if (ledcontrol) LED_A_ON();
// rescale the values to match the time of the timer below.
for (u = 0; u < 500; ++u) {
tab[u] = (tab[u] * 3) / 2;
@ -651,7 +651,7 @@ bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offset
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
tab[u + 2] = 88 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
} else { //add a bit 0
if (u == 0)
tab[u] = 98 * T0_PCF + offsetPulsePosition;
@ -660,7 +660,7 @@ bool AddBitPCF7931(bool b, uint32_t *tab, int8_t offsetPulseWidth, int8_t offset
tab[u + 1] = 6 * T0_PCF + tab[u] + offsetPulseWidth;
tab[u + 2] = 24 * T0_PCF + tab[u + 1] - offsetPulseWidth - offsetPulsePosition;
}
return true;
}

View file

@ -19,9 +19,9 @@
#include "common.h"
typedef enum{
typedef enum {
FALLING,
RISING
RISING
} EdgeType;
size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol);

View file

@ -102,7 +102,7 @@ local function reanimate_t5577(password)
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r0 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r1 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r2 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -p 00000000')
p:console('lf t55 write -b 0 -d 000880E0 --pg1 --r3 -p 00000000')
reset_log_file()
end
@ -118,7 +118,7 @@ local function main(args)
print(dash)
print("::: "..ac.cyan.."Hold on, I'm searching for a password in the dictionary"..ac.reset.." :::")
print(dash)
p:console('lf t55 chk')
p:console('lf t55 chk')
local log_content = read_log_file(logfile)
local password = log_content and extract_password(log_content) or nil
reanimate_t5577(password)
@ -141,4 +141,4 @@ local function main(args)
print(dash)
end
main(args)
main(args)

View file

@ -9,14 +9,14 @@ local command = core.console
command('clear')
author = ' Author: jareckib - 12.03.2025'
version = ' version v1.03'
desc = [[
desc = [[
This simple script stores 1, 2 or 3 different EM4102 on a single T5577.
There is an option to enter the number engraved on the fob in decimal form.
The script can therefore be useful if the original EM4102 doesn't work but
has an engraved ID number. By entering such an ID as a single EM4102, we
The script can therefore be useful if the original EM4102 doesn't work but
has an engraved ID number. By entering such an ID as a single EM4102, we
can create a working copy of our damaged fob.
A tag T5577 created in this way works with the following USB readers:
- ACM08Y
- ACM26C
- Sycreader R60D
@ -121,7 +121,7 @@ local function get_uid_from_user()
while true do
print(dash)
io.write(ac.cyan .. '(1)' .. ac.reset .. ' Manual entry UID |' .. ac.cyan .. ' (2)' .. ac.reset .. ' Read via Proxmark3 ')
local choice
repeat
choice = io.read()
@ -159,7 +159,7 @@ local function get_uid_from_user()
io.read()
while true do
reset_log_file()
reset_log_file()
command('lf em 410x read')
local log_content = read_log_file(logfile)
local uid = extract_uid(log_content)
@ -178,7 +178,7 @@ end
local function main(args)
for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end
end
end
local blocks = {}
local uid_count = 0
@ -224,4 +224,4 @@ local function main(args)
print(ac.green .. "Successfully written " .. uid_count .. " EM4102 UID(s) to T5577" .. ac.reset)
end
main(args)
main(args)

View file

@ -459,4 +459,4 @@ local function main(args)
end
end
main(args)
main(args)

View file

@ -77,14 +77,14 @@ def parse_config(config: str):
cfg_auth_type = config[8:10]
cfg_cuid = config[12:14]
cfg_memory_config = config[14:16]
log_magic_wup = "Magic wakeup " + ("en" if cfg_magic_wup != "8500" else "dis") + "abled" + (" with config access" if cfg_magic_wup == "7AFF" else "")
log_wup_style = "Magic wakeup style " + ("Gen1a 40(7)/43" if cfg_wup_style == "00" else ("GDM 20(7)/23" if cfg_wup_style == "85" else "unknown"))
log_regular_available = "Config " + ("" if cfg_regular_available == "A0" else "un") + "available in regular mode"
log_auth_type = "Auth type " + ("1B - PWD" if cfg_auth_type == "00" else "1A - 3DES")
log_cuid = "CUID " + ("dis" if cfg_cuid == "A0" else "en") + "abled"
log_memory_config = "Maximum memory configuration: " + (MEMORY_CONFIG[cfg_memory_config] if cfg_memory_config in MEMORY_CONFIG.keys() else "unknown")
print(SUCCESS + "^^^^............................ " + log_magic_wup)
print(SUCCESS + "....^^.......................... " + log_wup_style)
print(SUCCESS + "......^^........................ " + log_regular_available)
@ -93,7 +93,7 @@ def parse_config(config: str):
print(SUCCESS + "............^^.................. " + log_cuid)
print(SUCCESS + "..............^^................ " + log_memory_config)
print(SUCCESS + "................^^^^^^^^^^^^^^^^ version info")
def try_auth_magic(enforced = False):
if enforced and not (gen1a | alt):
print(ERROR + "Magic wakeup required. Please select one.")
@ -158,7 +158,7 @@ elif write_backdoor != None:
if len(data) % 8 != 0:
print(ERROR + "Data must be a multiple of 4 bytes.")
exit()
try_auth_magic(True)
for i in range(len(data) // 8):
p.console("hf 14a raw -" + ("k" if i != (len(data) // 8 - 1) else "") + f"c A2{(write_backdoor_num + i):02x}{data[8*i:8*i+8]}", False, False)
@ -171,13 +171,13 @@ elif uid != None:
p.console(f"hf 14a raw -kc" + ("s" if not (gen1a or alt) else "") + " 3002")
block_2 = p.grabbed_output.split("\n")[-2][4:-9].replace(" ", "")[:8]
uid_bytes = [int(uid[2*x:2*x+2], 16) for x in range(7)]
bcc_0 = 0x88 ^ uid_bytes[0] ^ uid_bytes[1] ^ uid_bytes[2]
new_block_0 = ""
for i in range(3):
new_block_0 += f"{uid_bytes[i]:02x}"
new_block_0 += f"{bcc_0:02x}"
bcc_1 = uid_bytes[3] ^ uid_bytes[4] ^ uid_bytes[5] ^ uid_bytes[6]
new_block_1 = uid[6:]
new_block_2 = f"{bcc_1:02x}" + block_2[2:]

View file

@ -42,7 +42,7 @@ typedef struct _em4x70_tag_info_t {
/// * UM2 does not exist on the tag
/// * Pin does not exist on the tag
/// * UM1 (including the lock bits) might be one-time programmable (OTP)
///
///
/// [31] == Block 15 MSB == UM2₆₃..UM2₅₆
/// [30] == Block 15 LSB == UM2₅₅..UM2₄₈
/// [29] == Block 14 MSB == UM2₄₇..UM2₄₀

View file

@ -186,6 +186,7 @@ static void fill_grabber(const char *string) {
g_grabbed_output.ptr = tmp;
g_grabbed_output.size += MAX_PRINT_BUFFER;
}
int len = snprintf(g_grabbed_output.ptr + g_grabbed_output.idx, MAX_PRINT_BUFFER, "%s", string);
if (len < 0 || len > MAX_PRINT_BUFFER) {
// We leave current g_grabbed_output_len untouched
@ -196,24 +197,34 @@ static void fill_grabber(const char *string) {
}
void PrintAndLogOptions(const char *str[][2], size_t size, size_t space) {
char buff[2000] = "Options:\n";
char format[2000] = "";
size_t counts[2] = {0, 0};
for (size_t i = 0; i < size; i++)
for (size_t j = 0 ; j < 2 ; j++)
for (size_t i = 0; i < size; i++) {
for (size_t j = 0 ; j < 2 ; j++) {
if (counts[j] < strlen(str[i][j])) {
counts[j] = strlen(str[i][j]);
}
}
}
for (size_t i = 0; i < size; i++) {
for (size_t j = 0; j < 2; j++) {
if (j == 0)
if (j == 0) {
snprintf(format, sizeof(format), "%%%zus%%%zus", space, counts[j]);
else
} else {
snprintf(format, sizeof(format), "%%%zus%%-%zus", space, counts[j]);
}
snprintf(buff + strlen(buff), sizeof(buff) - strlen(buff), format, " ", str[i][j]);
}
if (i < size - 1)
if (i < size - 1) {
strncat(buff, "\n", sizeof(buff) - strlen(buff) - 1);
}
}
PrintAndLogEx(NORMAL, "%s", buff);
}
@ -223,12 +234,14 @@ static uint8_t PrintAndLogEx_spinidx = 0;
void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
// skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG -0'
if (g_debugMode == 0 && level == DEBUG)
if (g_debugMode == 0 && level == DEBUG) {
return;
}
// skip HINT messages if client has hints turned off i.e. 'HINT 0'
if (g_session.show_hints == false && level == HINT)
if (g_session.show_hints == false && level == HINT) {
return;
}
char prefix[40] = {0};
char buffer[MAX_PRINT_BUFFER] = {0};
@ -242,17 +255,19 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
};
switch (level) {
case ERR:
if (g_session.emoji_mode == EMO_EMOJI)
if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _RED_("!!") "] :rotating_light: ", sizeof(prefix) - 1);
else
} else {
strncpy(prefix, "[" _RED_("!!") "] ", sizeof(prefix) - 1);
}
stream = stderr;
break;
case FAILED:
if (g_session.emoji_mode == EMO_EMOJI)
if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _RED_("-") "] :no_entry: ", sizeof(prefix) - 1);
else
} else {
strncpy(prefix, "[" _RED_("-") "] ", sizeof(prefix) - 1);
}
break;
case DEBUG:
strncpy(prefix, "[" _BLUE_("#") "] ", sizeof(prefix) - 1);
@ -264,10 +279,11 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
strncpy(prefix, "[" _GREEN_("+") "] ", sizeof(prefix) - 1);
break;
case WARNING:
if (g_session.emoji_mode == EMO_EMOJI)
if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, "[" _CYAN_("!") "] :warning: ", sizeof(prefix) - 1);
else
} else {
strncpy(prefix, "[" _CYAN_("!") "] ", sizeof(prefix) - 1);
}
break;
case INFO:
strncpy(prefix, "[" _YELLOW_("=") "] ", sizeof(prefix) - 1);
@ -276,13 +292,15 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
if (g_session.emoji_mode == EMO_EMOJI) {
strncpy(prefix, spinner_emoji[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
PrintAndLogEx_spinidx++;
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji))
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji)) {
PrintAndLogEx_spinidx = 0;
}
} else {
strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1);
PrintAndLogEx_spinidx++;
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner))
if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner)) {
PrintAndLogEx_spinidx = 0;
}
}
break;
case NORMAL:
@ -306,8 +324,9 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
const char delim[2] = "\n";
// line starts with newline
if (buffer[0] == '\n')
if (buffer[0] == '\n') {
fPrintAndLog(stream, "");
}
token = strtok_r(buffer, delim, &tmp_ptr);
@ -315,16 +334,21 @@ void PrintAndLogEx(logLevel_t level, const char *fmt, ...) {
size_t size = strlen(buffer2);
if (strlen(token))
if (strlen(token)) {
snprintf(buffer2 + size, sizeof(buffer2) - size, "%s%s\n", prefix, token);
else
} else {
snprintf(buffer2 + size, sizeof(buffer2) - size, "\n");
}
token = strtok_r(NULL, delim, &tmp_ptr);
}
fPrintAndLog(stream, "%s", buffer2);
} else {
snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer);
if (level == INPLACE) {
// ignore INPLACE if rest of output is grabbed
if (!(g_printAndLog & PRINTANDLOG_GRAB)) {
@ -354,6 +378,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
if (logging && g_session.incognito) {
logging = 0;
}
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) {
char *my_logfile_path = NULL;
char filename[40];
@ -361,11 +386,15 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
time_t now = time(NULL);
timenow = gmtime(&now);
strftime(filename, sizeof(filename), PROXLOG, timenow);
if (searchHomeFilePath(&my_logfile_path, LOGS_SUBDIR, filename, true) != PM3_SUCCESS) {
printf(_YELLOW_("[-]") " Logging disabled!\n");
my_logfile_path = NULL;
logging = 0;
} else {
logfile = fopen(my_logfile_path, "a");
if (logfile == NULL) {
printf(_YELLOW_("[-]") " Can't open logfile %s, logging disabled!\n", my_logfile_path);
@ -411,13 +440,16 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
linefeed = false;
buffer[strlen(buffer) - 1] = 0;
}
bool filter_ansi = !g_session.supports_colors;
memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi);
if (g_printAndLog & PRINTANDLOG_PRINT) {
if ((g_printAndLog & PRINTANDLOG_PRINT) == PRINTANDLOG_PRINT) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), g_session.emoji_mode);
fprintf(stream, "%s", buffer3);
if (linefeed)
if (linefeed) {
fprintf(stream, "\n");
}
}
#ifdef RL_STATE_READCMD
@ -433,33 +465,44 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
if (((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) ||
(g_printAndLog & PRINTANDLOG_GRAB)) {
memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), EMO_ALTTEXT);
if (filter_ansi == false) {
memcpy_filter_ansi(buffer, buffer3, sizeof(buffer3), true);
}
}
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) {
if (filter_ansi) {
fprintf(logfile, "%s", buffer3);
} else {
fprintf(logfile, "%s", buffer);
}
if (linefeed)
if (linefeed) {
fprintf(logfile, "\n");
}
fflush(logfile);
}
if (g_printAndLog & PRINTANDLOG_GRAB) {
if (filter_ansi) {
fill_grabber(buffer3);
} else {
fill_grabber(buffer);
}
if (linefeed)
if (linefeed) {
fill_grabber("\n");
}
}
if (flushAfterWrite)
if (flushAfterWrite) {
fflush(stdout);
}
//release lock
pthread_mutex_unlock(&g_print_lock);
@ -478,9 +521,10 @@ void memcpy_filter_rlmarkers(void *dest, const void *src, size_t n) {
uint8_t *rsrc = (uint8_t *)src;
uint16_t si = 0;
for (size_t i = 0; i < n; i++) {
if ((rsrc[i] == '\001') || (rsrc[i] == '\002'))
if ((rsrc[i] == '\001') || (rsrc[i] == '\002')) {
// skip readline special markers
continue;
}
rdest[si++] = rsrc[i];
}
}

View file

@ -5047,7 +5047,7 @@
"-v, --verbose verbose output",
"-f, --file <fn> Specify a filename for dump file",
"--emu from emulator memory",
"--start <dec> index of block to start writing (default 0)",
"--start <dec> index of block to start writing (def 0)",
"--end <dec> index of block to end writing (default last block)"
],
"usage": "hf mf gload [-hv] [--mini] [--1k] [--1k+] [--2k] [--4k] [-p <hex>] [-f <fn>] [--emu] [--start <dec>] [--end <dec>]"
@ -10992,8 +10992,8 @@
"-r, --reset Reset configuration to default values",
"-p, --pwd <hex> Password, 7bytes, LSB-order",
"-d, --delay <dec> Tag initialization delay (in us)",
"--lw <dec> offset, low pulses width (in us)",
"--lp <dec> offset, low pulses position (in us)"
"--lw <dec> offset, low pulses width (in us), optional!",
"--lp <dec> offset, low pulses position (in us), optional!"
],
"usage": "lf pcf7931 config [-hr] [-p <hex>] [-d <dec>] [--lw <dec>] [--lp <dec>]"
},
@ -13232,6 +13232,6 @@
"metadata": {
"commands_extracted": 760,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-03-12T15:46:33"
"extracted_on": "2025-03-18T06:54:58"
}
}