ASI

Материал из Неолурк, народный Lurkmore
Перейти к навигации Перейти к поиску

ASI (Аси, асишник, асай, в девичестве — обычная динамическая библиотека Dynamic Link Library, которой хитрые задроты поменяли расширение) — абсолютное и ультимативное оружие мододела, инструмент для брутального изнасилования памяти игровых процессов, а также главный источник крашей, багов, краж паролей и бесконечных драм на форумах. Если ты думаешь, что моддинг — это замена текстурки Сиджея на скин Человека-Паука, то ты безнадежно отстал от жизни. Настоящий моддинг начинается там, где в ход идут дизассемблер, отладчик, поиск смещений в оперативной памяти и инъекции вредоносного (или не очень) кода прямо в нежные внутренности игрового движка.

С появлением ASI-лоадеров жизнь школьников и суровых реверс-инженеров разделилась на до и после.

История болезни[править]

Когда-то давно, в эпоху динозавров и модемов со скоростью 56 кбит/с, мододелы были ограничены тем, что разработчики милостиво оставили лежать в открытом виде.

Каменный век[править]

В GTA 3 и Vice City все сводилось к банальному редактированию текстовых файлов типа handling.cfg (где можно было сделать так, чтобы танк летал) или замене файлов моделей в архивах gta3.img. Затем появились первые инструменты для компиляции скриптов. Люди начали ковырять main.scm, пытаясь заставить игру спавнить машины по нажатию кнопки. Но это был сущий ад. Чтобы добавить 1 новую миссию, приходилось перекомпилировать весь сюжетный файл, начинать новую игру и молиться, чтобы оно не упало с ошибкой.

Эпоха CLEO[править]

Потом пришел великий Seemann и принес миру CLEO. Это был прорыв. CLEO позволял писать скрипты отдельными файлами (с расширением *.cs), которые игра подгружала на лету. Школота ликовала: теперь можно было скачать скрипт на бессмертие, скрипт на вызов шлюх и скрипт на падение метеорита, закинуть их в папку и радоваться жизни.

Но у CLEO был 1 фатальный недостаток. Он работал в рамках виртуальной машины игрового движка. Скриптер мог использовать только те команды (опкоды), которые были заложены в игру. Хочешь нарисовать свое меню поверх экрана? Страдай. Хочешь перехватить нажатие клавиши до того, как игра его обработает? Соси лапу. Хочешь работать с сетью и отправлять HTTP-запросы? CLEO показывал тебе средний палец (пока для него не написали плагины расширения, но это уже другая история).

Рождение ASI[править]

И вот тогда суровые бородатые кодеры, знающие C++, сказали: Да пошло оно все в жопу, мы будем лезть в память напрямую!. Так появилась концепция ASI-плагинов. Изначально поддержка файлов *.asi была встроена в звуковой движок Miles Sound System, который использовался в GTA Vice City. Моддеры просто писали свои DLL, переименовывали их в ASI, и игра покорно их грузила.

Но в GTA San Andreas, GTA 4 и других играх этой фичи не было. И тут на сцену выходят ASI Loaders — гениальные в своей простоте хаки, которые заставляют игру жрать чужой код.

Анатомия ASI Loader’а[править]

Как заставить закрытую проприетарную программу (игру) загрузить твой код? Использовать уязвимость архитектуры Windows, известную как DLL Search Order Hijacking (перехват порядка поиска DLL).

Обман винды[править]

Когда ты кликаешь по gta_sa.exe, операционная система смотрит в заголовок файла (PE-заголовок) и видит: Ага, этой программе для работы нужны системные библиотеки d3d9.dll, dinput8.dll, dsound.dll и еще десяток других. Винда начинает искать эти файлы. И по правилам Microsoft, первым делом она ищет их в той же папке, где лежит сам EXE-файл. И только если не находит, лезет в системную папку C:\Windows\System32.

Этим и воспользовались создатели лоадеров (такие как ThirteenAG, Alexander Blade, JernejL).

  1. Моддер пишет свою библиотеку и называет ее, например, dinput8.dll (библиотека DirectInput для работы с клавиатурой и мышью).
  2. Игрок кидает этот фейковый файл в папку с игрой.
  3. Игра запускается, просит у винды dinput8.dll, винда находит фейковый файл в папке с игрой и радостно скармливает его процессу.
  4. Фейковый dinput8.dll получает управление. Чтобы игра не упала с ошибкой (ведь ей нужен настоящий DirectInput), лоадер подгружает оригинальный файл из System32 и проксирует (перенаправляет) все вызовы к нему.
  5. А параллельно лоадер сканирует папку игры в поисках всех файлов с расширением *.asi.
  6. Найдя ASI-файл, лоадер вызывает виндовую функцию LoadLibrary, внедряя плагин в адресное пространство игры.
  7. ПРОФИТ! Плагин внутри.

В Mass Effect 1, 2 и 3, а также в Legendary Edition, лоадеры работают по тому же принципу, но маскируются под binkw32.dll или bink2w64.dll — кодек для воспроизведения видеороликов Bink Video.

Что внутри ASI-плагина?[править]

Сам по себе ASI-файл — это стандартная динамическая библиотека. Ее точка входа — функция DllMain. Когда лоадер инжектит плагин, винда вызывает эту функцию с параметром DLL_PROCESS_ATTACH.

BOOL APIENTRY DLLMAIN(HMODULE HMODULE, DWORD UL_REASON_FOR_CALL, LPVOID LPRESERVED) {
    SWITCH (UL_REASON_FOR_CALL) {
        CASE DLL_PROCESS_ATTACH:
            DISABLETHREADLIBRARYCALLS(HMODULE);
            // ТУТ НАЧИНАЕТСЯ ЛЮТЫЙ ПИЗДЕЦ
            CREATE_MY_AWESOME_HOOKS();
            BREAK;
        CASE DLL_PROCESS_DETACH:
            // ТУТ МЫ ПЫТАЕМСЯ УБРАТЬ ЗА СОБОЙ, НО ИГРА ВСЕ РАВНО КРАШИТСЯ
            BREAK;
    }
    RETURN TRUE;
}

В этот момент игра еще только начинает просыпаться. Многие ее внутренние структуры еще не созданы. Поэтому грамотный кодер не лезет сразу менять гравитацию или спавнить объекты. Он ставит хуки.

Как поиметь память[править]

Хук (крюк) — это перехват потока выполнения программы. Это основа основ ASI-моддинга. Если ты не умеешь ставить хуки, тебя засмеют на любом профильном форуме.

Адресация и смещения[править]

Чтобы поставить хук, нужно знать, куда его ставить. Для этого игра вскрывается в дизассемблере (IDA Pro или Ghidra). Кодер ищет нужную функцию. Например, функцию, которая отнимает здоровье у игрока при падении. В IDA Pro он видит, что эта функция находится по адресу 0x56E210 (в версии GTA SA 1.0 US, которая стала священной коровой и стандартом для всех моддеров, так как на других версиях адреса смещены, и моды не работают).

Но есть проблема. Просто так писать в память нельзя. Винда защищает секцию кода (секцию .text) флагом PAGE_EXECUTE_READ. То есть код можно исполнять и читать, но изменять нельзя. Попытка записать туда хотя бы 1 байт приведет к ошибке нарушения прав доступа (Access Violation) и крашу игры. Поэтому перед установкой хука мододел вызывает виндовую функцию VirtualProtect, меняя права доступа на PAGE_EXECUTE_READWRITE.

DWORD OLDPROT;
VIRTUALPROTECT(REINTERPRET_CAST<VOID*>(0x56E210), 5, PAGE_EXECUTE_READWRITE, &OLDPROT);
// ТЕПЕРЬ МОЖНО ПИСАТЬ В ПАМЯТЬ

Call Hook (Подмена вызова)[править]

Самый простой способ. Допустим, функция обновления логики машины (CVehicle::ProcessControl) вызывает функцию расчета урона. В ассемблере это выглядит так:

CALL 0x6A42F0

Эта инструкция занимает 5 байт. 1 байт — это сам опкод E8 (что значит CALL), а 4 байта — это относительный адрес (оффсет) целевой функции. Моддер затирает эти 4 байта и вписывает туда смещение до своей собственной функции, написанной в плагине. Как посчитать это смещение? Любой ньюфаг ломает об это зубы, но формула проста:

RELATIVE_ADDRESS = (ADDRESS_OF_YOUR_FUNCTION) - (ADDRESS_OF_ORIGINAL_CALL_INSTRUCTION) - 5;

Почему минус 5? Потому что процессор (x86) отсчитывает относительный прыжок от адреса следующей инструкции, а текущая инструкция CALL занимает ровно 5 байт.

Теперь, когда игра пытается рассчитать урон, она вызывает функцию из ASI-плагина. В этой функции кодер пишет:

VOID __CDECL MY_CUSTOM_DAMAGE_FUNCTION(VOID* PVEHICLE, FLOAT DAMAGE) {
    IF (DAMAGE > 100.0F) {
        DAMAGE = 0.0F; // ЕСЛИ УРОН БОЛЬШЕ 100, МАШИНА СТАНОВИТСЯ НЕУЯЗВИМОЙ
    }
    // ВЫЗЫВАЕМ ОРИГИНАЛЬНУЮ ФУНКЦИЮ, ЧТОБЫ ИГРА ПРОДОЛЖИЛА РАБОТУ
    ORIGINAL_DAMAGE_FUNCTION(PVEHICLE, DAMAGE);
}

JMP Hook (Трамплины и Сплайсинг)[править]

Но что делать, если функцию вызывают из 1000 разных мест? Искать и подменять каждый CALL? Нет, это путь идиота. Тру-хакеры ставят хук в самом начале (прологе) целевой функции.

Принцип работы:

  1. Взять первые 5 байт оригинальной функции.
  2. Скопировать их в специально выделенный кусок памяти (это называется Трамплин).
  3. После этих 5 байт в трамплине дописать инструкцию JMP (безусловный прыжок), которая возвращает процессор обратно в оригинальную функцию, на 6-й байт.
  4. В самой оригинальной функции заменить первые 5 байт на инструкцию JMP, ведущую в функцию ASI-плагина.

Что получается? Игра вызывает свою родную функцию. Но на самом первом байте процессор натыкается на наш JMP и улетает в код плагина. Плагин делает свои дела (например, выводит матерное сообщение на экран). Затем плагин прыгает в Трамплин. В трамплине выполняются те самые украденные первые 5 байт оригинальной функции, после чего процессор прыгает обратно в оригинал, продолжая выполнение как ни в чем не бывало.

Это звучит просто в теории. На практике это сущий ад. А что, если первые инструкции оригинальной функции занимают не 5 байт, а 6? Процессор архитектуры x86 имеет инструкции переменной длины. Одна инструкция может занимать 1 байт, другая — 7 байт. Если ты тупо затрешь 5 байт, ты можешь разрезать пополам 6-байтовую инструкцию. Когда процессор попытается выполнить этот огрызок, он не поймет, что это за команда, и игра рухнет. Поэтому кодерам приходится использовать дизассемблеры длин (Length Disassemblers, например, HDE — Hacker Disassembler Engine), чтобы точно высчитать, сколько целых инструкций нужно скопировать (обычно 5, 6 или 7 байт), а оставшийся мусор забить инструкциями NOP (опкод 90).

VTable Hook (Удел элиты)[править]

Для игр, написанных с активным использованием объектно-ориентированного C++ (например, DirectX, который используется для графики), применяется подмена виртуальных таблиц. Каждый класс с виртуальными методами имеет указатель (vptr) на таблицу адресов этих методов (VTable). Это просто массив в памяти. Если ты хочешь перехватить функцию Present в DirectX 9 (которая отвечает за вывод готового кадра на монитор), тебе не нужно ковырять ассемблер и ставить JMP. Тебе нужно:

  1. Найти указатель на объект IDirect3DDevice9.
  2. Прочитать из него адрес VTable.
  3. Найти в этом массиве 17-й элемент (именно там лежит адрес оригинальной функции Present).
  4. Записать туда адрес своей функции.

Всё! Теперь каждый кадр DirectX будет вызывать твой код. Именно здесь ASI-плагины рисуют читерские менюшки, ESP (Wallhack), радары и прочий визуальный мусор.

Конвенции вызовов (Calling Conventions)[править]

Если ты думаешь, что поставить хук — это самое сложное, то ты глубоко заблуждаешься. Самое смешное начинается, когда ты пытаешься объявить свою функцию в C++, чтобы она совпала по параметрам с оригинальной игрой.

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

  • __cdecl (C Declaration) — параметры кладутся в стек (память) справа налево. После выполнения функции тот, кто ее вызывал, должен сам очистить стек (сдвинуть указатель ESP). Это стандарт для C++.
  • __stdcall (Standard Call) — параметры кладутся в стек так же, но функция сама обязана очистить стек перед выходом (инструкция RET N). Используется в API Windows (WinAPI) и DirectX.
  • __thiscall — конвенция для методов классов (Object-Oriented). Указатель на сам объект (this) передается через регистр процессора ECX. Остальные параметры — через стек. Функция сама чистит стек.

И вот юный кулхацкер решает перехватить метод класса CVehicle::SetEngineState. В оригинале это __thiscall. Школьник открывает Visual Studio, пишет:

VOID __THISCALL HOOK_SETENGINESTATE(VOID* PVEHICLE, BOOL BSTATE) {
    // КОД
}

И компилятор посылает его нахрен, выдавая ошибку: __thiscall можно использовать только для нестатических методов класса! Компиляторы от Microsoft (MSVC) запрещают вешать __thiscall на обычные глобальные функции, которые мы используем в плагинах.

Что делать? Приходится использовать грязный, вонючий костыль — конвенцию __fastcall. __fastcall передает первые 2 параметра не через стек, а через регистры ECX и EDX. Мододел объявляет свою функцию так:

VOID __FASTCALL HOOK_SETENGINESTATE(VOID* PVEHICLE, VOID* EDX_DUMMY, BOOL BSTATE) {
    // PVEHICLE ПОПАДАЕТ В ECX (КАК УКАЗАТЕЛЬ THIS)
    // EDX_DUMMY - ЭТО ЗАГЛУШКА ДЛЯ РЕГИСТРА EDX, ОНА НАМ НАХУЙ НЕ НУЖНА
    // BSTATE БЕРЕТСЯ ИЗ СТЕКА
    IF (BSTATE) {
        PRINT_MESSAGE("ДВИГАТЕЛЬ ЗАВЕДЕН!");
    }
}

Это отвратительно, это ломает логику красивого кода, но это РАБОТАЕТ. Весь форум BlastHack забит темами, где новички плачут кровавыми слезами, потому что забыли добавить фейковый параметр VOID* EDX, и их игра крашится из-за поломки стека.

Срачи[править]

Вокруг разработки ASI сформировалась своя субкультура. Центром русскоязычного моддинга/читоделия для GTA (в основном SAMP) стал форум BlastHack. Место, где ЧСВ обитателей пробивает стратосферу, а новичка за вопрос как скомпилировать плагин могут обосрать так, что ему захочется удалить Windows и уйти в монастырь.

Драма вокруг samp.asi[править]

В свое время на форумах появилась куча тем с криками: ААА! Что за файл samp.asi в моей папке? Это стиллер! У меня спиздили аккаунт на Аризоне с 10 миллионами виртов!.

Дело в том, что ASI-плагины, имея доступ к памяти и системным функциям ОС (WinAPI), могут делать абсолютно всё. Если CLEO-скрипт должен использовать сторонние библиотеки для выхода в интернет, то ASI-плагин написан на чистом C/C++. Подключил библиотеку Wininet.dll или curl — и вуаля! Твой полезный фикс камеры или FPS Unlocker при запуске игры тихо читает файл конфигурации SAMP, выцепляет твой ник и IP сервера, затем ставит хук на функцию отправки RPC-пакета с вводом пароля в диалоговое окно (DIALOG_STYLE_PASSWORD). Как только ты вводишь свой пароль, плагин отправляет его HTTP POST-запросом на левый сервер злоумышленника в Зажопинске.

Типичный диалог на форуме:

ПОЛЬЗОВАТЕЛЬ_1: РЕБЯТА, Я СКАЧАЛ МОД НА НОВЫЕ ТЕКСТУРЫ ДОРОГ С ГРУППЫ В ВК, А ВНУТРИ БЫЛ ФАЙЛ SAMP.ASI. ЭТО СТИЛЛЕР? 
МОДЕРАТОР: SAMP.ASI ЭТО ВООБЩЕ БЛЯТЬ ПЛАГИН КОТОРЫЙ СОХРАНЯЕТ ПОСЛЕДНИЕ ОТВЕТЫ НА ДИАЛОГ И ЛИСТАЙТЕМ ДИАЛОГА. БОЛЬШЕ ПОЛУГОДА С НИМ ИГРАЛ, НИЧЕ НЕ СПИЗДИЛИ.
ЭКСПЕРТ_ПО_РЕВЕРСУ: Я ДИЗАССЕМБЛИРОВАЛ ЭТОТ ВАШ SAMP.ASI В IDA PRO. ТАМ ВЫЗОВЫ ФУНКЦИЙ GETHOSTBYNAME И INTERNETCONNECT. ЭТО 100% СТИЛЛЕР, ТЫ ДАЛБАЕБ И ТВОЙ АККАУНТ УЖЕ ПРОДАЮТ НА SAMPCALL.

Чтобы защититься от этого, игроки параноидально проверяют каждый ASI-файл на VirusTotal, качают программы типа AVP Game Protect и мониторят трафик через Wireshark. Но хитрожопые кодеры начали шифровать (криптовать) свои ASI-плагины протекторами (типа VMProtect или Themida), превращая код в нечитаемую кашу. Оправдание всегда одно: Я закриптовал свой FPS Unlocker, чтобы злые хакеры не украли мой уникальный код, состоящий из 10 строк!. На деле же внутри 99 % спрятан троян.

ImGui[править]

Если в 2012 году крутым читом считался тот, который выводил текст через родные функции GTA (CFont), то сегодня стандарт индустрии — это Dear ImGui. Это библиотека для создания графических интерфейсов, которая рисует все сама через DirectX или OpenGL.

Чтобы прикрутить ImGui в свой ASI-плагин, кодеру нужно пройти через 9 кругов ада:

  1. Найти устройство DirectX (IDirect3DDevice9).
  2. Хукнуть функцию Present (вывод кадра) и Reset (сброс устройства при сворачивании игры). Если не хукнуть Reset и не освободить текстуры шрифтов ImGui перед сворачиванием альт-табом, игра намертво зависнет с белым экраном.
  3. Хукнуть обработчик оконных сообщений винды — WndProc. Игра получает от винды сообщения о нажатиях клавиш мыши (WM_LBUTTONDOWN) и клавиатуры (WM_KEYDOWN). Если не передать эти сообщения в ImGui, твое красивое меню не будет реагировать на клики.
  4. Сделать проверку: если курсор находится над окном ImGui, нужно блокировать передачу кликов в саму игру. Иначе ты будешь нажимать кнопку Включить Аимбот в меню, а твой персонаж на заднем фоне начнет стрелять из дробовика в прохожих.

Код выглядит примерно так:

HRESULT __STDCALL ON_PRESENT(IDIRECT3DDEVICE9* DEVICE_PTR, CONST RECT* PSOURCERECT, CONST RECT* PDESTRECT, HWND HDESTWINDOWOVERRIDE, CONST RGNDATA* PDIRTYREGION) {
    IF (!IMGUI_INITED) {
        IMGUI::CREATECONTEXT();
        IMGUI_IMPLWIN32_INIT(GAME_HWND);
        IMGUI_IMPLDX9_INIT(DEVICE_PTR);
        IMGUI_INITED = TRUE;
    }

    IMGUI_IMPLDX9_NEWFRAME();
    IMGUI_IMPLWIN32_NEWFRAME();
    IMGUI::NEWFRAME();

    IMGUI::BEGIN("ULTIMATE MEGA CHEAT ASI BY VASYAPRO2010");
    IF (IMGUI::BUTTON("GIVE MONEY")) {
        // ДОБАВЛЯЕМ 10000 ДОЛЛАРОВ
        *REINTERPRET_CAST<INT*>(0xB7CE50) += 10000; 
    }
    IMGUI::END();

    IMGUI::ENDFRAME();
    IMGUI::RENDER();
    IMGUI_IMPLDX9_RENDERDRAWDATA(IMGUI::GETDRAWDATA());

    RETURN ORIGINAL_PRESENT(DEVICE_PTR, PSOURCERECT, PDESTRECT, HDESTWINDOWOVERRIDE, PDIRTYREGION);
}

И вот ты написал это. Скомпилировал в Visual Studio. Получил файл MyAwesomeCheat.asi. Закинул в игру. И… краш по адресу 0x00000000. Почему? Потому что ты забыл обновить сигнатуры для новой версии SAMP 0.3.7 R3, и игра попыталась обратиться по нулевому указателю. Садись, два (то есть 2).

Экспансия[править]

Если ты думаешь, что ASI — это локальная забава дегенератов из SAMP, то посмотри на другие игры. Технология инжекта DLL с переименованным расширением оказалась настолько универсальной, что ее пихают везде.

Mass Effect[править]

В серии Mass Effect (особенно с выходом Legendary Edition) моддинг расцвел пышным цветом благодаря инструментам вроде ME3Tweaks Mod Manager. Поскольку игры сделаны на движке Unreal Engine 3, архитектура там совершенно другая, но принцип хуков остается неизменным.

ASI-плагины для Mass Effect маскируются под binkw32.dll или bink2w64.dll. Зачем они там нужны? Разве недостаточно редактировать конфиги (Coalesced.bin)? Оказывается, недостаточно. Например:

  • DLC Mod Enabler (ME1): В оригинальной игре код проверки DLC был захардкожен. ASI-плагин внедряется в процесс, находит функцию, которая парсит файл AutoLoad.ini, и заставляет движок монтировать фанатские дополнения так, будто их выпустила сама BioWare.
  • Streaming Levels HUD: Плагин, который рисует прямо на экране информацию о загруженных кусках карты (Streaming Levels). Полезно для моддеров, чтобы игра не сожрала все 3.5 гигабайта памяти (так как ME2/ME3 — это 32-битные приложения, ограничение памяти для них фатально) и не упала с криком Out of Memory. Плагин отслеживает выделение памяти и начинает моргать красным, когда процесс близок к самоубийству.
  • Garbage Collection Forcer: Unreal Engine имеет свой сборщик мусора (Garbage Collector), который удаляет из памяти неиспользуемые объекты. Но иногда он тупит. ASI-плагин принудительно вызывает сборку мусора в определенных локациях, чтобы игра не фризила и не крашилась.
  • Function Logger: Адская утилита, которая перехватывает функции виртуальной машины UnrealScript. Каждый вызов логгируется в текстовый файл. Это генерирует гигантский объем записи на диск (настолько жесткий, что SSD начинает плавиться), но позволяет точно отследить, на какой строчке скрипта игра обосралась.

И снова мы видим в логах до боли знакомые термины:

BOOL (WINAPI* GETOVERLOADPATHW)(WCHAR_T* OUT, SIZE_T OUT_SIZE) = NULLPTR;
MODULELIST DLLS;
DLLS.ENUMERATE(MODULELIST::SEARCHLOCATION::LOCALONLY);
FOR (AUTO& E : DLLS.M_MODULELIST) {
    AUTO M = STD::GET<HMODULE>(E);
    IF (ISMODULEUAL(M)) {
        GETOVERLOADPATHW = (DECLTYPE(GETOVERLOADPATHW))GETPROCADDRESS(M, "GETOVERLOADPATHW");
        BREAK;
    }
}

Ultimate ASI Loader (от ThirteenAG) позволяет создавать папки update, чтобы плагин перехватывал обращения игры к файлам и подсовывал модифицированные версии вместо оригинальных. Никакого редактирования архивов! Игра думает, что грузит оригинальную текстуру Шепарда, а лоадер перенаправляет поток чтения на кастомный PNG-файл высокого разрешения из папки мода. Гениально.

UWP игры и Dumper’ы[править]

Microsoft попыталась убить моддинг, внедрив формат UWP (Universal Windows Platform). Игры ставились в скрытые зашифрованные папки, к которым даже администратор не имел доступа. EXE-файлы были обвешаны DRM-защитой. Но хакеры посмеялись. Появился UWPDumper. Инструкция для мамкиных взломщиков:

  1. Запускаешь игру через меню Пуск.
  2. Запускаешь инжектор дамп-утилиты. Вводишь Process ID (PID) игры.
  3. Инжектор внедряется в процесс (пока тот расшифрован в оперативной памяти) и тупо копирует (дампит) всю структуру файлов на диск.
  4. Ты сносишь UWP-версию игры. Берешь сдампленные файлы, удаляешь AppxSignature.xml (чтобы отключить проверку подписи) и регистрируешь манифест заново через PowerShell.
  5. Берешь Ultimate ASI Loader, переименовываешь его в d3d11.dll или dinput8.dll (в зависимости от того, что игра схавает).
  6. Создаешь папочку plugins, кидаешь туда свои ASI-скрипты.
  7. Играешь в UWP версию GTA San Andreas с модами, посылая дядю Билла в пешее эротическое.

Red Dead Redemption 2[править]

Даже на Диком Западе без ASI не обойтись. Lenny's Mod Loader (LML) и ScriptHook для RDR2 — это всё те же яйца, только в профиль. Игроки путаются, куда кидать файлы. На реддите (сабреддит PCRedDead) регулярно возникают темы: Whenever I download mods with both .asi and lml folders, I drag the .asi folder to the main game directory… But the mods don’t show in LML.UI Бедные зумеры не понимают разницы между скриптовым движком (ScriptHook, который грузит ASI-файлы прямо из корня игры) и VFS (Virtual File System, которую использует LML для подмены файлов игры на лету без изменения архивов *.rpf). .ASI моды — это скомпилированные бинарники. Ленни Лоадер их не видит и не должен видеть в своем интерфейсе! Они загружаются автоматически через dinput8.dll. Но объяснить это поколению тиктока невозможно. Они продолжают кидать ASI в папку LML и жаловаться, что мод на AK-47 вместо револьвера не работает.