不能直接用字符串字面量做xor加密,因为其存储在只读段、不可修改,且c++不支持对const char*直接进行^运算;xor需按字节操作,而字面量非constexpr可索引数组,必须通过char const(&)[n]引用并转为std::array在编译期逐字节异或。

为什么不能直接用字符串字面量做 XOR 加密
因为 C++ 标准规定字符串字面量("hello")存储在只读段,且编译器可能合并相同内容、重排、甚至优化掉未引用的字符串。你如果手动写 "hello" ^ 0x55,编译器会报错——^ 不支持 const char* 和整数。更关键的是:XOR 是按字节操作的,而字符串字面量不是可索引的 constexpr 字节数组,无法在编译期展开。
constexpr 字符串异或必须用字符数组 + 模板递归展开
核心思路是把字符串转成 std::array<char n></char> 类型,在编译期逐字节异或。C++17 起支持 constexpr 数组构造和循环,但需避免运行时分支,所以常用模板参数包展开或 std::index_sequence。
常见错误:直接对 sizeof("abc") 做循环,忘了末尾 '\0';或用 std::string——它根本不能 constexpr 构造。
- 必须用
char const (&)[N]引用原始字面量,提取长度N - 解密函数也得是
constexpr,否则无法用于静态初始化场景(如全局const char*初始化) - 密钥建议用单字节(如
0x9A),多字节密钥需额外处理周期,容易在 constexpr 环境下超出编译器递归深度限制
template<size_t n>
constexpr std::array<char n> xor_encrypt(const char (&str)[N], char key) {
std::array<char n> out{};
for (size_t i = 0; i // 使用示例
constexpr auto enc = xor_encrypt("secret", 0x9A);
// enc 是编译期确定的 std::array<char></char></char></char></size_t>
运行时解密要避开字符串字面量地址硬编码
很多人把加密后的数组定义为 static constexpr,然后在运行时取地址解密——这没问题;但若试图把解密结果赋给 const char* 并期望它指向只读段,就错了:解密后数据必须存到可读写的内存(如栈/堆/全局 data 段),否则解密写操作会触发 SIGSEGV。
典型误用:const char* s = decrypt(enc.data(), 0x9A);,而 decrypt 内部尝试修改 enc.data() 所指内存(它是常量,不可写)。
- 解密函数应返回
std::string或写入用户提供的缓冲区(char*) - 若需 C 风格字符串,务必分配新内存(
new char[N]或static thread_local char buf[N]),再 memcpy + XOR - 注意:
thread_local缓冲区在首次调用时初始化,适合单次解密复用;但多线程并发调用同一解密函数时,需确保缓冲区不冲突
实际部署时最易忽略的 ABI 和调试问题
加密后的字符串在二进制里是“乱码”,IDA/Ghidra 可能识别不出字符串,这是好事;但调试时你看到的是异或后的字节,容易误判为数据损坏。更隐蔽的问题是:某些链接器(如 LLD)或 strip 工具会把未引用的 constexpr 数组整个丢弃,即使它被某个运行时函数间接使用。
验证是否生效的方法:用 objdump -s your_binary | grep -A2 "your_encrypted_bytes" 查看目标字节是否存在;或加一个 dummy 引用:volatile auto& keep = enc; 防止优化移除。
另外,Windows 下若字符串用于 OutputDebugStringA 等 API,解密后必须保证末尾 '\0' 存在且未被 XOR 错位——密钥作用于整个 N 字节(含 \0),解密后自然恢复,这点容易被忽略。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











