Недавно мне попался файл svchost.pyc. Сначала название не вызвало особого интереса — мало ли файлов с похожими именами встречается в системе. Но при ближайшем рассмотрении стало понятно, что к обычному svchost.exe этот файл отношения не имеет.

Передо мной оказался скомпилированный Python-код, внутри которого было довольно много интересного: работа с реестром, COM Hijacking, изменение настроек Windows Defender, отключение AMSI и ETW, внедрение кода в другие процессы и даже попытка сделать собственный процесс критическим для системы. В общем, обычным Python-скриптом это уже не выглядело.

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

Сначала посмотрим, что это вообще за файл

svchost.pyc — это скомпилированный Python bytecode. Исходного .py рядом нет, поэтому при анализе приходится работать непосредственно с .pyc. Внутри сохранилась интересная строка:

E:\code2\AVE\VA\no3\appi\payload.py

То есть изначально файл был собран из payload.py.

Самое интересное начинается дальше. Основной код частично спрятан. В файле находятся данные, которые сначала декодируются через Base85, затем проходят XOR и LZMA-декомпрессию. После этого полученный Python-код передаётся в exec(). Получается примерно такая цепочка:

данные
  ↓
Base85
  ↓
XOR
  ↓
LZMA
  ↓
Python-код
  ↓
exec()

Сделано это достаточно просто, но для статического анализа неудобно: часть логики нельзя увидеть сразу, пока не восстановишь содержимое. Но упаковка здесь далеко не самое интересное.

COM Hijacking

В коде я нашёл функцию setupcom_hijacking. Она работает с веткой:

HKCU\Software\Classes\CLSID\

и создаёт собственный CLSID:

{F56F6FDD-AA9D-4618-A949-C1B91AF43B1A}

Дальше появляется:

InprocServer32

а в качестве обработчика указывается:

C:\Windows\System32\scrobj.dll

Также задаётся:

ThreadingModel = Apartment

и параметр ScriptletURL.

Внутри самого файла есть ещё и JScript, который создаёт:

new ActiveXObject("WScript.Shell")

После этого выполняется:

tasklist /FI "IMAGENAME eq pythonw.exe"

То есть файл проверяет, запущен ли pythonw.exe, и в зависимости от результата может выполнить его запуск. Здесь уже становится понятно, что COM Hijacking используется как один из способов сохранить запуск вредоносного кода в системе. Но это только один из них.

Дальше начинается работа с Windows Defender

Следующее, что бросилось в глаза, — функция adddefender_exclusion. В ней встречаются:

HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths
HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Processes

А ещё:

PowerShell
Add-MpPreference

То есть файл пытается добавить свои файлы и процессы в исключения Microsoft Defender. В коде есть и непосредственная работа с реестром:

HKEY_LOCAL_MACHINE
KEY_SET_VALUE
KEY_WOW64_64KEY
REG_DWORD

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

Патчинг ETW

После этого я дошёл до функции patchetw. Она находит:

ntdll!EtwEventWrite

и меняет код этой функции прямо в памяти процесса. В качестве патча используется:

ret

То есть при вызове EtwEventWrite функция фактически сразу завершается.

Для чего это нужно — понятно из самого названия. Программа пытается отключить ETW для своего процесса и тем самым уменьшить количество событий, которые могут попасть в средства мониторинга. Это уже не просто настройка Windows через реестр. Здесь программа сама изменяет код системной DLL в памяти.

AMSI получает такой же патч

С AMSI используется примерно тот же подход. Есть функция patchamsi, которая работает с:

amsi.dll
AmsiScanBuffer

Адрес функции получается через:

LoadLibrary
GetProcAddress

Затем используется:

VirtualProtect

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

Один из вариантов патча:

mov eax, 0x80070057
ret

То есть AmsiScanBuffer больше не выполняет обычную проверку, а сразу возвращает ошибку. Для скриптового вредоносного кода это особенно полезно: AMSI является одним из механизмов, через которые Windows и защитные продукты могут проверять выполняемый скриптовый код.

Попытка притвориться svchost.exe

Ещё интереснее выглядит функция hideprocess_info.

Она работает с:

PROCESS_BASIC_INFORMATION
NtQueryInformationProcess
ReadProcessMemory

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

CommandLine
ImagePathName

А среди строк находится:

C:\Windows\System32\svchost.exe -k netsvcs

Здесь уже становится понятно, зачем файлу имя svchost.pyc. Программа пытается изменить информацию о собственном процессе так, чтобы при определённых способах проверки вместо настоящего пути и командной строки можно было увидеть что-то похожее на обычный системный svchost.exe. Сам процесс от этого, конечно, настоящим svchost.exe не становится. Меняется информация, которую можно получить из PEB.

Получение SeDebugPrivilege

Дальше программа проверяет, запущена ли она с правами администратора:

IsUserAnAdmin

После этого получает токен процесса через:

OpenProcessToken

и включает:

SeDebugPrivilege

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

Внедрение shellcode

Функция injectto_system_process получает список процессов через:

tasklist

После выбора процесса используются стандартные Windows API:

OpenProcess
VirtualAllocEx
WriteProcessMemory
CreateRemoteThread

Сначала открывается другой процесс, затем в нём выделяется память:

VirtualAllocEx

после чего туда записывается shellcode:

WriteProcessMemory

и создаётся поток:

CreateRemoteThread

В результате получается классическая последовательность:

OpenProcess
      ↓
VirtualAllocEx
      ↓
WriteProcessMemory
      ↓
CreateRemoteThread

То есть Python здесь используется уже не просто для выполнения скрипта. Через ctypes он напрямую вызывает Windows API и работает с памятью другого процесса.

А что будет, если процесс попытаться завершить?

На этот случай здесь тоже предусмотрена защита. Функция protectprocess использует:

NtSetInformationProcess

с параметром:

ProcessBreakOnTermination

Таким образом процесс помечается как критический. В самом коде даже есть сообщение:

[+] process protected (critical)

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

На этом способов восстановления не заканчивается

В коде я нашёл ещё функцию setupwatchdog_tasks.

Она создаёт Scheduled Task через:

schtasks

В XML-задании присутствует:

<LogonTrigger>
    <Enabled>true</Enabled>
</LogonTrigger>

а также:

<RestartOnFailure>
    <Interval>PT1M</Interval>
    <Count>999</Count>
</RestartOnFailure>

То есть при входе пользователя в систему задача запускается, а при падении процесса Windows может попробовать запустить его снова. Но и этого автору оказалось мало. Есть ещё один watchdog, который работает через WMI.

WMI следит за процессом

Функция setupwmi_watchdog работает с:

root\subscription

и создаёт:

__EventFilter
CommandLineEventConsumer
__FilterToConsumerBinding

Событие связано с удалением процесса:

__InstanceDeletionEvent

и классом:

Win32_Process

В частности, отслеживается pythonw.exe. Если процесс исчезает, WMI Consumer может выполнить команду повторного запуска. Получается интересная ситуация: за одним процессом одновременно могут следить Scheduled Task и WMI. Если один механизм убрать, второй всё ещё может вернуть процесс.

Обычный Run тоже присутствует

Ну и совсем без классики не обошлось. В коде есть writestartup, которая работает с:

Software\Microsoft\Windows\CurrentVersion\Run

и создаёт запись автозапуска через:

CreateKey
SetValueEx
HKEY_CURRENT_USER
REG_SZ

В результате у файла сразу несколько вариантов закрепления:

COM Hijacking
Registry Run
Scheduled Task
WMI

Для обычного приложения это выглядело бы очень странно. Здесь же всё складывается в одну картину.

Индикаторы компрометации (IOC)

MD5

10356274f35fc919623e297872ee7ebb

SHA-1

53ec5c3666844034733b58b13eda8bfc9a6467f2

SHA-256

c4e8547c04a8c395af60d7f005c6702482d897e02d2d71b64387466b6474bb0f

SSDEEP

98304:zvOesLOioeEVvLca87Hsc5jr4z/McrfL/lMHIF2wvjQmp6xnKJnJbLCrxE/q:CXOis2X4zDfL/lMe2a90CV2rxv

Что в итоге получилось

Когда я начал разбирать svchost.pyc, сначала казалось, что передо мной просто скомпилированный Python-файл с каким-то загрузчиком. Но чем дальше шёл анализ, тем интереснее он становился.

Файл умеет закрепляться в системе сразу несколькими способами, добавлять свои компоненты в исключения Defender, отключать AMSI и ETW прямо в памяти процесса, менять информацию о собственном процессе, получать SeDebugPrivilege, внедрять shellcode в другие процессы и защищать себя от завершения. При этом для восстановления используются сразу несколько независимых механизмов — реестр, COM Hijacking, Scheduled Task и WMI. Поэтому удаление одного файла или одной записи из автозагрузки здесь ещё не означает, что программа исчезнет из системы.

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

И именно поэтому файл с безобидным на первый взгляд именем svchost.pyc оказался совсем не тем, чем кажется.

Комментарии (1)


  1. HemulGM
    19.08.2026 07:07

    Да само название файла уже вызывает подозрение, если честно)