Obfuscated C code

Creating barely useful code that is as small as possible.

On this page I will talk about my experience with obfuscated C code, but we must go over one question first.

Why small code?

Well, why not? Seriously, the only point in writing obfuscated code is if you don't intend people to understand it, but that'd be stupid. In fact, writing code as short as possible does not always give you the smallest executable or smallest RAM usage in the end, so why? Well, there's not really a point in doing that indeed except for fun. You may have heard of the long-running International Obfuscated C Code Contest before. If not, the goal of that yearly contest is to write code as obfuscated as possible, without any reason - the only award the winner gets is to be displayed on the website. It's kinda the same for me, I did these 2 programs for fun and really liked it, so i wouldn't say it's time lost - and it brought me to some interesting aspects of the C language as well. Now before we go on to explain the code, we need to talk about the BMP file format.

The BMP format

A BMP file (generally with a .bmp extension) is a bitmap file format (so, an image) developed by Microsoft as a format intended for OS/2, but that is still used today by some devices and software due to how easy it is (e.g. the Nintendo 3DS's photos are taken in BMP format.)
Since both my programs make use of the simplicity of that file format, we need to go over it to understand the code better.
A standard BMP file is composed of 3[1] parts:
 - The BMP header
 - The DIB header
 - The pixel data
Now you might be thinking, "what's a DIB header?". DIB is short for Device-Independent Bitmap and it is in fact what will contain the information about the pixel data. This is because when loading a BMP file in memory, it becomes a DIB data structure, which is almost the same but doesn't have the BMP header, so another header is needed.
Let's start with the BMP header. This header is 14 bytes long and contains:
 - The BMP magic - 2 bytes, almost always BM
 - The size of the file in bytes - 4 bytes
 - Reserved - 2 bytes, we can use 0
 - Reserved - 2 bytes, we can use 0
 - The starting byte of the pixel data.
That starting byte is basically size of BMP header + side of DIB header, which is, in our case, 14 + 40 = 54.
Now we can talk about the DIB header, and there's some things to say. There is 7 (!!) different versions of DIB headers - the first one used in OS/2 was named BITMAPCOREHEADER and was 12-byte long, however it's not used today anymore and nearly all BMP images have a DIB header named BITMAPINFOHEADER, which is 40-bytes long.
I'll go over it quickly since there's more info but here's what BITMAPINFOHEADER contains:  - Size of header in 4 bytes -> 40
 - Image width in pixels, 4 bytes
 - Image height in pixels, 4 bytes
 - Number of color planes, 2 bytes, always 1
 - Number of bits per pixel, 2 bytes
 - Compression method, 4 bytes
 - Image size, 4 bytes
 - Horizontal resolution in pixel per metre, 4 bytes
 - Vertical resolution in pixel per metre, 4 bytes
 - Number of colors in the palette, 4 bytes
 - Numbers of important colors used, 4 bytes
Now we can already define some of these values before diving into the code. The number of colors in the palette is not important and can simply be set to 0, which defaults to 2n with n being the bits per pixel set earlier. The important colors is generally set to 0 as well (what's an "important" color, even?)
The image size is literally width*height*bytes per pixel. The compression method I used is 0 which is no compression - there is other values that go up to 13 (why saving 4 bytes for a value that takes maximum 1?) but i've never seen them being used.
The number of pixels per metre is something I never understood so I used some values I stole somewhere. The rest of the data depends on the image itself so now we can finally get to the code.

amogus.c

amogus.c is the first obfuscated program I made for fun and its goal is to make a BMP file that display as much pixel art amogus as the user enters in. One looks like this (upscaled for the sake of explaining):
Pixel art amogus
So if the user runs the program with argument 5, the output would be this (upscaled):
5 pixel art amoguses
You might already have noticed that these are all grayscale image - this is to make it easier, since grayscale colors in hexadecimals have the same value for red, green and blue. In fact, we will be using 24 bits per pixel (remember, that was an info to fill in the DIB header) because that corresponds to standard RGB - 32bpp being standard RGBA, but we do not need any transparency.
As for the size of this image, the height is always 5 pixels, and the width is always 4 times the number entered by the user, meaning we also have this and the size filled in the DIB header.
Maybe it's time to introduce the code already:

P(x){putchar(x);}o=255;i=0;j,k,d
,w,c;main(_,v)char**v;{w=4*atoi(
v[1]);d=w*15;c=d+54;char h[54]={
66,77,c&o,c>>8&o,c>>16&o,c>>24&o
,0,0,0,0,54,0,0,0,40,0,0,0,w&o,w
>>8&o,w>>16&o,w>>24&o,5,0,0,0,1,
0,24,0,0,0,0,0,d&o,d>>8&o,d>>16&
o,d>>24&o,19,11,0,0,19,11};for(;
i<54;i++)P(h[i]);float f[]={0,1,
0,1,0,1,1,1,.7,1,1,1,.7,1,.5,.5,
0,1,1,1};for(i=0;i<20;i+=4)for(j
=0;j<w/4;j++)for(k=0;k<4;k++){c=
f[i+k]*o;P(c);P(c);P(c);}}

Okay, this is really condensed so if you want to see a more readable version, i don't blame you, here it is.
Let's start by the first function : P(x){putchar(X);}. This is simply a short for putchar which we will use multiple times during the code. In fact, there is no mention of a file in that code, we will throw all the BMP data to stdout, so you might want to redirect the output to a file when executing the code.
Also, every function or variable defined outside of a function defaults to int, so this is a valid declaration, and so i the declaration of the variables o, i, j, k, d, w and c.
We'll get to some of these later, but a quick explanation is that declaring o to 255 avoids using 255 as a value later since it's longer, and declaring all the others is shorter since you don't need the int keyword.
Now to the main function. The declaration of a typical main function goes like this:

int main(int argc, char ** argv){
    // code...
}

Tho you might also see char * argv[], but it is of course longer. well, here, the function declaration (with proper variable names) looks like this:

int main(_, argv) char ** argv; {
    // code...
}

This is called an initializer list or K&R style function declaration and is valid syntax. While rarely used normally, it allows us to only define argv here since we don't need argc.
Next we have the usage of the atoi function, but you may notice that we don't include any header files. In fact, you might have noticed that when I talked about putchar before. This code heavily relies on implicit function declarations and on what the compiler implements - as such, this code might not work on all platforms (but it works on gcc, clang, and tcc on linux, so that's probably enough.)
We multiply the user-entered value by 4 and we already have our image width in pixels. Then we set d (the size of the pixel data in bytes) to the width times 15, which is the height (5) multiplied by the number of bytes per pixel (3). Then we set c (that, plus the size of both headers) and after that is the header data. I set the array size at 54 (because it is 54) but I do not provide all values because C autocompletes that, which is pretty convenient. Also, all the c>>X&o things is just because this is an array of chars (so, on most computers, bytes) and because an int is larger than one byte, I need to offset these ints for them to fit in bytes. o is a variable previously set to 255 so it's shorter to write.
Right after defining that, we pass it to P then set some data in an array of floats :
float f[]={0,1,0,1,0,1,1,1,.7,1,1,1,.7,1,.5,.5,0,1,1,1}. To understand that, we need to multiply each value by 255 : 0 stays 0, 1 is 255, .7 becomes 178.5 and .5 becomes 127.5. From 0 to 255, sounds familiar? Indeed, because that's from 0x00 to 0xFF, and if we print 3 times that, we get from 0x000000 to 0xFFFFFF, which are black and white in RGB colors. So this float array is simply our amogus pixel by pixel! It was much more convenient to store that as floats, since it takes less space.
But if we print that data in a terminal, it looks like this:

 0 1 0 1
 0 1 1 1
.7 1 1 1
.7 1.5.5
 0 1 1 1

Which is :

upside down amogus

Now of course, that doesn't look right. However, it turns out BMP still has a quirk : it stores lines from bottom to top.
So now that we have our correct data, we can start printing it. There's 3 for loops there, here's how it goes:

for(i=0;i<20;i+=4)

We start the first for loop. Since i is incremented by 4 every loop, we wil only do 5 loops of this one, which is our image height.

for(j=0;j<w/4;j++)

We start the second for loop. This for loop will be repeated the amount the user entered on start.

for(k=0;k<4;k++)

And we start the third loop. This one has k as a variable and will execute 4 times, which is the width in pixels of an amogus.

c=f[i+k]*o;P(c);P(c);P(c);

And finally, we print our character, c, 3 times (again, since this is grayscale the value used is the same for R, G and B).
But first we set c to f[i+k]*o. remember, i increments by 4 every time, which is the lenght of one line of an amogus. So depending on the value of i, we will print a different line.
Then to that we add k, which is between 0 and 3. Finally, we multiply that by o (255) to get a value between 0 and 255. This effectively prints 3 times the byte, does that for the whole line, and repeats it j times. Then, it goes to the next line, etc.
Here's a very simplified quick gif of the loops if the user entered 2:
Anyways, all this is

pixelart.c

pixelart.c is also a small program that has to do with BMP! This one takes in a filename and a number and generates a pixelart with random colors, the random seed being the number given by the user.
It needs a tiny bit more explanations before jumping in the code. Since I use random colors, I need an array of arrays of ints. A byte can be from 0 to 255 so I have an array with size 255 filled with arrays of size 3 (for R, G and B).
Unlike amogus.c, where I could just store as is the RGB values (grayscale there, but it was stored in the code), here a files is opened, as such we need to read the file once to determine the random color of a char (byte - wchar is not supported). We also use that to check the number of lines, as well as the longest line which is gonna be the width in pixels.
Now, there's one last important thing to mention. The BMP format requires that every line of pixels has to be stored as a multiple of 4 bytes. In amogus.c, the width of an amogus was 4 bytes, so that was not a problem at all. However here, it's not always the case, as it depends on the input file. To fix that issue, we have 2 solutions:
 - Use 32 bits per pixel, so 4 bytes, meaning the line will always be a multiple of 4 bytes, but add FF after every RGB color since 32bpp is RGBA
 - Use 24 bits per pixel, so 3 bytes, but add 00 padding bytes until we reach a multiple of 4.
While the second solution may seem more complicated, it's the one I went with because it seemed more interesting and it's convenient that we can use 00 as a padding since we also need to use 00 as black for lines that are not as long as the longest one.
Just to make sure you understand the deal with the longest line values, here are some files and their expected output:


        

Which is :

upside down amogus

Since the code is slightly bigger, let's jump in directly:

f,c,i,l=0,s=0,r=0,e,d,o,k=255;a[255][3
];P(X){putchar(X);}main(_,v)char**v;{f
=open(v[1],0);srand(atoi(v[2]));while(
read(f,&c,1)){if(c==10){++r;l=s>l?s:l;
s=0;}else++s;for(i=0;!a[c][2];++i)a[c]
[i]=rand()%k+2;}l=--s>l?s:l;o=((l*3/4)
+(l*3%4>0))*4;e=54+o*r++;r=-r;d=e-54;c
=s=i=0;int h[54]={66,77,e&k,e>>8&k,e>>
16&k,e>>24&k,0,0,0,0,54,0,0,0,40,0,0,0
,l&k,l>>8&k,l>>16&k,l>>24&k,r&k,r>>8&k
,r>>16&k,r>>24&k,1,0,24,0,0,0,0,0,d&k,
d>>8&k,d>>16&k,d>>24&k,19,11,0,0,19,11
};lseek(f,0,0);for(;i<54;i++)P(h[i]);
while(read(f,&c,1)){if(c!=10)for(i=0;i
<3;i++){P(a[c][i]-1);s++;}else{for(;s<
o;s++)P(0);s=0;}}for(;s<o;s++)P(0);
close(f);}