Break up code blocks by inserting opaque predicates. Requires that at least the InitOpaque transform has been previously issued and, preferably, that one or more UpdateOpaque transformations have been given.
Diversity
There are two sources of diversity:- The types of opaque predicates used, which is controlled by the InitOpaque transformation.
- The location in the target function where the split takes places, which is randomized.
Usage
This is the code generated for the arguments options to --AddOpaqueKinds:
Argument | Generated code |
---|---|
call |
if expr=false then call to random existing function |
fake |
if expr=false then call to non-existing function |
true |
if expr=true then existing statement |
bug |
if expr=true then existing statement else buggified version of the statement |
question |
if expr=true || false then existing statement else obfuscated version of the statement |
junk |
if expr=false then asm(".byte RandomBytes") |
question |
if expr=? then original statement else obfuscated version of the statement |
Question-mark Predicates
Consider the following script:tigress --Seed=0 \ --Inputs="+1:int:42,-1:length:1?10" \ --Transform=InitImplicitFlow \ --Transform=InitEntropy \ --Transform=InitOpaque --Functions=main --InitOpaqueCount=2 --InitOpaqueStructs=list,array,input,env \ --Transform=AddOpaque --Functions=obf3 --AddOpaqueKinds=question --AddOpaqueSplitKinds=inside \ --AddOpaqueCount=10 arith.c --out=arith_out.cThe result will look something like this:
{ strcmp_result5 = (int )strlen(*(_4_main__argv + (_4_main__argc - 1))); } if (x >= strcmp_result5 + y) { { } if (_2entropy * 3 >= _4_main__opaque_list1_1->data) { { atoi_result10 = atoi(*(_4_main__argv + 1)); } if (y >= atoi_result10 + x) { { } if (_4_main__opaque_array_0[(atoi_result10 & 2147483647) % 30] >= 22) { { } if (_4_main__opaque_list2_2->data <= (_2entropy | 6) + (_2entropy & 6)) { { strcmp_result15 = (int )strlen(*(_4_main__argv + (_4_main__argc - 1))); } if (x >= strcmp_result15 + y) { { atoi_result17 = atoi(*(_4_main__argv + 1)); } if (y >= atoi_result17 + y) { { atoi_result19 = atoi(*(_4_main__argv + 1)); } if (y >= atoi_result19 + y) { { strcmp_result21 = (int )strlen(*(_4_main__argv + (_4_main__argc - 1))); } if (y >= strcmp_result21 + atoi_result10) { { strcmp_result23 = (int )strlen(*(_4_main__argv + (_4_main__argc - 1))); if (y <= strcmp_result23 + x) { QUESTION_10_1(& z); } else { QUESTION_10_1_COPY(atoi_result24, & z); } } } else { { QUESTION_9_1_COPY(& z, 6.); } } { } } else { { QUESTION_8_1_COPY(& z, 1L); } } { } } else { { QUESTION_7_1_COPY(& z, z); } } { } } else { { QUESTION_6_1_COPY(0, & z); } } { } } else { { QUESTION_5_1_COPY(& z, 0); } } { } } else { { QUESTION_4_1_COPY(0, & z); } } { } } else { { QUESTION_3_1_COPY(& z, 0.); } } { } } else { { QUESTION_2_1_COPY(4L, & z); } } { } } else { { QUESTION_1_1_COPY(6L, & z); } } { } } }Notice that we attempt (and sometimes fail) to select opaque predicates expr1<=expr2 such that
- all the expri are independent of each other (i.e. analyzing a function should require you to break all the predicates in it);
- the expri depend on input (either because they are created from an entropy source or from invariants over the command line arguments); and
- expr1 and expr2 are computed from different sources.
Options
Option | Arguments | Description |
---|---|---|
--Transform | AddOpaque | Add opaque predicates to split up control-flow. |
--AddOpaqueCount | INTSPEC | How many opaques to add to each function. Default=1. |
--AddOpaqueKinds | call, bug, true, junk, fake, question, * | Comma-separated list of the types of insertions of bogus computation allowed. Default=call,bug,true,junk,question.
|
--AddOpaqueObfuscate | BOOL | Perform some light obfuscation of copied code when using the 'question' opaque predicate. Default=true. |
--AddOpaqueSplitKinds | top, block, deep, recursive, level, inside | Comma-separated list specifying the order in which different split methods are attempted when --AddOpaqueKinds=question is specified. Default=top,block,deep,recursive.
|
--AddOpaqueSplitLevel | INTSPEC | Levels which could be split out when specifying --AddOpaqueSplitKinds=level Default=1. |
--AddOpaqueStructs | list, array, input, env, * | Default=list,array.
|
Examples
Add Opaque Branches |
---|
Break up code by inserting bogus branches, protected by opaque predicates. |
tigress --Environment=x86_64:Darwin:Clang:5.1 --Verbosity=1 \ --Transform=InitOpaque --Functions=main \ --Transform=UpdateOpaque --Functions=fib --UpdateOpaqueCount=10 \ --Transform=AddOpaque --Functions=fib --AddOpaqueCount=10 --AddOpaqueKinds=call,bug,true,junk \ --Transform=CleanUp --CleanUpKinds=annotations \ --out=gen/opaque.c test1.c |
test1.c ⇒ opaque.sh.txt ⇒ opaque.c |
Issues
--AddOpaqueKinds=fake will result in undefined symbols being generated. You need to coerce the linker to ignore such errors. With gcc you can use this option:
-Wl,--unresolved-symbols=ignore-in-object-files
No similar option seems to exist for clang.