+ // Next state is replay:
+ playing = 1;
+
+ cardRead[selected] = 1;
+ }
+ /* MF Classic UID clone */
+ else if (iGotoClone==1)
+ {
+ iGotoClone=0;
+ LEDsoff();
+ LED(selected + 1, 0);
+ LED(LED_ORANGE, 250);
+
+ // record
+ Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]);
+
+ // wait for button to be released
+ // Delay cloning until card is in place
+ while(BUTTON_PRESS())
+ WDT_HIT();
+
+ Dbprintf("Starting clone. [Bank: %u]", selected);
+ // need this delay to prevent catching some weird data
+ SpinDelay(500);
+ // Begin clone function here:
+ /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
+ UsbCommand c = {CMD_MIFARE_CSETBLOCK, {params & (0xFE | (uid == NULL ? 0:1)), blockNo, 0}};
+ memcpy(c.d.asBytes, data, 16);
+ SendCommand(&c);
+
+ Block read is similar:
+ UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, blockNo, 0}};
+ We need to imitate that call with blockNo 0 to set a uid.
+
+ The get and set commands are handled in this file:
+ // Work with "magic Chinese" card
+ case CMD_MIFARE_CSETBLOCK:
+ MifareCSetBlock(c->arg[0], c->arg[1], c->d.asBytes);
+ break;
+ case CMD_MIFARE_CGETBLOCK:
+ MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes);
+ break;
+
+ mfCSetUID provides example logic for UID set workflow:
+ -Read block0 from card in field with MifareCGetBlock()
+ -Configure new values without replacing reserved bytes
+ memcpy(block0, uid, 4); // Copy UID bytes from byte array
+ // Mifare UID BCC
+ block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
+ Bytes 5-7 are reserved SAK and ATQA for mifare classic
+ -Use mfCSetBlock(0, block0, oldUID, wantWipe, MAGIC_SINGLE) to write it
+ */
+ uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0};
+ // arg0 = Flags, arg1=blockNo
+ MifareCGetBlock(params, 0, oldBlock0);
+ if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
+ Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
+ playing = 1;
+ }
+ else {
+ Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]);
+ memcpy(newBlock0,oldBlock0,16);
+ // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic)
+
+ newBlock0[0] = uid_1st[selected]>>24;
+ newBlock0[1] = 0xFF & (uid_1st[selected]>>16);
+ newBlock0[2] = 0xFF & (uid_1st[selected]>>8);
+ newBlock0[3] = 0xFF & (uid_1st[selected]);
+ newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3];
+
+ // arg0 = workFlags, arg1 = blockNo, datain
+ MifareCSetBlock(params, 0, newBlock0);
+ MifareCGetBlock(params, 0, testBlock0);
+
+ if (memcmp(testBlock0, newBlock0, 16)==0) {
+ DbpString("Cloned successfull!");
+ cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
+ playing = 0;
+ iGotoRecord = 1;
+ selected = (selected + 1) % OPTS;
+ } else {
+ Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
+ playing = 1;
+ }
+ }
+ LEDsoff();
+ LED(selected + 1, 0);
+ }
+ // Change where to record (or begin playing)
+ else if (playing==1) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
+ {
+ LEDsoff();
+ LED(selected + 1, 0);
+
+ // Begin transmitting
+ if (playing)
+ {
+ LED(LED_GREEN, 0);
+ DbpString("Playing");
+ for ( ; ; ) {
+ WDT_HIT();
+ int button_action = BUTTON_HELD(1000);
+ if (button_action == 0) { // No button action, proceed with sim
+ uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break
+ uint8_t flags = ( uid_2nd[selected] > 0x00 ) ? FLAG_7B_UID_IN_DATA : FLAG_4B_UID_IN_DATA;
+ num_to_bytes(uid_1st[selected], 3, data);
+ num_to_bytes(uid_2nd[selected], 4, data);
+
+ Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected);
+ if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) {
+ DbpString("Mifare Classic");
+ SimulateIso14443aTag(1, flags, data); // Mifare Classic
+ }
+ else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) {
+ DbpString("Mifare Ultralight");
+ SimulateIso14443aTag(2, flags, data); // Mifare Ultralight
+ }
+ else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) {
+ DbpString("Mifare DESFire");
+ SimulateIso14443aTag(3, flags, data); // Mifare DESFire
+ }
+ else {
+ Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
+ SimulateIso14443aTag(1, flags, data);
+ }
+ }
+ else if (button_action == BUTTON_SINGLE_CLICK) {
+ selected = (selected + 1) % OPTS;
+ Dbprintf("Done playing. Switching to record mode on bank %d",selected);
+ iGotoRecord = 1;
+ break;
+ }
+ else if (button_action == BUTTON_HOLD) {
+ Dbprintf("Playtime over. Begin cloning...");
+ iGotoClone = 1;
+ break;
+ }
+ WDT_HIT();
+ }
+
+ /* We pressed a button so ignore it here with a delay */
+ SpinDelay(300);
+ LEDsoff();
+ LED(selected + 1, 0);
+ }
+ else
+ while(BUTTON_PRESS())
+ WDT_HIT();
+ }
+ }
+}
+#elif WITH_LF
+// samy's sniff and repeat routine
+void SamyRun()
+{
+ StandAloneMode();
+ FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
+
+ int high[OPTS], low[OPTS];
+ int selected = 0;
+ int playing = 0;
+ int cardRead = 0;
+
+ // Turn on selected LED
+ LED(selected + 1, 0);
+
+ for (;;) {
+ usb_poll();
+ WDT_HIT();
+
+ // Was our button held down or pressed?
+ int button_pressed = BUTTON_HELD(1000);
+ SpinDelay(300);
+
+ // Button was held for a second, begin recording
+ if (button_pressed > 0 && cardRead == 0)
+ {
+ LEDsoff();
+ LED(selected + 1, 0);
+ LED(LED_RED2, 0);
+
+ // record
+ DbpString("Starting recording");
+
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ WDT_HIT();
+
+ /* need this delay to prevent catching some weird data */
+ SpinDelay(500);
+
+ CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
+ Dbprintf("Recorded %x %x %08x", selected, high[selected], low[selected]);
+
+ LEDsoff();
+ LED(selected + 1, 0);
+ // Finished recording
+ // If we were previously playing, set playing off
+ // so next button push begins playing what we recorded
+ playing = 0;
+ cardRead = 1;
+ }
+ else if (button_pressed > 0 && cardRead == 1) {
+ LEDsoff();
+ LED(selected + 1, 0);
+ LED(LED_ORANGE, 0);
+
+ // record
+ Dbprintf("Cloning %x %x %08x", selected, high[selected], low[selected]);
+
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ WDT_HIT();
+
+ /* need this delay to prevent catching some weird data */
+ SpinDelay(500);
+
+ CopyHIDtoT55x7(0, high[selected], low[selected], 0);
+ Dbprintf("Cloned %x %x %08x", selected, high[selected], low[selected]);
+
+ LEDsoff();
+ LED(selected + 1, 0);
+ // Finished recording
+
+ // If we were previously playing, set playing off
+ // so next button push begins playing what we recorded
+ playing = 0;
+ cardRead = 0;
+ }
+
+ // Change where to record (or begin playing)
+ else if (button_pressed) {
+ // Next option if we were previously playing
+ if (playing)
+ selected = (selected + 1) % OPTS;
+ playing = !playing;
+
+ LEDsoff();
+ LED(selected + 1, 0);
+
+ // Begin transmitting
+ if (playing)
+ {
+ LED(LED_GREEN, 0);
+ DbpString("Playing");
+ // wait for button to be released
+ while(BUTTON_PRESS())
+ WDT_HIT();
+
+ Dbprintf("%x %x %08x", selected, high[selected], low[selected]);
+ CmdHIDsimTAG(high[selected], low[selected], 0);
+ DbpString("Done playing");
+
+ if (BUTTON_HELD(1000) > 0) {
+ DbpString("Exiting");
+ LEDsoff();
+ return;
+ }
+
+ /* We pressed a button so ignore it here with a delay */
+ SpinDelay(300);
+
+ // when done, we're done playing, move to next option
+ selected = (selected + 1) % OPTS;
+ playing = !playing;
+ LEDsoff();
+ LED(selected + 1, 0);
+ }
+ else
+ while(BUTTON_PRESS())
+ WDT_HIT();
+ }
+ }
+}
+
+#endif
+/*
+OBJECTIVE
+Listen and detect an external reader. Determine the best location
+for the antenna.
+
+INSTRUCTIONS:
+Inside the ListenReaderField() function, there is two mode.
+By default, when you call the function, you will enter mode 1.
+If you press the PM3 button one time, you will enter mode 2.
+If you press the PM3 button a second time, you will exit the function.
+
+DESCRIPTION OF MODE 1:
+This mode just listens for an external reader field and lights up green
+for HF and/or red for LF. This is the original mode of the detectreader
+function.
+
+DESCRIPTION OF MODE 2:
+This mode will visually represent, using the LEDs, the actual strength of the
+current compared to the maximum current detected. Basically, once you know
+what kind of external reader is present, it will help you spot the best location to place
+your antenna. You will probably not get some good results if there is a LF and a HF reader
+at the same place! :-)
+
+LIGHT SCHEME USED:
+*/
+static const char LIGHT_SCHEME[] = {
+ 0x0, /* ---- | No field detected */
+ 0x1, /* X--- | 14% of maximum current detected */
+ 0x2, /* -X-- | 29% of maximum current detected */
+ 0x4, /* --X- | 43% of maximum current detected */
+ 0x8, /* ---X | 57% of maximum current detected */
+ 0xC, /* --XX | 71% of maximum current detected */
+ 0xE, /* -XXX | 86% of maximum current detected */
+ 0xF, /* XXXX | 100% of maximum current detected */
+};
+static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
+
+void ListenReaderField(int limit) {
+#define LF_ONLY 1
+#define HF_ONLY 2
+#define REPORT_CHANGE 10 // report new values only if they have changed at least by REPORT_CHANGE
+
+ int lf_av, lf_av_new, lf_baseline= 0, lf_max;
+ int hf_av, hf_av_new, hf_baseline= 0, hf_max;
+ int mode=1, display_val, display_max, i;
+
+ // switch off FPGA - we don't want to measure our own signal
+ FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+
+ LEDsoff();
+
+ lf_av = lf_max = AvgAdc(ADC_CHAN_LF);
+
+ if(limit != HF_ONLY) {
+ Dbprintf("LF 125/134kHz Baseline: %dmV", (MAX_ADC_LF_VOLTAGE * lf_av) >> 10);
+ lf_baseline = lf_av;
+ }
+
+ hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
+
+ if (limit != LF_ONLY) {
+ Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
+ hf_baseline = hf_av;
+ }
+
+ for(;;) {
+ if (BUTTON_PRESS()) {
+ SpinDelay(500);
+ switch (mode) {
+ case 1:
+ mode=2;
+ DbpString("Signal Strength Mode");
+ break;
+ case 2:
+ default:
+ DbpString("Stopped");
+ LEDsoff();
+ return;
+ break;
+ }
+ }
+ WDT_HIT();
+
+ if (limit != HF_ONLY) {
+ if(mode == 1) {
+ if (abs(lf_av - lf_baseline) > REPORT_CHANGE)
+ LED_D_ON();
+ else
+ LED_D_OFF();
+ }
+
+ lf_av_new = AvgAdc(ADC_CHAN_LF);
+ // see if there's a significant change
+ if(abs(lf_av - lf_av_new) > REPORT_CHANGE) {
+ Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10);
+ lf_av = lf_av_new;
+ if (lf_av > lf_max)
+ lf_max = lf_av;
+ }
+ }
+
+ if (limit != LF_ONLY) {
+ if (mode == 1){
+ if (abs(hf_av - hf_baseline) > REPORT_CHANGE)
+ LED_B_ON();
+ else
+ LED_B_OFF();
+ }
+
+ hf_av_new = AvgAdc(ADC_CHAN_HF);
+ // see if there's a significant change
+ if(abs(hf_av - hf_av_new) > REPORT_CHANGE) {
+ Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10);
+ hf_av = hf_av_new;
+ if (hf_av > hf_max)
+ hf_max = hf_av;
+ }
+ }
+
+ if(mode == 2) {
+ if (limit == LF_ONLY) {
+ display_val = lf_av;
+ display_max = lf_max;
+ } else if (limit == HF_ONLY) {
+ display_val = hf_av;
+ display_max = hf_max;
+ } else { /* Pick one at random */
+ if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
+ display_val = hf_av;
+ display_max = hf_max;
+ } else {
+ display_val = lf_av;
+ display_max = lf_max;
+ }
+ }
+ for (i=0; i<LIGHT_LEN; i++) {
+ if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
+ if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
+ if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
+ if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
+ if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void UsbPacketReceived(uint8_t *packet, int len)
+{
+ UsbCommand *c = (UsbCommand *)packet;
+
+ //Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]);
+
+ switch(c->cmd) {
+#ifdef WITH_LF
+ case CMD_SET_LF_SAMPLING_CONFIG:
+ setSamplingConfig((sample_config *) c->d.asBytes);
+ break;
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
+ cmd_send(CMD_ACK, SampleLF(c->arg[0]),0,0,0,0);
+ break;
+ case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
+ ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
+ break;
+ case CMD_LF_SNOOP_RAW_ADC_SAMPLES:
+ cmd_send(CMD_ACK,SnoopLF(),0,0,0,0);
+ break;
+ case CMD_HID_DEMOD_FSK:
+ CmdHIDdemodFSK(c->arg[0], 0, 0, 1);
+ break;
+ case CMD_HID_SIM_TAG:
+ CmdHIDsimTAG(c->arg[0], c->arg[1], 1);
+ break;
+ case CMD_FSK_SIM_TAG:
+ CmdFSKsimTAG(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+ break;
+ case CMD_ASK_SIM_TAG:
+ CmdASKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+ break;
+ case CMD_PSK_SIM_TAG:
+ CmdPSKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
+ break;
+ case CMD_HID_CLONE_TAG:
+ CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
+ break;
+ case CMD_IO_DEMOD_FSK:
+ CmdIOdemodFSK(c->arg[0], 0, 0, 1);
+ break;
+ case CMD_IO_CLONE_TAG:
+ CopyIOtoT55x7(c->arg[0], c->arg[1]);
+ break;
+ case CMD_EM410X_DEMOD:
+ CmdEM410xdemod(c->arg[0], 0, 0, 1);
+ break;
+ case CMD_EM410X_WRITE_TAG:
+ WriteEM410x(c->arg[0], c->arg[1], c->arg[2]);
+ break;
+ case CMD_READ_TI_TYPE:
+ ReadTItag();
+ break;
+ case CMD_WRITE_TI_TYPE:
+ WriteTItag(c->arg[0],c->arg[1],c->arg[2]);
+ break;
+ case CMD_SIMULATE_TAG_125K:
+ LED_A_ON();
+ SimulateTagLowFrequency(c->arg[0], c->arg[1], 1);
+ LED_A_OFF();
+ break;
+ case CMD_LF_SIMULATE_BIDIR:
+ SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);
+ break;
+ case CMD_INDALA_CLONE_TAG:
+ CopyIndala64toT55x7(c->arg[0], c->arg[1]);
+ break;
+ case CMD_INDALA_CLONE_TAG_L:
+ CopyIndala224toT55x7(c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6]);
+ break;
+ case CMD_T55XX_READ_BLOCK:
+ T55xxReadBlock(c->arg[0], c->arg[1], c->arg[2]);
+ break;
+ case CMD_T55XX_WRITE_BLOCK:
+ T55xxWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
+ break;
+ case CMD_T55XX_WAKEUP:
+ T55xxWakeUp(c->arg[0]);
+ break;
+ case CMD_T55XX_RESET_READ:
+ T55xxResetRead();
+ break;
+ case CMD_PCF7931_READ:
+ ReadPCF7931();
+ break;
+ case CMD_PCF7931_WRITE:
+ WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]);
+ break;
+ case CMD_EM4X_READ_WORD:
+ EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]);
+ break;
+ case CMD_EM4X_WRITE_WORD:
+ EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
+ break;
+ case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
+ CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
+ break;
+ case CMD_VIKING_CLONE_TAG:
+ CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]);
+ break;
+#endif
+
+#ifdef WITH_HITAG
+ case CMD_SNOOP_HITAG: // Eavesdrop Hitag tag, args = type
+ SnoopHitag(c->arg[0]);
+ break;
+ case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content
+ SimulateHitagTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
+ break;
+ case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function
+ ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
+ break;
+#endif
+
+#ifdef WITH_ISO15693
+ case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
+ AcquireRawAdcSamplesIso15693();
+ break;
+ case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693:
+ RecordRawAdcSamplesIso15693();
+ break;
+
+ case CMD_ISO_15693_COMMAND:
+ DirectTag15693Command(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
+ break;
+
+ case CMD_ISO_15693_FIND_AFI:
+ BruteforceIso15693Afi(c->arg[0]);
+ break;
+
+ case CMD_ISO_15693_DEBUG:
+ SetDebugIso15693(c->arg[0]);
+ break;
+
+ case CMD_READER_ISO_15693:
+ ReaderIso15693(c->arg[0]);
+ break;
+ case CMD_SIMTAG_ISO_15693:
+ SimTagIso15693(c->arg[0], c->d.asBytes);
+ break;
+#endif
+
+#ifdef WITH_LEGICRF
+ case CMD_SIMULATE_TAG_LEGIC_RF:
+ LegicRfSimulate(c->arg[0], c->arg[1], c->arg[2]);
+ break;
+
+ case CMD_WRITER_LEGIC_RF:
+ LegicRfWriter(c->arg[1], c->arg[0]);
+ break;
+
+ case CMD_READER_LEGIC_RF:
+ LegicRfReader(c->arg[0], c->arg[1]);
+ break;
+#endif
+
+#ifdef WITH_ISO14443b