14 Deploying applications
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
      • Deploying applications
        • Deployment options
        • Understanding saved states
        • State initialization
        • Using program resources
        • Debugging and updating deployed systems
        • Protecting your code
          • Obfuscating code in saved states
        • Finding Application files
    • Packages

14.6 Protecting your code

Prolog in general, but SWI-Prolog in particular is an transparent environment. Prolog's “code is data'' point of view makes this natural as it simplifies development and debugging. Some users though want or need to protect their code against copying or reverse engineering.

There are three ways to distribute code: as source, as .qlf file and in a saved state. Both QLF files and saved states contain the code as virtual machine code. QLF files capture the predicates and directives, while saved state capture the current state of the program. From the viewpoint of protecting code there is no significant difference.

There are two aspects to protection. One is to make sure the attacker has no access to the code in any format and the other is to provide access to a non-human-readable version of the code. The second approach is known as code obfuscation. Code obfuscation typically remove layout and comments and rename all internal identifiers. If an attacker gets access to the SWI-Prolog virtual machine code this can be decompiled. The decompiled code does not include layout information variable names and comments. Other identifiers, notably predicate and module names are maintained. This provides some protection against understanding the source as Prolog code without meaningful variable names and comments is generally hard to follow.

For further protecting the code, there are several scenarios.

  • If the user has unrestricted access to the file system on which the application is installed the user can always access the state or QLF file. This data can be loaded into a compatible emulator and be decompiled.

  • If the user can run arbitrary Prolog code or shell commands the state can be protected by embedding it as a string in the executable deny read access to the executable. This requires a small C program that includes the string and uses PL_set_resource_db_mem() to register the string as the resource database. See PL_set_resource_db_mem() for details. This protection should be combined with the protect_static_code described below.

  • Some extra protection can be provided using the Prolog flag protect_static_code, which disables decompilation of static predicates. Note that most Prolog implementations cannot decompile static code. Various SWI-Prolog tools depend on this ability though. Examples are list_undefined/0, autoload/0, show_coverage/1, etc.

14.6.1 Obfuscating code in saved states

If the option obfuscate(true) is used with qsave_program/2, certain atoms in the saved state are renamed. The renaming is performed by library library(obfuscate). The current implementation is rather conservative, renaming atoms that are used only to define the functor that names a predicate. This is a safe operation, provided the application does not create new references to renamed predicates by reading additional source code or constructing the atom that names the predicate dynamically in some other way such as using atom_concat/3. Predicates that are called this way must be declared using public/1.

Note that more aggressive renaming is possible, but this requires more detailed analysis of the various roles played by some atom. Helpful and descriptive predicate names tend to be unique and are thus subject to this transformation. More general names tend to collide with other roles of the same atom and thus prevent renaming.