如何制作 C 宏预构建预处理器?

Posted

技术标签:

【中文标题】如何制作 C 宏预构建预处理器?【英文标题】:How to make a C macro pre-build pre-processor? 【发布时间】:2011-10-24 00:53:07 【问题描述】:

假设我有一个字符串,我想在我的代码中进行混淆处理。 (本示例仅供学习。)

我的计划是用宏包装字符串文字,例如

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

并且,作为预构建步骤,通过我自己的预处理器运行我的源文件以查找 _MY_ENCRYPTION_MACRO 的所有用法并相应地混淆字符串。

我将如何使用 Visual C++ 进行这种预处理?

【问题讨论】:

请参阅***.com/questions/1356896/… 和***.com/questions/4102320/… @MitchWheat:这些链接并没有真正提供任何答案。 @K-ballo:哇,我没想到会在这里看到 Boost 答案!这可能是我尝试 Boost 的一个例外,谢谢! :) 【参考方案1】:

我在几个问题上发布了这个答案,因为很多人都有这个问题,比如我自己,我也认为这是不可能的,尽管它很简单,人们编写了解决方案,你需要一个自定义工具来扫描构建之后的文件并扫描字符串并加密这样的字符串,这还不错,但我想要一个从 Visual Studio 编译的包,现在可以了!

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

神奇的发生在这个新命令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() )
////////////////////////////////////////////////////////////////////

【讨论】:

这不适用于 vs15 更新 3。我使用了以下代码: printf(XorString( "test" ));但字符串应用程序(sysinternals)显示“测试”字符串。 尝试优化模式。 (-O)【参考方案2】:

如果您在 Linux 上使用了最近的 GCC(即 GCC 4.6),您还可以拥有一个插件,它提供了一个内置函数来“加密”编译时间字符串,或者您甚至可以将其设为 GCC MELT 扩展( MELT 是一种用于扩展 GCC 的高级领域特定语言。

如果您使用其他 C++,您可能有自己的预处理脚本来查找宏。 例如,您可能有一些程序扫描所有 C++ 源代码中 ENCRYPTSTRING("anyconstantstring") 的每次出现,并在您的 C++ 代码中生成一个 mycrypt.h 文件 #include "mycrypt.h"。然后你可能会做类似的技巧

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

并让您生成的"mycrypt.h" 包含类似

const char crypstring_123[]="thecryptedstringatline123";

等等。 "mycrypt.h" 生成器可以是 awkpythonocaml (等等...)脚本。

【讨论】:

以上是关于如何制作 C 宏预构建预处理器?的主要内容,如果未能解决你的问题,请参考以下文章

链接使用不同预处理器标志或 C 标准构建的库

使用预处理器指令定义输出路径

如何使用预处理器检测 GCC 线程模型?

使用 GNU autotools 进程和 Oracle Pro C 预处理器

将预处理器变量传递给 nmake 构建环境

如何在 C# 中快速处理 csproj 文件