Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there an API for sending Control Transfers over usb? #354

Open
A2nkF opened this issue Oct 9, 2020 · 6 comments
Open

Is there an API for sending Control Transfers over usb? #354

A2nkF opened this issue Oct 9, 2020 · 6 comments
Assignees
Labels
technical support request for technical support

Comments

@A2nkF
Copy link

A2nkF commented Oct 9, 2020

Hey,

I'm trying to use my greatfet to send Control Transfers to a device connected through the USB1 port, but I didn't manage to find any APIs to do that :/

I think there is a higher level API to do IN control transfers in gf.glitchkit.usb.capture_control_in but that doesn't quite cover what I'm trying to do.
I also tried ~$ gf info -A and

>>> dir(gf)
>>> dir(gf.apis)

but there didn't seem to be an API to just send Control Transfers. Not even in gf.apis.greatdancer.

Am I just looking in the wrong places or do I have to build a custom firmware to expose this functionality?

Thank you :D

@A2nkF
Copy link
Author

A2nkF commented Oct 9, 2020

Ok, so I didn't find what I'm looking for in libgreat but I think the facedancer module allows for sending Control Transfers :).

In case anyone else plans on doing this, this is what worked for me:

import os

from facedancer import FacedancerUSBHostApp

os.environ['BACKEND'] = 'greatfet'

dev = FacedancerUSBHostApp(verbose=5)
dev.initialize_device()

dev.control_request_in(...)
dev.control_request_out(...)

I think my issue was that I just assumed that gf.apis.greatdancer would be the same thing as facedancer, which isn't the case.

Some documentation would probably be helpful but the python code is definitely readable. That in combination with the comments is also enough to figure out how stuff works for the most part :)

@A2nkF
Copy link
Author

A2nkF commented Oct 10, 2020

Turns out, that still doesn't work properly. Glitchkit and Facedancer appear to do different things when sending control requests. I still can't get the device to respond properly using facedancer.

I can craft a setup request and send it using gf.glitchkit.usb.api.control_in and get the device to send me data just fine. But if I build that same request and send it using facedancer.FacedancerUSBHostApp.control_request_in it hangs...

Here's my code to build the two requests and send them first using glitchkit's API and then using facedancer's.

#!/usr/bin/env python3
import greatfet
import IPython
import usb_consts as consts
import facedancer

from facedancer import FacedancerUSBHostApp


def main():
    # Get some objects to interface with the usb contoller
    gf = greatfet.GreatFET()
    dev = FacedancerUSBHostApp(verbose=5)
    dev.initialize_device()

    # Build setup request using glitchkit 
    req_glitch = gf.glitchkit.usb.build_setup_request(
                        True,
                        consts.REQUEST_TYPE_STANDARD, consts.REQUEST_RECIPIENT_DEVICE,
                        consts.REQUEST_GET_DESCRIPTOR, length = 0x100, index = 0,
                        value = (consts.USB_DT_STRING | consts.DESCRIPTOR_IDX_SN)
                    )

    print(f"[i] req_glitch: {req_glitch}")

    # Build setup request using facedancer 
    req_face = facedancer.core.FacedancerUSBHost._build_setup_request(
                        True,
                        consts.REQUEST_TYPE_STANDARD, consts.REQUEST_RECIPIENT_DEVICE,
                        consts.REQUEST_GET_DESCRIPTOR, length = 0x100, index = 0,
                        value = (consts.USB_DT_STRING | consts.DESCRIPTOR_IDX_SN)
                    )

    print(f"[i] req_face:   {req_face}")

    assert(req_glitch == req_face)

    
    # Send requst using glitchkit
    resp_glitch = gf.glitchkit.usb.api.control_in(bytes(req_glitch), timeout=30*1024)
    print(f"[IN glitch] {resp_glitch}")

    # Send requst using facedancer
    # I'll use the control_request_in method for that, but it builds the request
    # to be sent itself using _build_setup_request.
    # 
    # But since we already know that facedancer.core.FacedancerUSBHost._build_setup_request
    # yields the same bytes as gf.glitchkit.usb.build_setup_request this shouldn't be an 
    # issue :)
    resp_face = dev.control_request_in(
                        consts.REQUEST_TYPE_STANDARD, consts.REQUEST_RECIPIENT_DEVICE,
                        consts.REQUEST_GET_DESCRIPTOR, length = 0x100, index = 0,
                        value = (consts.USB_DT_STRING | consts.DESCRIPTOR_IDX_SN)
                    )


    # IPython.embed() # now to debugging...

if __name__ == '__main__':
    main()

This is the output if I run the code and ^C it after a minute of hanging:

~$ ./test.py
Using GreatDancer Host backend.
Initializing control endpoint...
[i] req_glitch: [128, 6, 4, 3, 0, 0, 0, 1]
[i] req_face:   [128, 6, 4, 3, 0, 0, 0, 1]
[IN glitch] b'\xc6\x03C\x00P\x00I\x00D\x00:\x008\x000\x001\x005\x00 \x00C\x00P\x00R\x00V\x00:\x001\x001\x00 \x00C\x00P\x00F\x00M\x00:\x000\x003\x00 \x00S\x00C\x00E\x00P\x00:\x00'
Issuing setup packet: [128, 6, 4, 3, 0, 0, 0, 1]
^CTraceback (most recent call last):
  File "./test.py", line 62, in <module>
    main()
  File "./test.py", line 50, in main
    resp_face = dev.control_request_in(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/core.py", line 291, in control_request_in
    self.send_on_endpoint(0, setup_request, True, data_packet_pid=0)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/backends/GreatDancerHostApp.py", line 362, in send_on_endpoint
    status = self._get_write_status()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/backends/GreatDancerHostApp.py", line 187, in _get_write_status
    return self._fetch_status_register(self.WRITE_STATUS_REG)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/backends/GreatDancerHostApp.py", line 171, in _fetch_status_register
    raw_status = self.device.comms._vendor_request_in(self.vendor_requests.USBHOST_GET_STATUS, index=register_number, length=4)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pygreat/comms_backends/usb.py", line 226, in _vendor_request_in
    return self._vendor_request(usb.ENDPOINT_IN, request, length,
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pygreat/comms_backends/usb.py", line 213, in _vendor_request
    return self.device.ctrl_transfer(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/usb/core.py", line 1070, in ctrl_transfer
    ret = self._ctx.backend.ctrl_transfer(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/usb/backend/libusb1.py", line 893, in ctrl_transfer
    ret = _check(self.lib.libusb_control_transfer(
KeyboardInterrupt

I don't actually care about whether I have to use facedancer's or glitchkit's APIs but AFAIK facedancer is the only one that also allows me to send OUT transfers because there is no gf.glitchkit.usb.api.control_out :/

@Qyriad
Copy link
Contributor

Qyriad commented Jan 14, 2021

With regard to Facedancer, have you tried running the legacy-applets/facedancer-host-enumeration.py script? The Facedancer host API could use some reworking, but if that script doesn't work for you either then it might be indicative that something is strange about your device or host environment.

@straithe straithe added the technical support request for technical support label Feb 19, 2021
@straithe straithe self-assigned this Feb 19, 2021
@straithe
Copy link
Member

@A2nkF Are you still experiencing this issue?

@A2nkF
Copy link
Author

A2nkF commented Feb 25, 2021

@Qyriad - Running that script does fail:

~$ ./facedancer-host-enumeration.py
Using GreatDancer Host backend.
Traceback (most recent call last):
  File "./facedancer-host-enumeration.py", line 9, in <module>
    u.initialize_device(assign_address=1, apply_configuration=1)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/core.py", line 368, in initialize_device
    self.set_address(assign_address)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/core.py", line 419, in set_address
    self.control_request_out(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/core.py", line 329, in control_request_out
    self.send_on_endpoint(0, setup_request, True)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/facedancer/backends/GreatDancerHostApp.py", line 368, in send_on_endpoint
    raise IOError("Stalled!")
OSError: Stalled!

But I don't know if my setup is particularly weird. It's a MBP with Catalina and python3.8 on the host side and the target is an iPhone X. I've also tried an iPhone 7, 11 and 12 pro and observed the same behaviour.

@straithe - Yes, still the same issue. I just gave up on this project for now bc I spent a couple of days trying to get it to work and still had other things to work on.

The thing that's throwing me off is that everything works fine if you use gf.glitchkit.usb.api.control_in() to send the control transfer. I was able to receive the expected data from the device that way. The fact that sending the same bytes using the two APIs yields different results makes me think that the issue isn't with the environment but rather in the difference between gf.glitchkit.usb.api.control_in and FacedancerUSBHostApp.control_request_in.

Thanks for looking into it and lmk if you need any more info :)

@Qyriad Qyriad added the macOS label Mar 3, 2021
@straithe straithe removed the macOS label Sep 29, 2021
@straithe straithe removed their assignment Oct 11, 2023
@antoinevg antoinevg self-assigned this Oct 12, 2023
@straithe
Copy link
Member

Hi @A2nkF. We've updated Facedancer quite a bit in the last year. We are hoping your issue will be resolved with the new code. Can you please try again and let us know your results?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
technical support request for technical support
Projects
None yet
Development

No branches or pull requests

4 participants