Как изменить сигнатуру exe файла

В данном руководстве будут описаны методы и техники, которые позволят осуществить обход антивирусной защиты.

В данном руководстве будут описаны методы и техники, которые позволят осуществить обход антивирусной защиты.

Автор: InterNOT Security Team
Перевод: SecurityLab.ru

Глава 1. Вступление

На протяжении последних 10 лет простые антивирусы, использующие для проверки уже существующие сигнатуры угроз, постоянно приобретают новые и все более современные эвристические функции. Большинство антивирусов способно проверять как файлы на локальных дисках, таки и опкоды (opcodes) в памяти.

Опкоды – это команды на языке программирования Ассемблер, используемые на самом нижнем уровне программирования для настройки взаимодействия приложений с ЦП. Приложения, как правило, разрабатываются на языках более высокого уровня, в которых не применяются опкоды, например в C или C++. Компилятор, в свою очередь, переводит высокоуровневый код в опкоды, руководствуясь требуемой архитектурой и пр.

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

В данном руководстве будут описаны методы и техники, которые позволят осуществить обход антивирусной защиты.

Глава 2 Структура PE файлов

Формат файла PE (Portable Executable) используется Windows для обработки бинарных файлов по умолчанию (Рис. 2.1). Стоит отметить, что не все бинарные файлы состоят из 5 секций. Они также могут состоять из 4, 6 или 7 секций, в зависимости от их построения.

Сигнатура, которая  приводит в действие антивирусное приложение, может быть размещена где угодно, однако обычно ее стоит искать в одной из основных секций, а не в заголовках таблиц секций, заголовках DOS и пр.

Рис. 2.1: Структура PE файла

2.1 – Антивирусные сигнатуры и PE формат

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

Иногда сигнатуры находятся очень просто, например, при использовании ncx99.exe. ncx99.exe – это простой netcat listener, привязывающий cmd.exe к 99 порту на внешнем сетевом интерфейсе. На рис. 2.1.1 показана основная сигнатура между смещениями E77E и E78F.

Рис 2.1.1 Просмотр бинарного файла в шестнадцатеричной кодировке

Более того, в данном примере сигнатура обнаружена в секции idata. Это означает, что при попытке шифрования всей секции idata, исполняемый файл, который получиться в результате, может оказаться неработоспособным.

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

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

Рис 2.1.2 – Обзор части списка PE заголовков в Ollydbg

2.2 – Изменение сигнатур антивируса в PE файлах

После вероятного обнаружения сигнатуры в одной из секций, ее можно изменить, либо путем редактирования прямо в hex-редакторе, либо путем изменения опкодов в дисассемблере, а также в некоторых случаях, с помощью отладчика (применимо для Ollydbg).

В случае с ncx99.exe, есть возможность изменения, как слушающего порта, так и программы, которая будет выполняться. Конечно, если заменить его, например на calc.exe, при взломе это не поможет, а вот замена номера порта с 99, например, на 81 может оказаться полезной. Таким образом, можно успешно обойти механизмы обнаружения некоторых антивирусов.

Рис. 2.2.1 – проверка исходного файла ncx99.exe

Рис. 2.2.2 – проверка ncx99.exe с п      ривязкой к 81 порту

Как показано на рис 2.2.2, антивирусы Avast и Ikarus удалось успешно обойти. При атаке компьютеров, которые используют один из этих антивирусов, нам достаточно будет всего лишь изменить один из слушающих портов.

2.3 – Полиморфные техники и взломы

Полиморфные методы

Некоторые полиморфные вирусы имеют одинаковый функционал, но различные опкоды. В этом заключается очередной прием, применяемый опытными хакерами. Например, вместо инструкции PUSH -1, хакер может использовать DEC ESI, PUSH ESI, INC ESI, если регистр ESI равен 0. Если он не равен нулю, злоумышленнику придется сохранить значение ESI путем перемещения его в стек, и обнулить его с помощью оператора XOR (XOR ESI, ESI). Затем его можно использовать для записи в стек вместо PUSH -1.

После этого необходимо восстановить исходное значение ESI, с помощью оператора POP.

Это только один из примеров, большинство антивирусов не считают инструкцию PUSH -1 вредоносной. Но в случае с сигнатурой, являющей собой исполняемый код, нам не обойтись простой заменой данных пустыми командами (NOP), нам придется использовать методы шифрования, или «полиморфные методы».

Взломы

Если мы хотим  зашифровать файл, нам придется зашифровать точку входа бинарного файла, отредактировав заголовки PE, либо заменить первую инструкцию на jump, указывающий на неиспользуемую область данных. В этой области хакер может разместить собственный код, не изменяя при этом размер исходного файла.

Обратим внимание, что некоторые антивирусы проверяют также и размер файлов.

При необходимости можно перезаписать инструкции также и внутри бинарного файла. Если целевая программа полностью сохраняет свою функциональность, не имеет значения, какая именно область файла была изменена.

From https://docs.microsoft.com/en-us/windows/win32/debug/pe-format, emphasis mine:

When included in a certificate, the image digest must exclude certain fields in the PE Image, such as the Checksum and Certificate Table entry in Optional Header Data Directories. This is because the act of adding a Certificate changes these fields and would cause a different hash value to be calculated.

The Win32 ImageGetDigestStream function provides a data stream from a target PE file with which to hash functions. This data stream remains consistent when certificates are added to or removed from a PE file. Based on the parameters that are passed to ImageGetDigestStream, other data from the PE image can be omitted from the hash computation.

The ImageGetDigestStream function is documented at https://docs.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-imagegetdigeststream, which shows that it accepts a bitfield indicating optional file sections to include: the import data, the debug symbols, and the resource section (which is used for things like embedded image files and other large binary blobs). The executable image (code and static data) are always included.

Beyond all of that, there’s some padding between sections of file, and at the end of the file, that is not used in the digest. It’s conventionally zero (NULL) bytes, but can be changed as long as the total file length doesn’t change. I’ve verified that changing the padding at the end, at least, doesn’t invalidate the signature.


Based on that, some (non-exclusive) candidates for explaining the different Firefox downloads (without even looking at actual examples):

  • Unique certificates in the Checksum and Certificate Table, either actually used for code signing or just there to uniquely identify the binary.
  • Resource data that just isn’t included in the signature (I don’t know if there is any; it’s certainly quite common for installers to include lots of resource data but I’d hope it would be signed).
  • Padding, especially padding at the end of the file.

From https://docs.microsoft.com/en-us/windows/win32/debug/pe-format, emphasis mine:

When included in a certificate, the image digest must exclude certain fields in the PE Image, such as the Checksum and Certificate Table entry in Optional Header Data Directories. This is because the act of adding a Certificate changes these fields and would cause a different hash value to be calculated.

The Win32 ImageGetDigestStream function provides a data stream from a target PE file with which to hash functions. This data stream remains consistent when certificates are added to or removed from a PE file. Based on the parameters that are passed to ImageGetDigestStream, other data from the PE image can be omitted from the hash computation.

The ImageGetDigestStream function is documented at https://docs.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-imagegetdigeststream, which shows that it accepts a bitfield indicating optional file sections to include: the import data, the debug symbols, and the resource section (which is used for things like embedded image files and other large binary blobs). The executable image (code and static data) are always included.

Beyond all of that, there’s some padding between sections of file, and at the end of the file, that is not used in the digest. It’s conventionally zero (NULL) bytes, but can be changed as long as the total file length doesn’t change. I’ve verified that changing the padding at the end, at least, doesn’t invalidate the signature.


Based on that, some (non-exclusive) candidates for explaining the different Firefox downloads (without even looking at actual examples):

  • Unique certificates in the Checksum and Certificate Table, either actually used for code signing or just there to uniquely identify the binary.
  • Resource data that just isn’t included in the signature (I don’t know if there is any; it’s certainly quite common for installers to include lots of resource data but I’d hope it would be signed).
  • Padding, especially padding at the end of the file.

  • #1

Здраствуйте, не знаю куда влепить данную тему, вот написал сюда…
Всем известно, что скрипт хранится в EXE файле с сигнатурой AU3! EA06, а существую ли такие способы, которые смогли бы поменять данную сигнатуру на произвольную. Очень нужно для защиты от всяких там декомпиляторов. Протекторы и пакеры тоже не помогают — с дампа файла возможно вытащить нужный скрипт. Заранее извиняюсь, если эта тема поднималась.

CreatoR


  • #2

Ledgous [?]

Всем известно, что скрипт хранится в EXE файле с сигнатурой AU3! EA06, а существую ли такие способы, которые смогли бы поменять данную сигнатуру на произвольную

В Hex-редакторе это можно заменить.

нужно для защиты от всяких там декомпиляторов

А кто сказал что это защитит от них? :smile:

  • #3

В Hex-редакторе это можно заменить.

Любое изменение в HEX-редакторе приводят к неработаспособности скрипта.

А кто сказал что это защитит от них?

Защитит еще как! Давече встречал программу, у которой сигнатура вместо вышеописанной была ‘!*U#AUCN’ . Создать у себя на скрипте подобное не получилось. Может есть подобные программы, о которых я не знал, где вручную можно сменить сигнатуру? Или может я не те значение изменяю в HEX редакторе?

  • #4

До изменений

Не работает

Работает

Только толку от этого ноль… точно не знаю как интерпретатор ищет исходник в exe, но полагаю что именно по этой сигнатуре, если сигнатуру изменить, то интерпретатор выдаст ошибку, так как не смог найти данные которые нужно выполнить.

Добавлено:

Сообщение автоматически объединено: 4 Июл 2013


Удалось сменить сигнатуру

До

После

Но от декомпилятора не спасает. :whistle:

  • #5

В файле 2 сигнатуры — одну можно менять на что угодно, вторую нет.

CreatoR


  • #6

sngr [?]

В файле 2 сигнатуры — одну можно менять на что угодно, вторую нет.

EA06 встречается 3 раза, если это заменить на одно и то же (не трогая AU3!), то скрипт будет работать, но как я уже сказал, это никак не защитит скрипт от декомпиляции.

  • #7

sngr [?]

В файле 2 сигнатуры — одну можно менять на что угодно, вторую нет.

Сменить можно обе с помощью отладчика. А ко всему прочему это еще и защитит от декомпиляции, которая действует в процессе.

До: AU3!EA06
После: DEADCODE
И при этом во всех местах, которые используются по умолчанию, стоит: AU3! и EA06

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

3uQZJ.png

  • #8

firex

OffTopic:

Хотелось бы в итоге увидеть готовую программу для защиты скриптов от декомпиляции :smile:

  • #9

_Lexa98_

3uXid.png

— первое обращение, осуществляет поиск.

3uXjX.png

— второе обращение, обработка по типу (EA06).
Я вообще не понимаю как Viktor1703’у удалось сменить так просто через HEX редактор. Эта константа хранится в одном месте, и если ее сменить — поиск по новой будет работать, но скрипт не будет знать как обрабатывать оверлей. Ему ведь не известен тип отличный от EA06.

Самый надежный вариант — использовать компрессию не EA06, сменить обращения (записать для них данные в других местах). И кстати в секции импорта достаточно для этого места (порядка пары килобайт).

У себя я изменил подход к поиску скрипта в оверлее, тип, а также … это уже знать не обязательно <3
Автоматизированную программу для этого писать не стану, так как почти все действия нужно делать вручную :C

  • #10

firex

Очень просто, AU3!EA06 пишется вначале и в конце исходного кода (и как уже сказал Creator, EA06 встречается 3 раза тоже самое касается и AU3), если их заменить, то exe выдаст ошибку, по этому мотаем скрол вверх в hex редакторе и ищем AU3 и отдельно EA06, как я и полагал, интерпретатор принимает данные на запуск только в том случае если сигнатура равна паттерну, при декомпиляции такого exe, декомпилятор выдаёт сообщение типа сигнатура не найдена, далее спрашивает, уверены ли мы что это AutoIt’овский exe, далее декомпиль делает свою работу без всяких затруднений, на практике проверенно что если сменить сигнатуру и не только её, то от декомпиляции не спасёт, учите компилируемые языки либо оставьте вечные вопросы о защите.

  • #11

Viktor1703 [?]

на практике проверенно что если сменить сигнатуру и не только её, то от декомпиляции не спасёт, учите компилируемые языки либо оставьте вечные вопросы о защите.

Это я как раз таки понимаю. Лишние несколько дописанных строк — и данные в оверлее не примутся декомпилятором. Сделать можно все, начиная с банальной замены пары важных байт, которые исполняемый файл будет сам знать, либо переписать(хотя скорее поправить)(как это сделал я) чтение скрипта с оверлея.
Есть два варианта развития событий:
1)Оставить неизменными константы(AU3! и EA06), которые читает интерпретатор и декомпилятор, и использовать свои, которые записаны совершенно в другом месте. Банальным HEX редатором тут конечно же не обойтись, ну а чего вы хотели. И на финал пошутить с оверлеем, влить в конец левый или просто написать бреда.

2) Действовать принципу 1, только переписать(дописать) функцию 4152A0.

учите компилируемые языки либо оставьте вечные вопросы о защите.

Те вещи, что я делаю на AutoIt, писать к примеру на дельфи или того хуже на Visual c++ — в сотню раз дольше.

Добавлено:

Сообщение автоматически объединено: 4 Июл 2013


Сделал для вас пример на скорую руку. Ничего сверхъестественного делать не стал, банальное сохранение констант и только.

http://autoit-script.ru/index.php?action=downloads;sa=view;down=350

  • #12

firex [?]

Те вещи, что я делаю на AutoIt, писать к примеру на дельфи или того хуже на Visual c++ — в сотню раз дольше.

Для примера PureBasic — не сложнее AutoIt’a.

Оставить неизменными константы(AU3! и EA06), которые читает интерпретатор и декомпилятор, и использовать свои, которые записаны совершенно в другом месте.

Для чего?

И на финал пошутить с оверлеем, влить в конец левый или просто написать бреда.

И ещё раз, для чего?

Вообще выходной exe файл который получается при компиляции, построен не правильно, если взять любой другой exe, его спокойно можно открыть в том же 7-Zip, а вот AutoIt’овские exe не получится, я бы сделал иначе, я бы не дописывал исходник в конец exe, а создавал бы новую секцию в интерпретаторе например ‘.au3’ и записывал в неё код, AutoIt’овским exe даже релокации не нужны, он не ищет исходник по адресу, для теста я удалил 22 нуливых байта из exe (мне даже не пришлось делать релокацию), а он остался рабочим и вес его уменьшился ровно на столько — сколько я удалил, а пустого места (нулевых байт) там много…

Добавлено:

Сообщение автоматически объединено: 4 Июл 2013


firex [?]

Сделал для вас пример на скорую руку. Ничего сверхъестественного делать не стал, банальное сохранение констант и только.

Ваш код?

MSGBOX(64, 1 * 1, "Original code")

  • #13

Viktor1703 [?]

Если честно порядком удивлен. Имею при себе вроде как все рабочие декомпиляторы — ни один не справляется и с этим.

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

  • #14

Ledgous
Это — бесполезно.
Достаточно в отладчике глянуть — и все.
Все равно на каком ЯП. Не так ли?

  • #15

firex

При декомпиляции ни чего не поможет, хотите чтоб ваш exe не смогли декомпилировать, переписывайте сам интерпретатор (если конечно найдёте его исходные коды), ещё вот такая проблема есть, AutoIt’овские exe не способны запустится из памяти, писал на PureBasic типа Builder’a для упаковки AutoIt’овских exe, работает он так, при создании исполняющего файла, Builder добавляет в Stub новую секцию типа ‘.pack’, и записывает в него исполняющий AutoIt файл, пр запуске такого исполняющего файла, он считывает из секции ‘.pack’ данные, расшифровывает и запускает из памяти, на практике показало что декомпилятор не способен был выдрать из него исходник, но и сам AutoIt интерпретатор из памяти работал не корректно, не мог найти исходник и выдавал ошибку, хотя со всеми остальными exe работало нормально, после провала просто переделал код под Joiner.

  • #16

Ledgous
Раз уж речь идет о том, чтобы ваш исходный код не смогли просто так глянуть, тогда имеет смысл закинуть его в динамическую библиотеку (DLL). PureBasic — отлично подойдет для этих целей, уж поверьте.

  • #17

Viktor1703 [?]

на практике показало что декомпилятор не способен был выдрать из него исходник, но и сам AutoIt интерпретатор из памяти работал не корректно, не мог найти исходник и выдавал ошибку

Не знаю.
У меня этот код запустил из памяти скомпилированную AutoIt-прогу и ошибок не было. Правда, антивирусам это не понравилось.

PurePROCS_Execute(ProgramFilename(), ?EXE)
End

DataSection
  EXE:
  IncludeBinary "Proga.exe"
EndDataSection

  • #18

sims [?]

У меня этот код запустил из памяти скомпилированную AutoIt-прогу и ошибок не было. Правда, антивирусам это не понравилось.

Да, так работать будет, но и исходник будет извлекаться декомпилятором, а попробуй зашифровать и при запуске расшифровывать.

  • #19

firex
Ваш оверлей легко ломается — «Fake code» и «Original code» видны как на ладони :smile:.

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

http://rghost.ru/private/47127150/1c2a20516575b1259c252b38ff3f2cac

Там 3 файла: версия 2.0 имеет обычный незакодированный оверлей, последующие версии уже модифицированы, раскомпилировать с ходу у вас никак не получится.

  • #20

Ledgous

Не удалось декомпилировать только SkyIAR_v2.55_chinese.exe и то наверное из — за того что декомпилятор у меня старенький, думаю найдутся те кто это сможет и что можно было запихать в исполняющие файлы что они такие огромные, я даже не уверен, работают ли они, не стал запускать, так как кода много и не знаю что он делает.

Добавлено:

Сообщение автоматически объединено: 4 Июл 2013


а нет, ошибочка, сменил язык с КНР на кириллицу и он тоже декомпилировался и деобфусцировался (частично), вообщем получил чистый исходник на руки и REG52.exe, REG61.exe, devcon_x86.exe, lng.ini, SetUrlX.exe, bk.bmp, файлы расширения *.INFO, IAR.Core.x86.*…. :whistle:

image

Часть 1

В последнее время я работал над собственным форком ME3Explorer [неофициальный редактор игр серии Mass Effect], содержащим множество важных улучшений и даже новые инструменты. Также я поработал над Mod Manager 5.1, который имеет удобные новые функции импорта сторонних модов, однако был отодвинут на второй план, пока я работал над новым фронтендом установщика ALOT.

ALOT Installer с манифестом 2017 года

Для его реализации я сотрудничал с CreeperLava и Aquadran; он должен упростить жизнь конечным пользователям, устанавливающим ALOT и его аддон (сторонние текстуры). Одна из моих проблем заключалась в том, что Origin не запускал игру после установки ALOT, если не запустить его с правами администратора. И поскольку запуск Origin при загрузке невозможно выполнить с правами админа, это очень раздражает. К тому же это влияет на мод MEUITM. Поэтому я начал разбираться, почему это происходит. Дело оказалось в идеальном сочетании реализации защиты, плохого кода и желания упростить жизнь других людей.

Давайте посмотрим, как работает Mass Effect с Origin в неизменённом состоянии под Windows 10.

  • Пользователь запускает MassEffect.exe. Файл немедленно запрашивает повышение прав до администраторских.
  • В конце образа MassEffect.exe есть код вызова Origin для запуска игры, это некая DRM. Он вызывает Origin, а затем выполняет выход.
  • Origin проверяет права пользователя на запуск игры, а затем запускает MassEffect.exe в соответствии с указаниями в реестре (не тот, который вы запустили сами), после чего пытается запустить исполняемый файл.
  • Origin не может запустить исполняемый файл, потому что он требует повышения прав. Чтобы DRM работала, она должна иметь возможность взаимодействия с процессом, поэтому она повышает права одного из внутренних сервисов, чтобы он мог общаться с игрой в целях DRM-защиты.
  • MassEffect.exe выполняется с правами администратора. Origin обменивается данными с MassEffect.exe и выполнение игры продолжается, как это было бы в случае с DVD-версией.

Всё это работает (через два UAC-запроса) на немодифицированной игре. Но если установить MEUITM или ALOT, то вы больше не сможете запускать игру через Origin как стандартный пользователь. Что за дела?

Сигнатуры файлов

И MEUITM, и ALOT модифицируют исполняемый файл MassEffect.exe, чтобы он мог использовать Large Address Aware. Это позволяет 32-битному процессу Mass Effect использовать до 4 ГБ ОЗУ вместо обычного 32-битного ограничения в 2 ГБ. При модификации флага LAA цифровая сигнатура MassEffect.exe оказывается поломанной — сигнатура используется для проверки того, что файл не модифицирован. После модификации файла сигнатура становится неверной.

Origin при выполнении процесса с повышенными правами проверяет, подписан ли EXE компанией EA и правилен ли он. Если он не подписан EA, то он не повышает права модуля обмена данными DRM. Mass Effect загружается, а затем немедленно закрывается, потому что разблокировка DRM не работает, ведь со стороны Origin ей не с чем общаться, поскольку отказано в повышении прав.

То есть при модификации EXE Origin будет отказываться запускать исполняемый файл игры с повышенными правами. Но нам нужен LAA, поэтому необходимо как-то обойти эту проблему. Наша единственная надежда заключается в том, чтобы помешать MassEffect.exe запускаться с правами администратора. Сначала нужно разобраться, как задан его запуск с правами администратора.

Изучив манифест EXE, я увидел, что он запускается как инициатор вызова — пользователь, запускающий EXE. Это означает, что этот исполняемый файл не должен требовать администраторских прав. Я проверил свои параметры совместимости, там тоже ничего не было. Каким-то образом права повышаются при запуске, но не через сам exe и не из-за моих настроек. В чём же хитрость? В Microsoft Windows Compatibility Database.

mirh (я встречался с ним в кругах любителей моддинга) провёл исследование того, почему Mass Effect вынужден запускаться с правами администратора. Он соответствует критериям базы данных — в ней есть запись для Mass Effect, в которой указано, что нужно всегда принудительно запускать параметры совместимости. Это логично — пользователь не должен конфигурировать параметры, если MS уже знает, какие из них работают (теоретически).

Как видите, для этой игры есть две записи — MassEffect.exe (игра) и загрузчик (который, к сожалению, не включён в версию Origin). Для совместимости включается RunAsHighest (что означает права администратора). Критерии включения таковы:

  • EXE имеет название MassEffect.exe
  • Название компании в манифесте: BioWare
  • Название продукта в манифесте: Mass Effect
  • Версия продукта равна или меньше 1.2.0.0.

Эти критерии соответствуют всем известным версиям игры, в том числе, полагаю, и пиратским. Поэтому из-за совпадения всех этих критериев exe принудительно запускается с правами администратора. Это можно легко проверить, переименовав MassEffect.exe, после чего ему не потребуются администраторские права. (Однако Origin будет недоволен).

Исправление

Итак, теперь у нас есть понимание, как это исправить, но почему в базе данных есть эта запись? Поскольку Demiurge/Bioware не поддерживают идею Least User Access (LUA), Mass Effect при самом первом запуске требует прав администратора для выполнения записи в ключ реестра HKEY_LOCAL_MACHINESOFTWAREWOW6432NODEAGEIA Technologies. Если этот ключ не существует, он пытается создать его — без прав администратора у него нет для этого доступа, и игра просто вываливается. Похоже, в этом ключе содержится некая информация о том, что сейчас называется PhysX. Вероятно, запись в реестр мог внести и установщик игры, но разработчики реализовали это в самой игре.

Именно поэтому Microsoft вынуждает игру всегда запускаться с правами администратора, из-за этого единственного пункта. Это логично — если заставить её запускаться под администратором, но пользователю не нужно будет беспокоиться о параметрах совместимости. Однако из-за этой комбинации трёх проблем (LAA портит сигнатуру, MS принуждает запускаться игру с правами администратора, Origin отказывается работать с процессами с повышенными правами, имеющими сломанную сигнатуру EA) Mass Effect не запускается с Origin и LAA.

Как же нам это исправить? Просто изменим в EXE название продукта с Mass Effect на Mass_Effect. Серьёзно, это всё. Проверка критериев не срабатывает, игре больше не нужны права администратора и Origin доволен (если не считать постоянного ворчания из-за обновлений). В MEUITM и ALOT Installer мы добавили код, создающий ключ реестра с правами записи для текущего пользователя, поэтому если Mass Effect нужно создать эти ключи (допустим, если его никогда не запускали), то игра будет довольна.

Часть 2

Mass Effect на PC: что ожидать от порта с консолей середины 2000-х

Если вы не знали, Mass Effect вышла на PC в 2008 году, она была портирована с Xbox 360 студией под названием Demiurge, которая также разработала Pinnacle Station для Mass Effect. Это очень посредственный порт, не особо хорошо переживший смену времён. Он приемлем как игра, но имел множество проблем даже на момент выхода. LOD частиц работали неправильно, LOD текстур считывались в обратном порядке, параметры ini случайным образом сбрасывались на значения по умолчанию — проблем было довольно много. Но не было ничего, что бы полностью ломало игру.

Ну, или типа того. Была одна проблема, но вызванная не конкретно самой Mass Effect. Серьёзная проблема заключается в том, что Mass Effect требует для запуска прав администратора потому что Demiurge, похоже, считала, что все должны запускать игру как администратор — это вполне могло быть приемлемым, если бы игра разрабатывалась во время, когда была только Windows XP, однако на момент выпуска игры уже больше года существовала Windows Vista. Но даже Windows XP имела концепцию LUA (Least User Access) с разделёнными аккаунтами пользователей. Подробнее об этом можно прочитать в первой части статьи.

Ух ты, PhysX, моя любимая библиотека физики!

Наверно, у меня небольшая неприязнь к этому SDK.

Mass Effect для PC работает на немного модифицированной версии Unreal Engine 3, который был выпущен примерно в конце 2006. По словам некоторых бывших разработчиков из BioWare, эта версия Unreal Engine тогда была немного сыроватой, если не сказать больше. Согласно рассказам этих разработчиков, было очень сложно работать с ней, потому что Epic Games сосредоточенно работала над Gears of War и не уделяла особо много времени своим партнёрам, тоже использующим движок.

Для расчёта физических взаимодействий Unreal Engine 3 использует PhysX, поэтому Epic Games создала dll, реализующую интерфейс между PhysX и форматами данных Unreal Engine через файл под названием PhysXLoader.dll, который загружает библиотеки PhysX с обеих сторон. PhysX — это библиотека симуляции физики, приобретённая компанией AGEIA Technologies в середине 2000-х перед тем, как саму AGEIA в начале 2008 года купила Nvidia. Возможно, вы помните карты Physics Processing Unit (PPU) — они использовали PhysX до того, как Nvidia похоронила эту идею.

PhysXLoader.dll, PhysXCore.dll и NxCooking.dll составляют библиотеки PhysX для Mass Effect.

Все три части Mass Effect используют PhysX, однако Mass Effect 2 и Mass Effect 3 используют установленную в систему PhysX, а Mass Effect — локальную PhysX игры. Кроме того, в Mass Effect 2 и Mass Effect 3 применяется «современная» версия PhysX, а не устаревшая, которая была выпущена AGEIA. После приобретения Nvidia изменила некоторые пути внутри библиотеки, отделив устаревшие части от «современных» версий.

Но, похоже, это не мешает программе удаления старой PhysX удалять файлы/ключи реестра современной PhysX, поэтому в процессе тестирования моего исправления другие копии Mass Effect 2/3 не работали даже после установки «современного» дистрибутива PhysX. Очень бесит, что BioWare не смогла просто установить библиотеку на 8 МБ вместе с игрой — в комплекте с игрой всё равно поставляется установщик PhysX, то есть это даже не экономило место!

Ну да ладно…

Проблема PhysXLoader.dll компании Epic Games в том, что она может загружать PhysXCore.dll локально или из установленной в систему версии

Что? Как это может быть проблемой? Разве нельзя просто загружать локальную dll, и если она не существует, загружать системную? Почему это вообще проблема?

Вы не поверите, сколько фейспалмов я испытывал в процессе создания этого исправления.

При запуске Mass Effect записывает в реестр Windows HKEY_LOCAL_MACHINE два значения:

REG_BINARY HKLMSOFTWAREAGEIA Technologies enableLocalPhysXCore [mac-адрес, 6 байт]

REG_DWORD HKLMSOFTWAREAGEIA Technologies EpicLocalDllHack [1]

*Mass Effect — это 32-битная программа, поэтому на 64-битной системе она выполняет запись в HKLMSOFTWAREWOW6432NodeAGEIA Technologies (на случай, если вы захотите проверить сами).

Запомните эти значения реестра, они будут важны в дальнейшем!

Именно из-за этих значений реестра Mass Effect требует административных прав. В первой части мы говорили о том, почему этих операций было достаточно, чтобы Microsoft внесла Mass Effect в базу данных совместимостей, заставляющую игру запускаться под администратором при совпадении определённых критериев исполняемого файла. Мы обошли эту проблему, изменив критерии так, чтобы они больше не совпадали.

Нам нужно изменить исполняемый файл, чтобы включить Large Address Aware, благодаря чему игра сможет загружать текстуры повышенного разрешения без переполнения памяти, поэтому нет никакого способа избежать порчи сигнатуры. Это, в свою очередь, привело к тому, что Origin больше не мог запускать игру, потому что он не может повышать права игры без правильной сигнатуры EA. Но если игра не имеет возможности записывать эти ключи реестра при запуске, то она может вылететь…

Итак, это само по себе уже длинная цепь проблем, но мы обошли необходимость прав администратора в Mass Effect, просто дав аккаунту пользователя разрешение на этот конкретный ключ реестра AGEIA Technologies. Это позволит процессу игры записывать нужные ему значения. Я предполагал, что игра вылетает, потому что ей запрещался доступ для записи, а Demiurge не озаботилась написать try/catch вокруг кода записи в реестр.

Вероятно, не стоит называть значения реестра «hack»

Наше решение этой проблемы не изменило поведения Mass Effect — значения, которые игра хотела записать в реестр, тем или иным способом будут в него записаны, поэтому мы просто позволяем ей делать то, что она всегда делала, только без прав администратора. На самом деле, никаких изменений в поведении приложения не было.

Два значения реестра, записываемые Mass Effect.

Модератор PC Gaming Wiki под ником mirh долгие годы бил тревогу о том, что мы каким-то образом ломали другие игры в ALOT Installer, даже несмотря на то, что наше приложение никак не меняла способ записи Mass Effect этих значений, поэтом наше изменение никак не может сломать другие игры.

Спустя много месяцев он написал довольно подробное обоснование того, почему ALOT Installer (то есть на самом деле это была Mass Effect) ломает другие игры: находящийся в реестре enableLocalPhysXCore используется другими играми, работающими с PhysXLoader.dll. Когда я писал версию V4 установщика ALOT Installer, то сказал mirh, что серьёзнее рассмотрю его идею решения, не позволяющего ломать другие игры, хотя тогда я ещё не понимал, как ключ реестра с MAC-адресом системы может ломать другие игры и зачем вообще используется MAC-адрес.

Похоже, mirh был уверен, что эта enableLocalPhysXCore позволяет Mass Effect использовать PhysXCore.dll/NxCooking.dll в локальной папке, а не загружаться из установленного дистрибутива PhysX. Mass Effect не устанавливает дистрибутив PhysX, поэтому не может полагаться на её существование и вынуждена использовать локальные библиотеки.

Держитесь, теперь начинается нечто совершенно тупое:

MAC-адрес, сохраняемый в реестр файлом MassEffect.exe, считывается библиотекой PhysXLoader.dll и сравнивается с MAC-адресом вашей системы, чтобы определить, нужно ли загружать библиотеки PhysX из локальной папки или из системной.

Какой MAC-адрес?

¯_(ツ)_/¯

Итак, Mass Effect работает следующим образом:

  1. В самом начале процесса загрузки MassEffect.exe MAC-адрес вашей системы считывается и записывается в реестр как enableLocalPhysXCore (вместе с EpicLocalDllHack)
  2. MassEffect.exe загружает PhysXLoader.dll
  3. PhysXLoader.dll считывает значение enableLocalPhysXCore и сравнивает с ним MAC-адрес вашей системы
  4. Если они совпадают, она использует PhysX из локальной папки, если нет, то версию дистрибутива PhysX из системы

Да, вы всё поняли правильно.

Оказалось, что другие игры, например, Mirror’s Edge, имеют PhysXLoader.dll, которая тоже считывает эти значения (так как они основаны на одинаковом коде), но в этих играх нет локальных библиотек PhysX. Поэтому эти игры загружаются, видят enableLocalPhysXCore и пытаются загрузить локальную библиотеку, терпят неудачу и игра не запускается. Эту информацию я получил от mirh — сам я не тестировал другие игры, поломанные этим значением реестра.

Обычно этого значения не существует, и игра должна использовать PhysX. Это поведение можно протестировать в Mass Effect, запретив доступ на запись к ключу реестра, удалив значения и установив старую версию PhysX — она будет использовать системные библиотеки. Если системная PhysX не установлена, приложение не загрузится — именно поэтому мы изначально разрешали записывать эти ключи Mass Effect, в противном случае бы казалось, что установщик портит Mass Effect, хотя на самом деле виновата ужасная реализация со стороны Epic Games.

Сложно представить сценарий, при котором это было бы хорошей идеей.

Если вы реализуете интерфейс с библиотекой, имеющей экспорт, который можно вызвать для инициализации/загрузки PhysX SDK, то разве нельзя просто передать ей булево значение, приказывающее ей загрузиться локально? Почему она вообще не начинает с локального поиска? И что за дела с MAC-адресом? Почему он находится в реестре, где ведёт себя как глобальный параметр???

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

Находим начальную точку

Предупреждение: я совершенный новичок в реверс-инжиниринге. Я создавал ассемблерные моды для игр Megaman Battle Network (и написал неплохое руководство по созданию хуков), проектировал моды на ActionScript2 P-Code и работал с байт-кодом UnrealScript, но никогда не углублялся в ассемблер x86. Я множество раз открывал IDA и могу находить нужные мне вещи, но никогда не понимал их. Уверен, что для более опытных реверс-инженеров этот процесс намного проще.

Сложно получать удовольствие от реверс-инжиниринга, если почти ничего не понимаешь в том, с чего начать. Это режим графа IDA, который очень помогает визуализировать ассемблер, но его всё равно очень сложно понять в большом двоичном файле на 20 МБ.

Недавно (пару лет назад), Агентство национальной безопасности США (АНБ) выпустило Ghidra — бесплатный тулкит для реверс-инжиниринга с открытыми исходниками, который может отреверсировать ассемблерный код в довольно читаемый код на C; его бесконечно проще читать, чем ассемблерные графы IDA. И IDA, и Ghidra имеют свои сильные стороны: в IDA есть отладчик, позволяющий пошагово пройти по ассемблеру и посмотреть, какие пути кода будут выполняться, а также она может находить Unicode-строки (которые используются в Mass Effect ). Ghidra может рекомпилировать ассемблерный код из его декомпилированного кода на C (иногда), имеет преобразователь из ассемблера в C (простите, не знаю его названия), обладает открытыми исходниками и работает на куче платформ и со множеством двоичных форматов.

Ghidra — это отличный инструмент для новичков в реверс-инжиниринге, поскольку она позволяет просматривать ассемблер как код на C, хоть и без имён переменных.

Итак, в начале я знал, что Mass Effect записывает enableLocalPhysXCore и EpicLocalDllHack. Давайте начнём с изучения MassEffect.exe, найдём эти строки и посмотрим, что на них ссылается. Открыв шестнадцатеричный редактор, я знал, что это unicode-строки, поэтому я буду искать их в IDA, потому что Ghidra, похоже, не поддерживает эту функцию.

Окно IDA Strings. Я наконец узнал, что эта полезная вкладка открывается по Shift + F12.

Поискав внутри окна IDA Strings строку enableLocalPhysXCore, я её нашёл. При двойном нажатии программа переносит нас к области данных исполняемого файла, в которой она задаётся:

На изображении вы видите, где задаются enableLocalPhysXCore, EpicLocalDLLHack и даже ключ реестра, все они находятся прямо рядом друг с другом.

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

Режим IDA View, а не Graph View.

Изучив это, мы видим, что здесь записывается RegSetValueExW. Я очень слабый разработчик на C, поэтому после гугления я понял, что это подготовка стека для вызова на C метода из Windows API, что можно увидеть по отображаемому IDA названию параметра, например, lpData и dwType. Мы знаем, что значению enableLocalPhysXCore присваивается MAC-адрес системы. Давайте посмотрим, где выполняется это присваивание. Чтобы выглядело логичнее, переключимся на режим графа.

В третьем блоке мы видим, что eax записывается в стек для lpData, а также записывается в стек для этого загадочного вызова «sub_10929393». В этой подпроцедуре нет других вызовов с заданными названиями, поэтому вероятно именно там получается MAC. Давайте перейдём к ней.

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

Эта подпроцедура содержит названия, взятые из Windows API, и они показывают нам, что это как-то связано с сетью. Нас не волнует MAC-адрес, но давайте зададим название этой подпроцедуре. Назовём её GetMacAddress. Вернёмся к исходной подпроцедуре, которую изучали, и тоже переименуем её — похоже, это что-то типа SetupPhysXSDKLoad, поэтому назовём её так.

Это относительно небольшая подпроцедура, всё, что она делает — это производит запись двух вышеупомянутых значений реестра. Кроме ранних этапов загрузки двоичного файла, на эту подпроцедуру больше нет других ссылок, поэтому на этом этапе я вполне уверен, что исполняемый файл Mass Effect никогда не считывает эти значения, и пока я не знаю, что же делает EpicLocalDllHack.

Вскрываем PhysXLoader.dll

Теперь мы знаем, что исполняемый файл Mass Effect никогда не считывает этот ключ; значит, это делает одна из dll. Здесь я этого не показал, но в ProcMon (отличном инструменте для моддинга и подобных вещей в целом) я вижу, что значение реестра считывается непосредственно перед загрузкой библиотеки в процессе MassEffect.exe и перед загрузкой локальной dll. Я увидел, что после того, как запретил Mass Effect доступ на запись в эту папку, он считывает системную библиотеку, и игра не загружается, если не установлена системная версия старой PhysX.

Первой из dll загружается PhysXLoader, после которой загружается PhysXCore.dll, поэтому логично будет анализировать её. Давайте откроем её в IDA и посмотрим, где там используется enableLocalPhysXCore. Также я открою эту dll в Ghidra, чтобы лучше понимать, что происходит. Проделав ту же последовательность действий по поиску мест использования строки enableLocalPhysXCore, мы находим подпроцедуру:

Подпроцедуру читать не так уж сложно, особенно в режиме графа — мы видим, что есть цикл, идущий из левого блока в блок над ним. Тем не менее, всё это не так просто читать для новичка, поэтому давайте посмотрим, как это выглядит в Ghidra. Я использую адрес этой подпроцедуры, чтобы перейти к ней в Ghidra (0x10001640).

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

Чтобы немного сократить пост, скажу, что эта подпроцедура поиска в реестре и в самом деле является простой обёрткой для получения информации из реестра. После реверс-инжиниринга (который в основном заключался в сопоставлении входящих данных подпроцедуры с тем, чем они являются в вызовах windows api) выяснилось, что её параметры являются подключом, именем значения, возвращаемым указателем на данные и возвращаемым размером данных.

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

Мы знаем, что Mass Effect записала в реестр 6-байтный mac-адрес, и что PhysXLoader.dll просто считала это значение из реестра, и что подпроцедура сравнивает что-то побайтно 6 раз. Логически мы можем предположить, что local_14 с показанного выше изображения — это MAC-адрес. Зная это, мы также можем предположить, что FUN_10001580 получает MAC-адрес и задаёт его, поэтому мы переименуем ещё несколько элементов подпроцедуры.

Похоже, что вызов подпроцедуры не выполняет саму загрузку, он просто проверяет ключ и совпадение MAC-адреса. Зная название и информацию о действиях этого ключа, мы можем дать этой подпроцедуре обоснованное название ShouldUseLocalPhysX. Однако сравнение декомпиляции этой подпроцедуры в IDA и Ghidra приводит к немного различающимся результатам, и Ghidra, похоже, ошибается:

IDA показывает, что al присваивается 1 при нормальном выходе из цикла и 0 (xor al,al), если какие-то байты не совпадают. Ghidra этого не показывает, на самом деле она показывает, что возвращаемый тип равен void, что кажется ошибкой.

Немного погуглив информацию для этой части поста, я узнал, что EAX обычно используется как регистр возврата для x86, а регистр al — это нижние 8 бит EAX. Я не имею достаточно опыта в Ghidra, чтобы знать, как сменить тип сигнатуры для этого вида возвращаемых нижних 8 битов; возможно, Ghidra пока этого не поддерживает, или я упустил какую-то настройку, которую нужно использовать.

Дизассемблированная подпроцедура, вызывающая ту, которая ищет enableLocalPhysXCore.

Однако если мы взглянем на ссылки на эту подпроцедуру (их две — скорее всего, по одной на каждую библиотеку) в IDA и Ghidra, то увидим, что при вызове ShouldUseLocalPhysX она проверяет, не равен ли al нулю. Если он не равен нулю, то она загружает локальную PhysXCore.dll. Если равен, то она ищет библиотеку через системную установку PhysX, которая находится по ещё одному значению реестра в ключе AGEIA Technologies под названием PhysXCore Path. На самом деле это нам неинтересно, потому что мы хотим заставить PhysX всегда загружаться локально, вне зависимости от значения enableLocalPhysXCore.

Посмотрев на другую перекрёстную ссылку, можно и в самом деле увидеть, что она загружает библиотеку NxCooking, используя ShouldUseLocalPhysX таким же образом:

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

Например, если мне нужно было удалить проверку if, то мне приходилось находить способ изменить сравнения таким образом, чтобы они всегда были true или false. Один из способов возврата false проверкой if заключается в изменении ссылок на объект и токенов байт-кода сравнений, чтобы создать условный оператор вида if (objectA != objectA), всегда возвращающий false (если они не равны null). Мне нужно найти способ, чтобы в ShouldUseLocalPhysX всегда получался результат true.

Когда я писал таблицу символов для Megaman Battle Network 3, то научился всегда комментировать всё, что узнал об дизассемблированном коде. Я работал часами, совершенно забывая, что уже сделал, но мог вернуться к своим комментариям, и снова во всём разобраться.

Иногда мои символы/комментарии на отдельных строках, например, названия подпроцедур или таблицы указателей, встречались в других подпроцедурах, давая мне полезный контекст, которого бы я иначе не увидел. Ниже я прокомментировал и пометил несколько элементов, упрощающих чтение этой подпроцедуры.

Патчим худшую в мире проверку boolean

Нам нужно убедиться, что выполнение всегда доходит до нижнего левого блока, при этом мы не должны касаться стека (который запросто может поломать всю программу). Строго говоря, мы можем переписать часть этой подпроцедуры, но мне хотелось бы вносить здесь минимальные изменения. По сути, нам нужно гарантировать, что переход в нижний правый блок никогда не происходит.

В x86 есть удобная однобайтная команда nop, которая в буквальном смысле не делает ничего, но занимает один байт. Также удобно то, что команда перехода в этот блок занимает 2 байта и состоит из 0x75 (jnz rel8) и 0x19 (относительного смещения).

[ЗАБАВНАЯ ИСТОРИЯ] Увидев это однобайтное смещение, я вспомнил времена, когда я работал над моддингом Megaman Battle Network. Тогда от команд перехода/ветвления зависела возможность моддинга отдельных частей ROM. При написании хука (перенаправляющего счётчик программы к вашему собственному коду) вам нужно найти команду перехода или ветвления, относительное смещение которой можно модифицировать так, чтобы оно указывало на ваш код. Затем нужно записать регистры в стек, запустить код, а затем вернуть стек обратно, чтобы подпроцедура выполняла выход правильным образом.

ARM (а конкретнее THUMB) имеет ограниченные команды ветвления, использующие в качестве относительных смещений разные размеры, которые не всегда могли перейти в любую точку ROM из-за своего местоположения в ROM. Так как игра была написана на ассемблере, находить свободное место временами было сложновато — иногда приходилось соединять в цепочку несколько хуков, пока не удавалось переместить счётчик программы в свободную область, чтобы писать новый ассемблерный код. Этот jnz использует опкод 0x75, что даёт jnz rel8, то есть он может переходить только на расстояние до 128 байт (или, если переход возможен только вперёд, на 255?), что было бы настоящей проблемой, если бы я выполнял моддинг ассемблера так же, как мы работали раньше, когда не было мощных инструментов наподобие IDA и Ghidra. [КОНЕЦ ЗАБАВНОЙ ИСТОРИИ]

После замены nop-ами этого jnz наша подпроцедура ShouldUseLocalPhysX выглядит так:

Теперь в блок условия неравенства попасть нельзя. «Проверка» по-прежнему выполняется, но она никогда не возвращает false. Будет всегда использоваться локальное ядро PhysX.

Недостатки

Файл PhysXLoader.dll подписан Epic Games, поэтому это очевидно разрушает сигнатуру, ведь мы модифицировали файл. Игра не проверяет сигнатуры при загрузке, поэтому это не проблема. Некоторые антивирусы могут жаловаться на сломанные сигнатуры, но со временем обычно перестают. Кроме написания патча внутри памяти (как мы делаем это в загрузчике мода asi), нам нужно будет модифицировать двоичный файл библиотеки.

Получившееся поведение

Благодаря пропатченной dll игра работает как со значением реестра, так и без него, то есть Mass Effect для запуска больше не требуются права администратора. Дизассемблирование этого кода сопровождалось сильной руганью, потому что я не мог смириться с тупостью реализации этой проверки — проверяется не только значение в реестре, но и MAC-адрес. В процессе отладки и пошагового выполнения команд я на самом деле сломал игру, потому что включил VPN и мой MAC-адрес сменился.

Этот процесс оказался хорошим опытом учёбы, я намного больше узнал о Ghidra и IDA, а также о других проблемах в PC-версии Mass Effect. Этот патч автоматически применяется в процессе установки ALOT Installer, поэтому пользователям не придётся беспокоиться о задании ключа enableLocalPhysXCore. Также мы модифицировали исполняемый файл Mass Effect для записи значения enableLocalPhysXCor_, чтобы наши пропатченные версии не записывали значение, портящее игры. Ванильные исполняемые файлы Mass Effect всё равно портят другие игры, но защита программ от криво написанных загрузчиков PhysX уже не входит в мои задачи.

О, а что насчёт EpicLocalDllHack? Ну, оно в буквальном смысле ничего не делает. Абсолютно бесполезное значение, оно никогда не считывается. Единственная возможная причина его существования, которую я могу придумать — сохранение ключа реестра на случай деинсталляции дистрибутива PhysX, потому что оно не находится в списке значений дистрибутива PhysX, но это всё только догадки.

Разве добавление параметра «PreferLocalSDK» для PhysXLoader.dll — это слишком сложно для Epic Games?

Все части
Часть II

Привет! В этой статье мы обсудим и опробуем способы обхода антивирусов. Информация для подготовки статьи была взята

Ссылка скрыта от гостей

. Обход антивирусов состоит из 2 больших шагов:

  • Скрытие кода, который может быть опознан как вредоносный. В большинстве случаев это происходит при использовании шифрования.
  • Создание загрузчика-расшифровщика таким образом, чтобы он не был обнаружен как вирус или не обходился эмуляцией/песочницей.

В этой статье я сфокусируюсь на последнем, на одурачивании антивирусных систем эмуляции/песочницы.

ВНИМАНИЕ: Автор не призывает к нарушению УК РФ, а предоставляет информацию для общего развития. Автор не несёт ответственности за ваши действия.

virustotal_wrapper.png

Теория обхода антивирусов

Для того чтобы понять как обходить антивирусы, нужно понять как они работают. Вот 3 основных метода их работы.

1. Статический анализ сигнатур

Анализ сигнатур основан на чёрном списке методов. Когда антивирусным аналитиком обнаруживается новая малварь, для неё создаётся определённая сигнатура. Сигнатура может быть основана на конкретном коде или на данных (например использование некоторого строкового имени). Довольно часто сигнатуры построены на первых исполняемых байтах вредоносного файла. Антивирус содержит миллионы сигнатур в своей базе данных и они сравниваются со сканируемым кодом из этой базы данных. Первые антивирусы использовали этот метод; этот метод используется до сих пор комбинируя этот метод с эвристикой и с динамическом анализом.

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

2. Статический эвристический анализ

В этом случае антивирус ищет шаблоны в коде, которые, специфичны для малвари. Есть много существующих правил, которые зависят от антивируса. Обычно эти правила держат в секрете (я полагаю, чтобы избежать их обхода), поэтому не всегда так просто понять почему антивирус считает программу вредоносной. Главная ценность эвристического анализа, это то что он может быть использован для поиска новой малвари, сигнатур которых нет в базе данных. Главный недостаток этого метода, это то что он генерирует ложные срабатывания.

Например: функция CallNextHookEx обычно используется в кейлоггерах. Некоторые антивирусы предполагают, что использование этой функции является угрозой, и выдает эвристическое предупреждение о программном обеспечении, если имя функции обнаружено в сегменте данных исполняемого файла. Другой пример, это открытие процесса «explorer.exe» и попытки записать в виртуальную память, это действие тоже расценивается как вредоносное.

Легчайший путь обхода эвристического анализа, это убедиться что весь вредоносный код скрыт. Шифрование кода это самый частый метод, который используется для этого. Если до расшифрования двоичный код не вызывает никаких подозрений, и если загрузчик-расшифровщик не выполняет никаких вредоносных действий, то вредоносное ПО не будет обнаружено.

3. Динамический анализ

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

Это означает, что обход динамического анализа состоит из 2 вещей:

  • Необнаруживаемый механизм саморасшифрования
  • Не допустить, чтобы антивирус выполнил фазу расшифрования

Ограничения антивируса

На самом деле динамический анализ — сложная функция, способная сканировать миллионы файлов, запускать их в эмулируемой среде и проверять на все сигнатуры… И она также имеет некоторые ограничения.

Модель динамического анализа имеет 3 главных ограничения, которые могут быть использованы в своих целях:

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

На этом всё, продолжение в следующей части.
Часть II

Статья [0x01] Исследуем Portable Executable (EXE-файл) [Формат PE-файла]

Доброго времени суток, форумчане. Сегодня, мы немного поговорим, рассмотрим и изучим под микроскопом структуру исполняемых файлов Windows ( Portable EXEcutable , или просто PE ), а в следующих статьях изучим технику модифицирования (инфицирования) PE-файлов, для того, чтобы исполнять свой собственный код после запуска чужого исполняемого файла (кстати, эта техника используется многими вирусами, для собственного «паразитического» распространения) и другие «хаки» с использованием знаний о структуре PE.

Portable Executabe файл (PE-файл) — это отдельный исполняемый модуль с расширением .exe (или .dll), получаемый в процессе сборки (компиляции и линковкии). В него включены код, ресурсы (иконки и другие данные), библиотеки, данные программы и т.д..

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

PE101-v1RU.png

  1. Заголовки
  2. Секции

Если формально и без аналогий, то заголовки — структуры содержащие необходимые данные для загрузки программы, а секции — блоки данных с различным содержимым произвольного размера. Этим содержимым может быть код, ресурсы, виртуальные адреса функций и т.д..

Секции.png

  1. DOS заголовок
  2. Заглушка DOS
  3. PE заголовок
  4. Таблица секций

Как я и сказал, заголовки хранят необходимую информацию для загрузки PE-файла. Поэтому данный заголовок является обязательным для загрузки PE-файла, хоть и не несёт в себе большой смысловой информации.

Заголовок состоит из полей, как список состоит из пунктов свойств. Каждый пункт хранит в себе какое-либо значение. Естественно, в файле всё это представленно в байтовом представлении. Не все поля нужны для загрузки (запуска) PE-файла. Поэтому комментировать и рассматривать мы будем только поля, необходимые для загрузки файла в память.

Вот его структура на языке C/C++.

    e_magic
    Двухбайтовое поле e_magic хранит в себе специальную сигнатуру. Эта сигнатура нужна, чтобы указать что это действительно исполняемый файл. Вот она — «MZ». Каждый PE-файл обязан начинаться с неё. Если это не так, файл просто не запустится.

DOS_header.png

Я выделил самым большим красный прямоугольником область DOS-заголовка. Здесь мы можем увидеть байты в шестнадцатеричном представлении.

Вы можете поинтересоваться, для чего же другие поля? Дело в том, что система Windows построена на базе старой системы MS DOS (была до Windows). И на самом деле, это заголовок для DOS программы. Так вот, эти поля хранятся на случай, если кто-то попытается запустить PE-файл в DOS . В наше время никто практически ей не пользуется, но они остаются, так как если поменяют формат PE-файла, то перестанут работать программы с нынешним стандартом.

DOS_stub.png

Дальше у нас по списку PE-заголовок, который на самом деле, состоит из трёх частей: сигнатуры, файлового подзаголовка и дополнительного подзаголовка.

Вот его структура на языке C/C++:

Pe_begin.png

pe_header.png

    Signature
    Это четырёхбайтовое поле содержит сигнатуру, а именно значение 50 45 00 00 (или «PEx00x00»). Эта сигнатура указывает на то, что перед нами действительно PE-файл (Ага, ещё одна проверка).

На C/C++ структура данного заголовка выглядит так:

    Machine
    Данное двухбайтовое поле содержит информацию о характеристике процессора, на котором может быть выполнена данная программа. Вот 3 основных значения, которые может принять этот заголовок:
    1. IMAGE_FILE_MACHINE_I386 ( 0x014c ) — означает, что программа может выполняться на x32
    2. IMAGE_FILE_MACHINE_IA64 ( 0x0200 ) — означает, что программа может выполняться на процессорах Intel Itanium (Intel x64).
    3. IMAGE_FILE_MACHINE_AMD64 ( 0x8664 ) — означает, что программа может выполняться на процессорах AMD64 (x64).

FileHeader.png

Структура дополнительного заголовка представлена следующий C/C++ кодом.

    Magic
    Это двухбайтовое поле отвечает за битность программы (x32/x64). Оно может принимать следующие значения:

1. IMAGE_NT_OPTIONAL_HDR32_MAGIC ( 0x10b ) — означает, что это x32 (x86) исполняемый образ.
2. IMAGE_NT_OPTIONAL_HDR64_MAGIC ( 0x20b ) — означает, что это x64 исполняемый образ.
3. IMAGE_ROM_OPTIONAL_HDR_MAGIC ( 0x107 ) — означает, что это ROM образ.

Heaventools

EnglishEnglish DeutschDeutsch РусскийРусский

  • Программы
  • Ссылки:

Я системный архитектор драйверов устройств под NT/XP, и я использовал PE Explorer для изуче- ния .SYS файлов. Меня интересовали способы взаимодействия этих фай- лов между собой, и ваша программа помогла мне лучше понять это взаимо- действие.

Dominick Cafarelli,
Sniffer Technologies,
Network Associates

Хочу сказать, что PE Explorer, возможно, самая лучшая программа из тех, что мне попадались. Раньше, чтобы получить тот же самый результат, мне приходилось исполь- зовать много разных отдельных программ, некоторые из которых уже довольно старые, еще в духе командной строки. Теперь в них нет больше необходимости. Всё, что надо, есть в PE Explorer на тулбаре.

Chris LaJoie

Я пишу на ассемблере, C и C++. Спустя всего несколько месяцев ис- пользования PE Explorer я поражаюсь, как это я раньше мог обходиться без него. Он стоит каждого цента потра- ченных денег. Спасибо за создание такой замеча- тельной программы.

Robert Limoges

PE Explorer содержит средства для дизассемблирования и изучения исполняемых файлов, а также изменения их свойств и ресурсов.

Просмотр и редактирование Portable Executable (PE) файлов

  • Работа с 32-битными PE файлами — такими как .EXE, .DLL, драйвера устройств (.SYS, .ACM), ActiveX Controls (.OCX), библиотеки Borland (.DPL и .BPL), файлы визуальных стилей (.MSSTYLES), апплеты контрольной панели (.CPL), скринсейверы (.SCR) и любые другие win32 исполняемые файлы.
  • Работа с поврежденными и запакованными файлами: такие файлы открываются в Safe режиме.
  • Проверка целостности файла при открытии.
  • Вычисление и коррекция контрольной суммы файла.
  • Модификация значения точки входа.
  • Модификация свойств файлов .
  • Автоматичесие распаковщики для UPX, Upack и NSPack.
  • Возможно подключение пользовательских плагинов для обработки файлов при открытии.

Средства просмотра

  • Headers Info Viewer отображает сводную таблицу данных из заголовка PE файла.
  • Data Directories Viewer отображает каталог Data Directories, описывающий содержащиеся в файле данные.
  • Sections Header Viewer позволяет просматривать количество секций в файле, их названия, адреса, извлекать или удалять секции из файла.
  • Export, Import и Delay Import Viewers отображают списки экспорта и импорта.
  • Function Syntax Viewer служит для просмотра и редактирования описаний функций.
  • Digital Signature Viewer отображает детали сертификата в блоке цифровой подписи.
  • Dependency Scanner показывает цепочку зависимостей и полный путь к каждому модулю.
  • Relocation Viewer показывает информацию о базовых поправках, содержащихся в таблице релокаций.
  • Debug Information Viewer отображает отладочную информацию, содержащуюся в файле.
  • Resource Viewer позволяет просматривать, удалять или извлекать любой тип ресурсов.

Редакторы

  • Редактор ресурсов служит для редактирования или замены ресурсов в файле.
  • Мастер создания манифестов позволяет добавлять в ресурсы манифест приложения.
  • Редактор характеристик изменяет набор флагов в поле Characteristics в заголовке файла.
  • Редактор секций служит для редактирования названия и размера секции, восстановления утраченных значений и коррекции характеристик секции.
  • Редактор описаний позволяет добавлять комментарии или изменять значения в описаниях функций.
  • Средства удаления Debug Information и Relocations
  • TimeDateStamp Adjuster позволяет выбрать и изменить значение штампа времени.

Дизассемблер

  • Поддерживает Intel 80×86, процессоры семества Pentium и совместимые с ним.
  • Набор инструкций x86 (MMX, SSE, SSE2 и SSE3), расширения AMD K6-2 3D-Now!
  • Удобная навигация по коду с использованием панелей, поиска и истории переходов.
  • Нахождение всех текстовых строк и объектов VCL внутри EXE файла.
  • Сохранение сессии и последующее открытие ассемблерного листинга и внесенных изменений.

Дизассемблер, входящий в состав PE Explorer, разработан с целью дать разработчикам и исследователям простой и удобный инструмент для выполнения экспресс-анализа исполняемых файлов.

Чтобы избавить пользователя от рутинной работы и уменьшить объём ручной правки, дизассемблер использует очень гибкий и интелектуальный алгоритм дизассемблирования, способный реконструировать ассемблерный код изучаемого исполняемого файла с высокой степенью достоверности. [ подробнее. ]

Общие настройки программы

  • Список из 20-ти последних открывавшихся файлов.
  • Добавление часто открывающихся файлов в список избранных.
  • Опциональная интеграция с контекстным меню Проводника Windows.
  • Настраиваемый внешний вид и цвет у панелей и шрифтов.
  • Создание резервной копии редактируемого файла (включено по умолчанию).
  • Отображение событий и сообщений в окне лога, запись событий в лог файл.

Скачайте бесплатную ознакомительную версию!

PE Explorer работает на всех версиях Windows
от Windows 95 до XP, Vista, 7, 8, 10 и 11.

Минимальные системные требования:
Процессор Intel Pentium® или AMD K5 166 MHz
16 MB RAM

Если ваша единственная задача — это редактирование ресурсов, и вам совершенно не нужна расширенная функциональность PE Explorer, то вы можете попробовать Resource Tuner — это программа представляет собой редактор ресурсов из PE Explorer, выделенный в отдельный продукт.

Битва потрошителей. Выбираем лучший редактор для вскрытия исполняемых файлов Windows

Так как мы в основном исследуем исполняемые файлы и динамические библиотеки для Windows, я брал только те РЕ-редакторы, которые работают в этой ОС. Если какой-то из инструментов поддерживает другие операционные системы и их исполняемые файлы (например, ELF), то это только плюс, но в данном случае для нас особого значения не имеет.

Мы будем выбирать утилиты на основе разумных и понятных факторов: функциональность, цена, удобство использования и частота обновления. Совсем старые решения, позволяющие редактировать бинарники для MS-DOS или Windows 9x, нам рассматривать ни к чему. Если какой-то из редакторов распространяется платно, то мы воспользуемся ознакомительной версией и отдельно отметим, какие функции в ней доступны. Но самый главный критерий будет состоять во взломе настоящего кракми.

Чтобы не тратить время на создание подопытной программы, мы воспользуемся уже готовой — passCompare35 . Именно на ней и будем испытывать разные тулзы. По большому счету, чтобы взломать наш простой крякмис, PE-редактору надо обладать не такой уж широкой функциональностью: перейти по указанному адресу и переписать команду (желательно в дизассемблерном листинге). Править циферки в шестнадцатеричном дампе мне совсем не хочется (вероятно, тебе тоже), поэтому наличие встроенного дизассемблера запишем в ключевые свойства.

Как ты помнишь, с помощью отладчика мы нашли в памяти адрес инструкции (см. четвертую статью «Фундаментальных основ»), которая определяет ход выполнения программы при вводе пароля. А благодаря сведениям из третьей статьи этот виртуальный адрес у нас получилось преобразовать в физический, находящийся на носителе. Таким образом, перейдя в исполняемом файле по адресу 0x402801 и заменив там инструкцию test на xor , мы получим программу, принимающую любые пароли. Меньше слов, больше дела!

PE-Explorer

Разработчик: Heaventools Software
Сайт: http://www.heaventools.ru/pe-explorer.htm
Дата выхода последней версии: Октябрь, 2009
Стоимость: $129 – персональная лицензия

Под первым номером идет довольно распространенный редактор PE-Explorer. В отличие от своего собрата Resource Tuner, он способен редактировать не только ресурсы приложения, но и код. Несмотря на свой почтенный возраст, исправно работает даже в Windows 10. К сожалению, PE-Explorer умеет работать только с 32-битными файлами и при попытке открыть 64-битный бинарник сообщает об ошибке.

Утилита обладает богатой функциональностью: отображает все элементы заголовка РЕ, определяет, к каким DLL происходит обращение, предсказывает поведение программ и логику взаимодействия с другими модулями и даже открывает запакованные UPX, UPack или NSPack файлы. Кроме того, она позволяет просматривать и редактировать секции PE-файла, исследовать содержимое таблиц импорта и экспорта и проверять наличие и целостность цифровой подписи. В качестве «вишенки на торте» тут присутствует полноценный дизассемблер.

Но это только на словах, а на деле мы его сейчас проверим. Из-за того что продукт платный, я использовал триальную версию, готовую работать на протяжении 30 дней. Об урезанных функциях ничего сказано не было.

Запустим редактор и сразу же откроем наше подопытное приложение. PE-Explorer первым делом выводит информацию о заголовке PE-файла. Для получения сведений об остальных разделах достаточно пощелкать кнопки на панели инструментов. Жмем пиктограмму Disassembler и открываем окно для выбора поддерживаемых инструкций: SSE, SSE2 и прочее. Указываем необходимые и начинаем процесс нажатием кнопки Start Now .

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

Так как мы с помощью отладчика нашли адрес инструкции, которая отвечает за ход выполнения программы, то попробуем проверить этот адрес в PE-Explorer: нажимаем Ctrl-F (или Search → Find) и вводим адрес для поиска: 402801 .

Что ж, я немного разочарован результатом дизассемблирования. Даже отладчик в этом месте показывает мне инструкцию test , а здесь я вижу лишь начало ее шестнадцатеричного кода: 0х85 . При этом я не могу редактировать код! Зачем мне все эти возможности, если утилита не позволяет делать самую базовую вещь?

Я даже не могу списать этот недочет на ограничения демоверсии, так как о ее отличиях от платной ничего толком не сказано. Допускаю, что с теми целями, для которых этот продукт предназначен (статическое изучение приложения и вектора его выполнения), он справляется хорошо. Однако нашим требованиям программа не соответствует, поэтому смело вычеркиваю PE-Explorer из списка кандидатов.

FlexHex

Разработчик: Heaventools Software
Сайт: http://www.heaventools.ru/flexhex-hex-editor.htm
Дата выхода последней версии: Июль, 2018
Стоимость: $59,95

Думаю, нужно дать разработчику еще один шанс, поэтому рассмотрим другую утилиту Heaventools Software — hex-редактор FlexHex. Это инструмент для редактирования любых файлов, процессов или устройств в двоичном формате, ASCII и Unicode. По словам авторов, редактор умеет работать с файлами просто гигантского размера — 8 эксабайт. Кроме того, он поддерживает множество типов данных: байты, слова, двойные слова, восьмибитовые слова, различные десятичные значения со знаком и без, 32- и 64-битовые целые.

Сложные типы данных тут могут быть определены самим пользователем — это структуры, объединения, массивы, перечисления, строки и их сочетания. Обещают прямое редактирование любых значений, в том числе шестнадцатеричных, строковых, изменение областей памяти и типизированных данных. Поддерживаются битовые операции (NOT, AND, OR и XOR над блоками данных) и, конечно же, арифметические операции: сложение, вычитание, умножение, деление и взятие остатка.

Однако главная особенность FlexHex — это возможность сравнения файлов целиком или отдельными блоками. При этом использование карт сравнения позволяет сделать процесс более интуитивным и наглядным.

Все это хорошо, но как утилита справится со взломом — нашей элементарной задачкой? Отсутствие дизассемблера сразу намекает нам, что придется работать в hex-кодах. Запустим FlexHex и откроем с его помощью наш крякмис.

Первым делом попробуем найти смещение 402801 . Кликаем Navigate → Go To и в списке слева выбираем пункт Address, а в поле Enter address вводим значение для поиска. Убеждаемся, что включен режим Hex , и нажимаем кнопку Go To.

Однако результат поиска выносит нас далеко за границы приложения. Обрати внимание, что последние читаемые символы находятся по смещению 0x3659F0 . Если напрячь память, то вспоминается, что в заголовке РЕ базовый адрес (или адрес загрузки модуля) прописан как 0x400000 . А здесь он даже не учитывается!

Ладно, как говорил дедушка Ленин, мы «пойдем другим путем». Строго говоря, FlexHex не понимает формат РЕ и потому его нельзя признать полноценным PE-редактором. Так что нам ничего не остается, как править байтики. Из того же отладчика, где мы нашли проверяющую пароли инструкцию, возьмем уникальную последовательность байтов: 85 C0 74 3C 68 . Она покрывает ассемблерные команды:

Я выбрал такую длинную последовательность, чтобы не было ложных срабатываний. За ключевым байтом 0x74 тут скрывается ассемблерная инструкция JZ . Чтобы сделать из нее JNZ , достаточно переписать как 0x75 . В итоге мы получим программу, кушающую любые пароли, кроме эталонного.

С помощью Search → Find открываем окно и указываем в качестве типа для поиска Hex Bytes и направление. В поле ввода пишем нашу последовательность байтов: 85 C0 74 3C 68 . Есть совпадение! Теперь ставим курсор на 74 , нажимаем Delete и вписываем на этом месте 75 . Сохраняем результат и закрываем редактор. Проверь «пропатченное» приложение, оно теперь должно работать значительно лучше.

В целом я бы не сказал, что этот редактор отличается значительным удобством и соответствует нюансам работы благородного крекера. Поэтому отдавать за него 60 долларов кровных лично я бы не стал.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.

Юрий Язев

Юрий Язев

Широко известен под псевдонимом yurembo. Программист, разработчик видеоигр, независимый исследователь. Старый автор журнала «Хакер».

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить сигнал уведомления на андроид
  • Как изменить сигнал сообщения на андроид
  • Как изменить сигнал на роутере
  • Как изменить сеть интернета на виндовс 10
  • Как изменить сеть вай фай на яндекс станции мини

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии