在编译时加密/混淆字符串文字

kar*_*son 15 c++ string templates metaprogramming compile-time

我想在编译时加密/编码一个字符串,以便原始字符串不会出现在已编译的可执行文件中.

我已经看过几个例子,但他们不能把字符串文字作为参数.请参阅以下示例:

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"
}
Run Code Online (Sandbox Code Playgroud)

我不想像它那样单独提供每个角色.我的目标是传递一个字符串文字,如下所示:

EncryptString<"String to encrypt">::value
Run Code Online (Sandbox Code Playgroud)

还有一些像这样的例子:

#define CRYPT8(str) { CRYPT8_(str "\0\0\0\0\0\0\0\0") }
#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, '\0'

// calling it
const char str[] = CRYPT8("ntdll");
Run Code Online (Sandbox Code Playgroud)

但它限制了字符串的大小.

有没有办法实现我想要的?

Car*_*arl 7

使用模板元编程为自己节省一大堆麻烦,只需编写一个独立的程序来加密字符串并生成一个cpp源文件然后编译进来.这个程序将在你编译之前运行并产生一个cpp和/或头文件,包含您要使用的加密字符串.

所以这就是你的开始:

  1. encrypted_string.cpp和encrypted_string.h(空白)
  2. 将文本文件作为输入并通过写入encrypted_string.cpp和encrypted_string.h的脚本或独立应用程序

如果脚本失败,则编译将失败,因为代码中将引用不存在的变量.你可以变聪明,但这足以让你开始.


kar*_*son 6

我认为这个问题值得更新。

几年前我问这个问题时,我没有考虑混淆和加密之间的区别。如果我当时知道这种区别,那么我之前会在标题中加入“ 混淆 ”一词。

C ++ 11和C ++ 14具有使以有效且合理的简单方式实现编译时字符串混淆(以及可能的加密,尽管我还没有尝试过)的功能,并且它已经完成了。

ADVobfuscator是由Sebastien Andrivet创建的混淆库,它使用C ++ 11/14生成编译时混淆代码,而无需使用任何外部工具,而仅使用C ++代码。无需创建额外的构建步骤,只需添加并使用它即可。我不知道没有使用外部工具或构建步骤的更好的编译时字符串加密/混淆实现。如果您这样做,请分享。

它不仅模糊字符串,还具有其他有用的功能,例如可以随机混淆函数调用的编译时FSM(有限状态机)和编译时伪随机数生成器,但是这些都不在本文的讨论范围之内。回答。

这是一个使用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;
}
Run Code Online (Sandbox Code Playgroud)

您可以替换宏DEF_OBFUSCATED,并OBFUSCATED用自己的宏。例如。:

#define _OBF(s) OBFUSCATED(s)

...

cout << _OBF("klapaucius");
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?

如果查看一下MetaString.h中这两个宏的定义,您将看到:

#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())
Run Code Online (Sandbox Code Playgroud)

基本上,MetaString该类有三种不同的变体(字符串混淆的核心)。每个都有自己的混淆算法。使用库的伪随机数生成器(MetaRandom)以及char选择的算法对xor字符串字符使用的随机数,可以在编译时随机选择这三个变量之一。

“嘿,但是,如果我们做数学运算,则有3种算法* 255个可能的char键(未使用0)=混淆字符串的765个变体”

你是对的。同一字符串只能以765种不同的方式进行混淆。如果您有理由需要更安全的东西(您偏执狂/您的应用程序要求更高的安全性),则可以使用更强的混淆甚至加密功能来扩展库并实现自己的算法(白盒加密技术在lib的路线图中)。


它在哪里/如何存储混淆后的字符串?

我发现有关此实现的有趣之处在于,它不会在可执行文件的数据部分中存储混淆的字符串。相反,它是静态存储在MetaString对象本身中(在堆栈上),并且算法会在运行时对其进行解码。这种方法使静态或在运行时查找混淆的字符串变得更加困难。

您可以自己深入研究实现。这是非常好的基本混淆解决方案,并且可以成为更复杂的解决方案的起点。