Tools

Ducky comes with basic toolchain necessary for development of complex programs. One piece missing is the C cross-compiler with simple C library but this issue will be resolved one day.

Common options

All tools accept few common options:

-q, --quiet

Lower verbosity level by one. By default, it is set to info, more quiet levels are warnings, `error and critical.

-v, --verbose

Increase verbosity level by one. By default, it is set to info, more verbose levels is debug. debug level is not available for ducky-vm unless -d option is set.

-d, --debug

Set logging level to debug immediately. ducky-vm also requires this option to even provide any debugging output - it is not possible to emit debug output by setting -v enough times if -d was not specified on command-line.

When option takes an address as an argument, address can be specified either using decimal or hexadecimal base. Usually, the absolute address is necessary when option is not binary-aware, yet some options are tied closely to particular binary, such options can also accept name of a symbol. Option handling code will try to find corresponding address in binary’s symbol table. This is valid for both command-line options and configuration files.

as

Assembler. Translates assembler files (.asm) to object files (.o) - files containing bytecode, symbol information, etc.

Options

-i FILE

Take assembly FILE, and create an object file from its content. It can be specified multiple times, each input file will be processed.

-o FILE

Write resulting object data into FILE.

This options is optional. If no -o is specified, ducky-as will then create output file for each input one by replacing its suffix by .o. If it is specified, number of -o options must match the number of -i options.

-f

When output file exists already, ducky-as will refuse to overwrite it, unless -f is set.

-D VAR

Define name, passed to processed assembly sources. User can check for its existence in source by .ifdef/.ifndef directives.

-I DIR

Add DIR to list of directories that are searched for files, when .include directive asks assembler to process additional source file.

-m, --mmapable-sections

Create object file with sections that can be loaded using mmap() syscall. This option can save time during VMstartup, when binaries can be simply mmapped into VM’s memory space, but it also creates larger binary files because of the alignment of sections in file.

-w, --writable-sections

By default, .text and .rodata sections are read-only. This option lowers this restriction, allowing binary to e.g. modify its own code.

-b, --blob

Create object file wrapping a binary blob. Such file then contains the data from input file, encoded as ASCII data, with several symbols allowing other code to access this data.

-B BLOB_FLAGS, --blob-flags=BLOB_FLAGS

Flags of blob section. Syntax of assembly .section directive is accepted.

ld

Linker. Takes (one or multiple) object files (.o) and merges them into one, binary, which can be executed by VM.

Options

-i FILE

Take object FILE, and create binary file out of it. It can be specified multiple times, all input files will be processed into one binary file.

-o FILE

Output file.

-f

When output file exists already, ducky-ld will refuse to overwrite it, unless -f is set.

--section-base=SECTION=ADDRESS

Linker tries to merge all sections into a binary in a semi-random way - it can be influenced by order of sections in source and object files, and order of input files passed to linker. It is in fact implementation detail and can change in the future. If you need specific section to have its base set to known address, use this option. Be aware that linker may run out of space if you pass conflicting values, or force sections to create too small gaps between each other so other sections would not fit in.

coredump

Prints information stored in a saved VM snapshot.

objdump

Prints information about object and binary files.

profile

Prints information stored in profiling data, created by VM. Used for profiling running binaries.

vm

Stand-alone virtual machine - takes binary, configuration files, and other resources, and executes binaries.

Options

--machine-config=PATH

Specify PATH to VM configuration file. For its content, see VM Configuration file.

--set-option=SECTION:OPTION=VALUE

--add-option=SECTION:OPTION=VALUE

These two options allow user to modify the content of configuration file, by adding of new options or by changing the existing ones.

Lets have (incomplete) config file vm.conf:

[machine]
cpu = 1
core = 1

[binary-0]

You can use it to run different binaries without having separate config file for each of them, just by telling ducky-vm to load configuration file, and then change one option:

$ ducky-vm --machine-config=vm.conf --add-option=binary-0:file=<path to binary of your choice>

Similarly, you can modify existing options. Lets have (incomplete) config file vm.conf:

[machine]
cpus = 1
cores = 1

[binary-0]
file = some/terminal/app

[device-1]
klass = input
driver = ducky.devices.keyboard.KeyboardController
master = device-3

[device-2]
klass = output
driver = ducky.devices.tty.TTY
master = device-3

[device-3]
klass = terminal
driver = ducky.devices.terminal.StandardIOTerminal
input = device-1
output = device-2

Your app will run using VM’s standard IO streams for input and out. But you may want to start it with a different kind of terminal, e.g. PTY one, and attach to it using screen:

$ ducky-vm --machine-config=vm.conf --set-option=device-3:driver=ducky.devices.terminal.StandalonePTYTerminal

--enable-device=DEVICE

--disable-device=DEVICE

Shortcuts for --set-option=DEVICE:enabled=yes and --set-option=DEVICE:enabled=no respectively.

--poke=ADDRESS:VALUE:LENGTH

poke option allows modification of VM’s memory after all binaries and resources are loaded, just before the VM starts execution of binaries. It can be used for setting runtime-specific values, e.g. argument for a binary.

Consider a simple binary, running a loop for specified number of iterations:

By default, 10 iterations are hard-coded into binary. If you want to termporarily change number of iterations, it’s not necessary to recompile binary. By default, this binary, being the only one running, would get segment 0x02, it’s .data section was mentioned first, therefore its base address will be 0x0000, leading to loops having absolute address 0x020000. Then:

$ ducky-vm --machine-config=vm.conf --poke=0x020000:100:2

will load binary, then modify its .data section by changing value at address 0x020000 to 100, which is new number of iterations. Meta variable LENGTH specifies number of bytes to overwrite by poke value, and poke will change exactly LENGTH bytes - if VALUE cannot fit into available bits, exceeding bits of VALUE are masked out, and VALUE that can fit is zero-extended to use all LENGTH bytes.

--jit

Enable JIT - more dense implementation of Ducky instructions is used. Result is higher execution speed of each instruction, however it removes many debugging code. It may be difficult to debug instruction execution even with -d option enabled.

img

Converts binaries to binary images that can be loaded by boot loader.

Options

-i FILE

Take binary FILE, and create a binary image from its content.

-o FILE

Write resulting object data into FILE.

-f

When output file exists already, ducky-img will refuse to overwrite it, unless -f is set.