Гайд Aimware crack. Объяснение защиты и гайдик на crack

Участник
Статус
Оффлайн
Регистрация
15 Янв 2021
Сообщения
499
Реакции[?]
310
Поинты[?]
100K
Доброго дня, прекрасный и замечательный форум YouGame.biz. Хотел бы предоставить Вам небольшую выдержку о том как работает защита аимвара и какие методы есть, чтобы её побороть.

Принцип защиты
Бинарник чита накрывается собственным протектором, логика которого построена на том, чтобы чит был максимально под одну сессию. То есть проверку исходя из инструкции cpuid, структуры KUSER_SHARED_DATA и мануальных импортов, которые "зашифрованы".

Что касательно проверок через cpuid, то просто я шёл по пути самурая, так как паттерн на них составлять идея говна, то я просто взял поиск по инструкции в x64dbg и проверял, есть ли дальше в коде mov'ы eax, ebx, ecx, edx. В eax регистре передаются параметры для получения строки бренда процессора.
Пример кода:
C++:
00000023B6B81AEE | 66:0F43F2                  | cmovae si,dx                       
00000023B6B81AF2 | 66:F7DA                    | neg dx                             
00000023B6B81AF5 | 0FA2                       | cpuid                                ; вызов инструкции
00000023B6B81AF7 | 41:80D9 AF                 | sbb r9b,AF                         
00000023B6B81AFB | 44:0FBFD6                  | movsx r10d,si                     
00000023B6B81AFF | 41:0F9FC2                  | setg r10b                         
00000023B6B81B03 | 41:89442A 03               | mov dword ptr ds:[r10+rbp+3],eax     ; помещаем результат выполнения инструкции в стек
00000023B6B81B08 | 4F:8D8409 A6048B25         | lea r8,qword ptr ds:[r9+r9+258B04A6]
00000023B6B81B10 | 41:0FB7C2                  | movzx eax,r10w                     
00000023B6B81B14 | 42:895C95 FC               | mov dword ptr ss:[rbp+r10*4-4],ebx   ; и тут
00000023B6B81B19 | 41:C0E1 06                 | shl r9b,6                         
00000023B6B81B1D | 8BDE                       | mov ebx,esi                       
00000023B6B81B1F | 42:894C55 FA               | mov dword ptr ss:[rbp+r10*2-6],ecx   ; и так
00000023B6B81B24 | 42:895415 F7               | mov dword ptr ss:[rbp+r10-9],edx     ; и даже так
Чеки на KUSER_SHARED_DATA. Тут уже всё не так однозначно, так как на поиск данной проверки ушёл месяц, а точнее я просто 3 дня поковырял и забил, а потом в последние 3 дня сабки всё нашёл и отломал. Собственно, стоить упомянуть, что все чеки не лежат открыто. Например вот это:
Код:
00000023B69C4F81 | 43:8B8C19 FF1FE9FF | mov ecx,dword ptr ds:[r9+r11-16E001]
r9+r11-16E001 будет равно 0x7ffe0260, а это указатель на KUSER_SHARED_DATA.NtBuildNumber

И последнее, мануальные импорты, отчасти самая весёлая часть, потому что на все импорты ( рассмотрим их чуть ниже ), есть по несколько CRC-check функций, я не подсчитывал сколько их точно, но много и бороться с ними бесполезно, так как проверки выполнены также как и с KUSER_SHARED_DATA.NtBuildNumber. Вызов импорта выглядит так:

Код:
00000023B66F89B8 | 49:BA E038087F722BF97F     | mov r10,7FF92B727F0838E0                  |
00000023B66F89C2 | 48:C1C8 0E                 | ror rax,E                                 |
00000023B66F89C6 | 4D:85D2                    | test r10,r10                              |
00000023B66F89C9 | 49:81C2 EE7D6E2A           | add r10,2A6E7DEE                          |
00000023B66F89D0 | 49:F7D2                    | not r10                                   |
00000023B66F89D3 | 48:39C0                    | cmp rax,rax                               |
00000023B66F89D6 | 49:81EA EA0FD448           | sub r10,48D40FEA                          |
00000023B66F89DD | 48:05 D1D90401             | add rax,104D9D1                           |
00000023B66F89E3 | 48:2D 0F9CD901             | sub rax,1D99C0F                           |
00000023B66F89E9 | 49:C1CA 02                 | ror r10,2                                 |
00000023B66F89ED | 4D:85D2                    | test r10,r10                              |
00000023B66F89F0 | 48:85C0                    | test rax,rax                              |
00000023B66F89F3 | 48:C1C0 06                 | rol rax,6                                 |
00000023B66F89F7 | 49:81F2 F25A8428           | xor r10,28845AF2                          |
00000023B66F89FE | 48:39C0                    | cmp rax,rax                               |
00000023B66F8A01 | 49:81EA A414B543           | sub r10,43B514A4                          |
00000023B66F8A08 | 49:F7D2                    | not r10                                   |
00000023B66F8A0B | 48:F7D0                    | not rax                                   |
00000023B66F8A0E | 49:C1CA 0E                 | ror r10,E                                 |
00000023B66F8A12 | 48:2D E0D3837C             | sub rax,7C83D3E0                          |
00000023B66F8A18 | 4D:39D2                    | cmp r10,r10                               |
00000023B66F8A1B | 48:85C0                    | test rax,rax                              |
00000023B66F8A1E | 48:C1C0 16                 | rol rax,16                                |
00000023B66F8A22 | 50                         | push rax                                  |
00000023B66F8A23 | 41:FFE2                    | jmp r10                                   |
Кратко разберём логику, присутствует базовая "обфускация" адреса импорта через разные инструкции ror, rol, xor, not, sub, add. А также в некоторых случаях ( как здесь ) на стек пушится другой также обфусцированный return-адрес. В принципе ничего сложного, ищем по паттерну все jmp r10/r11/rax, потом ищем mov на найденный регистр и параллельно сохраняем все операции с ним, для того, чтобы при фиксе импортов пропатчить лишь первый mov r??, 0x????????????????. Сурса фикса импортов не будет, потому что сами можете написать, Zydis & unicorn в руки и погнали. А вот что касается CRC чеков ? Тут всё интереснее, как я и говорил, тут система такая же, как и с проверкой структуры KUSER_SHARED_DATA. Но при этом проверяемый адрес увеличивается на 4 байта, то есть проверяется прям весь код вызова импорта, так что патчить импорты на ранних этапах нелья и как я это обошёл расскажу дальше.

Принцип кряка
Первое что нам нужно, так это задампить бинарник. Для этого я использую связку SSDT хуков в кернеле и EfiGuard для отключения патчгуарда и проверки подписей загружаемых драйверов. Поскольку бинарник записывается через кернел драйвер аимвара, то никакие вызовы NtWriteVirtualMemory не проходят, но они всегда создают поток на точке входа с флагом 6 используя NtCreateThreadEx. Соответственно, в хуке на создание потока проверяем флаг и просто возвращаем SUCCESS, таки образом спуфая старт чита и можем легко его задампить через что угодно.

Далее, парсим импорты по тому алгоритму, который я описал, берём любой импорт, ставим хардварный бряк в дебаггере на доступ к памяти этого импорта и выпадаем на CRC чек. Важная деталь, некоторые CRC-чеки проверяются другими CRC-чеками и запатчить их для наших корыстных целей не прям выйдет, так что лучше поискать другой.

Нашли CRC-чек ? Почти финалочка. Выбираем место где будет ставить int3 бряк и сохраняем инструкции. По хорошему стоит для этого написать либу, которая будет копировать инструкцию, которую патчим, аллокать память, записывать её туда и после выполнения джампить на следующую, но мне впадлу и я просто ручками восстановил код. После установки патча, сохраняем то количество, сколько она выполнилась и чекая, когда данное количество отработало, то восстанавливаем все импорты. Но есть закономерный вопрос, а как до этого фиксить импорты ?

А вот тут вступает в силу VEH, чекая что ExceptionCode == STATUS_ACCESS_VIOLATION и проверка, что Rip равен одному из адресов импортов. Меняем Rip на валидный и всё у нас замечательно.

Остаётся только самое тяжкое, это правильно пропатчить cpuid. По каким-то причинам на них CRC никак не распространяется, что даёт нам возможность спокойной их патчить даже пока чит не полностью проинициализировался. Я все это искал ручками, так как это просто надёжнее, нужно учитывать, что после инструкции cpuid, обязательно мувается информация которую и запросили через eax. Ну вы об этом и так знаете из моих слов выше. Просто патчим их на int3 и обрабатываем eax в VEH хендлере.

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


Пожалуйста, авторизуйтесь для просмотра ссылки.
 
09-29-2022 Thu 18:48:59
Эксперт
Статус
Онлайн
Регистрация
28 Ноя 2019
Сообщения
1,225
Реакции[?]
413
Поинты[?]
110K
Пользователь
Статус
Оффлайн
Регистрация
25 Мар 2021
Сообщения
186
Реакции[?]
73
Поинты[?]
31K
кто читает тот умрет
Участник
Статус
Оффлайн
Регистрация
29 Июл 2019
Сообщения
698
Реакции[?]
542
Поинты[?]
155K
пиздец и это все? я слышал что в ав всегда защита была так себе, но чет пацаны походу пару модулей ваще нахуй вырезали
 
Участник
Статус
Оффлайн
Регистрация
15 Янв 2021
Сообщения
499
Реакции[?]
310
Поинты[?]
100K
пиздец и это все? я слышал что в ав всегда защита была так себе, но чет пацаны походу пару модулей ваще нахуй вырезали
Основную сложность доставляет дамп самого модуля наверное, так как без кернеля никуда всё таки. Ну и раньше, протект был ещё легче и завязан только на мануальных импортах и cpuid которые расшифровались по мере выполнения кода по типу такого xor dword ptr [0x2018203266], 0x1744DEFA. И то составляешь паттерны на все эти xor'ы, эмулируешь, чекаешь что там cpuid и всё патчишь тупо nop'ами.

Да и если бы не трассировка на несколько миллионов инструкций я бы не нашёл это обращение к KUSER_SHARED_DATA, а она и вызвала основные проблемы.
 
Тьомчик
Участник
Статус
Оффлайн
Регистрация
30 Июн 2020
Сообщения
751
Реакции[?]
153
Поинты[?]
61K
знатоки, напишите мне аимвар берёт логи с каждого инжекта и отправляет их на сервер? Потому что мне отьебал мою купленную ЛТ учётку когда я делал луашку для себя
 
Новичок
Статус
Оффлайн
Регистрация
21 Окт 2024
Сообщения
2
Реакции[?]
1
Поинты[?]
1K
Основную сложность доставляет дамп самого модуля наверное, так как без кернеля никуда всё таки. Ну и раньше, протект был ещё легче и завязан только на мануальных импортах и cpuid которые расшифровались по мере выполнения кода по типу такого xor dword ptr [0x2018203266], 0x1744DEFA. И то составляешь паттерны на все эти xor'ы, эмулируешь, чекаешь что там cpuid и всё патчишь тупо nop'ами.

Да и если бы не трассировка на несколько миллионов инструкций я бы не нашёл это обращение к KUSER_SHARED_DATA, а она и вызвала основные проблемы.
Так чтобы аимвар сдампить, кернел не нужен... Дамп является самой лёгкой частью по факту
 
Начинающий
Статус
Оффлайн
Регистрация
5 Дек 2024
Сообщения
5
Реакции[?]
5
Поинты[?]
5K
Основную сложность доставляет дамп самого модуля наверное, так как без кернеля никуда всё таки. Ну и раньше, протект был ещё легче и завязан только на мануальных импортах и cpuid которые расшифровались по мере выполнения кода по типу такого xor dword ptr [0x2018203266], 0x1744DEFA. И то составляешь паттерны на все эти xor'ы, эмулируешь, чекаешь что там cpuid и всё патчишь тупо nop'ами.

Да и если бы не трассировка на несколько миллионов инструкций я бы не нашёл это обращение к KUSER_SHARED_DATA, а она и вызвала основные проблемы.
Чтобы сдампить аимвар, кернел не обязателен.
 
Участник
Статус
Оффлайн
Регистрация
15 Янв 2021
Сообщения
499
Реакции[?]
310
Поинты[?]
100K
Чтобы сдампить аимвар, кернел не обязателен.
До вызова энтрипоинта или после ?) То что можно и так сдампить это понятно, а вот как это делать до вызова оепа. Кернел как самый легкий и логичный вариант виднеется.
знатоки, напишите мне аимвар берёт логи с каждого инжекта и отправляет их на сервер?
С лоадера разве что, внутри чита никаких конектов никуда нет.
 
Начинающий
Статус
Оффлайн
Регистрация
5 Дек 2024
Сообщения
5
Реакции[?]
5
Поинты[?]
5K
пиздец и это все? я слышал что в ав всегда защита была так себе, но чет пацаны походу пару модулей ваще нахуй вырезали
В аимваре до этого секур был хуже в 3 раза где-то, но автор почему-то не написал про интересный момент, а конкретно о том, как строится архитектура текущего секура. Вероятно он просто сдампил один раз и этот дамп и завел и поскольку больше не инжектил, попросту не заметил рофляна
До вызова энтрипоинта или после ?) То что можно и так сдампить это понятно, а вот как это делать до вызова оепа. Кернел как самый легкий и логичный вариант виднеется.
Ты можешь сдампить до энтрипоинта спокойно и с юзермода (возможно ты боялся словить бан и поэтому не экспериментировал)
Кернел как самый легкий и логичный вариант виднеется.
Ну кому как собственно, но я бы не сказал, что прям самый легкий, учитывая, что можно легче
 
Участник
Статус
Оффлайн
Регистрация
15 Янв 2021
Сообщения
499
Реакции[?]
310
Поинты[?]
100K
В аимваре до этого секур был хуже в 3 раза где-то, но автор почему-то не написал про интересный момент, а конкретно о том, как строится архитектура текущего секура. Вероятно он просто сдампил один раз и этот дамп и завел и поскольку больше не инжектил, попросту не заметил рофляна

Ты можешь сдампить до энтрипоинта спокойно и с юзермода (возможно ты боялся словить бан и поэтому не экспериментировал)
Ну у меня давным давно есть кернел дампер и потому не пытался иначе делать, так как, как минимум небезопасно. Софт отламывал и дампил я каждый апдейт игры начиная с сентября и заканчивая ноябрём. Что там за интересный секур ещё ? Помимо постоянного накрывания бинаря протектором на сервере ничего не заметил.
 
Начинающий
Статус
Оффлайн
Регистрация
5 Дек 2024
Сообщения
5
Реакции[?]
5
Поинты[?]
5K
Помимо постоянного накрывания бинаря протектором на сервере ничего не заметил.
Ну да, я как раз о том, что там для каждого инжекта ревирт делается
Ну у меня давным давно есть кернел дампер и потому не пытался иначе делать, так как, как минимум небезопасно. Софт отламывал и дампил я каждый апдейт игры начиная с сентября и заканчивая ноябрём. Что там за интересный секур ещё ? Помимо постоянного накрывания бинаря протектором на сервере ничего не заметил.
Вообще не понятен смысл от кернела в самом аимваре и зачем они такой убогий метод используют для вызова энтрипоинта, ибо это буквально тоже самое, что если бы они этот поток с юзермода делали, абсолютно разницы нет никакой 🤔
 
Сверху Снизу