📜 ⬆️ ⬇️

Data generation using C ++ templates

Once there was a task to write a small program, it had to do something, but it was necessary to complicate the code analysis process as much as possible during disassembly. One of the methods is to remove from the exe all references to the functions used by WinApi, and it was decided not to store the names of the WinApi functions, but some hash codes calculated by some simple algorithm. Then when listing all the functions of the dll library to find the necessary for these hash codes. One of the commonly used methods is to write a small utility, give it a list of names of the necessary functions, it calculates their hash codes and outputs the source code in which there is a ready-made table with codes. Then this source is connected to the project and then used in full. But as always laziness intervened. Too lazy to write such a utility, and even prescribe the necessary actions in the make file. I wanted everything to be computed at compile time. It was then that a look was made at C ++ templates ...

C ++ templates do not allow working with char * strings, you cannot write to them, you cannot read them, you can only use a pointer to pass it somewhere further. But laziness is a stubborn thing, but what if in the template parameters you specify not the string itself, but separate characters? This is already very good, and templates can have default parameters, and this is just what we need. Now it is enough to write a template class whose parameters are characters (type char) and a function to calculate the hash based on the values ​​of the parameters, and here is the class itself:
template<char c01 = 0, char c02 = 0, char c03 = 0, char c04 = 0, char c05 = 0, char c06 = 0, char c07 = 0, char c08 = 0, char c09 = 0, char c10 = 0, char c11 = 0, char c12 = 0, char c13 = 0, char c14 = 0, char c15 = 0, char c16 = 0, char c17 = 0, char c18 = 0, char c19 = 0, char c20 = 0, char c21 = 0, char c22 = 0, char c23 = 0, char c24 = 0, char c25 = 0, char c26 = 0, char c27 = 0, char c28 = 0, char c29 = 0, char c30 = 0, char c31 = 0, char c32 = 0 > class hash_text { public: //   static unsigned int get_hash() { unsigned int hash = c01; if( c02 ) { hash ^= (hash << 8) | c02; } if( c03 ) { hash ^= (hash << 8) | c03; } if( c04 ) { hash ^= (hash << 8) | c04; } if( c05 ) { hash ^= (hash << 8) | c05; } if( c06 ) { hash ^= (hash << 8) | c06; } if( c07 ) { hash ^= (hash << 8) | c07; } if( c08 ) { hash ^= (hash << 8) | c08; } if( c09 ) { hash ^= (hash << 8) | c09; } if( c10 ) { hash ^= (hash << 8) | c10; } if( c11 ) { hash ^= (hash << 8) | c11; } if( c12 ) { hash ^= (hash << 8) | c12; } if( c13 ) { hash ^= (hash << 8) | c13; } if( c14 ) { hash ^= (hash << 8) | c14; } if( c15 ) { hash ^= (hash << 8) | c15; } if( c16 ) { hash ^= (hash << 8) | c16; } if( c17 ) { hash ^= (hash << 8) | c17; } if( c18 ) { hash ^= (hash << 8) | c18; } if( c19 ) { hash ^= (hash << 8) | c19; } if( c20 ) { hash ^= (hash << 8) | c20; } if( c21 ) { hash ^= (hash << 8) | c21; } if( c22 ) { hash ^= (hash << 8) | c22; } if( c23 ) { hash ^= (hash << 8) | c23; } if( c24 ) { hash ^= (hash << 8) | c24; } if( c25 ) { hash ^= (hash << 8) | c25; } if( c26 ) { hash ^= (hash << 8) | c26; } if( c27 ) { hash ^= (hash << 8) | c27; } if( c28 ) { hash ^= (hash << 8) | c28; } if( c29 ) { hash ^= (hash << 8) | c29; } if( c30 ) { hash ^= (hash << 8) | c30; } if( c31 ) { hash ^= (hash << 8) | c31; } if( c32 ) { hash ^= (hash << 8) | c32; } return hash; } }; 

As you can see everything is not so difficult. The only limitation for this class is the ability to use strings with a length of no more than 32 characters, but if you need more, it is easy to expand.
How to use this class now? Everything is quite simple, take the name of the function and write it character-by-character in the template parameters:
 typedef hash_text<'C','r','e','a','t','e','F','i','l','e'> hashCreateFile; //   

How do you?

And to get the hash itself:
 hashCreateFile::get_hash(); 

and all! Now it is enough to declare the required number of function types and use hashes in where you need.
If you think that the compiler will generate a bunch of unnecessary code, then you will be mistaken, there will be only one number and nothing more (try compiling into an assembler view yourself).
But this is not the limit, in this way you can still encrypt strings directly on the fly, during compilation.

String Encryption

To encrypt strings, we will use a simple algorithm: we will change each pair of characters in places, depending on some parameter code. To do this, add an additional buffer to our class (and where else to store the encryption?) And several special functions and voila:
 template<unsigned int code, char c01 = 0, char c02 = 0, char c03 = 0, char c04 = 0, char c05 = 0, char c06 = 0, char c07 = 0, char c08 = 0, char c09 = 0, char c10 = 0, char c11 = 0, char c12 = 0, char c13 = 0, char c14 = 0, char c15 = 0, char c16 = 0, char c17 = 0, char c18 = 0, char c19 = 0, char c20 = 0, char c21 = 0, char c22 = 0, char c23 = 0, char c24 = 0, char c25 = 0, char c26 = 0, char c27 = 0, char c28 = 0, char c29 = 0, char c30 = 0, char c31 = 0, char c32 = 0 > class code_text { //     static const char count = (c01 ? 1 : 0) + (c02 ? 1 : 0) + (c03 ? 1 : 0) + (c04 ? 1 : 0) + (c05 ? 1 : 0) + (c06 ? 1 : 0) + (c07 ? 1 : 0) + (c08 ? 1 : 0) + (c09 ? 1 : 0) + (c10 ? 1 : 0) + (c11 ? 1 : 0) + (c12 ? 1 : 0) + (c13 ? 1 : 0) + (c14 ? 1 : 0) + (c15 ? 1 : 0) + (c16 ? 1 : 0) + (c17 ? 1 : 0) + (c18 ? 1 : 0) + (c19 ? 1 : 0) + (c20 ? 1 : 0) + (c21 ? 1 : 0) + (c22 ? 1 : 0) + (c23 ? 1 : 0) + (c24 ? 1 : 0) + (c25 ? 1 : 0) + (c26 ? 1 : 0) + (c27 ? 1 : 0) + (c28 ? 1 : 0) + (c29 ? 1 : 0) + (c30 ? 1 : 0) + (c31 ? 1 : 0) + (c32 ? 1 : 0); char buf[count + 1]; //     char encode_char( bool first, int bit, char b1, char b2 ) { if( b2 == 0 ) //  return b1; unsigned int change = code & (1 << bit); //    if( first ) return change ? b2 : b1; // 1-  else return change ? b1 : b2; // 2-  } //    , n -      bool put_char( int n, char c1, char c2 ) { if( c1 == 0 ) return false; //  buf[n] = encode_char( true, n / 2, c1, c2 ); if( c2 == 0 ) return false; //  buf[n + 1] = encode_char( false, n / 2, c1, c2 ); return true; } //   void encode() { int v = 0; //    ,  if   ,      ) if( put_char( 0, c01, c02 ) ) if( put_char( 2, c03, c04 ) ) if( put_char( 4, c05, c06 ) ) if( put_char( 6, c07, c08 ) ) if( put_char( 8, c09, c10 ) ) if( put_char( 10, c11, c12 ) ) if( put_char( 12, c13, c14 ) ) if( put_char( 14, c15, c16 ) ) if( put_char( 16, c17, c18 ) ) if( put_char( 18, c19, c20 ) ) if( put_char( 20, c21, c22 ) ) if( put_char( 22, c23, c24 ) ) if( put_char( 24, c25, c26 ) ) if( put_char( 26, c27, c28 ) ) if( put_char( 28, c29, c30 ) ) if( put_char( 30, c31, c32 ) ) v = 0; //   if   -  buf[count] = 0; } public: code_text() { encode(); } const char* ptr() const //    { return buf; } int len() { return count; } char* str( char* to ) { return decode( buf, count, to ); //  to } }; 

As you can see here is a little more complicated, but the meaning is the same. You need to use it a little differently:
 code_text<44717397, 'E','n','c','o','d','e','S','t','r','i','n','g'> EncodeString; 

an object is created here, and not like the type above. Well, you can apply as follows:
 printf( "%s\n", EncodeString.ptr() ); 

the screen will have an encrypted string, or
 char to[33]; printf( "%s\n", EncodeString.str(to) ); 

on the screen will be the decoded line. The decryption function (decode) naturally has to be described somewhere.
When creating an object, and not a type, there is one thing, the data obtained is not placed in this way into the .data section (like normal strings), the compiler generates code that saves the calculated data by means of mov instructions. This is the so-called initialized code, and is run before the main () function call, that is, for us everything is transparent and we can use the result as normal strings. You may also have to work on compiler optimization options, since such huge inline functions can remain in your final exe, i.e. you need to ensure that only the initialized code (data transfer) remains and nothing else.
')
Snack

Well, for a snack yet such primerchik. C ++ does not have built-in tools for writing numbers in binary. But we can get around this using this method. Below is a class that can convert 32-bit numbers:
 template<int c01 = -1, int c02 = -1, int c03 = -1, int c04 = -1, int c05 = -1, int c06 = -1, int c07 = -1, int c08 = -1, int c09 = -1, int c10 = -1, int c11 = -1, int c12 = -1, int c13 = -1, int c14 = -1, int c15 = -1, int c16 = -1, int c17 = -1, int c18 = -1, int c19 = -1, int c20 = -1, int c21 = -1, int c22 = -1, int c23 = -1, int c24 = -1, int c25 = -1, int c26 = -1, int c27 = -1, int c28 = -1, int c29 = -1, int c30 = -1, int c31 = -1, int c32 = -1 > class bin_to_dec { static unsigned int get_bit( int res, int c ) { return (res << 1) | (c ? 1 : 0); //c      0  1 } public: static unsigned int dec() { unsigned int res = 0; if( c01 >= 0 ) res = get_bit( res, c01 ); if( c02 >= 0 ) res = get_bit( res, c02 ); if( c03 >= 0 ) res = get_bit( res, c03 ); if( c04 >= 0 ) res = get_bit( res, c04 ); if( c05 >= 0 ) res = get_bit( res, c05 ); if( c06 >= 0 ) res = get_bit( res, c06 ); if( c07 >= 0 ) res = get_bit( res, c07 ); if( c08 >= 0 ) res = get_bit( res, c08 ); if( c09 >= 0 ) res = get_bit( res, c09 ); if( c10 >= 0 ) res = get_bit( res, c10 ); if( c11 >= 0 ) res = get_bit( res, c11 ); if( c12 >= 0 ) res = get_bit( res, c12 ); if( c13 >= 0 ) res = get_bit( res, c13 ); if( c14 >= 0 ) res = get_bit( res, c14 ); if( c15 >= 0 ) res = get_bit( res, c15 ); if( c16 >= 0 ) res = get_bit( res, c16 ); if( c17 >= 0 ) res = get_bit( res, c17 ); if( c18 >= 0 ) res = get_bit( res, c18 ); if( c19 >= 0 ) res = get_bit( res, c19 ); if( c20 >= 0 ) res = get_bit( res, c20 ); if( c21 >= 0 ) res = get_bit( res, c21 ); if( c22 >= 0 ) res = get_bit( res, c22 ); if( c23 >= 0 ) res = get_bit( res, c23 ); if( c24 >= 0 ) res = get_bit( res, c24 ); if( c25 >= 0 ) res = get_bit( res, c25 ); if( c26 >= 0 ) res = get_bit( res, c26 ); if( c27 >= 0 ) res = get_bit( res, c27 ); if( c28 >= 0 ) res = get_bit( res, c28 ); if( c29 >= 0 ) res = get_bit( res, c29 ); if( c30 >= 0 ) res = get_bit( res, c30 ); if( c31 >= 0 ) res = get_bit( res, c31 ); if( c32 >= 0 ) res = get_bit( res, c32 ); return res; } }; 

Use this:
 typedef bin_to_dec<1,1,1,0,0,0,1,1,1> flags; printf( "%u", flags::dec() ); 


Afterword


I use this method in one of my projects to generate hashes and encoded strings and everything is fine so far, but I don’t recommend you, write individual utilities better, though ... who knows you and your laziness)

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


All Articles