How to make a C macro pre-build pre-processor?

1.9k views Asked by At

Let's say I have a string that I would like to obfuscate in my code. (This example is just for learning.)

My plan is to wrap the string literal with a macro, e.g.

#define MY_STRING "lol"
const char *get_string() { return _MY_ENCRYPTION_MACRO(MY_STRING); }

and, as a pre-build step, to run my source file through my own preprocessor to look for all usages of _MY_ENCRYPTION_MACRO and obfuscate the strings accordingly.

How would I go about doing this preprocessing with Visual C++?

2

There are 2 answers

0
Basile Starynkevitch On BEST ANSWER

If you used a recent GCC (i.e. GCC 4.6) on Linux, you could also have a plugin which provides a builtin function to "encrypt" compile time strings, or you could even make it a GCC MELT extension (MELT is a high-level domain specific language to extend GCC).

If you use some other C++, you might have your own pre-processing scripts finding your macros. You might for instance have some program which scan every occurrence of ENCRYPTSTRING("anyconstantstring") in all your C++ sources, and generate a mycrypt.h file which you #include "mycrypt.h" in your C++ code. Then you might do tricks like

#define ENCRYPTSTRING(S) ENCRPYTSTRING_AT(S,__LINE__)
#define ENCRYPTSTRING_AT(S,L) cryptstring_#L

and have your generated "mycrypt.h" contain things like

const char crypstring_123[]="thecryptedstringatline123";

etc. The "mycrypt.h" generator could be an awk or python or ocaml (etc...) script.

2
SSpoke On

I posted this answer on a couple of questions as many people have this problem such as myself, I also thought this wasn't possible, even though it's very simple, people wrote solutions where you need a custom tool to scan the built file afterwards and scan for strings and encrypt the strings like that, which wasn't bad but I wanted a package that's compiled from Visual Studio, and it's possible now!

What you need is C++ 11 (Visual Studio 2015 Update 1 out of the box)

the magic happens with this new command constexpr

By magic happens in this #define

#define XorString( String ) ( CXorString<ConstructIndexList<sizeof( String ) - 1>::Result>( String ).decrypt() )

It won't decrypt the XorString at compile-time, only at run-time, but it will encrypt the string only in compile-time, so the strings will not appear in the Executable file

printf(XorString( "this string is hidden!" ));

It will print out "this string is hidden!" but you won't find it inside Executable file as strings!, check it yourself with Microsoft Sysinternals Strings program download link: https://technet.microsoft.com/en-us/sysinternals/strings.aspx

The full source code is quite large but could easily be included into one header file. But also quite random so the encrypted string outputs will always change every new compile, the seed is changed based on the time it took it compile, pretty much solid,perfect solution.

Create a file called XorString.h

#pragma once

//-------------------------------------------------------------//
// "Malware related compile-time hacks with C++11" by LeFF   //
// You can use this code however you like, I just don't really //
// give a shit, but if you feel some respect for me, please //
// don't cut off this comment when copy-pasting... ;-)       //
//-------------------------------------------------------------//

////////////////////////////////////////////////////////////////////
template <int X> struct EnsureCompileTime {
    enum : int {
        Value = X
    };
};
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//Use Compile-Time as seed
#define Seed ((__TIME__[7] - '0') * 1  + (__TIME__[6] - '0') * 10  + \
              (__TIME__[4] - '0') * 60   + (__TIME__[3] - '0') * 600 + \
              (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000)
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
constexpr int LinearCongruentGenerator(int Rounds) {
    return 1013904223 + 1664525 * ((Rounds> 0) ? LinearCongruentGenerator(Rounds - 1) : Seed & 0xFFFFFFFF);
}
#define Random() EnsureCompileTime<LinearCongruentGenerator(10)>::Value //10 Rounds
#define RandomNumber(Min, Max) (Min + (Random() % (Max - Min + 1)))
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
template <int... Pack> struct IndexList {};
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
template <typename IndexList, int Right> struct Append;
template <int... Left, int Right> struct Append<IndexList<Left...>, Right> {
    typedef IndexList<Left..., Right> Result;
};
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
template <int N> struct ConstructIndexList {
    typedef typename Append<typename ConstructIndexList<N - 1>::Result, N - 1>::Result Result;
};
template <> struct ConstructIndexList<0> {
    typedef IndexList<> Result;
};
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
const char XORKEY = static_cast<char>(RandomNumber(0, 0xFF));
constexpr char EncryptCharacter(const char Character, int Index) {
    return Character ^ (XORKEY + Index);
}

template <typename IndexList> class CXorString;
template <int... Index> class CXorString<IndexList<Index...> > {
private:
    char Value[sizeof...(Index) + 1];
public:
    constexpr CXorString(const char* const String)
    : Value{ EncryptCharacter(String[Index], Index)... } {}

    char* decrypt() {
        for(int t = 0; t < sizeof...(Index); t++) {
            Value[t] = Value[t] ^ (XORKEY + t);
        }
        Value[sizeof...(Index)] = '\0';
        return Value;
    }

    char* get() {
        return Value;
    }
};
#define XorS(X, String) CXorString<ConstructIndexList<sizeof(String)-1>::Result> X(String)
#define XorString( String ) ( CXorString<ConstructIndexList<sizeof( String ) - 1>::Result>( String ).decrypt() )
////////////////////////////////////////////////////////////////////