Rustock-C

Rustock.C – секретные техники анализа\\ или заглядывая реверсеру через плечо

крис касперски, ака мыщъх

легендарно-неуловимому rootkit'у Rustock.C посвящены десятки технических публикаций, детально описывающих _что_ именно он делает, но никто из реверсеров не говорит _как_ именно он это выяснил, _какие_ инструменты и методики анализа использовались? мыщъх предпринял попытку заполнить этот пробел, поделившись экзотическими блюдами хакерской кухни.

Качественная малварь в последнее время — большая редкость. В основном попадается жутко примитивная «шрапнель», написанная на языках высокого уровня с использованием готовых компонентов, выдранных из других вирусов или собранных в автоматизированных конструкторах типа метасплоита. Потом все это дело заворачивается несколькими слоями различных протекторов (опять-таки широко известных) и после небольшой модификации кода распаковщика (или даже вообще без таковой) выпускается в сеть.

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

Rustock.C – словно проливной дождь в знойной пустыне. Это настоящий вызов, реально напрягающий мозги и на несколько дней (а то и недель) выбивающий хакера из круговорота повседневной суеты. Окружающий мир исчезает. Остается только монитор, клава, Русток и бесчисленное множество распечаток, осенним листопадом падающих на пол. Rustock.C затягивает, не отпуская даже во сне, заставляя хакера подскакивать среди ночи, лихорадочно опробуя только что вспыхнувшую идею, озарившую казалось совершенно неразрешимую проблему.

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

Как и следует из его названия, Rustock.C – не первый в своем семействе. До него были версии A и B, построенные по тому же принципу, что и С, но гораздо хуже защищенные, а потому начинающим хакерам рекомендуется начинать свой путь именно с них. Когда версия B будет разобрана по винтикам и байтикам, почерк автора вируса станет знаком настолько, что «жуткий и ужасный» Rustock.C окажется не такой уж непроходимой проблемой. К слову сказать, у мыщъха имеется множество сэмлов, опознаваемых антивирусами как Rustock.C, но радикально отличающимися поведением расшифровщика третьего уровня (в частности, в некоторых сэмплах отсутствует привязка к чипсету, имеющая в других).

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

Забавно, но даже антивирусным компаниям пришлось всерьез напрячься, чтобы раздобыть живые образцы этого легендарного вируса и это с учетом распределенных систем для отлова малвари с кучей датчиков и сенсоров, рассредоточенных по всему миру, грабящих весь трафик и сохраняющих его длительное время для последующего анализа. Но датчики упорно молчали. Вируса не было. То есть, не то, чтобы совсем не было, но скудность собранного «урожая» вызывает смутные сомнения в цифрах, приводимых различными исследовательскими группами: сколько времени неуловимый Rustock.C жил и как много машин он заразил.

Где же все-таки брать образцы для анализа?! В антивирусные компании обращаться бесполезно. Все равно не дадут. Во всяком случае через официальные каналы. А вот по дружбе… в обход всех должностных инструкций… Однако, для завязывания знакомств требуется время, и, если хакер, по натуре человек не очень общительный, и не вращается в индустрии безопасности, зная всех и каждого, ему придется грызть асфальт зубами или задействовать профессиональные социальные сети, крупнейшей из которых на данный момент является www.linkedin.com.

Рисунок 1 мыщъх с алиской на LinkedIn (алиска — вторая сверху, знает ассемблер и еще кучу языков, включая Перл, Питон, Си, Руби и…)

Грубо говоря, www.linkedin.com это тоже самое, что «Мой мир», только порядка на два круче и реализованный должным образом. В принципе, все социальные сети построены по общей схеме: «я», «мой друг» и «друг моих друзей», причем количество контактов при переходе от одной ступени к другой увеличивается в геометрической прогрессии! Имя десяток-другой знакомых первого уровня, через списки их контактов можно дотянуться практически до кого угодно, а дотянувшись — познакомится через общих друзей, используя их как залог своей лояльности, что мыщъх не пойдет и не начнет распространять полученный образец вируса налево и направо.

На http://www.offensivecomputing.net (требуется регистрация) есть один экземпляр Rustock.C, однако, нет дропера и, чтобы заставить «зверька» заработать, придется конкретно напрячь свой хвост (хотя после небольшой доработки «напильником» он соглашается жить под VM Ware и даже размножается, нужно только «отломать» процедуру детектирования, ну и, конечно, подобрать ключ привязки к машине, шифрующий основной код вируса).

Рисунок 2 www.offensivecomputing.net — огромная коллекция малвари на любой вкус

Другой источник сэмплов — http://malwaredatabase.net/blog/, откуда Rustock.C периодически то появляется, то исчезает. А еще можно влиться в ряды распределенной сети «Malware Database Over Dropbox», где малварь хранится не на публичных серверах (которые закрываются так же стихийно как и открываются), а на локальных жестких дисках членов сети. Короче говоря, это тот же самый eMule, только без координирующих серверов. На компьютер устанавливается специальный клиент и файл, положенный в определенную папку, немедленно становится доступным всем остальным членам сети.

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

Для подключения к этому ресурсу, необходимо быть принятым в ряды сообщества «Professional Reverse Engineers & Ethical Hackers» — http://ehre.collectivex.com/ (требуется регистрация, причем регистрация премодерируемая, т. е. координатор вправе немотивированно отказать, лично у меня вступление в ряды заняло с неделю достаточно оживленной переписки, естественно, на английском — чес-слово, процедура устройства в антивирусную компанию с открытием доступа к коллекции вирусов отняла у мыщъха _гораздо_ меньше времени).

Рисунок 3 ehre.collectivex.com/ — сообщество профессиональных реверсеров и хакеров, живущих по понятиям

На хакерских форумах ссылки на Rustock.C (выложенный на «Рапишиду») попадались не раз и не два, но сейчас все они битые, однако, если запастись терпением, то откопать живого зверька вполне можно.

Добытый образец Rustock.C грузим в HIEW, IDA-Pro или Ольгу. Стоп! А Ольга тут причем? Ведь Rustock.C заражает драйвера режима ядра, а Ольга работает в прикладном режиме, что, впрочем, совсем не мешает ей грузить драйвер как DLL в Ring-3, где, конечно, драйвер работать не будет, но первый уровень шифровки из трех снимается Ольгой на счет «раз», а вот со вторым уже возникают практически непреодолимые трудности. Но не будем забегать вперед.

Рисунок 4 Rustock.C в Ольге

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

.00010200: 60pushad

.00010201: B9D5030000movecx,0000003D5 —↓ (1)

.00010206: 31DBxorebx,ebx

.00010208: 31D2xoredx,edx

.0001020A: 81C331085F7Daddebx,07D5F0831

.00010210: 83D200adcedx,000

.00010213: 49dececx

.00010214: 75F4jne.00001020A —↑ (2)

.00010216: BE33020100movesi,000010233 —↓ (3)

.0001021B: 89F7movedi,esi

.0001021D: B905DF0000movecx,00000DF05 —↓ (4)

.00010222: 89D8moveax,ebx

.00010224: C1E803shreax,003 ;«♥»

.00010227: 01C2addedx,eax

.00010229: 87DAxchgebx,edx

.0001022B: ADlodsd

.0001022C: 29D8subeax,ebx

.0001022E: ABstosd

.0001022F: 49dececx

.00010230: 75F0jne.000010222 —↑ (5)

.00010232: 61popad

Листинг 1 первый уровень шифровки

За концом расшифровщика следует «мусорный» код, который, собственно, и расшифровывается. Достаточно установить точку останова на команду POPAD, нажать <F9> (Run) и… первого слоя шифровки как не бывало. Можно смело сохранять дамп.

Решение номер два. Написать скрипт для IDA-Pro, расшифровывая код прямо в дизассемблере (плюс исчезают проблемы с возможными ошибками сохранения дампа). Способ надежный, но мыщъх — зверь ленивый и потому просто рипнул оригинальный код, заснул его в ассемблерную вставку на Си, дописал еще несколько строк, расходующихся на файловый ввод/вывод, в результате чего через пару минут появился статический расшифровщик (см. листинг 2).

#define BASE 0x00010000

decrypt(char *p)

{

asm ripped code { movecx, 0000003D5h xorebx, ebx xoredx, edx … movesi, [p] addesi, 233h … jnzshort loc_10222 } end of rip } main() { FILE *f_in, *f_out; int base = BASE; char *p; fpos_t pos; if(!(f_in =fopen(«rustock-c» ,«rb»)))return printf(«-ERR:open rustock\n»); if(!(f_out=fopen(«rustock-c-un»,«wb»)))return printf(«-ERR:open rustock-un\n»); fseek(f_in, 0, SEEK_END); fgetpos(f_in, &pos); fseek(f_in, 0, SEEK_SET); p = (char *) malloc((size_t)pos); fread(p, 1, (int) pos, f_in); decrypt(p); fwrite(p, 1, (int)pos, f_out); fclose(f_out); fclose(f_in); } Листинг 2 статический расшифровщик первого уровня с рипнутым кодом В оригинальном коде расшифровщика потребовалось заменить всего одну строку (в листинге 1 она выделена инверсией): MOV ESI,000010233h  MOV ESI, [p]/ADD ESI, 233h, где p – указатель на блок памяти, в который загружен расшифровываемый файл, а 233h – смещение первого зашифрованного байта, следующего непосредственно за командой POPAD. Подобный прием (рипанье кода) — весьма эффективный способ для борьбы даже с навороченными шифровщиками, правда, если код шифровщика разбросан по десяткам функций, «размазанным» по всей программе, рипанье существенно усложняется и такие защиты уже предпочтительнее снимать в отладчике. Рисунок 5 первый уровень шифровки снят, а за ним второй! голубым выделен код расшифровщика, серым — то, что он расшифровывает Расшифрованный Rustoc-C-unpack загружаем в IDA-Pro и смотрим на панель навигатора (см. рис. 5), где синим цветом показан код, а серым — данные. То есть, никакие это, конечно, не данные, а основное вирусное тело. Зашифрованное, разумеется. Расшифровщик второго уровня занимает сравнительно небольшую часть, сбившуюся в левый угол, однако, не стоит надеяться, что он дастся нам так же легко как и предыдущий! Рисунок 6 функции расшифровщика второго уровня, переплетенные тесным клубком Попытка визуализации расшифровщика второго уровня вгоняет IDA-Pro в глубокую задумчивость, после чего она отображает жуткое хитросплетение графов, похожее на паутину, сотканную обкуренным пауком (см. рис. 6). Попытки трассировки потока управления гаснут как бычок в писсуаре, оставляя нас наедине с кучей функцией, условных и безусловных переходов, просмотр которых в укрупненном масштабе показывает, что Rustock.C разбивает код расшифровщика второго уровня на множество мелких блоков (см. рис. 7) которые было бы несложно собрать обратно, прогнав программу через отладчик и построив полную трассу потока выполнения, вот только… сделать это у нас не получится, поскольку, Rustock.C активно сопротивляется отладке!!! Рисунок 7 фрагмент блок-схемы расшифровщика второго уровня Просматривая код распаковщика второго уровня, мы натыкаемся на кучу привилегированных команд, включающих в себя и обращение к отладочным регистрам, что на прикладном уровне не трассируется в принципе, вызывая исключение: .00010C17: 0F21C0moveax,dr0 .00010C1A: E845340000call.000014064 —↓ (2) .00010C1F: 0F21C8moveax,dr1 .00010C22: E83D340000call.000014064 —↓ (3) Листинг 3 привилегированные машинные команды в расшифровщике второго уровня Следовательно, мы должны либо модифицировать код, переписать его так, чтобы он работал в Ring-3 без нарушения функционала, либо же воспользоваться эмулятором типа x86emu (Plug-in для IDA-Pro), который лучше всего брать прямо с CVS (https://sourceforge.net/projects/ida-x86emu/), где находится самая свежая версия с кучей фиксов, сильно отличающая от последнего официального релиза (см. рис. 8). Впрочем, x86emu эмулирует ограниченный набор инструкций/регистров и потому без ручной работы здесь не обойтись. Как вариант, можно попробовать BOCHS (со встроенным отладчиком), но BOCHS _очень_ медленно работает, а с популярными отладчиками ядерного уровня Rustock.C ведет отчаянную войну и потому вовсе не факт, что «живая» отладка приведет нас к цели быстрее эмулятора. Рисунок 8 эмулятор x86emu на CVS с последними фиксами Но обращения к отладочным регистрам — это мелочи. Очень быстро мы встречаем код, взаимодействующий с ядерной памятью, в частности, следующий фрагмент (см. листинг 4) осуществляет разбор таблицы экспорта ntoskrnl.exe на предмет поиска необходимых вирусу функций. Как это он делает?! Сначала что-то грузит из указателя, полученного из FS:[38h], где на прикладном уровне находится кол-во критических секций, принадлежащих потоку (TIBCount of owned critical sections), что не дружит со здравым смыслом. Но ведь Rustock.C отнюдь не на прикладном уровне работает! А ядро здесь держит Processor Control Region (или, сокращенно, _KPCR), по смещению 38h от начала которого лежит указатель на глобальную таблицу дескрипторов прерываний (IDT), «смотрящую» непосредственно в ядро (если, конечно, ее никто не захучил). Как мы это узнали?! Раскладка ядерной памяти хорошо описана в документации на Soft-Ice, а определения самих структур можно найти в NTDDK от Microsoft или обратиться к замечательному ресурсу: «Windows Vista Kernel Structures», содержащего практически всю информацию о ядре Вислы(http://www.nirsoft.net/kernel_struct/vista/index.html). 000138C4moveax, large fs:38h; _KPCR→IDT; 000138CAaddeax, 4 000138CDmoveax, [eax] 000138CFxoral, al 000138D1stc 000138D2jbloc_10C00 00010C00subeax, 5A9D558h 00010C05subeax, 0FA562BA8h 00010C0Acmpword ptr [eax], 'ZM' 00010C0Fpushf 00010C10callsub_13667 … 00010E31cmpdword ptr [eax+ebx], 'EP' 00010E38pushf 00010E39callsub_14484 Листинг 4 прямой поиск ядра в памяти Кстати говоря, Lukasz Kwiatek, так же исследовавший Rustock.C,приводит очень похожий, но подозрительно «вылизанный» код (см. листинг 7, http://www.eset.com/threat-center/blog/?p=127), что наводит на определенные размышления: либо он дербанил другую версию, либо же прогнал код через деобфускатор. 00000261mov eax, dword ptr fs:38 00000267mov eax, [eax+4] 0000026Dxor al, al 0000026Fsub eax, 100h 00000275cmp word ptr [eax], 'ZM' 0000027Ajnz loc_26F 00000280mov bx, [eax+3Ch] 00000284and ebx, 0FFFFh 0000028Acmp dword ptr [eax+ebx], 'EP' 00000291jnz loc_26F Листинг 5 прямой поиск ядра в памяти в варианте от Lukasz Kwiatek'a Возникает резонный вопрос: как жить дальше и что с этим делать?! Спускаться в ядро как-то не хочется. И правильно! Поднять ядро на прикладной уровень намного быстрее, да и надежнее! IDA-Pro позволяет грузить намного более одного файла одновременно, что осуществляется посредством вызова функции load_nonbinary_file(), доступной из plug-in'ов, но отсутствующей в пользовательском интерфейсе. ОК, пишем plug-in, грузящий любые библиотекии драйвера, какие мы только захотим (включая ядро операционной системы), после чего останется только присобачить несложный эмулятор окружения ядра (чтобы в селекторе FS был не мусор, а валидные данные) и можно смело продолжать эмуляцию посредством x86emu. Рисунок 9 внешний вид эмулятора x86emu Ключевой фрагмент plug-in'а, работающих на версиях IDA-Pro вплоть до 4.7 включительно, приведен ниже (см. листинг 6): void idaapi run(int arg) { load_info_t *ld; warning(«plugin \»dual-load\« is called!»); ld = build_loaders_list(«KERNEL32.DLL»); load_nonbinary_file(«KERNEL32.DLL»,«KERNEL32.DLL»,«.», NEF_SEGS|NEF_RSCS|NEF_NAME|NEF_IMPS|NEF_CODE,ld); load_nonbinary_file(«NTDLL.DLL»,«NTDLL.DLL»,«.», NEF_SEGS|NEF_RSCS|NEF_NAME|NEF_IMPS|NEF_CODE,ld); qfree(ld); } Листинг 6 загрузка нескольких файлов в одну базу IDA-Pro 4.7 Начиная с IDA-Pro 4.8 прототип функции load_nonbinary_file() был злостно изменен Ильфаков без всякой заботы об обратной совместимости и старые plug-in'ы перестали работать, однако, небольшая косметическая операция (см. листинг 7) спасает операцию! void idaapi run(int arg) { load_info_t *ld; warning(«plugin \»dual-load\« is called!»); /* NOTE: KERNEL32.DLL and NTDLL.DLL has to be in the current directory!!! */ linput_t *p = open_linput(«KERNEL32.DLL»,false); fix ld = build_loaders_list(p); load_nonbinary_file(«KERNEL32.DLL», p, «.», NEF_SEGS | NEF_RSCS | NEF_NAME | NEF_IMPS | NEF_CODE, ld); close_linput(p); } Листинг 7 загрузка нескольких файлов в одну базу IDA-Pro 4.8+ С загруженным ядром, расшифровщик второго уровня снимается в IDA-Pro на ура и мы попадаем в… третий. А вот в нем… нас ждет настоящий «подарок» судьбы, ставящий в тупик и высаживающий на измену. Вирус, обращаясь к PCI-шине, извлекает оттуда параметры моста «PCI/ISA», формируя RC4 ключ на основе Device ID и Vendor ID, перебрать которые тупым Brute-Force совершенно нереально. Да и ненужно!!! Роковая ошибка создателя Rustock.C заключается в том, что производителей чипсетов (где, собственно говоря, и находится обозначенный мост) не так уж и много. Просто идем на любую достаточно полную онлайновую базу PCI-устройств (например, www.pcidatabase.com), даем ей запрос, после чего осуществляем элегантный перебор на небольшой выборке. Все! С падением последнего бастиона с вирусом можно делать все, что угодно. В частности, отломав детектор VM Ware (которая определяется через IDT), запустить его в среде виртуальной машины, наблюдая за изменениями в памяти и файловой системе. Никакие маскировочные приемы не помогут против посекторного сравнения образов виртуального жесткого диска до и после заражения. Тоже самое относиться и к дампам памяти. Вторая роковая ошибка создателя Rustock.С – отсутствие перехвата функции KeBugCheckEx, которая, собственно, и сбрасывает дамп на диск. ===== заключение ===== А вот некоторые вообще не заморачиваются с ручной распаковкой и эмуляций, запуская вируса под доброкачественным виртуализатором, с которым Rustock.C никак не сражается. Помимо SEYE эмулятора (недоступного широким массам), вполне сгодится и BOCHS, в котором (с учетом наличия исходных текстов) ничего не стоит подделать Device ID и Vendor ID, правда, мы должны заранее знать что на чипсет установлен на зараженной машине. Естественно, пользы (познавательного плана) в подобном способе запуска вируса немного. Нормальные вирусы вообще-то и без танцев с бубном запускается. Наибольший интерес представляет именно скрупулезный анализ вируса и используемых их приемов, многие их которых стоит взять на вооружение, если не на свое, так хоть на чужое, в смысле приготовиться к появлению «зверьков», оборудованных модулями, выдранными из Rustock.C и, возможно, основательно доработанными. ===== »> врезка: ссылки по теме ===== - Win32.Ntldrbot (aka Rustock.C) no longer a myth, no longer a threat: - сага о том как сотрудники DrWeb Ltd ловили Неуловимого Джо, а потом поймали и прищемили. PR, конечно, но общее представление о вирусе, переименованном в Win32.Ntldrbot, она все-таки дает (на английском языке):http://www.drweb.com/upload/6c5e138f917290cb99224a8f8226354f_1210062403_DDOCUMENTSArticales_PRDrWEB_RustockC_eng.pdf__;
(та же самая сага, только уже на русском языке — великом и могучем):
http://www.drweb.com/upload/a8601a8e66f6ff9a9c629c969482d292_1210059861_DDOCUMENTSArticales_PRDrWEB_Rustock_rus.pdf; - Rustock.C - Unpacking a Nested Doll: - животрепещущая история о том, как с вируса содрали первый слой упаковщика, чему страшно возрадовались, но застряли во втором, который не смогли пройти даже с помощью IDA-Pro (на английском языке):
http://blog.threatexpert.com/2008/05/rustockc-unpacking-nested-doll.html__; - Featured Article: Ruining the Rustock.C rumors and myths and Kaspersky Lab role: - увлекательная детективная история с разоблачением… нет, не вируса, а его создателей, на роль которых выдвигаются парни с краклаба (наанглийском): http://www.rootkit.com/newsread.php?newsid=879__; - Rustock.C - kernel mode protector (short analysis): - короткое, но самое техничное описание вируса из всех встреченных мною с описанием прохождения всех уровней шифрования (на английском языке): http://www.eset.com/threat-center/blog/?p=127__; - Rustock B preliminary analysis: - техничный анализ предыдущей версии Rustock.C (на английском языке): http://www.offensivecomputing.net/?q=node/331__; - Backdoor.Rustock.A, BKDR_RUSTOCK.A: - краткое описание вируса от компании F-Secure (на английском языке): http://www.f-secure.com/v-descs/mailbot_az.shtml__; - Top Spam Botnets Exposed: - оценки масштабности ботнета, поднятого рустоком (на английском языке): http://www.secureworks.com/research/threats/topbotnets/?threat=topbotnets__; - Rustock.C aka Ntldrbot - Small Advisory: - треп на форуме за Rustock'а и его создателей, по сути ничего интересного, но ведь затягивает же, да так, что не оторвешься (на английском языке): http://forum.sysinternals.com/forum_posts.asp?TID=14844__; - EP_X0FF and Rootkit Unhooker off to Microsoft: - и ты Брут?! и ты продался Microsoft?! печальная история на английском языке: http://www.antirootkit.com/blog/category/microsoft/__;