Гайд Как работают метки протекторов?

#define VOID void
Начинающий
Статус
Оффлайн
Регистрация
13 Май 2017
Сообщения
120
Реакции[?]
24
Поинты[?]
13K
Приветствую вас, дорогие читатели! В этой статье мы погрузимся в изучение интересного и важного аспекта защиты программного обеспечения. Конкретно будем рассматривать принцип работы меток протекторов, таких как VMProtect, Themida и других. Я стараюсь сделать это максимально просто и понятно, так что давайте приступим.

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

Существует два распространенных типа меток: inline assembly marker и library call marker. Первый тип, inline assembly marker, является самым удобным, так как он позволяет вставить инструкции любого размера непосредственно в тело функции на этапе компиляции. Это означает, что простым протекторам не нужно будет выделять память под защитный код, который оборачивает ваш блок кода.
Однако, в настоящее время самым популярным способом является использование library call marker. Это связано с тем, что компилятор Microsoft не поддерживает inline assembly в X64. Кроме того, этот способ позволяет быть уверенным на 10 миллиардов процентов, что это именно метка протектора, а не простое совпадение паттерна в случайном месте кода.

Так давайте же посмотри как выглядят метки разных протекторов в листинге:


1720605889358.png
Рисунок 1 — Метки Themida в листинге.

1720605895130.png
Рисунок 2 — Метки VMProtect в листинге.

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

1720605900430.png
Рисунок 3 — Метки VMProtect в таблице импортов.


Теперь на основе полученных знаний попробуем реализовать собственные метки. Будем пользоваться способом library call marker. Для начала нужно сделать 2 проекта: Marker-SDK представляет из себя динамическую библиотеку с функциями заглушками, Marker-APP занимется поиском меток нашего Marker-SDK в PE-файле и их реализацией. Именно динамическая библиотека нам необходима потому что она может на 10 миллиардов процентов гарантировать внешний вызов функции в коде и давать нам запись в таблице импорта, в том время как статическая вполне может заинлайнить код своей функции внутрь нашей.

Первым этапом будет описывание нашего Marker-SDK, для этого создадим sdk.h и вставим туда следующий код:

C++:
#ifndef MARKER_SDK_H
#define MARKER_SDK_H

#ifdef MARKER_SDK_EXPORTS
#define MARKER_API __declspec(dllexport)
#else
#define MARKER_API __declspec(dllimport)
#endif  // MARKER_SDK_EXPORTS

extern "C" {
MARKER_API void begin_encrypted(void);
MARKER_API void end_encrypted(void);
}

#endif  // MARKER_SDK_H
Так же для корректной компиляции нам понадобиться файл заглушка sdk.cpp, в котором будет храниться пустая имплементация этих 2-х функций.

Следующим этапом у нас идёт реализация Marker-APP. Тут нам понадобиться какой-нибудь PELib, PEBliss, либо же можно просто использовать структуры Windows, но я буду пользоваться кроссплатформенным
Пожалуйста, авторизуйтесь для просмотра ссылки.
. Весь код выкладывать нет смысла, так что рассмотрим исключительно функцию поиска метки:

C++:
auto find_sdk_imports(std::error_code& ec) {
    auto result = std::pair<std::uintptr_t, std::uintptr_t>{};

    // Получаем директории таблицы импортов
    auto imports_boundary = image_->get_directory(win::directory_entry_import);
    if (!imports_boundary) {
      ec = std::make_error_code(std::errc::no_such_file_or_directory);
      return result;
    }

   // Перебираем все импортируемые библиотеки
    for (auto library = reinterpret_cast<win::import_directory_t*>(
             image_->rva_to_ptr(imports_boundary->rva));
         library->rva_name; ++library) {
      // Получаем имя библиотеки
      auto library_name = std::string{
          reinterpret_cast<const char*>(image_->rva_to_ptr(library->rva_name))};

      if (library_name != "Marker-SDK.dll") continue;
      // Перебираем все импортируемые функции для библиотеки
      for (auto function = reinterpret_cast<win::image_thunk_data_x64_t*>(
               image_->rva_to_ptr(library->rva_first_thunk));
           function->address; ++function) {
       // Получаем имя функции
        auto function_name =
            std::string{reinterpret_cast<win::image_named_import_t*>(
                            image_->rva_to_ptr(function->address))
                            ->name};

        // Получаем смещение до функции в IAT
        // Так же я конвертирую в смещение относительно начала буффера
        auto iat_address = image_->ptr_to_raw(function);
        if (function_name == "begin_encrypted") {
          result.first = iat_address;
        } else if (function_name == "end_encrypted") {
          result.second = iat_address;
        }
      }
    }

    return result;
  }
На выходе эта функция вернёт нам пару [начало, конец] адресов меток на IAT. Теперь мы можем подключить наш Marker-SDK к любому проекту и чтобы заменить их на полезную нагрузку остаётся прогнать PE-файл любым дизассемблером и сравнить расчитанные адреса для call/jmp с адресами меток.

Текст статьи написан с помощью mistral.ai.
 
Начинающий
Статус
Оффлайн
Регистрация
21 Апр 2024
Сообщения
24
Реакции[?]
17
Поинты[?]
16K
Как мне это вставить в свой софт?Будет работать если чит написан на python?
 
Забаненный
Статус
Оффлайн
Регистрация
24 Июн 2024
Сообщения
28
Реакции[?]
3
Поинты[?]
3K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Приветствую вас, дорогие читатели! В этой статье мы погрузимся в изучение интересного и важного аспекта защиты программного обеспечения. Конкретно будем рассматривать принцип работы меток протекторов, таких как VMProtect, Themida и других. Я стараюсь сделать это максимально просто и понятно, так что давайте приступим.

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

Существует два распространенных типа меток: inline assembly marker и library call marker. Первый тип, inline assembly marker, является самым удобным, так как он позволяет вставить инструкции любого размера непосредственно в тело функции на этапе компиляции. Это означает, что простым протекторам не нужно будет выделять память под защитный код, который оборачивает ваш блок кода.
Однако, в настоящее время самым популярным способом является использование library call marker. Это связано с тем, что компилятор Microsoft не поддерживает inline assembly в X64. Кроме того, этот способ позволяет быть уверенным на 10 миллиардов процентов, что это именно метка протектора, а не простое совпадение паттерна в случайном месте кода.

Так давайте же посмотри как выглядят метки разных протекторов в листинге:


Посмотреть вложение 280830
Рисунок 1 — Метки Themida в листинге.

Посмотреть вложение 280831
Рисунок 2 — Метки VMProtect в листинге.

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

Посмотреть вложение 280832
Рисунок 3 — Метки VMProtect в таблице импортов.


Теперь на основе полученных знаний попробуем реализовать собственные метки. Будем пользоваться способом library call marker. Для начала нужно сделать 2 проекта: Marker-SDK представляет из себя динамическую библиотеку с функциями заглушками, Marker-APP занимется поиском меток нашего Marker-SDK в PE-файле и их реализацией. Именно динамическая библиотека нам необходима потому что она может на 10 миллиардов процентов гарантировать внешний вызов функции в коде и давать нам запись в таблице импорта, в том время как статическая вполне может заинлайнить код своей функции внутрь нашей.

Первым этапом будет описывание нашего Marker-SDK, для этого создадим sdk.h и вставим туда следующий код:

C++:
#ifndef MARKER_SDK_H
#define MARKER_SDK_H

#ifdef MARKER_SDK_EXPORTS
#define MARKER_API __declspec(dllexport)
#else
#define MARKER_API __declspec(dllimport)
#endif  // MARKER_SDK_EXPORTS

extern "C" {
MARKER_API void begin_encrypted(void);
MARKER_API void end_encrypted(void);
}

#endif  // MARKER_SDK_H
Так же для корректной компиляции нам понадобиться файл заглушка sdk.cpp, в котором будет храниться пустая имплементация этих 2-х функций.

Следующим этапом у нас идёт реализация Marker-APP. Тут нам понадобиться какой-нибудь PELib, PEBliss, либо же можно просто использовать структуры Windows, но я буду пользоваться кроссплатформенным
Пожалуйста, авторизуйтесь для просмотра ссылки.
. Весь код выкладывать нет смысла, так что рассмотрим исключительно функцию поиска метки:

C++:
auto find_sdk_imports(std::error_code& ec) {
    auto result = std::pair<std::uintptr_t, std::uintptr_t>{};

    // Получаем директории таблицы импортов
    auto imports_boundary = image_->get_directory(win::directory_entry_import);
    if (!imports_boundary) {
      ec = std::make_error_code(std::errc::no_such_file_or_directory);
      return result;
    }

   // Перебираем все импортируемые библиотеки
    for (auto library = reinterpret_cast<win::import_directory_t*>(
             image_->rva_to_ptr(imports_boundary->rva));
         library->rva_name; ++library) {
      // Получаем имя библиотеки
      auto library_name = std::string{
          reinterpret_cast<const char*>(image_->rva_to_ptr(library->rva_name))};

      if (library_name != "Marker-SDK.dll") continue;
      // Перебираем все импортируемые функции для библиотеки
      for (auto function = reinterpret_cast<win::image_thunk_data_x64_t*>(
               image_->rva_to_ptr(library->rva_first_thunk));
           function->address; ++function) {
       // Получаем имя функции
        auto function_name =
            std::string{reinterpret_cast<win::image_named_import_t*>(
                            image_->rva_to_ptr(function->address))
                            ->name};

        // Получаем смещение до функции в IAT
        // Так же я конвертирую в смещение относительно начала буффера
        auto iat_address = image_->ptr_to_raw(function);
        if (function_name == "begin_encrypted") {
          result.first = iat_address;
        } else if (function_name == "end_encrypted") {
          result.second = iat_address;
        }
      }
    }

    return result;
  }
На выходе эта функция вернёт нам пару [начало, конец] адресов меток на IAT. Теперь мы можем подключить наш Marker-SDK к любому проекту и чтобы заменить их на полезную нагрузку остаётся прогнать PE-файл любым дизассемблером и сравнить расчитанные адреса для call/jmp с адресами меток.

Текст статьи написан с помощью mistral.ai.
Привет, хорошая статья, для объяснения новичкам, но разве это не все уже знают?
Как мне это вставить в свой софт?Будет работать если чит написан на python?
Привет, в твоем случае не получится использовать метки протектора, переведи свой скрипт на пайтоне в .exe, используя специальные ультилиты ( сам можешь нагуглить ), и уже сверху можешь наложить протектор VMP/WinLicense ( Themida, Code Virtualizer )
 
Последнее редактирование:
practice makes perfect
Пользователь
Статус
Оффлайн
Регистрация
16 Мар 2019
Сообщения
86
Реакции[?]
67
Поинты[?]
19K
Как мне это вставить в свой софт?Будет работать если чит написан на python?
нет нужды, оно ни на что не повлияет🤙🤙🤙. это типа кавер на начало своего протектора? я трохи не зрозумів goal of this topic👽
 
#define VOID void
Начинающий
Статус
Оффлайн
Регистрация
13 Май 2017
Сообщения
120
Реакции[?]
24
Поинты[?]
13K
это типа кавер на начало своего протектора? я трохи не зрозумів goal of this topic
Это "типа" ты так поддержку проявляешь?) Если хочешь поддержать, то старайся лучше. Если хочешь указать на ошибки, то пиши по фактам. Сейчас твоё сообщение не несёт никакой смысловой нагрузки, друг. :roflanPominki:
 
practice makes perfect
Пользователь
Статус
Оффлайн
Регистрация
16 Мар 2019
Сообщения
86
Реакции[?]
67
Поинты[?]
19K
Это "типа" ты так поддержку проявляешь?) Если хочешь поддержать, то старайся лучше. Если хочешь указать на ошибки, то пиши по фактам. Сейчас твоё сообщение не несёт никакой смысловой нагрузки, друг. :roflanPominki:
жиденько
 
Пользователь
Статус
Оффлайн
Регистрация
23 Авг 2021
Сообщения
520
Реакции[?]
53
Поинты[?]
20K
Это "типа" ты так поддержку проявляешь?) Если хочешь поддержать, то старайся лучше. Если хочешь указать на ошибки, то пиши по фактам. Сейчас твоё сообщение не несёт никакой смысловой нагрузки, друг. :roflanPominki:
Так он спросил в чем смысл этого поста..
 
Начинающий
Статус
Оффлайн
Регистрация
5 Фев 2024
Сообщения
19
Реакции[?]
2
Поинты[?]
2K
Есть ли софт, чтобы парсить метки. Или это только ручками искать ?
 
#define VOID void
Начинающий
Статус
Оффлайн
Регистрация
13 Май 2017
Сообщения
120
Реакции[?]
24
Поинты[?]
13K
practice makes perfect
Пользователь
Статус
Оффлайн
Регистрация
16 Мар 2019
Сообщения
86
Реакции[?]
67
Поинты[?]
19K
Спасибо за разжёвывание, но у человека явно проблемы с общением раз смысл его сообщений переводят:roflanEbalo:
wat? ты хоть понял что написал? как вообще связано мое сообщение и то, что написал тот чувак выше? видимо, в который раз убеждаюсь, что напастить софт на гташку мозгов не требует от слова совсем и какого-либо мыслительного процесса. давай следующую статью про сервер-маппер)
 
Сверху Снизу