Advertisement
Guest User

Testing megadump from Fitbit Flex

a guest
Aug 28th, 2013
1,482
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import usb.core
  2. import usb.util
  3. import sys
  4.  
  5. from array import *
  6. from time import sleep
  7.  
  8.  
  9. # look for a fitbit flex, zip base station
  10.  
  11. dev = usb.core.find(idVendor=0x2687, idProduct=0xfb01)
  12.  
  13. if dev is None:
  14. raise ValueError('Couldn\'t find a Flex/Zip/One base station')
  15.  
  16. print('\n--=== Found a Fitbit Flex/Zip/One base station ===--\n')
  17.  
  18. sys.stdout.write('Device class: ' + str(dev.bDeviceClass) + '\n')
  19.  
  20.  
  21. cfg = dev.get_active_configuration();
  22.  
  23. # first interface is for passing data
  24.  
  25. intfData = cfg[(0,0)]
  26.  
  27.  
  28. if dev.is_kernel_driver_active(0) is True:
  29. print('we need to detach kernel driver for the Data interface')
  30.  
  31. try:
  32. # unload the kernel driver
  33. dev.detach_kernel_driver(0)
  34. except usb.core.USBError as err:
  35. sys.exit("Could not detach the kernel driver for Data interface: %s" % str(err))
  36.  
  37. # claim the interface
  38. # usb.util.claim_interface(0)
  39.  
  40.  
  41. if dev.is_kernel_driver_active(1) is True:
  42. print('we need to detach kernel driver for the Ctrl interface')
  43.  
  44. try:
  45. # unload the kernel driver
  46. dev.detach_kernel_driver(1)
  47. except usb.core.USBError as err:
  48. sys.exit("Could not detach the kernel driver for Ctrl interface: %s" % str(err))
  49.  
  50. # claim the interface
  51. # usb.util.claim_interface(1)
  52.  
  53. dev.set_configuration();
  54.  
  55.  
  56. # second interface is for control
  57.  
  58. intfCtrl = cfg[(1,0)]
  59.  
  60.  
  61.  
  62. # unload the kernel driver
  63.  
  64. # get the outgoing data endpoint (0x01) and incoming data ep (0x81)
  65.  
  66. ep81DataIn = intfData[0]
  67. ep01DataOut = intfData[1]
  68.  
  69. # get the outgoing control endpoint (0x02) and incoming ep (0x82)
  70.  
  71. ep82CtrlIn = intfData[0]
  72. ep02CtrlOut = intfData[1]
  73.  
  74. START_DISC = array('B',[0x1a,0x04,0xba,0x56,0x89,0xa6,0xfa,0xbf, \
  75. 0xa2,0xbd,0x01,0x46,0x7d,0x6e,0x00,0x00, \
  76. 0xab,0xad,0x00,0xfb,0x01,0xfb,0x02,0xfb, \
  77. 0xa0,0x0f,0x00,0xd3,0x00,0x00,0x00,0x00])
  78.  
  79. CANCEL_DISC = array('B',[0x02,0x05,0x00,0x00,0x00,0x00,0x00,0x00, \
  80. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  81. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  82. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
  83.  
  84.  
  85. # NOTE: My tracker ID is hardcoded in this command!
  86. # || || || || || ||
  87. ESTAB_LINK = array('B',[0x0B,0x06,0x4c,0x52,0x5b,0xf9,0xab,0xc8, \
  88. 0x01,0x00,0xfb,0x1b,0x00,0x00,0x00,0x07, \
  89. 0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x02, \
  90. 0x00,0x00,0x00,0xee,0x00,0x00,0x00,0x00])
  91.  
  92. ENABLE_TX_PIPE = array('B',[0x03,0x08,0x01,0x00,0x00,0x00,0x00,0x00, \
  93. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  94. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  95. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
  96.  
  97. DISABLE_TX_PIPE = array('B',[0x03,0x08,0x00,0x00,0x00,0x00,0x00,0x00, \
  98. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  99. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  100. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
  101.  
  102. INIT_AIRLINK = array('B',[0xc0,0x0a,0x0a,0x00,0x06,0x00,0x06,0x00, \
  103. 0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00, \
  104. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  105. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c])
  106.  
  107. START_MEGADUMP = array('B',[0xc0,0x10,0x0d,0x00,0x00,0x00,0x00,0x00, \
  108. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  109. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  110. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03])
  111.  
  112. TERM_AIRLINK = array('B',[0x02,0x07,0x00,0x00,0x00,0x00,0x06,0x00, \
  113. 0x00,0x00,0xc8,0x00,0x00,0x00,0x00,0x00, \
  114. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \
  115. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
  116.  
  117. xbuf = array('B',[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
  118.  
  119.  
  120. def printhex( data ):
  121. r = ''
  122. for num in ret:
  123. r += '%02X' % num
  124. r += ' '
  125. print( r )
  126.  
  127.  
  128.  
  129. # -------------------------------------------------------------
  130. # Step 1, cancel discovery & terminate link (force disconnect)
  131. # -------------------------------------------------------------
  132.  
  133. print ('\nCancel discovery and terminate link (reset)...')
  134.  
  135. xbuf[0] = 0x02
  136. xbuf[1] = 0x02
  137. xbuf[2] = 0x00
  138. dev.write(0x02, xbuf, intfCtrl.bInterfaceNumber, 32)
  139.  
  140. # expect: 0x20, 0x01, "CancelDiscovery" within ~2-5ms
  141. try:
  142. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  143. except:
  144. sys.exit("Timeout on cancel discovery & terminate handshake (1)")
  145. printhex( ret )
  146.  
  147. # expect 0x20, 0x01, "TerminateLink" within ~2ms
  148. try:
  149. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  150. except:
  151. sys.exit("Timeout on cancel discovery handshake (2)")
  152. printhex( ret )
  153.  
  154. # # expect 0x03, 0x02, 0x00, terminate link acknowledgement
  155. # however, it doesn't matter if not received. FBC doesn't care either.
  156. # try:
  157. # ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  158. # except:
  159. # sys.exit("Timeout on cancel discovery handshake (3)")
  160. # printhex( ret )
  161.  
  162. # -------------------------------------------------------------
  163. # Step 4, get dongle (base station) info
  164. # not really necessary to do a sync(?)
  165. # -------------------------------------------------------------
  166. print ('\nGet dongle info...')
  167.  
  168. # ??? wait ~ 500ms before issuing this command?
  169. sleep(0.500)
  170.  
  171. xbuf[0] = 0x02
  172. xbuf[1] = 0x01
  173. xbuf[2] = 0x00
  174. dev.write(0x02, xbuf, intfCtrl.bInterfaceNumber, 32)
  175.  
  176. # expect reply with dongle info within ~2ms
  177. try:
  178. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  179. except:
  180. sys.exit("Timeout on get dongle info handshake")
  181. printhex( ret )
  182.  
  183.  
  184. # -------------------------------------------------------------
  185. # Step 6, start discovery, wait up to 2 seconds for a response
  186. # -------------------------------------------------------------
  187. print ('\nStart discovery...')
  188.  
  189. # send 0x1a, 0x04...
  190. dev.write(0x02, START_DISC, intfCtrl.bInterfaceNumber, 32)
  191.  
  192. # expect: 0x20, 0x01, "StartDiscovery"
  193. # about 4 ms after prev command
  194. try:
  195. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  196. except:
  197. sys.exit("Timeout on start discovery handshake")
  198.  
  199. printhex( ret )
  200.  
  201. # TODO: if no response, cancel discovery and repeat
  202.  
  203. #
  204.  
  205. print ('\nWaiting for discovery...')
  206.  
  207. # NOTE: FitbitConnect program only waits about 2000 ms before
  208. # giving up and starting over.
  209.  
  210. # expect: 0x13, 0x03 plus tracker ID plus RSSI plus other unknown stuff
  211. # FitbitConnect doesn't seem to accept less than about
  212. # -80 dBm for RSSI.
  213. try:
  214. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 10000)
  215. except:
  216. sys.exit("No answer on discovery - tracker not found.")
  217. printhex( ret )
  218.  
  219. # expect: 0x03, 0x02, 0x01
  220. try:
  221. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 10000)
  222. except:
  223. sys.exit("No ACK discovery - tracker found but what went wrong?")
  224. printhex( ret )
  225.  
  226.  
  227.  
  228. # extract tracker ID from data, same as NFC ID
  229. # TODO:
  230. # if response received, get tracker ID and feed it back to dongle with
  231. # EstablishLink command
  232.  
  233.  
  234.  
  235. # -------------------------------------------------------------
  236. # Step 9, cancel discovery in prep for connecting to tracker
  237. # -------------------------------------------------------------
  238.  
  239. print ('\nGot a tracker, cancel discovery...')
  240.  
  241. # send 0x02, 0x05
  242. dev.write(0x02, CANCEL_DISC, intfCtrl.bInterfaceNumber, 32)
  243. # expect: 0x03, 0x02, 0x01
  244. try:
  245. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  246. except:
  247. sys.exit("Timeout on cancel discovery handshake")
  248. printhex( ret )
  249.  
  250. sleep(2.000)
  251.  
  252. # expect: 0x20, 0x01, "CancelDiscovery"
  253. try:
  254. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 500)
  255. except:
  256. sys.exit("Timeout on cancel discovery handshake")
  257. printhex( ret )
  258.  
  259.  
  260. # -------------------------------------------------------------
  261. # Step 11, establish link, wait up to 2 seconds for a response
  262. # -------------------------------------------------------------
  263. print ('\nEstablishing link...')
  264.  
  265. # TODO: use tracker ID from discovery in this pkt, not hardcoded!
  266.  
  267. # send 0x0b, 0x06...
  268. dev.write(0x02, ESTAB_LINK, intfCtrl.bInterfaceNumber, 32)
  269.  
  270. # expect: 0x20, 0x01, "EstablishLink" on read
  271. # dongle ACKing the request to link to tracker
  272. try:
  273. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 5000)
  274. except:
  275. sys.exit("Timeout on establish link handshake (1)")
  276. printhex( ret )
  277.  
  278. # expect: 0x03, 0x04 on read
  279. # dongle indicating link made?
  280. # about 400 ms after previous recv pkt
  281. try:
  282. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 5000)
  283. except:
  284. sys.exit("Timeout on establish link handshake (2)")
  285. printhex( ret )
  286.  
  287. # expect: 0x20, 0x01, "GAP_LINK_ESTABLISHED_EVENT" on read
  288. # dongle indicating link made.
  289. # about 1 ms after previous recv pkt
  290. try:
  291. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 15000)
  292. except:
  293. sys.exit("Timeout on establish link handshake (3)")
  294. printhex( ret )
  295.  
  296. # expect: 0x02, 0x07 on read
  297. # dongle indicating what?
  298. # about 750 to 1600 ms after previous recv pkt
  299. try:
  300. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 15000)
  301. except:
  302. # sys.exit("Timeout on establish link handshake (4)")
  303. print("Timeout on establish link handshake (4), proceeding anyway")
  304. printhex( ret )
  305.  
  306.  
  307. # -------------------------------------------------------------
  308. # Step 16, enable TX pipe, wait up to 2 seconds for a response
  309. # -------------------------------------------------------------
  310. print ('\nEnable TX pipe...')
  311.  
  312. # send 0x03, 0x08, 0x01
  313. dev.write(0x02, ENABLE_TX_PIPE, intfCtrl.bInterfaceNumber, 32)
  314.  
  315. # note response is from data in endpoint
  316.  
  317. # expect: 0xc0, 0x0b on read
  318. # about 300 ms after previous command
  319. #
  320. try:
  321. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 5000)
  322. except:
  323. # sys.exit("Timeout on enable TX pipe handshake")
  324. print( "Hrmmm, didn't get expected C00B from the data intf, proceeding")
  325. printhex( ret )
  326.  
  327.  
  328. # -------------------------------------------------------------
  329. # Step 18, initialize airlink, wait up to 5 seconds for a response
  330. # -------------------------------------------------------------
  331. print ('\nInit airlink...')
  332.  
  333. # send 0xc0, 0x0a, 0x0a ...
  334. dev.write(0x01, INIT_AIRLINK, intfData.bInterfaceNumber, 32)
  335.  
  336. # TX pipe open/airlink up
  337. # expect: 0x08, 0x06 on read
  338. # about 3000 ms after prev command on data intf
  339. try:
  340. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 10000)
  341. except:
  342. sys.exit("Timeout on init airlink handshake (1)")
  343. printhex( ret )
  344.  
  345. # airlink up, read tracker info
  346. # @#@#@# this is where it's hanging up...
  347. # expect: 0xc0, 0x14 plus tracker ID on read
  348. # about 100 ms after prev recv pkt on ctrl intf
  349. try:
  350. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 10000)
  351. except:
  352. sys.exit("Timeout on init airlink handshake (2)")
  353. printhex( ret )
  354.  
  355.  
  356. # -------------------------------------------------------------
  357. # Step 21, begin megadump
  358. # -------------------------------------------------------------
  359. print ('\nBegin megadump...')
  360.  
  361. # send 0xc0, 0x10, 0x0d
  362. dev.write(0x01, START_MEGADUMP, intfData.bInterfaceNumber, 32)
  363. # Read expected ACK to start of megadump
  364. try:
  365. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 500)
  366. except:
  367. sys.exit("Timeout on begin megadump handshake")
  368. printhex( ret )
  369.  
  370. # expect: 0xc0 0x41 0x0d
  371. try:
  372. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 500)
  373. except:
  374. sys.exit("Timeout on megadump header")
  375. printhex( ret )
  376.  
  377. # Read expected header of megadump (starts with 0x28 0x02
  378. try:
  379. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 500)
  380. except:
  381. sys.exit("Timeout on megadump header")
  382. printhex( ret )
  383.  
  384. # -------------------------------------------------------------
  385. # read megadump in a loop, stop when datalen < 20
  386. # -------------------------------------------------------------
  387. while True:
  388. try:
  389. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 500)
  390. except:
  391. sys.exit("Timeout on megadump data")
  392. printhex( ret )
  393. if ret[31] < 20:
  394. break
  395.  
  396.  
  397. # step 25
  398. # read megadump footer (0xc0 0x42 ...)
  399.  
  400. try:
  401. ret = dev.read (0x81, 32, intfData.bInterfaceNumber, 500)
  402. except:
  403. sys.exit("Timeout on megadump footer")
  404. printhex( ret )
  405.  
  406. # -------------------------------------------------------------
  407. # step 28, start server data dump to tracker
  408. # -------------------------------------------------------------
  409. # @#@#@# not implemented
  410.  
  411. # -------------------------------------------------------------
  412. # Step 37, disable TX pipe
  413. # -------------------------------------------------------------
  414. print ('\nDisable TX pipe...')
  415.  
  416. # send 0x03, 0x08, 0x00
  417. dev.write(0x02, DISABLE_TX_PIPE, intfCtrl.bInterfaceNumber, 32)
  418. # note response is from data in endpoint
  419. # expect: 0xc0 0x0b
  420. try:
  421. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 5000)
  422. except:
  423. sys.exit("Timeout on disable TX pipe handshake")
  424. printhex( ret )
  425.  
  426. # -------------------------------------------------------------
  427. # Step 39, terminate link
  428. # -------------------------------------------------------------
  429. print ('\nTerminate airlink...')
  430.  
  431. # send 0x02, 0x07
  432. dev.write(0x02, TERM_AIRLINK, intfCtrl.bInterfaceNumber, 32)
  433. # expect: 0x20, 0x01, "TerminateLink"
  434. try:
  435. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 5000)
  436. except:
  437. sys.exit("Timeout on terminate airlink handshake (1)")
  438. printhex( ret )
  439.  
  440. # expect: 0x03, 0x05, 0x16
  441. try:
  442. ret = dev.read (0x82, 32, intfCtrl.bInterfaceNumber, 5000)
  443. except:
  444. sys.exit("Timeout on terminate airlink handshake (2)")
  445. printhex( ret )
Advertisement
RAW Paste Data Copied
Advertisement