Joy-Con HID Reverse Engineering

Discussion in 'Switch - Hacking & Homebrew' started by shinyquagsire23, Apr 11, 2017.

  1. shinyquagsire23
    OP

    shinyquagsire23 SALT/Sm4sh Leak Guy

    Member
    1,961
    3,231
    Nov 18, 2012
    United States
    Las Vegas
    Making a thread to get a bit of visibility and maybe some input from people, but over the last week I've been working on reverse engineering parts of the Joy-Con communication methods, and so far I've had success talking straight with the rails using UART and an ESP32, and more recently, HID via Joy-Con Charging Grip.

    Contrary to the name, the Joy-Con charging grip actually does quite a bit more than charge. Plugging it into a computer exposes two USB interfaces (one per Joy-Con) with two endpoints which can be talked with via the HID protocol. By dumping the firmware of the STM32 chip on the charging grip I've also managed to reverse engineer the custom HID commands which allowed me to talk more extensively with the Joy-Con. My code repository for my HID Joy-Con research can be found at https://github.com/shinyquagsire23/HID-Joy-Con-Whispering. Currently it is untested with a Pro Controller, but it has the same STM32 chip as the grip and the firmware is similar, so if anyone has a Pro Controller and wants to try seeing if it works with one, feel free.

    What can it do now?
    Currently with what I have, the following is already done:
    • Retrieving full input packets from each Joy-Con, including analog joystick values, buttons, etc.
    • Joy-Con SPI firmware dumping. Since UART commands exist to read from the SPI firmware, and the HID protocol exposes a command to send UART commands, the entirety of the Joy-Con on-board SPI flash can be dumped with only a charging grip
    What else is possible?
    Anything which the Joy-Con can do while clicked into console should be possible. This includes HD rumble, NFC, IR, and other things. It should also be possible to write Linux or maybe Windows drivers which can interact with the Joy-Con over HID so that the device can act as a single controller with what is already done.

    What needs to be done?
    There are still a lot of unknowns with the wired UART protocol, specifically with most of the extra peripherals like HD rumble. The best way to document these, unfortunately, is by using a logic analyzer to watch the UART communication while it is attached to a console, but dekuNukem has already done a lot of this at his repo here. Additionally, it seems despite Bluetooth using HID, the USB-C HID protocol is not the same as the Bluetooth protocol, which means that reversing Bluetooth will take either Switch privilege escalation or Joy-Con firmware reverse engineering.
     


  2. jt_1258

    jt_1258 GBAtemp Maniac

    Member
    1,337
    661
    Aug 21, 2016
    United States
    I suppose it would be cool if a day came where we could at least do custom stuff with hd rumble, it sounds like it's cool
     
  3. Jiehfeng

    Jiehfeng A Racist

    Member
    4,224
    1,970
    Aug 15, 2012
    Nigeria
    Under your fucking chair.
    Good post, but reading this I was under the impression hacks could be loaded onto the Joycon to be exploited on the Switch at first. :P
     
  4. jt_1258

    jt_1258 GBAtemp Maniac

    Member
    1,337
    661
    Aug 21, 2016
    United States
    something tells me theres a reason this can't be done since I have never heard of anything like this on other systems
     
  5. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    I'm having trouble compiliing it in debian jessie. What deps am I missing?

    Code:
    In file included from /usr/include/c++/4.9/chrono:35:0,
                     from hidtest.cpp:7:
    /usr/include/c++/4.9/bits/c++0x_warning.h:32:2: error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
     #error This file requires compiler and library support for the \
      ^
    hidtest.cpp: In function ‘void spi_flash_dump(hid_device*, char*)’:
    hidtest.cpp:62:8: error: ‘uint32_t’ was not declared in this scope
      for(*(uint32_t*)(&spi_read[0x13]) = 0; *(uint32_t*)(&spi_read[0x13]) < 0x80000; *(uint32_t*)(&spi_read[0x13]) += 0x1C)
            ^
    hidtest.cpp:62:17: error: expected primary-expression before ‘)’ token
      for(*(uint32_t*)(&spi_read[0x13]) = 0; *(uint32_t*)(&spi_read[0x13]) < 0x80000; *(uint32_t*)(&spi_read[0x13]) += 0x1C)
                     ^
    hidtest.cpp:62:52: error: expected primary-expression before ‘)’ token
      for(*(uint32_t*)(&spi_read[0x13]) = 0; *(uint32_t*)(&spi_read[0x13]) < 0x80000; *(uint32_t*)(&spi_read[0x13]) += 0x1C)
                                                        ^
    hidtest.cpp:62:93: error: expected primary-expression before ‘)’ token
      for(*(uint32_t*)(&spi_read[0x13]) = 0; *(uint32_t*)(&spi_read[0x13]) < 0x80000; *(uint32_t*)(&spi_read[0x13]) += 0x1C)
                                                                                                 ^
    hidtest.cpp: In function ‘int main(int, char**)’:
    hidtest.cpp:208:28: error: ‘std::chrono’ has not been declared
      unsigned long last = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
                                ^
    hidtest.cpp:208:82: error: ‘std::chrono’ has not been declared
      unsigned long last = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
                                                                                      ^
    hidtest.cpp:210:45: error: ‘std::chrono’ has not been declared
          printf("%02llums delay,  left ", (std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1)) - last);
                                                 ^
    hidtest.cpp:210:99: error: ‘std::chrono’ has not been declared
          printf("%02llums delay,  left ", (std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1)) - last);
                                                                                                       ^
    hidtest.cpp:211:18: error: ‘std::chrono’ has not been declared
          last = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
                      ^
    hidtest.cpp:211:72: error: ‘std::chrono’ has not been declared
          last = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
    
     
  6. evandixon

    evandixon PMD Researcher

    Member
    1,654
    780
    May 29, 2009
    United States
    I don't know for sure, but I suspect this line is important:
    #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options.
     
  7. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    It compiled after I added -std=gnu++11 but running it with a Pro controller connected returns:
    Code:
    Could not get handle(s) for Joy-Con! Handles L 00000000, R 29b14b50
    The R number is random each time.


    Pro controller in lsusb -v:
    Code:
    Bus 001 Device 002: ID 057e:2009 Nintendo Co., Ltd
    Device Descriptor:
      bLength                18
      bDescriptorType         1
      bcdUSB               2.00
      bDeviceClass            0 (Defined at Interface level)
      bDeviceSubClass         0
      bDeviceProtocol         0
      bMaxPacketSize0        64
      idVendor           0x057e Nintendo Co., Ltd
      idProduct          0x2009
      bcdDevice            2.00
      iManufacturer           1 Nintendo Co., Ltd.
      iProduct                2 Pro Controller
      iSerial                 3 000000000001
      bNumConfigurations      1
      Configuration Descriptor:
        bLength                 9
        bDescriptorType         2
        wTotalLength           41
        bNumInterfaces          1
        bConfigurationValue     1
        iConfiguration          0
        bmAttributes         0xa0
          (Bus Powered)
          Remote Wakeup
        MaxPower              500mA
        Interface Descriptor:
          bLength                 9
          bDescriptorType         4
          bInterfaceNumber        0
          bAlternateSetting       0
          bNumEndpoints           2
          bInterfaceClass         3 Human Interface Device
          bInterfaceSubClass      0 No Subclass
          bInterfaceProtocol      0 None
          iInterface              0
            HID Device Descriptor:
              bLength                 9
              bDescriptorType        33
              bcdHID               1.11
              bCountryCode            0 Not supported
              bNumDescriptors         1
              bDescriptorType        34 Report
              wDescriptorLength     203
             Report Descriptors:
               ** UNAVAILABLE **
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x81  EP 1 IN
            bmAttributes            3
              Transfer Type            Interrupt
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               8
          Endpoint Descriptor:
            bLength                 7
            bDescriptorType         5
            bEndpointAddress     0x01  EP 1 OUT
            bmAttributes            3
              Transfer Type            Interrupt
              Synch Type               None
              Usage Type               Data
            wMaxPacketSize     0x0040  1x 64 bytes
            bInterval               8
    Device Status:     0x0001
      Self Powered
    
    
     
    Last edited by normal19, Apr 11, 2017
  8. Giodude

    Giodude Ruler of Italy

    Member
    GBAtemp Patron
    Giodude is a Patron of GBAtemp and is helping us stay independent!

    Our Patreon
    3,608
    1,007
    May 17, 2015
    United States
    New York
    since the pro controller uses the exact same firmware, theoretically, once the joycons are completely exposed, the pro controller should be exactly the same right?
     
  9. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    I imagine it's not exactly the same because Pro controller has most but not all joycon features like IR.
     
  10. shinyquagsire23
    OP

    shinyquagsire23 SALT/Sm4sh Leak Guy

    Member
    1,961
    3,231
    Nov 18, 2012
    United States
    Las Vegas
    Hm, looks about the same as the grip with just one less interface, so I think it should work if you just remove all references to handle_l like this? I'll need to figure out exactly how I want to handle Pro Controllers because the grip requires both Joy-Con to initialize. I'll also go ahead and add -std=gnu++11 to the README, latest GCC uses C++11 by default but Debian tends to stick to older versions for a while.
     
  11. Mr. Wizard

    Mr. Wizard Ending the spread of bullshit one thread at a time

    Member
    1,112
    424
    Mar 20, 2015
    Canada
    10th Dimension
    Make them sing yo!





     
    supermario18 and 8BitWonder like this.
  12. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    This program recognizes pro controller, the controller vibrates lightly for a moment and then it outputs mostly this
    Code:
    Found Joy-Con (R), MAC: 08:30:00:00:00:01
    Switching baudrate...
    Start input poll loop
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 21 11 ac 3b 7f 00 00 b0 f6 10 ac 3b 7f 00 00 c0 d3 f4 37 ff 7f 00 00 00 25 11 ac 3b 7f 00 00 e8 d3 f4 37 ff 7f 00 00 a8 21 11 ac 3b
                right 80 92 00 01 01 00 00 00 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    
    And sometimes this
    Code:
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 21 11 ac 3b 7f 00 00 b0 f6 10 ac 3b 7f 00 00 c0 d3 f4 37 ff 7f 00 00 00 25 11 ac 3b 7f 00 00 e8 d3 f4 37 ff 7f 00 00 a8 21 11 ac 3b
                right 81 01 00 03 56 2c fa 8a bb 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    
    pressing buttons and moving sticks doesn't change anything.
     
    Last edited by normal19, Apr 12, 2017
  13. CompC

    CompC GBAtemp Fan

    Member
    366
    160
    May 28, 2009
    United States
    I've been waiting for someone to do this! I like using the Joy-Con on my computer but I don't like that you can't get analog values for the sticks. And that there's no rumble. And it's great that you can use the grip to do this over USB! The Bluetooth on my computer is pretty bad.

    So eventually (hopefully soon?), we will be able to use the charge grip to use two Joy-Con like a traditional controller over USB?
     
  14. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    Here's the pro controller firmware dump, don't know if its the right size
     

    Attached Files:

  15. shinyquagsire23
    OP

    shinyquagsire23 SALT/Sm4sh Leak Guy

    Member
    1,961
    3,231
    Nov 18, 2012
    United States
    Las Vegas
    Hm, the "left" one is irrelevant, I just didn't want to mess with the formatting. It looks like it didn't successfully handshake since it's sending MACs, maybe try a few more times (and without firmware dumping enabled)? During development it was finnicky with handshaking sometimes, I might be missing something needed for Pro Controllers. Also, with the firmware dump, it should be 0x80000 bytes large, though that does look valid for what you have. It almost sounds like it's working at least for a little bit, and then just disconnecting somehow? Definitely a good sign though, I have a copy of the STM32 firmware on the controller so I might see if there's significant differences which might make a difference.

    EDIT: Maybe also take out the baud switch and the second handshake packet as well? Maybe the Pro Controller initializes UART at a higher baudrate since it's all internal.
     
    Last edited by shinyquagsire23, Apr 12, 2017
  16. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    I ran the program several times and the output is always the same. The delay is usually 08ms but it occasionally comes out as 07ms and 16ms
     
  17. normal19

    normal19 Member

    Newcomer
    30
    0
    Aug 23, 2014
    Afghanistan
    I commented out
    Code:
        printf("Switching baudrate...\n");
    
       memset(buf_r, 0x00, 0x40);
       buf_r[0] = 0x80;
       buf_r[1] = 0x03;
       hid_exchange(handle_r, buf_r, 0x2);
      
       memset(buf_r, 0x00, 0x40);
       buf_r[0] = 0x80;
       buf_r[1] = 0x02;
       hid_exchange(handle_r, buf_r, 0x2);
    but it does the same thing, I ran the program a few times and noticed the output is different each time, but it still prints mostly the same random line over and over with a different random line about every second.
    Code:
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 21 60 5b 68 7f 00 00 b0 f6 5f 5b 68 7f 00 00 a0 7d 3c 70 fe 7f 00 00 00 25 60 5b 68 7f 00 00 c8 7d 3c 70 fe 7f 00 00 a8 21 60 5b 68
                right 81 01 00 03 56 2c fa 8a bb 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 21 60 5b 68 7f 00 00 b0 f6 5f 5b 68 7f 00 00 a0 7d 3c 70 fe 7f 00 00 00 25 60 5b 68 7f 00 00 c8 7d 3c 70 fe 7f 00 00 a8 21 60 5b 68
                right 81 01 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 21 60 5b 68 7f 00 00 b0 f6 5f 5b 68 7f 00 00 a0 7d 3c 70 fe 7f 00 00 00 25 60 5b 68 7f 00 00 c8 7d 3c 70 fe 7f 00 00 a8 21 60 5b 68
                right 80 92 00 01 01 00 00 00 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    
    Run it again and it prints
    Code:
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 a1 b6 b1 06 7f 00 00 b0 d6 b6 b1 06 7f 00 00 30 85 6b 27 ff 7f 00 00 00 a5 b6 b1 06 7f 00 00 58 85 6b 27 ff 7f 00 00 a8 a1 b6 b1 06
                right 80 92 00 01 01 00 00 00 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    08ms delay,  left 80 92 00 01 01 00 00 00 1f 08 00 00 01 00 00 00 a8 a1 b6 b1 06 7f 00 00 b0 d6 b6 b1 06 7f 00 00 30 85 6b 27 ff 7f 00 00 00 a5 b6 b1 06 7f 00 00 58 85 6b 27 ff 7f 00 00 a8 a1 b6 b1 06
                right 81 01 00 03 56 2c fa 8a bb 7c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    
     
    Last edited by normal19, Apr 12, 2017
  18. ogioto

    ogioto Member

    Newcomer
    21
    3
    Mar 30, 2017
    Somebody edit me if I'm wrong, but wasn't it done with the wii u this way? I mean, one of the major exploits was found due to unsecured connection between the gamepad and the console.
     
  19. jt_1258

    jt_1258 GBAtemp Maniac

    Member
    1,337
    661
    Aug 21, 2016
    United States
    the game pad feels like a slightly different story then a normal controller
     
  20. TotalInsanity4

    TotalInsanity4 GBAtemp Supreme Overlord

    Member
    6,927
    6,908
    Dec 1, 2014
    United States
    Under a rock
    That wasn't an exploit, it was a way of controlling and grabbing feed from the console wirelessly by using your computer as a gamepad
     
    jt_1258 likes this.