Главная | Программы | Статьи | Заработай 100$ и более

Гостевая книга

 
Статьи: Исследование вируса Win.32.Friendly и лечение заражённых им файлов 30.04.2006

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

Для понимания всего нижеописанного понадобятся:
1) Знание ассемблера
2) Знание C++
3) Знание API
4) Знание структуры PE файла (хотя бы общее)
5) Отладчик (хватит OllyDebug)
6) MicroSoft Visual Studio 200x

Содержание :)
1) Исследование заражённых файлов, работы вируса и Написание программы для лечения заражённых файлов
2) Выводы, заключения, радость за наш мозг
 

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

Чтобы написать программу, которая будет исправлять заражённые файлы надо для начала (надеюсь вы уже догадались):
1) Искать эти файлы среди других ( а вы думали ручками будем задавать каждый отдельно? неа, учитесь на моих ошибках ) => надо искать признаки, выдающие заражённые файлы
2) Проверить, не забирает ли вирус код программы. Если да ( как у нас ), будем искать способы его обнаружения. Также надо понять способ переход управления из вируса в программу.

Пока в принципе хватит.

Для начала посмотрим на точку входа программы, заражённой вирусом:

00407796 >/$ RCL ECX,1B
00407799 |. SUB AL,6D
0040779B |. OR EDX,ACC599F1
004077A1 |. ADC EDI,EAX
004077A3 |. CMP AL,9D
004077A5 |. JNB SHORT config.004077B6
004077A7 |. XADD ESI,EAX
004077AA |. ADC EAX,EBX
004077AC |. SUB EAX,ECX
004077AE |. AND EDI,1F
004077B1 |. INC EBP
004077B2 |. RCR EDI,11
004077B5 |. DEC ECX
004077B6 |> DEC EBX
004077B7 |. XADD EDI,ECX
004077BA |. MOV ESI,0CADFA44
004077BF |. MOV ECX,F3F0B22F
004077C4 |. MOV EBX,EBP
004077C6 |. XCHG EAX,ECX
004077C8 |. XOR EBX,EAX
004077CA |. SUB EAX,EBX
004077CC |. ADC ECX,EBP
004077CE |. PUSH config.00417000
004077D3 |. CMP ESP,844660E
004077D9 |. JG SHORT config.004077DF
004077DB |. SUB EDI,0E
004077DE |. DEC EAX
004077DF |> ADD EAX,E60D1631
004077E4 \. RETN

Другой пример:

00484001 > XCHG AH,BL
00484003 MOV EDI,ECX
00484005 SAR EBX,18
00484008 SBB EAX,94D657FD
0048400D JS SHORT fearr.00484014
0048400F NOP
00484010 MOVZX EAX,SI
00484013 NOP
00484014 ADD EAX,93F74BD8
00484019 RCL EBP,19
0048401C SUB EDI,872D8B18
00484022 AND AH,1C
00484025 SBB ECX,9
00484028 MOVZX EDI,DL
0048402B XCHG AL,DL
0048402D PUSH fearr.00488000
00484032 XADD ECX,EDI
00484035 SHR AH,0C
00484038 AND EDI,5FCB2508
0048403E JNS SHORT fearr.00484044
00484040 XOR EAX,ECX
00484042 ROL EAX,1
00484044 OR CL,AL
00484046 RETN

Ну и последний:

00AA4330 > ADD EDX,EAX
00AA4332 MOVZX EBP,CX
00AA4335 INC ECX
00AA4336 PUSH FEAR.00D98000
00AA433B ADC EDX,ESI
00AA433D OR EDI,ECX
00AA433F OR EBX,ECX
00AA4341 AND EDI,EDX
00AA4343 SUB EDX,DC6F85E2
00AA4349 ADD EBP,0C
00AA434C OR EDI,13
00AA434F ADD EDI,10
00AA4352 DEC EDI
00AA4353 JS SHORT FEAR.00AA4360
00AA4355 AND EDX,ESI
00AA4357 MOV ECX,4309562F
00AA435C DEC EBX
00AA435D ROL ESI,1D
00AA4360 ROR ESI,0B
00AA4363 SBB ESI,1B
00AA4366 DEC ECX
00AA4367 DEC EBX
00AA4368 AND EAX,A406A645
00AA436D ADD EDX,3
00AA4370 ADD AL,5
00AA4372 OR ECX,6
00AA4375 ADC EBP,18
00AA4378 SBB EAX,63FAA4C9
00AA437D SBB ESI,ECX
00AA437F RETN

Выводы:
1) Код программы забирается, т.к. не заражённые программы начинаются с тех же адресов, но код там другой
2) Замещающий код непредсказуем ( пока )
3) Длина замещающего кода непостоянна

С первым всё понятно, просто будем искать в работе вируса исправление украденных байтов.
Второе и третье не предсказуемы. Отсюда получается, что предсказать вроде как не получается. Но пытливые умы прекрасно видят что:
1) Команд, работающих со стеком 2, всё остальное или с регистром, или прыжки
2) Переход на код вируса осуществляется конструкцией.

tratata
...
push xxxxxxxx
...
tratata
...
retn

где tratata в начале и в конце может и не быть, начинаясь сразу с push xxxxxxxx

Это нам даёт возможный вариант определения наличия вируса.
На стоячей программе можем найти лишь ещё один интересный момент - код передаётся на последнюю секцию. Далее программу придётся изучать пошагово...
В месте, куда ведёт переход, очень много команд, которые нам для разбора принципа работы вируса параллельны. Ищите ПРИМЕРНО такую строчку:

004172E9 XOR DWORD PTR DS:[EBX],7BCDF907

Примерно потому, как вирус использует метаморфизм, т.е. код разный, а выполняет функцию одинаковую. В данном случае метаморфизм связан с изменяемым регистром ( он может быть и EBX, ECX, EAX, EDX ) и с параметром XOR ( в данном случае число у нас 7BCDF907,  но при следующих заражениях оно будет меняться ), также будет меняться адрес этой строки относительно начала этого кода, то-есть в нашем случае 004172E9 - 00417000 = 2E9, но в другом файле будет не так. Но что собственно делает этот код? Он просто расшифровывает код самого вируса, вредоносный код. Вот конец цикла:

0041753A CMP EBX,config.0041902C
00417540 JNZ config.0041723B


Делаем точку останова за прыгом, топаем по шагам и приходим сюда:

004176A8 PUSHFD
004176A9 PUSHFD
004176AA PUSHAD
004176AB CALL config.004176B0


Смотрим теперь сюда:

004176BD CALL config.004177C1

А там:

004177C8 CMP DWORD PTR DS:[EAX],-1
004177CB JE SHORT config.004177D1
004177CD MOV EAX,DWORD PTR DS:[EAX]
004177CF ^JMP SHORT config.004177C8
004177D1 MOV EAX,DWORD PTR DS:[EAX+4]
004177D4 XOR AX,AX
004177D7 CMP WORD PTR DS:[EAX],5A4D
004177DC JE SHORT config.004177E5
004177DE SUB EAX,10000 ; UNICODE "=::=::\"
004177E3 ^JMP SHORT config.004177D7
004177E5 MOV ECX,DWORD PTR DS:[EAX+3C]


Здесь везде уже описанным способом находится адрес библиотеки kernel32.dll через SEH без использования апи. Принцип - полседний SEH указывет на -1 (цепочка кончилась), а обработчик в нём стандартный системный из kernel32.dll. Дальше, т.к. модули грузятся с выравниваниями, вычитая по 10000 от адреса обработчика исключений находится адрес библиотеки (5A4D начало любого приложения или библиотеки). Смотрим далее:

004177E5 MOV ECX,DWORD PTR DS:[EAX+3C]
004177E8 ADD ECX,EAX
004177EA MOV ECX,DWORD PTR DS:[ECX+78]
004177ED ADD ECX,EAX
004177EF PUSH EDI
004177F0 PUSH ECX
004177F1 PUSH EAX
004177F2 MOV EDX,DWORD PTR DS:[ECX+20]
004177F5 ADD EDX,EAX
004177F7 XOR EBX,EBX
004177F9 XOR EAX,EAX
004177FB XOR ECX,ECX
004177FD DEC ECX
004177FE MOV EDI,ESI
00417800 REPNE SCAS BYTE PTR ES:[EDI]
00417802 NOT ECX
00417804 POP EAX
00417805 DEC ECX
00417806 JE SHORT config.0041783B
00417808 INC ECX
00417809 PUSH ESI
0041780A PUSH ECX
0041780B MOV EDI,DWORD PTR DS:[EDX+EBX*4] Переходит к
0041780E ADD EDI,EAX
                      следующей
00417810 REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:>   
Проверяет имя искомой функции и в библиотеке
00417812 JE SHORT config.00417819
00417814 INC EBX
00417815 POP ECX
00417816 POP ESI
00417817 ^JMP SHORT config.00417809


Здесь вирус получает таблицу экспорта kernel32.dll и ищет функции по их имени без использования GetProcAddress. Здесь всё понятно. Нам интересны функции CreateThread и FindFirstFile

004176C8 PUSH EAX
004176C9 PUSH ESP
004176CA PUSH 40
004176CC PUSH 50
004176CE PUSH DWORD PTR SS:[EBP+1914]
004176D4 CALL NEAR DWORD PTR SS:[EBP+151C] ; kernel32.VirtualProtect
004176DA POP EAX
004176DB MOV EDI,DWORD PTR SS:[EBP+1914]
004176E1 LEA ESI,DWORD PTR SS:[EBP+1918]
004176E7 MOV ECX,50
004176EC REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]


Здесь
вирус разрешает запись в секцию кода (VirtualProtect), т.к. строками ниже он возвращает настоящее начало программы ( 50 байтов ). Запоминаем это место. Пока что информации нам маловато. Ждём любое запоминающееся событие...

004177B0 50 PUSH EAX
004177B1 54 PUSH ESP
004177B2 50 PUSH EAX
004177B3 52 PUSH EDX
004177B4 53 PUSH EBX
004177B5 50 PUSH EAX
004177B6 50 PUSH EAX
004177B7 FF95 18150000 CALL NEAR DWORD PTR SS:[EBP+1518] ; kernel32.CreateThread

Этот CreateThread запускает механизм размножения вируса. Давайте немного поблуждаем там...

00417708 PUSHAD
00417709 MOV EBP,DWORD PTR SS:[ESP+24] ; config.004176B0
0041770D CALL config.00417D10 //

Здесь находятся все остальные необходимые API

Далее ищутся жесткие локальные диски и создаются потоки тем же CreateThread для их инфицирования.
Эти функции составляют маску (например C:\*.exe) и начинают искать:

00417B6D PUSH EAX
00417B6E PUSH DWORD PTR SS:[EBP+8]
00417B71 CALL <config.strcat>
00417B76 LEA EAX,DWORD PTR DS:[EBX+1794]
00417B7C PUSH EAX
00417B7D 08 PUSH DWORD PTR SS:[EBP+8]
00417B80 CALL <config.strcat>
00417B85 PUSH DWORD PTR SS:[EBP+C]
00417B88 08 PUSH DWORD PTR SS:[EBP+8]
00417B8B CALL NEAR DWORD PTR DS:[EBX+1538] ; kernel32.FindFirstFileA

Когда файл находится опять составив поный путь к нему происходит следующая интересная проверка:

00417DE7 PUSH EBP
00417DE8 MOV EBP,ESP
00417DEA MOV EAX,DWORD PTR SS:[EBP+C]
00417DED MOV EAX,DWORD PTR DS:[EAX+2C] // Первые 4 буквы имени файла
00417DF0 AND EAX,DFDFDFDF// типа
strupr, все 4 буквы большие
00417DF5 CMP EAX,45575244
// число представляет из себя буквы DRWE
00417DFA JE SHORT config.00417E4D
00417DFC CMP EAX,44495053 //SPID
00417E01 JE SHORT config.00417E4D
00417E03 CMP EAX,54534E49 //INST
00417E08 JE SHORT config.00417E4D
00417E0A CMP EAX,55544553 //SETU
00417E0F JE SHORT config.00417E4D
00417E11 AND EAX,0FFFFFF
00417E16 CMP EAX,56414B //KAV
00417E1B JE SHORT config.00417E4D
00417E1D PUSH DWORD PTR SS:[EBP+8]
00417E20 CALL config.00417E51
00417E25 TEST EAX,EAX
00417E27 JNZ SHORT config.00417E4D
00417E29 PUSH DWORD PTR SS:[EBP+C]
00417E2C PUSH DWORD PTR SS:[EBP+8]
00417E2F CALL config.00417E8B
00417E34 TEST EAX,EAX
00417E36 JNZ SHORT config.00417E4D
00417E38 MOV EDX,DWORD PTR SS:[EBP+8]
00417E3B CMP BYTE PTR DS:[EDX],41
00417E3E JE SHORT config.00417E4D
00417E40 PUSH EAX
00417E41 PUSH 4E20
00417E46 CALL NEAR DWORD PTR DS:[EBX+1520]
00417E4C POP EAX
00417E4D LEAVE
00417E4E RETN 8

Обратите внимание, вирус проверяет, чтобы имя файла не было одним из выше описанных, и имена некоторые весьма интересны:
SPID(ER) -
это модуль DoctorWeb'a
DRWE(B) -
это сам DoctorWeb
KAV -
касперский ав.
Так вот что интересно - нет упоминаний ни о NOD ни о PANDA, что наталкивает на мысль, что автор из местных земель :)), но это только предположение!!!
Ладно, теперь пробуем поставить бряку на CreateFile. Проследив немного приходим к такому месту:

00417EE9 MOV DWORD PTR SS:[EBP-C],EAX
00417EEC CMP WORD PTR DS:[EAX],5A4D
00417EF1 JNZ config.004180C3
00417EF7 CMP WORD PTR DS:[EAX+18],40
00417EFC JNZ config.004180C3
00417F02 MOV EAX,DWORD PTR DS:[EAX+3C]
00417F05 MOV DWORD PTR SS:[EBP-1C],EAX
00417F08 ADD EAX,DWORD PTR SS:[EBP-C]
00417F0B CMP DWORD PTR DS:[EAX],4550
00417F11 JNZ config.004180C3
00417F17 CMP BYTE PTR DS:[EAX-1],2A
00417F1B JE config.004180BA


Это типичная проверка PE-файла, но есть здесь одно подозрительное место:
00417F17 CMP BYTE PTR DS:[EAX-1],2A


Если истина, то файл закрывается и поиск продолжается => это есть признак заражённости для самого вируса. Его я не использую, итак наличие вируса определяем точно.
Всё, теперь отладчик можно закрывать.
Отлично, теперь подведём итог. Что поняли для обнаружения вируса:
1)
В начале программы должны быть 2 команды: push xxxxxxxx и retn, никаких call, pop, push eax и др регистры.
2) xxxxxxxx должен быть быть в пределах последней секции.

Что поняли для восстановления настоящего начала программы:
1) При вызове CreateThread код уже восстановлен.

Теперь основной вопрос: восстановитель файлов делать динамический (то есть испольнять, но под контролем ) или эмулирующий.


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

Эмулирующий восстановитель:
-
придётся писать эмулятор процессора :)) Пусть далеко не для всех функций, но и того, что надо, хватит надолго.
+
из под контроля вирусу не выйти, т.к. на самом деле не он исполняется, а мы исполняем его

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

Прежде всего остановимся на определении вируса.  Закономерностей математических (байт AA на расстоянии x от BB, а ret на расстоянии Y от начала) нету, поэтому, IMHO самый простой вариант - взять бесплатный дизассемблер (в нашем случае CADT) и на основе него сделать простенький анализатор мнемоник. Запускать программу для этого не понадобится.

В принципе
инфицированные файлы
идентифицируются элементарно. Теперь как фиксить. Мы помним, что при вызове CreateThread байты в начале программы уже исправлены. Надо этим воспользоваться, т.е. остановить программу на CreateThread и заменить байты. Как остановить в этот момент, спросите Вы? Тут на помощь нам приходят Debug Api, набор функций для отладки приложений. Они позволяют отслеживать работу программы, менять данные, читать и писать из/в процесс, приостанавливать и т.д.. Таким образом мы напишем простенький отладчик.


Остальось дело техники: реализовать задуманное. Результат можно взять здесь