lkubuntu

A listing of random software, tips, tweaks, hacks, and tutorials I made for Ubuntu

Category Archives: programming

Fun obfuscation in openlux

I was working on a free software alternative to f.lux named openlux a while ago, and I wasn’t working on any interesting aspects of the program, just rewriting functions, which gets a bit tedious after a while, so I decided to try writing one part of the code in a slightly different manner, for fun! :D

The code is supposed to add a variable to another if a character is ‘+’, and subtract it if the character is ‘-‘. Here would be how one might implement this:

int a = /* something */;
unsigned short b = /* something ... note that b is a smaller data type than A, this is important */;
char chr = /* '+' or '-' */

if (chr == '+')
    return b + a;
else
    return b - a;

After a few hours (maybe even a day, I’m not very good at this :P), I came up with this instead:

a = (0x80000000 | a) ^ (0x80000000 - !!(chr - 43));
if (a & 0x80000000) a++;
return a + b;

To dissect this, let’s start with the easiest part (other than return a + b;, of course :P): !!(chr - 43).

43 is simply the value of ‘+’. Yes, okay, that was a bit cheap :P So, what !!(chr - '+') does is that it will return 0 if chr == ‘+’, 1 otherwise. This could be have been rewritten as (chr != '+').

Easy part out of the way, let’s look at how numbers are encoded, via example, in binary:

00000000 = 0
00000001 = 1
00000010 = 2
00000011 = 3
(...)

So far so good, right? But what about when we reach 10000000? If it’s an unsigned byte, it will return 128 (2^7). If it’s signed, however, it will return -127:

(...)
01111111 = 127
unsigned 10000000 = 128
signed   10000000 = -127
unsigned 10000001 = 129
signed   10000001 = -126
(...)

In both cases, the number will keep getting larger after 10000000, but if it’s signed, it will have wrapped around to -127.

Let’s see larger values:

(...)
unsigned 11111101 = 253
signed   11111101 = -3
unsigned 11111110 = 254
signed   11111110 = -2
unsigned 11111111 = 255
signed   11111111 = -1

Notice that the largest value for the signed number is not 0, but rather, -1. This is important. If it was 0, then it would mean inverting the bits of a number would make it negative (i.e. ~n == -n).

So what would inverting the bits do?

11111111 = -1
00000000 = 0

11111110 = -2
00000001 = 1

11111101 = -3
00000010 = 2

11111100 = -4
00000011 = 3

(...)

Notice a pattern here? If we want to turn a negative number positive, we can do it via (~n) - 1. Vice-versa, it’s (~n) + 1.

Alright, back to the code!

(0x80000000 - (chr != '+'))

0x80000000 can be represented in binary as 10000000000000000000000000000000. In other words, the sign bit for a 32-bit integer. So if chr == '+', it will simply evaluate as 0, and therefore, keeping 0x80000000 intact. Otherwise, it will turn it into 0x7fffffff, which is equivalent to 01111111..., or ~0x80000000.

(0x80000000 | a) simply returns a, with the sign bit on.

Now, to deal with the xor part, let’s use a few examples to clarify:

chr = '+';
(0x80000000 | a) ^ (0x80000000 - (chr != '+'));
(0x80000000 | a) ^ (0x80000000 - 0);
// 0x80000000 ^ 0x80000000 cancel each other out, leaving us with 'a', unchanged (assuming a < 0x80000000)

chr = '-';
(0x80000000 | a) ^ (0x80000000 - (chr != '+'));
(0x80000000 | a) ^ (0x7fffffff);
// assuming a < 0x80000000, this is equivalent to ~a, because the sign bit is left on, while every bit of a is inversed
// as we discussed, ~a is equal to ((-a) - 1)

if (a & 0x80000000) a++; checks if the sign bit is set (i.e. a < 0), and if so, increments a so that it gets the correct (negative) value, for the reasons I explained earlier.

Lastly, all we have to do is return a + b;, which should hopefully be pretty obvious :P

Let’s recap quickly

If chr == '+', a is left unchanged, and the result is simply a + b

If chr != '+', a‘s bits are inverted, and then incremented so that it can be equivalent to a = -a, so the result would be (assuming a’s original value, not the inverted+incremented value): -a + b or b - a.

I hope that you found this interesting, or at least fun to read! I’m sorry if this isn’t very clear, I’m sort of writing this to try and get to sleep, I’ll edit it tomorrow :)