Просмотр исходного кода

Misc cleanup and README updates

Zachary Weiss 3 лет назад
Родитель
Сommit
92a601d558
6 измененных файлов с 24 добавлено и 243 удалено
  1. 16 14
      README.md
  2. 5 2
      application.fam
  3. 2 6
      helpers/mag_helpers.c
  4. 0 1
      scenes/mag_scene_config.h
  5. 0 209
      scenes/mag_scene_emulate_test.c
  6. 1 11
      scenes/mag_scene_start.c

+ 16 - 14
README.md

@@ -1,30 +1,32 @@
 # magspoof_flipper
 WIP of MagSpoof for the Flipper Zero. Currently rewriting from the ground up; basic TX of saved files should now work over both RFID (using the Flipper's internal coil) and GPIO (pins A6 and A7: such that one can connect an H-bridge and external coil). A sample file with test data is included in `assets`, for anyone wishing to experiment. Using this README as coarse notes of what remains to be done; anyone is welcome to contribute!
 
-Disclaimer: use responsibly, and at your own risk. While in my testing, I've seen no reason to believe this could damage the RFID hardware, this is inherently driving the coil in ways it was not designed or intended for; I take no responsibility for fried/bricked Flippers. Similarly, please only use this with magstripe cards and mag readers you own — this is solely meant as a proof of concept for educational purposes, and I neither condone nor am sympathetic to malicious uses of my code.
+Disclaimer: use responsibly, and at your own risk. While in my testing, I've seen no reason to believe this could damage the RFID hardware, this is inherently driving the coil in ways it was not designed or intended for; I take no responsibility for fried/bricked Flippers. Similarly, please only use this with magstripe cards and mag readers you own — this is solely meant as a proof of concept for educational purposes. I neither condone nor am sympathetic to malicious uses of my code.
 
 ## TODO
 Emulation:
-- Clean up old testing scenes, remove deprecated helpers
-- Reverse track precomputation
-- Does the main timing-sensitive section need to be branchless? (Remove `if`s from the `FURI_CRITICAL...` section of `mag_spoof()`?)
-- Implement/integrate better bitmap than hacky first pass? antirez's better approach (from ProtoView) included at bottom of `helpers/mag_helpers.c`
+- General code cleanup
+- Reverse track precompute & replay
+- Implement/integrate better bitmap than hacky first pass? Boilerplate from [antirez](https://github.com/antirez)'s better approach (from [ProtoView](https://github.com/antirez/protoview)) included at the bottom of `helpers/mag_helpers.c`
+- Should the main timing-sensitive section be branchless? (Remove `if` and `switch` statements from the `FURI_CRITICAL...` section of `mag_spoof()`?)
 - Pursue skunkworks TX improvement ideas listed below
 
 Scenes:
-- Complete emulation config scene (include reverse track functionality; possibly expand settings list to include prefix/between/suffix options)
+- Finish emulation config scene (reverse track functionality; possibly expand settings list to include prefix/between/suffix options)
 - Improved saved info display (better text wrapping options? remove and just include that info on the emulate scene? decode data to fields?)
-- Edit saved card scene
+- "About" scene?
+- "Edit" scene (generalize "Add manually")
 
 File management:
-- Parsing loaded files into relevent fields (would we need to specify card type as well, to decode correctly?)
-- Modify manual add scene to allow editing and renaming of existing files
 - Validation of card track data?
+- Parsing loaded files into human-readable fields (would we need to specify card type to decode correctly?)
 - Update Add Manually flow to reflect new file format (currently only sets Track 2, and Info/Emulate scene only displays Track 2)
 
 Known bugs:
 - Custom text input scene with expanded characterset (Add Manually) has odd behavior when navigating the keys near the numpad
 - Track 1 data typically starts with a `%` sign. Unless escaped, it won't be displayed when printed, as C considers it a special character. To confirm: how does this impact the emulation when iterating through the chars? Does it get played correctly?
+- Possible file format issues when Track 2 data exists but Track 1 is left empty; doesn't seem to load happily.
+- Attempting to play a track that doesn't have data results in a crash (as one might expect). Need to lock out users from selecting empty tracks in the config menu or do better error handling
 
 ## Skunkworks ideas
 Internal TX improvements:
@@ -32,15 +34,15 @@ Internal TX improvements:
 - Implement using the timer system, rather than direct-writing to pins
 - Use the NFC (HF RFID) coil instead of or in addition to the LF coil (likely unfruitful from initial tests; we can enable/disable the oscillating field, but even with transparent mode to the ST25R3916, it seems we don't get low-enough-level control to pull it high/low correctly) 
 
-External RX options (What is simplest read module?):
-- Some UART mag reader (bulky, but likely easiest to read over GPIO, and means one can read all tracks)
-- Square audio jack mag reader (this may be DOA; seems like newer versions of the Square modules have some form of preprocessing, that also modifies the signal, perhaps in an effort to discourage folks using their hardware independent of their software. Thanks @[arha](https://github.com/arha) for your work investigating this)
+External RX options:
+- UART-connected mag reader (bulky, but likely easiest to read over GPIO, and means one can read all tracks)
+- Square audio jack mag reader (this may be DOA; seems like newer versions of the Square modules have some form of preprocessing that also modifies the signal, perhaps in an effort to discourage folks using their hardware independent of their software. Thanks [@arha](https://github.com/arha) for your work investigating this)
 - Some read-head directly connected to GPIO, ADC'd, and parsed all on the Flipper. Likely the most compact and cheapest module option, but also would require the most work.
-- USB HID input feasible? Flipper seemingly can't act as an HID host, is there any way to circumvent this or is it due to a hardware incompatibility? This would be the easiest / best option all-around if feasible. 
+- USB HID input likely infeasible; seems the FZ cannot act as an HID host.
 
 ----
 ## Credits
-This project interpolates work from [Samy Kamkar's original MagSpoof project](https://github.com/samyk/magspoof), [dunaevai135's Flipper hackathon project](https://github.com/dunaevai135/flipperzero-firmware), and the Flipper team's [LF RFID](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/main/lfrfid) and [SubGhz](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/main/subghz) apps.  
+This project interpolates work from [Samy Kamkar's original MagSpoof project](https://github.com/samyk/magspoof), [dunaevai135 & AlexYaro's Flipper hackathon project](https://github.com/dunaevai135/flipperzero-firmware), and the Flipper team's [LF RFID](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/main/lfrfid) and [SubGhz](https://github.com/flipperdevices/flipperzero-firmware/tree/dev/applications/main/subghz) apps.  
 
 Many thanks to everyone who has helped in addition to those above, most notably: 
 - [antirez](https://github.com/antirez) for bitmapping suggestions and general C wisdom

+ 5 - 2
application.fam

@@ -5,11 +5,10 @@ App(
     entry_point="mag_app",
     cdefines=["APP_MAG"],
     requires=[
-        "gui", 
+        "gui",
         "storage",
         "notification",
         "dialogs",
-        'toolbox',
     ],
     provides=[],
     stack_size=2 * 1024,
@@ -17,4 +16,8 @@ App(
     fap_icon="icons/mag_10px.png",
     fap_category="Tools",
     fap_icon_assets="icons",
+    fap_version=(0, 1),  # major, minor
+    fap_description="WIP MagSpoof port using the RFID subsystem",
+    fap_author="Zachary Weiss",
+    fap_weburl="https://github.com/zacharyweiss/magspoof_flipper",
 )

+ 2 - 6
helpers/mag_helpers.c

@@ -190,9 +190,8 @@ void track_to_bits(uint8_t* bit_array, const char* track_data, uint8_t track_ind
     bit_array[i] = 2;
     i++;
 
-    // Log the output
+    // Log the output (messy but works)
     char output[100] = {0x0};
-    //FURI_LOG_D(TAG, "%s", bit_array);
     FuriString* tmp_str;
     tmp_str = furi_string_alloc();
     for(uint8_t j = 0; bit_array[j] != 2; j++) {
@@ -201,16 +200,13 @@ void track_to_bits(uint8_t* bit_array, const char* track_data, uint8_t track_ind
     }
     FURI_LOG_D(TAG, "Track %d: %s", (track_index + 1), output);
     furi_string_free(tmp_str);
-
-    //bool is_correct_length = (i == (strlen(track_data) * bitlen[track_index]));
-    //furi_assert(is_correct_length);
 }
 
 void mag_spoof(Mag* mag) {
     MagSetting* setting = mag->setting;
 
     // precompute tracks (WIP; ignores reverse and 3rd track)
-    // likely will be reworked to Samy's bitmap method anyway...
+    // likely will be reworked to antirez's bitmap method anyway...
     const char* data1 = furi_string_get_cstr(mag->mag_dev->dev_data.track[0].str);
     const char* data2 = furi_string_get_cstr(mag->mag_dev->dev_data.track[1].str);
     uint8_t bit_array1[(strlen(data1) * bitlen[0]) + 1];

+ 0 - 1
scenes/mag_scene_config.h

@@ -1,5 +1,4 @@
 ADD_SCENE(mag, start, Start)
-ADD_SCENE(mag, emulate_test, EmulateTest)
 ADD_SCENE(mag, emulate, Emulate)
 ADD_SCENE(mag, emulate_config, EmulateConfig)
 ADD_SCENE(mag, file_select, FileSelect)

+ 0 - 209
scenes/mag_scene_emulate_test.c

@@ -1,209 +0,0 @@
-#include "../mag_i.h"
-
-#define PIN_A 0
-#define PIN_B 1 // currently unused
-#define CLOCK_US 500 // typically set between 200-500us
-#define TEST_STR "%%B123456781234567^LASTNAME/FIRST^YYMMSSSDDDDDDDDDDDDDDDDDDDDDDDDD?\0"
-#define TEST_TRACK 0
-// TODO: better way of setting temp test str,
-//       text wrapping on screen? (Will be relevant for any loaded data too)
-
-uint8_t magspoof_bit_dir = 0;
-const char* test_str = TEST_STR;
-
-void gpio_item_set_rfid_pin(uint8_t index, bool level) {
-    if(index == 0) {
-        furi_hal_gpio_write(&gpio_rfid_carrier_out, level);
-        // A7 GPIO pin for debugging purposes
-        // furi_hal_gpio_write(&gpio_ext_pa7, level);
-    }
-}
-
-static void play_bit(uint8_t send_bit) {
-    magspoof_bit_dir ^= 1;
-    gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
-    // PIN_B goes unused in current LF modulation.
-    // Leaving legacy here in event we attempt downstream modulation,
-    // rather than just modulating RFID_OUT upstream for signal forming
-    gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
-    furi_delay_us(CLOCK_US);
-
-    // NFC TEST
-    //(magspoof_bit_dir) ? furi_hal_nfc_ll_txrx_on() : furi_hal_nfc_ll_txrx_off();
-
-    if(send_bit) {
-        magspoof_bit_dir ^= 1;
-        gpio_item_set_rfid_pin(PIN_A, magspoof_bit_dir);
-        gpio_item_set_rfid_pin(PIN_B, !magspoof_bit_dir);
-
-        //(magspoof_bit_dir) ? furi_hal_nfc_ll_txrx_on() : furi_hal_nfc_ll_txrx_off();
-    }
-    furi_delay_us(CLOCK_US);
-}
-
-static void mag_spoof_test(FuriString* track_str, uint8_t track) {
-    furi_hal_power_enable_otg();
-
-    size_t from;
-    size_t to;
-
-    // TODO ';' in first track case
-    if(track == 0) {
-        from = furi_string_search_char(track_str, '%');
-        to = furi_string_search_char(track_str, '?', from);
-    } else if(track == 1) {
-        from = furi_string_search_char(track_str, ';');
-        to = furi_string_search_char(track_str, '?', from);
-    } else {
-        from = 0;
-        to = furi_string_size(track_str);
-    }
-    if(from >= to) {
-        return;
-    }
-    furi_string_mid(track_str, from, to - from + 1);
-
-    const char* data = furi_string_get_cstr(track_str);
-
-    printf("%s", data);
-
-    furi_hal_ibutton_start_drive();
-    furi_hal_ibutton_pin_low();
-
-    // NFC TEST
-    //furi_hal_nfc_exit_sleep();
-
-    // Initializing at GpioSpeedLow seems sufficient for our needs; no improvements seen by increasing speed setting
-
-    // this doesn't seem to make a difference, leaving it in
-    furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    furi_hal_gpio_write(&gpio_rfid_data_in, false);
-
-    // false->ground RFID antenna; true->don't ground
-    // skotopes (RFID dev) say normally you'd want RFID_PULL in high for signal forming, while modulating RFID_OUT
-    // dunaevai135 had it low in their old code. Leaving low, as it doesn't seem to make a difference on my janky antenna
-    furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
-
-    furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-
-    // A7 GPIO pin for debugging purposes
-    // furi_hal_gpio_init(&gpio_ext_pa7, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-
-    // TODO: initialize pins on scene enter, perhaps, so as to avoid this delay each time the button is pressed?
-    // Also, why is such a long delay needed?
-    furi_delay_ms(300);
-
-    // prevents interrupts &c. from impacting critical timings
-    FURI_CRITICAL_ENTER();
-
-    const uint8_t bitlen[] = {7, 5, 5};
-    const int sublen[] = {32, 48, 48};
-    int tmp, crc, lrc = 0;
-    magspoof_bit_dir = 0;
-
-    // First put out a bunch of leading zeros.
-    for(uint8_t i = 0; i < 25; i++) {
-        play_bit(0);
-    }
-
-    for(uint8_t i = 0; data[i] != '\0'; i++) {
-        crc = 1;
-        tmp = data[i] - sublen[track];
-
-        for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
-            crc ^= tmp & 1;
-            lrc ^= (tmp & 1) << j;
-            play_bit(tmp & 1);
-            tmp >>= 1;
-        }
-        play_bit(crc);
-    }
-
-    // finish calculating and send last "byte" (LRC)
-    tmp = lrc;
-    crc = 1;
-    for(uint8_t j = 0; j < bitlen[track] - 1; j++) {
-        crc ^= tmp & 1;
-        play_bit(tmp & 1);
-        tmp >>= 1;
-    }
-    play_bit(crc);
-
-    // finish with 0's
-    for(uint8_t i = 0; i < 5 * 5; i++) {
-        play_bit(0);
-    }
-
-    gpio_item_set_rfid_pin(PIN_A, 0);
-    gpio_item_set_rfid_pin(PIN_B, 0);
-    // NFC TEST
-    //furi_hal_nfc_ll_txrx_off();
-
-    // end critical timing section
-    FURI_CRITICAL_EXIT();
-
-    // NFC TEST
-    //furi_hal_nfc_start_sleep();
-
-    furi_hal_rfid_pins_reset();
-    furi_hal_power_disable_otg();
-}
-
-void mag_scene_emulate_test_on_enter(void* context) {
-    Mag* mag = context;
-    Widget* widget = mag->widget;
-
-    //FuriString *tmp_string;
-    //tmp_string = furi_string_alloc();
-
-    widget_add_button_element(widget, GuiButtonTypeLeft, "Back", mag_widget_callback, mag);
-    widget_add_button_element(widget, GuiButtonTypeRight, "Emulate", mag_widget_callback, mag);
-    //widget_add_button_element(widget, GuiButtonTypeRight, "Re", mag_widget_callback, mag);
-    //widget_add_button_element(widget, GuiButtonTypeCenter, "Two", mag_widget_callback, mag);
-
-    //furi_string_printf(tmp_string, test_str);
-    //widget_add_string_element(
-    //    widget, 64, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string));
-    //furi_string_reset(tmp_string);
-
-    view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewWidget);
-    //furi_string_free(tmp_string);
-}
-
-bool mag_scene_emulate_test_on_event(void* context, SceneManagerEvent event) {
-    Mag* mag = context;
-    SceneManager* scene_manager = mag->scene_manager;
-    bool consumed = false;
-
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == GuiButtonTypeRight) {
-            consumed = true;
-
-            // Hardcoding a test string for the time being, while we debug/improve LF RFID TX
-            FuriString* v = furi_string_alloc();
-            furi_string_set_str(v, test_str);
-
-            // blink led while spoofing
-            notification_message(mag->notifications, &sequence_blink_start_cyan);
-            mag_spoof_test(v, TEST_TRACK);
-            // mag_spoof_single_track_rfid(v, TEST_TRACK);
-            notification_message(mag->notifications, &sequence_blink_stop);
-
-            furi_string_free(v);
-        } else if(event.event == GuiButtonTypeLeft) {
-            consumed = true;
-
-            scene_manager_previous_scene(scene_manager);
-        }
-    }
-
-    return consumed;
-}
-
-void mag_scene_emulate_test_on_exit(void* context) {
-    Mag* mag = context;
-
-    notification_message(mag->notifications, &sequence_blink_stop);
-    widget_reset(mag->widget);
-}

+ 1 - 11
scenes/mag_scene_start.c

@@ -1,7 +1,6 @@
 #include "../mag_i.h"
 
 typedef enum {
-    //SubmenuIndexEmulateTest,
     SubmenuIndexSaved,
     SubmenuIndexAddManually,
 } SubmenuIndex;
@@ -16,15 +15,10 @@ void mag_scene_start_on_enter(void* context) {
     Mag* mag = context;
     Submenu* submenu = mag->submenu;
 
-    /*submenu_add_item(
-        submenu,
-        "Emulate (Hardcoded)",
-        SubmenuIndexEmulateTest,
-        mag_scene_start_submenu_callback,
-        mag);*/
     submenu_add_item(submenu, "Saved", SubmenuIndexSaved, mag_scene_start_submenu_callback, mag);
     submenu_add_item(
         submenu, "Add Manually", SubmenuIndexAddManually, mag_scene_start_submenu_callback, mag);
+    // TODO: "About" scene?
 
     submenu_set_selected_item(
         submenu, scene_manager_get_scene_state(mag->scene_manager, MagSceneStart));
@@ -40,10 +34,6 @@ bool mag_scene_start_on_event(void* context, SceneManagerEvent event) {
     bool consumed = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
-        /*if(event.event == SubmenuIndexEmulateTest) {
-            scene_manager_next_scene(mag->scene_manager, MagSceneEmulateTest);
-            consumed = true;
-        } else */
         if(event.event == SubmenuIndexSaved) {
             furi_string_set(mag->file_path, MAG_APP_FOLDER);
             scene_manager_next_scene(mag->scene_manager, MagSceneFileSelect);