C ++:如何在编译时encryptionstring?

我想在我的.exe中隐藏一些string,所以人们不能简单地打开.exe,看看那里的所有string。 我不关心encryption方法的强度,所以我可能会使用XOR等。

我怎样才能在编译时做到这一点? 这样我的string将不会存储在.exe中,但encryption版本会。 然后,我会每次使用我的解密函数在屏幕上显示这些string。

您可以使用宏对其进行加密或编写自己的预处理器

#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"); 

我也认为这是不可能的,即使它很简单,人们写了解决方案,你需要一个自定义工具来扫描构建的文件,然后扫描字符串和加密字符串,这不是坏的,但我想从Visual Studio编译的包,现在就可以了!

你需要的是C++ 11 (开箱即用的Visual Studio 2015 Update 1)

这个新的命令constexpr发生了constexpr

魔术发生在这个#define

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

它不会在编译时解密XorString,只会在运行时解密,但它只会在编译时加密字符串,所以字符串不会出现在可执行文件

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

它会打印出"this string is hidden!" 但是你不会在可执行文件中找到它作为字符串!,请使用Microsoft Sysinternals Strings程序下载链接自己检查: https : //technet.microsoft.com/en-us/sysinternals/strings.aspx

完整的源代码是相当大的,但可以很容易地被包含到一个头文件。 但也是非常随机的,所以加密的字符串输出总是会改变每一个新的编译,种子会根据编译时间而改变,非常稳固,完美的解决方案。

创建一个名为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() ) //////////////////////////////////////////////////////////////////// 

您不能通过С++编译器或预处理器对字符串(字符串文字)进行加密,但是您可以编写一个预编译工具来解析源代码并加密字符串。

或者,你可以尝试使用boost :: mpl :: string。

要完成你所建议的唯一方法就是编写一个真正可怕的宏。 但是这里有一些替代品。

  1. 将加密的字符串存储在数据文件中。
  2. 在一个源文件中收集字符串,然后在实际编译之前,在构建中,用一个可以加密它们的工具(比如sed)来检查它。 您可以自动执行此步骤。
  3. 使用功能强大的编辑器,可以在工作时毫不费力地加密/解密字符串。

如果你只是想隐藏字符串,那么你可以试着压缩你的可执行文件像UPX 。

无论您的解决方案的细节,它将涉及使用一些加密程序加密字符串。

你可以编写一个脚本来加密源代码中的文字。

或者对于Windows EXE文件,你可以在[.rc]文件中加密文字,将字符串作为字符串表格资源嵌入到EXE中。

但可能最好的解决办法是不要尝试任何隐藏。

当微软在Windows代码上尝试了XOR隐藏技巧时,它会随意地警告非微软的DOS-es是不可靠的,并且与这个不兼容,这只会让他们反感。 当然,对竞争对手说坏话的想法,把与Windows的坏话捆绑在一起,首先是一个真正的愚蠢的想法。 但是,试图隐藏代码却让公众陷入了尴尬的境地:没有人真正注意到代码产生的警告,但是当人们发现“加密”的代码时,他们的好奇心自然而然地被发现了, ,并写有关它的文章。

干杯&hth。,

任何在编译时加密都必须在原始EXE中被撤销(除非你正在做一些真正奇怪的事情)。 而你的应用程序正在他们的硬件上运行。 注定… DRM,这是(在我心中)邪恶。

这可能不适用于古代编译器的问题,但是在更现代的C ++实现中,我们可以使用一个字符串常量运算符模板 ,它被声明为constexpr来实现编译时混淆。 为此,我使用了GCC 7.2.0和-std=c++17 (当然还有一整套警告选项)。

首先,我们定义一个类型来保存混淆的字符串数据,并使用一个转换运算符按需生成一个明文字符串:

 #include <array> #include <string> template<typename Char> static const Char SECRET = 0x01; template<typename Char, typename std::basic_string<Char>::size_type Length> struct obfuscated_string { using String = std::basic_string<Char>; const std::array<const Char, Length> storage; operator String() const { String s{storage.data(), Length}; for (auto& c: s) c ^= SECRET<Char>; return s; } }; 

现在,将源代码文字转换为模糊字符串的文字操作符模板:

 template<typename ctype, ctype...STR> constexpr obfuscated_string<ctype, sizeof... (STR)> operator ""_hidden() { return { { (STR ^ SECRET<ctype>)... } }; } 

展示:

 #include <iostream> int main() { static const auto message = "squeamish ossifrage"_hidden; std::string plaintext = message; std::cout << plaintext << std::endl; } 

我们可以用strings程序来检查目标代码。 这个二进制文件在任何地方都不含有squeamish ossifrage ; 相反它有rptd`lhri!nrrhgs`fd 。 我已经用一系列的优化级别证实了这一点,以证明转换回std::string没有得到预先计算,但是我建议你每当你改变编译器和/或设置时进行你自己的测试。

(我故意忽视这是否是一个明智的做法 – 只是提出一个技术性的解决方案)。