# DotFix Script - built-in automation language of DotFix NiceProtect

> DotFix Script lets you run your own scripts immediately before and after the protection stage — to prepare input files, edit the PE header, strip unwanted resources, patch the protected binary, compute checksums, sign it, or kick off your installer build — without leaving the tool.

Canonical HTML: <https://www.niceprotect.com/help/dotfix_script.htm>

## DotFix Script — Custom Scripting Engine

DotFix Script is the built-in automation language of DotFix NiceProtect. It lets you run your own scripts immediately before and after the protection stage — to prepare input files, edit the PE header, strip unwanted resources, patch the protected binary, compute checksums, sign it, or kick off your installer build — without leaving the tool.

**On this page**
[Overview](https://www.niceprotect.com/help/dotfix_script.htm#gps-overview) ·
[Syntax](https://www.niceprotect.com/help/dotfix_script.htm#gps-syntax) ·
[Registers & macros](https://www.niceprotect.com/help/dotfix_script.htm#gps-registers) ·
[Numbers](https://www.niceprotect.com/help/dotfix_script.htm#gps-numbers) ·
[Conditions](https://www.niceprotect.com/help/dotfix_script.htm#gps-if) ·
[Variables & math](https://www.niceprotect.com/help/dotfix_script.htm#gps-vars) ·
[Strings](https://www.niceprotect.com/help/dotfix_script.htm#gps-strings) ·
[Labels & jumps](https://www.niceprotect.com/help/dotfix_script.htm#gps-flow) ·
[Files](https://www.niceprotect.com/help/dotfix_script.htm#gps-files) ·
[Binary & PE](https://www.niceprotect.com/help/dotfix_script.htm#gps-pe) ·
[Registry / INI / XML](https://www.niceprotect.com/help/dotfix_script.htm#gps-config) ·
[Dialogs & console](https://www.niceprotect.com/help/dotfix_script.htm#gps-ui) ·
[System](https://www.niceprotect.com/help/dotfix_script.htm#gps-system) ·
[Examples](https://www.niceprotect.com/help/dotfix_script.htm#gps-examples) ·
[Errors](https://www.niceprotect.com/help/dotfix_script.htm#gps-errors)

### Overview

A DotFix Script is plain text, interpreted line by line at runtime. Each line is one command followed by comma‑separated parameters. There is no separate compile step you manage: you write the script, and the engine reads it from top to bottom, executing one command per line.

NiceProtect can invoke a script at two points in a protection job:

- **Pre‑protection** — before the file is processed. Use it to stage source files, clean previous output, generate inputs, or read settings.

- **Post‑protection** — after the protected binary is written. Use it to patch the output, adjust PE headers, hash or sign the result, copy it to a release folder, or notify the user.

The file being produced is exposed to the script through the predefined register `@output`. Commands that read or write a binary without an explicit path operate on this output file by default.

- The number of script lines is not limited.

- Empty lines are skipped.

- Lines beginning with `;`, `#`, or `!` are comments.

- An unknown command is reported as an error; the script continues with the next line.

- Lines starting with `GPS` are treated as obfuscated and decrypted automatically, so you can ship scripts whose contents are not easily readable.

Return code
A script run returns `0` if it finished with no errors, or `1` if one or more errors were recorded — so a faulty script can fail your build pipeline.

### Syntax

One command per line. The command name is separated from its parameters by the first space; parameters are separated by commas. A command takes up to ten parameters. Command names are case‑insensitive, and leading spaces in a parameter are trimmed.

; set register _name to the literal text "build42"
set build42, _name

; join two values into _path
concat @current, output\, _path

To include commas or spaces literally, wrap a parameter in double quotes; a doubled quote (`""`) inside produces one literal quote. The escape `\n` is converted to a line break.

### Registers & macros

A register is a named slot holding a string. You create one simply by writing to it; most commands take the destination register name as their last parameter. Prefix a name with `@` anywhere in a parameter to substitute its current value before the command runs.

set Hello, _greeting
concat @_greeting, " World", _line   ; _line = "Hello World"
status @_line                        ; prints: Hello World

Several predefined registers are filled in automatically:

| Register | Value |
| --- | --- |
| `@windows` | Windows directory, with trailing backslash. |
| `@temp` | User temp directory, with trailing backslash. |
| `@current` | Directory of the running NiceProtect executable. |
| `@output` | Full path of the output file for the current job. |
| `@crlf` | A carriage‑return + line‑feed pair. |

### How numbers are read

Numbers are **decimal by default** throughout the engine. A value written with a `0x` (or `$`) prefix is hexadecimal; anything else is decimal. Every command that produces a number writes it in decimal, so the result of one operation feeds straight into the next.

add 0x10, 5, _a     ; _a = "21"  (16 + 5)
add @_a, 4, _b      ; _b = "25"  (previous result reused directly)

Calculation and byte layout are two separate ideas. Use `calc` to compute a value, then `pack` to turn it into a fixed‑width little‑ or big‑endian byte string for writing into a file.

calc (0x1000 + 16) * 2, _v       ; _v = "8224"
pack @_v, dword, le, _bytes      ; _bytes = "20200000" (LE DWord)
putcode 0x1000, @_bytes

Note
Raw byte payloads differ from numbers: the data argument of `putcode` and the result of `getcode` are hex byte strings (for example `90909090`), not decimal quantities.

### Conditions (the IF modifier)

Any command can be made conditional by appending an `IF` clause as its last parameter. If the condition is false, the command is skipped.

goto done, IF @_count = 3

A condition is one or more comparisons of the form `value OP value`:

| Operator | Meaning | Comparison |
| --- | --- | --- |
| `=` | equal | string |
| `^` | not equal (also `!=` , `<>` ) | string |
| `>` | greater than | numeric |
| `<` | less than | numeric |
| `>=` | greater or equal | numeric |
| `<=` | less or equal | numeric |

The relational operators compare numerically, using the `0x`/decimal rule above. Comparisons can be joined with `AND` and `OR`, evaluated left to right.

goto ready, IF @_size > 0 AND @_state = ok
goto retry, IF @_code = 1 OR @_code = 2

Spaces in IF values
A condition is split on spaces, so values inside an `IF` clause must not contain spaces. To compare text with spaces, store it in a register and compare the register, or test emptiness with `length`.

### Commands — variables & math

Math commands accept decimal or hex input and write a **decimal** result.

**set** value, destReg

Stores `value` verbatim into `destReg`.

**calc** expression, destReg *[, hex]*

Evaluates an arithmetic expression with `+ - * /` and parentheses; numbers may be decimal or hex. Result is decimal, or an unpadded hex string when the third parameter is `hex`.

**pack** value, byte|word|dword|qword, le|be, destReg write

Encodes `value` as a fixed‑width hex byte string in little‑ or big‑endian order, ready for `putcode`.

**unpack** hexBytes, le|be, destReg read

Decodes a hex byte string back into a decimal number.

**add** / **sub** / **mul** / **div** a, b, destReg

Addition, subtraction, multiplication, integer division. Inputs decimal or hex; decimal result. `div` reports an error on a zero or missing divisor.

**invert** value, destReg

Encodes `value` as a little‑endian 4‑byte hex string. Retained for compatibility; `pack value, dword, le, dest` is the clearer equivalent.

### Commands — strings

**concat** a, b, destReg

Joins `a` and `b`.

**length** value, destReg

Stores the length of `value` (decimal).

**substr** source, start, count, destReg

Extracts `count` characters from `source` starting at position `start` (1‑based).

**createstring** char, count, destReg

Builds a string of `count` repetitions of the first character of `char`.

**chrtohex** char, destReg  /  **hextochr** hex, destReg

Convert a character to its two‑digit hex code and back.

**rndbyte** destReg

Stores a random byte as a two‑digit hex string.

### Commands — labels & jumps

**label** name

Declares a jump target. Labels are resolved before execution, so you can jump forward or backward.

**goto** label *[, IF ...]*

Transfers execution to a label, optionally only when a condition holds.

**exit**

Stops the script immediately.

### Commands — files

**createpath** path fs

Creates a directory, including missing parents.

**copyfile** source, dest fs

Copies a file. A trailing `$` on a path expands to the application directory.

**delfile** path fs

Deletes a file.

**addlog** file, text fs

Appends `text` as a new line to `file`, creating it if needed.

**getfile** destReg read

Reads the entire output file into a register.

**getfilelength** file, destReg read

Stores the size of `file` in bytes (decimal).

### Commands — binary & PE editing

These operate on the output file and understand the Windows PE format. Addresses and offsets accept decimal or hex on input and are returned in decimal.

**putcode** offset, hexBytes write

Writes a sequence of bytes (hex string) at a file offset. `putcode 0x1000, 90909090` writes four NOP bytes.

**getcode** offset, length, destReg read

Reads `length` bytes from `offset` and stores them as a hex string.

**getoep** destRaw, destRva read

Resolves the original entry point: raw file offset and RVA (both decimal).

**setoep** rva write

Sets the PE entry point to the given RVA.

**getimagebase** destReg read

Stores the PE image base address (decimal).

**getoem** destReg  /  **setoem** text readwrite

Reads or writes the OEM identifier string in the DOS stub (up to 29 characters).

**createsection** name, size, destRaw, destRva write

Appends a new PE section with the given name and size (decimal), returning its raw offset and RVA, and updates the image size.

**setflag** flags write

Sets the characteristics flags on the file's sections (use `0x` for a hex bitmask).

**xorcode** rva, length, destStubReg write

XOR‑encrypts a region of code at the given RVA with a random key, writes it back, and returns a ready‑to‑use decryptor stub (hex) in the register.

### Commands — Registry / INI / XML

Across all three stores the convention is the same: **set writes, get reads.**

**registry.set** Root, SubKey\ValueName, Type, Value write

Writes a value. `Root` is one of `HKCR HKCU HKLM HKU HKPD HKCC HKDD`; `Type` is `REG_DWORD` or a string type.

**registry.get** Root, SubKey\ValueName, destReg *[, default]* read

Reads a value, with an optional default if it is missing.

**ini.set** file, Section, Key, Value write

Writes a value to an INI file.

**ini.get** file, Section, Key, destReg read

Reads a value, or an empty string if absent.

**xml.set** file, XPath, Value write

Writes `Value` as the text of the node addressed by `XPath` (for example `/root/item`). Creates the file and any missing elements of a simple path automatically; saved as UTF‑8 without a BOM.

**xml.get** file, XPath, destReg read

Reads the text of the node, or an empty string if the file or node is absent. Loading detects the file's actual encoding, so files from other tools load reliably.

### Commands — dialogs & console

**messagebox** text, type, caption, destReg

Shows a message box and stores the numeric button result.

**inputbox** prompt, destReg

Prompts for a line of text.

**settoclipboard** text

Places `text` on the clipboard.

A console is available for interactive output. It adapts to how the protector was launched: in the console build `console.load` reuses the existing console; in the GUI build it creates a window, and `console.unload` closes only what it created. The close button and Ctrl‑C are disabled for a created console so the user cannot terminate the protector by closing it. The `status` command always writes to the protection log, so console commands are optional.

**console.load** title  ·  **console.print** text  ·  **console.get** destReg

Attach a console / write a line / read a line.

**console.color** fg, bg  ·  **console.attributes** mode  ·  **console.unload**

Set text colour / set mode flags / detach the console.

### Commands — system

**run** commandLine, destReg read

Runs an external command or console application, **waits** for it to finish, and stores its exit code (decimal). On a start failure it records an error and stores `-1`.

**shell** command

Runs a program or opens a file or URL through the shell, without waiting.

**getenv** name, destReg read

Reads an environment variable into a register.

**md5** file, destReg  /  **sha256** file, destReg read

Computes the MD5 (32 hex chars) or SHA‑256 (64 hex chars) hash of a file.

**loadfunction** dll, function, a1, a2, a3, destReg

Loads a DLL, calls an exported function with three integer arguments, and stores the numeric return value.

**pause** milliseconds  ·  **play** wavFile

Wait for a number of milliseconds / play a WAV file.

**status** text

Writes a diagnostic line to the NiceProtect status bar (and the console, if attached). The main way to report progress from a script.

### Examples

#### Copy the protected file into a release folder

concat @current, release\, _dir
createpath @_dir
concat @_dir, app_protected.exe, _dest
copyfile @output, @_dest
status [INFO] Copied protected build to release folder

#### Stamp a checksum and sign the protected binary

sha256 @output, _sum
concat @output, .sha256, _sumfile
delfile @_sumfile
xml.set @_sumfile, /file/sha256, @_sum

run signtool sign /f cert.pfx @output, _rc
goto signed, IF @_rc = 0
status [FAIL] Signing failed (code @_rc)
exit
label signed
status [PASS] Signed @output

#### Compute an address and patch bytes

getimagebase _base
calc @_base + 0x1000, _addr
pack @_addr, dword, le, _bytes
putcode 0x400, @_bytes

### Errors & diagnostics

Errors are collected during the run and printed to the status bar when it finishes; each begins with `!` and names the failing command and line. A failed command does not stop the script — the next line still runs. Use `status` with a simple convention such as `[PASS]`, `[FAIL]`, and `[INFO]` prefixes to make results easy to scan, and check the run's return code (`0`/`1`) from your build system.

Change language: [English](https://www.niceprotect.com/help/index.htm) [German](https://www.niceprotect.com/help/de/index.htm) [Russian](https://www.niceprotect.com/help/ru/index.htm)
