
   This transformation inserts checkers into the program
   in order to ensure the integrity of the codebytes.
   A checker computes a hash over a code region and, if the hash is
   different than expected, issues a response, such as 
   crashing the program. A hash function can be simple (such as 
   computing the xor over the code region) or a highly complex
   randomly generated function. Responders can be simple
   (such as exiting the program with an abort() or
   modifying a global variable) or can be user-specified 
   plugins of arbitrary complexity. Checkers can, of course, be
   obfuscated with Tigress' other transformations (such as
   flattening or virtualization), making them harder to 
   detect.
            
Here is a LigerLabs video that gives a good introduction to the checksum transformation:
And here's another LigerLabs video that describes attacks against checksums:
 Checkers can be invoked over a function prior to it being called,
ensuring that the function hasn't been tampered with before it is 
executed. This is illustrated in this figure, where foo 
is checked by the pink checker, prior to being called. 
The e1 value is the expected  hash value computed 
over foo. 
            

Checkers can also cover arbitrary levels of overlapping,
randomly chosen, code regions. This is the case for the
orange and blue checkers. Here, f2
and t2 represent the range of addresses
covered by the orange checker.
            
Unlike other Tigress transformations, the Checksum 
transform requires a post-processing step. This is performed
by the tigress_post program:
            

The Checksum transformation generates two
files: the Tigress-obfuscated output file (here P1.c) into
which checkers have been inserted and a file (here hashes.c) 
that contains information about the generated hash functions.
This file needs to be compiled into a dynamically linked .so file.
The tigress_post post-processor
reads the compiled obfuscated file (P1.exe) and
hashes.so and generates a patched
executable file (here P2.exe).
            
 Here's an example of how to call Tigress and tigress_post:
            
> tigress --Seed=0 --Statistics=0 --Verbosity=0 --Environment=x86_64:Darwin:Clang:5.1  \
       --Verbosity=0 \
       --Transform=InitEntropy --Functions=main --InitEntropyKinds=vars \
       --Transform=InitOpaque --Functions=main --InitOpaqueStructs=list,array,env   \
       --Transform=Checksum \
          --ChecksumAddressing=relative \
          --ChecksumInsertSegmentCheckersInTheseFunctions=main \
          --ChecksumDoNotInsertSegmentCheckersInTheseFunctions=fib \
          --ChecksumSegmentCheckersToBeInsertedWhere=randomlyNoLoops \
          --ChecksumRequiredNumberOfSegmentCheckers=10 \
          --ChecksumFunctionsToBeCheckedAtCallSites=fac,fib \
          --ChecksumCallCheckersToBeInsertedWhere='((fac beforeCall) (fib beforeCall))' \
          --ChecksumFunctionPriority="((fac 1.0) (fib 0.5))" \
          --ChecksumHashFunctionsFile=hashes.c \
          --ChecksumHashValueTypes=int64  \
          --ChecksumHashFunctionKinds=add \
            test1.c --out=obf.c 
> gcc -static -fPIC -fno-plt -fcf-protection=none -o obf.exe obf.c     # for Linux
> gcc         -fPIC -fno-plt -o obf.exe obf.c     # for Darwin
> gcc -shared -o hashes.so -fPIC hashes.c
> tigress_post \
           --Action=checksum \
              --HashFunctionsFile=hashes.so \
           obf.exe
A randomly generated checker looks like this:
/*******************************************************************************/
/* Inline template to be patched by tigress_post.                              */
if (opaque-false) {
    __asm__  volatile   (".align 8,0xf5;\n":);
   L4:  __asm__  volatile   (".long 0xAAAAA001":);         /* Start address */
   L5:  __asm__  volatile   (".long 0xBBBBB001":);         /* End address */
   L6:  __asm__  volatile   (".quad 0xCCCCCCCCCCCCC001":); /* Expected hash value */
}
/*******************************************************************************/
/* Load values from the patched template                                       */
codePtrVar_offset = (int )*((unsigned long *)(&&L4));
codePtrVar_templateAddress = (unsigned long *)(&&L4);
codePtrVar = (unsigned long *)((char *)codePtrVar_templateAddress + codePtrVar_offset);
endPtrVar_offset = (int )*((unsigned long *)(&&L5));
endPtrVar_templateAddress = (unsigned long *)(&&L5);
endPtrVar = (unsigned long *)((char *)endPtrVar_templateAddress + endPtrVar_offset);
/*******************************************************************************/
/* Compute the hash value.                                                     */
hashVar = 0;
while (codePtrVar < endPtrVar) {
  hashVar = ((hashVar + *codePtrVar) + (760749724UL ^ (1 ^ hashVar))) & 
            (*codePtrVar * 5027005UL + 4949079U);
  codePtrVar ++;
}
/*******************************************************************************/
/* Check if the hash value is correct, if not, respond.                        */
expectedHashVar = *((unsigned long *)(&&L6));
if (hashVar != expectedHashVar) {
  abort();
}
/*******************************************************************************/
The word at L4 will (after patching by tigress_post) hold
the address of the region that the hash function will check, L5
will hold the address of the end of that region, and L6 will hold
the expected hash value.
            
| Option | Arguments | Description | 
|---|---|---|
| --Transform | Checksum | Insert checkers that compute hashes over the code bytes and take action if the hashes return the wrong value | 
| --ChecksumTemplateKinds | local, function, string, data |  Where to insert checker templates. Default=local.
  | 
| --ChecksumHashFunctionKinds | add, mul, xor, linear, quadratic, random |  Kinds of expressions to use in the hash function. Default=xor.
  | 
| --ChecksumHashValueTypes | int32, int64 |  Comma-separated list of the kinds of expressions to use in the hash functions. Default=int32,int64.
  | 
| --ChecksumRandomHashFunctionSize | INTSPEC | Size of the randomly generated hash function. Default=1. | 
| --ChecksumObfuscateBody | BOOLSPEC | Obfuscate the body of the hash function. Default=false. | 
The purpose of tigress_post --Action=checksum is to patch the checker
``templates'' that were inserted by Tigress:
            

 There are three main steps: first the executable is parsed and the 
templates are located, then each checker is assigned to a region of the text 
segment, and finally the hash value is computed and the templates are patched. 
An option tigress_post ... --OverlapRate=int ... can be set to adjust the number checkers will 
check each region of the text segment.
            
tigress_post has the following options:
            
--Action=checksum 
    Patch the checkers after the 'tigress --Transform=Checksum' transformation.
--Action=parse 
    Parse and print the information collected from the executable input file.
--HashFunctionsFile=file.so 
  The .so-file for the generated hash functions. 
  The file 'hashes'c' is generated by Tigress and 
  should be compiled using the command:
     'gcc -shared -o hashes.so -fPIC hashes.c'
--OverlapRate=int                      
   Amount of overlap in hash function assignment.
--ShowResults                          
   Show a table of final results, i.e. which hashfunctions check which regions.
--Dump=templates   
   Print the checker templates.
--Dump=regions     
   Print the regions that the executable was broken up into.
--Dump=textSegment 
   Print the text segment from the executable.
--Dump=sections    
   Print the sections of the executable.
--Dump=symbols     
   Print the symbol table extracted from the executable.
--Dump=codeBytes   
   Print the code bytes for each function in the executable.
--Trace|-e                             
   Trace the execution of tigress_post.
--Help
To check that the checkers inserted by Tigress actually trigger when 
the executable is modified, you can use the tigress_post --Action=kill 
command. It will randomly modify one or more bits in the executable which
should cause the responses to trigger.
            
These are the relevant tigress_post options:
            
--Action=kill       
   Destroy a function to test that the checkers trigger a response.
--KillFunctions=f1,f2,...
   The functions to be killed by changing random bits.
--KillSize=1|8|16|32
   Number of consecutive bits to be changed when killing a function.
--KillCount= 
   Number of times to kill a function.
 Tigress has a few simple built-in responders. You can easily add your own by adding a plugin function to your input program:
void responder_1 () {
   for(int i=0; i<10; i++) {
      printf("Hacked %i!\n", i);
   }
   exit(-1);
}
The body of these functions will be inserted in the checkers. These are the relevant options:
tigress ... \
         --Transform=InitPlugins  \
            --InitPluginsResponderPrefix=responder    \
         --Transform=Checksum \
            --ChecksumResponseKinds=plugin \
         ...
You can read more about plugins here.
| Option | Arguments | Description | 
|---|---|---|
| --ChecksumResponseKinds | abort, random, global, plugin |  Kinds of response to use in in case a checksum computes the wrong hash value Default=abort.
  | 
Tigress has a few options that control where checkers are inserted, and which functions are being checked.
Unlike all other Tigress transformations, --Transform=Checksum
does not make use of the --Functions=... option. Instead, for call checkers 
you should use --ChecksumFunctionsToBeCheckedAtCallSitess=... to indicate which functions
should be checked before they are called, and --ChecksumCallCheckersToBeInsertedWhere=.. to
specify a more exact location (such as after the call, randomly, etc.):
            
> tigress ... \
          --ChecksumFunctionsToBeCheckedAtCallSites=f1,f2 \
          --ChecksumCallCheckersToBeInsertedWhere='((f1 beforeCall) (f2 beforeCall))' \
          ...
The option --ChecksumCallCheckersToBeInsertedWhere=... describes where in the function the 
checkers can be inserted. Here, function f6, for example, will be checked by a function that calls it,
and the checker will be inserted anywhere in the caller, except within loops (this helps with performance): 
            
tigress ...
          --ChecksumCallCheckersToBeInsertedWhere='((f1 beforeCall) (f2 afterCall) (f3 randomly) (f4 first) (f5 topLevel) (f6 randomlyNoLoops))'
The option --ChecksumFunctionPriority=... can give a priority value for each function, where 0.0 means "never check this function",
and 1.0 means "always check this function." This allows you to control how many of the available checkers are assigned to check
a particular function: 
            
tigress ...
          --ChecksumFunctionPriority='((fac 1.0) (fib 0.7) (zap 0.2))' \
| Option | Arguments | Description | 
|---|---|---|
| --ChecksumFunctionPriority | S-Expression | S-Expression describing which functions are most important to checksum. The syntax is ((function priority) (function priority) ...) where priority is a floating point number in the range [0.0,1.0]. (foo 0.0) means that foo should not be checked. Default=NONE. | 
| --ChecksumFunctionsToBeCheckedAtCallSites | String,String,... | Comma-separated list of functions that should be checked where they are called. Use --ChecksumCallCheckersToBeInsertedWhere to specify where withing the caller the checker should be inserted. Default=NONE. | 
| --ChecksumCallCheckersToBeInsertedWhere | randomly, randomlyNoLoops, topLevel, first, beforeCall, afterCall, annotations |  S-Expression describing which functions should be checksummed before/after they are called. The syntax is ((function where) (function where) ...) where where is one of "randomly", "first", "beforeCall",  "afterCall",  "randomlyNoLoops", "topLevel", "annotations". If function bar calls function foo and (foo,randomly) is specified, a checker of foo will be inserted at some random place in bar. If (foo,beforeCall) is specified, the checker will be inserted immediately before the call to foo. If (foo,afterCall) is specified, the checker will be inserted immediately after the call to foo. If (foo,first) is specified, the checker will be inserted at the very beginning of bar. If (foo,randomlyNoLoops) is specified, the checker will be inserted anywhere within bar, but loops will be avoided.  If (foo,annotations) is specified, the checker will be inserted where the annotation CHECKSUM_INSERT is specified within bar. Default=first.
  | 
For segment checkers, --ChecksumRequiredNumberOfSegmentCheckers=... specifies how many checkers to insert, and
--ChecksumInsertCheckersWhere=... describe where in the function to insert them. Here, checkers will be inserted anywhere 
in the function, except within control structures, or anywhere where the user has added a CHECKSUM_INSERT annotation: 
            
tigress ...
          --ChecksumInsertSegmentCheckersInTheseFunctions='/foo*/' \
          --ChecksumProtectSegments=text \
          --ChecksumRequiredNumberOfSegmentCheckers=10 \
          --ChecksumSegmentCheckersToBeInsertedWhere=topLevel,annotations \
Here's an example of a function with annotations (don't forget to include tigress.h!):
            
void foo(void) { 
  int x = 10;
  int y = 2;
  if (x < 5) {
     y++;
     CHECKSUM_INSERT;
  } else {
     x++;
     CHECKSUM_INSERT;
  }
  y++;
}
| Option | Arguments | Description | 
|---|---|---|
| --ChecksumRequiredNumberOfSegmentCheckers | INTSPEC | Number of segment checkers to insert. Default=0. | 
| --ChecksumProtectSegments | text, cstring, const, data |  Comma-separated list of which segments to protect. Default=text.
  | 
| --ChecksumSegmentCheckersToBeInsertedWhere | randomly, randomlyNoLoops, topLevel, first, annotations |  Insert checkers randomly, at top-level, first, or where 'CHECKER'-annotations have been given in the code. Default=first.
  | 
| --ChecksumInsertSegmentCheckersInTheseFunctions | IDENTSPEC | Names of functions into which checkers may be inserted. Default=NONE. | 
| --ChecksumDoNotInsertSegmentCheckersInTheseFunctions | String,String,... | Comma-separated list of functions in which not to insert checkers. Default=NONE. | 
Calling tigress_post --ShowResults will generate a table like this:
            
+========+===========================================+===============+=====================================+========+========+========+========+========+========+
| region |    section, priority, address range, size |      function |             template, checker, size |      A |      B |      C |      D |      E |      F |
+========+===========================================+===============+=====================================+========+========+========+========+========+========+
|      0 |    text,0.5,[0x100002d40, 0x100002d4f],16 |     _megaInit |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|      1 |    text,1.0,[0x100002d50, 0x100002d8f],64 |  _loop_switch |                                     | hash_8 |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|      2 |   text,0.5,[0x100002d90, 0x100002e8f],256 |      ___sputc |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|      3 |   text,0.5,[0x100002e90, 0x100003007],376 |         _main |                                     |        |        |        |        |        |        |
|      4 |     text,1.0,[0x100003008, 0x10000300b],4 |               |           start=100002d50,hash_8,64 |        |        |        |        |        |        |
|      5 |     text,1.0,[0x10000300c, 0x10000300f],4 |               |             end=100002d8f,hash_8,64 |        |        |        |        |        |        |
|      6 |     text,1.0,[0x100003010, 0x100003013],4 |               |         expected=5a11fe33,hash_8,64 |        |        |        |        |        |        |
|      7 |   text,0.5,[0x100003014, 0x10000311f],268 |               |                                     |        |        |        |        |        |        |
|      8 |     text,1.0,[0x100003120, 0x100003123],4 |               |           start=100003dc0,hash_0,96 |        |        |        |        |        |        |
|      9 |     text,1.0,[0x100003124, 0x100003127],4 |               |             end=100003e1f,hash_0,96 |        |        |        |        |        |        |
|     10 |     text,1.0,[0x100003128, 0x10000312b],4 |               |         expected=37f9a377,hash_0,96 |        |        |        |        |        |        |
|     11 |   text,0.5,[0x10000312c, 0x1000031ff],212 |               |                                     |        |        |        |        |        |        |
|     12 |     text,1.0,[0x100003200, 0x100003203],4 |               |           start=100003dc0,hash_1,96 |        |        |        |        |        |        |
|     13 |     text,1.0,[0x100003204, 0x100003207],4 |               |             end=100003e1f,hash_1,96 |        |        |        |        |        |        |
|     14 |     text,1.0,[0x100003208, 0x10000320b],4 |               |         expected=37f9a377,hash_1,96 |        |        |        |        |        |        |
|     15 |   text,0.5,[0x10000320c, 0x1000033d7],460 |               |                                     |        |        |        |        |        |        |
|     16 |     text,1.0,[0x1000033d8, 0x1000033db],4 |               |           start=100003dc0,hash_2,96 |        |        |        |        |        |        |
|     17 |     text,1.0,[0x1000033dc, 0x1000033df],4 |               |             end=100003e1f,hash_2,96 |        |        |        |        |        |        |
|     18 |     text,1.0,[0x1000033e0, 0x1000033e3],4 |               |         expected=37f9a377,hash_2,96 |        |        |        |        |        |        |
|     19 |   text,0.5,[0x1000033e4, 0x1000034f7],276 |               |                                     |        |        |        |        |        |        |
|     20 |     text,1.0,[0x1000034f8, 0x1000034fb],4 |               |           start=100003dc0,hash_3,96 |        |        |        |        |        |        |
|     21 |     text,1.0,[0x1000034fc, 0x1000034ff],4 |               |             end=100003e1f,hash_3,96 |        |        |        |        |        |        |
|     22 |     text,1.0,[0x100003500, 0x100003503],4 |               |         expected=37f9a377,hash_3,96 |        |        |        |        |        |        |
|     23 |   text,0.5,[0x100003504, 0x100003617],276 |               |                                     |        |        |        |        |        |        |
|     24 |     text,1.0,[0x100003618, 0x10000361b],4 |               |           start=100003dc0,hash_4,96 |        |        |        |        |        |        |
|     25 |     text,1.0,[0x10000361c, 0x10000361f],4 |               |             end=100003e1f,hash_4,96 |        |        |        |        |        |        |
|     26 |     text,1.0,[0x100003620, 0x100003627],8 |               | expected=a8b3c8039f4a6b74,hash_4,96 |        |        |        |        |        |        |
|     27 |   text,0.5,[0x100003628, 0x100003987],864 |               |                                     |        |        |        |        |        |        |
|     28 |     text,1.0,[0x100003988, 0x10000398b],4 |               |           start=100003dc0,hash_5,96 |        |        |        |        |        |        |
|     29 |     text,1.0,[0x10000398c, 0x10000398f],4 |               |             end=100003e1f,hash_5,96 |        |        |        |        |        |        |
|     30 |     text,1.0,[0x100003990, 0x100003993],4 |               |         expected=37f9a377,hash_5,96 |        |        |        |        |        |        |
|     31 |   text,0.5,[0x100003994, 0x100003aa7],276 |               |                                     |        |        |        |        |        |        |
|     32 |     text,1.0,[0x100003aa8, 0x100003aab],4 |               |          start=100003e20,hash_6,128 |        |        |        |        |        |        |
|     33 |     text,1.0,[0x100003aac, 0x100003aaf],4 |               |            end=100003e9f,hash_6,128 |        |        |        |        |        |        |
|     34 |     text,1.0,[0x100003ab0, 0x100003ab3],4 |               |        expected=2a71a278,hash_6,128 |        |        |        |        |        |        |
|     35 |   text,0.5,[0x100003ab4, 0x100003c1f],364 |               |                                     |        |        |        |        |        |        |
|     36 |     text,1.0,[0x100003c20, 0x100003c23],4 |               |           start=100003ea0,hash_7,96 |        |        |        |        |        |        |
|     37 |     text,1.0,[0x100003c24, 0x100003c27],4 |               |             end=100003eff,hash_7,96 |        |        |        |        |        |        |
|     38 |     text,1.0,[0x100003c28, 0x100003c2f],8 |               | expected=14d8ac0977e8efd8,hash_7,96 |        |        |        |        |        |        |
|     39 |   text,0.5,[0x100003c30, 0x100003d3f],272 |               |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     40 |    text,0.5,[0x100003d40, 0x100003d9f],96 | _switch_sw... |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     41 |    text,0.5,[0x100003da0, 0x100003dbf],32 | _tigress_exit |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     42 |    text,1.0,[0x100003dc0, 0x100003e1f],96 |          _fac |                                     | hash_0 | hash_1 | hash_2 | hash_3 | hash_4 | hash_5 |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     43 |   text,1.0,[0x100003e20, 0x100003e9f],128 |          _fib |                                     | hash_6 |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     44 |    text,1.0,[0x100003ea0, 0x100003eff],96 |          _sum |                                     | hash_7 |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     45 |    text,0.5,[0x100003f00, 0x100003f4f],80 | _tigress_r... |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     46 |     text,0.5,[0x100003f50, 0x100003f55],6 |          _dbg |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
|     47 | cstring,1.0,[0x100003f56, 0x100003fb7],98 |               |                                     |        |        |        |        |        |        |
+--------+-------------------------------------------+---------------+-------------------------------------+--------+--------+--------+--------+--------+--------+
The first three columns show that the .text-segment has been broken up into 
47 regions. The main function, for example, has been broken up into
37 regions. The fourth column shows that there are 9 checkers, named hash_0 through
hash_8. You can learn more about these checkers by inspecting the 
file generated by Tigress (the --ChecksumHashFunctionsFile=hashes.c options provide the names of
the files).  The size field shows how many bytes each hash function is
checking. The function hash_7, for example, computes a hash over 
the sum function. Columns A-F, finally, show which regions each hash
function is covering. The function hash_7, again, computes a hash
over region 44. 
            
Calling tigress_post --ShowResults will also generate tables that provide some statistical information:
            
Number of bytes checked by each hash function
=============================================
Hash function 'hash_0' checks 96 bytes
Hash function 'hash_1' checks 96 bytes
Hash function 'hash_2' checks 96 bytes
Hash function 'hash_3' checks 96 bytes
Hash function 'hash_4' checks 96 bytes
Hash function 'hash_5' checks 96 bytes
Hash function 'hash_6' checks 128 bytes
Hash function 'hash_7' checks 96 bytes
Hash function 'hash_8' checks 64 bytes
On average, a hash function checks 96.0 bytes
Number of hash function checking each byte
==========================================
4344 bytes are checked by 0 checkers
288 bytes are checked by 1 checkers
96 bytes are checked by 6 checkers
The average byte is checked by 0.2 hash functions
Note that the amount of overlap needs to be controlled with options to
both Tigress and tigress_post: for more overlap you need to
introduce more checkers (using
tigress --ChecksumRequiredNumberOfSegmentCheckers=...)
and increase the overlap rate in tigress_post (tigress_post --OverlapRate=...).
            
| Option | Arguments | Description | 
|---|---|---|
| --Transform | Checksum | Insert checkers that compute hashes over the code bytes and take action if the hashes return the wrong value | 
| --ChecksumTraceKinds | start, stop, step, check, dump10, dump16 |  List of the information that should be printed at runtime when a checker is executed. Default=NONE.
  | 
| --ChecksumHashFunctionsFile | String | The name of the generated file containing hash functions. It should be compiled into a .so file and becomes input into tigress_post. Default=hashFunctions.c. | 
| --ChecksumAddressing | relative, absolute |  How to load the address of the code region to check. Default=relative.
  | 
endbr64 after branches. In what appears to be a gcc bug, in the code below the compiler inserts the endbr64 instruction after the label, when, presumably, it should go between the test and the label. As a result, we can't correctly calculate the address of the asm instruction:
if (_2_main_1_opaque_ptr_1 == _2_main_1_opaque_ptr_2) {
   Lab_2000002: 
    __asm__ volatile (".balign 8,0xf9;\n"
                      ".long 0xAAAAA001;\n"
                      ".long 0xBBBBB001;\n"
                      ".quad 0xCCCCCCCCCCCCC001;\n":);
}
-fcf-protection=none to your gcc command line.