Comments 38
интересно, как к вашим внедрениям в чужие процессы относятся антивирусы? :-)
+4
Microsoft Security Essentials и Symantec молчат. Про других не знаю :) Вообще способ более чем легальный…
+3
А чего им ругаться, взять тот же PuntoSwitcher, Lingvo, они внедряют свои dll в процессы и ничего, все нормально. Внедрить dll это ничего страшного по сути. Но на это точно ругается Outpost, на любые внедрения.
+3
Совсем никудышние антивирусы, если не ругаются.
0
Один из самых интересных постов на хабре за последнее время, спасибо.
+11
Для Firefox и Chromium можно скомпилировать свою версию браузера. Преимущество такого способа — можно узнать по дороге много нового о их внутренней структуре. Недостаток — нужно перекомпилировать браузер каждые 6 недель.
+1
Строго говорят для них же можно написать расширения, которые не будут иметь проблем с HTTPS например. Примером тому множество расширений для YouTube с возможностью скачивания видео. Да и тот же Adblock работает по схожему принципу, только вместо отдельных пакетов он получает страницу целиком. Но было все же интереснее попробовать более-менее универсальный метод…
+1
А можно где-то подобный софт поиметь? Может подскажете уже готовые реализации перехватчиков потокового видео, которые его отсылают, в идеале, в WMP? И можно смотреть не в браузере, а в плейере, ну и творить с ним что хочешь, например отсылать изображение на экран Smart TV :)
0
Честно говоря я не знаю готового софта для этих целей. Написать его с нуля не такая уж и тяжелая работа, тем более что для WMP будет достаточно привинтить YouTube каталоги к DLNA серверу типа Twonky и объявить себя медиа сервером. SmartTV по умолчанию работает с DLNA серверами на ура. Но я пока не готов что-то подобное делать из-за отсутствия времени.
0
x64?
+2
Есть еще мало знакомая в околохакерских кругах технология — LSP (Wnisock SPI).
Используя ее можно избежать использования NDIS драйвера и нормально работать в ring3, без танцев с бубном.
Кстати странно, что создатели Jaksta не знаю про WinPcap.
Используя ее можно избежать использования NDIS драйвера и нормально работать в ring3, без танцев с бубном.
Кстати странно, что создатели Jaksta не знаю про WinPcap.
+2
WinPcap/libpcap?
Анализ — фильтр — дамп?
Анализ — фильтр — дамп?
0
Автор, как давно Вы это всё писали? Вы в курсе, что последний Хром все процессы вкладок и плагинов держит в песочнице с Untrusted integrity level и многие пляски с внедрением DLL-ок и хуками перестали работать?
0
Писал я это все не далее как вчера, 31 августа 2012 года. Проверял в последней версии Google Chrome Beta, SRWare Iron и IE 9. Видимо дело в том что плагины и расширения в данном случае не играют существенной роли, независимо от того где их хром держит…
+3
Вынужден сильно поругать Ваш метод перехвата, хоть сама реализация и не является главной темой статьи.
1. Самый кошмар конечно в том, что происходит постоянная перезапись кода в контролируемых функциях. Вы задумывались что произойдёт, если какой-то параллельный поток в это же самое время будет выполнять код функции в затираемом месте?
2. Даже если от постоянной перезаписи избавиться, то остаётся ещё узкое место: однократная установка хука. По той же причине, описанной в предыдущем пункте, приложение может вылететь. Для того, чтобы решить данную проблему, Вы можете перечислять потоки и замораживать все, кроме своего, с помощью SuspendThread().
3. Правильная организация перехвата такова: Вы переносите несколько первых инструкций перехватываемой функции в заранее подготовленное место, после последней инструкции добавляете jmp на Ваш код-обработчик (получается эдакий переходник). В конце кода-обработчика jmp на первую незатёртую инструкцию оригинального кода. Ну и в начало перехватываемой функции лепите прыжок на «переходник». Это перехват до выполнения. Перехват после выполнения делается схожим образом, но там мы должны подменить адрес возврата на стеке в нашем «переходнике».
4. Нужно понимать, что не всякую функцию можно перехватить таким образом. К примеру, если перемещаемые инструкции будут содержать прыжки по относительным адресам, то после перемещения такой код перестанет быть рабочим. Благо, почти все WinAPI-функции содержат стандартный пролог в 5-6 байт, который можно смело двигать куда угодно.
1. Самый кошмар конечно в том, что происходит постоянная перезапись кода в контролируемых функциях. Вы задумывались что произойдёт, если какой-то параллельный поток в это же самое время будет выполнять код функции в затираемом месте?
2. Даже если от постоянной перезаписи избавиться, то остаётся ещё узкое место: однократная установка хука. По той же причине, описанной в предыдущем пункте, приложение может вылететь. Для того, чтобы решить данную проблему, Вы можете перечислять потоки и замораживать все, кроме своего, с помощью SuspendThread().
3. Правильная организация перехвата такова: Вы переносите несколько первых инструкций перехватываемой функции в заранее подготовленное место, после последней инструкции добавляете jmp на Ваш код-обработчик (получается эдакий переходник). В конце кода-обработчика jmp на первую незатёртую инструкцию оригинального кода. Ну и в начало перехватываемой функции лепите прыжок на «переходник». Это перехват до выполнения. Перехват после выполнения делается схожим образом, но там мы должны подменить адрес возврата на стеке в нашем «переходнике».
4. Нужно понимать, что не всякую функцию можно перехватить таким образом. К примеру, если перемещаемые инструкции будут содержать прыжки по относительным адресам, то после перемещения такой код перестанет быть рабочим. Благо, почти все WinAPI-функции содержат стандартный пролог в 5-6 байт, который можно смело двигать куда угодно.
+5
Критика справедливая и принимается. Я не зря написал что перезапись кода это недостаток именно данного примера. В данном посте мне стоило некоторых усилий держаться в рамках научно-популярной статьи и не сорваться в хардкор. К сожалению если бы я стал копать в сторону анализа инструкций, то хардкора было бы не избежать. Уверяю Вас что у меня есть другая реализация, очень похожая на ту что Вы описали.
0
Годная статья для хабра. stpark, смотрите сорцы хукера зевса, там более корректно выппонено
+1
Лютый overkill.
1. Для записи видео достаточно прописать в браузере свой прокси-сервер и из него сейвить все ответы.
2. Для Firefox API расширений позволяет ловить все HTTP-реквесты и респонсы в своём javascript-фильтре.
Второй способ, в отличие от хуковского и проксёвого, пробивает https.
Видимо, автор не решал задачу сохранения видео, а захотел поиграться с системой.
1. Для записи видео достаточно прописать в браузере свой прокси-сервер и из него сейвить все ответы.
2. Для Firefox API расширений позволяет ловить все HTTP-реквесты и респонсы в своём javascript-фильтре.
Второй способ, в отличие от хуковского и проксёвого, пробивает https.
Видимо, автор не решал задачу сохранения видео, а захотел поиграться с системой.
+1
Просто любопытно. Почему вы не произвели внедрение через CreateRemoteThread? Мне кажется этот вариант был бы лучше глобального хука.
0
VirtualAllocEx в чужом процессе + WriteProcessMemory + CreateRemoteThread.
Плюсы:
— подгрузить код можно избирательно, а не во все процессы
— можно обойтись без DLL на диске и в списке загруженных DLL процесса
Минусы:
— антивирусы сильнее ругаются на WriteProcessMemory, чем на хуки
— сложнее реализовать
Сложности в том, что внедряемому коду надо настроить relocations на адрес внедрения, настроить импорты из зависимых DLL (из-за ASLR заранее неизвестно, где системные DLL). То есть, реализовать часть DLL-загрузчика.
Если внедряемый код маленький (загрузка DLL и запуск функции оттуда), его настройка упрощается, но теряется второй плюс этого метода.
Плюсы:
— подгрузить код можно избирательно, а не во все процессы
— можно обойтись без DLL на диске и в списке загруженных DLL процесса
Минусы:
— антивирусы сильнее ругаются на WriteProcessMemory, чем на хуки
— сложнее реализовать
Сложности в том, что внедряемому коду надо настроить relocations на адрес внедрения, настроить импорты из зависимых DLL (из-за ASLR заранее неизвестно, где системные DLL). То есть, реализовать часть DLL-загрузчика.
Если внедряемый код маленький (загрузка DLL и запуск функции оттуда), его настройка упрощается, но теряется второй плюс этого метода.
0
Я не стал возиться с CreateRemoteThread() из за соображений наглядности. Глобальный хук это самое простое решение не требующее возни с чужим процессом извне. Чтобы избежать дополнительной возни с релокациями и импортами есть более простое решение. Делается оно так:
1. Открываем процесс на запись:
2. Резервируем кусок памяти для имени подгружаемой DLL:
3. Пишем туда собственно имя:
4. Делаем трюк с kernel32.dll — он всегда грузится по одному и тому же адресу в разных процессах:
FARPROC pLoadLibrary = GetProcAddress(GetModuleHandle(«Kernel32»), «LoadLibraryA»);
5. Запускаем поток:
HANDLE ht = CreateRemoteThread(hp, NULL, 0, (LPTHREAD_START_ROUTINE) pLoadLibrary,
pLibName, 0, NULL);
После этого ждем выхода и все дела. DLL точно так же прогрузится в чужой процесс и поставит там хуки.
1. Открываем процесс на запись:
HANDLE hp = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, <ИДЕНТИФИКАТОР ПРОЦЕССА>);
2. Резервируем кусок памяти для имени подгружаемой DLL:
void *pLibName = VirtualAllocEx(hp, NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);
3. Пишем туда собственно имя:
WriteProcessMemory(hp, pLibName, (void *) <ИМЯ DLL>, MAX_PATH, NULL)
4. Делаем трюк с kernel32.dll — он всегда грузится по одному и тому же адресу в разных процессах:
FARPROC pLoadLibrary = GetProcAddress(GetModuleHandle(«Kernel32»), «LoadLibraryA»);
5. Запускаем поток:
HANDLE ht = CreateRemoteThread(hp, NULL, 0, (LPTHREAD_START_ROUTINE) pLoadLibrary,
pLibName, 0, NULL);
После этого ждем выхода и все дела. DLL точно так же прогрузится в чужой процесс и поставит там хуки.
0
Это работало на XP.
В Windows 7 по умолчанию в каждом процессе свой адрес kernel32.dll, поэтому GetModuleHandle(«kernel32») в процессе, выполняющем внедрение, бесполезен
В Windows 7 по умолчанию в каждом процессе свой адрес kernel32.dll, поэтому GetModuleHandle(«kernel32») в процессе, выполняющем внедрение, бесполезен
0
Ок. Тогда придется-таки копаться в IAT :)
0
И это работает и в Windows 7 (да и в 8 тоже). Может это просто везение, но у меня еще не возникало проблем с этим способом внедрения.
0
В подавляющем большинстве случаев, в рамках одной сессии, адреса загрузки системных библиотек будут совпадать. К примеру, сейчас, на рабочей Win7 sp0, адрес загрузки kernel32.dll одинаков во всех процессах. Однако, вчера, на компьютере жены с Win7 sp1, я наблюдал различие адресов загрузки user32.dll. Адреса было всего два и они никак не зависели от пользователя, под которым запущен процесс.
0
Однако же, получать адрес процедуры в другом процессе начиная с систем, в которых активен ASLR, лучше как-то так (delphi 7):
function GetModuleHandleEx(sLibName: string; dwPID: DWORD): pointer;
var
me: TMODULEENTRY32;
hSnap: DWORD;
begin
result := nil;
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if hSnap <> DWORD(INVALID_HANDLE_VALUE) then
begin
me.dwSize := SizeOf(TMODULEENTRY32);
if Module32First(hSnap, me) then
repeat
if UpperCase(string(me.szModule)) = UpperCase(sLibName) then
begin
result := pointer(me.modBaseAddr);
break;
end;
until not Module32Next(hSnap, me);
CloseHandle(hSnap);
end;
end;
{$O-}
function GetProcAddressEx(sLibName, sFuncName: string; dwPID: DWORD): DWORD;
var
hLib: DWORD;
begin
hLib := GetModuleHandle(PChar(sLibName));
result := DWORD(DWORD(GetProcAddress(hLib, PChar(sFuncName))) -
hLib + DWORD(GetModuleHandleEx(sLibName, dwPID)));
end;
{$O+}
+2
глобальный хук CreateRemoteThread вроде требует чтобы ZwResumeThread был похукан, дабы внедриться во все процесы
0
Сложно, зато не универсально ))
Во-первых, таким способом без серьёзного перепиливания вы не перехватите RTMP-стрим.
А для остального можно установить AdBlock, прописать нужные правила. Тогда загрузка видеоконтента будет блокироваться и высвечиваться в списке заблокированного AdBlock-ом. Откуда можно просто скопировать ссылку и поставить на закачку.
Например, для youtube подойдёт такое правило:
Для подавляющего большинства остальных видеофайлов:
Во-первых, таким способом без серьёзного перепиливания вы не перехватите RTMP-стрим.
А для остального можно установить AdBlock, прописать нужные правила. Тогда загрузка видеоконтента будет блокироваться и высвечиваться в списке заблокированного AdBlock-ом. Откуда можно просто скопировать ссылку и поставить на закачку.
Например, для youtube подойдёт такое правило:
http://*.youtube.com/videoplayback?*
Для подавляющего большинства остальных видеофайлов:
/^https?\:\/(\/[^\/\?]*){2,}\.(flv|iflv|f4v|mpg|mpeg|wmv|mp3|mp4|m4v|mov)(\?.*)?$/
+1
На эту тему можно спорить бесконечно. Начать с того что Ваш фильтр для AdBlock так же не перехватит RTMP и тоже не универсален, потому что это плагин под конкретный браузер. Закончить можно тем что RTMP инкапсулированный в HTTP ловится точно очень даже легко как, за исключением того что помимо GET надо еще отсматривать POST.
А «чистый» RTMP протокол (который на порту 1935 под префиксом rtmp://) технически к браузерам имеет мало отношения и не всегда дружит с проксями. То есть да, его можно перехватить, но не с перепиливанием в смысле рефакторинга, а вообще с дописыванием отдельного обработчика, равно как и для rtp, rtsp, mms и тому подобные. Мой простенький пример даже HTTP-то через пень-колоду обрабатывает — это в целях наглядности.
Попробую повториться, целью поста было показать что перехват пакетов из браузера или чего то там еще, это не такая сложная задача, которая требует написания драйвера как это сделали в Jaksta. Я на нее потратил в общей сложности три часа, поэтому и функционал очень ограниченный.
А «чистый» RTMP протокол (который на порту 1935 под префиксом rtmp://) технически к браузерам имеет мало отношения и не всегда дружит с проксями. То есть да, его можно перехватить, но не с перепиливанием в смысле рефакторинга, а вообще с дописыванием отдельного обработчика, равно как и для rtp, rtsp, mms и тому подобные. Мой простенький пример даже HTTP-то через пень-колоду обрабатывает — это в целях наглядности.
Попробую повториться, целью поста было показать что перехват пакетов из браузера или чего то там еще, это не такая сложная задача, которая требует написания драйвера как это сделали в Jaksta. Я на нее потратил в общей сложности три часа, поэтому и функционал очень ограниченный.
+1
Sign up to leave a comment.
Перехват видео в браузере или TCP сниффер под Windows на коленке (часть первая)