Numerical Signatures (with a Bit of Magic)
Posted by Mariia Mykhailova on January 31, 2011I've always been fascinated by programming magic - small tricks which make seemingly meaningless code do something unexpected. The most famous of such tricks are "signatures", which output a short text (usually author's name). My previous post featured several unusual ways of printing text using esoteric programming languages, and (surprisingly) it helped someone to make their new-year greetings something special. But real magic is doing such things in common everyday languages, like C++ or Java. In this writeup I will show several ways to print short text using only numeric constants as raw data.
Disclaimer. Tricks given in C++ are based on low-level memory manipulations, thus the results may vary depending on platform and compiler. I'm using gcc 4.4.1 on 32-bit Ubuntu, and it all works fine for me, but the codes are not too portable.
C++ favors marginal manipulations with memory, pointers, bitwise representation of numbers and stuff like that, so obfuscations like representing a string as a number are almost common for this language. The simplest example follows:
#include <stdio.h> int main() { int A = 2037539149; printf((char *)&A); }
How does it work? The first (and the only one which is really necessary) parameter of printf function is char * format, which describes the format of the output. Usually it is a constant string, and variable part of the output is formed using later parameters. However, using simply a char * variable works as well, though the compiler warns that "format not a string literal and no format arguments". (char *)&A treats the pointer to varible A as a pointer to character array, regardless of what the type of variable A really is. After realizing this, the things are easy: put into A bytes which will be interpreted as the required word: for "Mary" it will be 0x4D 0x61 0x72 0x79 -> hexadecimal 0x7972614D (bytes are reversed, since characters are printed from lowest order byte to highest order) -> decimal 2037539149.
The limitation of this method is that it can output only 4 intended characters, after that things go really random - the "string" we output has no end-of-string character, so it proceeds to next bytes in memory. For a clean job, you should output 3 characters you want and end-of-string after them. Replacing the data type with unsigned long long allows to extend the message to 8 characters (or 7 + end-of-string):
#include <stdio.h> int main() { unsigned long long A = 8751164009814452552ULL; printf((char *)&A); }
Let's complicate the task and move from integer numbers to floating-point ones; less people understand their intrinsic details, so this increases obfuscation level. The simplest example is:
#include <stdio.h> int main() { double A = 2.222663600523023e-313; printf((char*)&A); }
How does this work? In exactly the same way as previous ones, except for that the constant to output is trickier to construct. To output "Mary" + line feed, we need bytes 0x4D 0x61 0x72 0x79 0x0A placed in memory. To find a constant which is written using these bytes, one can use the following hack:
- Write the bytes to a string as a hexadecimal number, same as before: "A7972614D" (decimal works the same, but converting the bytes to it is an extra step).
- Read a number from this string as unsigned long long, but write it to a double variable.
- The resulting double variable print with maximal possible precision, for example, using STL tools.
#include <stdio.h> #include <iostream> #include <iomanip> #include <limits> using namespace std; int main() { double a; sscanf("A7972614D", "%llx", (unsigned long long *)&a); cout << setprecision (numeric_limits<double>::digits10 + 1) << a << endl; }
If desired, the code can be complicated some more, for example, the printed value can be given not immediately but as a result of some calculation. It would be really cool to get some text from magic constants of Pi, E, golden ratio etc. This particular writeup has been inspired with a lovely recursive signature like this (the constant is fixed to print my name):
#include <stdio.h> double x = 0.003609087829883, y; int main() { return(*(char*)&x?x*=y=x,main():printf((char*)&y)); }
After adding some whitespace and some debug output one can find out that this snippet recursively squares x and prints the last non-zero power of it (once again as a string). A text of 4 characters is represented with a constant of order of magnitude 10-300, so the square of this constant really becomes 0. The initial constant in the code is calculated as a square root (applied several times) of text's constant.
A lot of languages deny the programmer that level of liberty in memory manipulation, so one has to use something more traditional - representing the number in non-decimal base. Was my name Ada, I could have done it with hexadecimal, but Mary requires a base of at least 35, and preferably 36:
public class Magic { public static void main(String[] args) { System.out.println(Integer.toString(1040398,36)); } }
Sincerely yours,
1446440069272325681930