Тема: Как находить и расшифровывать ссылки (tivix.net)
В личке меня попросили научить расшифровывать ссылки.
Поэтому я решил написать целый пост о том, как же это всё делается и с помощью каких подручных инструментов.
Желательны хотя бы базовые познания в каком-либо языке программирования, чтобы понимать и не пугаться HTML и JavaScript кода.
Итак, рассмотрим несколько примеров.
tivix.net - пример поиска ссылок на IPTV каналы
Итак, нам могут понадобиться:
- Браузер - из последних версий InternetExplorer, FireFox, Chrome или Opera - кому что нравится
- Свободное время
Например, у нас есть сайт http://tivix.net/ и мы хотим узнать, откуда же этот сайт показывает нам каналы и как узнать ссылки на такое вещание?
Открываем сайт в браузере. Открываем страничку с конкретным каналом, например http://tivix.net/93-pyatyy-kanal-sankt-peterburg.html - 5 канал. На ней видим, что на странице имеется три вида источника: "HQ", "Торрент" и "Моб. №1". Тут ясно, что "Торрент" - это использование плагина AcePlayer и просмотр канала будет через торрент протокол по специальному ID для торрент-телевидения. А вот "HQ" - что-то не понятное. Давайте посмотрим, что и как там.
Нажимаем Ctrl-U - откроется исходник страницы сайта. Там мы прокручиваем и ищем код плеера. Находим примерно такой:
<object id="player33" type="application/x-shockwave-flash" data="/templates/Default/style/uppod.swf" width="799" height="450">
<param name="wmode" value="transparent" />
<param name="bgcolor" value="#ffffff"/>
<param name="allowFullScreen" value="true"/>
<param name="allowScriptAccess" value="always"/>
<param name="movie" value="/templates/Default/style/uppod.swf"/>
<param name="flashvars" value=""/>
</object>
Но тут flashvars чистый и нет ссылки на поток, а где же она? Чуть ниже видим javascript код, на подобии этого:
<script>
;eval(function(w,i,s,e){var lIll=0;var ll1I=0;var Il
...
1r2l141','e97859af5e411a43e0b1930a181d6e83'));
</script>
Видно, что через функцию eval исполняется код, который запакован и в таком виде вообще не понятно что пока делает.
Ну ок. Будем расшифровывать. Чуть ниже я покажу как проще, без расшифровки этого кода, посмотреть ссылку на видео-поток. Но для начала посмотрим всё-таки, что же делает этот код и есть ли там подводные камни, модифицируется ли ссылка при каждом открытии или добавляется ли какой-либо параметр.
Для этого сначала просто внимательно смотрим на этот код, который находится между скобок функции eval.
Если текст функции или структура кода уж совсем непонятна, можно сделать так. Выделить нужный код и вставить, например, сюда и нажать кнопку "Beautify". Справа будет немного понятней структура кода и мы увидим, что есть небольшая функция, начинающаяся с { и кончающаяся на }, после чего идут значения передаваемых параметров в скобках для этой функции.
Давайте выполним этот участок кода и посмотрим, что нам это распакует.
Для этого нужно в браузере на странице канала зайти в инструменты разработчика (Chrome - нажать Ctrl+Chift+I, IE - F12, Firefox - Ctrl+Chift+K) и там перейти на вкладку Console, где мы сможем выполнять команды javascript на этой страничке сайта.
Нужно скопировать участок кода, начинающийся с function(w,i,s,e){
и заканчивающийся return l1ll.join('');}
- т.е. всю часть функции. Перейти в Console и набрать в ней: a =
и дальше вставить скопированный текст, нажать Enter. Это присвоит переменной a
значение - саму эту функцию, т.е. переменная a - это и будет сама функция.
a
и вставляем скопированный текст, чтобы получилось что-то вроде:
a('1b1b0d0a1n2t3a2p30142u39322r382x3332143b182x1837182t153f2u333614371p1c1n371o3b1a302t322v382w1n37171p1e153f2x171p2b38362x322v1a2u3633311v2w2p361v332s2t14342p36372t213238143b1a37392q3738361437181e15181f1i15151n3h362t383936320w2x1n3h14131d2q1d2q1c2s1c2p1318131318131318131315151n1n2t3a2p30142u39322r382x3332143b182x1837182t153f2u333614371p1c1n371o3b1a302t322v382w1n37171p1e153f2x171p2b38362x322v1a2u3633311v2w2p361v332s2t14342p36372t213238143b1a37392q3738361437181e15181f1i15151n3h362t383936320w2x1n3h14131d2q1d2q1c2s1c2p1d321e381f2p1e341f1c1d1g1e391f1l1f1e1e361f1k1e3c1f1f1f1e1d1g1f2q1d1k1e3c1d1k1f1j1d1k1e381d1h1f2u1e391f1f1f1i1d1g1f1j1d341d2r1d321f1j1d331f2q1d2p1f1c1e381f1e1e3a1f1k1e3b1d321f1j1d1j1d341d2t1d1h1f2u1e3c1d1j1d341e2q1f1k1f1i1e3c1f1e1e3a1d2p1e391f1i1f1f1f1d1d3a1e3b1e341f1i1d3a1f1f1e371e381d1g1f1g1e341f1i1f1j1e381e1d1f1e1f1k1d1g1f2q1d2p1f1j1f1l1e351f1j1f1k1f1i1d1g1f1j1d1k1d2t1d1h1d1k1d2u1d2x1d1h1d1h1d321f2w1f1i1e381f1k1f1l1f1i1f1e1c3b1e3c1d321f2w1d1g1d1f1d2s1e351d2s1e351d2r1e371d2r1e341d1f1d1k1d1f1d1f1d1k1d1f1d1f1d1k1d1f1d1f1d1h1d1h1d321318131318131318131315151n','','','')
Выполняем это и смотрим ответ. А в ответ нам будет строка очередного кода, который будет выполнятся. И как мы можем увидеть, там опять будет пара eval с функциями eval(function(w,i,s,e)
и длинными значениями зашифрованного текста как параметры для таких функций.
Где я синим прямоугольником выделил код, который нужно присвоить переменной
a =
и зелёным - ту часть, которую нужно вставлять при вызове функции.Ну что, у нас времени много, мы им заранее запаслись, поэтому будем вытворять дальше такие трюки и с остальным полученным кодом. Поэтому просто повторяем процедуру сначала для одного eval, потом для другого.
Т.е. копируем текст функции начиная с function(w,i,s,e)
и заканчивая символом }
, переходим в консоль, присваиваем переменной b скопированный код и потом копируем значения параметров со скобками и вызываем функцию b с этими скопированными значениями. Пока не увидим что-то наподобие вот этого:
Вся эта мутотень была показана для того, чтобы продемонстрировать, что запакованные функции в HTML коде - это бутафория и терпеливому человеку не помеха.
На самом деле, вот эту вот ссылку можно и нужно смотреть на странице сразу немного по-другому.
Открываете страницу с каналом в браузере и нажимаете чуть выше плеера правой кнопкой мыши и выбираете "Посмотреть код" (в IE - "Проверить элемент"). Внизу или сбоку откроется HTML срутрура страницы с уже выполненными javascript и модифицированным DOM (структурой HTML), где можно найти объект <object id="player33"
<object id="player33" type="application/x-shockwave-flash" data="/templates/Default/style/uppod.swf" width="799" height="450">
<param name="wmode" value="transparent">
<param name="bgcolor" value="#ffffff">
<param name="allowFullScreen" value="true">
<param name="allowScriptAccess" value="always">
<param name="movie" value="/templates/Default/style/uppod.swf">
<param name="flashvars" value="m=video&file=http://85.25.43.50:8081/pyatiy/pl.m3u8?wmsAuthSign=c2VydmVyX3RpbWU9Ny8xNi8yMDE2IDM6MzI6MjggUE0maGFzaF92YWx1ZT1OV0IzQkdjTmswdy95VUlhT3ZRNnFBPT0mdmFsaWRtaW51dGVzPTEyMA==&st=%2Ftemplates%2FDefault%2Fstyle%2Fvideo189-1185.txt&">
</object>
где flashvars уже проставлены и видна ссылка на поток. В данном ресурсе эта ссылка на плейлист m3u8 не зашифрована и сама по себе вот такая:
http://85.25.43.50:8081/pyatiy/pl.m3u8?wmsAuthSign=c2VydmVyX3RpbWU9Ny8xNi8yMDE2IDM6MzI6MjggUE0maGFzaF92YWx1ZT1OV0IzQkdjTmswdy95VUlhT3ZRNnFBPT0mdmFsaWRtaW51dGVzPTEyMA==
Но эту ссылку мы получили "вручную", т.е. сидя за компом и руками. Но если нам нужно автоматом выдергивать актуальную ссылку куда-то ещё, например в подкаст или на страницу нашего сайта, то тут уже нужно это дело всё автоматизировать.
К сожалению, ничего обычно нельзя придумать, как полностью повторить все действия по расшифровке где-то в своём коде скрипта. Т.е. нам нужно изучить, как на самом деле работает расшифровка, чтобы написать свой код для её воспроизведения у себя.
Например, в подкастах приходится искать нужные участки, брать оттуда и в какой-то специально написанной функции это дело расшифровывать.
В случаях сайтов, можно написать какой-то PHP скрипт, который будет повторять действия расшифровки тоже.
Для этого очень внимательно и долго смотрим на код дешифровки:
function(w, i, s, e) {
var lIll = 0;
var ll1I = 0;
var Il1l = 0;
var ll1l = [];
var l1lI = [];
while (true) {
if (lIll < 5) l1lI.push(w.charAt(lIll));
else if (lIll < w.length) ll1l.push(w.charAt(lIll));
lIll++;
if (ll1I < 5) l1lI.push(i.charAt(ll1I));
else if (ll1I < i.length) ll1l.push(i.charAt(ll1I));
ll1I++;
if (Il1l < 5) l1lI.push(s.charAt(Il1l));
else if (Il1l < s.length) ll1l.push(s.charAt(Il1l));
Il1l++;
if (w.length + i.length + s.length + e.length == ll1l.length + l1lI.length + e.length) break;
}
var lI1l = ll1l.join('');
var I1lI = l1lI.join('');
ll1I = 0;
var l1ll = [];
for (lIll = 0; lIll < ll1l.length; lIll += 2) {
var ll11 = -1;
if (I1lI.charCodeAt(ll1I) % 2) ll11 = 1;
l1ll.push(String.fromCharCode(parseInt(lI1l.substr(lIll, 2), 36) - ll11));
ll1I++;
if (ll1I >= l1lI.length) ll1I = 0;
}
return l1ll.join('');
}
и пытаемся эту функцию переписать, например, на PHP. Например, у меня получился такой код PHP, где я через параметр ulr получаю адрес странички сайта канала, загружаю её и там получаем параметры для функции, которые выполняем, пока такая функция встречается в дешифрованном тексте.
<?php
$url = isset($_REQUEST['url']) ? $_REQUEST['url'] : ''; // url странички канала сайта http://tivix.net
if (!$url) die('No url set'); // Если url канала не указан, выходим с сообщением об этом
$page = file_get_contents($url); // Загружаем страницу канала
// В цикле ищем javascript код функции eval(function(w,i,s,e) и получаем её параметры,
// выполняем дешифровку, пока такую функцию там встречаем
while (preg_match("#.*eval\(function\(w,i,s,e\).*?}\('(.*?)','(.*?)','(.*?)','(.*?)'#", $page, $m)) {
$page = Decode($m[1], $m[2], $m[3], $m[4]);
}
// В дешифрованных данных ищем ссылку
if (preg_match("#(http://.*?)'#", $page, $m))
echo $m[1];
else
echo "Link not found :(";
//////////////////////////////////////////////////////////////////////////////
// Функция дешифровки javascript кода с сайта tivix.net
function Decode ($w, $i, $s, $e) {
$lIll = 0;
$ll1I = 0;
$Il1l = 0;
$ll1l = "";
$l1lI = "";
while (true) {
if ($lIll < 5 ) $l1lI .= substr($w, $lIll, 1);
else if ($lIll < strlen($w)) $ll1l .= substr($w, $lIll, 1);
$lIll++;
if ($ll1I < 5 ) $l1lI .= substr($i, $ll1I, 1);
else if ($ll1I < strlen($i)) $ll1l .= substr($i, $ll1I, 1);
$ll1I++;
if ($Il1l < 5 ) $l1lI .= substr($s, $Il1l, 1);
else if ($Il1l < strlen($s)) $ll1l .= substr($s, $Il1l, 1);
$Il1l++;
if (strlen($w) + strlen($i) + strlen($s) + strlen($e) == strlen($ll1l) + strlen($l1lI) + strlen($e)) break;
}
$lI1l = $ll1l;
$I1lI = $l1lI;
$ll1I = 0;
$l1ll = "";
for ($lIll = 0; $lIll < strlen($ll1l); $lIll += 2) {
$ll11 = -1;
if (ord(substr($I1lI, $ll1I, 1)) % 2) $ll11 = 1;
$l1ll .= chr(intval(substr($lI1l, $lIll, 2), 36) - $ll11);
$ll1I++;
if ($ll1I >= strlen($l1lI)) $ll1I = 0;
}
return $l1ll;
}
Но это всё работает ровно до тех пор, пока на сайте не произошли изменения и функцию получения ссылки не придётся заново переписывать.