# GodMode9 "Hello Script" # Tutorial script - read / run this to learn how it works # last changed: 20170906 # author: d0k3 # COMMENTS / SCRIPTING BASICS / 'echo' COMMAND # Anything after '#' will be ignored by the scripting engine # Commands and arguments are separated by whitespaces, any redundant whitespaces will be ignored # Use '"' if an argument has to include whitespaces # The echo command outputs info on screen echo "'Hello Script'\nby d0k3\n \nThis is a sample script to\nshowcase the GM9 script engine." # comments work anywhere # Unknown commands lead to script abort (remove the '#' below to test) # iamunknown test test # 'qr' COMMAND # The 'qr' command does the same as the echo command, but also displays a QR code on the top screen qr "Scan for cool stuff!" https://github.com/d0k3/GodMode9 # 'ask' COMMAND # The 'ask' command is similar to the 'echo' command, but will allow the user to abort # Note that normally any failed command (like a negative user response on 'ask') will result in script abort ask "Continue running this script?" # (-o/-s) SWITCHES # You may use the -o / --optional and -s / --silent switches on any command # -o / --optional continues on failures # -s / --silent tries to suppress all error messages # This would have completely ignored the user response on the previous command: ask -o -s "Really continue running this script?\n(I will completely ignore your answer)" # ENVIRONMENTAL VARS # GM9VER is the GodMode9 version number # REGION is the region of your device's SysNAND (USA, EUR, JPN, KOR, CHN, TWN or UNK for unknown) # SERIAL is the serial number of your device # GM9OUT is the standard output path # CURRDIR is the directory the script is running from # HAX is the hax the system is currently running from ("ntrboot", "sighax", "a9lh" or empty) # ONTYPE is the console type ("O3DS" or "N3DS") # RDTYPE is the unit type ("devkit" or "retail") # SYSID0 is the id0 belonging to your SysNAND # EMUID0 is the id0 belonging to your EmuNAND (if available) # TIMESTAMP is the current time in hhmmss format # DATESTAMP is the current date in YYMMDD format # Use $[VAR] to get the *content* of a variable VAR echo "Your GodMode9 version is $[GM9VER]\nYour region is $[REGION]\nYour serial number is $[SERIAL]\nYour std output path is $[GM9OUT]\nCurrent dir is $[CURRDIR]\nCurrent hax is $[HAX]\nYour system is a $[RDTYPE] $[ONTYPE]\nCurrent datestamp is: $[DATESTAMP]\nCurrent timestamp is: $[TIMESTAMP]\n \nYour sys / emu ID0 is:\n$[SYSID0]\n$[EMUID0]" qr "You can also have this as a QR code :)" "Your GodMode9 version is $[GM9VER]\nYour region is $[REGION]\nYour serial number is $[SERIAL]\nYour std output path is $[GM9OUT]\nCurrent dir is $[CURRDIR]\nCurrent hax is $[HAX]\nYour system is a $[RDTYPE] $[ONTYPE]\nCurrent datestamp is: $[DATESTAMP]\nCurrent timestamp is: $[TIMESTAMP]\n \nYour sys / emu ID0 is:\n$[SYSID0]\n$[EMUID0]" # ERRORMSG and SUCCESSMSG / 'set' COMMAND # These two are special environment vars, allowing you to control the message on script failure or success set ERRORMSG "HelloScript testing script failed" set SUCCESSMSG "HelloScript testing script success" # you can also reset these to return to default script messages # set ERRORMSG "" # set SUCCESSMSG "" # 'chk' COMMAND # Using the check command, you can check if two arguments match (not case sensitive) # -u / -unequal check if not matching instead # These checks will (most likely) pass chk "hello" "HeLlo" chk "0:/gm9/out" $[GM9OUT] chk $[SYSID0] $[SYSID0] # unsure about these chk -o $[HAX] "sighax" chk -o -u $[HAX] "" # PREVIEW_MODE, PREVIEW_COLOR_ACTIVE, PREVIEW_COLOR_COMMENT and PREVIEW_COLOR_CODE # PREVIEW_MODE controls how the preview on the top screen is displayed, set it it to off, quick or full # PREVIEW_COLOR_ACTIVE, PREVIEW_COLOR_COMMENT and PREVIEW_COLOR_CODE set the colors of the preview (RGB, hex) set PREVIEW_MODE quick # we don't want these ugly colors # set PREVIEW_COLOR_ACTIVE 00FF00 # set PREVIEW_COLOR_COMMENT 0000FF # set PREVIEW_COLOR_CODE FF0000 # CREATING VARS # You can also create new variables using 'set' # Notice how you can use variables when setting variables set TESTPATH 0:/testdir/$[SERIAL]_tick.db echo "Your testpath is:\n$[TESTPATH]" # 'input' COMMAND # The 'input' command will allow the user to input a string and store that string in a variable # Preset the variable to have an initial value set USERINPUT "Hello World" input "Enter something please?" USERINPUT echo "You entered:\n$[USERINPUT]" # 'strsplit' COMMAND # The 'strsplit' command extracts a substring from a string # -b / --before extracts the substring *before* the split char # -f / --first matches the first, not last occurence of the split char strsplit TESTSPLIT1 "one/two/three" "/" strsplit -b TESTSPLIT2 "one/two/three" "/" strsplit -f TESTSPLIT3 "one/two/three" "/" strsplit -b -f TESTSPLIT4 "one/two/three" "/" echo "one/two/three\n$[TESTSPLIT1]\n$[TESTSPLIT2]\n$[TESTSPLIT3]\n$[TESTSPLIT4]" # strrep COMMAND # The 'strrep' command replaces one char with another inside a string # notice how we use TESTREP both as input and output set TESTREP "Hello_World" strrep TESTREP $[TESTREP] "_ " echo $[TESTREP] # 'filesel' COMMAND # The 'filesel' command allows the user to choose a file inside a directory # The path is stored inside a variable, and the selection can be limited via wildcards # -d / --include_dirs allows to browse folders and select files inside # -x / --explorer uses new style file selector like main file explorer filesel "Please select a file" 0:/*.* SELFILE # 'dirsel' COMMAND # The 'dirsel' command works identically to the 'filesel' command, but allows selecting a dir # Note that a final slash ('/') is not expected here and there can be no wildcard pattern. # -x / --explorer uses new style file selector like main file explorer dirsel "Now, select a dir" 0: SELDIR echo "You selected $[SELFILE]\nand $[SELDIR]\nWe'll do nothing with either :)." # 'allow' COMMAND # typically used at the beginning of a script, prompts to allow writes to the location given in the argument # doing this from the beginning is preferable, so that no actions are taken unless all required write permissions are unlocked # (note #1: without 'allow', write permissions are still in place and the user will be asked on demand) # (note #2: this simple testing script requires no additional permissions, thus the command is hidden behind a '#') # -a / --all allows writes to the specified location and all included files and directories # allow -a M:/ # 'rm' COMMAND # The 'rm' command is used to remove files and directories (recursively) # Here, we remove the dir if it is still here from an earlier run of this script # If it is not here, we ignore any errors and keep silent about it rm -o -s 0:/testdir # 'mkdir' COMMAND # Use this to create a directory at the specified location mkdir 0:/testdir # 'imgmount' COMMAND # The 'imgmount' command is used to mount an image. # An image can be (among other things) FAT, NAND, NCCH, NCSD, FIRM, ticket.db... imgmount S:/ctrnand_full.bin # 'cp' COMMAND # Use 'cp' to copy a file or directory (recursively) # -h / --hash also adds a .sha file containing the files SHA256 # -w / --overwrite forces overwrite on existing files (disables -k and -p) # -k / --skip forces skip on existing files (disables -p) # -p / --append will append copied files to the end of existing files (disables -h) # -n / --no_cancel prevents user cancels (useful on critical operations) cp -h -w -n 7:/dbs/ticket.db $[TESTPATH] # 'imgumount' COMMAND # This unmounts the current mounted image. imgumount # 'findnot' COMMAND # Use 'findnot' in conjunction with '?' to find an unused filename findnot $[TESTPATH]_???.rn RENPATH # 'mv' COMMAND # The 'mv' command renames or moves a file or directory # -w / --overwrite forces overwrite on existing files (disables -k) # -k / --skip forces skip on existing files # -n / --no_cancel prevents user cancels (useful on critical operations) mv -w -k $[TESTPATH] $[RENPATH] # 'find' COMMAND # The 'find' command has two main uses, (1) checking if files / dirs exist and (2) finding files / dirs # Here we use it to check for RENPATH, thus we use NULL as second argument (we're not interested in the output) find $[RENPATH] NULL # Wildcards ('*' / '?') are allowed when searching for a file / directory name # If wildcards are used, 'find' will return the last alphanumerical match # -f / --first return the first alphanumerical match instead find S:/nand.* NANDIMAGE # 'sha' COMMAND # Use this to check a files' SHA256 sha $[RENPATH] $[TESTPATH].sha # Instead of an .sha file you can also use the SHA256 in hex as second argument # sha S:/sector0x96.bin 82F2730D2C2DA3F30165F987FDCCAC5CBAB24B4E5F65C981CD7BE6F438E6D9D3 # This also allows partial SHA checks (for @x:y handling see 'inject' below) # sha S:/firm0.bin@100:100 078CC0CFD850A27093DDA2630C3603CA0C96969BD1F26DA48AC7B1BAE5DD5219 # 'shaget' COMMAND # Use this to calculate (and store) a files' SHA256 # If the second argument is a filename, the SHA256 will be stored there # shaget 0:/boot.firm 0:/boot.firm.sha # If it's a variable, it will be stored there temporarily instead shaget S:/nand_hdr.bin NANDHDRSHA sha S:/nand_hdr.bin $[NANDHDRSHA] # Partial SHA calculation is also possible (for @x:y handling see 'inject' below) # shaget 0:/boot.firm@100:100 0:/boot.firm.partial.sha # 'inject' COMMAND # This command is used to inject part of one file into another # The syntax is: inject origin@x:y destination@z # x: origin offset (in hex) # y: origin size, starting at x (in hex) # z: destination offset (in hex) # If destination does not exist or z is not given, a new destination file will be created(!) # If x is not given, the full origin file size, starting from offset 0, is used to inject # If y is not given, everything starting from offset x is used to inject # -n / --no_cancel prevents user cancels (useful on critical operations) inject S:/nand_hdr.bin@100:4 $[RENPATH]@200 # offsets and sizes are in hex # As we just deliberately corrupted our test file, the subsequent SHA check will fail set ERRORMSG "SHA check failed (this was expected)" sha -o $[RENPATH] $[TESTPATH].sha set ERRORMSG "" # 'fdummy' COMMAND # This command creates a dummy file of the specified size (size in hex) # Contents of the dummy file are undefined and existing files won't be overwritten set DUMMY 0:/testdir/dummy.bin fdummy $[DUMMY] 400 # 'fill' COMMAND # This command fills (a portition of) a file with the specified byte value # The syntax is: fill destination@x:y fillbyte # x: destination offset (in hex) # y: destination size, starting at x (in hex) # If x is not given, the full file size, starting from offset 0, is overwritten # If y is not given, everything starting from offset x is overwritten # -n / --no_cancel prevents user cancels (useful on critical operations) fill $[DUMMY]@100:100 FF fill $[DUMMY]@300 80 # 'fset' COMMAND # This command sets a portition of a file with the specified data in hex # The syntax is: fset destination@x hexdata # x: destination offset (in hex) # y: bytes to write (in hex) (must be lower than hexdata size) # If x is not given, data is inserted at the beginning of the file # If y is not given, all of hexdata is written to the file # -e / --flip_endian flips the order of the bytes fset $[DUMMY]@100 48454c4c4f # 'HELLO' # 'fget' COMMAND # This command reads data from a file and stores it in a var # The syntax is: fset origin@x:y var # x: origin offset (in hex) # y: origin size, starting at x (in hex) # Both x and y have to be set(!) # -e / --flip_endian flips the order of the bytes fget -e $[DUMMY]@100:5 OLLEH echo "This is 'HELLO', in hex and reverse:\n$[OLLEH]" # 'dumptxt' COMMAND # This command dumps the given text to a file # -p / --append appends text instead of writing a new file # dumptxt 0:/hello.txt HELLO # dumptxt -p 0:/hello.txt WORLD # 'fixcmac' COMMAND # Use this to fix the CMACs for a file or a whole folder (recursively) # This will count as success if a file does not contain a CMAC # More info on CMACs: http://3dbrew.org/wiki/Savegames#AES_CMAC_header # fixcmac 1:/data # 'verify' COMMAND # Certain file formats (NAND, NCCH, NCSD, CIA, FIRM, ...) can also be verified. Use 'verify' to do so. # verify -o s:/firm0.bin # As drive letters are case sensitive, this would fail verify S:/firm1.bin # 'decrypt' COMMAND # Certain file formats (NCCH, NCSD, CIA, FIRM, BOSS, ...) can be decrypted. Use 'decrypt' to do so. # Take note that all crypto operations are done INPLACE and will overwrite the file(!) # decrypt 0:/x.ncch # 'encrypt' COMMAND # Certain file formats (NCCH, NCSD, CIA, BOSS, ...) can be encrypted. Use 'encrypt' to do so. # Take note that all crypto operations are done INPLACE and will overwrite the file(!) # encrypt 0:/x.ncch # 'buildcia' COMMAND # You can build CIA files from certain file formats (TMD, NCCH, NCSD ...). Use 'buildcia' to do so. # CIA files will always be built to the standard output directory (0:/gm9/out) # -l / --legit force CIA to be legit (only works for legit system installed titles) # buildcia 0:/x.ncch # 'extrcode' COMMAND # You can extract the binary code from any file that contains it (NCSD, NCCH, CXI). # Specify the containing file and the file to write to. # If the code is compressed, it will be decompressed. # C:/titleid.3ds 0:/gm9/out/titleid.dec.code # 'cmprcode' COMMAND # Attempt to open a file as uncompressed binary code and compress it into the 3DS's reverse LZSS format. # Specify the source file and the file to write to. # 0:/gm9/out/titleid.dec.code 0:/gm9/out/titleid.code # 'sdump' COMMAND # This command dumps a supported file to the standard output directory (0:/gm9/out) # Supported files: encTitleKeys.bin, decTitleKeys.bin, seeddb.bin # -w / --overwrite overwrite existing files without asking # sdump encTitleKeys.bin # sdump decTitleKeys.bin # sdump seeddb.bin # 'applyips' COMMAND # This will apply the given IPS-formatted delta patch (argument 1) to the specified file (argument 2) # to produce the patched file (argument 3). 2 and 3 may be the same to perform an in-place patch. # applyips 0:/example/patch.ips 0:/data/original.bin 0:/game/modded.bin # 'applybps' COMMAND # This will apply the given BPS-formatted delta patch (argument 1) to the specified file (argument 2) # to produce the patched file (argument 3). # applybps 0:/example/patch.bps 0:/data/original.bin 0:/game/modded.bin # 'applybpm' COMMAND # This will apply the given BPM-formatted delta patch (argument 1) to the specified directory (argument 2) # to produce a directory containing patched files (argument 3). # applybpm 0:/example/patch.bpm 0:/data/originalfolder 0:/game/moddedfolder # 'textview' COMMAND # This will show a text file on screen, in a dedicated text viewer. Size restrictions apply (max 1MiB) # textview 0:/sometext.txt # 'boot' COMMAND # Use this command to chainload a compatible FIRM # boot 0:/boot.firm # disabled cause it would leave the script # 'switchsd' COMMAND # Use this to allow the user to switch the SD card # switchsd "Please switch SD card." # 'reboot' / 'poweroff' COMMAND # These are used to reboot or power off the 3DS console set ERRORMSG "Test script finished,\n(without reboot)\n \nIgnore the error message." ask "Reboot now?" reboot poweroff # this line can never be reached