1*e25b118aSDominic Spill#!/usr/bin/env python 2*e25b118aSDominic Spill# 3*e25b118aSDominic Spill# Copyright 2009 Joshua Wright, Michael Ossmann 4*e25b118aSDominic Spill# 5*e25b118aSDominic Spill# This file is part of gr-bluetooth 6*e25b118aSDominic Spill# 7*e25b118aSDominic Spill# gr-bluetooth is free software; you can redistribute it and/or modify 8*e25b118aSDominic Spill# it under the terms of the GNU General Public License as published by 9*e25b118aSDominic Spill# the Free Software Foundation; either version 2, or (at your option) 10*e25b118aSDominic Spill# any later version. 11*e25b118aSDominic Spill# 12*e25b118aSDominic Spill# gr-bluetooth is distributed in the hope that it will be useful, 13*e25b118aSDominic Spill# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*e25b118aSDominic Spill# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*e25b118aSDominic Spill# GNU General Public License for more details. 16*e25b118aSDominic Spill# 17*e25b118aSDominic Spill# You should have received a copy of the GNU General Public License 18*e25b118aSDominic Spill# along with gr-bluetooth; see the file COPYING. If not, write to 19*e25b118aSDominic Spill# the Free Software Foundation, Inc., 51 Franklin Street, 20*e25b118aSDominic Spill# Boston, MA 02110-1301, USA. 21*e25b118aSDominic Spill 22*e25b118aSDominic Spillimport sys 23*e25b118aSDominic Spillimport struct 24*e25b118aSDominic Spillimport time 25*e25b118aSDominic Spillfrom pcapdump.pcapdump import * 26*e25b118aSDominic Spill 27*e25b118aSDominic SpillDLT_EN10MB = 1 28*e25b118aSDominic SpillDLT_BLUETOOTH_HCI_H4 = 187 29*e25b118aSDominic SpillUSBHID_MAP = { 30*e25b118aSDominic Spill 0x04 : "a", 31*e25b118aSDominic Spill 0x05 : "b", 32*e25b118aSDominic Spill 0x06 : "c", 33*e25b118aSDominic Spill 0x07 : "d", 34*e25b118aSDominic Spill 0x08 : "e", 35*e25b118aSDominic Spill 0x09 : "f", 36*e25b118aSDominic Spill 0x0A : "g", 37*e25b118aSDominic Spill 0x0B : "h", 38*e25b118aSDominic Spill 0x0C : "i", 39*e25b118aSDominic Spill 0x0D : "j", 40*e25b118aSDominic Spill 0x0E : "k", 41*e25b118aSDominic Spill 0x0F : "l", 42*e25b118aSDominic Spill 0x10 : "m", 43*e25b118aSDominic Spill 0x11 : "n", 44*e25b118aSDominic Spill 0x12 : "o", 45*e25b118aSDominic Spill 0x13 : "p", 46*e25b118aSDominic Spill 0x14 : "q", 47*e25b118aSDominic Spill 0x15 : "r", 48*e25b118aSDominic Spill 0x16 : "s", 49*e25b118aSDominic Spill 0x17 : "t", 50*e25b118aSDominic Spill 0x18 : "u", 51*e25b118aSDominic Spill 0x19 : "v", 52*e25b118aSDominic Spill 0x1A : "w", 53*e25b118aSDominic Spill 0x1B : "x", 54*e25b118aSDominic Spill 0x1C : "y", 55*e25b118aSDominic Spill 0x1D : "z", 56*e25b118aSDominic Spill 0x1E : "1", 57*e25b118aSDominic Spill 0x1F : "2", 58*e25b118aSDominic Spill 0x20 : "3", 59*e25b118aSDominic Spill 0x21 : "4", 60*e25b118aSDominic Spill 0x22 : "5", 61*e25b118aSDominic Spill 0x23 : "6", 62*e25b118aSDominic Spill 0x24 : "7", 63*e25b118aSDominic Spill 0x25 : "8", 64*e25b118aSDominic Spill 0x26 : "9", 65*e25b118aSDominic Spill 0x27 : "0", 66*e25b118aSDominic Spill 0x28 : "[Return]\n", 67*e25b118aSDominic Spill 0x29 : "[Esc]", 68*e25b118aSDominic Spill 0x2A : "[Backspace]", 69*e25b118aSDominic Spill 0x2B : "[Tab]\t", 70*e25b118aSDominic Spill 0x2C : " ", 71*e25b118aSDominic Spill 0x2D : "-", 72*e25b118aSDominic Spill 0x2E : "=", 73*e25b118aSDominic Spill 0x2F : "[", 74*e25b118aSDominic Spill 0x30 : "]", 75*e25b118aSDominic Spill 0x31 : "\\", 76*e25b118aSDominic Spill 0x32 : "#", 77*e25b118aSDominic Spill 0x33 : ";", 78*e25b118aSDominic Spill 0x34 : "'", 79*e25b118aSDominic Spill 0x35 : "[Grave Accent]", 80*e25b118aSDominic Spill 0x36 : ",", 81*e25b118aSDominic Spill 0x37 : ".", 82*e25b118aSDominic Spill 0x38 : "/", 83*e25b118aSDominic Spill 0x39 : "[Caps Lock]", 84*e25b118aSDominic Spill 0x3A : "[F1]", 85*e25b118aSDominic Spill 0x3B : "[F2]", 86*e25b118aSDominic Spill 0x3C : "[F3]", 87*e25b118aSDominic Spill 0x3D : "[F4]", 88*e25b118aSDominic Spill 0x3E : "[F5]", 89*e25b118aSDominic Spill 0x3F : "[F6]", 90*e25b118aSDominic Spill 0x40 : "[F7]", 91*e25b118aSDominic Spill 0x41 : "[F8]", 92*e25b118aSDominic Spill 0x42 : "[F9]", 93*e25b118aSDominic Spill 0x43 : "[F10]", 94*e25b118aSDominic Spill 0x44 : "[F11]", 95*e25b118aSDominic Spill 0x45 : "[F12]", 96*e25b118aSDominic Spill 0x46 : "[PrintScreen]", 97*e25b118aSDominic Spill 0x47 : "[Scroll]", 98*e25b118aSDominic Spill 0x48 : "[Pause]", 99*e25b118aSDominic Spill 0x49 : "[Insert]", 100*e25b118aSDominic Spill 0x4A : "[Home]", 101*e25b118aSDominic Spill 0x4B : "[PageUp]", 102*e25b118aSDominic Spill 0x4C : "[Delete]", 103*e25b118aSDominic Spill 0x4D : "[End]", 104*e25b118aSDominic Spill 0x4E : "[PageDown]", 105*e25b118aSDominic Spill 0x4F : "[RightArrow]", 106*e25b118aSDominic Spill 0x50 : "[LeftArrow]", 107*e25b118aSDominic Spill 0x51 : "[DownArrow]", 108*e25b118aSDominic Spill 0x52 : "[UpArrow]", 109*e25b118aSDominic Spill 0x53 : "[Keypad Num Lock and Clear]", 110*e25b118aSDominic Spill 0x54 : "[Keypad /]", 111*e25b118aSDominic Spill 0x55 : "[Keypad *]", 112*e25b118aSDominic Spill 0x56 : "[Keypad -]", 113*e25b118aSDominic Spill 0x57 : "[Keypad +]", 114*e25b118aSDominic Spill 0x58 : "[Keypad Enter]\n", 115*e25b118aSDominic Spill 0x59 : "[Keypad 1 and End]", 116*e25b118aSDominic Spill 0x5A : "[Keypad 2 and Down Arrow]", 117*e25b118aSDominic Spill 0x5B : "[Keypad 3 and PageDn]", 118*e25b118aSDominic Spill 0x5C : "[Keypad 4 and Left Arrow]", 119*e25b118aSDominic Spill 0x5D : "[Keypad 5]", 120*e25b118aSDominic Spill 0x5E : "[Keypad 6 and Right Arrow]", 121*e25b118aSDominic Spill 0x5F : "[Keypad 7 and Home]", 122*e25b118aSDominic Spill 0x60 : "[Keypad 8 and Up Arrow]", 123*e25b118aSDominic Spill 0x61 : "[Keypad 9 and PageUp]", 124*e25b118aSDominic Spill 0x62 : "[Keypad 0 and Insert]", 125*e25b118aSDominic Spill 0x63 : "[Keypad . and Delete]", 126*e25b118aSDominic Spill 0x64 : "\\", 127*e25b118aSDominic Spill 0x65 : "[WinKey]", 128*e25b118aSDominic Spill 0x66 : "[Power9]", 129*e25b118aSDominic Spill 0x67 : "[Keypad =]", 130*e25b118aSDominic Spill 0x68 : "[F13]", 131*e25b118aSDominic Spill 0x69 : "[F14]", 132*e25b118aSDominic Spill 0x6A : "[F15]", 133*e25b118aSDominic Spill 0x6B : "[F16]", 134*e25b118aSDominic Spill 0x6C : "[F17]", 135*e25b118aSDominic Spill 0x6D : "[F18]", 136*e25b118aSDominic Spill 0x6E : "[F19]", 137*e25b118aSDominic Spill 0x6F : "[F20]", 138*e25b118aSDominic Spill 0x70 : "[F21]", 139*e25b118aSDominic Spill 0x71 : "[F22]", 140*e25b118aSDominic Spill 0x72 : "[F23]", 141*e25b118aSDominic Spill 0x73 : "[F24]", 142*e25b118aSDominic Spill 0x74 : "[Execute]", 143*e25b118aSDominic Spill 0x75 : "[Help]", 144*e25b118aSDominic Spill 0x76 : "[Menu]", 145*e25b118aSDominic Spill 0x77 : "[Select]", 146*e25b118aSDominic Spill 0x78 : "[Stop]", 147*e25b118aSDominic Spill 0x79 : "[Again]", 148*e25b118aSDominic Spill 0x7A : "[Undo]", 149*e25b118aSDominic Spill 0x7B : "[Cut]", 150*e25b118aSDominic Spill 0x7C : "[Copy]", 151*e25b118aSDominic Spill 0x7D : "[Paste]", 152*e25b118aSDominic Spill 0x7E : "[Find]", 153*e25b118aSDominic Spill 0x7F : "[Mute]", 154*e25b118aSDominic Spill 0x80 : "[Volume Up]", 155*e25b118aSDominic Spill 0x81 : "[Volume Down]", 156*e25b118aSDominic Spill 0x82 : "[Locking Caps Lock]", 157*e25b118aSDominic Spill 0x83 : "[Locking Num Lock]", 158*e25b118aSDominic Spill 0x84 : "[Locking Scroll Lock]", 159*e25b118aSDominic Spill 0x85 : "[Keypad Comma]", 160*e25b118aSDominic Spill 0x86 : "[Keypad Equal]", 161*e25b118aSDominic Spill 0x87 : "[International1]", 162*e25b118aSDominic Spill 0x88 : "[International2]", 163*e25b118aSDominic Spill 0x89 : "[International3]", 164*e25b118aSDominic Spill 0x8A : "[International4]", 165*e25b118aSDominic Spill 0x8B : "[International5]", 166*e25b118aSDominic Spill 0x8C : "[International6]", 167*e25b118aSDominic Spill 0x8D : "[International7]", 168*e25b118aSDominic Spill 0x8E : "[International8]", 169*e25b118aSDominic Spill 0x8F : "[International9]", 170*e25b118aSDominic Spill 0x90 : "[LANG1]", 171*e25b118aSDominic Spill 0x91 : "[LANG2]", 172*e25b118aSDominic Spill 0x92 : "[LANG3]", 173*e25b118aSDominic Spill 0x93 : "[LANG4]", 174*e25b118aSDominic Spill 0x94 : "[LANG5]", 175*e25b118aSDominic Spill 0x95 : "[LANG6]", 176*e25b118aSDominic Spill 0x96 : "[LANG7]", 177*e25b118aSDominic Spill 0x97 : "[LANG8]", 178*e25b118aSDominic Spill 0x98 : "[LANG9]", 179*e25b118aSDominic Spill 0x99 : "[Alternate Erase]", 180*e25b118aSDominic Spill 0x9A : "[SysReq/Attention]", 181*e25b118aSDominic Spill 0x9B : "[Cancel]", 182*e25b118aSDominic Spill 0x9C : "[Clear]", 183*e25b118aSDominic Spill 0x9D : "[Prior]", 184*e25b118aSDominic Spill 0x9E : "[Return]\n", 185*e25b118aSDominic Spill 0x9F : "[Separator]", 186*e25b118aSDominic Spill 0xA0 : "[Out]", 187*e25b118aSDominic Spill 0xA1 : "[Oper]", 188*e25b118aSDominic Spill 0xA2 : "[Clear/Again]", 189*e25b118aSDominic Spill 0xA3 : "[CrSel/Props]", 190*e25b118aSDominic Spill 0xA4 : "[ExSel]", 191*e25b118aSDominic Spill 0xB0 : "[Keypad 00]", 192*e25b118aSDominic Spill 0xB1 : "[Keypad 000]", 193*e25b118aSDominic Spill 0xB2 : "[Thousands Separator]", 194*e25b118aSDominic Spill 0xB3 : "[Decimal Separator]", 195*e25b118aSDominic Spill 0xB4 : "[Currency Unit]", 196*e25b118aSDominic Spill 0xB5 : "[Currency Sub-unit]", 197*e25b118aSDominic Spill 0xB6 : "[Keypad (]", 198*e25b118aSDominic Spill 0xB7 : "[Keypad )]", 199*e25b118aSDominic Spill 0xB8 : "[Keypad {]", 200*e25b118aSDominic Spill 0xB9 : "[Keypad }]", 201*e25b118aSDominic Spill 0xBA : "[Keypad Tab]\t", 202*e25b118aSDominic Spill 0xBB : "[Keypad Backspace]", 203*e25b118aSDominic Spill 0xBC : "[Keypad A]", 204*e25b118aSDominic Spill 0xBD : "[Keypad B]", 205*e25b118aSDominic Spill 0xBE : "[Keypad C]", 206*e25b118aSDominic Spill 0xBF : "[Keypad D]", 207*e25b118aSDominic Spill 0xC0 : "[Keypad E]", 208*e25b118aSDominic Spill 0xC1 : "[Keypad F]", 209*e25b118aSDominic Spill 0xC2 : "[Keypad XOR]", 210*e25b118aSDominic Spill 0xC3 : "[Keypad ^]", 211*e25b118aSDominic Spill 0xC4 : "[Keypad %]", 212*e25b118aSDominic Spill 0xC5 : "[Keypad <]", 213*e25b118aSDominic Spill 0xC6 : "[Keypad >]", 214*e25b118aSDominic Spill 0xC7 : "[Keypad &]", 215*e25b118aSDominic Spill 0xC8 : "[Keypad &&]", 216*e25b118aSDominic Spill 0xC9 : "[Keypad |]", 217*e25b118aSDominic Spill 0xCA : "[Keypad ||]", 218*e25b118aSDominic Spill 0xCB : "[Keypad :]", 219*e25b118aSDominic Spill 0xCC : "[Keypad #]", 220*e25b118aSDominic Spill 0xCD : "[Keypad Space]", 221*e25b118aSDominic Spill 0xCE : "[Keypad @]", 222*e25b118aSDominic Spill 0xCF : "[Keypad !]", 223*e25b118aSDominic Spill 0xD0 : "[Keypad Memory Store]", 224*e25b118aSDominic Spill 0xD1 : "[Keypad Memory Recall]", 225*e25b118aSDominic Spill 0xD2 : "[Keypad Memory Clear]", 226*e25b118aSDominic Spill 0xD3 : "[Keypad Memory Add]", 227*e25b118aSDominic Spill 0xD4 : "[Keypad Memory Subtract]", 228*e25b118aSDominic Spill 0xD5 : "[Keypad Memory Multiply]", 229*e25b118aSDominic Spill 0xD6 : "[Keypad Memory Divide]", 230*e25b118aSDominic Spill 0xD7 : "[Keypad +/-]", 231*e25b118aSDominic Spill 0xD8 : "[Keypad Clear]", 232*e25b118aSDominic Spill 0xD9 : "[Keypad Clear Entry]", 233*e25b118aSDominic Spill 0xDA : "[Keypad Binary]", 234*e25b118aSDominic Spill 0xDB : "[Keypad Octal]", 235*e25b118aSDominic Spill 0xDC : "[Keypad Decimal]", 236*e25b118aSDominic Spill 0xDD : "[Keypad Hexadecimal]", 237*e25b118aSDominic Spill 0xE0 : "[LeftControl]", 238*e25b118aSDominic Spill 0xE1 : "[LeftShift]", 239*e25b118aSDominic Spill 0xE2 : "[LeftAlt]", 240*e25b118aSDominic Spill 0xE3 : "[LeftWinKey]", 241*e25b118aSDominic Spill 0xE4 : "[RightControl]", 242*e25b118aSDominic Spill 0xE5 : "[RightShift]", 243*e25b118aSDominic Spill 0xE6 : "[RightAlt]", 244*e25b118aSDominic Spill 0xE7 : "[RightWinKey]" 245*e25b118aSDominic Spill} 246*e25b118aSDominic Spill 247*e25b118aSDominic Spill# some keycodes represent different things when Shift is held down 248*e25b118aSDominic SpillUSBHID_SHIFT_MAP = { 249*e25b118aSDominic Spill 0x04 : "A", 250*e25b118aSDominic Spill 0x05 : "B", 251*e25b118aSDominic Spill 0x06 : "C", 252*e25b118aSDominic Spill 0x07 : "D", 253*e25b118aSDominic Spill 0x08 : "E", 254*e25b118aSDominic Spill 0x09 : "F", 255*e25b118aSDominic Spill 0x0A : "G", 256*e25b118aSDominic Spill 0x0B : "H", 257*e25b118aSDominic Spill 0x0C : "I", 258*e25b118aSDominic Spill 0x0D : "J", 259*e25b118aSDominic Spill 0x0E : "K", 260*e25b118aSDominic Spill 0x0F : "L", 261*e25b118aSDominic Spill 0x10 : "M", 262*e25b118aSDominic Spill 0x11 : "N", 263*e25b118aSDominic Spill 0x12 : "O", 264*e25b118aSDominic Spill 0x13 : "P", 265*e25b118aSDominic Spill 0x14 : "Q", 266*e25b118aSDominic Spill 0x15 : "R", 267*e25b118aSDominic Spill 0x16 : "S", 268*e25b118aSDominic Spill 0x17 : "T", 269*e25b118aSDominic Spill 0x18 : "U", 270*e25b118aSDominic Spill 0x19 : "V", 271*e25b118aSDominic Spill 0x1A : "W", 272*e25b118aSDominic Spill 0x1B : "X", 273*e25b118aSDominic Spill 0x1C : "Y", 274*e25b118aSDominic Spill 0x1D : "Z", 275*e25b118aSDominic Spill 0x1E : "!", 276*e25b118aSDominic Spill 0x1F : "@", 277*e25b118aSDominic Spill 0x20 : "#", 278*e25b118aSDominic Spill 0x21 : "$", 279*e25b118aSDominic Spill 0x22 : "%", 280*e25b118aSDominic Spill 0x23 : "^", 281*e25b118aSDominic Spill 0x24 : "&", 282*e25b118aSDominic Spill 0x25 : "*", 283*e25b118aSDominic Spill 0x26 : "(", 284*e25b118aSDominic Spill 0x27 : ")", 285*e25b118aSDominic Spill 0x2D : "_", 286*e25b118aSDominic Spill 0x2E : "+", 287*e25b118aSDominic Spill 0x2F : "{", 288*e25b118aSDominic Spill 0x30 : "}", 289*e25b118aSDominic Spill 0x31 : "|", 290*e25b118aSDominic Spill 0x32 : "~", 291*e25b118aSDominic Spill 0x33 : ":", 292*e25b118aSDominic Spill 0x34 : "\"", 293*e25b118aSDominic Spill 0x35 : "~", 294*e25b118aSDominic Spill 0x36 : "<", 295*e25b118aSDominic Spill 0x37 : ">", 296*e25b118aSDominic Spill 0x38 : "?", 297*e25b118aSDominic Spill 0x64 : "|" 298*e25b118aSDominic Spill} 299*e25b118aSDominic Spill 300*e25b118aSDominic Spill# global variable to track currently depressed keys 301*e25b118aSDominic Spillactive_keys = [] 302*e25b118aSDominic Spill 303*e25b118aSDominic Spilldef hid2ascii(scancode, shift): 304*e25b118aSDominic Spill ''' 305*e25b118aSDominic Spill Convert the specified scancode value to the ASCII equivalent using the 306*e25b118aSDominic Spill USBHID_MAP list. 307*e25b118aSDominic Spill ''' 308*e25b118aSDominic Spill if shift: 309*e25b118aSDominic Spill try: 310*e25b118aSDominic Spill code = USBHID_SHIFT_MAP[scancode] 311*e25b118aSDominic Spill return code 312*e25b118aSDominic Spill except KeyError: 313*e25b118aSDominic Spill pass 314*e25b118aSDominic Spill try: 315*e25b118aSDominic Spill code = USBHID_MAP[scancode] 316*e25b118aSDominic Spill except KeyError: 317*e25b118aSDominic Spill return "[Reserved]" 318*e25b118aSDominic Spill return code 319*e25b118aSDominic Spill 320*e25b118aSDominic Spilldef usage(): 321*e25b118aSDominic Spill print >>sys.stderr, "Usage: btaptap [-r pcapfile.pcap] [-c count] [-h]\n" 322*e25b118aSDominic Spill sys.exit(0) 323*e25b118aSDominic Spill 324*e25b118aSDominic Spilldef parse_l2cap_keydata(l2cappkt): 325*e25b118aSDominic Spill global active_keys 326*e25b118aSDominic Spill 327*e25b118aSDominic Spill TRANS_HDR_IN_DATA = 0xA1 328*e25b118aSDominic Spill REPORT_ID_KEYBOARD = 0x01 329*e25b118aSDominic Spill CTRL = 1 330*e25b118aSDominic Spill SHIFT = 2 331*e25b118aSDominic Spill ALT = 4 332*e25b118aSDominic Spill GUI = 8 333*e25b118aSDominic Spill 334*e25b118aSDominic Spill # Keyboard keystrokes are only seen in L2CAP packets at least 10 bytes long 335*e25b118aSDominic Spill l2clen = (ord(l2cappkt[1]) << 8) | ord(l2cappkt[0]) 336*e25b118aSDominic Spill if l2clen < 10: 337*e25b118aSDominic Spill return 338*e25b118aSDominic Spill 339*e25b118aSDominic Spill # Keyboard keystrokes are only carried by Channel ID >= 0x40 340*e25b118aSDominic Spill cid = (ord(l2cappkt[3]) << 8) | ord(l2cappkt[2]) 341*e25b118aSDominic Spill if cid < 0x40: 342*e25b118aSDominic Spill return 343*e25b118aSDominic Spill # Ideally we would check for the particular CID for the HID_INTERRUPT 344*e25b118aSDominic Spill # channel, but we don't handle the negotiation (and may not have even 345*e25b118aSDominic Spill # seen it). 346*e25b118aSDominic Spill 347*e25b118aSDominic Spill # Transaction Header should indicate input data 348*e25b118aSDominic Spill thdr = ord(l2cappkt[4]) 349*e25b118aSDominic Spill if thdr != TRANS_HDR_IN_DATA: 350*e25b118aSDominic Spill return 351*e25b118aSDominic Spill 352*e25b118aSDominic Spill # Report ID should indicate this is a keyboard 353*e25b118aSDominic Spill rid = ord(l2cappkt[5]) 354*e25b118aSDominic Spill if rid != REPORT_ID_KEYBOARD: 355*e25b118aSDominic Spill return 356*e25b118aSDominic Spill 357*e25b118aSDominic Spill # This byte describes modifier key status (one bit per key) 358*e25b118aSDominic Spill mod = ord(l2cappkt[6]) 359*e25b118aSDominic Spill 360*e25b118aSDominic Spill # We don't care whether left or right modifier keys are pressed, so we 361*e25b118aSDominic Spill # combine the status bits. 362*e25b118aSDominic Spill leftmod = mod & 0x0f 363*e25b118aSDominic Spill rightmod = (mod & 0xf0) >> 4 364*e25b118aSDominic Spill mod = leftmod | rightmod 365*e25b118aSDominic Spill 366*e25b118aSDominic Spill # up to six keys can be reported at once 367*e25b118aSDominic Spill keycodes = [] 368*e25b118aSDominic Spill for byte in range(8,14): 369*e25b118aSDominic Spill keystroke = ord(l2cappkt[byte]) 370*e25b118aSDominic Spill if keystroke != 0x00: 371*e25b118aSDominic Spill keycodes.append(keystroke) 372*e25b118aSDominic Spill 373*e25b118aSDominic Spill for keystroke in keycodes: 374*e25b118aSDominic Spill # don't repeat keys that are still held down 375*e25b118aSDominic Spill if active_keys.count(keystroke) == 0: 376*e25b118aSDominic Spill 377*e25b118aSDominic Spill if (mod & CTRL): 378*e25b118aSDominic Spill sys.stdout.write("CTRL^") 379*e25b118aSDominic Spill if (mod & ALT): 380*e25b118aSDominic Spill sys.stdout.write("ALT^") 381*e25b118aSDominic Spill if (mod & GUI): # e.g. Windows key 382*e25b118aSDominic Spill sys.stdout.write("GUI^") 383*e25b118aSDominic Spill 384*e25b118aSDominic Spill sys.stdout.write(hid2ascii(keystroke, mod & SHIFT)) 385*e25b118aSDominic Spill 386*e25b118aSDominic Spill active_keys = keycodes 387*e25b118aSDominic Spill 388*e25b118aSDominic Spilldef parse_bb_keydata(packet): 389*e25b118aSDominic Spill 390*e25b118aSDominic Spill BTBBHDR_TYPE_MASK = 0x78 391*e25b118aSDominic Spill BTBBHDR_TYPE_SHIFT = 3 392*e25b118aSDominic Spill BTBBHDR_TYPE_DM1 = 3 393*e25b118aSDominic Spill BTBBPAYLOADHDR_LLID_MASK = 0x03 394*e25b118aSDominic Spill BTBBPAYLOADHDR_LLID_SHIFT = 0 395*e25b118aSDominic Spill BTBBPAYLOADHDR_LEN_MASK = 0xF8 396*e25b118aSDominic Spill BTBBPAYLOADHDR_LEN_SHIFT = 3 397*e25b118aSDominic Spill LLID_L2CAP = 2 398*e25b118aSDominic Spill 399*e25b118aSDominic Spill # Keyboard keystrokes are only seen in frames at least 40 bytes long 400*e25b118aSDominic Spill if len(packet) < 40: 401*e25b118aSDominic Spill return 402*e25b118aSDominic Spill 403*e25b118aSDominic Spill # Keyboard keystrokes are only seen in DM1 frames 404*e25b118aSDominic Spill btbbhdr = packet[20:23] 405*e25b118aSDominic Spill type = (ord(btbbhdr[0]) & BTBBHDR_TYPE_MASK) >> BTBBHDR_TYPE_SHIFT 406*e25b118aSDominic Spill if type != BTBBHDR_TYPE_DM1: 407*e25b118aSDominic Spill return 408*e25b118aSDominic Spill 409*e25b118aSDominic Spill # Keyboard keystrokes are only seen in L2CAP packets 14 bytes long 410*e25b118aSDominic Spill btbbpayloadhdr = ord(packet[23]) 411*e25b118aSDominic Spill llid = btbbpayloadhdr & (BTBBPAYLOADHDR_LLID_MASK) >> BTBBPAYLOADHDR_LLID_SHIFT 412*e25b118aSDominic Spill l2clen = (btbbpayloadhdr & BTBBPAYLOADHDR_LEN_MASK) >> BTBBPAYLOADHDR_LEN_SHIFT 413*e25b118aSDominic Spill #print "Debug btbbpayloadhdr 0x%02x, llid %d, l2clen %d"%(btbbpayloadhdr, llid, l2clen) 414*e25b118aSDominic Spill if llid != LLID_L2CAP or l2clen < 14: 415*e25b118aSDominic Spill return 416*e25b118aSDominic Spill 417*e25b118aSDominic Spill parse_l2cap_keydata(packet[24:38]) 418*e25b118aSDominic Spill 419*e25b118aSDominic Spilldef parse_hci_keydata(packet): 420*e25b118aSDominic Spill 421*e25b118aSDominic Spill HCI_TYPE_ACL_DATA = 2 422*e25b118aSDominic Spill 423*e25b118aSDominic Spill # Keyboard keystrokes are only seen in frames at least 19 bytes long 424*e25b118aSDominic Spill if len(packet) < 19: 425*e25b118aSDominic Spill return 426*e25b118aSDominic Spill 427*e25b118aSDominic Spill # Keyboard keystrokes are only seen in ACL Data frames 428*e25b118aSDominic Spill type = ord(packet[0]) 429*e25b118aSDominic Spill if type != HCI_TYPE_ACL_DATA: 430*e25b118aSDominic Spill return 431*e25b118aSDominic Spill 432*e25b118aSDominic Spill parse_l2cap_keydata(packet[5:]) 433*e25b118aSDominic Spill 434*e25b118aSDominic Spillif __name__ == '__main__': 435*e25b118aSDominic Spill 436*e25b118aSDominic Spill arg_pcapfile = None 437*e25b118aSDominic Spill arg_count = -1 438*e25b118aSDominic Spill packetcount = 0 439*e25b118aSDominic Spill 440*e25b118aSDominic Spill while len(sys.argv) > 1: 441*e25b118aSDominic Spill op = sys.argv.pop(1) 442*e25b118aSDominic Spill if op == '-r': 443*e25b118aSDominic Spill arg_pcapfile = sys.argv.pop(1) 444*e25b118aSDominic Spill if op == '-c': 445*e25b118aSDominic Spill arg_count = int(sys.argv.pop(1)) 446*e25b118aSDominic Spill if op == '-h': 447*e25b118aSDominic Spill usage() 448*e25b118aSDominic Spill sys.exit(0) 449*e25b118aSDominic Spill 450*e25b118aSDominic Spill if arg_pcapfile == None: 451*e25b118aSDominic Spill print >>sys.stderr, "Must specify a libpcap filename." 452*e25b118aSDominic Spill usage() 453*e25b118aSDominic Spill sys.exit(1) 454*e25b118aSDominic Spill 455*e25b118aSDominic Spill cap = PcapReader(arg_pcapfile) 456*e25b118aSDominic Spill 457*e25b118aSDominic Spill while arg_count != packetcount: 458*e25b118aSDominic Spill try: 459*e25b118aSDominic Spill (pheader, packet) = cap.pnext() 460*e25b118aSDominic Spill pkttime = pheader[0] 461*e25b118aSDominic Spill packetcount+=1 462*e25b118aSDominic Spill 463*e25b118aSDominic Spill if cap.datalink() == DLT_EN10MB: 464*e25b118aSDominic Spill parse_bb_keydata(packet) 465*e25b118aSDominic Spill elif cap.datalink() == DLT_BLUETOOTH_HCI_H4: 466*e25b118aSDominic Spill parse_hci_keydata(packet) 467*e25b118aSDominic Spill else: 468*e25b118aSDominic Spill print >>sys.stderr, "Unsupported libpcap data link layer: %d\n" % cap.datalink() 469*e25b118aSDominic Spill except TypeError: # raised when pnext returns Null (end of capture) 470*e25b118aSDominic Spill break 471*e25b118aSDominic Spill 472*e25b118aSDominic Spill cap.close() 473*e25b118aSDominic Spill print 474