Created
January 29, 2021 07:55
-
-
Save finnmglas/f7b299d86a4d537404dbb82c187633b4 to your computer and use it in GitHub Desktop.
Create arduino C++ code from duckyscripts
This file contains 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
#This script will be used to translate duckyscript | |
#(see https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Duckyscript) | |
#To C / C++ source code which can be compiled for the Digistump AVR Boards | |
#(also called Digispark) | |
#Makes use of https://github.com/adnan-alhomssi/DigistumpArduinoDe/blob/master/digistump-avr/libraries/DigisparkKeyboard/DigiKeyboardDe.h | |
#Last Edit: 18.09.2019 | |
import getopt, sys | |
inputfile = "" #duckyscript file | |
outfile = "" #arduino file | |
hidecomments = False #if false the REM comments are put behind "//" | |
lang = "De" #De | |
ledpin = 1 | |
startdelay = 1000 #Depends on your device speed/ security | |
#show the documentation | |
def usage(): | |
print("\nDuckyscript to Arudino C Translator\n") | |
print("Usage:\n") | |
print("\t-h, --help\t|\tdisplays this text\n") | |
print("\t-o, --output\t|\tspecify the output ino file\n") | |
print("\t-c, --content\t|\tspecify the duckyscript file\n") | |
print("\t-n, --nocomment\t|\tcomments are hidden") | |
sys.exit(0) | |
#Dictionaries needed for the translation Process | |
chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', | |
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', | |
'y', 'z', 'c', 'd', '1', '2', '3', '4', '5', '6', '7', '8', | |
'9', '0'] | |
strokes = {**dict([("f"+str(fn),"KEY_F"+str(fn)) for fn in range(1, 13)]), | |
**dict([(char, "KEY_"+char.upper()) for char in chars]), | |
'delete': '42', 'home': '74', 'insert': '73', 'pageup': '75', | |
'pagedown': '78', 'windows': 'MOD_GUI_LEFT', 'gui': 'MOD_GUI_LEFT', | |
'uparrow': '82', 'downarrow': '81', 'leftarrow': '80', | |
'rightarrow': '79', 'tab': '43', 'esc': '41', 'escape': '41', | |
'space': 'KEY_SPACE', 'up': '82', 'down': '81', 'left': '80', | |
'right': '79', 'pause': '72', 'shift': '225', 'alt': 'MOD_ALT_LEFT', | |
'break': 'KEY_ENTER', 'enter': 'KEY_ENTER', 'ctrl':'MOD_CONTROL_LEFT', | |
'control':'MOD_CONTROL_LEFT', 'menu':'101', 'app':'101'} | |
def match(dictionary, index, line): | |
try: | |
return dictionary[index] | |
except: | |
print("\nSyntax Error in line ", line, ":") | |
print(index, "could not be matched") | |
sys.exit(0) | |
#This is the core function of this script... everything else is only a wrapper for it | |
def translate(script): | |
rval = """ | |
#include "DigiKeyboard"""+lang+""".h" | |
void setup() { | |
\tpinMode("""+str(ledpin)+""", OUTPUT); //Initialise the onboard LED | |
\tDigiKeyboard"""+lang+""".delay("""+str(startdelay)+"""); | |
""" #will be returned in the end | |
script = script.replace("\r","").split("\n") | |
ddelay = "0" #delay between strokes | |
linetranslation = "" | |
for n in range(len(script)): | |
line = script[n] | |
#prevent empty lines from being analyzed | |
if line == "": | |
rval += "\n" | |
continue | |
#split the line to analyse it | |
line = line.split(" ") | |
command = line[0] | |
args = " ".join(str(i) for i in line[1:]) | |
#Repeat command (for loop) | |
if command == "REPEAT": | |
try: | |
int(args) | |
except: | |
print("\nSyntax Error in line ", n+1, ": ", command, " requires") | |
print("an integer as argument... \"", args, "\" is not one") | |
sys.exit(0) | |
rval += "\tfor(int i=0; i<"+args+"; i++){\n"+linetranslation+"\t}\n" | |
continue | |
linetranslation = "" | |
#insert a default delay | |
if ddelay != "0" and command not in ("DEFAULTDELAY", "DEFAULT_DELAY", | |
"REM", "DELAY"): | |
linetranslation += "\tDigiKeyboard"+lang+".delay("+ddelay+");\n" | |
#Translation of a single line | |
#Comments | |
if command == "REM": | |
if not hidecomments: | |
linetranslation += "\t//"+args+"\n" | |
#Default delay between strokes | |
elif command in ("DEFAULTDELAY","DEFAULT_DELAY"): | |
try: | |
int(args) | |
except: | |
print("\nSyntax Error in line ", n+1, ": ", command, " requires") | |
print("an integer as argument... \"", args, "\" is not one") | |
sys.exit(0) | |
ddelay = args | |
#delay | |
elif command in ("DELAY", "SLEEP"): | |
try: | |
int(args) | |
except: | |
print("\nSyntax Error in line ", n+1, ": ", command, " requires") | |
print("an integer as argument... \"", args, "\" is not one") | |
sys.exit(0) | |
linetranslation += "\tDigiKeyboard"+lang+".delay("+args+");\n" | |
#Strings | |
elif command == "STRING": | |
linetranslation += "\tDigiKeyboard"+lang+".print(\""+args.replace("\\", "\\\\").replace("\"", "\\\"")+"\");\n" | |
#One Keystroke | |
elif len(line) == 1: | |
try: | |
linetranslation += "\tDigiKeyboard"+lang+".sendKeyStroke("+strokes[line[0].lower()]+");\n" | |
except: | |
print("\nSyntax Error in line ", n+1, ": ", command, " is") | |
print("not recognized") | |
sys.exit(0) | |
#two Keystrokes | |
elif len(line) == 2: | |
try: | |
linetranslation += "\tDigiKeyboard"+lang+".sendKeyStroke("+strokes[line[1].lower()]+", "+strokes[line[0].lower()]+");\n" | |
except: | |
print("\nSyntax Error in line ", n+1, ": command is") | |
print("not recognized") | |
sys.exit(0) | |
#too long | |
else: | |
print("\nSyntax Error in line ", n+1, ": to many keystrokes") | |
print("in one single line!!!") | |
sys.exit(0) | |
rval += linetranslation | |
rval += """} | |
//Blink to show that the attack is done | |
void loop() { | |
\tdigitalWrite("""+str(ledpin)+""", HIGH); | |
\tdelay(200); | |
\tdigitalWrite("""+str(ledpin)+""", LOW); | |
\tdelay(200); | |
}""" #is executed after the attack | |
return rval | |
#Here the actual script starts i guess haha | |
#Parse all commandline arguments | |
try: | |
opts, args = getopt.getopt(sys.argv[1:],"ho:c:n", | |
["help","output","content","nocomment"]) | |
except getopt.GetoptError as err: | |
print(str(err)) | |
usage() | |
for o,a in opts: | |
if o in ("-h","--help"): | |
usage() | |
elif o in ("-o", "--output"): | |
outfile = a | |
elif o in ("-c", "--content"): | |
inputfile = a | |
elif o in ("-n", "--nocomment"): | |
hidecomments = True | |
else: | |
assert False,"Unhandled Option" | |
if inputfile == "": | |
if len(sys.argv)>1 and sys.argv[1].split(".")[len(sys.argv[1].split("."))-1] in ("txt", "ds"): | |
inputfile = sys.argv[1] | |
else: | |
usage() | |
#Try opening the file and reading from it | |
try: | |
file = open(inputfile) | |
filecontent = file.read() | |
file.close() | |
except: | |
print("Error occured during reading the file") | |
print("Make sure it actually exists\n") | |
usage() | |
if filecontent == "": | |
print("Error: file is empty\n") | |
usage() | |
if outfile == "": | |
outfile = ".".join(inputfile.split(".")[:-1]) + ".ino" | |
#Translate and write to the outfile | |
output = translate(filecontent) | |
file = open(outfile, "w") | |
file.write(output) | |
file.close() | |
print("\nSuccessfully translated", inputfile, "to ", outfile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment