Pull to refresh

Comments 38

интересно, как к вашим внедрениям в чужие процессы относятся антивирусы? :-)
Microsoft Security Essentials и Symantec молчат. Про других не знаю :) Вообще способ более чем легальный…
А чего им ругаться, взять тот же PuntoSwitcher, Lingvo, они внедряют свои dll в процессы и ничего, все нормально. Внедрить dll это ничего страшного по сути. Но на это точно ругается Outpost, на любые внедрения.
Совсем никудышние антивирусы, если не ругаются.
Один из самых интересных постов на хабре за последнее время, спасибо.
Для Firefox и Chromium можно скомпилировать свою версию браузера. Преимущество такого способа — можно узнать по дороге много нового о их внутренней структуре. Недостаток — нужно перекомпилировать браузер каждые 6 недель.
Строго говорят для них же можно написать расширения, которые не будут иметь проблем с HTTPS например. Примером тому множество расширений для YouTube с возможностью скачивания видео. Да и тот же Adblock работает по схожему принципу, только вместо отдельных пакетов он получает страницу целиком. Но было все же интереснее попробовать более-менее универсальный метод…
А можно где-то подобный софт поиметь? Может подскажете уже готовые реализации перехватчиков потокового видео, которые его отсылают, в идеале, в WMP? И можно смотреть не в браузере, а в плейере, ну и творить с ним что хочешь, например отсылать изображение на экран Smart TV :)
Честно говоря я не знаю готового софта для этих целей. Написать его с нуля не такая уж и тяжелая работа, тем более что для WMP будет достаточно привинтить YouTube каталоги к DLNA серверу типа Twonky и объявить себя медиа сервером. SmartTV по умолчанию работает с DLNA серверами на ура. Но я пока не готов что-то подобное делать из-за отсутствия времени.
Постараюсь на неделе найти время и все это сделать для x64.
Есть еще мало знакомая в околохакерских кругах технология — LSP (Wnisock SPI).
Используя ее можно избежать использования NDIS драйвера и нормально работать в ring3, без танцев с бубном.
Кстати странно, что создатели Jaksta не знаю про WinPcap.
Полностью согласен что LSP был бы более корректным методом. Но моей скрытой целью было показать как работает перехват функций DLL в принципе и возиться с написанием сервис провайдера для WinSock не хотелось :)
UFO just landed and posted this here
1. Да ладно, чего там собирать-то…
2. Этот ndis-драйвер хотя бы в BSOD не выпадает.
UFO just landed and posted this here
Автор, как давно Вы это всё писали? Вы в курсе, что последний Хром все процессы вкладок и плагинов держит в песочнице с Untrusted integrity level и многие пляски с внедрением DLL-ок и хуками перестали работать?
Писал я это все не далее как вчера, 31 августа 2012 года. Проверял в последней версии Google Chrome Beta, SRWare Iron и IE 9. Видимо дело в том что плагины и расширения в данном случае не играют существенной роли, независимо от того где их хром держит…
Вынужден сильно поругать Ваш метод перехвата, хоть сама реализация и не является главной темой статьи.

1. Самый кошмар конечно в том, что происходит постоянная перезапись кода в контролируемых функциях. Вы задумывались что произойдёт, если какой-то параллельный поток в это же самое время будет выполнять код функции в затираемом месте?

2. Даже если от постоянной перезаписи избавиться, то остаётся ещё узкое место: однократная установка хука. По той же причине, описанной в предыдущем пункте, приложение может вылететь. Для того, чтобы решить данную проблему, Вы можете перечислять потоки и замораживать все, кроме своего, с помощью SuspendThread().

3. Правильная организация перехвата такова: Вы переносите несколько первых инструкций перехватываемой функции в заранее подготовленное место, после последней инструкции добавляете jmp на Ваш код-обработчик (получается эдакий переходник). В конце кода-обработчика jmp на первую незатёртую инструкцию оригинального кода. Ну и в начало перехватываемой функции лепите прыжок на «переходник». Это перехват до выполнения. Перехват после выполнения делается схожим образом, но там мы должны подменить адрес возврата на стеке в нашем «переходнике».

4. Нужно понимать, что не всякую функцию можно перехватить таким образом. К примеру, если перемещаемые инструкции будут содержать прыжки по относительным адресам, то после перемещения такой код перестанет быть рабочим. Благо, почти все WinAPI-функции содержат стандартный пролог в 5-6 байт, который можно смело двигать куда угодно.
Критика справедливая и принимается. Я не зря написал что перезапись кода это недостаток именно данного примера. В данном посте мне стоило некоторых усилий держаться в рамках научно-популярной статьи и не сорваться в хардкор. К сожалению если бы я стал копать в сторону анализа инструкций, то хардкора было бы не избежать. Уверяю Вас что у меня есть другая реализация, очень похожая на ту что Вы описали.
А есть какая-либо возможность с ней ознакомиться? Интересно.
Постараюсь на следующей неделе написать апдейт или отдельный пост на эту тему и скомпилить x64, как обещал ранее.
Годная статья для хабра. stpark, смотрите сорцы хукера зевса, там более корректно выппонено
Лютый overkill.
1. Для записи видео достаточно прописать в браузере свой прокси-сервер и из него сейвить все ответы.
2. Для Firefox API расширений позволяет ловить все HTTP-реквесты и респонсы в своём javascript-фильтре.
Второй способ, в отличие от хуковского и проксёвого, пробивает https.

Видимо, автор не решал задачу сохранения видео, а захотел поиграться с системой.
Видимо, я вкладываю другой смысл в выражение «перехват из браузера», извините. Другие люди не стесняются писать для этого целый драйвер…
Просто любопытно. Почему вы не произвели внедрение через CreateRemoteThread? Мне кажется этот вариант был бы лучше глобального хука.
VirtualAllocEx в чужом процессе + WriteProcessMemory + CreateRemoteThread.
Плюсы:
— подгрузить код можно избирательно, а не во все процессы
— можно обойтись без DLL на диске и в списке загруженных DLL процесса
Минусы:
— антивирусы сильнее ругаются на WriteProcessMemory, чем на хуки
— сложнее реализовать

Сложности в том, что внедряемому коду надо настроить relocations на адрес внедрения, настроить импорты из зависимых DLL (из-за ASLR заранее неизвестно, где системные DLL). То есть, реализовать часть DLL-загрузчика.
Если внедряемый код маленький (загрузка DLL и запуск функции оттуда), его настройка упрощается, но теряется второй плюс этого метода.
Я не стал возиться с CreateRemoteThread() из за соображений наглядности. Глобальный хук это самое простое решение не требующее возни с чужим процессом извне. Чтобы избежать дополнительной возни с релокациями и импортами есть более простое решение. Делается оно так:

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 точно так же прогрузится в чужой процесс и поставит там хуки.
Это работало на XP.
В Windows 7 по умолчанию в каждом процессе свой адрес kernel32.dll, поэтому GetModuleHandle(«kernel32») в процессе, выполняющем внедрение, бесполезен
Ок. Тогда придется-таки копаться в IAT :)
И это работает и в Windows 7 (да и в 8 тоже). Может это просто везение, но у меня еще не возникало проблем с этим способом внедрения.
В подавляющем большинстве случаев, в рамках одной сессии, адреса загрузки системных библиотек будут совпадать. К примеру, сейчас, на рабочей Win7 sp0, адрес загрузки kernel32.dll одинаков во всех процессах. Однако, вчера, на компьютере жены с Win7 sp1, я наблюдал различие адресов загрузки user32.dll. Адреса было всего два и они никак не зависели от пользователя, под которым запущен процесс.
Однако же, получать адрес процедуры в другом процессе начиная с систем, в которых активен 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+}
глобальный хук CreateRemoteThread вроде требует чтобы ZwResumeThread был похукан, дабы внедриться во все процесы
Глобальный хук тут не при чём. Alex имеет ввиду способ, при котором dll или кусок кода внедряется в АП целевого процесса (одного) и на него передаётся управление с помощью CreateRemoteThread().
Сложно, зато не универсально ))
Во-первых, таким способом без серьёзного перепиливания вы не перехватите RTMP-стрим.
А для остального можно установить AdBlock, прописать нужные правила. Тогда загрузка видеоконтента будет блокироваться и высвечиваться в списке заблокированного AdBlock-ом. Откуда можно просто скопировать ссылку и поставить на закачку.
Например, для youtube подойдёт такое правило:
http://*.youtube.com/videoplayback?*
Для подавляющего большинства остальных видеофайлов:
/^https?\:\/(\/[^\/\?]*){2,}\.(flv|iflv|f4v|mpg|mpeg|wmv|mp3|mp4|m4v|mov)(\?.*)?$/
На эту тему можно спорить бесконечно. Начать с того что Ваш фильтр для AdBlock так же не перехватит RTMP и тоже не универсален, потому что это плагин под конкретный браузер. Закончить можно тем что RTMP инкапсулированный в HTTP ловится точно очень даже легко как, за исключением того что помимо GET надо еще отсматривать POST.

А «чистый» RTMP протокол (который на порту 1935 под префиксом rtmp://) технически к браузерам имеет мало отношения и не всегда дружит с проксями. То есть да, его можно перехватить, но не с перепиливанием в смысле рефакторинга, а вообще с дописыванием отдельного обработчика, равно как и для rtp, rtsp, mms и тому подобные. Мой простенький пример даже HTTP-то через пень-колоду обрабатывает — это в целях наглядности.

Попробую повториться, целью поста было показать что перехват пакетов из браузера или чего то там еще, это не такая сложная задача, которая требует написания драйвера как это сделали в Jaksta. Я на нее потратил в общей сложности три часа, поэтому и функционал очень ограниченный.
Sign up to leave a comment.

Articles