📜 ⬆️ ⬇️

Numeric signatures

I have always been fascinated by the magic of programming - little tricks in which the seemingly meaningless code does something interesting. The most famous of them are “signatures”, which print a short text (usually the name of the author). Last time I showed a few such tricks based on esoteric programming languages, and some readers even came in handy when preparing New Year's greetings :-) The real magic is creating such things in a perfectly normal language that you use every day, for example, C ++ or Java. In this article I will show several ways to display a short text using only numeric constants as input data.

Disclaimer: Most of these tricks are based on low-level actions with memory, so the results can vary depending on the computer architecture and the compiler used (I use gcc).


C ++ calmly treats marginal manipulations with memory and pointers, so obfuscation of the type of specifying a row with a number is almost a common thing :-) The simplest example:
')
#include <stdio.h> int main() { int A = 2037539149; printf((char *)&A); } 


How it works? The first and only required argument to the printf function is char * format, which specifies the output format. Usually a constant string is passed to it, and the variable parts are taken from the following arguments; using the char * variable as an argument also works, albeit with a compiler warning “format not a string literal and no format arguments”.

(char *) & A treats the address of variable A as a pointer to an array of characters (regardless of what is actually stored in this variable). Things are going to be easy: put in A the bytes that make up the desired word, for example, Mary -> 0x4D 0x61 0x72 0x79 -> 0x7972614D (the characters are printed in the reverse order, from low order to high order) -> 2037539149.

The limitation of this method is that it displays words up to 4 letters long; it will no longer fit into an int. 8 letters can be obtained by replacing int with unsigned long long:

 #include <stdio.h> int main() { unsigned long long A = 8751164009814452552ULL; printf((char *)&A); } 


Complicate the problem and move from integers to floating-point numbers. In their internal representation fewer people understand, so it will increase the degree of obfuscation :-)

The simplest example:

 #include <stdio.h> int main() { double A = 2.222663600523023e-313; printf((char*)&A); } 


How it works? In the same way, just getting a constant to output a specific string is a little more difficult. To display “Mary” with a line break after the name, you need to have in memory a set of bytes 0x4D 0x61 0x72 0x79 0x0A. To search for a double-constant, which is written by these bytes, you can use the following hack:
1. Write the necessary bytes to the string as a hexadecimal number (similar to the first method): A7972614D.
2. From this line read the number as unsigned long long, but write it into a double variable.
3. Print the resulting variable as accurately as possible, 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 you wish, you can complicate the code, for example, to set a numeric constant not directly, but as the result of some calculations. It would look great to get text from the magic constants pi, e, the golden section, etc. This article was inspired by the strange recursive signature of the following form (constant changed):

 #include <stdio.h> double x = 0.003609087829883, y; int main() { return(*(char*)&x?x*=y=x,main():printf((char*)&y)); } 


By reformatting and adding debugging pins one can make sure that this code recursively squares the number x and prints the last non-zero degree (again, as a string). Since the text of 4 characters is represented by a constant of the order of 10 -300 , the square of this constant really becomes zero. The source constant in the code is calculated as the root of the degree of two of the text constant.

Many languages ​​do not allow the programmer such liberties with memory and data types, but you can get by in a more classical way — by representing a number in a number system other than decimal. If my name was Ada, it would be possible to limit to hexadecimal numbers, 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)); } } 


Respectfully,
370288658856287000618250P

Source: https://habr.com/ru/post/112831/


All Articles