This is the initialization transformation that should precede the Checksum and CheckEnvironment transformations. This transformation will create a set of global variables that checkers will increment whenever a check fails. It will also create a set of responders which will trigger a response whenever the number of failed checks exceed a threshold.
As an example, consider this command:
tigress --Environment=x86_64:Linux:Clang:5.1 \
--Transform=InitChecker \
--InitCheckersResponseKinds=abort \
--InitCheckersResponderCount=2 \
--InitCheckersStateSize=2 \
--InitCheckersFakeSize=2 \
--InitCheckersThreshold=2 \
--InitCheckersStateEncodings=rnc,xor \
--InitCheckersFunctionsToInvokeResponders=fib,fac \
--Functions=main \
--Transform=CheckEnvironment \
--Functions=fac \
--CheckEnvironmentSandboxes=valgrind \
--CheckEnvironmentCheckerCount=2 \
foo.c --out=obf.c
--Transform=InitChecker
will create global variables that will count the number of tests
conducted and the number of tests that failed. You can also add fake variables to make it harder for
the attacker to identify the real ones:
int fail_1 = 0;
int fail_2 = 0;
int test_1 = 0;
int test_2 = 0;
int fake_1 = 0;
int fake_2 = 0;
In practice, we don't want these values in cleartext. The --InitCheckersStateEncodings
option decides
how the state variables should be encoded. Here's what the initialization looks like when you choose Residue Number Coding:
long fail_1_0 = ((0L % 230135L ^ ~ (10L * 230135L)) + ((0L % 230135L | 10L * 230135L) + (0L % 230135L | 10L * 230135L))) + 1L;
long fail_1_1 = ((0L % 211253L | 10L * 211253L) << 1L) - (0L % 211253L ^ 10L * 211253L);
The --InitCheckersFunctionsToInvokeResponders
option decides into which functions the responders should
be inserted.
The --Transform=CheckEnvironment
transformation will spread responders throughout the program.
The --CheckEnvironmentSandboxes
and --CheckEnvironmentCheckerCount
options
decide what sandboxes we should check for, and how many checks we should insert. The --Functions
option decides into which functions the checkers should be inserted.
The responders look like this:
total4 = __1_counterState_fail_1_0;
total4 += __1_counterState_fail_0_0;
if (total4 > 2) {
abort();
} else {
}
I.e. we compute the total number of failed tests by adding up all the failure state variables, and, if the
total exceeds the --InitCheckersThreshold
value, we execute the response. With Residue Number Coding,
it looks like this:
decode4 = (((fail_1_0 * 16680518100L) % 24104988860L + (fail_1_1 * 7424470761L) % 24104988860L) % 24104988860L + 24104988860L) % 24104988860L;
if (decode4 > 12052494429L) {
decode4 -= 24104988860L;
} else {
}
total5 = (int )decode4;
decode6 = (((fail_0_0 * 7721719656L) % 48616709155L + (fail_0_1 * 40894989500L) % 48616709155L) % 48616709155L + 48616709155L) % 48616709155L;
if (decode6 > 24308354576L) {
decode6 -= 48616709155L;
} else {
}
total5 += (int )decode6;
if (total5 > 2) {
abort();
} else {
}
Option | Arguments | Description |
---|---|---|
--Transform | InitCheckers | Initialize the checking system used by transforms Checksum and CheckEnvironment |
--InitCheckersResponseKinds | abort, modifyGlobal, random, plugin | Comma-separated list of ways to respond when a check fails. Default=abort.
|
--InitCheckersResponderCount | INTSPEC | Number of responders to insert in the program. Default=1. |
--InitCheckersStateSize | INTSPEC | Number of global variables that hold the check counts. Default=1. |
--InitCheckersFakeSize | INTSPEC | Number of fake global variables that look like real state variables. Default=1. |
--InitCheckersThreshold | INTSPEC | How many tests need to fail before a response is issued. Default=1. |
--InitCheckersStateEncodings | rnc, xor, list, plugin, none | The encoding of the state in which to store successes and failures. Default=rnc.
|
--InitCheckersFunctionsToInvokeResponders | Comma-separated list of functions in which we can install responders. Default=None. |