Как скрыть строки в exe или dll?

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

Вот код простого исполняемого файла, который я написал, чтобы просто протестировать его:

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    _TCHAR* hiddenString1 =_T("4537774B-CC80-4eda-B3E4-7A9EE77991F5");
    _TCHAR* hiddenString2 =_T("hidden_password_or_whatever");
    for (int i= 0; i<argc; i++) {
        if (0 == _tcscmp(argv[i],hiddenString1)) {
            _tprintf (_T("The guid argument is correct.\n")); }
        else if (0 == _tcscmp(argv[i],hiddenString2)) {
            _tprintf (_T("Do something here.\n")); }
    }

    _tprintf (_T("This is a visible string.\n"));
    //Keep Running
    Sleep(60000);
    return 0;
}

Строки могут быть явно извлечены из соответствующего исполняемого файла:
alt text

Я думаю, что слишком легко найти строки.

Мои вопросы:

  • Как просто скрывать hiddenString1 или hiddenString2 в исполняемый файл?
  • Есть ли более безопасный способ использования "чит-кода", чем с какой-то скрытый скрытый ввод?

Ответ 1

Добро пожаловать в более широкий мир защитных программ.

Есть несколько вариантов, но я считаю, что все они зависят от какой-то формы запутывания; который, хотя и не совершенен, по крайней мере что-то.

  • Вместо прямого значения строки вы можете сохранить текст в другой двоичной форме (hex?).

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

  • Вы можете разбить их по различным точкам вашего кода и восстановить позже.

Или их комбинация.

Имейте в виду, что некоторые атаки идут дальше, чем смотреть на фактический двоичный файл. Иногда они будут исследовать адресное пространство памяти программы во время ее работы. MS придумала что-то вроде SecureString в .Net 2.0. Целью является сохранение зашифрованных строк во время работы приложения.

Четвертая идея состоит в том, чтобы не хранить строку в самом приложении, а скорее полагаться на код проверки, который должен быть отправлен на сервер, которым вы управляете. На сервере вы можете проверить, является ли он законным "чит-кодом" или нет.

Ответ 2

Существует множество способов затенения данных в исполняемом файле. Другие здесь опубликовали хорошие решения - некоторые сильнее других. Я не добавлю к этому списку.

Просто имейте в виду: это все кошки-мышки: невозможно гарантировать, что никто не узнает ваш "секрет".

Независимо от того, сколько шифрования или других трюков вы используете; независимо от того, сколько усилий или денег вы вкладываете в него. Независимо от того, сколько типов NASA/MIT/CIA/NSA участвуют в его скрытии.

Все сводится к простой физике:
Если бы любой пользователь мог вытащить ваш секрет из исполняемого файла и "показать" его, компьютер тоже не сможет его отобразить, и ваша программа не сможет его использовать. Любой умеренно квалифицированный разработчик с достаточным стимулом найдет способ раскрывать секрет.

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

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

Итак, это нормально, чтобы попытаться скрыть данные, если это просто "не-приятно" для него, чтобы быть общедоступным, или если последствия его появления стали бы просто "неудобными". Но даже не думайте скрывать в своей программе "пароль к вашей основной клиентской базе данных", закрытый ключ или какой-либо другой критический секрет. Вы просто не можете.

Если у вас есть действительно критически секретная информация о том, что ваша программа каким-то образом понадобится, но НИКОГДА не станет общедоступной информацией (например, секретным ключом), вам нужно будет поговорить о своей программе с удаленным сервером под вашим контролем, применить соответствующую проверку подлинности и авторизации (то есть убедитесь, что только разрешенные люди или компьютеры могут выполнить запрос на сервер), и этот сервер хранит секрет и использует его.

Ответ 3

Самый простой способ - зашифровать их чем-то тривиальным, например, xor или rot-13, а затем расшифровывать их "на лету", когда они используются. Это позволит избежать случайного просмотра их, но это не остановит никого, у кого много опыта в обращении.

Ответ 4

В дополнение к тем методам, которые Крис упоминает, вы также можете использовать алгоритм хэширования. Если все, что вы хотите сделать, это проверить, был ли указан правильный идентификатор, вам фактически не нужно хранить весь идентификатор в вашей программе.

  • Создайте хэш (MD5, SHA и т.д.) строки/пароля/идентификатора, с которым вы хотите сравнить, возможно, добавьте к нему значение "соль". Сохраните это в своей программе.
  • Когда программа запущена, выполните один и тот же алгоритм на входной строке/пароле/id и сравните два хэша, чтобы увидеть, соответствуют ли они.

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

Ответ 5

Есть URL-адреса для HTTP-запросов, которые я тоже хотел бы скрыть.

Если ваше приложение делает запрос, нет смысла скрывать это. Запуск приложения, такого как скрипач, http-анализатор или один из десятков других бесплатных и доступных методов, покажет весь трафик, создаваемый вашим приложением.

Ответ 6

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

Если вы не хотите, чтобы люди увидели ваш GUID, тогда создайте его из байтов, а не постройте из строки:

const GUID SecretGuid = 
      { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };

Ответ 7

Будут ли все ваши секретные коды GUID или это просто пример?

Возможно, сохраните свой секрет в качестве двоичного указателя:

const GUID SecretGuid =
    { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };

Затем преобразуйте предоставленный вами указатель из строки в двоичный формат и сравните два бинарных файла.

Ответ 8

Самое лучшее, что вы можете сделать, это код вашего пароля или другой строки, которую вы хотите скрыть как массив char. Например:

std::string s1 = "Hello";   // This will show up in exe in hex editor
char* s2 = "World";   // this will show up in exe in hex editor
char s3[] = {'G', 'O', 'D'}; // this will not show up in exe in hex editor.