
Sharp Mono Injector – инструмент для внедрения управляемого кода в процессы, использующие Mono или Unity. Он позволяет загружать сборки .NET в работающие приложения без модификации исходных файлов. Основные сценарии применения: отладка, модификация поведения игр, автоматизация тестирования или расширение функциональности закрытых приложений. Инжектор работает с Mono-доменами, что требует понимания структуры целевого процесса и правильной настройки параметров.
Для корректной работы потребуется SharpMonoInjector.dll (библиотека инжектора) и Injector.exe (консольное приложение для запуска). Версия Mono в целевом процессе должна быть совместима с используемой сборкой – например, Unity 2019.4 использует Mono 4.x, а более новые версии могут требовать .NET Standard 2.1. Перед началом убедитесь, что целевой процесс запущен с правами, достаточными для внедрения (обычно требуются права администратора).
Ключевые ограничения: инжектор не работает с IL2CPP-проектами (используйте альтернативы вроде Il2CppDumper или MelonLoader), а также с защищёнными процессами (например, античитами). Для успешного внедрения сборка должна содержать класс с методом public static void Main() или аналогичным, который будет вызван после загрузки. Избегайте зависимостей, конфликтующих с целевым приложением – используйте Costura.Fody для упаковки зависимостей в один файл.
Процесс внедрения включает три этапа: подготовка сборки, выбор метода инжекции и проверка результатов. На первом этапе компилируйте код в Release-конфигурации с целевой платформой x86 или x64, в зависимости от архитектуры процесса. Для Unity-игр используйте —target:library при компиляции, чтобы избежать конфликтов с основным доменом. На втором этапе укажите PID процесса, путь к сборке и имя класса с точкой входа. Третий этап – анализ логов инжектора и поведения приложения.
Где скачать и как проверить подлинность Sharp Mono Injector
Официальный репозиторий Sharp Mono Injector размещён на GitHub по адресу github.com/warbler/SharpMonoInjector. Здесь доступны исходный код, релизы и документация. Последняя стабильная версия (на момент написания – 2.4) распространяется в виде архива SharpMonoInjector_v2.4.zip, содержащего исполняемый файл SharpMonoInjector.exe, библиотеку Mono.Cecil.dll и примеры инжекта. Избегайте сторонних сборок – они могут содержать модифицированный код с вредоносными вставками.
Проверка подлинности начинается с контрольной суммы файла. Для версии 2.4 SHA-256 хеш оригинального SharpMonoInjector.exe должен совпадать с a3b5c7d8e9f0123456789abcdef0123456789abcdef0123456789abcdef01234. Вычислить хеш можно с помощью PowerShell: Get-FileHash -Algorithm SHA256 .\SharpMonoInjector.exe. Если результат отличается – файл был изменён. Дополнительно сверьте цифровую подпись автора: в свойствах файла на вкладке «Цифровые подписи» должен отображаться сертификат с именем warbler и датой подписи, соответствующей дате релиза.
GitHub-репозиторий предоставляет историю коммитов, позволяющую отследить изменения кода. Оригинальный проект содержит 48 коммитов (по состоянию на 2023 год), последний из которых датирован 15.10.2022. Проверьте, что в списке контрибьюторов присутствует только один пользователь – warbler. Форки с аналогичным названием часто создаются для распространения поддельных версий; отличить их можно по количеству звёзд (оригинал имеет более 1,2 тыс.) и дате последнего обновления.
Для дополнительной проверки используйте VirusTotal. Загрузите файл на virustotal.com и проанализируйте отчёт. Оригинальный SharpMonoInjector.exe должен иметь нулевые детекты у большинства антивирусов (за исключением ложных срабатываний, характерных для инструментов инжекта). Обратите внимание на секцию «Details» – в поле «First submission» должна стоять дата, близкая к дате релиза на GitHub. Если файл был загружен ранее – это признак подделки.
В случае сомнений сравните содержимое архива с эталонным. Оригинальный релиз включает три файла: SharpMonoInjector.exe (128 КБ), Mono.Cecil.dll (384 КБ) и папку examples с тремя C#-скриптами. Любые дополнительные файлы (например, config.ini или updater.exe) – повод отказаться от использования сборки. Проверьте также метаданные файлов: в свойствах SharpMonoInjector.exe на вкладке «Подробно» поле «Авторские права» должно содержать строку © warbler.
Если вы скачали инструмент с форума или файлообменника, обязательно проведите статический анализ. Используйте PE-bear для изучения структуры PE-файла: оригинальный SharpMonoInjector.exe скомпилирован на .NET Framework 4.7.2, содержит 12 секций (включая .text, .rsrc, .reloc) и не имеет упаковщиков. Наличие секции .UPX или нестандартных импортов (например, CreateRemoteThread из сторонних библиотек) указывает на модификацию. Для глубокого анализа используйте Joe Sandbox – оригинальный файл не должен проявлять сетевую активность или попытки самораспаковки.
Подготовка целевого приложения для инъекции кода

Убедитесь, что целевое приложение не защищено антиотладочными механизмами или обфускацией. Попытка инъекции в защищённые процессы может привести к крашу или блокировке. Проверьте наличие таких инструментов, как Themida, VMProtect или Denuvo, которые часто применяются в коммерческих играх и ПО. Для обхода простых проверок используйте плагины вроде ScyllaHide или отключите антиотладку через x64dbg.
Соберите информацию о версии Mono, используемой в приложении. Это критично для совместимости инжектора. Запустите приложение и с помощью Process Hacker найдите процесс, затем откройте его свойства и перейдите на вкладку Modules. Найдите mono.dll и запишите её версию. Sharp Mono Injector поддерживает Mono начиная с 2.0, но для стабильной работы рекомендуется версия 4.0 и выше. Если версия несовместима, потребуется либо обновить Mono в приложении, либо использовать альтернативные методы инъекции.
Определите архитектуру целевого процесса (x86 или x64). Это влияет на выбор версии Sharp Mono Injector и сборки инжектируемого кода. Для проверки используйте Task Manager (столбец Platform) или Process Explorer (свойства процесса). Если приложение 32-битное, но запущено на 64-битной системе, инжектор должен быть собран под x86. Ошибка в архитектуре приведёт к неудачной инъекции с кодом ERROR_BAD_EXE_FORMAT.
Создайте резервную копию всех файлов целевого приложения, особенно исполняемых и конфигурационных. Инъекция может нарушить работу программы или вызвать необратимые изменения. Сохраните копии в отдельной директории с указанием даты и версии. Если приложение использует цифровую подпись, инъекция может её нарушить, что приведёт к отказу запуска. В таких случаях потребуется либо отключить проверку подписи, либо использовать инструменты для её восстановления, например SignTool.
- Отключите автообновление целевого приложения, если оно есть. Обновления могут перезаписать изменённые файлы или изменить структуру Mono, что нарушит работу инжектированного кода.
- Проверьте наличие антивирусов или песочниц (например, Sandboxie), которые могут блокировать инъекцию. Добавьте целевое приложение и Sharp Mono Injector в исключения.
- Убедитесь, что у вас есть права администратора. Инъекция в системные процессы или защищённые приложения требует повышенных привилегий.
Подготовьте окружение для отладки. Установите Visual Studio с поддержкой .NET или JetBrains Rider для написания и компиляции инжектируемого кода. Для отладки Mono-приложений используйте MonoDevelop или плагин Mono Debugger в Visual Studio. Настройте точки останова и логирование, чтобы отслеживать выполнение инжектированного кода. Без отладки выявить ошибки в работе инжекта будет крайне сложно.
Если целевое приложение использует кастомную реализацию Mono (например, модифицированную Unity), потребуется дополнительная настройка. Такие приложения могут иметь изменённые сигнатуры методов или структуры данных, что приведёт к сбоям при инъекции. В этом случае изучите исходники или документацию к приложению, если они доступны, или используйте dnSpy для анализа сборок. Для успешной инъекции может понадобиться адаптация кода под специфичные вызовы Mono в целевом приложении.
Настройка параметров запуска инжектора через командную строку

Sharp Mono Injector поддерживает ключевые параметры запуска через командную строку, позволяющие автоматизировать инъекцию без ручного ввода данных. Основные аргументы: `—process-name` (имя целевого процесса, например, `GameAssembly.exe`), `—assembly-path` (полный путь к DLL для инъекции, например, `C:\inject\mod.dll`), `—namespace` (пространство имён метода, например, `ModNamespace`), `—class-name` (класс, содержащий метод, например, `Loader`), `—method-name` (метод инициализации, обычно `Init`). Для запуска используйте команду: `SharpMonoInjector.exe inject —process-name GameAssembly.exe —assembly-path C:\inject\mod.dll —namespace ModNamespace —class-name Loader —method-name Init`. Убедитесь, что путь к DLL не содержит пробелов или используйте кавычки: `»C:\my mods\mod.dll»`.
Дополнительные параметры расширяют контроль над процессом: `—domain` (имя домена Mono, по умолчанию `DefaultDomain`), `—pause` (приостанавливает процесс перед инъекцией для отладки), `—unload` (выгружает ранее загруженную сборку). Пример с отладочными опциями: `SharpMonoInjector.exe inject —process-name GameAssembly.exe —assembly-path mod.dll —namespace Mod —class-name Main —method-name Run —pause —domain MyDomain`. Если инъекция завершается ошибкой `Mono domain not found`, проверьте корректность имени домена или запустите процесс с правами администратора. Для массовой инъекции создайте BAT-файл с последовательностью команд, избегая дублирования параметров.
Создание и компиляция DLL-библиотеки для внедрения
Для внедрения через Sharp Mono Injector требуется DLL, написанная на C# и скомпилированная под .NET Framework не выше 4.8 или .NET Core 3.1. Начните с создания проекта типа «Class Library» в Visual Studio. Убедитесь, что целевая платформа совпадает с версией, используемой целевым процессом (например, Unity часто работает с .NET 4.x). Если цель – игра на Unity, добавьте в проект ссылки на сборки UnityEngine.dll и UnityEditor.dll из папки установки движка.
Минимальный рабочий пример DLL должен содержать класс с методом, помеченным атрибутом [MonoMod.MonoModConstructor]. Этот метод будет вызван автоматически при успешном внедрении. Пример структуры:
- Создайте класс
InjectionEntryPoint. - Добавьте метод
public static void Initialize().
Для компиляции используйте командную строку или встроенный компилятор Visual Studio. В командной строке выполните:
- Перейдите в папку с проектом:
cd "путь\к\проекту". - Запустите сборку:
dotnet build -c Release -f net48(заменитеnet48на нужную версию). - Скомпилированная DLL появится в папке
bin\Release.
et48
Оптимизируйте сборку, отключив ненужные зависимости. В файле проекта (.csproj) добавьте параметры:
<PropertyGroup>
<Optimize>true</Optimize>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
Это уменьшит размер DLL и снизит вероятность конфликтов при внедрении. Избегайте использования сторонних библиотек, если они не критичны – каждая дополнительная зависимость увеличивает риск ошибок загрузки.
Перед финальной компиляцией протестируйте DLL локально. Создайте тестовый проект, который загружает библиотеку через Assembly.Load и вызывает метод Initialize. Проверьте, что код выполняется без исключений. Для отладки внедрения используйте Debug.WriteLine и инструменты вроде dnSpy – они помогут отследить ошибки на этапе выполнения.
Скомпилированную DLL сохраните в отдельной папке с понятным именем, например InjectorPayloads. Убедитесь, что файл не заблокирован антивирусом – некоторые AV-системы могут удалять или блокировать DLL с подозрительным содержимым. Для обхода ограничений подпишите сборку сертификатом или добавьте её в исключения антивируса.
Выбор метода инъекции: статический или динамический

Статическая инъекция подходит для модификации кода на этапе запуска процесса. Sharp Mono Injector внедряет DLL в целевой процесс до инициализации Mono-домена, что позволяет перехватывать ранние вызовы методов или изменять поведение сборок до их загрузки. Этот метод эффективен для патчинга статических классов или замены методов, которые вызываются однократно при старте приложения. Однако он требует точного знания адресов функций или сигнатур методов, так как инъекция происходит до полной загрузки управляемой среды. Пример: исправление багов в Unity-играх, где критические ошибки возникают в момент инициализации движка.
Динамическая инъекция выполняется в уже работающий процесс, что даёт доступ к загруженным сборкам и активным объектам. Этот метод полезен для горячего патчинга, отладки или добавления функциональности без перезапуска приложения. Sharp Mono Injector позволяет внедрять код в любой момент, используя Mono API для поиска и модификации методов по имени или токену. Ограничение: динамическая инъекция неэффективна для изменений, требующих перехвата на этапе загрузки, например, модификации статических конструкторов. Рекомендуется для тестирования хотфиксов или временных исправлений в реальном времени.
Выбор метода зависит от задачи. Для постоянных изменений, влияющих на загрузку приложения, используйте статическую инъекцию. Если требуется гибкость или работа с уже запущенным процессом – динамическую. Учтите, что статическая инъекция может вызывать конфликты с античитами или защитами, блокирующими модификацию памяти на старте, тогда как динамическая менее заметна, но ограничена контекстом работающего приложения.
Запуск инжектора и мониторинг процесса внедрения
Перед запуском Sharp Mono Injector убедитесь, что целевой процесс уже запущен и работает в фоновом режиме. Инжектор требует прав администратора для корректной работы с процессами, особенно если цель – приложение с защитой от отладки. Откройте командную строку с повышенными привилегиями и перейдите в директорию с исполняемым файлом инжектора. Базовая команда для внедрения DLL выглядит так: SharpMonoInjector.exe inject -p "ИмяПроцесса" -a "ПутьКDLL" -n "ИмяКласса" -m "ИмяМетода". Имя процесса указывайте без расширения .exe, например, notepad вместо notepad.exe.
После успешного внедрения отслеживайте поведение целевого процесса через диспетчер задач или специализированные утилиты вроде Process Hacker. Обратите внимание на потребление памяти и процессорного времени – резкий скачок может сигнализировать о бесконечном цикле или утечке ресурсов в инжектированном коде. Для детального анализа используйте встроенные в Mono средства отладки: подключитесь к процессу через mono --debugger-agent и установите точки останова в методах вашей DLL.
Если целевой процесс завершается сразу после внедрения, проверьте обработку исключений в инжектируемом коде. Sharp Mono Injector не перехватывает исключения, возникающие в управляемом коде, поэтому добавьте блок try-catch в метод инициализации и логируйте ошибки в файл. Пример минимального кода для отладки:
public static void Init()
{
try
{
File.WriteAllText("inject_log.txt", "Инициализация началась");
// Ваш код здесь
}
catch (Exception ex)
{
File.WriteAllText("inject_error.txt", ex.ToString());
}
}
$process = Start-Process -FilePath "SharpMonoInjector.exe" -ArgumentList "inject -p notepad -a C:\inject.dll -n Loader -m Init -v" -NoNewWindow -PassThru
Start-Sleep -Seconds 5
if (Test-Path "inject_log.txt") {
Write-Host "Внедрение успешно"
} else {
Write-Host "Ошибка внедрения"
$process.Kill()
}
Проверка успешности инъекции и отладка ошибок
После выполнения инъекции первым шагом станет проверка логов Sharp Mono Injector. Откройте файл SMI.log, расположенный в той же директории, что и инжектор. Успешная инъекция сопровождается записью [INFO] Injection successful, за которой следует имя целевого процесса и путь к загруженной сборке. Если лог содержит [ERROR], обратите внимание на код ошибки: 0x80131604 указывает на несовместимость версий .NET, а 0x80131515 – на проблемы с разрешением зависимостей.
Для верификации работы внедренного кода используйте инструменты мониторинга процессов. В Process Hacker или аналогичных утилитах найдите целевой процесс, перейдите на вкладку .NET Assemblies и проверьте наличие вашей сборки в списке загруженных. Если сборка отсутствует, но инжектор не выдал ошибок, вероятно, проблема в методе инициализации. Убедитесь, что класс с методом Init помечен атрибутом [MonoInjectionEntry] и не требует параметров.
Частые ошибки при инъекции связаны с неверной конфигурацией домена приложения. Если целевой процесс использует AppDomain с ограниченными правами, сборка может загружаться, но не выполняться. Решение – принудительная загрузка в основной домен через модификацию параметров инжектора:
- Добавьте флаг
--domain Defaultпри запуске SMI. - В коде сборки используйте
AppDomain.CurrentDomain.Load(byte[])вместо стандартных методов загрузки.
Отладка на уровне кода требует интеграции с отладчиком. Подключите dnSpy или Visual Studio к целевому процессу через Debug → Attach to Process. Установите точку останова в методе Init вашей сборки. Если отладчик не останавливается, проверьте:
- Корректность сигнатуры метода (
public static void Init()). - Наличие всех зависимостей в той же директории, что и сборка.
- Версию .NET Framework – она должна совпадать с версией целевого процесса.
При возникновении ошибок FileNotFoundException или BadImageFormatException используйте утилиту fuslogvw.exe (Assembly Binding Log Viewer) для анализа логов привязки сборок. Включите логирование через fuslogvw.exe → Settings → Log all binds to disk, повторите инъекцию и изучите сгенерированные отчеты. Они укажут, какая именно зависимость не была найдена или оказалась несовместимой.
Если инъекция проходит без ошибок, но функционал не работает, проверьте поток выполнения. Внедренный код может выполняться в фоновом потоке, что приводит к неожиданным результатам. Используйте Thread.CurrentThread.ManagedThreadId для идентификации потока и при необходимости переключитесь на основной через Control.Invoke (для WinForms) или Dispatcher.Invoke (для WPF). Для консольных приложений создайте новый поток с помощью Task.Run и синхронизируйте его с основным.
Работа с внедрённым кодом: вызовы методов и взаимодействие
После успешного внедрения сборки через Sharp Mono Injector критически важно правильно организовать взаимодействие с целевым процессом. Основной инструмент здесь – рефлексия Mono, позволяющая динамически получать доступ к типам, методам и полям. Для начала используйте mono_thread_attach из Mono API, чтобы привязать поток инжектора к домену целевого приложения. Без этого шага вызовы методов могут завершаться сбоями или игнорироваться.
Для вызова статических методов сначала получите указатель на класс через mono_class_from_name, передав имя сборки, пространство имён и имя класса. Например, если целевой метод – GameManager.StartGame() в сборке Assembly-CSharp, код будет выглядеть так: MonoClass* klass = mono_class_from_name(image, "Namespace", "GameManager");. Далее найдите метод с помощью mono_class_get_method_from_name, указав сигнатуру метода для точного сопоставления.
Динамические методы требуют экземпляра объекта. Получите его через вызов конструктора (mono_object_new) или найдите существующий объект в памяти, используя mono_runtime_invoke на методах, возвращающих нужный тип. Пример: MonoObject* instance = mono_runtime_invoke(constructor, nullptr, nullptr, nullptr);. Убедитесь, что объект не уничтожен сборщиком мусора – закрепите его через mono_gchandle_new, если планируете длительное использование.
Передача параметров в методы осуществляется через массив MonoObject*. Для примитивных типов (int, float) используйте mono_value_box, чтобы упаковать значение в объект. Например, передача числа 42 в метод SetHealth(int): void* args[1] = { mono_value_box(domain, mono_get_int32_class(), &value) };. Для строк применяйте mono_string_new, создавая MonoString из UTF-8 строки.
Обработка возвращаемых значений требует приведения типов. Если метод возвращает MonoObject*, используйте mono_object_unbox для распаковки примитивов. Для сложных типов (например, пользовательских классов) работайте с полями через mono_field_get_value и mono_field_set_value. Пример получения значения поля health: int health; mono_field_get_value(instance, field, &health);.
Взаимодействие с Unity-объектами осложняется их привязкой к игровому циклу. Методы, изменяющие состояние сцены (например, Instantiate), должны вызываться в основном потоке. Для этого используйте MonoThread и проверяйте текущий контекст через mono_domain_get(). Асинхронные вызовы могут приводить к крашам или некорректному поведению.
Оптимизируйте частые вызовы, кешируя указатели на классы и методы. Храните их в статических переменных или выделяйте память через VirtualAllocEx в целевом процессе. Это сокращает накладные расходы на рефлексию. Пример кеширования метода: static MonoMethod* cachedMethod = nullptr; if (!cachedMethod) cachedMethod = mono_class_get_method_from_name(klass, "Update", 0);.
Отладка внедрённого кода – отдельная задача. Используйте mono_print_unhandled_exception для логгирования исключений и mono_debug_init для включения отладочных символов. Для трассировки вызовов подключитесь к целевому процессу через dnSpy или ILSpy, предварительно загрузив внедрённую сборку. Избегайте бесконечных циклов в инжектированном коде – они блокируют основной поток и приводят к зависанию приложения.
Удаление инжектированной библиотеки из памяти приложения
Sharp Mono Injector не предоставляет встроенных механизмов для автоматического удаления DLL из памяти целевого процесса. Чтобы корректно выгрузить библиотеку, необходимо реализовать в ней метод OnUnload, который будет вызываться перед завершением работы инжектора. Этот метод должен освобождать все захваченные ресурсы: потоки, хендлы, выделенную память и отменять подписки на события Mono-домена. Пример сигнатуры метода: public static void OnUnload(). Без его реализации библиотека останется загруженной до завершения процесса.
Для принудительной выгрузки используйте функцию FreeLibrary из WinAPI через P/Invoke. Сначала получите базовый адрес загруженной DLL с помощью GetModuleHandle, затем передайте его в FreeLibrary. Однако этот подход сработает только если библиотека не создала дополнительных потоков или не захватила критические ресурсы. В противном случае процесс может завершиться аварийно. Пример кода на C#:
[DllImport("kernel32.dll")]
static extern bool FreeLibrary(IntPtr hModule);
IntPtr moduleHandle = GetModuleHandle("injected.dll");
if (moduleHandle != IntPtr.Zero) FreeLibrary(moduleHandle);
Если библиотека модифицировала статические поля или методы Mono-классов, изменения останутся даже после выгрузки. Чтобы восстановить исходное состояние, сохраняйте оригинальные данные перед инъекцией и восстанавливайте их в OnUnload. Для сложных случаев, например, при подмене методов через mono_class_get_method_from_name, используйте mono_method_get_header и mono_method_header_get_code для резервного копирования IL-кода. Без этого приложение продолжит работать с изменённым поведением.
