C ++: Как зашифровать строки во время компиляции? - PullRequest
10 голосов
/ 05 ноября 2010

Я хочу спрятать некоторые строки в моем .exe, чтобы люди не могли просто открыть .exe и просмотреть все строки там.Меня не волнует сила метода шифрования, поэтому я, вероятно, буду использовать XOR и т. Д.

Как мне это сделать во время компиляции?Таким образом, мои строки не будут храниться в .exe, но зашифрованные версии будут.Затем я просто использовал бы функцию расшифровки каждый раз, чтобы отобразить эти строки на экране.

Ответы [ 9 ]

11 голосов
/ 05 ноября 2010

вы можете зашифровать его с помощью макросов или написать собственный препроцессор

#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");
7 голосов
/ 24 января 2016

Я также думал, что это было невозможно, хотя это очень просто, люди писали решения, в которых вам нужен специальный инструмент для последующего сканирования встроенного файла, сканирования строк и шифрования таких строк, что было неплохо, ноЯ хотел пакет, скомпилированный из Visual Studio, и теперь это возможно!

Вам нужно C++ 11 (обновление 1 для Visual Studio 2015 из коробки)

волшебство происходит с этимновая команда 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() )
////////////////////////////////////////////////////////////////////
2 голосов
/ 03 ноября 2017

Это, вероятно, не относится к древнему компилятору вопроса, но в более современных реализациях 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 предварительно не вычисляется, но я советую вам проводить собственные тесты всякий раз, когда вы меняете компилятор и / или настройки.

(я намеренно игнорирую, рекомендуется ли сделать - просто представить техническое рабочее решение).

1 голос
/ 05 ноября 2010

Если вы только пытаетесь скрыть строки, то вы можете просто попробовать сжать ваш исполняемый файл чем-то вроде UPX .

1 голос
/ 05 ноября 2010

О единственном способе сделать точно , что вы предлагаете, это написать действительно ужасный макрос. Но вот несколько альтернатив.

  1. Хранить зашифрованные строки в файле данных.
  2. Соберите строки в одном исходном файле, затем в сборке, перед фактической компиляцией, пройдите по ней с помощью инструмента, который зашифрует их (например, sed). Вы можете автоматизировать этот шаг.
  3. Используйте мощный редактор, чтобы вы могли без труда шифровать / дешифровать строки во время работы.
0 голосов
/ 02 июля 2019

Опираясь на ответ SSPoke, это немного более простое и надежное решение. Протестировано с MSVC 2017 и gcc 7.3 https://godbolt.org/z/7fc3Zi

Изменения:

  • Исправлено предупреждение о переполнении целых чисел для длинных строк
  • Исправить / убедиться, что MSVC оценивает encrypt_character () в время компиляции даже для очень длинных строк (в исходной версии некоторые строки не шифровались во время компиляции)
  • Поддержка строк широких символов
  • Более простые шаблоны кода
#include <iostream>

// =============================================================================
namespace crypt {
// =============================================================================

// compile-time seed
#define 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)

// -----------------------------------------------------------------------------

// @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) : (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;
}

0 голосов
/ 05 ноября 2010

Любое шифрование, которое выполняется во время компиляции, также должно быть отменено в сыром EXE (если вы не делаете что-то действительно странное).И ваше приложение работает на их оборудовании.Обреченный ... за исключением DRM, который (по моему мнению) Зло.

0 голосов
/ 05 ноября 2010

Независимо от деталей вашего решения, оно будет включать шифрование строк с использованием некоторой программы шифрования.

Вы можете написать скрипт для шифрования литералов в исходном коде.

Или для Windowsexe вы можете зашифровать литералы в файле [.rc], встраивая строки как ресурс таблицы строк в exe.

Но, вероятно, лучшее решение - не пытаться скрывать.

КогдаMicrosoft попыталась скрыть трюк с XOR в коде Windows, который произвольно предупредил о ненадежности и несовместимости DOS-ов других компаний с Microsoft Windows, но это имело неприятные последствия.Конечно, идея говорить плохие вещи о конкурентах и ​​связывать эти плохие слова с Windows была в первую очередь действительно глупой идеей.Но попытка скрыть код была тем, что превратило его в публичное смущение: никто действительно не заметил предупреждений, которые выдает код, но когда люди обнаружили «зашифрованный» код, естественно, их любопытство было задействовано, им просто пришлось выяснить, что этои писать статьи об этом.

Приветствия & hth.,

0 голосов
/ 05 ноября 2010

Вы не можете зашифровать строки (строковые литералы) компилятором С ++ или препроцессором, но вы можете написать инструмент предварительной сборки, который будет анализировать ваш исходный код и шифровать строки.

Или вы можете попробовать использовать boost :: mpl :: string.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...