• XSS.stack #1 – первый литературный журнал от юзеров форума

Прячем строки в программах. C++

tabac

CPU register
Пользователь
Регистрация
30.09.2018
Сообщения
1 610
Решения
1
Реакции
3 332
Доброго времени суток!

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

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

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

Могу привести пример - вирусописание. Зачастую у неопытных малварь-писателей в билдах остаётся информация, по которой можно выйти на них.

Помимо метаданных, которые некоторые компиляторы оставляют, есть еще и строки. Ссылки, пути, другая информация.

Сразу скажу, этот метод защитит от поверхностного анализа файла. То есть, если пользователь целенаправленно ищет слово "remote" или "rms", то он его не найдет.

И так приступим. Я буду проводить тест на Kali Linux 2019.2
Не обращайте внимание на Linux, под Windows есть подобные программы.

Что нам понадобится?
  1. Начальное знание C++ (так как тесты я как раз на нем буду проводить)
  2. Утилита "strings". ( Strings - *nix-утилита, применяемая для поиска печатных строк в двоичных файлах )
  3. Компилятор C++.
Начинаем.
Давайте для начала посмотрим, что мы имеем, когда создаем билд с обычной строкой.

Пишем код:
C++:
#include <string.h> //библиотека для работы с классом std::string
int main(){ //функция входа
    std::string mystr = "abcd123"; //Строка со значением "abcd123". Эту строку мы будем искать, ее нужно будет скрыть.
    //Заметьте мы просто вставляем строку в ячейку памяти. Мы не выводим ее.
    return 0; //Успешно завершаем выполнение
}
Компилируем:
Bash:
mkdir builds  # Папка для билдов
c++ uncrypted.cpp -o builds/uncrypted  # В моем случае я использую компилятор "c++", указываю файл исходного кода uncrypted.cpp и сохраняю в builds под именем uncrypted
Смотрим строки:
Bash:
strings uncrypted
И видим нашу строку:

1.png


Она написана открытым текстом. Что же я предлагаю сделать? Я предлагаю банально зашифровать строку при помощи XOR. (XOR берется в качестве примера)

Напишем наш криптор строк:
C++:
#include <iostream> // потоки ввода/вывода
#include <string.h> // библиотека для работы с классом std::string
int main(){ //функция входа
std::string mystr = "abcd123"; // Строка. Вы можете вводить строку и ключ с помощью потоков ввода, делайте на своё усмотрение.
std::string crypted = ""; // Переменная для сохранение зашифрованной строки

for(int i = 0; i < strlen(mystr.c_str()); i++) // Создаем цикл для шифровки каждого символа
crypted += mystr[i] ^ [B]2[/B]; //проводим операцию xor с ключом 2

std::cout << crypted << std::endl; // выводим результат

return 0; //Успешно завершаем выполнение.
}
Компилируем:
c++ crypter.cpp -o builds/cryptor
Запускаем:
./builds/cryptor
Видим, что совершенно понятный нам текст превратился в не понятный набор символов.
Код:
c`af301
Согласитесь, это выглядит куда загадочнее и не понятнее чем наш текст.

Ну и теперь напишем основную программу для теста:
C++:
#include <iostream> //потоки ввода/вывода
#include <string.h> // std::string

int main(){
    std::string mystr = "c`af301"; //Зашифрованный текст
    std::string a = ""; //Строка под расшифрованный текст

    for(int i = 0; i < strlen(mystr.c_str()); i++) //Запускаем цикл для каждого символа
    a += mystr[i] ^ 2; // Расшифровываем и заполянем переменную.
    std::cout << a << std::endl; //Выводим
    return 0; //Успешное завершение.
}
Заметьте, ключи при шифрование и расшифровке должны быть одинаковы. Если разные - результат будет другой.

Компилируем:
c++ crypted.cpp -o builds/crypted

Запускаем:
./builds/crypted
Видим правильный вывод строки.

Теперь заглянем внутрь файла.
strings builds/crypted

2.png


Видим только зашифрованный текст.

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

Всем спасибо за внимание, пишите свои мнения и критику.

Жду PE криптор с использованием XOR xD


Копирайт и автор @Pazsh
 
На форуме была тема кажется Crack me называлась там предлогалось найти пароль для exe (который как я понимаю находится где-то в коде в каком-то if ввиде char[100] pass; cin >> pass; if(pass =="password"))я взял эту утилиту string подствил туда этот exe с темы ,получил строки но не одна строка не пошла как пароль))
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Копирайт и автор @Pazsh
Причем его на этом форуме нет. Тема взята с другого борда - кодбай.
 
Если делать по умному, достаточно написать "макрос" который шифрует строку на этапе компиляции, без всяких выше описаных выебонов.

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


К сожалению, редактировать строки самими макросами невозможно. По факту, compile-time обфускация строк возможна благодаря constexpr, что прибавляет зависимостей (или вес, одно из двух). Самим же макросом можно высчитывать только хэш строки и то, если мы её изначально передаём в макрос посимвольно (HASH('A', 'B', 'C')). Поэтому, обфускация на этапе компиляции - это "События сброки" и запуск внешнего скрипта:D
 
К сожалению, редактировать строки самими макросами невозможно. По факту, compile-time обфускация строк возможна благодаря constexpr, что прибавляет зависимостей (или вес, одно из двух). Самим же макросом можно высчитывать только хэш строки и то, если мы её изначально передаём в макрос посимвольно (HASH('A', 'B', 'C')). Поэтому, обфускация на этапе компиляции - это "События сброки" и запуск внешнего скрипта:D
Причем тут макрос и зачем посимвольно?
Код:
constexpr ULONG xGetHashA(_In_ LPCSTR pStr, _In_ ULONG len)

{

    ULONG hash = 0; 

    for (ULONG i = 0; i < len; i++)

    {

        hash += pStr[i];       

    }

    return(hash);

}


#define xHASH(str) xGetHashA(str, sizeof(str)-1)


constexpr ULONG xh = xHASH("1234567890");


п.с.
алг чисто для демо.
 
Последнее редактирование:
Причем тут макрос и зачем посимвольно?
Код:
constexpr ULONG xGetHashA(_In_ LPCSTR pStr, _In_ ULONG len)

{

    ULONG hash = 0;

    for (ULONG i = 0; i < len; i++)

    {

        hash += pStr[i];      

    }

    return(hash);

}


#define xHASH(str) xGetHashA(str, sizeof(str)-1)


constexpr ULONG xh = xHASH("1234567890");


п.с.
алг чисто для демо.

Обрати внимание на комментарий, на который я ответил. Я просто внёс конкретику, так как с помощью обычного макроса НЕВОЗМОЖНО изменить строку.

И твой пример только подтвердил мои слова)
 
Самим же макросом можно высчитывать только хэш строки и то, если мы её изначально передаём в макрос посимвольно (HASH('A', 'B', 'C')).
Я продемонстрировал что не обязательно посимвольно передавать строку что бы высчитывать хеш.
Что вы подразумеваете под изменением строки и для чего ее менять...не улавливаю сути. Топик был про скрытие/шифрование строк, не про изменения.
Шифрование не должно менять строку, оно должно менять лишь предствление в котором она хранится до расшифровки и тут все ок.
 
Последнее редактирование:
Я продемонстрировал что не обязательно посимвольно передавать строку что бы высчитывать хеш.
Что вы подразумеваете под изменением строки и для чего ее менять...не улавливаю сути. Топик был про скрытие/шифрование строк, не про изменения.
Шифрование не должно менять строку, оно должно менять лишь предствление в котором она хранится до расшифровки и тут все ок.

Я говорил конкретно про использвоание макросов без constexpr (ещё раз прошу обратить внимание на то, на что я ответил и на то, чем я ответил).
Менять предтсавление строки разве можно без её изменения? Покажи мне пример с помощью макросов (без constexpr, так как изначально я сказал, что это минус) как это можно сделать.

UPD: И представление не логичное - это представление без возвращения к исходному. Мы по логике вещей можем представить строку как целое число (что и делает хэширование), но сможем ли мы восстановить исходную строку?
 
Кстити constexpr в принципе не создает дополнительного кода(не добавляет вес готовому коду), но замедляет компиляцию это да.
Зависимости от стандарта 11? - ну это совсем странная проблема, только если кодер поставил себя в зависимость от древнего компиля.
Обфускация в отношении строк это мне вообще непонятно, вопервых как а во вторых для чего.
А так да, без constexpr делать то для чего предназначен constexpr как минимум неудобно...если только не написать свой препроцессор(я кстати написал) и считаю хеши и многое другое на нем.
Рекомендую осваивать и использовать новые инструменты если они того стоят, constexpr стоит того.
 
Менять предтсавление строки разве можно без её изменения?
Была у нас строка "123", от того что мы ее поксорим ^0x11 она не перестанет быть строкой "123" но представлена она будет в иной "кодировке". А еще "123" это та же самая строка что и L"123"но представление они имеют разное.
Это о форме и содержании.
 
Возможно кому то это будет полезным.
Для множества кодерских задач, таких как хеширование и тд - я уже давно написал программу которая при нажатии определенной комбинации клавиш
проверяет данные в буффере обмена, опознанные данные она обрабатывает и помещает в буффер обмена результат
например
в буффер HASH("1234234")
извлекаем 0x435743

в буффер asm32(
mov eax, 1
ret
)
извлекаем 0xb8, 0x01, 0x00, 0x00, 0x00, 0xc3

ну и в том же духе, криптование строк или массивов ну и всякие прочие полезности...но свой препроцессор серьезному кодеру всеравно желателен.
Просто есть то что удобнее вот так сразу посчитать, а что то удобно препроцессором.
 
ВЫ
Возможно кому то это будет полезным.
Для множества кодерских задач, таких как хеширование и тд - я уже давно написал программу которая при нажатии определенной комбинации клавиш
проверяет данные в буффере обмена, опознанные данные она обрабатывает и помещает в буффер обмена результат
например
в буффер HASH("1234234")
извлекаем 0x435743

в буффер asm32(
mov eax, 1
ret
)
извлекаем 0xb8, 0x01, 0x00, 0x00, 0x00, 0xc3

ну и в том же духе, криптование строк или массивов ну и всякие прочие полезности...но свой препроцессор серьезному кодеру всеравно желателен.
Просто есть то что удобнее вот так сразу посчитать, а что то удобно препроцессором.

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

Во вторых. Хэш-сумма не восстанавливается к исходной строке. У тебя просто байтов не хватит для того, чтобы хранить те данные, из которых получится восстановить исходную строку. Далее, без constexpr ты не сможешь взять ЦЕЛУЮ строку и воздействовать на неё, только посимвольно (как я обозначил выше). Если хочешь сказать, что я не прав - прошу опубликовать пример, где макрос (#define) способен без взаимодействия с constexpr проделать любую операцию со строкой (compile-time).

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

UPD: constexpr способен не только хэшировать строку, но и обфусцировать её с возможностью восстановления;)
 
Последнее редактирование:
Во первых. Малварь - это базонезависимый код.
Утверждение мягко говря спорное... и причем тут вообще малварь? а особенно базонезависимый код. Но на всякий случай подскажу вам что малварь это - вредоносное програмное обеспечение а базонезависимый код это совсем другое.
Я не знаю в каком году конкретно ты подключился к этому делу, но твой подход к делу не эффективен.
К делу сокрытия строк в программах?
А каком именно подходе идет речь?
Далее, проблема в msvcrt, это ужас в тех приложениях, где требуется независимость и маленький вес.
Причем тут msvcrt? вы думаете что constexpr подтянет за собой msvcrt? Причем тут вес программ?
Во вторых. Хэш-сумма не восстанавливается к исходной строке. У тебя просто байтов не хватит для того, чтобы хранить те данные, из которых получится восстановить исходную строку.
Это вообще трезвым умом не понять а я увы не пью спиртного.
Далее, без constexpr ты не сможешь взять ЦЕЛУЮ строку и воздействовать на неё, только посимвольно (как я обозначил выше). Если хочешь сказать, что я не прав - прошу опубликовать пример, где макрос (#define) способен без взаимодействия с constexpr проделать любую операцию со строкой (compile-time).
А еще я не смогу взять велосипед и переплыть на нем океан. Есть constexpr и есть препроцессоры, и по линку на который вы ссылались так же есть примеры с constexpr. в чем проблема мне совсем не понятно.
UPD: constexpr способен не только хэшировать строку, но и обфусцировать её с возможностью восстановления;)
Для чего обфусцировать строки мне непонятно в принципе...если только вы не путает шифрование с обфускацией, а это я вам скажу совсем разные методы.
 
Утверждение мягко говря спорное... и причем тут вообще малварь? а особенно базонезависимый код. Но на всякий случай подскажу вам что малварь это - вредоносное програмное обеспечение а базонезависимый код это совсем другое.

К делу сокрытия строк в программах?
А каком именно подходе идет речь?

Причем тут msvcrt? вы думаете что constexpr подтянет за собой msvcrt? Причем тут вес программ?

Это вообще трезвым умом не понять а я увы не пью спиртного.

А еще я не смогу взять велосипед и переплыть на нем океан. Есть constexpr и есть препроцессоры, и по линку на который вы ссылались так же есть примеры с constexpr. в чем проблема мне совсем не понятно.

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

1. Это просто одна из характеристик. Не общая, а частичная.
2. Подход с constexpr.
3. constexpr как и любой другой спецификатор, доступный только в C++, подвязан на msvcrt. Веса это прибавляет достаточно, если мы пишем приложение с минимальной языковой зависимостью (компонуем вместе с флагом /MT).
4. Без комментариев.
5. Частично, проблемы описаны выше. Также не стоит забывать о воздействии каких-либо языковых зависимостей на структуру файла, что может повлиять на крипт/любой запуск в памяти.
6. Источник Вики: Обфуска́ция (от лат. obfuscare — затенять, затемнять; и англ. obfuscate — делать неочевидным, запутанным, сбивать с толку) или запутывание кода — приведение исходного текста или исполняемого кода программы к виду, сохраняющему её функциональность, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции (source). Суть в сохранении исходного значения. Обфускация - общее понятие, которое может включать в себя криптование/шифрование.

Этим сообщением хочу закончить этот бесполезный спор. Советую глубже изучать предмет обсуждения.
 
1. Это просто одна из характеристик. Не общая, а частичная.
2. Подход с constexpr.
3. constexpr как и любой другой спецификатор, доступный только в C++, подвязан на msvcrt. Веса это прибавляет достаточно, если мы пишем приложение с минимальной языковой зависимостью (компонуем вместе с флагом /MT).
4. Без комментариев.
5. Частично, проблемы описаны выше. Также не стоит забывать о воздействии каких-либо языковых зависимостей на структуру файла, что может повлиять на крипт/любой запуск в памяти.
6. Источник Вики: Обфуска́ция (от лат. obfuscare — затенять, затемнять; и англ. obfuscate — делать неочевидным, запутанным, сбивать с толку) или запутывание кода — приведение исходного текста или исполняемого кода программы к виду, сохраняющему её функциональность, но затрудняющему анализ, понимание алгоритмов работы и модификацию при декомпиляции (source). Суть в сохранении исходного значения. Обфускация - общее понятие, которое может включать в себя криптование/шифрование.

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


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх