【发布时间】:2011-05-05 09:04:00
【问题描述】:
我想在我的 .exe 中隐藏一些字符串,这样人们就不能简单地打开 .exe 并查看那里的所有字符串。我不关心加密方法的强度,所以我可能会使用 XOR 等。
如何在编译时执行此操作?这样我的字符串就不会存储在 .exe 中,但加密版本会。然后,我每次都使用我的解密函数在屏幕上显示这些字符串。
【问题讨论】:
标签: c++ windows visual-studio-2008
我想在我的 .exe 中隐藏一些字符串,这样人们就不能简单地打开 .exe 并查看那里的所有字符串。我不关心加密方法的强度,所以我可能会使用 XOR 等。
如何在编译时执行此操作?这样我的字符串就不会存储在 .exe 中,但加密版本会。然后,我每次都使用我的解密函数在屏幕上显示这些字符串。
【问题讨论】:
标签: c++ windows visual-studio-2008
您可以使用宏对其进行加密或编写您自己的预处理器
#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");
【讨论】:
CRYPT(myString+12)
我也认为这是不可能的,尽管它很简单,但人们编写了解决方案,您需要一个自定义工具来扫描构建的文件,然后扫描字符串并像这样加密字符串,这还不错但是我想要一个从 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() )
////////////////////////////////////////////////////////////////////
这是下面的更新代码,感谢 arkan,可在 char 和 wchar_t 上工作
#pragma once
#include <string>
#include <array>
#include <cstdarg>
#define BEGIN_NAMESPACE( x ) namespace x {
#define END_NAMESPACE }
BEGIN_NAMESPACE(XorCompileTime)
constexpr auto time = __TIME__;
constexpr auto seed = static_cast< int >(time[7]) + static_cast< int >(time[6]) * 10 + static_cast< int >(time[4]) * 60 + static_cast< int >(time[3]) * 600 + static_cast< int >(time[1]) * 3600 + static_cast< int >(time[0]) * 36000;
// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division
template < int N >
struct RandomGenerator
{
private:
static constexpr unsigned a = 16807; // 7^5
static constexpr unsigned m = 2147483647; // 2^31 - 1
static constexpr unsigned s = RandomGenerator< N - 1 >::value;
static constexpr unsigned lo = a * (s & 0xFFFF); // Multiply lower 16 bits by 16807
static constexpr unsigned hi = a * (s >> 16); // Multiply higher 16 bits by 16807
static constexpr unsigned lo2 = lo + ((hi & 0x7FFF) << 16); // Combine lower 15 bits of hi with lo's upper bits
static constexpr unsigned hi2 = hi >> 15; // Discard lower 15 bits of hi
static constexpr unsigned lo3 = lo2 + hi;
public:
static constexpr unsigned max = m;
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};
template <>
struct RandomGenerator< 0 >
{
static constexpr unsigned value = seed;
};
template < int N, int M >
struct RandomInt
{
static constexpr auto value = RandomGenerator< N + 1 >::value % M;
};
template < int N >
struct RandomChar
{
static const char value = static_cast< char >(1 + RandomInt< N, 0x7F - 1 >::value);
};
template < size_t N, int K, typename Char >
struct XorString
{
private:
const char _key;
std::array< Char, N + 1 > _encrypted;
constexpr Char enc(Char c) const
{
return c ^ _key;
}
Char dec(Char c) const
{
return c ^ _key;
}
public:
template < size_t... Is >
constexpr __forceinline XorString(const Char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... }
{
}
__forceinline decltype(auto) decrypt(void)
{
for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]);
}
_encrypted[N] = '\0';
return _encrypted.data();
}
};
//--------------------------------------------------------------------------------
//-- Note: XorStr will __NOT__ work directly with functions like printf.
// To work with them you need a wrapper function that takes a const char*
// as parameter and passes it to printf and alike.
//
// The Microsoft Compiler/Linker is not working correctly with variadic
// templates!
//
// Use the functions below or use std::cout (and similar)!
//--------------------------------------------------------------------------------
static auto w_printf = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_printf_s = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_sprintf = [](char* buf, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
};
static auto w_sprintf_ret = [](char* buf, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(buf, fmt, args);
va_end(args);
return ret;
};
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
};
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
return ret;
};
//Old functions before I found out about wrapper functions.
//#define XorStr( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char >( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ).decrypt() )
//#define XorStrW( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t >( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ).decrypt() )
//Wrapper functions to work in all functions below
#define XorStr( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
#define XorStrW( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
END_NAMESPACE
【讨论】:
基于 SSPoke 的答案,这里是一个稍微简单且更强大的解决方案。使用 MSVC 2017 和 gcc 7.3 https://godbolt.org/z/7fc3Zi 测试
变化:
#include <iostream>
// =============================================================================
namespace crypt {
// =============================================================================
// convert __TIME__ == "hh:mm:ss" to a sum of seconds this gives us a compile-time seed
// Note: in some weird cases I've seen the seed being different from encryption
// to decryption so it's safer to not use time and set the seed manually
#if 0
#define TBX_XSTR_SEED ((__TIME__[7] - '0') * 1ull + (__TIME__[6] - '0') * 10ull + \
(__TIME__[4] - '0') * 60ull + (__TIME__[3] - '0') * 600ull + \
(__TIME__[1] - '0') * 3600ull + (__TIME__[0] - '0') * 36000ull)
#else
#define TBX_XSTR_SEED (3600ull)
#endif
// -----------------------------------------------------------------------------
// @return a pseudo random number clamped at 0xFFFFFFFF
constexpr unsigned long long linear_congruent_generator(unsigned rounds) {
return 1013904223ull + (1664525ull * ((rounds> 0) ? linear_congruent_generator(rounds - 1) : (TBX_XSTR_SEED) )) % 0xFFFFFFFF;
}
// -----------------------------------------------------------------------------
#define Random() linear_congruent_generator(10)
#define XSTR_RANDOM_NUMBER(Min, Max) (Min + (Random() % (Max - Min + 1)))
// -----------------------------------------------------------------------------
constexpr const unsigned long long XORKEY = XSTR_RANDOM_NUMBER(0, 0xFF);
// -----------------------------------------------------------------------------
template<typename Char >
constexpr Char encrypt_character(const Char character, int index) {
return character ^ (static_cast<Char>(XORKEY) + index);
}
// -----------------------------------------------------------------------------
template <unsigned size, typename Char>
class Xor_string {
public:
const unsigned _nb_chars = (size - 1);
Char _string[size];
// if every goes alright this constructor should be executed at compile time
inline constexpr Xor_string(const Char* string)
: _string{}
{
for(unsigned i = 0u; i < size; ++i)
_string[i] = encrypt_character<Char>(string[i], i);
}
// This is executed at runtime.
// HACK: although decrypt() is const we modify '_string' in place
const Char* decrypt() const
{
Char* string = const_cast<Char*>(_string);
for(unsigned t = 0; t < _nb_chars; t++) {
string[t] = string[t] ^ (static_cast<Char>(XORKEY) + t);
}
string[_nb_chars] = '\0';
return string;
}
};
}// END crypt NAMESPACE ========================================================
#define XorS(name, my_string) constexpr crypt::Xor_string<(sizeof(my_string)/sizeof(char)), char> name(my_string)
// Because of a limitation/bug in msvc 2017 we need to declare crypt::Xor_string() as a constexpr
// otherwise the constructor is not evaluated at compile time. The lambda function is here to allow this declaration inside the macro
// because there is no such thing as casting to 'constexpr' (and casting to const does not solve this bug).
#define XorString(my_string) []{ constexpr crypt::Xor_string<(sizeof(my_string)/sizeof(char)), char> expr(my_string); return expr; }().decrypt()
// Crypt normal string char*
#define _c( string ) XorString( string )
#define XorWS(name, my_string) constexpr crypt::Xor_string<(sizeof(my_string)/sizeof(wchar_t)), wchar_t> name(my_string)
#define XorWideString(my_string) []{ constexpr crypt::Xor_string<(sizeof(my_string)/sizeof(wchar_t)), wchar_t> expr(my_string); return expr; }().decrypt()
// crypt wide characters
#define _cw( string ) XorWideString( string )
int main(void ) {
std::cout << _c("0obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze0\n"
"1obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze1\n"
"2obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze2\n"
"3obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze3\n"
"4obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze4\n"
"5obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze5\n"
"6obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze6\n"
"7obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze7\n"
"8obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze8\n"
"9obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze9\n" ) << std::endl;
std::cout << "Wide strings" << std::endl;
std::wcout << _cw(L"0obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze0\n"
"1obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze1\n"
"2obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze2\n"
"3obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze3\n"
"4obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze4\n"
"5obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze5\n"
"6obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze6\n"
"7obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze7\n"
"8obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze8\n"
"9obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzze obfuscate me pleazzzzzzeobfuscate me pleazzzzzze obfuscate me pleazzzzzze9\n") << std::endl;
return 0;
}
【讨论】:
这可能不适用于问题的古老编译器,但在更现代的 C++ 实现中,我们可以使用声明为 constexpr 的字符串 literal operator template 来实现编译时混淆。为此,我使用了 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 的转换,但我建议您在更改编译器和/或设置时进行自己的测试。
(我故意忽略这是否是一个可取的事情 - 只是提出一个技术可行的解决方案)。
【讨论】:
-O3 -std:c++20,GCC 有reached the point,其中加密和解密被优化掉,主要是由于C++20 的constexpr containers。它仍然将字符串放在寄存器常量中,而不是在内存中线性布局,因此它被切成 8-B 段,但现在已经可以读取短字符串了。
完全你建议的唯一方法是编写一个真正可怕的宏。但这里有一些替代方案。
【讨论】:
您不能通过 С++ 编译器或预处理器加密字符串(字符串文字),但您可以编写一个预构建工具来解析您的源代码并加密字符串。
或者,您可以尝试使用 boost::mpl::string。
【讨论】:
无论您的解决方案的细节如何,都将涉及使用一些加密程序对字符串进行加密。
您可以编写一个脚本来加密源代码中的文字。
或者对于 Windows exe,您可以在 [.rc] 文件中加密文字,将字符串作为字符串表资源嵌入到 exe 中。
但可能最好的解决方案是不要尝试任何隐藏。
当 Microsoft 尝试在 Windows 代码上使用 XOR 隐藏技巧时,该技巧武断地警告非 Microsoft DOS-es 不可靠且与此不兼容,但结果适得其反。当然,说竞争对手的坏话并将坏话与 Windows 捆绑在一起的想法首先是一个非常愚蠢的想法。但是,试图隐藏代码却成了公开的尴尬:没有人真正注意到代码产生的警告,但是当人们发现“加密”代码时,自然会产生好奇心,他们只需要找出它是什么,并撰写有关它的文章。
干杯,
【讨论】:
如果您只是想隐藏字符串,那么您可以尝试使用 UPX 之类的东西压缩您的可执行文件。
【讨论】:
这是我目前使用的,它有 hack 来支持 sprintf 函数,这些函数会在编译的二进制文件中溢出纯文本。您现在可以使用 w_sprintf_s 而不是 sprintf,就像这样
char test[256] = { 0 };
w_sprintf_s(test, 256, XorStr("test test :D %d %+d\n"), 1, 1337);
或
wchar_t test[256] = { 0 };
w_sprintf_s(test, 256, XorStrW(L"test test from unicode :D %d %+d\n"), 1, 1337);
可能会像 arkan 那样添加对 wchar_t 宽字符串的支持。但我现在对它们没有用处,因为我没有在符号/unicode 中写任何东西。
#pragma once
#include <string>
#include <array>
#include <cstdarg>
#define BEGIN_NAMESPACE( x ) namespace x {
#define END_NAMESPACE }
BEGIN_NAMESPACE(XorCompileTime)
constexpr auto time = __TIME__;
constexpr auto seed = static_cast< int >(time[7]) + static_cast< int >(time[6]) * 10 + static_cast< int >(time[4]) * 60 + static_cast< int >(time[3]) * 600 + static_cast< int >(time[1]) * 3600 + static_cast< int >(time[0]) * 36000;
// 1988, Stephen Park and Keith Miller
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
// with 32-bit math and without division
template < int N >
struct RandomGenerator
{
private:
static constexpr unsigned a = 16807; // 7^5
static constexpr unsigned m = 2147483647; // 2^31 - 1
static constexpr unsigned s = RandomGenerator< N - 1 >::value;
static constexpr unsigned lo = a * (s & 0xFFFF); // Multiply lower 16 bits by 16807
static constexpr unsigned hi = a * (s >> 16); // Multiply higher 16 bits by 16807
static constexpr unsigned lo2 = lo + ((hi & 0x7FFF) << 16); // Combine lower 15 bits of hi with lo's upper bits
static constexpr unsigned hi2 = hi >> 15; // Discard lower 15 bits of hi
static constexpr unsigned lo3 = lo2 + hi;
public:
static constexpr unsigned max = m;
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
};
template <>
struct RandomGenerator< 0 >
{
static constexpr unsigned value = seed;
};
template < int N, int M >
struct RandomInt
{
static constexpr auto value = RandomGenerator< N + 1 >::value % M;
};
template < int N >
struct RandomChar
{
static const char value = static_cast< char >(1 + RandomInt< N, 0x7F - 1 >::value);
};
template < size_t N, int K, typename Char >
struct XorString
{
private:
const char _key;
std::array< Char, N + 1 > _encrypted;
constexpr Char enc(Char c) const
{
return c ^ _key;
}
Char dec(Char c) const
{
return c ^ _key;
}
public:
template < size_t... Is >
constexpr __forceinline XorString(const Char* str, std::index_sequence< Is... >) : _key(RandomChar< K >::value), _encrypted{ enc(str[Is])... }
{
}
__forceinline decltype(auto) decrypt(void)
{
for (size_t i = 0; i < N; ++i) {
_encrypted[i] = dec(_encrypted[i]);
}
_encrypted[N] = '\0';
return _encrypted.data();
}
};
//--------------------------------------------------------------------------------
//-- Note: XorStr will __NOT__ work directly with functions like printf.
// To work with them you need a wrapper function that takes a const char*
// as parameter and passes it to printf and alike.
//
// The Microsoft Compiler/Linker is not working correctly with variadic
// templates!
//
// Use the functions below or use std::cout (and similar)!
//--------------------------------------------------------------------------------
static auto w_printf = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_printf_s = [](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf_s(fmt, args);
va_end(args);
};
static auto w_sprintf = [](char* buf, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
};
static auto w_sprintf_ret = [](char* buf, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf(buf, fmt, args);
va_end(args);
return ret;
};
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
};
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
int ret;
va_list args;
va_start(args, fmt);
ret = vsprintf_s(buf, buf_size, fmt, args);
va_end(args);
return ret;
};
//Old functions before I found out about wrapper functions.
//#define XorStr( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char >( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ).decrypt() )
//#define XorStrW( s ) ( XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t >( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ).decrypt() )
//Wrapper functions to work in all functions below
#define XorStr( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
#define XorStrW( s ) []{ constexpr XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
END_NAMESPACE
【讨论】:
在编译时完成的任何加密也必须在原始 EXE 中是可撤消的(除非您正在做一些非常奇怪的事情)。您的应用程序正在他们的硬件上运行。注定...除非 DRM,这(在我看来)是邪恶的。
【讨论】: