Plugins

 
free web templates

Tigress has a simple way of letting you add code (we call them plugins) that we can then incorporate into the obfuscated program. For now, there are just two applications of plugins: you can provide your own responders and invariants which are proprietary to you and unique to your application. Responders are code snippets that will be invoked when there has been some sort of integrity violation, such as a checksum failure, and invariants are true facts about your code that can be used to create opaque predicates. These are the available options:

OptionArgumentsDescription
--Transform InitPlugins Initialize the plugin system.
--InitPluginsInvariantPrefix String The prefix for the name of invariant plugin functions. Default=NONE.
--InitPluginsResponderPrefix String The prefix for the name of responder plugin functions. Default=NONE.

free web templates

Plugin functions can take parameters. Two special parameters {\tt argc} and {\tt argv} (of type int and char**, respectively) will be initialized with the arguments passed to main(). Any remaining formal parameters (which need to be of arithmetic types) will be initialized with random local variables found where the plugin function is inserted. They can be read but should, obviously, not be modified, unless you're writing a responder that you want to crash the program.

free web templates

The plugin functions are only used during obfuscation and are removed from the resulting program.

 

Invariants

free web templates

The purpose of invariant plugins is to allow the application developer to provide properties about the program that Tigress itself would not be able to figure out. These properties can then be used in Tigress transformations, often causing the program to crash or misbehave if an adversary modifies the program such that the invariants no longer hold.

free web templates

Invariant plugin functions should always return an int. The name of an invariant plugin function should start with the prefix (set by the --InitPluginsInvariantPrefix=prefix option) and be followed by an encoding of the value(s) the function will return. These are the possible specifications:

  • ANY : the function returns an arbitrary value.
  • VALUE_value : the function always returns the integer value.
  • MIN_value : the function always returns an integer greater than or equal to value.
  • MAX_value : the function always returns an integer less than or equal to value.
  • RANGE_from_to : the function always returns an integer in the range [from, to], inclusive.
free web templates

For example, if you have set --InitPluginsInvariantPrefix=acme you could add the following function to your application:

int highScore = 0;     /* Always less than 100! */
...
int acme_RANGE_0_99 (void) {
   return highScore;
}
free web templates

The idea here is that transformations which use opaque predicates will introduce code that assumes that 0 ≤ highScore < 100. If an attacker modifies the code so that highScore is outside of this range, the program will start to misbehave.

free web templates

Here is how you would call Tigress with the AddOpaque transform:

tigress \
           --Transform=InitPlugins  --InitPluginsInvariantPrefix=acme    \
           --Transform=InitOpaque --Functions=main --InitOpaqueStructs=plugin    \
           --Transform=AddOpaque \
              --Functions=* \
              --AddOpaqueKinds=true \
              --AddOpaqueStructs=plugin	\
free web templates

Here are some examples of invariant plugin functions:

/* Returns a random value */
int acme_ANY (void) {
   return list_length(myList);
}

/* Returns 42. */
int acme_VALUE_42 (void) {
   return aes_key[4];
}

/* Returns 5. */
int acme_VALUE_5 (void) {
   return 5;
}

/* Returns a value in [10..]. */
int acme_MIN_10 () {
   return 10 + random();
}

/* Returns a value in [..10]. */
int acme_MAX_10 () {
   return (random() % 11);
}

/* Returns a value in [10..20]. */
int acme_RANGE_10_20 () {
   return 10 + (random() % 11);
}

/* Returns the length of the argument list, for a program
   that is expected to be called with 1,2, or 3 arguments . */
int acme_RANGE_1_3 (int argc) {
   return argc;
}
 

Responders

free web templates

Tigress has a few simple built-in responders that can be used in the Checksum transformation. With plugins, you can easily add your own responders to your application. Responder plugin functions should always return void.

free web templates

Here is how you would invoke Tigress to use your own plugin responders with the Checksum transform:

tigress \
         --Transform=InitPlugins  --InitPluginsResponderPrefix=acme_responder    \
         --Transform=Checksum ... --ChecksumResponseKinds=plugin ... \
         ...
free web templates

Here are some simple examples of responder plugins:

void acme_responder_1 () {
   abort();
}
void acme_responder_2 (int argc, char** argv) {
   argv[argc-1] = '\0';
}
void acme_responder_3 () {
   for(int i=0; i<10; i++) {
      printf("Hacked %i!\n", i);
   }
   exit(-1);
}
void acme_responder_4 () {
   phone_home("We've been hacked!");
}

void acme_responder_5 () {
   memset(aes_key, 0, 16);
}
 

Write Your Own Opaque Library!

free web templates

Using plugins you can write your own opaque predicate library. Two more plugin functions are available to facilitate this, initialize and update:

OptionArgumentsDescription
--Transform InitPlugins Initialize the plugin system.
--InitPluginsInvariantPrefix String The prefix for the name of invariant plugin functions. Default=NONE.
--InitPluginsInitializePrefix String The prefix for the name of initializer plugin functions. Default=NONE.
--InitPluginsUpdatePrefix String The prefix for the name of update plugin functions. Default=NONE.

free web templates

Here's a simple example of a library that you would add to the beginning of your application:

int alwaysEven;

void acme_initialize_even (int argc) {
   alwaysEven = (argc+1) * 2;
}

void acme_update_even_1 () {
   alwaysEven += 2;
}

void acme_update_even_2 (int f) {
   alwaysEven += f + (f % 2);
}

int acme_invariant_even_VALUE_0 (void) {
   return alwaysEven%2;
}
free web templates

This library adds a global variable alwaysEven which, as the name implies, is alwyas even. The body of the initialize_even function will be inserted in the function where you want initializations to take place, and the two update functions will be inserted by the UpdateOpaque transformation. Here is the call to Tigress:

tigress  ... \
     --Transform=InitPlugins  \
        --InitPluginsInvariantPrefix=acme_invariant    \
        --InitPluginsInitializePrefix=acme_initialize    \
        --InitPluginsUpdatePrefix=acme_update    \
     --Transform=InitOpaque   \
         --Functions=main \
          --InitOpaqueStructs=plugin    \
     --Transform=AddOpaque \
        --Functions=* \
        --AddOpaqueKinds=true \
        --AddOpaqueStructs=plugin \
     --Transform=UpdateOpaque \
        --Functions=* \
        --UpdateOpaqueCount=10 
free web templates

Below is another example which uses linked list to make an opaque predicate library. There are two invariants that hold over this list: the list is always of even length and the elements of the list are always odd:

free web templates

typedef struct intList {
   struct intListNode* first;
} *INTLIST;

typedef struct intListNode {
   int value;
   struct intListNode* next;
} *INTLISTNODE;

typedef INTLIST intList_t;
typedef INTLISTNODE intListNode_t;

intList_t list;

void acme_initialize_list (int argc) {
   list = (intList_t) malloc(sizeof(struct intList));
   list->first = NULL;
   for(int i=0; i < (argc * 2); i++) {
      intListNode_t r = (intListNode_t) malloc(sizeof(struct intListNode));
      r->value = i*2+1;
      r->next = list->first;
      list->first = r;
   }
}

void acme_update_list (int v1, int v2) {
   intListNode_t r = (intListNode_t) malloc(sizeof(struct intListNode));
   r->value = v1*2+1;
   r->next = list->first;
   list->first = r;
   r = (intListNode_t) malloc(sizeof(struct intListNode));
   r->value = v2*4+1;
   r->next = list->first;
   list->first = r;
}

int acme_invariant_length_VALUE_0 () {
   int length = 0;
   intListNode_t i = list->first;
   while (i != NULL) {
     length++;
     i = i->next;
   };
   return length % 2;
}

int acme_invariant_odd_VALUE_0 (int v) {
   int value = 3;
   intListNode_t i = list->first;
   int times = v;
   while ((i != NULL) && (times > 0)) {
     value = i->value;
     times--;
     i = i->next;
   };
   return value % 2 - 1;
}