Der P4wnP1 macht laune auf mehr, also habe ich mich entschlossen den zumodden. Ich habe mir ein Adafruit 128x64 OLED Bonnet Display besorgt, das Display ist nicht sehr gross aber es hat ein Joystick und 2 Tasten somit kann man zb ein Menu bauen wo es einem erlaubt den payload zu wechseln ohne sich direkt auf dem Pi0W ein zu loggen.

Das ganze habe ich in einem nachmittag zusammen gebastelt und eine sehr einfache App geschieben mit dem man die Payloads wechseln kann. Jetzt sieht das ganze schon eher aus wie ein Hollywood Hacking gadget.

display installation

sudo apt-get update
sudo apt-get install -y build-essential python-dev python-pip i2c-tools python-imaging python-smbus
sudo pip install RPi.GPIO
mkdir /home/pi/P4wnP1/OLED_Bonnet
cd /home/pi/P4wnP1/OLED_Bonnet
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
cd Adafruit_Python_SSD1306
sudo python setup.py install

Jetzt muss man nur noch den I2C einschalten

sudo raspi-config

Im menu Interfacing Options aktivieren wir den I2C

Bei Problemen sollte man diese Anleitung lesen. https://learn.adafruit.com/adafruit-128x64-oled-bonnet-for-raspberry-pi/usage

Die App für den Payload wechsel ist sehr einfach aufgebaut.

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import subprocess
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# Input pins:
L_pin = 27
R_pin = 23
C_pin = 4
U_pin = 17
D_pin = 22

A_pin = 5
B_pin = 6

GPIO.setmode(GPIO.BCM)

GPIO.setup(A_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(B_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(L_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(R_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(U_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(D_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(C_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up

RST = 24
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
disp.begin()
disp.clear()
disp.display()

width = disp.width
height = disp.height
image = Image.new('1', (width, height))

draw = ImageDraw.Draw(image)
draw.rectangle((0,0,width,height), outline=0, fill=0)

font = ImageFont.load_default()

x = 0
top = -2

def system_shutdown(max_row,payloads,pos_in_payloads,menu_cursor_pos):
 draw.rectangle((0,0,width,height), outline=0, fill=0)
 draw.text((x, top), "Shutdown P4wnP1",font=font, fill=255)
 draw.text((x, top+24), "to activate payload?",font=font, fill=255)
 draw.text((x, top+48), "Yes / No",font=font, fill=255)
 disp.image(image)
 disp.display()

 try:
  while 1:

   if not GPIO.input(A_pin):
    draw.rectangle((0,0,width,height), outline=0, fill=0)
    disp.image(image)
    disp.display()
    cmd = "sudo shutdown -h now"
    cmdout = subprocess.check_output(cmd, shell = True )

   if not GPIO.input(B_pin):
    draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos)

  time.sleep(.18)

 except KeyboardInterrupt:
  GPIO.cleanup()

def activate_payload(max_row,payloads,pos_in_payloads,menu_cursor_pos):
 # comment out active payload
 cmd = "sed -i -e '/^PAYLOAD=/s/^PAYLOAD=/#PAYLOAD=/' /home/pi/P4wnP1/setup.cfg"
 cmdout = subprocess.check_output(cmd, shell = True )

 # activate payload
 cmd = "sed -i -e '/#PAYLOAD=" + payloads[pos_in_payloads+menu_cursor_pos] + "/s/#PAYLOAD=/PAYLOAD=/' /home/pi/P4wnP1/setup.cfg"
 cmdout = subprocess.check_output(cmd, shell = True )

 system_shutdown(max_row,payloads,pos_in_payloads,menu_cursor_pos)

def select_payload(max_row,payloads,pos_in_payloads,menu_cursor_pos):
 draw.rectangle((0,0,width,height), outline=0, fill=0)
 draw.text((x, top), "Activate Payload ?",font=font, fill=255)
 draw.text((x, top+24), payloads[pos_in_payloads+menu_cursor_pos],font=font, fill=255)
 draw.text((x, top+48), "Yes / No",font=font, fill=255)
 disp.image(image)
 disp.display()

 try:
  while 1:
   if not GPIO.input(A_pin):
    activate_payload(max_row,payloads,pos_in_payloads,menu_cursor_pos)

   if not GPIO.input(B_pin):
    draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos)

  time.sleep(.18)

 except KeyboardInterrupt:
  GPIO.cleanup()

def draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos):
 draw.rectangle((0,0,width,height), outline=0, fill=0)
 draw.text((x, top), "Select Payload",font=font, fill=255)
 z = 0
 for i in payloads:
  if z > max_row - 1: # end of screen
   break
  if z + pos_in_payloads > len(payloads)-1: # end of payload list
   break
  if z == menu_cursor_pos:
   draw.text((x, top+12+(z*8)), ">" + payloads[z+pos_in_payloads],font=font, fill=255)
  else:
   draw.text((x, top+12+(z*8)), " " + payloads[z+pos_in_payloads],font=font, fill=255)
  z += 1

 disp.image(image)
 disp.display()
 buttons(max_row,payloads,pos_in_payloads,menu_cursor_pos)

# only up / down / center used
def buttons(max_row,payloads,pos_in_payloads,menu_cursor_pos):
 try:
  while 1:
   if not GPIO.input(U_pin):
    menu_cursor_pos -= 1

    if menu_cursor_pos < 0: # check if cursor is on top
     if pos_in_payloads > max_row -1: # check if we not on page 1
      pos_in_payloads -= max_row
      menu_cursor_pos = max_row -1
     else: # we are on top on page 1
      menu_cursor_pos = 0

    draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos)

   if not GPIO.input(D_pin):
    if pos_in_payloads + menu_cursor_pos != len(payloads)-1: # check if we are at the end of payloads
      menu_cursor_pos += 1

    if menu_cursor_pos > max_row -1 : # if cursor is at end of screnn jump to next page
     pos_in_payloads += max_row
     menu_cursor_pos = 0

    draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos)

   if not GPIO.input(C_pin):
    select_payload(max_row,payloads,pos_in_payloads,menu_cursor_pos)

   time.sleep(.18)

 except KeyboardInterrupt:
  GPIO.cleanup()

if __name__ == '__main__':
 # get list of payloads
 cmd = "cat /home/pi/P4wnP1/setup.cfg | grep 'PAYLOAD' |  grep -o '^[^#]*#\?[^#]*' | awk -F '=' '{print $2}' | awk -F '.' '{print $1}'"
 cmdout = subprocess.check_output(cmd, shell = True )
 payloads = cmdout.splitlines()
 max_row = 6
 menu_cursor_pos = 0
 pos_in_payloads = 0

 draw_menu(max_row,payloads,pos_in_payloads,menu_cursor_pos)

Um die App beim P4wnP1 booten automatisch zu starten, tragen wir die im /etc/rc.local vor dem exit 0 ein.

sudo python /home/pi/P4wnP1/OLED_Bonnet/pmenu.py  &

Um ein einbrennen des OLED Displays zu verhindern schalte ich die anzeige via crontab aus, wenn man den joystick bewegt kommt diese automatisch wieder zurück.

screen saver app clear.py

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
import subprocess
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# Input pins:
L_pin = 27
R_pin = 23
C_pin = 4
U_pin = 17
D_pin = 22

A_pin = 5
B_pin = 6

GPIO.setmode(GPIO.BCM)

GPIO.setup(A_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(B_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(L_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(R_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(U_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(D_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
GPIO.setup(C_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up

RST = 24
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
disp.begin()
disp.clear()
disp.display()

width = disp.width
height = disp.height
image = Image.new('1', (width, height))

draw = ImageDraw.Draw(image)
draw.rectangle((0,0,width,height), outline=0, fill=0)
disp.image(image)
disp.display()

crontab eintrag

*/5 * * * * /home/pi/P4wnP1/OLED_Bonnet/clear.py >/dev/null 2>&1

P4wnP1 https://github.com/mame82/P4wnP1

Adafruit 128x64 OLED Bonnet https://learn.adafruit.com/adafruit-128x64-oled-bonnet-for-raspberry-pi/overview