6

I'm setting up my pi0 as HID Keyboard. I've followed this link Pi0 libcomposite gadget.

Every thing works fine, the pi is well recognized as USB Keyboard

$ dmesg
[ +16,318525] usb 1-1.3: new high-speed USB device number 8 using ehci-pci
[  +0,093215] usb 1-1.3: New USB device found, idVendor=1d6b, idProduct=0104
[  +0,000003] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0,000001] usb 1-1.3: Product: hid3myPi
[  +0,000001] usb 1-1.3: Manufacturer: sk4mi
[  +0,000001] usb 1-1.3: SerialNumber: 1049799107101100
[  +0,001447] input: sk4mi hid3myPi as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.3/1-1.3:1.0/0003:1D6B:0104.0004/input/input15
[  +0,053447] hid-generic 0003:1D6B:0104.0004: input,hidraw2: USB HID v1.01 Keyboard [sk4mi hid3myPi] on usb-0000:00:1a.0-1.3/input0

with lsusb:

$ lsusb
Bus 001 Device 008: ID 1d6b:0104 Linux Foundation Multifunction Composite Gadget
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x1d6b Linux Foundation
  idProduct          0x0104 Multifunction Composite Gadget
  bcdDevice            1.00
  iManufacturer           1 sk4mi
  iProduct                2 hid3myPi
  iSerial                 3 1049799107101100
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4 Config 1 : test
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              250mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              5 HID Interface
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      63
         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     0x0008  1x 8 bytes
        bInterval               4
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               4
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      1
Device Status:     0x0000
  (Bus Powered)

But now there is a little problem: when i send keystrokes to the host, the layout keyboard of HID device is wrong.

Per example, when i want to send the a char, i send:

echo -ne "\0\0\x4\0\0\0\0\0" > /dev/hidg0 #press a
echo -ne "\0\0\x0\0\0\0\0\0" > /dev/hidg0 #release key

But it's a q on the screen. So the device is configured as qwerty keyboard, but i want to send in azerty mode.

my script to initiate pi0 as HID device:

# load libcomposite module
modprobe libcomposite
# create gadget
cd /sys/kernel/config/usb_gadget/
mkdir -p hidzero
cd hidzero
echo 0x1d6b > idVendor
echo 0x0104 > idProduct
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB
echo 8      > bCountryCode

mkdir -p strings/0x409
echo "1049799107101100" > strings/0x409/serialnumber
echo "sk4mi" > strings/0x409/manufacturer
echo "hid3myPi" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1 : test" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

#-------------------
#functions here:
# ------------------

#hid conf
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
bash -c 'echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0  > functions/hid.usb0/report_desc'
ln -s functions/hid.usb0 configs/c.1/

#end functions

ls /sys/class/udc > UDC

I try to change the value of bCountryCode, but it don't take effect as we can see on lsusb result...

Anyone knows how to change that ?

Thanks!

Sk4mi

  • Nice work so far! I'm not sure what effect this country code field is supposed to have, I would expect you to select the keyboard layout in the host OS. Have you tried that? – Dmitry Grigoryev Apr 7 '17 at 7:56
  • Thanks :) Yes my host is config in azerty mode... I think it's a parameter to change on the HID configuration itself, but no way to find which :/ – skami Apr 7 '17 at 8:02
2

Scan codes identify physical keys on the keyboard, not characters. Since your host is in AZERTY mode (where A and Q are swapped), sending a scancode corresponding to A results in Q being typed. This is by design.

The comment in your tutorial is misleading. This line

echo -ne "\0\0\x4\0\0\0\0\0" > /dev/hidg0 #press a

is not pressing A, it presses the key number 4, which corresponds to A in en-US layout. Your layout is different, so you get a different character for the same key.

PS. If you need a quick hack to convert strings between QWERTY and AZERTY layouts in your scripts, that would be:

$ echo qwerty AZERTY | tr qwazQWAZ azqwAZQW
azerty QWERTY
  • I've followed your idea and i managed to make it works! I use python to send to /dev/hidg0, i'll post how to that works. I use my keyboard and wireshark to capture scan codes for azerty, and i report it in python to make my mapping works, thank you for the help ;) – skami Apr 8 '17 at 18:21
0

Like dmitry say it, it was just tho wrong mapping for azerty. I code little python script to send the right code! Each character got two values, first one use for decimal of modifier key value (like SHIFT ) and second is the decimal of key pressed.

 azerty_hid_codes = {
    'a' : (0, 20), 'b' : (0, 5), 'c' : (0, 6),
    'd' : (0, 7), 'e' : (0, 8), 'f' : (0, 9),
    'g' : (0, 10), 'h' : (0, 11), 'i' : (0, 12),
    'j' : (0, 13), 'k' : (0, 14), 'l' : (0, 15),
    'm' : (0, 51), 'n' : (0, 17), 'o' : (0, 18),
    'p' : (0, 19), 'q' : (0, 4), 'r' : (0, 21),
    's' : (0, 22), 't' : (0, 23), 'u' : (0, 24),
    'v' : (0, 25), 'w' : (0, 29), 'x' : (0, 27),
    'y' : (0, 28), 'z' : (0, 26), '1' : (2, 30),
    '2' : (2, 31), '3' : (2, 32), '4' : (2, 33),
    '5' : (2, 34), '6' : (2, 35), '7' : (2, 36),
    '8' : (2, 37), '9' : (2, 38), '0' : (2, 39),
    '\n': (0, 40), '\b': (0, 42), '\t': (0, 43),
    ' ' : (0, 44), '-' : (0, 35), '=' : (0, 46),
    '[' : (64, 34), ']' : (64, 45), '\\': (64, 37),
    ';' : (0, 54), '\'': (64, 33), '`' : (64, 36),
    ',' : (0, 16), ':' : (0, 55), '/' : (2, 55),
    'A' : (2, 20), 'B' : (2, 5), 'C' : (2, 6),
    'D' : (2, 7), 'E' : (2, 8), 'F' : (2, 9),
    'G' : (2, 10), 'H' : (2, 11), 'I' : (2, 12),
    'J' : (2, 13), 'K' : (2, 14), 'L' : (2, 15),
    'M' : (2, 51), 'N' : (2, 17), 'O' : (2, 18),
    'P' : (2, 19), 'Q' : (2, 4), 'R' : (2, 21),
    'S' : (2, 22), 'T' : (2, 23), 'U' : (2, 24),
    'V' : (2, 25), 'W' : (2, 29), 'X' : (2, 27),
    'Y' : (2, 28), 'Z' : (2, 26), '!' : (0, 56),
    '@' : (64, 39), '#' : (64, 32), '$' : (0, 48),
    '%' : (32, 52), '^' : (64, 38), '&' : (0, 30),
    '*' : (0, 49), '(' : (0, 34), ')' : (0, 45),
    '_' : (0, 37), '+' : (2, 46), '{' : (64, 33),
    '}' : (64, 46), '|' : (64, 35), '.' : (2, 54),
    '"' : (0, 32), '~' : (64, 31), '<' : (0, 100),
    '>' : (2, 100), '?' : (2, 16) }

This list can be enriched there aren't all keys but minimal for HID attack ! And now to send character i use struct library, to encode data in good format on usb bus.

import struct
modif, key = azerty_hid_codes[wantedChar]
raw = struct.pack("BBBBL", modif, 0x00, key, 0x00, 0x00000000)
with open("/dev/hidg0", "wb") as f:
    f.write(raw) # press key
    f.write(struct.pack("Q", 0)) # release key

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.