0x0c0de
25.09.2007, 18:56
Итак.... Представим ситуацию. Есть фаер/антитварь, ставящее хуки на нужные зловредному коду функции. И все бы ничего...
Возьмем да и снимем поставленые хуки... а нет... на функции ZwProtectVirtualMemory тоже стоит перехват=\ что тогда? с утра сегодня пришла идея сэмулировать нужную функцию... мож кому-то будет интересно. Если не будет -тему дельнете. делов-то
Посидела немного за дизасмом VirtualProtectEx и ZwProtectVirtualMemory. Я их обе сэмулирую. Значит с первой проблем вообще не возникло. Просто проследила за содержанием стека, чтобы узнать где какой параметр. Далее... Далее вызов ntdll функции, на начале которой стоит наш воображаемый хук. Пять байт затерто. А нам надо узнать номер функции
7C90DE77 n>/$ B8 86000000 MOV EAX,86
7C90DE7C |. BA 0003FE7F MOV EDX,7FFE0300
7C90DE81 |. FF12 CALL DWORD PTR DS:[EDX]
7C90DE83 \. C2 0C00 RETN 0C
7C90DE86 90 NOP
7C90DE87 90 NOP
7C90DE88 90 NOP
7C90DE89 90 NOP
7C90DE8A 90 NOP
7C90DE8B 90 NOP
7C90DE8C n>/$ B8 87000000 MOV EAX,87
7C90DE91 |. BA 0003FE7F MOV EDX,7FFE0300
7C90DE96 |. FF12 CALL DWORD PTR DS:[EDX]
7C90DE98 \. C2 1800 RETN 18
7C90DE9B 90 NOP
7C90DE9C 90 NOP
7C90DE9D 90 NOP
7C90DE9E 90 NOP
7C90DE9F 90 NOP
7C90DEA0 90 NOP
7C90DEA1 n>/$ B8 88000000 MOV EAX,88
7C90DEA6 |. BA 0003FE7F MOV EDX,7FFE0300
7C90DEAB |. FF12 CALL DWORD PTR DS:[EDX]
7C90DEAD \. C2 1400 RETN 14
Мы видим, что номера функций идут строго по порядку. Это означает, что чтобы нам вычислить адрес ZwProtectVirtualMemory надо просто посмотреть номер предыдущей функции и прибавить 1 или последующей (но тогда надо вычитать 1). Второй вариант мне больше понравился.
а тот же аутпост (в пример привожу его - это модный пример) ставит хук так
7C90EA32 n> $- E9 71DE7393 JMP wl_hook.1004C8A8 ; это поясняет мои стова относительно пяти байт
7C90EA37 . BA 0003FE7F MOV EDX,7FFE0300
7C90EA3C . FF12 CALL DWORD PTR DS:[EDX]
7C90EA3E . C2 1400 RETN 14
Значит нам потребуется вычислить номер функции. Теперь подробнее. Ищем байт 0B8, забираем двойное слово- номер функции декрементируем, вписываем значение в наш код.... Потом ищем 0BA, поступаем так же. По поводу записи непосредственно в секцию кода. VirtualProtect тут вызывать тоже не надо. Я установила характеристики секции в 0E0000020H, поэтому все в порядке=)
.386
.model flat, stdcall
include kernel32.inc
include windows.inc
includelib kernel32.lib
.data
ntdl_ db "ntdll.dll",0
vprotect db "ZwProtectVirtualMemory",0
func_ dword ?
.const
.code
system_call proc
mov eax,0 ; сюда мы запишем номер функции
mov edx,0
call dword ptr [edx] ; KiFastSystemCall
retn 14h ; количество передаваемых параметров я знаю точно
system_call endp
emulator_ proc ; эмуляция VirtualProtectEx
local old_protect:dword
local size_c:dword
local address:dword
lea eax,old_protect
push eax
push 40h ; тип протекта запись-чтение-исполнение
mov size_c,10
lea eax,size_c
push eax
push func_ ; на ней же и протестим=)
pop address
lea eax,address
push eax
push -1 ; пишем в своем процессе, поэтому -1
call system_call
mov esi,func_
mov byte ptr[esi],8 ; проверяем на запись. ошибки нет=)
ret
emulator_ endp
Main:
invoke GetModuleHandleA,offset ntdl_
invoke GetProcAddress,eax,offset vprotect
test eax,eax
je ext_
mov func_,eax
add eax,4 ; пять байт мы смело пропускаем. тут четыре, да ниже inc - итого 5)
loo:
inc eax
cmp byte ptr [eax],0b8h ; начало инструкции mov eax,xxxx. для надежности можно проверять длину инструкции. должно быть 5 байт. в этом нам поможет
; дизассемблер длин, его прикрутить вообще не проблема
jnz loo
inc eax
mov edx,dword ptr[eax]
mov edi,offset system_call
dec edx
inc edi
mov dword ptr[edi],edx
add eax,5
add edi,5
mov edx,dword ptr[eax]
mov dword ptr[edi],edx
call emulator_
ext_:
invoke ExitProcess, NULL
end Main
Не забудьте установить характеристики секции кода данной проги в 0E0000020H!
Вообще наверняка есть способ лучше..
Возьмем да и снимем поставленые хуки... а нет... на функции ZwProtectVirtualMemory тоже стоит перехват=\ что тогда? с утра сегодня пришла идея сэмулировать нужную функцию... мож кому-то будет интересно. Если не будет -тему дельнете. делов-то
Посидела немного за дизасмом VirtualProtectEx и ZwProtectVirtualMemory. Я их обе сэмулирую. Значит с первой проблем вообще не возникло. Просто проследила за содержанием стека, чтобы узнать где какой параметр. Далее... Далее вызов ntdll функции, на начале которой стоит наш воображаемый хук. Пять байт затерто. А нам надо узнать номер функции
7C90DE77 n>/$ B8 86000000 MOV EAX,86
7C90DE7C |. BA 0003FE7F MOV EDX,7FFE0300
7C90DE81 |. FF12 CALL DWORD PTR DS:[EDX]
7C90DE83 \. C2 0C00 RETN 0C
7C90DE86 90 NOP
7C90DE87 90 NOP
7C90DE88 90 NOP
7C90DE89 90 NOP
7C90DE8A 90 NOP
7C90DE8B 90 NOP
7C90DE8C n>/$ B8 87000000 MOV EAX,87
7C90DE91 |. BA 0003FE7F MOV EDX,7FFE0300
7C90DE96 |. FF12 CALL DWORD PTR DS:[EDX]
7C90DE98 \. C2 1800 RETN 18
7C90DE9B 90 NOP
7C90DE9C 90 NOP
7C90DE9D 90 NOP
7C90DE9E 90 NOP
7C90DE9F 90 NOP
7C90DEA0 90 NOP
7C90DEA1 n>/$ B8 88000000 MOV EAX,88
7C90DEA6 |. BA 0003FE7F MOV EDX,7FFE0300
7C90DEAB |. FF12 CALL DWORD PTR DS:[EDX]
7C90DEAD \. C2 1400 RETN 14
Мы видим, что номера функций идут строго по порядку. Это означает, что чтобы нам вычислить адрес ZwProtectVirtualMemory надо просто посмотреть номер предыдущей функции и прибавить 1 или последующей (но тогда надо вычитать 1). Второй вариант мне больше понравился.
а тот же аутпост (в пример привожу его - это модный пример) ставит хук так
7C90EA32 n> $- E9 71DE7393 JMP wl_hook.1004C8A8 ; это поясняет мои стова относительно пяти байт
7C90EA37 . BA 0003FE7F MOV EDX,7FFE0300
7C90EA3C . FF12 CALL DWORD PTR DS:[EDX]
7C90EA3E . C2 1400 RETN 14
Значит нам потребуется вычислить номер функции. Теперь подробнее. Ищем байт 0B8, забираем двойное слово- номер функции декрементируем, вписываем значение в наш код.... Потом ищем 0BA, поступаем так же. По поводу записи непосредственно в секцию кода. VirtualProtect тут вызывать тоже не надо. Я установила характеристики секции в 0E0000020H, поэтому все в порядке=)
.386
.model flat, stdcall
include kernel32.inc
include windows.inc
includelib kernel32.lib
.data
ntdl_ db "ntdll.dll",0
vprotect db "ZwProtectVirtualMemory",0
func_ dword ?
.const
.code
system_call proc
mov eax,0 ; сюда мы запишем номер функции
mov edx,0
call dword ptr [edx] ; KiFastSystemCall
retn 14h ; количество передаваемых параметров я знаю точно
system_call endp
emulator_ proc ; эмуляция VirtualProtectEx
local old_protect:dword
local size_c:dword
local address:dword
lea eax,old_protect
push eax
push 40h ; тип протекта запись-чтение-исполнение
mov size_c,10
lea eax,size_c
push eax
push func_ ; на ней же и протестим=)
pop address
lea eax,address
push eax
push -1 ; пишем в своем процессе, поэтому -1
call system_call
mov esi,func_
mov byte ptr[esi],8 ; проверяем на запись. ошибки нет=)
ret
emulator_ endp
Main:
invoke GetModuleHandleA,offset ntdl_
invoke GetProcAddress,eax,offset vprotect
test eax,eax
je ext_
mov func_,eax
add eax,4 ; пять байт мы смело пропускаем. тут четыре, да ниже inc - итого 5)
loo:
inc eax
cmp byte ptr [eax],0b8h ; начало инструкции mov eax,xxxx. для надежности можно проверять длину инструкции. должно быть 5 байт. в этом нам поможет
; дизассемблер длин, его прикрутить вообще не проблема
jnz loo
inc eax
mov edx,dword ptr[eax]
mov edi,offset system_call
dec edx
inc edi
mov dword ptr[edi],edx
add eax,5
add edi,5
mov edx,dword ptr[eax]
mov dword ptr[edi],edx
call emulator_
ext_:
invoke ExitProcess, NULL
end Main
Не забудьте установить характеристики секции кода данной проги в 0E0000020H!
Вообще наверняка есть способ лучше..