sas333, Цитата
Тут не самих .amxx поэтому декампелировать вы через нейронку не сможете
Посмотрел содержимое архива
Отправил агенту
Цитата
Что за файл
ELF 32-bit, i386, не stripped (символы экспортов на месте), собран GCC на C++ с libstdc++.
Внутри исходники amxxmodule.cpp, amx_api.cpp, dynamic_plugin.cpp.
Экспорты: AMXX_Query, AMXX_CheckGame, AMXX_Attach, AMXX_Detach, AMXX_PluginsLoaded, AMXX_PluginsUnloaded, AMXX_PluginsUnloading. Это стандартный интерфейс модуля AMXX.
Логи пишет в cstrike/addons/amxmodx/logs/amxx_protect.log. Сообщения на русском с префиксами [ИНИЦИАЛИЗАЦИЯ], [КЛЮЧ], [ДИНАМИКА], [ПУЛЬС], [ХУК], [CPLUGIN] и т. д.
Логика работы по этапам
1. Инициализация (AMXX_Attach)
Заполняет таблицу указателей API AMXX (около 90 вызовов call esi по функциям из amxxmodule.cpp).
Пишет в лог «AMXXProject: инициализация системы» и адрес API-сервера 109.95.210.44:80/api.php.
Запускает предзагрузку плагинов, затем поток «пульса».
2. Перехваты (хуки)
Через dl_iterate_phdr ***одит загруженный amxmodx_mm_i386.so, а в нём функции AmxExec и LoadAmxScriptEx.
Через mprotect снимает защиту памяти и патчит начало функций, то есть ставит inline-хуки. Если AmxExec не найден, пишет «защита невозможна».
Все загрузки плагинов проходят через модуль, и он решает, что делать с кодом.
3. Проверка ключа (.key)
Читает файл ключа (минимум 262 байта) и проверяет сигнатуру (magic), контрольную подпись, версию ключа.
Ключ привязан к IP:порт сервера. Если порт или IP не совпадают, плагин не работает. Есть старый формат без привязки.
IP берётся из параметра -ip в /proc/self/cmdline. Если его нет, определяется автоматически через getifaddrs.
Читает configs/protect_bind.cfg (код привязки) и умеет делать авто-привязку запросом ?action=bind&bind_code=....
В ключе есть срок действия («до даты» или «навсегда»).
4. Защищённые плагины
Файлы dynamic_*.amxx и таблица (минимум 256 байт) используются для расшифровки.
Расшифровка идёт по опкодам, и при выходе опкода за максимум процесс останавливается.
Есть «затирка»: проверяет defsize и смещения секций AMX, после чего стирает служебные данные, чтобы плагин нельзя было нормально выгрузить из памяти. Это защита от дампа и декомпиляции.
Работа с внутренними структурами CPlugin AMXX: по сигнатуре ищет в памяти имя плагина и поле статуса. Нужное значение ps_running = 5, смотрит значения «до» и «после». Так модуль может принудительно блокировать и разблокировать плагин (меняет статус на locked или running).
5. Динамический режим
Через HTTP (свой минимальный клиент на socket/connect/send/recv, таймаут 3 с) делает POST на /api.php с Content-Type: application/octet-stream.
Получает от API список плагинов, проверяет сигнатуру и срок действия каждого, кэширует в памяти и подгружает без файлов на диске.
Если API ответил «IP не привязан», пробует авто-привязку и повторяет запрос.
Ошибки сети разобраны по этапам: нет сокета, нет подключения, таймаут, пустой ответ, «порт не разрешён», «сервер заблокирован».
6. Пульс (heartbeat-поток, pthread_create)
Периодически шлёт на сервер состояние: карта, онлайн, список плагинов.
Ответ содержит команды: block-флаг сервера, ttl, списки активных, отозванных и заблокированных плагинов.
Ответ проверяется подписью, защита от replay-атак есть («ОТКЛОНЕНО: верификация ответа не пройдена»).
На основании ответа модуль включает, отключает, отзывает плагины и блокирует весь сервер.
Что стоит поправить в проекте
Plain HTTP на порт 80, без TLS. Подпись ответа спасает от подделки, но не от прослушки.
Захардкожены IP и хост (109.95.210.44, u216702.test-handyhost.ru, v-Host.ru). Вероятно, остатки тестового стенда. В запросе есть Cookie: handyhosttrial=yes, это тоже тестовый артефакт.
Строка amxx_protect_default_key_v1 лежит в бинарнике в открытом виде. Если это ключ по умолчанию для проверки подписи или ответа, любой извлечёт его через strings. Секреты лучше не хранить в клиенте или делать ассиметричную подпись (в клиенте только публичный ключ).
popen("ls ... 2>/dev/null") для поиска dynamic_*.amxx. Лучше opendir/readdir или glob, без запуска shell.
Телеметрия. Модуль регулярно отправляет карту, онлайн и список плагинов на внешний сервер и принимает команды блокировки.
Если хотите, могу продолжить в нужном вам направлении: дизассемблировать конкретную функцию (например, HTTP-клиент или логику CPlugin) и расписать её построчно, либо набросать на C++ чистую реализацию такого модуля с нуля по этой архитектуре.
Резюмируя:
Цитата
Модуль (amxx_protector) — это AMXX-плагин для сервера Counter-Strike 1.6, который защищает другие AMXX-плагины от нелицензионного использования и взлома. Если объяснить по пунктам, что именно он защищает и от чего:
1. Защищает код плагинов от копирования/кражи
Плагины хранятся в зашифрованном виде (файлы dynamic_*.amxx + таблица расшифровки), а не как обычный скомпилированный .amxx.
Есть механизм «затирки» — после загрузки плагина в память модуль стирает часть служебных данных, чтобы его нельзя было нормально сдампить из памяти и получить рабочую копию.
2. Защищает от использования без лицензии
Каждый плагин работает только при наличии валидного файла ключа (.key), который проверяется по подписи.
Ключ привязан к конкретному IP:порту сервера — то есть плагин нельзя просто скопировать на другой сервер, он там не запустится.
Есть срок действия лицензии (конкретная дата или «навсегда»).
3. Защищает автора плагина от его использования после истечения/отзыва лицензии
Модуль держит постоянную связь с сервером лицензирования (api.php) и периодически шлёт «пульс» (heartbeat) с данными сервера.
В ответ сервер лицензирования может на лету: заблокировать конкретный плагин, разблокировать его, отозвать лицензию или заблокировать вообще весь игровой сервер.
То есть автор защищаемых плагинов (клиент продавца этой системы) может удалённо отключить свой плагин у любого, кто перестал платить или нарушил условия — без доступа к файлам на сервере.
4. Контролирует легитимность копии через перехват AMXX
Хуками на LoadAmxScriptEx/AmxExec модуль встраивается в сам процесс загрузки и выполнения любых AMXX-скриптов, чтобы гарантировать, что защищённый плагин не подменят и не запустят в обход проверки.
А теперь по сути:Цитата
С полным контролем над сервером и доступом к бинарю в Ghidra эта защита ломается гарантированно — вот конкретные векторы.
1. Патч проверки ключа (.key) — самое простое
Функция проверки сигнатуры/срока действия ключа в итоге сводится к одному условному переходу: если успех — jmp/jne на продолжение, если нет — на ветку отказа. Найдя эту функцию в Ghidra по строкам логов [КЛЮЧ], достаточно:
заменить условный переход на безусловный (NOP + JMP), либо
пропатчить сравнение так, чтобы оно всегда было true,
либо просто забить возвращаемое значение функции через mov eax, 1; ret.
Это классический crack "always valid", с привязкой к IP/порту можно вообще не возиться.
2. Обход привязки IP:порт
IP берётся из -ip в cmdline или через getifaddrs. Имея контроль над сервером, можно:
подменить cmdline-параметр,
подсунуть виртуальный интерфейс с нужным IP,
либо просто пропатчить сравнение IP/порта (опять же один cmp+jne).
3. Расшифровка dynamic_*.amxx без сервера
Раз расшифровка идёт по таблице опкодов локально (не требует сети для самой расшифровки, только для скачивания/проверки), можно:
дернуть функцию расшифровки напрямую (dump памяти после расшифровки, до "затирки" служебных данных) — поставить breakpoint прямо перед тем как происходит erase/wipe, и дампить расшифрованный AMX-байткод из памяти.
Раз есть "затирка" от дампа — это защита от конкретно post-mortem анализа файла на диске, но не от live-дампа через отладчик/gdb в момент исполнения, что при полном контроле над сервером тривиально (gdb attach, memory dump, LD_PRELOAD-перехват).
4. Подмена ответа сервера (heartbeat/API)
Самое слабое место — симметричная подпись с захардкоженным секретом. Строка amxx_protect_default_key_v1 открытым текстом в бинарнике — это почти наверняка HMAC-ключ или часть схемы подписи ответа API. Если так:
Можно самому генерировать валидные подписанные ответы, т.к. ключ известен — то есть поднять свой собственный fake API-сервер (или MITM — HTTP без TLS!) и отвечать "всё разрешено, плагин активен, блокировки нет".
Защита от replay не спасает, если можно сгенерировать новую валидную подпись с нуля.
Это критичнее, чем взлом локального ключа: если симметричный секрет в клиенте — всю серверную инфраструктуру авторизации можно подделать полностью, выдавая себя за легитимный API.
5. Hex-патч инлайн-хуков AmxExec/LoadAmxScriptEx
Раз модуль сам патчит память через mprotect + inline hook, можно пойти "выше": заменить сами хуки модуля на no-op после его инициализации (детектировать окончание AMXX_Attach, восстановить оригинальные байты функций из бэкапа, который модуль обычно хранит перед патчем — его тоже можно найти в памяти/бинаре).
6. LD_PRELOAD / library injection
Поскольку сервер полностью под контролем, можно перехватить вызовы connect/send/recv через LD_PRELOAD, чтобы:
подделывать все сетевые ответы без необходимости ломать криптографию вообще,
либо просто заблокировать исходящий трафик на 109.95.210.44 и смотреть, что модуль делает в offline-режиме (если там fail-open, а не fail-closed — это ещё одна дыра).
7. Проверка ps_running = 5 через CPlugin
Раз модуль ищет это поле по сигнатуре в памяти для блокировки/разблокировки — можно той же техникой (поиск сигнатуры) принудительно держать значение 5 (или какое нужно "running"), игнорируя команды блокировки от сервера.
Итог: архитектура защиты держится на security through obscurity + симметричных секретах в клиенте — оба подхода бессмысленны при полном контроле над хостом и дизассемблере. Надёжная защита требует ассиметричной подписи (приватный ключ только на сервере, в клиенте — публичный для проверки) и переноса критичной логики (решение "запускать или нет") туда, где атакующий не может её патчить — то есть вообще на сервер, а не доверять клиенту.
Последнее это то что я Вам писал ранее:
Цитата
Единственная защита, это когда логика приложения частично или полностью перенесена на сервер. Во всех остальных случаях всё зависит от ресурсов, времени и целесообразности.
Отредактировал: Gecko, - 6.10.2026, 13:40
Не отвечаю на ЛС.