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

Я обнаружил, что можно извлечь жестко закодированные строки из двоичного файла.
Например, представление свойств 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. Есть ли более безопасный способ использования «чит-кода», чем с каким-то неясным скрытым вводом?

person Winz    schedule 29.05.2009    source источник
comment
Это вопрос о GUID или о строках вообще?   -  person xtofl    schedule 29.05.2009
comment
GUID был просто примером: есть URL-адреса для http-запросов, которые я тоже хотел бы скрыть.   -  person Winz    schedule 29.05.2009
comment
Скрытие URL-адресов для http-запросов не сработает. Любой, у кого есть сниффер, сможет точно увидеть, что делает ваше приложение, и сделать это будет намного проще, чем исследовать память вашего процесса.   -  person JoeG    schedule 19.01.2010
comment
Как скрыть строку в двоичном коде?   -  person phuclv    schedule 02.02.2016
comment
Вы можете обратиться к этому — там объясняется, что такое функциональное шифрование и полностью гомоморфное шифрование.   -  person StefanS    schedule 11.05.2016


Ответы (9)


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

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

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

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

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

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

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

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

person NotMe    schedule 29.05.2009
comment
Хорошие варианты. Поскольку спрашивающий особенно заинтересован в сокрытии строки GUID Windows, которая представляет собой просто шестнадцатеричное число, эти данные также могут быть сохранены как несколько целых чисел. - person Drew Dormann; 29.05.2009
comment
Я хотел бы добавить к вашему приятному ответу возможность посолить пароль. - person AndersK; 31.03.2015
comment
@CyberSpock: я не уверен, что это было бы целью соления. Строка (соленая или нет) хранится в двоичном файле и поэтому подлежит обнаружению. Это означает, что есть только два решения: запутать, чтобы хотя бы немного усложнить задачу, или вообще не хранить ее в приложении. - person NotMe; 01.04.2015
comment
может быть труднее определить пароль, если он соленый, так как это будет алгоритм для сравнения паролей друг с другом, но в любом случае это все напрасно. - person AndersK; 01.04.2015
comment
я только что попытался преобразовать мою массивную строку (char str[] = {'H', 'i', '\0'}) в последовательность шестнадцатеричных байтов, и они могут быть обнаружены точно так же - person duckduckgo; 18.02.2016

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

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

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

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

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

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

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

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

person Euro Micelli    schedule 29.05.2009
comment
Хорошо сказано. А настоящие взломщики довольно грозны, маленькой хитростью их не остановить. Они заметят точку доступа, где вы играете со строками, и будут терпеливо ждать, пока приложение расшифрует ее, чтобы увидеть реальную вещь. - person toto; 31.05.2009

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

person Rob K    schedule 29.05.2009
comment
Если на то пошло, ничто не остановит любого, у кого есть большой опыт в движении задним ходом;) - person n3rd; 29.05.2009
comment
Поскольку для запуска программы у них должен быть ключ дешифрования в памяти, AES их тоже не остановит. - person Martin Beckett; 29.05.2009

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

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

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

person Andre Miller    schedule 29.05.2009
comment
будьте осторожны, коллизии для некоторых хэшей (например, md5) в наши дни можно найти относительно легко. - person Josef Pfleger; 29.05.2009
comment
Я не уверен, что это проблема для этого использования. - person Head Geek; 29.05.2009
comment
Вы можете пойти дальше и просто сделать часть сделки по шифрованию с открытым ключом только с открытым ключом. это решит проблему столкновений. Это также один из наиболее безопасных способов сделать это — такой же безопасный, как и используемый вами алгоритм шифрования, даже после того, как он был выкопан с помощью шестнадцатеричного редактора. - person Ben Barden; 02.04.2013

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

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

person CaffGeek    schedule 19.01.2010
comment
Это действительно плохо. :( - person Zeeshan Mahmood; 23.08.2016
comment
@ZeeshanMahmood какая часть? - person CaffGeek; 23.08.2016
comment
Это означает, что мы не можем скрыть URL-адреса в коде, так как они будут раскрыты каким-то другим способом. - person Zeeshan Mahmood; 24.08.2016
comment
Вы можете скрыть их, но как только вы получите к ним доступ, они будут видны - person CaffGeek; 24.08.2016

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

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

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

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

person Kevin Newman    schedule 29.05.2009
comment
GUID был просто примером. Есть URL-адреса для http-запросов, которые я тоже хотел бы скрыть. - person Winz; 29.05.2009
comment
Каждый, кто умеет искать строки в вашем исполняемом файле, сможет запустить сниффер и следить за HTTP-запросом из вашего приложения. На самом деле я бы сначала попробовал сниффер, прежде чем искать строки. - person Martin Thurau; 29.05.2009

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

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

const GUID SecretGuid = 
      { 0x4537774B, 0xCC80, 0x4eda, { 0x7A, 0x9E, 0xE7, 0x79, 0x91, 0xF5 } };
person Ian Boyd    schedule 29.05.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.
person suprit chaudhary    schedule 12.06.2009
comment
В этой простой программе на C char s3[] = {'G', 'O', 'D'}; int n = sizeof(s3)/sizeof(s3[0]); printf("%d\n", n); я нахожу текст с помощью шестнадцатеричного редактора -> .D$.G.D$.O.D$.D.D$. в исполняемом файле сборки. - person Tuksn; 14.06.2014
comment
Я видел, что если данные находятся в куче, строка в исполняемом файле находится в обычном виде, если в стеке, строка исчезает. Я знаю, что это очень зависит от компилятора/платформы (у меня Win 10) - person Zac; 08.06.2021

Вот метод, который я использую для этой цели. Во-первых, я использую инструмент 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;

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

person Michael Haephrati    schedule 07.08.2018