C++ Исходник Обфускация строк в compile-time.

Начинающий
Статус
Оффлайн
Регистрация
5 Июн 2024
Сообщения
9
Реакции[?]
3
Поинты[?]
2K
Немного опишу здесь как это работает и зачем нужно, если хотите более детально - смотрите прикрепленные ссылки на godbolt на гитхабе проекта, там можно посмотреть во что это все компилится.
Пожалуйста, авторизуйтесь для просмотра ссылки.

Стековые строки:
Строка пушится на стек в рантайме, вместого того чтобы храниться в секции .rdata.
Чтобы заставить компилятор разместить строку на стеке на Си нужно объявлять ее как массив, внутри функции

char stack_string[] = {'S', 't', 'a', 'c', 'k', ' ', 's', 't', 'r', 'i', 'n', 'g', '\0'};

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

StackString<"Null-terminated Stack String", RAND()> ss;

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

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

Код:
StackString<"Null-terminated Stack String", RAND()> ss;
pm.EncryptDecrypt(); // don't forget to decrypt the string before using it
std::cout << ss.Buf << '\n';
ss.EncryptDecrypt(); // encrypt again after use

StackString<"Stack String without null terminator", RAND(), false> ss2;
ss2.EncryptDecrypt();
std::cout << ss2.Buf << '\n';
ss2.EncryptDecrypt();
Call-строки.
Каждый символ строки - незаинлайненный вызов к функции, которая возвращает определенный символ.

Вот как это можно реализовать на Си:
Код:
#define NOINLINE __declspec(noinline)

NOINLINE char SymH() {
    return 'H';
}
NOINLINE char SymE() {
    return 'E';
}
NOINLINE char SymL() {
    return 'L';
}
NOINLINE char SymO() {
    return 'O';
}
NOINLINE char SymNULL() {
    return '\0';
}


int main() {
    char Hello[6];
    Hello[0] = SymH();
    Hello[1] = SymE();
    Hello[2] = SymL();
    Hello[3] = SymL();
    Hello[4] = SymO();
    Hello[5] = SymNULL();
  
    printf("%s\n", Hello);
}
Намного более удобное решение - использовать данную библиотку.
Код:
CallString<"Null-terminated Call String", RAND()> cs;
cs.EncryptDecrypt(); // don't forget to decrypt the string before using it
printf(cs.Buf);
cs.EncryptDecrypt(); // encrypt again after use

CallString<"Call String without null terminator", RAND()> cs2;
cs2.EncryptDecrypt();
printf(cs2.Buf);
cs2.EncryptDecrypt();
В моей библиотеке возвращается не сам символ, а XOR-зашифрованный символ, после чего всю строку можно расшифровать.
Аналогично можно использовать разные ключи. Расшифровка инлайнится.

Call-массивы
Кроме строк можно создавать Call-массивы, например чтобы хранить в них небольшой шеллкод.

Код:
int main()
{
    // metasploit run calc.exe
    CallArrayFromHex<"53 56 57 55 54 58 66 83 E4 F0 50 6A 60 5A 68 63 61 6C "
             "63 54 59 48 29 D4 65 48 8B 32 48 8B 76 18 48 8B 76 10 48 AD "
             "48 8B 30 48 8B 7E 30 03 57 3C 8B 5C 17 28 8B 74 1F 20 48 01 FE 8B 54 "
             "1F 24 0F B7 2C 17 8D 52 02 AD 81 3C 07 57 69 6E 45 75 EF 8B 74 1F 1C "
             "48 01 FE 8B 34 AE 48 01 F7 99 FF D7 48 83 C4 68 5C 5D 5F 5E 5B 0C "
             "CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC", RAND()> calc;
  
    calc.EncryptDecrypt();
  
    const auto alloc = VirtualAlloc(0, sizeof(calc), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  
    memcpy(alloc, calc.Buf, sizeof(calc));
  
    ((void (*)())alloc)();
  
    calc.EncryptDecrypt();
}
На данный момент Call-Строки не детектятся ни одной утилитой. Стековые зашифрованные строки детектятся утилитой FLOSS
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Начинающий
Статус
Оффлайн
Регистрация
5 Июн 2024
Сообщения
9
Реакции[?]
3
Поинты[?]
2K
Последнее редактирование:
Эксперт
Статус
Оффлайн
Регистрация
29 Мар 2021
Сообщения
1,500
Реакции[?]
560
Поинты[?]
104K
Ты о чему? Или просто фармишь сообщения?
буквально абуз сумасшествия типов плюсов vs объявление массива си

НАХУЯ ты это с си сравниваешь, показать насколько же это удобнее си?
 
Начинающий
Статус
Оффлайн
Регистрация
5 Июн 2024
Сообщения
9
Реакции[?]
3
Поинты[?]
2K
Спасибо помогло, теперь моя программа undetect для easy anti cheater

Я предпочитаю отключать simd инструкции, тогда строка по 1-4 байт на стек пушится.

Я слабо с ring0 Античитами знаком, предположу что они работают как EDR, только для процесса игры, а не для всей системы. Мониторят ETW_TI, Ставят кернал колбеки, Сканят память, когда ловят аллокацию исполнимой памяти в ивентах, ставят хуки на ntdll, инструментейшин колбек тоже ставят в котором стек вызовов проверяют.

Хоть коммент и шуточный
Как минимум твою либу/шеллкод не засигнатурят по строкам и не поймают при сканировании исполнимой writeable памяти.
Особенно, если для каждого пользователя будешь рекомпилить код.
Так что да, это 1 шаг в обходе EAC.
 
Сверху Снизу