Configuring Protection Settings
  • 21 Feb 2025
  • 8 Minutes à lire
  • Sombre
    Lumière
  • PDF

Configuring Protection Settings

  • Sombre
    Lumière
  • PDF

The content is currently unavailable in French. You are viewing the default English version.
Résumé de l’article

Section Encryption

Section encryption configurations are defined as a sectionEncryption JSON object with the following properties:

Section encryption settings

Property

Description

"enabled"

Set to true or false to enable or disable section encryption. Enabled by default.

"sectionRules"

Array of rules to determine which sections to include or exclude.

Default value: [ "*" ].

See Rules Processing for more details.

"symbolRules"

Array of rules to determine which symbols in the specified section(s) to include.

Default value: [ "*" ].

"stringRules"

Array of rules to determine which cstrings in an iOS Mach-O binary to include.

Default value: [ "*" ].

"minimumRange"

The minimum size, in bytes, for an encrypted range.

Default value: 8.

An example configuration looks like the following:

{
    "sectionEncryption": {
        "enabled": true,
        "sectionRules": [ "*", "!.rodata" ],
        "minimumRange": 8
    }
}

The above example instructs Jigsaw to encrypt all sections (i.e., "*") except .rodata sections. See Rules Processing for more details on defining rules with "sectionRules".

On some platforms, like iOS, some sections can be quite fragmented, and section encryption must break them into multiple ranges. When this occurs, you can use the "minimumRange" property to configure the minimum size. The default is 8 and should not need to change unless there is a particular problem that could be avoided by making this value larger.

Control Flow Abstraction

Configurations for control flow abstraction are defined as a "controlFlow" JSON object with the following properties:

Control flow abstraction properties

Property

Description

"enabled"

Set to true or false to enable or control flow abstraction. Enabled by default.

"protectionLevels"

Array of protection level configuration objects.

"pullCallTarget"

Number of bindings to create to link Jigsaw to App Shielding.

Default value: 100. This default value should never be changed.

Consult the App Shielding documentation for more information. Disabled by default for Android x86_64 binaries.

"sectionRules"

Array of rules to determine which binary sections to include or exclude.

By default set to all sections (i.e., [ "*" ]).

See Rules Processing for more details.

The "protectionLevels" determine the "level" of protection for a given scope of symbols. Protection level configurations have the following properties:

Protection levels properties

Property

Description

"name"

Display name for debugging purposes.

"level"

The percentage of call instructions in the code that are redirected to the control flow dispatch function. A value of 100 means all calls are redirected; a value of 0 means no calls are redirected.

"computedBranches"

Enables a feature where a small number of redirected branches will not directly call the dispatch function but instead call it via a computation.

"location"

Array of rules (i.e., symbol names) to determine where the calls must originate from to be included in control flow abstraction.

"target"

Array of rules to determine which call destinations in the specified location(s) are included.

The following example illustrates a low level of coverage for the whole app but maximum protection on two specific symbols:

{
    "controlFlow": {
        "enabled": true,
        "protectionLevels": [
            {
                "name": "low",
                "level": 30,
                "computedBranches": true,
                "location": [ "*" ],
                "target": [ "*", "!malloc" ]
            },
            {
                "name": "heavy",
                "level": 100,
                "computedBranches": true,
                "location": [ "login", "authenticate" ],
                "target": [ "*" ]
            }
        ],
        "pullCallTarget": 100,
        "sectionRules": [ "*" ]
    }
}

In this example, there are two levels: low with 30% of call instructions redirected, and heavy with 100%. Note that the value, 30%, merely serves as a target within each symbol. The target is an approximate, because it depends on the number of calls suitable within the symbol, which could be a small number.

The "location" and "target" determine the scope of each, matching against the specified symbols. The low protection level includes call instructions within all symbols ("location" set to [ "*" ]) but then excludes inner calls targeting malloc. For heavy, two symbols are explicitly named as locations (login and authenticate), with full coverage of only those symbols.

The other setting to note is "computedBranches". Computed branches are particularly difficult for an attacker to find and will even disable program functionality in the event of a successful attack against the control flow dispatch function.

Block Splitting

Configurations for block splitting are defined as a "blockSplitting" JSON object with the following properties:

Block splitting properties

Property

Description

"enabled"

Set to true or false to enable or disable block splitting. Disabled by default.

"groups"

Array of configuration objects.

The "groups" configurations have the following properties:

Groups configuration properties

Property

Description

"rules"

Array of rules to determine which symbols to include in the block splitting scope.

"maxInstructions"

The size of symbol fragments. A lower number is more convoluted; a higher number is faster.

Default value: 4 instructions per fragment.

"link"

Sets whether to join the control flow via a direct branch or an indirect call. Can be either "Direct" or "Indirect".

An example configuration looks like the following:

{
    "blockSplitting": {
        "enabled": true,
        "groups": [
            {
                "rules": [ "crypto*" ],
                "maxInstructions": 4,
                "link": "Direct"
            }
        ]
    }
}

This example protects all symbols that start with crypto and joins the control flow via a direct link. Direct links are explicit jumps between disparate fragments. Even though they convolute the flow, they are transparent to a decompiler but fast. Indirect links are later subject to control flow abstraction and are preferred for obfuscation purposes, but there will be an incurred performance overhead. See Performance Considerations for more details.

Block splitting does not currently support code which raises or catches C++ exceptions. It should be used sparingly and only in areas which can be thoroughly tested. Problem areas will cause an unexpected termination most likely seen as a segmentation violation or illegal instruction signal.

Checksum

Configurations for checksums (i.e., integrity checking) are defined as a "checksum" JSON object with the following properties:

Checksum properties

Property

Description

"enabled"

Set to true or false to enable or disable checksumming. Enabled by default, and requires control flow abstraction.

"level"

The percentage of redirected control flow call instructions to use for checksum validation. Defaults to 50 (i.e., 50%).

"external"

Set to true or false to enable or disable interlocking checksum call instructions with the App Shielding library. Disabled by default for x86_64 binaries.

"externalLevel"

The percentage of available checksum call instructions to use for interlocking with the Shield library.

Default value: 20(i.e., 20%).

"rules"

Array of configuration objects to determine which symbols to include in the checksum scope.

The "rules" configurations have the following properties:

Rules configuration properties

Property

Description

"name"

Display name for debugging purposes.

"location"

Array of rules (i.e., symbol names) to determine which control flow abstracted calls are eligible for checksumming.

Default value: [*].

"target"

Array of rules (i.e., symbol names) to determine which symbols in the given location(s) should have their integrity verified.

Default value: [*] but should be more specific if the location is more specific to avoid performance issues.

An example configuration looks like the following:

{
    "checksum": {
        "enabled": true,
        "level": 50,
        "rules": [
            {
                "name": "default",
                "location": [ "*", "!game_loop" ],
                "target": [ "*" ]
            },
            {
                "name": "payments",
                "location": [ "login", "register" ],
                "target": [ "login", "crypto*",  "authenticate" ]
            }
        ]
    }
}

This example sets the level to 50% (i.e., half of the redirected control flow call instructions are used for checksum validation). There are two rules: the first is a default-like configuration which embeds checks for the entire application across all the available call instructions except any in the symbol game_loop. This keeps game_loop running fast, because there is no additional burden added due to integrity checking.

The second rule checks login, authenticate, and any symbol starting with crypto. The validation logic is placed randomly across call instructions in login and register. This ensures, for example, that all the crypto* symbols are checked when login or register is reached.

Generally, checksums can only use existing control flow call instructions. If a particular symbol is excluded from control flow abstraction, checksum calculations cannot be placed at the given location. However, Jigsaw has a priority mechanism where, if the checksum location rules contain only complete and partial symbol names (i.e., no generic "*" wildcard rules), the control flow settings are overridden to provide a call instruction for it even if it was excluded there.

Integrity checking has the biggest performance impact of all Jigsaw features and, therefore, has carefully chosen defaults to keep good performance. See the section on Performance Considerations for more information.

External Checksums

By default, a small number (20%) of the available checksum call instructions are reserved for external checksums. These cover important OneSpan components which help build an interlocked security solution. If insufficient call instructions are available for external checksums, a warning is issued at the time of protection. Consider increasing the "externalLevel" value in this case. Because the placement of external checksums is automatic, they can’t be configured with the checksum rules above. If you need to ensure that a specific symbol does not contain any checksums, it is best to exclude it via the control flow rules.

Android binaries with an x86_64 architecture do not support external checksums. For such libraries, external checksums are disabled by default.

Debug Stripping

Debug stripping only has one configuration option, enabled which can be set to true or false to either enable or disable it, respectively. For example:

{
    # Disable stripping, but maybe don't do this!
    "stripping": {
        "enabled": false
    }
}

The default value is true, and it is not recommended to disable it unless you have a specific reason to keep debug information in your code.


Cet article vous a-t-il été utile ?

Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.
ESC

Ozzy, facilitant la découverte de connaissances grâce à l’intelligence conversationnelle