2020-01-31 00:05:59 +08:00
//-----------------------------------------------------------------------------
// Christian Herrmann, 2020
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for HID collector aka IceHID by Iceman
//-----------------------------------------------------------------------------
2020-03-14 01:18:05 +08:00
# include <inttypes.h>
2020-01-31 00:05:59 +08:00
# include "standalone.h" // standalone definitions
# include "proxmark3_arm.h"
# include "appmain.h"
# include "lfops.h"
2020-02-04 04:39:44 +08:00
# include "lfsampling.h"
# include "BigBuf.h"
2020-01-31 00:05:59 +08:00
# include "fpgaloader.h"
# include "util.h"
# include "dbprint.h"
# include "printf.h"
# include "spiffs.h"
# include "ticks.h"
2020-02-04 04:39:44 +08:00
# include "lfdemod.h"
2020-01-31 00:05:59 +08:00
/*
* ` lf_hidcollect ` sniffs after LF HID credentials , and stores them in internal
* flash . It requires RDV4 hardware ( for flash and battery ) .
*
* On entering stand - alone mode , this module will start reading / record HID credentials .
2020-02-04 04:39:44 +08:00
* Every found / collected credential will be written / appended to the logfile in flash
* as a text string .
2020-01-31 00:05:59 +08:00
*
* LEDs :
* - LED A : reading / record
* - LED B : writing to flash
* - LED C : unmounting / sync ' ing flash ( normally < 100 ms )
*
* To retrieve log file from flash :
*
* 1. mem spiffs dump o lf_hidcollect . log f lf_hidcollect . log
2020-03-30 21:12:06 +08:00
* Copies log file from flash to your client .
2020-01-31 00:05:59 +08:00
*
* 2. exit the Proxmark3 client
*
* 3. more lf_hidcollect . log
*
* This module emits debug strings during normal operation - - so try it out in
* the lab connected to PM3 client before taking it into the field .
*
2020-02-04 04:39:44 +08:00
* To delete the log file from flash :
*
2020-01-31 00:05:59 +08:00
* 1. mem spiffs remove lf_hidcollect . log
*/
# define LF_HIDCOLLECT_LOGFILE "lf_hidcollect.log"
2020-02-04 04:39:44 +08:00
2020-05-11 00:04:50 +08:00
static void DownloadLogInstructions ( void ) {
2020-01-31 00:05:59 +08:00
Dbprintf ( " " ) ;
Dbprintf ( " [=] To get the logfile from flash and display it: " ) ;
2020-04-22 08:22:55 +08:00
Dbprintf ( " [=] " _YELLOW_ ( " 1. " ) " mem spiffs dump o " LF_HIDCOLLECT_LOGFILE " f " LF_HIDCOLLECT_LOGFILE ) ;
Dbprintf ( " [=] " _YELLOW_ ( " 2. " ) " exit proxmark3 client " ) ;
Dbprintf ( " [=] " _YELLOW_ ( " 3. " ) " cat " LF_HIDCOLLECT_LOGFILE ) ;
2020-02-04 04:39:44 +08:00
}
bool log_exists ;
2020-05-11 00:04:50 +08:00
static void append ( uint8_t * entry , size_t entry_len ) {
2020-02-04 04:39:44 +08:00
LED_B_ON ( ) ;
if ( log_exists = = false ) {
rdv40_spiffs_write ( LF_HIDCOLLECT_LOGFILE , entry , entry_len , RDV40_SPIFFS_SAFETY_SAFE ) ;
log_exists = true ;
} else {
rdv40_spiffs_append ( LF_HIDCOLLECT_LOGFILE , entry , entry_len , RDV40_SPIFFS_SAFETY_SAFE ) ;
}
LED_B_OFF ( ) ;
}
2020-05-11 00:04:50 +08:00
static uint32_t IceEM410xdemod ( void ) {
2020-02-04 04:39:44 +08:00
uint8_t * dest = BigBuf_get_addr ( ) ;
size_t idx = 0 ;
int clk = 0 , invert = 0 , maxErr = 20 ;
uint32_t hi = 0 ;
uint64_t lo = 0 ;
size_t size = MIN ( 16385 , BigBuf_max_traceLen ( ) ) ;
//askdemod and manchester decode
int errCnt = askdemod ( dest , & size , & clk , & invert , maxErr , 0 , 1 ) ;
WDT_HIT ( ) ;
if ( errCnt > 50 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
errCnt = Em410xDecode ( dest , & size , & idx , & hi , & lo ) ;
if ( errCnt ! = 1 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
2020-02-05 04:57:33 +08:00
uint8_t entry [ 81 ] ;
2020-02-04 04:39:44 +08:00
memset ( entry , 0 , sizeof ( entry ) ) ;
if ( size = = 128 ) {
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " EM XL TAG ID: %06 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " - (%05 " PRIu32 " _%03 " PRIu32 " _%08 " PRIu32 " ) \n " ,
2020-03-09 23:57:13 +08:00
hi ,
( uint32_t ) ( lo > > 32 ) ,
( uint32_t ) lo ,
( uint32_t ) ( lo & 0xFFFF ) ,
( uint32_t ) ( ( lo > > 16LL ) & 0xFF ) ,
( uint32_t ) ( lo & 0xFFFFFF ) ) ;
2020-02-04 04:39:44 +08:00
} else {
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " EM TAG ID: %02 " PRIx32 " %08 " PRIx32 " - (%05 " PRIu32 " _%03 " PRIu32 " _%08 " PRIu32 " ) \n " ,
2020-03-09 23:57:13 +08:00
( uint32_t ) ( lo > > 32 ) ,
( uint32_t ) lo ,
( uint32_t ) ( lo & 0xFFFF ) ,
( uint32_t ) ( ( lo > > 16LL ) & 0xFF ) ,
( uint32_t ) ( lo & 0xFFFFFF ) ) ;
2020-02-04 04:39:44 +08:00
}
2020-03-09 23:57:13 +08:00
append ( entry , strlen ( ( char * ) entry ) ) ;
2020-02-04 04:39:44 +08:00
Dbprintf ( " %s " , entry ) ;
BigBuf_free ( ) ;
return PM3_SUCCESS ;
}
2020-05-11 00:04:50 +08:00
static uint32_t IceAWIDdemod ( void ) {
2020-02-04 04:39:44 +08:00
uint8_t * dest = BigBuf_get_addr ( ) ;
size_t size = MIN ( 12800 , BigBuf_max_traceLen ( ) ) ;
int dummyIdx = 0 ;
//askdemod and manchester decode
int idx = detectAWID ( dest , & size , & dummyIdx ) ;
if ( idx < = 0 | | size ! = 96 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
//get raw ID before removing parities
uint32_t rawLo = bytebits_to_byte ( dest + idx + 64 , 32 ) ;
uint32_t rawHi = bytebits_to_byte ( dest + idx + 32 , 32 ) ;
uint32_t rawHi2 = bytebits_to_byte ( dest + idx , 32 ) ;
size = removeParity ( dest , idx + 8 , 4 , 1 , 88 ) ;
if ( size ! = 66 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
uint8_t entry [ 110 ] ;
memset ( entry , 0 , sizeof ( entry ) ) ;
uint8_t fmtLen = bytebits_to_byte ( dest , 8 ) ;
if ( fmtLen = = 26 ) {
uint8_t fac = bytebits_to_byte ( dest + 9 , 8 ) ;
uint32_t cardnum = bytebits_to_byte ( dest + 17 , 16 ) ;
uint32_t code1 = bytebits_to_byte ( dest + 8 , fmtLen ) ;
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " AWID bit len: %d, FC: %d, Card: % " PRIu32 " - Wiegand: % " PRIx32 " , Raw: %08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " \n " , fmtLen , fac , cardnum , code1 , rawHi2 , rawHi , rawLo ) ;
2020-02-04 04:39:44 +08:00
} else {
uint32_t cardnum = bytebits_to_byte ( dest + 8 + ( fmtLen - 17 ) , 16 ) ;
if ( fmtLen > 32 ) {
uint32_t code1 = bytebits_to_byte ( dest + 8 , fmtLen - 32 ) ;
uint32_t code2 = bytebits_to_byte ( dest + 8 + ( fmtLen - 32 ) , 32 ) ;
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " AWID bit len: %d -unk bit len - Card: % " PRIu32 " - Wiegand: % " PRIx32 " %08 " PRIx32 " , Raw: %08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " \n " , fmtLen , cardnum , code1 , code2 , rawHi2 , rawHi , rawLo ) ;
2020-02-04 04:39:44 +08:00
} else {
uint32_t code1 = bytebits_to_byte ( dest + 8 , fmtLen ) ;
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " AWID bit len: %d -unk bit len - Card: % " PRIu32 " - Wiegand: % " PRIx32 " , Raw: %08 " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " \n " , fmtLen , cardnum , code1 , rawHi2 , rawHi , rawLo ) ;
2020-02-04 04:39:44 +08:00
}
}
2020-03-09 23:57:13 +08:00
append ( entry , strlen ( ( char * ) entry ) ) ;
2020-02-04 04:39:44 +08:00
Dbprintf ( " %s " , entry ) ;
BigBuf_free ( ) ;
return PM3_SUCCESS ;
}
2020-05-11 00:04:50 +08:00
static uint32_t IceIOdemod ( void ) {
2020-02-04 04:39:44 +08:00
int dummyIdx = 0 ;
2020-02-05 00:37:19 +08:00
uint8_t version = 0 , facilitycode = 0 ;
uint16_t number = 0 ;
2020-02-04 04:39:44 +08:00
uint32_t hi = 0 , lo = 0 ;
size_t size = MIN ( 12000 , BigBuf_max_traceLen ( ) ) ;
// uint8_t *dest = BigBuf_malloc(size);
uint8_t * dest = BigBuf_get_addr ( ) ;
//fskdemod and get start index
int idx = detectIOProx ( dest , & size , & dummyIdx ) ;
if ( idx < 0 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
hi = bytebits_to_byte ( dest + idx , 32 ) ;
lo = bytebits_to_byte ( dest + idx + 32 , 32 ) ;
version = bytebits_to_byte ( dest + idx + 27 , 8 ) ; //14,4
facilitycode = bytebits_to_byte ( dest + idx + 18 , 8 ) ;
number = ( bytebits_to_byte ( dest + idx + 36 , 8 ) < < 8 ) | ( bytebits_to_byte ( dest + idx + 45 , 8 ) ) ; //36,9
uint8_t entry [ 64 ] ;
memset ( entry , 0 , sizeof ( entry ) ) ;
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " IO Prox XSF(%02u)%02x:%05u (%08 " PRIx32 " %08 " PRIx32 " ) \n "
2020-03-09 23:57:13 +08:00
, version
, facilitycode
, number
, hi
, lo
) ;
append ( entry , strlen ( ( char * ) entry ) ) ;
2020-02-04 04:39:44 +08:00
Dbprintf ( " %s " , entry ) ;
BigBuf_free ( ) ;
return PM3_SUCCESS ;
}
2020-05-11 00:04:50 +08:00
static uint32_t IceHIDDemod ( void ) {
2020-02-04 04:39:44 +08:00
int dummyIdx = 0 ;
uint32_t hi2 = 0 , hi = 0 , lo = 0 ;
// large enough to catch 2 sequences of largest format
2020-06-22 18:22:52 +08:00
// size_t size = 50 * 128 * 2; // 12800 bytes
size_t size = MIN ( 12800 , BigBuf_max_traceLen ( ) ) ;
2020-02-04 04:39:44 +08:00
//uint8_t *dest = BigBuf_malloc(size);
uint8_t * dest = BigBuf_get_addr ( ) ;
// FSK demodulator
int idx = HIDdemodFSK ( dest , & size , & hi2 , & hi , & lo , & dummyIdx ) ;
if ( idx < 0 ) {
BigBuf_free ( ) ;
return PM3_ESOFT ;
}
if ( ( size = = 96 | | size = = 192 ) ) {
uint8_t entry [ 80 ] ;
memset ( entry , 0 , sizeof ( entry ) ) ;
// go over previously decoded manchester data and decode into usable tag ID
if ( hi2 ! = 0 ) { //extra large HID tags 88/192 bits
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " HID large: % " PRIx32 " %08 " PRIx32 " %08 " PRIx32 " (% " PRIu32 " ) \n " ,
2020-03-09 23:57:13 +08:00
hi2 ,
hi ,
lo ,
( lo > > 1 ) & 0xFFFF
) ;
2020-02-04 04:39:44 +08:00
2020-03-09 23:57:13 +08:00
append ( entry , strlen ( ( char * ) entry ) ) ;
2020-02-05 00:37:19 +08:00
2020-02-04 04:39:44 +08:00
} else { //standard HID tags 44/96 bits
uint8_t bitlen = 0 ;
uint32_t fac = 0 ;
uint32_t cardnum = 0 ;
if ( ( ( hi > > 5 ) & 1 ) = = 1 ) { //if bit 38 is set then < 37 bit format is used
uint32_t lo2 = 0 ;
lo2 = ( ( ( hi & 31 ) < < 12 ) | ( lo > > 20 ) ) ; //get bits 21-37 to check for format len bit
uint8_t idx3 = 1 ;
while ( lo2 > 1 ) { //find last bit set to 1 (format len bit)
lo2 > > = 1 ;
idx3 + + ;
}
bitlen = idx3 + 19 ;
fac = 0 ;
cardnum = 0 ;
if ( bitlen = = 26 ) {
cardnum = ( lo > > 1 ) & 0xFFFF ;
fac = ( lo > > 17 ) & 0xFF ;
}
if ( bitlen = = 37 ) {
cardnum = ( lo > > 1 ) & 0x7FFFF ;
fac = ( ( hi & 0xF ) < < 12 ) | ( lo > > 20 ) ;
}
if ( bitlen = = 34 ) {
cardnum = ( lo > > 1 ) & 0xFFFF ;
fac = ( ( hi & 1 ) < < 15 ) | ( lo > > 17 ) ;
}
if ( bitlen = = 35 ) {
cardnum = ( lo > > 1 ) & 0xFFFFF ;
fac = ( ( hi & 1 ) < < 11 ) | ( lo > > 21 ) ;
}
} else { //if bit 38 is not set then 37 bit format is used
bitlen = 37 ;
cardnum = ( lo > > 1 ) & 0x7FFFF ;
fac = ( ( hi & 0xF ) < < 12 ) | ( lo > > 20 ) ;
}
2020-02-05 00:37:19 +08:00
2020-03-13 20:52:55 +08:00
sprintf ( ( char * ) entry , " HID: % " PRIx32 " %08 " PRIx32 " (% " PRIu32 " ) Format: %d bit FC: % " PRIu32 " Card: % " PRIu32 " \n " ,
2020-03-09 23:57:13 +08:00
hi ,
lo ,
( lo > > 1 ) & 0xFFFF ,
bitlen ,
fac ,
cardnum
) ;
append ( entry , strlen ( ( char * ) entry ) ) ;
2020-02-04 04:39:44 +08:00
}
Dbprintf ( " %s " , entry ) ;
}
BigBuf_free ( ) ;
return PM3_SUCCESS ;
2020-01-31 00:05:59 +08:00
}
void ModInfo ( void ) {
2020-02-05 00:37:19 +08:00
DbpString ( _YELLOW_ ( " LF HID / IOprox / AWID / EM4100 collector mode " ) " - a.k.a IceHID (Iceman) " ) ;
2020-01-31 00:05:59 +08:00
}
2020-05-10 22:59:38 +08:00
void RunMod ( void ) {
2020-01-31 00:05:59 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_LF ) ;
2020-02-04 04:39:44 +08:00
LFSetupFPGAForADC ( LF_DIVISOR_125 , true ) ;
BigBuf_Clear ( ) ;
2020-01-31 00:05:59 +08:00
StandAloneMode ( ) ;
2020-02-04 04:39:44 +08:00
2020-02-05 00:37:19 +08:00
Dbprintf ( _YELLOW_ ( " [=] Standalone mode IceHID started " ) ) ;
2020-02-04 04:39:44 +08:00
2020-01-31 00:05:59 +08:00
rdv40_spiffs_lazy_mount ( ) ;
2020-02-04 04:39:44 +08:00
log_exists = exists_in_spiffs ( LF_HIDCOLLECT_LOGFILE ) ;
2020-01-31 00:05:59 +08:00
// the main loop for your standalone mode
for ( ; ; ) {
WDT_HIT ( ) ;
// exit from IceHID, send a usbcommand.
if ( data_available ( ) ) break ;
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD ( 280 ) ;
if ( button_pressed = = BUTTON_HOLD )
break ;
2020-02-04 04:39:44 +08:00
LED_A_ON ( ) ;
uint32_t res ;
2020-01-31 00:05:59 +08:00
2020-06-22 18:22:52 +08:00
// since we steal 12800 from bigbuffer, no need to sample it.
size_t size = MIN ( 28000 , BigBuf_max_traceLen ( ) ) ;
DoAcquisition_config ( false , size ) ;
2020-02-04 04:39:44 +08:00
res = IceHIDDemod ( ) ;
if ( res = = PM3_SUCCESS ) {
LED_A_OFF ( ) ;
2020-01-31 00:05:59 +08:00
continue ;
2020-02-04 04:39:44 +08:00
}
2020-01-31 00:05:59 +08:00
2020-06-22 18:22:52 +08:00
DoAcquisition_config ( false , size ) ;
2020-02-04 04:39:44 +08:00
res = IceAWIDdemod ( ) ;
if ( res = = PM3_SUCCESS ) {
LED_A_OFF ( ) ;
continue ;
2020-01-31 00:05:59 +08:00
}
2020-06-22 18:22:52 +08:00
DoAcquisition_config ( false , size ) ;
res = IceIOdemod ( ) ;
2020-02-04 04:39:44 +08:00
if ( res = = PM3_SUCCESS ) {
LED_A_OFF ( ) ;
continue ;
}
2020-06-22 18:22:52 +08:00
size = MIN ( 20000 , BigBuf_max_traceLen ( ) ) ;
DoAcquisition_config ( false , size ) ;
res = IceEM410xdemod ( ) ;
2020-02-04 04:39:44 +08:00
if ( res = = PM3_SUCCESS ) {
LED_A_OFF ( ) ;
continue ;
}
2020-01-31 00:05:59 +08:00
}
LED_C_ON ( ) ;
rdv40_spiffs_lazy_unmount ( ) ;
LED_C_OFF ( ) ;
LEDsoff ( ) ;
DownloadLogInstructions ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_OFF ) ;
}