Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
346 views
in Technique[技术] by (71.8m points)

c++ - Encrypting / obfuscating a string literal at compile-time

I want to encrypt/encode a string at compile time so that the original string does not appear in the compiled executable.

I've seen several examples but they can't take a string literal as argument. See the following example:

template<char c> struct add_three {
    enum { value = c+3 };
};

template <char... Chars> struct EncryptCharsA {
    static const char value[sizeof...(Chars) + 1];
};

template<char... Chars>
char const EncryptCharsA<Chars...>::value[sizeof...(Chars) + 1] = {
    add_three<Chars>::value...
};

int main() {   
    std::cout << EncryptCharsA<'A','B','C'>::value << std::endl;
    // prints "DEF"
}

I don't want to provide each character separately like it does. My goal is to pass a string literal like follows:

EncryptString<"String to encrypt">::value

There's also some examples like this one:

#define CRYPT8(str) { CRYPT8_(str "") }
#define CRYPT8_(str) (str)[0] + 1, (str)[1] + 2, (str)[2] + 3, (str)[3] + 4, (str)[4] + 5, (str)[5] + 6, (str)[6] + 7, (str)[7] + 8, ''

// calling it
const char str[] = CRYPT8("ntdll");

But it limits the size of the string.

Is there any way to achieve what I want?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I think this question deserves an updated answer.

When I asked this question several years ago, I didn't consider the difference between obfuscation and encryption. Had I known this difference then, I'd have included the term Obfuscation in the title before.

C++11 and C++14 have features that make it possible to implement compile-time string obfuscation (and possibly encryption, although I haven't tried that yet) in an effective and reasonably simple way, and it's already been done.

ADVobfuscator is an obfuscation library created by Sebastien Andrivet that uses C++11/14 to generate compile-time obfuscated code without using any external tool, just C++ code. There's no need to create extra build steps, just include it and use it. I don't know a better compile-time string encryption/obfuscation implementation that doesn't use external tools or build steps. If you do, please share.

It not only obuscates strings, but it has other useful things like a compile-time FSM (Finite State Machine) that can randomly obfuscate function calls, and a compile-time pseudo-random number generator, but these are out of the scope of this answer.

Here's a simple string obfuscation example using ADVobfuscator:

#include "MetaString.h"

using namespace std;
using namespace andrivet::ADVobfuscator;

void Example()
{
    /* Example 1 */

    // here, the string is compiled in an obfuscated form, and
    // it's only deobfuscated at runtime, at the very moment of its use
    cout << OBFUSCATED("Now you see me") << endl;

    /* Example 2 */

    // here, we store the obfuscated string into an object to
    // deobfuscate whenever we need to
    auto narrator = DEF_OBFUSCATED("Tyler Durden");

    // note: although the function is named `decrypt()`, it's still deobfuscation
    cout << narrator.decrypt() << endl;
}

You can replace the macros DEF_OBFUSCATED and OBFUSCATED with your own macros. Eg.:

#define _OBF(s) OBFUSCATED(s)

...

cout << _OBF("klapaucius");

How does it work?

If you take a look at the definition of these two macros in MetaString.h, you will see:

#define DEF_OBFUSCATED(str) MetaString<andrivet::ADVobfuscator::MetaRandom<__COUNTER__, 3>::value, andrivet::ADVobfuscator::MetaRandomChar<__COUNTER__>::value, Make_Indexes<sizeof(str) - 1>::type>(str)

#define OBFUSCATED(str) (DEF_OBFUSCATED(str).decrypt())

Basically, there are three different variants of the MetaString class (the core of the string obfuscation). Each has its own obfuscation algorithm. One of these three variants is chosen randomly at compile-time, using the library's pseudo-random number generator (MetaRandom), along with a random char that is used by the chosen algorithm to xor the string characters.

"Hey, but if we do the math, 3 algorithms * 255 possible char keys (0 is not used) = 765 variants of the obfuscated string"

You're right. The same string can only be obfuscated in 765 different ways. If you have a reason to need something safer (you're paranoid / your application demands increased security) you can extend the library and implement your own algorithms, using stronger obfuscation or even encryption (White-Box cryptography is in the lib's roadmap).


Where / how does it store the obfuscated strings?

One thing I find interesting about this implementation is that it doesn't store the obfuscated string in the data section of the executable. Instead, it is statically stored into the MetaString object itself (on the stack) and the algorithm decodes it in place at runtime. This approach makes it much harder to find the obfuscated strings, statically or at runtime.

You can dive deeper into the implementation by yourself. That's a very good basic obfuscation solution and can be a starting point to a more complex one.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...