Skip to content

Instantly share code, notes, and snippets.

@jeamland
Created December 2, 2019 04:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeamland/64c7b7c525deeb5d4a8846cad08424a8 to your computer and use it in GitHub Desktop.
Save jeamland/64c7b7c525deeb5d4a8846cad08424a8 to your computer and use it in GitHub Desktop.
Attempt at a fake device in Python
#!/usr/bin/env python
import os
import select
import subprocess
import time
import traceback
import functionfs
import functionfs.ch9
GADGET_NAME = "fakedevice"
CONFIG_NAME = "c.1"
FUNCTION_NAME = "ffs.fakedevice"
CONFIGFS_PATH = "/sys/kernel/config/usb_gadget"
GADGET_PATH = f"{CONFIGFS_PATH}/{GADGET_NAME}"
CONFIG_PATH = f"{GADGET_PATH}/configs/{CONFIG_NAME}"
FUNCTION_PATH = f"{GADGET_PATH}/functions/{FUNCTION_NAME}"
STRINGS_PATH = f"{GADGET_PATH}/strings/0x409"
CONFIG_STRINGS_PATH = f"{CONFIG_PATH}/strings/0x409"
FUNCTIONFS_PATH = f"/dev/{FUNCTION_NAME}"
class FakeDevice(functionfs.Function):
def __init__(self, path):
fs, hs, ss = functionfs.getInterfaceInAllSpeeds(
interface={
"bInterfaceClass": functionfs.ch9.USB_CLASS_VENDOR_SPEC,
"iInterface": 1,
},
endpoint_list=[
{
"endpoint": {
"bEndpointAddress": 0x81,
"bmAttributes": functionfs.ch9.USB_ENDPOINT_XFER_BULK,
},
},
],
)
super().__init__(path, fs_list=fs, lang_dict={0x0409: ["FAKETEST"]})
self.out_ep = self.getEndpoint(1)
self.enabled = False
def onBind(self):
print("BOUND")
def onUnbind(self):
print("UNBOUND")
self.enabled = False
def onEnable(self):
print("ENABLED")
self.enabled = True
super().onEnable()
def onDisable(self):
print("DISABLED")
self.enabled = True
def onSetup(self, *args, **kwargs):
print("SETUP")
super().onSetup(*args, **kwargs)
def timer(self):
print("TIMER")
if self.enabled:
self.out_ep.write(b"YEET")
# Setup
## Ensure we have the right kernel modules loaded.
subprocess.check_call(["modprobe", "usb_f_fs"])
# Create our gadget.
os.mkdir(GADGET_PATH)
# Create the configuration for our gadget.
os.mkdir(CONFIG_PATH)
# Create the function for our gadget.
os.mkdir(FUNCTION_PATH)
# Create strings entries.
os.mkdir(STRINGS_PATH)
os.mkdir(CONFIG_STRINGS_PATH)
# Populate device data and strings.
with open(f"{GADGET_PATH}/idVendor", "w") as vendor:
vendor.write("0x04e8\n")
with open(f"{GADGET_PATH}/idProduct", "w") as product:
product.write("0x2d01\n")
with open(f"{STRINGS_PATH}/serialnumber", "w") as serial:
serial.write("FAKETEST\n")
with open(f"{STRINGS_PATH}/manufacturer", "w") as manufacturer:
manufacturer.write("Vendor\n")
with open(f"{STRINGS_PATH}/product", "w") as product:
product.write("Product\n")
with open(f"{CONFIG_STRINGS_PATH}/configuration", "w") as configuration:
configuration.write("Configuration 1\n")
with open(f"{CONFIG_PATH}/MaxPower", "w") as max_power:
max_power.write("120\n")
# Connect function to configuration.
os.symlink(FUNCTION_PATH, f"{CONFIG_PATH}/{FUNCTION_NAME}")
# Create FunctionFS instance.
os.mkdir(FUNCTIONFS_PATH)
subprocess.check_call(["mount", "fakedevice", FUNCTIONFS_PATH, "-t", "functionfs"])
udc_name = os.listdir("/sys/class/udc")[0]
print(repr(udc_name))
# Run
try:
with FakeDevice(FUNCTIONFS_PATH) as f:
with open(f"{GADGET_PATH}/UDC", "w") as udc:
udc.write(udc_name)
epoll = select.epoll()
epoll.register(f.ep0, select.EPOLLIN)
while True:
for fd, event in epoll.poll(1.0):
if fd == f.ep0.fileno():
f.processEvents()
f.timer()
except:
traceback.print_exc()
# Teardown
with open(f"{GADGET_PATH}/UDC", "w") as udc:
udc.write("")
subprocess.check_call(["umount", FUNCTIONFS_PATH])
os.rmdir(FUNCTIONFS_PATH)
os.unlink(f"{CONFIG_PATH}/{FUNCTION_NAME}")
os.rmdir(CONFIG_STRINGS_PATH)
os.rmdir(STRINGS_PATH)
os.rmdir(FUNCTION_PATH)
os.rmdir(CONFIG_PATH)
os.rmdir(GADGET_PATH)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment