Как спрятать строки в exe или dll? - PullRequest
30 голосов
/ 29 мая 2009

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

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

#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

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

Мои вопросы:

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

Ответы [ 9 ]

29 голосов
/ 29 мая 2009

Добро пожаловать в мир защитного программирования.

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

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

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

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

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

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

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

18 голосов
/ 30 мая 2009

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

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

Независимо от того, сколько шифрования или других уловок вы используете; независимо от того, сколько усилий или денег вы вложите в это. Независимо от того, сколько типов «НАСА / МИТ / ЦРУ / АНБ» вовлечено в его сокрытие.

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

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

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

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

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

9 голосов
/ 29 мая 2009

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

6 голосов
/ 29 мая 2009

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

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

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

5 голосов
/ 19 января 2010

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

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

2 голосов
/ 29 мая 2009

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

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

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

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

2 голосов
/ 29 мая 2009

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

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

const GUID SecretGuid = 
      { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
1 голос
/ 07 августа 2018

Вот метод, который я использую для этой цели. Во-первых, я использую инструмент Strings от Sysinternals для отображения строк в EXE или DLL. Затем я использую следующий небольшой инструмент (см. article ), чтобы заменить эти строки зашифрованным массивом символов, хранящимся как арифметическое выражение: например: вместо строки: "это тест" Я помещу следующий код: (который автоматически генерируется этим инструментом )

WCHAR T1[28];
 T1[22] = 69;
 T1[15] = 121 - 17;
 T1[9] = L':' + -26;
 T1[12] = L't' - 1;
 T1[6] = 116 - 1;
 T1[17] = 117 - 12;
 T1[3] = 116 - 1;
 T1[14] = L'' - 3;
 T1[13] = L'w' - 3;
 T1[23] = 69;
 T1[26] = L'Y' + 3;
 T1[19] = 111 + 0;
 T1[21] = L'k' - 34;
 T1[27] = L'\\' - 8;
 T1[20] = L'B' + 32;
 T1[4] = 42 + -10;
 T1[25] = L'm' - 17;
 T1[16] = L'H' + 18;
 T1[18] = L'A' + 56;
 T1[24] = 68;
 T1[1] = 105 - 1;
 T1[11] = L'k' - 6;
 T1[10] = 66 + 50;
 T1[2] = 105;
 T1[0] = 117 - 1;
 T1[5] = L'k' - 2;
 T1[8] = 89 + 8;
 T1[7] = 32;

Существует много решений этой проблемы, и ни одно из них (включая мое) не является идеальным, однако существуют способы шифрования, маскировки и скрытия чувствительных строк. Конечно, вы можете зашифровать их и расшифровать во время выполнения (см. Эту статью), но я считаю более важным, чтобы эти строки исчезали среди битов и байтов исполняемого файла, и это работает. После запуска моего инструмента вы не найдете «это тест» в исполняемом файле.

1 голос
/ 12 июня 2009

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

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.
...