Data Generation Using C ++ Templates

    Once the task was set to write some small program, it had to do something, but at the same time it was required to complicate the process of code analysis during disassembly as much as possible. One of the methods is to remove from exe all references to the WinApi functions used, and it was decided to store not the WinApi function names, but some hash codes calculated by some thread with a simple algorithm. Then, when enumerating all the functions of the dll library, find the ones you need by these hash codes. One of the most commonly used methods is to write a small utility, give it an input list of the names of the necessary functions, it calculates their hash codes and outputs the source code in which the finished table with codes is located. Then this source code is connected to the project and then it is fully used. But as always, laziness intervened. It was too lazy to write such a utility, and even write the necessary actions in the make file. I wanted everything to be computed at compile time. Then a glance was cast at C ++ templates ...

    C ++ templates do not allow working with strings of type char *, you cannot write to them, you cannot read from them, you can only use a pointer to pass it somewhere further. But laziness is a stubborn thing, but what if the parameters of the template specify not the string itself, but separately characters? This is already very good, and templates can have default parameters, which is exactly what we need. Now it’s enough to write a template class whose parameters are characters (char type) and a function to calculate the hash based on the parameter values, and here is the class itself:
    
    template
    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 complicated. 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 like it?

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

    and all! Now it’s enough to declare the required number of function types and use hashes in where you need to.
    If you think that the compiler will generate a bunch of unnecessary code, then you are mistaken, there will be only one number and nothing else (try compiling yourself in assembly language).
    But this is not the limit, in this way it is still possible to encrypt strings right on the fly, at compile time.

    String encryption

    We will use a simple algorithm to encrypt strings: we will change each pair of characters in places, depending on some code parameter. To do this, add an additional buffer to our class (and where else to store the encryption?) And several special functions and voila:
    
    template
    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 in a slightly different way:
    
    code_text<44717397, 'E','n','c','o','d','e','S','t','r','i','n','g'> EncodeString;
    

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

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

    there will be a decrypted string on the screen. The decode function, of course, must be described somewhere.
    When creating an object, not a type, there is one thing, but the received data is not placed in this way in the .data section (like ordinary lines), the compiler generates code that saves the calculated data using the mov instructions. This is the so-called initialized code, and is run before the main () function is called, that is, everything is transparent for us and we can use the result as normal lines. You may also have to work on options for optimizing the compiler, since such huge inline functions can remain in your final exe, that is, you need to ensure that only the initialized code remains (data transfer) and nothing else.

    Snack

    Well, for an appetizer there is still such an example. C ++ does not have built-in binary numbers. But we can get around this using this method. Below is a class that can convert 32-bit numbers:
    
    template
    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 like 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 project to generate hashes and encoded strings, and so far everything is great, but I don’t particularly recommend it to you, it’s better to write separate utilities, though ... who knows you and your laziness)

    Also popular now: