Поводом для написания этой статьи стала необходимость лечения вируса Win32.Friendly, принесённого из института, т.к. после его разгула приходилось ручками перед запуском программ просматривать, не заражён ли файлик. Так фиксились почти все программы. К сожалению именно почти. После запуска нефиксенного все труды слетали. Но главный неприятный момент-автор решил себя не утруждать проверкой наличия оверлея, благодаря чему все сетапки, попавшие под это произведение кривых ручек, благополучно портятся без возможности восстановления. Вот поэтому решил писать программку для автоматизации процесса. Делаю это публично, потому как это может кого-нибудь заинтересовать. Для понимания всего нижеописанного понадобятся: 1) Знание ассемблера 2) Знание C++ 3) Знание API 4) Знание структуры PE файла (хотя бы общее) 5) Отладчик (хватит OllyDebug) 6) MicroSoft Visual Studio 200x Содержание 1) Исследование заражённых файлов, работы вируса и Написание программы для лечения заражённых файлов 2) Выводы, заключения, радость за наш мозг Исследование заражённых файлов, работы вируса и Написание программы для лечения заражённых файлов Чтобы написать программу, которая будет исправлять заражённые файлы надо для начала (надеюсь вы уже догадались): 1) Искать эти файлы среди других ( а вы думали ручками будем задавать каждый отдельно? неа, учитесь на моих ошибках ) => надо искать признаки, выдающие заражённые файлы 2) Проверить, не забирает ли вирус код программы. Если да ( как у нас ), будем искать способы его обнаружения. Также надо понять способ переход управления из вируса в программу. Пока в принципе хватит. Для начала посмотрим на точку входа программы, заражённой вирусом: Code: 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 Другой пример: Code: 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 Ну и последний: Code: 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 Это нам даёт возможный вариант определения наличия вируса. На стоячей программе можем найти лишь ещё один интересный момент - код передаётся на последнюю секцию. Далее программу придётся изучать пошагово... В месте, куда ведёт переход, очень много команд, которые нам для разбора принципа работы вируса параллельны. Ищите ПРИМЕРНО такую строчку: Code: 004172E9 XOR DWORD PTR DS:[EBX],7BCDF907 Примерно потому, как вирус использует метаморфизм, т.е. код разный, а выполняет функцию одинаковую. В данном случае метаморфизм связан с изменяемым регистром ( он может быть и EBX, ECX, EAX, EDX ) и с параметром XOR ( в данном случае число у нас 7BCDF907, но при следующих заражениях оно будет меняться ), также будет меняться адрес этой строки относительно начала этого кода, то-есть в нашем случае 004172E9 - 00417000 = 2E9, но в другом файле будет не так. Но что собственно делает этот код? Он просто расшифровывает код самого вируса, вредоносный код. Вот конец цикла: Code: 0041753A CMP EBX,config.0041902C 00417540 JNZ config.0041723B Делаем точку останова за прыгом, топаем по шагам и приходим сюда: Code: 004176A8 PUSHFD 004176A9 PUSHFD 004176AA PUSHAD 004176AB CALL config.004176B0 Смотрим теперь сюда: Code: 004176BD CALL config.004177C1 А там: Code: 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 начало любого приложения или библиотеки). Смотрим далее: Code: 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 Code: 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 байтов ). Запоминаем это место. Пока что информации нам маловато. Ждём любое запоминающееся событие... Code: 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 запускает механизм размножения вируса. Давайте немного поблуждаем там... Code: 00417708 PUSHAD 00417709 MOV EBP,DWORD PTR SS:[ESP+24] ; config.004176B0 0041770D CALL config.00417D10 // Здесь находятся все остальные необходимые API Далее ищутся жесткие локальные диски и создаются потоки тем же CreateThread для их инфицирования. Эти функции составляют маску (например C:\*.exe) и начинают искать: Code: 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 Когда файл находится опять составив поный путь к нему происходит следующая интересная проверка: Code: 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. Проследив немного приходим к такому месту: Code: 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, набор функций для отладки приложений. Они позволяют отслеживать работу программы, менять данные, читать и писать из/в процесс, приостанавливать и т.д.. Таким образом мы напишем простенький отладчик. Остальось дело техники: реализовать задуманное. Результат можно взять здесь ЗЫ:были проблемы с аспром. ыв принципе нормальные проги фиксит нормально. но сырая лечилка, была написана за день. http://ifolder.ru/1312913 pass: virus ВНИМАНИЕ: config.exe пример вируса. не запускайте
Хотелось бы заметить, что иногда очень удобно для экономии времени и сил перед тем как заняться реверсингом, прогнать заразу через песочницу (sandbox). Примеры: sandboie, CWSandbox, norman.