12.4 Performing Bit and Byte Obfuscation

12.4.1 Problem

Small values such as bytes, shorts, and integers are difficult to disguise while undergoing mathematical transformations. This makes the values or ranges of constants, indexes, and counters easy to determine in compiled binary code.

12.4.2 Solution

The Obcode library by Pawel Krawczyk (http://echelon.pl/pubs/) provides an API for obfuscating bit and byte values, even during the manipulation of those values. The size of the variables are inflated eightfold, so that a byte variable takes 8 bytes and an integer variable takes 32 bytes. The library provides for byte operations such as XOR, AND, OR, and NOT, and operations for integers including ADD, XOR, copy, and swap.

The Obcode library is still under development and thus is lacking in features; however, even in its current state it provides an excellent means of obfuscating small values in memory. Obfuscated values can be stored within data files or within the program itself, provided that the same seed or key is passed to obcode_init( ) for both the reading and the writing of the value.

12.4.3 Discussion

In the Obcode data types, each bit is represented by a byte. If the value of the byte is even, the value of the encoded bit is 1; otherwise, the value of the bit is 0. An Obcode byte is encoded as a series of 8 Obcode bits; likewise, an Obcode int is encoded as a series of 32 Obcode bits. Operations on Obcode values do not decode the values, but rather work on the encoded versions; therefore, the C statement:

x = y ^ z;

would be implemented as:

int i;
for (i = 0;  i < 8;  i++) {
  if (obit_get(y.s[i]) =  = obit_get(z.s[i])) x.s[i] = obit_set(0);
  else x.s[i] = obit_set(1);

where x, y, and z are Obcode bytes, obit_get( ) returns 0 if the Obcode bit argument is odd and 1 if the argument is even, and obit_set( ) returns an Obcode bit representation of the argument. The values of x, y, and z are randomly determined at runtime.

The Obcode API is defined in the file obcode.h:

/* obcode.h */
struct obyte {
  unsigned char s[8];
struct obint {
  unsigned char s[32];
extern void obcode_init(unsigned char key);
extern void obcode_finish(void);
extern unsigned char obit_set(int b);
extern unsigned char obit_get(unsigned char b);
extern void obyte_set(struct obyte *b, unsigned char c);
extern unsigned char obyte_get(struct obyte *b);
extern void obit_xor(unsigned char *b1, unsigned char *b2, unsigned char *b3);
extern void obyte_xor(struct obyte *ob1, struct obyte *ob2, struct obyte *ob3);
extern void obit_or(unsigned char *b1, unsigned char *b2, unsigned char *b3);
extern void obit_and(unsigned char *b1, unsigned char *b2, unsigned char *b3);
extern void obit_not(unsigned char *b1, unsigned char *b2);
extern void obyte_add(struct obyte *ob1, struct obyte *ob2, struct obyte *ob3);
extern void obyte_copy(struct obyte *dst, struct obyte *src);
extern void obyte_swap(struct obyte *ob1, struct obyte *ob2);

The following program demonstrates the basic usage of the Obcode library: the first argument passed to the program is XOR'd with a key, then used as an index into a table of function pointers.

#include <stdio.h>
#include <stdlib.h>
#include <obcode.h>
/* typedefs for clarity */
typedef unsigned char obit_t;
typedef struct obyte  obyte_t;
typedef struct obint  obint_t;
int obytes_equal(obyte_t *a, obyt_t *b) {
  int i;
  for (i = 0;  i < 8;  i++)
    if (obit_get(a.s[i]) != obit_get(b.s[i])) return 0;
  return 1;
/* do-nothing subroutines */
void action_write(char *arg) { printf("write %s\n", arg); }
void action_read(char *arg)  { printf("read %s\n", arg); }
void action_error(void)      { printf("ERROR: Bad parameter\n"); }{
int main(int argc, char *argv[  ]) {
  obyte_t       input, read_val, write_val;
  unsigned char i;
  if (argc < 2) {
    fprintf(stderr, "Usage: %s num string\n", argv[0]);
    return 1;
  /* initialize the obcode lib with a random key */
  /* obfuscate the first argument */
  obyte_set(&input, (unsigned char)atoi(argv[1]));
  /* obfuscate the values to compare it to--these should really be stored in
   * obfuscated form instead of generated
  obyte_set(&read_val, 63);
  obyte_set(&write_val, 112);
  /* perform comparisons */
  if (obytes_equal(&input, &read_val)) action_read(argv[2]);
  else if (obytes_equal(&input, &write_val)) action_write(argv[2]);
  else action_err(  );
  /* cleanup */
  obcode_finish(  );
  return 0;

12.4.4 See Also

Obcode library by Pawel Krawczyk: http://echelon.pl/pubs/