Как защитить строки в неуправляемом приложении от дампа процесса - PullRequest
0 голосов
/ 21 сентября 2018

Прежде всего, это не повторяющийся пост!

Пожалуйста, прочитайте до конца, вы четко понимаете!

Я занимаюсь разработкой некоторых приложений и безопасность очень важна для меня ...

Я много искал, я делал много способов, я проверял каждый найденный метод, но разница не такая большая!

◾️Мне нужно защитить некоторые действительно важные строки в моем приложении, такие как Ключ и IV Ключ шифрования AES256 или Base64.

Два факта, с которыми мы все столкнулись:

  1. Мы все знаем, что безопасность .NET очень низкая!На самом деле, ребенок может взломать его с помощью мобильного телефона !!!

  2. Нет ничего, что 100% безопасности , мы только снижаем скорость доступа к ресурсам навсе сложнее и сложнее ...

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

Хорошо, время спрашивать ...

Мне нужно знать, как я могу хранить свои ключи AES и AES IV в безопасности от самосвалы и экстракторы памяти , даже если я не могу создать очень высокий уровень безопасности, мне нужно защитить его от открытия с помощью одним щелчком мыши!

My application is a Unmanaged C++

То, что я сделал и попробовал:

A) Использование метода XOR:

Я использовал метод xor для создания моей строки, но его можно извлечь с помощью string2 dumper одним щелчком мыши!

Подробнее: https://github.com/Jyang772/XOR_Crypter

B) Использование разделенных строк:

Вотпример:

char Departed_String1[4];
int nmbr1 = 0;
char Departed_String1_dep[4];
int nmbr1_dep = 0;
Departed_String1[nmbr1++] = 'T';
Departed_String1_dep[nmbr1_dep++] = 'U';
Departed_String1[nmbr1++] = 'E';
Departed_String1_dep[nmbr1_dep++] = 'C';
Departed_String1[nmbr1++] = 'S';
Departed_String1_dep[nmbr1_dep++] = 'h';
Departed_String1_dep[nmbr1_dep++] = 'U';
Departed_String1[nmbr1++] = 'T';
Departed_String1_dep[nmbr1_dep++] = 'y';
Departed_String1_dep[nmbr1_dep++] = '8';

TЕго также можно легко открыть с помощью отладчика!

C) Мой собственный метод: LostChars

const char* teststring_src = "HeVthsNiNVrtTuODkhPgDkmCxQApD:feSCiQDDWePakOTtFcLzTSbKTaZwsUnpeYMlndoYXJyXBpSSSNGsWblpQhUKKCzWUfHnNxQtNsXXnFzXtSGzIBYjCIlSMbEoqwJfArwrqfeLRANEYgjdknHuzSIzgiglRBFEDmFqDBBbgUQD VvDjnQPdFKDYTSxnDXTqKdHtOCayMbACkmQLJqgHtBtTj CoiXxETJwiIkgMgaVaskZtLiWDotsTldTHdBiJiGIfCmjjjBdAbIFiJFFhXPeAjiKbPuktOmiIuhqDkIhMxFBGZevIIjoOuKfddWgUmdFbNfShAIhphPYKhpxtimPhmDatYlOWCXBXQbkFDY QaKyRMhHznNJClQjDmevKUSnfoCXfWplSDzVWxMOkGkntVMmijf QzbalAbRokBAXXfDvevyHbOmAaUIKMBivJVrTxALngQjGShZdzTsZJwIooYLIuqxcTjELFPRFAAzqE fnIznpwtUzEXFBm"; 
std::string teststring = (std::string(1,teststring_src[468])+std::string(1,teststring_src[4])+std::string(1,teststring_src[230])+std::string(1,teststring_src[249])+std::string(1,teststring_src[174])+std::string(1,teststring_src[343])+std::string(1,teststring_src[239])+std::string(1,teststring_src[365])+std::string(1,teststring_src[41])+std::string(1,teststring_src[417])+std::string(1,teststring_src[227])+std::string(1,teststring_src[62])+std::string(1,teststring_src[469])+std::string(1,teststring_src[248])+std::string(1,teststring_src[220])+std::string(1,teststring_src[329])+std::string(1,teststring_src[504])+std::string(1,teststring_src[453])+std::string(1,teststring_src[223])+std::string(1,teststring_src[66])+std::string(1,teststring_src[156])+std::string(1,teststring_src[496])+std::string(1,teststring_src[29])+std::string(1,teststring_src[20]));

Не работает идеально, по-прежнему дампы!

D) Использование Hex вместо String:

wchar_t string[7] = { 0x0118, 0x0154, 0x010C, 0x012C, 0x0154, 0x0084, 0x0000 };

for (unsigned int GUEvK = 0, GNsdj = 0; GUEvK < 7; GUEvK++)
{
        GNsdj = string[GUEvK];
        GNsdj = ((GNsdj << 14) | ( (GNsdj & 0xFFFF) >> 2)) & 0xFFFF;
        string[GUEvK] = GNsdj;
}

wprintf(string);

Хорошо :) Этот парень создал программное обеспечение для сильной защиты строк ... Wow Awesome! Отличная сделка для 50EURO !Но здесь есть небольшая проблема!

Это может быть дамп всего за 2 клика и 1 секунда Process Explorer

Это пример:

unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };

myKey[30] -= 0x18;
myKey[39] -= 0x8E;
myKey[3] += 0x16;
myKey[1] += 0x45;
myKey[0] ^= 0xA2;
myKey[24] += 0x8C;
myKey[44] ^= 0xDB;
myKey[15] ^= 0xC5;
myKey[7] += 0x60;
myKey[27] ^= 0x63;
myKey[37] += 0x23;
myKey[2] ^= 0x8B;
myKey[25] ^= 0x18;
myKey[12] ^= 0x18;
myKey[14] ^= 0x62;
myKey[11] ^= 0x0C;
myKey[13] += 0x31;
myKey[6] -= 0xB0;
myKey[22] ^= 0xA3;
myKey[43] += 0xED;
myKey[29] -= 0x8C;
myKey[38] ^= 0x47;
myKey[19] -= 0x54;
myKey[33] -= 0xC2;
myKey[40] += 0x1D;
myKey[20] -= 0xA8;
myKey[34] ^= 0x84;
myKey[8] += 0xC1;
myKey[28] -= 0xC6;
myKey[18] -= 0x2A;
myKey[17] -= 0x15;
myKey[4] ^= 0x2C;
myKey[9] -= 0x83;
myKey[26] += 0x31;
myKey[10] ^= 0x06;
myKey[16] += 0x8A;
myKey[42] += 0x76;
myKey[5] ^= 0x58;
myKey[23] ^= 0x46;
myKey[32] += 0x61;
myKey[41] ^= 0x3B;
myKey[31] ^= 0x30;
myKey[46] ^= 0x6C;
myKey[35] -= 0x08;
myKey[36] ^= 0x11;
myKey[45] -= 0xB6;
myKey[21] += 0x51;
myKey[47] += 0xD9;

Вам просто нужно запустить приложение, щелкните правой кнопкой мыши свое приложение в Process Explorer и Нажмите Полный дамп

... Boom !!!Все строки прямо здесь!

** Я перепробовал множество других методов, но все еще в полном дампе ... **

Неужели нет способа предотвратить этот пробел в безопасности?Я ценю любую помощь!

1 Ответ

0 голосов
/ 21 сентября 2018

Прежде всего, помните, что если злоумышленник может подключить отладчик к вашему процессу, а ваш процесс должен отвечать за расшифровку, вы уже проиграли по определению;лучшее, что вы можете получить, это «безопасность через неизвестность».Более безопасные подходы обычно требуют передачи части работы субъекту, к которому злоумышленник не может получить доступ - будь то внешнее криптографическое устройство, защищенное от взлома, или удаленный сервис.

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

При этом, вы можете смягчить эту последнюю проблему, расшифровав вашу строку только по требованию, и сразу же стерев ее;это сокращает окно возможностей для атакующего.Таким образом, вам не нужна функция, которая расшифровывает статический буфер, а функция, которая заполняет предоставленный клиентом буфер необходимыми секретами (и убедитесь, что клиенты фактически обнуляют содержимое такого буфера перед его освобождением - используйтеmemset -подобный, который берет указатель volatile, чтобы убедиться, что стирание не оптимизировано).

Что касается фактического хранения ключей в исполняемом файле, вы можете использовать различные методы для создания путаницы.Инициализация глобального с помощью простого инициализатора помещает соответствующие данные в секцию .rodata исполняемого файла, которая является первым местом, куда я смотрю;любая строка с достаточно высокой энтропией была бы мертвой раздачей для дальнейшего изучения того, где она используется (дизассемблер IDA делает это особенно легко).Возможность, которая приходит на ум, состоит в том, чтобы фактически инициализировать буфер по одному байту за раз от функции (возможно, сделать указатель на буфер volatile, чтобы компилятор не использовал странные трюки);это должно поместить ваши данные прямо в секцию кода, которая немного менее подозрительна, и где энтропия должна поддерживаться ниже благодаря чередованию с кодами операций.

Эти данные могли бы быть дополнительно зашифрованы с помощью некоторого простого трюка - скажем, XORed с выводом простого XorShift PRNG;это снова добавляет путаницу, но XorShift реализован в нескольких инструкциях, поэтому у вас нет дополнительных зависимостей или «подозрительного» кода.

Другим важным моментом, если вы скрываете ключи дешифрования, является не использование криптографических примитивов, предоставляемых вашей операционной системой, а статическое связывание вашей реализации, и, возможно, тот, который не использует AES-NI или другие очевидные раздачи.,Если бы я сначала попытался извлечь ключи дешифрования, я бы подключил к отладчику все соответствующие CryptoAPI и посмотрел в исполняемом файле криптографические инструкции, чтобы найти наиболее интересные зоны.

...