2020-06-15 20:31:34 +08:00
//-----------------------------------------------------------------------------
// Copyright (C) 2020 tharexde
//
2020-12-04 07:11:57 +08:00
// modified iceman, 2020
//
2020-06-15 20:31:34 +08:00
// 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.
//-----------------------------------------------------------------------------
// Low frequency EM4x50 commands
//-----------------------------------------------------------------------------
2020-11-02 05:51:32 +08:00
# include "cliparser.h"
2020-06-15 20:31:34 +08:00
# include "cmdlfem4x50.h"
# include <ctype.h>
2020-12-04 07:11:57 +08:00
# include "cmdparser.h" // command_t
2020-06-15 20:31:34 +08:00
# include "fileutils.h"
2020-06-18 05:39:00 +08:00
# include "commonutil.h"
2020-11-10 07:39:48 +08:00
# include "pmflash.h"
2020-12-05 05:38:48 +08:00
# include "cmdflashmemspiffs.h"
2020-06-15 20:31:34 +08:00
2020-12-04 03:40:58 +08:00
# define BYTES2UINT32(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3]))
2020-12-07 03:40:46 +08:00
static int CmdHelp ( const char * Cmd ) ;
2020-06-15 20:31:34 +08:00
2020-12-30 00:40:18 +08:00
static void write_gnuplot_config_file ( int gHigh , int gLow ) {
const char * fn = " ../data/data.gnu " ;
FILE * fp = NULL ;
if ( ( fp = fopen ( fn , " w+ " ) ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, open file %s " , fn ) ;
}
fprintf ( fp , " set term qt size 1400, 350 enhanced \n " ) ;
fprintf ( fp , " set border 31 front linecolor rgb 'dark-grey' linewidth 1.000 dashtype solid \n " ) ;
fprintf ( fp , " set xtics 0, 1 textcolor rgb 'dark-grey' \n " ) ;
fprintf ( fp , " set ytics 0, 64 textcolor rgb 'dark-grey' \n " ) ;
fprintf ( fp , " set title 'EM4x50 signal (amplitude vs time)' \n " ) ;
fprintf ( fp , " set title font ',14' textcolor rgb 'white' \n " ) ;
fprintf ( fp , " set xlabel 'time / ms' \n " ) ;
fprintf ( fp , " set xlabel font ',12' textcolor rgb 'dark-grey' \n " ) ;
fprintf ( fp , " set ylabel 'amplitude' \n " ) ;
fprintf ( fp , " set ylabel font ',12' textcolor rgb 'dark-grey' \n " ) ;
fprintf ( fp , " set key textcolor 'green' \n " ) ;
fprintf ( fp , " set grid \n " ) ;
fprintf ( fp , " #set time textcolor 'dark-grey' \n " ) ;
fprintf ( fp , " plot [0:][-50:300] '../data/data.dat' u ($1/1000):2 w l linecolor 'green' title '500/4', '../data/data.dat' u ($1/1000):3 w l linecolor 'yellow' title 'gHigh = %i', '../data/data.dat' u ($1/1000):4 w l linecolor 'yellow' title 'gLow = %i' \n " , gHigh , gLow ) ;
fprintf ( fp , " pause -1 \n " ) ;
fclose ( fp ) ;
}
static void get_samples ( void ) {
int gHigh = 0 , gLow = 0 ;
const char * fn = " ../data/data.dat " ;
FILE * fp = NULL ;
// download from BigBuf memory
uint8_t data [ EM4X50_MAX_NO_SAMPLES + 2 ] = { 0x0 } ;
if ( GetFromDevice ( BIG_BUF , data , EM4X50_MAX_NO_SAMPLES + 2 , 0 , NULL , 0 , NULL , 2500 , false ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, transfer from device time-out " ) ;
}
if ( ( fp = fopen ( fn , " w+ " ) ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, open file %s " , fn ) ;
}
gHigh = data [ 0 ] ;
gLow = data [ 1 ] ;
for ( int i = 2 ; i < EM4X50_MAX_NO_SAMPLES + 2 ; i + + ) {
fprintf ( fp , " %i %i %i %i \n " , ( i - 2 ) * 8 , data [ i ] , gHigh , gLow ) ;
}
fclose ( fp ) ;
write_gnuplot_config_file ( gHigh , gLow ) ;
}
2021-01-04 05:50:27 +08:00
/*
static void get_time_samples ( void ) {
const char * fn = " ../data/data.dat " ;
FILE * fp = NULL ;
// download from BigBuf memory
uint32_t data [ EM4X50_MAX_TIME_SAMPLES ] = { 0x0 } ;
if ( GetFromDevice ( BIG_BUF , ( uint8_t * ) data , EM4X50_MAX_TIME_SAMPLES , 0 , NULL , 0 , NULL , 2500 , false ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, transfer from device time-out " ) ;
}
if ( ( fp = fopen ( fn , " w+ " ) ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, open file %s " , fn ) ;
}
for ( int i = 0 ; i < EM4X50_MAX_TIME_SAMPLES ; i + + ) {
PrintAndLogEx ( INFO , " %i % " PRIu32 " " , i , data [ i ] ) ;
fprintf ( fp , " %i % " PRIu32 " \n " , i , data [ i ] ) ;
}
fclose ( fp ) ;
}
*/
2020-10-12 02:06:03 +08:00
static void prepare_result ( const uint8_t * data , int fwr , int lwr , em4x50_word_t * words ) {
2020-06-15 20:31:34 +08:00
2020-10-12 02:06:03 +08:00
// restructure received result in "em4x50_word_t" structure
2020-12-09 19:18:01 +08:00
for ( int i = fwr ; i < = lwr ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
2020-12-12 21:46:40 +08:00
words [ i ] . byte [ j ] = data [ i * 4 + ( 3 - j ) ] ;
2020-12-09 19:18:01 +08:00
}
}
2020-06-15 20:31:34 +08:00
}
2020-07-06 11:41:44 +08:00
static void print_result ( const em4x50_word_t * words , int fwr , int lwr ) {
2020-07-01 00:50:38 +08:00
2020-06-15 20:31:34 +08:00
// print available information for given word from fwr to lwr, i.e.
// bit table + summary lines with hex notation of word (msb + lsb)
2020-07-01 00:50:38 +08:00
2020-07-06 11:41:44 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " # | word (msb) | word (lsb) | desc " ) ;
PrintAndLogEx ( INFO , " ----+-------------+-------------+-------------------- " ) ;
2020-06-15 20:31:34 +08:00
for ( int i = fwr ; i < = lwr ; i + + ) {
2020-07-06 11:41:44 +08:00
char s [ 50 ] = { 0 } ;
2020-08-13 18:25:04 +08:00
switch ( i ) {
2020-07-06 11:41:44 +08:00
case EM4X50_DEVICE_PASSWORD :
sprintf ( s , _YELLOW_ ( " password, write only " ) ) ;
break ;
case EM4X50_PROTECTION :
sprintf ( s , _YELLOW_ ( " protection cfg (locked) " ) ) ;
break ;
case EM4X50_CONTROL :
sprintf ( s , _YELLOW_ ( " control cfg (locked) " ) ) ;
break ;
case EM4X50_DEVICE_SERIAL :
sprintf ( s , _YELLOW_ ( " device serial number (read only) " ) ) ;
break ;
case EM4X50_DEVICE_ID :
sprintf ( s , _YELLOW_ ( " device identification (read only) " ) ) ;
break ;
default :
sprintf ( s , " user data " ) ;
break ;
}
2020-06-29 03:35:06 +08:00
2020-07-06 11:41:44 +08:00
char r [ 30 ] = { 0 } ;
for ( int j = 3 ; j > = 0 ; j - - ) {
sprintf ( r + strlen ( r ) , " %02x " , reflect8 ( words [ i ] . byte [ j ] ) ) ;
2020-06-15 20:31:34 +08:00
}
2020-08-13 18:25:04 +08:00
2020-07-06 11:41:44 +08:00
PrintAndLogEx ( INFO , " %2i | " _GREEN_ ( " %s " ) " | %s| %s " ,
2020-08-13 18:25:04 +08:00
i ,
sprint_hex ( words [ i ] . byte , 4 ) ,
r ,
s
) ;
2020-06-15 20:31:34 +08:00
}
2020-07-06 11:41:44 +08:00
PrintAndLogEx ( INFO , " ----+-------------+-------------+-------------------- " ) ;
2020-06-15 20:31:34 +08:00
}
2020-12-20 05:00:48 +08:00
static void print_info_result ( uint8_t * data , bool verbose ) {
2020-06-15 20:31:34 +08:00
2020-06-23 06:36:19 +08:00
// display all information of info result in structured format
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
prepare_result ( data , 0 , EM4X50_NO_WORDS - 1 , words ) ;
bool bpwc = words [ EM4X50_CONTROL ] . byte [ CONFIG_BLOCK ] & PASSWORD_CHECK ;
bool braw = words [ EM4X50_CONTROL ] . byte [ CONFIG_BLOCK ] & READ_AFTER_WRITE ;
2020-06-30 23:43:47 +08:00
2020-06-23 06:36:19 +08:00
int fwr = reflect8 ( words [ EM4X50_CONTROL ] . byte [ FIRST_WORD_READ ] ) ;
int lwr = reflect8 ( words [ EM4X50_CONTROL ] . byte [ LAST_WORD_READ ] ) ;
int fwrp = reflect8 ( words [ EM4X50_PROTECTION ] . byte [ FIRST_WORD_READ_PROTECTED ] ) ;
int lwrp = reflect8 ( words [ EM4X50_PROTECTION ] . byte [ LAST_WORD_READ_PROTECTED ] ) ;
int fwwi = reflect8 ( words [ EM4X50_PROTECTION ] . byte [ FIRST_WORD_WRITE_INHIBITED ] ) ;
int lwwi = reflect8 ( words [ EM4X50_PROTECTION ] . byte [ LAST_WORD_WRITE_INHIBITED ] ) ;
2020-07-01 00:50:38 +08:00
2020-06-30 23:43:47 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --- " _CYAN_ ( " Tag Information " ) " --------------------------- " ) ;
PrintAndLogEx ( INFO , " ------------------------------------------------------------- " ) ;
2020-07-01 00:50:38 +08:00
2020-06-15 20:31:34 +08:00
// data section
2020-06-30 23:43:47 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , _YELLOW_ ( " EM4x50 data: " ) ) ;
2020-12-20 05:00:48 +08:00
if ( verbose ) {
print_result ( words , 0 , EM4X50_NO_WORDS - 1 ) ;
} else {
print_result ( words , EM4X50_DEVICE_SERIAL , EM4X50_DEVICE_ID ) ;
}
2020-08-13 18:25:04 +08:00
2020-06-15 20:31:34 +08:00
// configuration section
2020-06-30 23:43:47 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " ---- " _CYAN_ ( " Configuration " ) " ---- " ) ;
2020-06-15 20:31:34 +08:00
2020-06-30 23:43:47 +08:00
PrintAndLogEx ( INFO , " first word read %3i " , fwr ) ;
PrintAndLogEx ( INFO , " last word read %3i " , lwr ) ;
2020-08-13 18:25:04 +08:00
PrintAndLogEx ( INFO , " password check %3s " , ( bpwc ) ? _RED_ ( " on " ) : _GREEN_ ( " off " ) ) ;
2020-06-30 23:43:47 +08:00
PrintAndLogEx ( INFO , " read after write %3s " , ( braw ) ? " on " : " off " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " --------- " _CYAN_ ( " Protection " ) " --------- " ) ;
PrintAndLogEx ( INFO , " first word read protected %3i " , fwrp ) ;
PrintAndLogEx ( INFO , " last word read protected %3i " , lwrp ) ;
PrintAndLogEx ( INFO , " first word write inhibited %3i " , fwwi ) ;
PrintAndLogEx ( INFO , " last word write inhibited %3i " , lwwi ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " zero values may indicate read protection " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
}
2020-06-15 20:31:34 +08:00
2020-11-20 06:18:04 +08:00
static int em4x50_load_file ( const char * filename , uint8_t * data , size_t data_len , size_t * bytes_read ) {
2020-06-15 20:31:34 +08:00
2020-11-20 06:18:04 +08:00
// read data from dump file; file type is derived from file name extension
2020-06-15 20:31:34 +08:00
2020-11-20 06:18:04 +08:00
int res = 0 ;
uint32_t serial = 0x0 , device_id = 0x0 ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
if ( str_endswith ( filename , " .eml " ) )
res = loadFileEML ( filename , data , bytes_read ) ! = PM3_SUCCESS ;
else if ( str_endswith ( filename , " .json " ) )
res = loadFileJSON ( filename , data , data_len , bytes_read , NULL ) ;
else
res = loadFile ( filename , " .bin " , data , data_len , bytes_read ) ;
2020-11-02 05:51:32 +08:00
2020-11-20 06:18:04 +08:00
if ( ( res ! = PM3_SUCCESS ) & & ( * bytes_read ! = DUMP_FILESIZE ) )
return PM3_EFILE ;
2020-06-15 20:31:34 +08:00
2020-11-20 06:18:04 +08:00
// valid em4x50 data?
serial = bytes_to_num ( data + 4 * EM4X50_DEVICE_SERIAL , 4 ) ;
device_id = bytes_to_num ( data + 4 * EM4X50_DEVICE_ID , 4 ) ;
if ( serial = = device_id ) {
PrintAndLogEx ( WARNING , " No valid em4x50 data in file %s. " , filename ) ;
return PM3_ENODATA ;
2020-06-15 20:31:34 +08:00
}
2020-11-20 06:18:04 +08:00
return PM3_SUCCESS ;
}
2020-06-15 20:31:34 +08:00
2020-12-04 03:40:58 +08:00
static void em4x50_seteml ( uint8_t * src , uint32_t offset , uint32_t numofbytes ) {
2020-12-04 05:00:52 +08:00
2020-12-04 03:40:58 +08:00
// fast push mode
conn . block_after_ACK = true ;
for ( size_t i = offset ; i < numofbytes ; i + = PM3_CMD_DATA_SIZE ) {
size_t len = MIN ( ( numofbytes - i ) , PM3_CMD_DATA_SIZE ) ;
if ( len = = numofbytes - i ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
clearCommandBuffer ( ) ;
SendCommandOLD ( CMD_LF_EM4X50_ESET , i , len , 0 , src + i , len ) ;
}
}
2020-11-20 06:18:04 +08:00
int CmdEM4x50ELoad ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 eload " ,
2020-12-04 03:40:58 +08:00
" Loads EM4x50 tag dump into emulator memory on device. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 eload -f mydump.bin \n "
" lf em 4x50 eload -f mydump.eml \n "
" lf em 4x50 eload -f mydump.json "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-11-20 06:18:04 +08:00
arg_str1 ( " f " , " filename " , " <filename> " , " dump filename " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-11-20 06:18:04 +08:00
2020-11-02 05:51:32 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
2020-11-20 06:18:04 +08:00
CLIParserFree ( ctx ) ;
// read data from dump file; file type has to be "bin", "eml" or "json"
2020-12-09 19:18:01 +08:00
size_t bytes_read = 0 ;
uint8_t data [ DUMP_FILESIZE ] = { 0x0 } ;
2020-11-20 06:18:04 +08:00
if ( em4x50_load_file ( filename , data , DUMP_FILESIZE , & bytes_read ) ! = PM3_SUCCESS ) {
PrintAndLogEx ( FAILED , " Read error " ) ;
return PM3_EFILE ;
2020-11-02 05:51:32 +08:00
}
2020-11-20 06:18:04 +08:00
2020-12-04 03:40:58 +08:00
// upload to emulator memory
PrintAndLogEx ( INFO , " Uploading dump " _YELLOW_ ( " %s " ) " to emulator memory " , filename ) ;
em4x50_seteml ( data , 0 , DUMP_FILESIZE ) ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INFO , " Done " ) ;
return PM3_SUCCESS ;
}
int CmdEM4x50ESave ( const char * Cmd ) {
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 esave " ,
2020-12-04 03:40:58 +08:00
" Saves bin/eml/json dump file of emulator memory. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 esave -> use UID as filename \n "
" lf em 4x50 esave -f mydump.bin \n "
" lf em 4x50 esave -f mydump.eml \n "
" lf em 4x50 esave -f mydump.json \n "
2020-11-20 06:18:04 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str0 ( " f " , " filename " , " <filename> " , " data filename " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
2020-11-02 05:51:32 +08:00
CLIParserFree ( ctx ) ;
2020-06-17 05:25:27 +08:00
2020-12-04 03:40:58 +08:00
// download emulator memory
PrintAndLogEx ( SUCCESS , " Reading emulator memory... " ) ;
2020-12-09 19:18:01 +08:00
uint8_t data [ DUMP_FILESIZE ] = { 0x0 } ;
if ( GetFromDevice ( BIG_BUF_EML , data , DUMP_FILESIZE , 0 , NULL , 0 , NULL , 2500 , false ) = = false ) {
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( WARNING , " Fail, transfer from device time-out " ) ;
2020-06-18 05:13:13 +08:00
return PM3_ETIMEOUT ;
2020-06-17 05:25:27 +08:00
}
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
// valid em4x50 data?
2020-12-09 19:18:01 +08:00
uint32_t serial = bytes_to_num ( data + 4 * EM4X50_DEVICE_SERIAL , 4 ) ;
uint32_t device_id = bytes_to_num ( data + 4 * EM4X50_DEVICE_ID , 4 ) ;
2020-11-20 06:18:04 +08:00
if ( serial = = device_id ) {
PrintAndLogEx ( WARNING , " No valid em4x50 data in flash memory. " ) ;
return PM3_ENODATA ;
2020-06-30 23:59:06 +08:00
}
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
// user supplied filename?
2020-12-09 19:18:01 +08:00
if ( fnlen = = 0 ) {
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INFO , " Using UID as filename " ) ;
2020-12-09 19:18:01 +08:00
char * fptr = filename ;
2020-11-20 06:18:04 +08:00
fptr + = snprintf ( fptr , sizeof ( filename ) , " lf-4x50- " ) ;
FillFileNameByUID ( fptr , ( uint8_t * ) & data [ 4 * EM4X50_DEVICE_ID ] , " -dump " , 4 ) ;
2020-06-30 23:59:06 +08:00
}
2020-11-20 06:18:04 +08:00
saveFile ( filename , " .bin " , data , DUMP_FILESIZE ) ;
saveFileEML ( filename , data , DUMP_FILESIZE , 4 ) ;
saveFileJSON ( filename , jsfEM4x50 , data , DUMP_FILESIZE , NULL ) ;
2020-06-30 23:59:06 +08:00
return PM3_SUCCESS ;
2020-06-17 05:25:27 +08:00
}
2020-12-12 02:55:15 +08:00
int CmdEM4x50EView ( const char * Cmd ) {
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " lf em 4x50 eview " ,
" Displays em4x50 content of emulator memory. " ,
" lf em 4x50 eview \n "
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
CLIParserFree ( ctx ) ;
// download emulator memory
PrintAndLogEx ( SUCCESS , " Reading emulator memory... " ) ;
uint8_t data [ DUMP_FILESIZE ] = { 0x0 } ;
if ( GetFromDevice ( BIG_BUF_EML , data , DUMP_FILESIZE , 0 , NULL , 0 , NULL , 2500 , false ) = = false ) {
PrintAndLogEx ( WARNING , " Fail, transfer from device time-out " ) ;
return PM3_ETIMEOUT ;
}
2020-12-24 02:51:10 +08:00
2020-12-12 02:55:15 +08:00
// valid em4x50 data?
uint32_t serial = bytes_to_num ( data + 4 * EM4X50_DEVICE_SERIAL , 4 ) ;
uint32_t device_id = bytes_to_num ( data + 4 * EM4X50_DEVICE_ID , 4 ) ;
if ( serial = = device_id ) {
PrintAndLogEx ( WARNING , " No valid em4x50 data in emulator memory. " ) ;
return PM3_ENODATA ;
}
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
for ( int i = 0 ; i < EM4X50_NO_WORDS ; i + + ) {
memcpy ( words [ i ] . byte , data + i * 4 , 4 ) ;
}
print_result ( words , 0 , EM4X50_NO_WORDS - 1 ) ;
PrintAndLogEx ( NORMAL , " " ) ;
return PM3_SUCCESS ;
}
2020-11-20 06:18:04 +08:00
int CmdEM4x50Login ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 login " ,
2020-11-20 06:18:04 +08:00
" Login into EM4x50 tag. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 login -p 12345678 -> login with password 12345678 \n "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-04 04:01:39 +08:00
arg_str1 ( " p " , " passsword " , " <hex> " , " password, 4 bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-11-20 06:18:04 +08:00
2020-12-12 21:46:40 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 1 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes " ) ;
2020-11-02 05:51:32 +08:00
return PM3_EINVARG ;
2020-12-12 21:46:40 +08:00
}
2020-11-20 06:18:04 +08:00
2020-12-09 19:18:01 +08:00
uint32_t password = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
// start
clearCommandBuffer ( ) ;
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-11-20 06:18:04 +08:00
SendCommandNG ( CMD_LF_EM4X50_LOGIN , ( uint8_t * ) & password , sizeof ( password ) ) ;
WaitForResponse ( CMD_LF_EM4X50_LOGIN , & resp ) ;
// print response
if ( resp . status = = PM3_SUCCESS )
PrintAndLogEx ( SUCCESS , " Login " _GREEN_ ( " ok " ) ) ;
else
PrintAndLogEx ( FAILED , " Login " _RED_ ( " failed " ) ) ;
2021-01-04 05:50:27 +08:00
get_samples ( ) ;
2020-11-20 06:18:04 +08:00
return resp . status ;
}
int CmdEM4x50Brute ( const char * Cmd ) {
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 brute " ,
2020-12-09 19:18:01 +08:00
" Tries to bruteforce the password of a EM4x50. \n "
" Function can be stopped by pressing pm3 button. " ,
" lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000 \n "
2020-11-20 06:18:04 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-09 19:18:01 +08:00
arg_str1 ( NULL , " first " , " <hex> " , " first password (start), 4 bytes, lsb " ) ,
arg_str1 ( NULL , " last " , " <hex> " , " last password (stop), 4 bytes, lsb " ) ,
2020-11-20 06:18:04 +08:00
arg_param_end
} ;
2020-12-12 21:46:40 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int first_len = 0 ;
2020-12-12 21:46:40 +08:00
uint8_t first [ 4 ] = { 0 , 0 , 0 , 0 } ;
2020-12-09 19:18:01 +08:00
CLIGetHexWithReturn ( ctx , 1 , first , & first_len ) ;
int last_len = 0 ;
2020-12-12 21:46:40 +08:00
uint8_t last [ 4 ] = { 0 , 0 , 0 , 0 } ;
2020-12-09 19:18:01 +08:00
CLIGetHexWithReturn ( ctx , 2 , last , & last_len ) ;
CLIParserFree ( ctx ) ;
2020-11-20 06:18:04 +08:00
2020-12-09 19:18:01 +08:00
if ( first_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes " ) ;
2020-11-02 05:51:32 +08:00
return PM3_EINVARG ;
2020-12-12 21:46:40 +08:00
}
if ( last_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes " ) ;
return PM3_EINVARG ;
}
2020-06-17 05:25:27 +08:00
2020-12-09 19:18:01 +08:00
em4x50_data_t etd ;
etd . password1 = BYTES2UINT32 ( first ) ;
etd . password2 = BYTES2UINT32 ( last ) ;
// 27 passwords/second (empirical value)
2020-12-12 21:46:40 +08:00
const int speed = 27 ;
2020-06-17 05:25:27 +08:00
2020-11-20 06:18:04 +08:00
// print some information
2020-12-09 19:18:01 +08:00
int no_iter = etd . password2 - etd . password1 + 1 ;
int dur_s = no_iter / speed ;
int dur_h = dur_s / 3600 ;
int dur_m = ( dur_s - dur_h * 3600 ) / 60 ;
2020-11-20 06:18:04 +08:00
dur_s - = dur_h * 3600 + dur_m * 60 ;
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( INFO , " Trying %i passwords in range [0x%08x, 0x%08x] "
2020-12-12 21:46:40 +08:00
, no_iter
, etd . password1
, etd . password2
) ;
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INFO , " Estimated duration: %ih%im%is " , dur_h , dur_m , dur_s ) ;
// start
2020-06-17 05:25:27 +08:00
clearCommandBuffer ( ) ;
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-11-20 06:18:04 +08:00
SendCommandNG ( CMD_LF_EM4X50_BRUTE , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
WaitForResponse ( CMD_LF_EM4X50_BRUTE , & resp ) ;
2020-06-17 05:25:27 +08:00
2020-11-20 06:18:04 +08:00
// print response
2020-12-09 19:18:01 +08:00
if ( resp . status = = PM3_SUCCESS )
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( SUCCESS , " Password " _GREEN_ ( " found " ) " : 0x%08x " , resp . data . asDwords [ 0 ] ) ;
else
PrintAndLogEx ( FAILED , " Password: " _RED_ ( " not found " ) ) ;
return PM3_SUCCESS ;
}
2020-12-09 19:18:01 +08:00
// upload passwords from given dictionary to device and start check;
// if no filename is given dictionary "t55xx_default_pwds.dic" is used
2020-11-20 06:18:04 +08:00
int CmdEM4x50Chk ( const char * Cmd ) {
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 chk " ,
2020-11-20 06:18:04 +08:00
" Dictionary attack against EM4x50. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 chk -> uses T55xx default dictionary \n "
" lf em 4x50 chk -f my.dic "
2020-11-20 06:18:04 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str0 ( " f " , " filename " , " <filename> " , " dictionary filename " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
2020-11-20 06:18:04 +08:00
CLIParserFree ( ctx ) ;
2020-12-12 21:46:40 +08:00
2020-12-09 19:18:01 +08:00
if ( IfPm3Flash ( ) = = false ) {
PrintAndLogEx ( WARNING , " no flash memory available " ) ;
return PM3_EFLASH ;
}
2020-11-20 06:18:04 +08:00
// no filename -> default = t55xx_default_pwds
if ( strlen ( filename ) = = 0 ) {
snprintf ( filename , sizeof ( filename ) , " t55xx_default_pwds " ) ;
PrintAndLogEx ( INFO , " treating file as T55xx keys " ) ;
2020-06-17 05:25:27 +08:00
}
2020-12-09 19:18:01 +08:00
size_t datalen = 0 ;
uint8_t data [ FLASH_MEM_MAX_SIZE ] = { 0x0 } ;
uint8_t * keys = data ;
uint32_t key_count = 0 ;
int res = loadFileDICTIONARY ( filename , data , & datalen , 4 , & key_count ) ;
2020-11-20 06:18:04 +08:00
if ( res | | ! key_count )
return PM3_EFILE ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INFO , " You can cancel this operation by pressing the pm3 button " ) ;
2020-12-09 19:18:01 +08:00
int status = PM3_EFAILED ;
int keyblock = 2000 ; // block with 2000 bytes -> 500 keys
uint8_t destfn [ 32 ] = " em4x50_chk.bin " ;
2020-12-12 21:46:40 +08:00
PacketResponseNG resp ;
2020-12-09 19:18:01 +08:00
int bytes_remaining = datalen ;
2020-12-06 06:47:53 +08:00
while ( bytes_remaining > 0 ) {
2020-12-12 21:46:40 +08:00
2020-12-06 06:47:53 +08:00
PrintAndLogEx ( INPLACE , " Remaining keys: %i " , bytes_remaining / 4 ) ;
2020-12-05 05:38:48 +08:00
// upload to flash.
2020-12-06 06:47:53 +08:00
datalen = MIN ( bytes_remaining , keyblock ) ;
res = flashmem_spiffs_load ( destfn , keys , datalen ) ;
2020-11-20 06:18:04 +08:00
if ( res ! = PM3_SUCCESS ) {
2020-12-05 05:42:54 +08:00
PrintAndLogEx ( WARNING , " SPIFFS upload failed " ) ;
2020-11-20 06:18:04 +08:00
return res ;
}
2020-12-06 06:47:53 +08:00
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_CHK , destfn , sizeof ( destfn ) ) ;
WaitForResponseTimeoutW ( CMD_LF_EM4X50_CHK , & resp , - 1 , false ) ;
2020-12-12 21:46:40 +08:00
2020-12-06 06:47:53 +08:00
status = resp . status ;
if ( ( status = = PM3_SUCCESS ) | | ( status = = PM3_EOPABORTED ) )
break ;
bytes_remaining - = keyblock ;
keys + = keyblock ;
2020-11-20 06:18:04 +08:00
}
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
// print response
if ( status = = PM3_SUCCESS ) {
PrintAndLogEx ( SUCCESS , " Key " _GREEN_ ( " found: %02x %02x %02x %02x " ) ,
resp . data . asBytes [ 3 ] ,
resp . data . asBytes [ 2 ] ,
resp . data . asBytes [ 1 ] ,
resp . data . asBytes [ 0 ]
2020-12-12 21:46:40 +08:00
) ;
2020-11-20 06:18:04 +08:00
} else {
PrintAndLogEx ( FAILED , " No key found " ) ;
}
PrintAndLogEx ( INFO , " Done " ) ;
return PM3_SUCCESS ;
}
//quick test for EM4x50 tag
bool detect_4x50_block ( void ) {
em4x50_data_t etd = {
. pwd_given = false ,
. addr_given = true ,
2020-12-20 04:27:03 +08:00
. addresses = ( EM4X50_DEVICE_SERIAL < < 8 ) | EM4X50_DEVICE_SERIAL ,
2020-11-20 06:18:04 +08:00
} ;
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
return ( em4x50_read ( & etd , words ) = = PM3_SUCCESS ) ;
}
2020-06-29 03:35:06 +08:00
2020-11-20 06:18:04 +08:00
int read_em4x50_uid ( void ) {
em4x50_data_t etd = {
. pwd_given = false ,
. addr_given = true ,
. addresses = ( EM4X50_DEVICE_SERIAL < < 8 ) | EM4X50_DEVICE_SERIAL ,
} ;
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
int res = em4x50_read ( & etd , words ) ;
if ( res = = PM3_SUCCESS )
PrintAndLogEx ( INFO , " Serial: " _GREEN_ ( " %s " ) , sprint_hex ( words [ EM4X50_DEVICE_SERIAL ] . byte , 4 ) ) ;
return res ;
2020-06-17 05:25:27 +08:00
}
2020-06-26 20:20:46 +08:00
2020-12-09 19:18:01 +08:00
// envoke reading
// - with given address (option b) (and optional password if address is
// read protected) -> selective read mode
2020-10-28 02:16:54 +08:00
int em4x50_read ( em4x50_data_t * etd , em4x50_word_t * out ) {
2020-07-01 00:50:38 +08:00
2020-06-30 23:59:06 +08:00
em4x50_data_t edata = { . pwd_given = false , . addr_given = false } ;
2020-07-01 00:50:38 +08:00
2020-06-30 23:43:47 +08:00
if ( etd ! = NULL ) {
edata = * etd ;
}
2020-06-29 03:35:06 +08:00
2020-06-30 23:43:47 +08:00
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_READ , ( uint8_t * ) & edata , sizeof ( edata ) ) ;
2020-06-26 20:20:46 +08:00
2020-06-30 23:43:47 +08:00
PacketResponseNG resp ;
2020-10-13 20:00:03 +08:00
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_READ , & resp , TIMEOUT ) ) {
2020-09-06 05:57:06 +08:00
PrintAndLogEx ( WARNING , " (em4x50) timeout while waiting for reply. " ) ;
2020-06-30 23:43:47 +08:00
return PM3_ETIMEOUT ;
}
2020-07-01 00:50:38 +08:00
2020-11-20 06:18:04 +08:00
if ( resp . status ! = PM3_SUCCESS )
2020-06-30 23:43:47 +08:00
return PM3_ESOFT ;
2020-07-01 00:50:38 +08:00
2020-06-30 23:43:47 +08:00
uint8_t * data = resp . data . asBytes ;
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
2020-10-28 02:16:54 +08:00
prepare_result ( data , etd - > addresses & 0xFF , ( etd - > addresses > > 8 ) & 0xFF , words ) ;
2020-06-26 20:20:46 +08:00
2020-11-20 06:18:04 +08:00
if ( out ! = NULL )
2020-06-30 23:43:47 +08:00
memcpy ( out , & words , sizeof ( em4x50_word_t ) * EM4X50_NO_WORDS ) ;
2020-07-01 00:50:38 +08:00
2020-10-28 02:16:54 +08:00
print_result ( words , etd - > addresses & 0xFF , ( etd - > addresses > > 8 ) & 0xFF ) ;
2020-09-05 19:25:57 +08:00
2020-06-30 23:43:47 +08:00
return PM3_SUCCESS ;
2020-06-26 20:20:46 +08:00
}
2020-06-30 23:43:47 +08:00
int CmdEM4x50Read ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 read " ,
2020-11-13 07:50:49 +08:00
" Reads single EM4x50 block/word. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 rdbl -b 3 \n "
" lf em 4x50 rdbl -b 32 -p 12345678 -> reads block 32 with pwd 0x12345678 \n "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-04 04:01:39 +08:00
arg_int1 ( " b " , " block " , " <dec> " , " block/word address " ) ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " p " , " pwd " , " <hex> " , " password, 4 hex bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-06-26 20:20:46 +08:00
2020-11-02 05:51:32 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-12 21:46:40 +08:00
2020-12-09 19:18:01 +08:00
int addr = arg_get_int_def ( ctx , 1 , 0 ) ;
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 2 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
2020-11-02 05:51:32 +08:00
if ( addr < = 0 | | addr > = EM4X50_NO_WORDS ) {
return PM3_EINVARG ;
2020-12-12 21:46:40 +08:00
}
2020-10-22 06:42:18 +08:00
2020-12-09 19:18:01 +08:00
em4x50_data_t etd ;
// init
memset ( & etd , 0x00 , sizeof ( em4x50_data_t ) ) ;
etd . addr_given = false ;
etd . pwd_given = false ;
etd . addresses = ( addr < < 8 ) | addr ;
etd . addr_given = true ;
if ( pwd_len ) {
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
2020-11-02 05:51:32 +08:00
return PM3_EINVARG ;
2020-11-20 06:18:04 +08:00
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
etd . pwd_given = true ;
}
2020-11-02 05:51:32 +08:00
}
2020-11-20 06:18:04 +08:00
return em4x50_read ( & etd , NULL ) ;
2020-09-05 19:25:57 +08:00
}
2020-09-28 05:22:51 +08:00
2020-12-09 19:18:01 +08:00
// envoke reading of a EM4x50 tag which has to be on the antenna because
// decoding is done by the device (not on client side)
2020-11-20 06:18:04 +08:00
int CmdEM4x50Info ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 info " ,
2020-11-20 06:18:04 +08:00
" Tag information EM4x50. " ,
2020-12-07 06:14:41 +08:00
" lf em 4x50 info \n "
2020-12-20 05:00:48 +08:00
" lf em 4x50 info -v -> show data section \n "
2020-12-09 19:18:01 +08:00
" lf em 4x50 info -p 12345678 -> uses pwd 0x12345678 \n "
2020-11-02 05:51:32 +08:00
) ;
2020-09-28 05:39:04 +08:00
2020-11-02 05:51:32 +08:00
void * argtable [ ] = {
arg_param_begin ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " p " , " pwd " , " <hex> " , " password, 4 hex bytes, lsb " ) ,
2020-12-20 05:00:48 +08:00
arg_lit0 ( " v " , " verbose " , " additional output of data section " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-10-22 06:42:18 +08:00
2020-11-02 05:51:32 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int pwd_len = 0 ;
2020-12-12 21:46:40 +08:00
uint8_t pwd [ 4 ] = { 0x0 } ;
2020-12-09 19:18:01 +08:00
CLIGetHexWithReturn ( ctx , 1 , pwd , & pwd_len ) ;
2020-12-20 05:00:48 +08:00
bool verb = arg_get_lit ( ctx , 2 ) ;
2020-12-09 19:18:01 +08:00
CLIParserFree ( ctx ) ;
2020-12-12 21:46:40 +08:00
em4x50_data_t etd = { . pwd_given = false } ;
2020-12-09 19:18:01 +08:00
if ( pwd_len ) {
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
etd . pwd_given = true ;
}
}
2020-09-28 05:39:04 +08:00
clearCommandBuffer ( ) ;
2020-11-20 06:18:04 +08:00
SendCommandNG ( CMD_LF_EM4X50_INFO , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
PacketResponseNG resp ;
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_INFO , & resp , TIMEOUT ) ) {
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
}
2020-12-12 21:46:40 +08:00
if ( resp . status = = PM3_SUCCESS )
2020-12-20 05:00:48 +08:00
print_info_result ( resp . data . asBytes , verb ) ;
2020-09-28 05:39:04 +08:00
else
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( FAILED , " Reading tag " _RED_ ( " failed " ) ) ;
2020-09-28 05:39:04 +08:00
2020-12-09 19:18:01 +08:00
return resp . status ;
2020-09-28 05:39:04 +08:00
}
2020-10-06 04:59:08 +08:00
2020-11-30 06:59:36 +08:00
int CmdEM4x50Reader ( const char * Cmd ) {
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 reader " ,
2020-11-30 06:59:36 +08:00
" Shows standard read data of EM4x50 tag. " ,
2020-12-07 06:14:41 +08:00
" lf em 4x50 reader \n "
" lf em 4x50 reader -@ -> continuous reader mode "
2020-11-30 06:59:36 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_lit0 ( " @ " , NULL , " optional - continuous reader mode " ) ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
bool cm = arg_get_lit ( ctx , 1 ) ;
CLIParserFree ( ctx ) ;
// start
do {
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-11-30 06:59:36 +08:00
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_READER , 0 , 0 ) ;
2020-12-01 03:31:02 +08:00
WaitForResponseTimeoutW ( CMD_LF_EM4X50_READER , & resp , - 1 , false ) ;
2020-11-30 06:59:36 +08:00
2020-12-09 19:18:01 +08:00
// iceman, misuse of return status code.
int now = resp . status ;
2020-11-30 06:59:36 +08:00
if ( now > 0 ) {
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
prepare_result ( resp . data . asBytes , 0 , now - 1 , words ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " word (msb) | word (lsb) " ) ;
PrintAndLogEx ( INFO , " -------------+------------- " ) ;
for ( int i = 0 ; i < now ; i + + ) {
2020-12-09 19:18:01 +08:00
char r [ 30 ] ;
memset ( r , 0 , sizeof ( r ) ) ;
for ( int j = 3 ; j > = 0 ; j - - ) {
2020-11-30 06:59:36 +08:00
sprintf ( r + strlen ( r ) , " %02x " , reflect8 ( words [ i ] . byte [ j ] ) ) ;
2020-12-09 19:18:01 +08:00
}
2020-11-30 06:59:36 +08:00
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( INFO , _GREEN_ ( " %s " ) " | %s " , sprint_hex ( words [ i ] . byte , 4 ) , r ) ;
2020-11-30 06:59:36 +08:00
}
2020-12-12 21:46:40 +08:00
2020-11-30 06:59:36 +08:00
PrintAndLogEx ( INFO , " -------------+------------- " ) ;
}
} while ( cm & & ! kbd_enter_pressed ( ) ) ;
return PM3_SUCCESS ;
}
2020-11-20 06:18:04 +08:00
int CmdEM4x50Dump ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 dump " ,
2020-11-20 06:18:04 +08:00
" Reads all blocks/words from EM4x50 tag and saves dump in bin/eml/json format. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 dump \n "
" lf em 4x50 dump -f mydump.eml \n "
2020-12-07 06:14:41 +08:00
" lf em 4x50 dump -p 12345678 \n "
2020-12-09 19:18:01 +08:00
" lf em 4x50 dump -f mydump.eml -p 12345678 "
2020-11-20 06:18:04 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_str0 ( " f " , " filename " , " <filename> " , " dump filename (bin/eml/json) " ) ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " p " , " pwd " , " <hex> " , " password, 4 hex bytes, lsb " ) ,
2020-11-20 06:18:04 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int fnLen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnLen ) ;
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 2 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
em4x50_data_t etd = { . pwd_given = false } ;
if ( pwd_len ) {
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes " ) ;
CLIParserFree ( ctx ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
etd . pwd_given = true ;
}
}
PrintAndLogEx ( INFO , " Reading EM4x50 tag " ) ;
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_INFO , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
PacketResponseNG resp ;
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_INFO , & resp , TIMEOUT ) ) {
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
}
2020-12-09 19:18:01 +08:00
if ( resp . status ! = PM3_SUCCESS ) {
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( FAILED , " Reading tag " _RED_ ( " failed " ) ) ;
return PM3_ESOFT ;
}
// structured format
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
prepare_result ( resp . data . asBytes , 0 , EM4X50_NO_WORDS - 1 , words ) ;
// result output
PrintAndLogEx ( INFO , _YELLOW_ ( " EM4x50 data: " ) ) ;
print_result ( words , 0 , EM4X50_NO_WORDS - 1 ) ;
// user supplied filename?
if ( fnLen = = 0 ) {
PrintAndLogEx ( INFO , " Using UID as filename " ) ;
2020-12-09 19:18:01 +08:00
char * fptr = filename ;
2020-11-20 06:18:04 +08:00
fptr + = sprintf ( fptr , " lf-4x50- " ) ;
FillFileNameByUID ( fptr , words [ EM4X50_DEVICE_ID ] . byte , " -dump " , 4 ) ;
}
2020-12-09 19:18:01 +08:00
uint8_t data [ DUMP_FILESIZE ] = { 0 } ;
for ( int i = 0 ; i < EM4X50_NO_WORDS ; i + + ) {
2020-11-20 06:18:04 +08:00
memcpy ( data + ( i * 4 ) , words [ i ] . byte , 4 ) ;
2020-12-09 19:18:01 +08:00
}
2020-11-20 06:18:04 +08:00
saveFile ( filename , " .bin " , data , sizeof ( data ) ) ;
2020-12-09 19:18:01 +08:00
saveFileEML ( filename , data , sizeof ( data ) , 4 ) ;
2020-11-20 06:18:04 +08:00
saveFileJSON ( filename , jsfEM4x50 , data , sizeof ( data ) , NULL ) ;
return PM3_SUCCESS ;
}
2020-12-09 19:18:01 +08:00
// envoke writing a single word (32 bit) to a EM4x50 tag
2020-11-20 06:18:04 +08:00
int CmdEM4x50Write ( const char * Cmd ) {
CLIParserContext * ctx ;
2020-12-09 19:18:01 +08:00
CLIParserInit ( & ctx , " lf em 4x50 wrbl " ,
2020-11-20 06:18:04 +08:00
" Writes single block/word to EM4x50 tag. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 wrbl -b 3 -d 4f22e7ff \n "
" lf em 4x50 wrbl -b 3 -d 4f22e7ff -p 12345678 \n "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-04 04:01:39 +08:00
arg_int1 ( " b " , " block " , " <dec> " , " block/word address, dec " ) ,
arg_str1 ( " d " , " data " , " <hex> " , " data, 4 bytes, lsb " ) ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " p " , " pwd " , " <hex> " , " password, 4 bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-12-12 21:46:40 +08:00
2020-11-02 05:51:32 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int addr = arg_get_int_def ( ctx , 1 , 0 ) ;
2020-12-12 21:46:40 +08:00
2020-12-09 19:18:01 +08:00
int word_len = 0 ;
uint8_t word [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 2 , word , & word_len ) ;
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 3 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
if ( addr < = 0 | | addr > = EM4X50_NO_WORDS ) {
PrintAndLogEx ( FAILED , " address has to be within range [0, 31] " ) ;
2020-11-02 05:51:32 +08:00
return PM3_EINVARG ;
2020-12-12 21:46:40 +08:00
}
2020-12-09 19:18:01 +08:00
if ( word_len ! = 4 ) {
PrintAndLogEx ( FAILED , " word/data length must be 4 bytes instead of %d " , word_len ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
2020-11-02 05:51:32 +08:00
}
2020-12-09 19:18:01 +08:00
2020-12-12 21:46:40 +08:00
em4x50_data_t etd = { . pwd_given = false } ;
2020-12-09 19:18:01 +08:00
if ( pwd_len ) {
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
2020-11-02 05:51:32 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-02 05:51:32 +08:00
etd . pwd_given = true ;
}
2020-10-25 23:39:10 +08:00
}
2020-12-09 19:18:01 +08:00
etd . addresses = ( addr < < 8 ) | addr ;
etd . addr_given = true ;
etd . word = BYTES2UINT32 ( word ) ;
2020-10-25 23:39:10 +08:00
clearCommandBuffer ( ) ;
2020-11-20 06:18:04 +08:00
SendCommandNG ( CMD_LF_EM4X50_WRITE , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
2020-10-25 23:39:10 +08:00
PacketResponseNG resp ;
2020-11-20 06:18:04 +08:00
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_WRITE , & resp , TIMEOUT ) ) {
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
2020-10-25 23:39:10 +08:00
return PM3_ETIMEOUT ;
}
2020-12-09 19:18:01 +08:00
int status = resp . status ;
2020-11-20 06:18:04 +08:00
if ( status = = PM3_ETEAROFF )
2020-12-09 19:18:01 +08:00
return status ;
2020-10-25 23:39:10 +08:00
2020-11-20 06:18:04 +08:00
if ( status ! = PM3_SUCCESS ) {
PrintAndLogEx ( FAILED , " Writing " _RED_ ( " failed " ) ) ;
2020-10-25 23:39:10 +08:00
return PM3_ESOFT ;
}
2020-11-20 06:18:04 +08:00
// display result of writing operation in structured format
uint8_t * data = resp . data . asBytes ;
em4x50_word_t words [ EM4X50_NO_WORDS ] ;
prepare_result ( data , addr , addr , words ) ;
print_result ( words , addr , addr ) ;
PrintAndLogEx ( SUCCESS , " Successfully wrote to tag " ) ;
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( HINT , " Try ` " _YELLOW_ ( " lf em 4x50 rdbl -a %u " ) " ` - to read your data " , addr ) ;
2020-10-27 05:11:57 +08:00
return PM3_SUCCESS ;
}
2020-12-09 19:18:01 +08:00
// envokes changing the password of EM4x50 tag
2020-11-20 06:18:04 +08:00
int CmdEM4x50WritePwd ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 writepwd " ,
2020-11-20 06:18:04 +08:00
" Writes EM4x50 password. " ,
2020-12-09 19:18:01 +08:00
" lf em 4x50 writepwd -p 4f22e7ff -n 12345678 "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-09 19:18:01 +08:00
arg_str1 ( " p " , " pwd " , " <hex> " , " password, 4 hex bytes, lsb " ) ,
arg_str1 ( " n " , " new " , " <hex> " , " new password, 4 hex bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-12-12 21:46:40 +08:00
2020-11-02 05:51:32 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 1 , pwd , & pwd_len ) ;
int npwd_len = 0 ;
uint8_t npwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 2 , npwd , & npwd_len ) ;
CLIParserFree ( ctx ) ;
2020-12-12 21:46:40 +08:00
em4x50_data_t etd ;
2020-12-09 19:18:01 +08:00
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
}
2020-12-09 19:18:01 +08:00
if ( npwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , npwd_len ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password2 = BYTES2UINT32 ( npwd ) ;
2020-11-20 06:18:04 +08:00
}
2020-10-27 07:53:50 +08:00
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-11-20 06:18:04 +08:00
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_WRITEPWD , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
2020-11-10 07:39:48 +08:00
2020-11-20 06:18:04 +08:00
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_WRITEPWD , & resp , TIMEOUT ) ) {
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
2020-10-27 07:53:50 +08:00
}
2020-10-27 05:11:57 +08:00
2020-12-09 19:18:01 +08:00
if ( resp . status = = PM3_ETEAROFF )
2020-10-27 05:11:57 +08:00
return PM3_SUCCESS ;
2020-11-20 06:18:04 +08:00
2020-12-09 19:18:01 +08:00
if ( resp . status ! = PM3_SUCCESS ) {
PrintAndLogEx ( FAILED , " Writing password ( " _RED_ ( " failed " ) " ) " ) ;
2020-11-20 06:18:04 +08:00
return PM3_EFAILED ;
2020-11-02 05:51:32 +08:00
}
2020-10-27 05:11:57 +08:00
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( SUCCESS , " Writing new password %s (%s) "
2020-12-12 21:46:40 +08:00
, sprint_hex_inrow ( npwd , sizeof ( npwd ) )
, _GREEN_ ( " ok " )
) ;
2020-10-25 23:39:10 +08:00
return PM3_SUCCESS ;
}
2020-10-28 01:18:02 +08:00
2020-12-09 19:18:01 +08:00
// fills EM4x50 tag with zeros including password
2020-11-20 06:18:04 +08:00
int CmdEM4x50Wipe ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 wipe " ,
2020-12-09 19:18:01 +08:00
" Wipes EM4x50 tag by filling it with zeros, including the new password \n "
" Must give a password. " ,
" lf em 4x50 wipe -p 12345678 "
2020-11-02 05:51:32 +08:00
) ;
2020-10-28 01:18:02 +08:00
2020-11-02 05:51:32 +08:00
void * argtable [ ] = {
arg_param_begin ,
2020-12-04 04:01:39 +08:00
arg_str1 ( " p " , " passsword " , " <hex> " , " password, 4 bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-10-28 01:18:02 +08:00
2020-12-12 21:46:40 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 1 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
CLIParserFree ( ctx ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
}
2020-10-28 01:18:02 +08:00
2020-12-09 19:18:01 +08:00
em4x50_data_t etd = { . pwd_given = false , . word = 0x0 , . password2 = 0x0 } ;
etd . password1 = BYTES2UINT32 ( pwd ) ;
etd . pwd_given = true ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
// clear password
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-10-28 01:18:02 +08:00
clearCommandBuffer ( ) ;
2020-11-20 06:18:04 +08:00
SendCommandNG ( CMD_LF_EM4X50_WRITEPWD , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_WRITEPWD , & resp , TIMEOUT ) ) {
2020-10-28 01:18:02 +08:00
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
}
2020-11-20 06:18:04 +08:00
if ( resp . status = = PM3_SUCCESS ) {
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( SUCCESS , " Resetting password to 00000000 ( " _GREEN_ ( " ok " ) " ) " ) ;
2020-11-20 06:18:04 +08:00
} else {
PrintAndLogEx ( FAILED , " Resetting password " _RED_ ( " failed " ) ) ;
return PM3_ESOFT ;
}
// from now on new password 0x0
etd . password1 = 0x0 ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
// clear data (words 1 to 31)
for ( int i = 1 ; i < EM4X50_DEVICE_SERIAL ; i + + ) {
2020-10-28 01:18:02 +08:00
2020-11-20 06:18:04 +08:00
// no login necessary for blocks 3 to 31
etd . pwd_given = ( i < = EM4X50_CONTROL ) ;
2020-12-12 21:46:40 +08:00
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INPLACE , " Wiping block %i " , i ) ;
2020-10-28 01:18:02 +08:00
2020-11-20 06:18:04 +08:00
etd . addresses = i < < 8 | i ;
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_WRITE , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_WRITE , & resp , TIMEOUT ) ) {
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
2020-10-28 01:18:02 +08:00
}
2020-12-12 21:46:40 +08:00
if ( resp . status ! = PM3_SUCCESS ) {
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( FAILED , " Wiping data " _RED_ ( " failed " ) ) ;
return PM3_ESOFT ;
}
2020-10-28 01:18:02 +08:00
}
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " Done " ) ;
return PM3_SUCCESS ;
2020-10-28 01:18:02 +08:00
}
2020-10-30 07:41:45 +08:00
2020-11-20 06:18:04 +08:00
int CmdEM4x50Restore ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 restore " ,
2020-12-09 19:18:01 +08:00
" Restores data from dumpfile onto a Em4x50 tag. \n "
" if used with -u, the filetemplate `lf-4x50-UID-dump.bin` is used as filename " ,
" lf em 4x50 restore -u 1b5aff5c -> uses lf-4x50-1B5AFF5C-dump.bin \n "
" lf em 4x50 restore -f mydump.eml \n "
2020-12-07 06:14:41 +08:00
" lf em 4x50 restore -u 1b5aff5c -p 12345678 \n "
" lf em 4x50 restore -f mydump.eml -p 12345678 \n "
2020-11-02 05:51:32 +08:00
) ;
2020-10-30 07:41:45 +08:00
2020-11-02 05:51:32 +08:00
void * argtable [ ] = {
arg_param_begin ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " u " , " uid " , " <hex> " , " uid, 4 hex bytes, msb " ) ,
2020-11-20 06:18:04 +08:00
arg_str0 ( " f " , " filename " , " <filename> " , " dump filename (bin/eml/json) " ) ,
2020-12-09 19:18:01 +08:00
arg_str0 ( " p " , " pwd " , " <hex> " , " password, 4 hex bytes, lsb " ) ,
2020-11-02 05:51:32 +08:00
arg_param_end
} ;
2020-10-30 07:41:45 +08:00
2020-12-12 21:46:40 +08:00
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-09 19:18:01 +08:00
int uidLen = 0 ;
uint8_t uid [ 4 ] = { 0x0 } ;
2020-11-20 06:18:04 +08:00
CLIGetHexWithReturn ( ctx , 1 , uid , & uidLen ) ;
2020-12-09 19:18:01 +08:00
int fnlen = 0 ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 2 ) , ( uint8_t * ) filename , FILE_PATH_SIZE , & fnlen ) ;
int pwd_len = 0 ;
uint8_t pwd [ 4 ] = { 0x0 } ;
CLIGetHexWithReturn ( ctx , 3 , pwd , & pwd_len ) ;
CLIParserFree ( ctx ) ;
if ( ( uidLen & & fnlen ) | | ( ! uidLen & & ! fnlen ) ) {
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( FAILED , " either use option 'u' or option 'f' " ) ;
return PM3_EINVARG ;
}
2020-12-09 19:18:01 +08:00
int startblock = EM4X50_CONTROL + 1 ;
em4x50_data_t etd = { . pwd_given = false } ;
if ( pwd_len ) {
if ( pwd_len ! = 4 ) {
PrintAndLogEx ( FAILED , " password length must be 4 bytes instead of %d " , pwd_len ) ;
2020-11-20 06:18:04 +08:00
return PM3_EINVARG ;
} else {
2020-12-04 03:40:58 +08:00
etd . password1 = BYTES2UINT32 ( pwd ) ;
2020-11-20 06:18:04 +08:00
etd . pwd_given = true ;
2020-12-07 02:26:20 +08:00
// if password is available protection and control word can be restored
startblock = EM4X50_PROTECTION ;
2020-11-20 06:18:04 +08:00
}
}
2020-12-09 19:18:01 +08:00
if ( uidLen ) {
PrintAndLogEx ( INFO , " Using UID as filename " ) ;
char * fptr = filename ;
fptr + = sprintf ( fptr , " lf-4x50- " ) ;
FillFileNameByUID ( fptr , uid , " -dump " , 4 ) ;
}
2020-10-30 07:41:45 +08:00
2020-11-20 06:18:04 +08:00
PrintAndLogEx ( INFO , " Restoring " _YELLOW_ ( " %s " ) " to card " , filename ) ;
2020-10-30 07:41:45 +08:00
// read data from dump file; file type has to be "bin", "eml" or "json"
2020-12-09 19:18:01 +08:00
uint8_t data [ DUMP_FILESIZE ] = { 0x0 } ;
size_t bytes_read = 0 ;
2020-11-20 06:18:04 +08:00
if ( em4x50_load_file ( filename , data , DUMP_FILESIZE , & bytes_read ) ! = PM3_SUCCESS )
2020-10-30 07:41:45 +08:00
return PM3_EFILE ;
2020-12-07 02:26:20 +08:00
for ( int i = startblock ; i < EM4X50_DEVICE_SERIAL ; i + + ) {
2020-10-30 07:41:45 +08:00
2020-12-04 05:00:52 +08:00
PrintAndLogEx ( INPLACE , " Restoring block %i " , i ) ;
etd . addresses = i < < 8 | i ;
etd . word = reflect32 ( BYTES2UINT32 ( ( data + 4 * i ) ) ) ;
2020-12-12 21:46:40 +08:00
2020-12-09 19:18:01 +08:00
PacketResponseNG resp ;
2020-12-04 05:00:52 +08:00
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_LF_EM4X50_WRITE , ( uint8_t * ) & etd , sizeof ( etd ) ) ;
if ( ! WaitForResponseTimeout ( CMD_LF_EM4X50_WRITE , & resp , TIMEOUT ) ) {
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-12-04 05:00:52 +08:00
PrintAndLogEx ( WARNING , " Timeout while waiting for reply. " ) ;
return PM3_ETIMEOUT ;
}
2020-12-09 19:18:01 +08:00
if ( resp . status ! = PM3_SUCCESS ) {
2020-12-04 05:00:52 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( FAILED , " Restoring data " _RED_ ( " failed " ) ) ;
return PM3_ESOFT ;
}
2020-10-30 07:41:45 +08:00
}
2020-11-20 06:18:04 +08:00
2020-12-12 21:46:40 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2020-12-04 05:00:52 +08:00
PrintAndLogEx ( INFO , " Done " ) ;
return PM3_SUCCESS ;
2020-11-02 05:51:32 +08:00
}
2020-11-20 06:18:04 +08:00
int CmdEM4x50Sim ( const char * Cmd ) {
2020-11-02 05:51:32 +08:00
CLIParserContext * ctx ;
2020-12-07 06:14:41 +08:00
CLIParserInit ( & ctx , " lf em 4x50 sim " ,
2020-12-09 19:18:01 +08:00
" Simulates a EM4x50 tag. \n "
" Upload using `lf em 4x50 eload` " ,
" lf em 4x50 sim "
2020-11-02 05:51:32 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
CLIParserFree ( ctx ) ;
2020-11-11 08:11:09 +08:00
2020-12-09 19:18:01 +08:00
PrintAndLogEx ( INFO , " Simulating data from emulator memory " ) ;
2020-11-20 06:18:04 +08:00
clearCommandBuffer ( ) ;
2020-12-09 19:18:01 +08:00
SendCommandNG ( CMD_LF_EM4X50_SIM , NULL , 0 ) ;
PacketResponseNG resp ;
2020-11-20 06:18:04 +08:00
WaitForResponse ( CMD_LF_EM4X50_SIM , & resp ) ;
2020-12-09 19:18:01 +08:00
if ( resp . status = = PM3_SUCCESS )
2020-11-21 05:03:19 +08:00
PrintAndLogEx ( INFO , " Done " ) ;
else
2020-12-06 08:53:43 +08:00
PrintAndLogEx ( FAILED , " No valid em4x50 data in memory. " ) ;
2020-11-02 05:51:32 +08:00
2020-11-21 05:03:19 +08:00
return resp . status ;
2020-10-30 07:41:45 +08:00
}
2020-12-07 03:40:46 +08:00
2020-12-28 05:22:44 +08:00
int CmdEM4x50Test ( const char * Cmd ) {
CLIParserContext * ctx ;
CLIParserInit ( & ctx , " lf em 4x50 test " ,
" perform EM4x50 tests. " ,
2020-12-30 00:40:18 +08:00
" lf em 4x50 test --field on -> reader field on \n "
" lf em 4x50 test --field off -> reader field off \n "
" lf em 4x50 test --check -> check on/off status of reader field \n "
2021-01-05 08:11:46 +08:00
" lf em 4x50 test --cycles 100 -> measure time of 100 field cycles \n "
" lf em 4x50 test --reset -> intitiate reset command \n "
2020-12-28 05:22:44 +08:00
) ;
void * argtable [ ] = {
arg_param_begin ,
2020-12-30 00:40:18 +08:00
arg_str0 ( NULL , " field " , " on/off " , " field on/off " ) ,
arg_lit0 ( NULL , " check " , " check if field is on or off " ) ,
arg_int0 ( NULL , " cycles " , " <dec> " , " number of field cycles " ) ,
2021-01-05 08:11:46 +08:00
arg_lit0 ( NULL , " reset " , " initiates a manual reset command " ) ,
2020-12-28 05:22:44 +08:00
arg_param_end
} ;
CLIExecWithReturn ( ctx , Cmd , argtable , true ) ;
2020-12-30 00:40:18 +08:00
// option: field
int slen = 0 ;
char format [ 3 ] = { 0 } ;
CLIParamStrToBuf ( arg_get_str ( ctx , 1 ) , ( uint8_t * ) format , sizeof ( format ) , & slen ) ;
em4x50_test_t ett = { . field = - 1 } ;
if ( slen ! = 0 ) {
if ( strcmp ( format , " on " ) = = 0 ) {
ett . field = 1 ;
} else if ( strcmp ( format , " off " ) = = 0 ) {
ett . field = 0 ;
} else {
PrintAndLogEx ( INFO , " Unknown option for --field: %s " , format ) ;
return PM3_ESOFT ;
}
}
// option: check_field
ett . check_field = arg_get_lit ( ctx , 2 ) ;
// option: cycles
ett . cycles = arg_get_int_def ( ctx , 3 , 0 ) ;
2021-01-05 08:11:46 +08:00
// option: reset
ett . reset = arg_get_lit ( ctx , 4 ) ;
2020-12-28 05:22:44 +08:00
CLIParserFree ( ctx ) ;
// start
clearCommandBuffer ( ) ;
PacketResponseNG resp ;
SendCommandNG ( CMD_LF_EM4X50_TEST , ( uint8_t * ) & ett , sizeof ( ett ) ) ;
WaitForResponse ( CMD_LF_EM4X50_TEST , & resp ) ;
// print response
if ( resp . status = = 1 ) {
2020-12-30 00:40:18 +08:00
if ( ett . field = = 1 )
PrintAndLogEx ( SUCCESS , " Field switched " _GREEN_ ( " on " ) ) ;
if ( ett . check_field = = 1 )
PrintAndLogEx ( SUCCESS , " Field status evaluated " ) ;
2021-01-05 08:11:46 +08:00
if ( ett . reset = = 1 )
PrintAndLogEx ( SUCCESS , " reset command " _GREEN_ ( " ok " ) ) ;
2020-12-28 05:22:44 +08:00
} else if ( resp . status = = 0 ) {
2021-01-05 08:11:46 +08:00
if ( ett . field = = 1 )
PrintAndLogEx ( SUCCESS , " Field switched " _GREEN_ ( " off " ) ) ;
if ( ett . reset = = 1 )
PrintAndLogEx ( SUCCESS , " reset command " _GREEN_ ( " failed " ) ) ;
2020-12-30 00:40:18 +08:00
} else if ( resp . status = = - 1 ) {
PrintAndLogEx ( INFO , " Nothing done " ) ;
2020-12-28 05:22:44 +08:00
} else {
PrintAndLogEx ( FAILED , " Test call " _RED_ ( " failed " ) ) ;
}
return resp . status ;
}
2020-12-04 07:11:57 +08:00
static command_t CommandTable [ ] = {
2020-12-07 06:08:43 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2020-12-09 19:18:01 +08:00
{ " brute " , CmdEM4x50Brute , IfPm3EM4x50 , " guess password of EM4x50 " } ,
{ " chk " , CmdEM4x50Chk , IfPm3EM4x50 , " check passwords from dictionary " } ,
2020-12-07 06:00:26 +08:00
{ " dump " , CmdEM4x50Dump , IfPm3EM4x50 , " dump EM4x50 tag " } ,
{ " info " , CmdEM4x50Info , IfPm3EM4x50 , " tag information EM4x50 " } ,
2020-12-09 19:18:01 +08:00
{ " login " , CmdEM4x50Login , IfPm3EM4x50 , " login into EM4x50 " } ,
{ " rdbl " , CmdEM4x50Read , IfPm3EM4x50 , " read word data from EM4x50 " } ,
{ " wrbl " , CmdEM4x50Write , IfPm3EM4x50 , " write word data to EM4x50 " } ,
2020-12-12 21:46:40 +08:00
{ " writepwd " , CmdEM4x50WritePwd , IfPm3EM4x50 , " change password of EM4x50 " } ,
2020-12-07 06:00:26 +08:00
{ " wipe " , CmdEM4x50Wipe , IfPm3EM4x50 , " wipe EM4x50 tag " } ,
2020-12-09 19:18:01 +08:00
{ " reader " , CmdEM4x50Reader , IfPm3EM4x50 , " show standard read mode data of EM4x50 " } ,
2020-12-12 21:46:40 +08:00
{ " restore " , CmdEM4x50Restore , IfPm3EM4x50 , " restore EM4x50 dump to tag " } ,
2020-12-07 06:00:26 +08:00
{ " sim " , CmdEM4x50Sim , IfPm3EM4x50 , " simulate EM4x50 tag " } ,
2020-12-12 02:55:15 +08:00
{ " eload " , CmdEM4x50ELoad , IfPm3EM4x50 , " upload dump of EM4x50 to emulator memory " } ,
{ " esave " , CmdEM4x50ESave , IfPm3EM4x50 , " save emulator memory to file " } ,
{ " eview " , CmdEM4x50EView , IfPm3EM4x50 , " view EM4x50 content in emulator memory " } ,
2020-12-28 05:22:44 +08:00
{ " test " , CmdEM4x50Test , IfPm3EM4x50 , " perform EM4x50 tests " } ,
2020-12-04 07:11:57 +08:00
{ NULL , NULL , NULL , NULL }
} ;
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
return PM3_SUCCESS ;
}
int CmdLFEM4X50 ( const char * Cmd ) {
clearCommandBuffer ( ) ;
return CmdsParse ( CommandTable , Cmd ) ;
}
2020-12-28 05:22:44 +08:00