Лучший подход к декодированию сигнатуры шифрования Youtube с использованием PHP или JS

Youtube использует сигнатуру шифрования для некоторых видео, когда use_cipher_signature = true в словаре, возвращаемом через http://www.youtube.com/get_video_info?&video_id=Video_Id

Пример id: _JQH3G0cCtY

Шифрованная подпись - это фактически скремблированная подпись, которую любой может отлаживать несколькими наборами работающих подписей. Но Youtube продолжает менять скремблирующий алгоритм. Я видел несколько загрузчиков видео Youtube, которые работают плавно, не затрагивая эту меняющуюся игру. Я думаю, что они проверяют игрока и извлекают декодер script из файла игрока, и, следовательно, он удерживает их.

Мне нужна некоторая помощь в использовании этой техники. Я знаю о программе "youtube-dl" - программе python для загрузки видео. Поскольку я не очень хорош в python, я думаю, что они используют один и тот же подход.

Также есть файл user-script JS, доступный здесь: http://userscripts.org/scripts/show/25105, который делает то же самое.

Любая помощь по разумному подходу к расшифровке кода шифрования в PHP или JS будет оценена.

Ответ 1

Структура URL и код шифрования продолжают меняться на Youtube. В настоящее время наилучший подход к декодированию сигнатуры шифрования объясняется ниже:

Шифрованная подпись в Youtube - это просто "скремблированная" подпись, которую вы должны переставить в соответствии с Алгоритмом, присутствующим в файле игрока (проигрыватель HTML5 или Flash Player).

Например, http://www.youtube.com/watch?v=UxxajLWwzqY использует следующий файл с файлом HTML5: //s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js

в этом файле вы можете легко найти код расшифровки подписи, ища 'sig'. Здесь в этом случае Algo:

function bz(a) {
    a = a.split("");
    a = cz(a, 61);
    a = cz(a, 5);
    a = a.reverse();
    a = a.slice(2);
    a = cz(a, 69);
    a = a.slice(2);
    a = a.reverse();
    return a.join("")
}

function cz(a, b) {
    var c = a[0];
    a[0] = a[b % a.length];
    a[b] = c;
    return a
};

Выше код расшифровки.

Но имейте в виду, что он продолжает меняться, когда они меняют файл плеера, поэтому вам нужно продолжать использовать файл проигрывателя.

Кроме того, чтобы загружать видео с помощью шифрованной подписи, вы должны позаботиться о отправке одинаковых файлов cookie, используя один и тот же заголовок пользовательского агента, отправив запрос с того же IP-адреса и отправив запрос вскоре после извлечения. Все это или требуется в какой-то момент

Если вас интересует алгоритм шифрования шифрования, посетите CipherAPI

Еще один классный API: TYstream API

Ответ 2

Ye old s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js теперь 404, и новый URL-адрес, который, я думаю, немного похож на hxxps://s.ytimg.com/yts/jsbin/player-en_US-vfl_cdzrt/base.js

если вы выполните поиск по JavaScript, вы найдете немного кода, который выглядит следующим образом:

function(a,b,c)
{
a=new Mr(a);
a.set("alr","yes");a.set("keepalive","yes");a.set("ratebypass","yes");a.set("mime",(0,window.encodeURIComponent)(b.mimeType.split(";")[0]));c&&a.set("signature",xr(c));return a},Jt=function(a,b){var c=Yr(b,"id"),c=c.replace(":",";");..............
}

Функция xr, которую вызывают вышеуказанные вызовы кода, выглядит следующим образом:

xr=function(a)
{
a=a.split("");
wr.rF(a,54);
wr.fs(a,75);
wr.N0(a,1);
wr.rF(a,52);
wr.N0(a,3);
wr.fs(a,31);
wr.rF(a,16);
wr.fs(a,38);
return a.join("")
}

После этого я начинаю немного проигрывать с помощью javascript и могу сделать с собой немного помощи, но, говоря об этом, в проекте кода вы попадаете в troube.

Ответ 3

Я перевел на Swift 3 ответ Akhilesh для людей iOS:

func decryptSignature(signature:String)->String {
    return bz(signature)
}
func bz(_ a:String)->String {
    var arrayA = Array(a.characters)
    arrayA = cz(arrayA, 61)
    arrayA = cz(arrayA, 5)
    arrayA = arrayA.reversed()
    arrayA = Array(arrayA[2..<arrayA.count])
    arrayA = cz(arrayA, 69)
    arrayA = Array(arrayA[2..<arrayA.count])
    arrayA = arrayA.reversed()
    return String(arrayA)
}
func cz(_ a:Array<Character>, _ b:Int)->Array<Character> {
    var arrayA = a
    let c = a[0]
    arrayA[0] = a[b % a.count];
    arrayA[b] = c
    return arrayA
}

Но я думаю, что этого алгоритма недостаточно, он расшифровывает подпись по определенному правилу. Фактически, согласно this perl script (youtubedown от Jamie Zawinski), алгоритм меняется каждый раз, а script собирает список правил и алгоритмы в течение дней!. До сих пор в шифрах использовались только три команды, поэтому мы можем их компактно представить:

# - r  = reverse the string;
# - sN = slice from character N to the end;
# - wN = swap 0th and Nth character.

Я думаю, что лучший способ - реализовать что-то вроде:

func decryptChiper(_ commands:String, signature:String)->String {
    var a = Array(signature.characters)
    let cmdArray:[String]! = commands.components(separatedBy: " ")
    for cmd in cmdArray {
        var value:Int!
        if cmd.characters.count>1 {
            let secondChar = cmd.index(cmd.startIndex, offsetBy: 1)
            value = Int(cmd.substring(from:secondChar))
        }

        switch cmd[cmd.startIndex] {
        case "r": a = a.reversed()
        case "s":
            if let sliceFrom = value {
                a = Array(a[sliceFrom..<a.count])
            }
        case "w":
            if let swapValue = value {
                a = swap(a,swapValue)
            }
        default:break
        }
    }
    return String(a)
}

func swap(_ a:Array<Character>, _ b:Int)->Array<Character> {
    var arrayA = a
    let c = a[0]
    arrayA[0] = a[b % a.count];
    arrayA[b] = c
    return arrayA
}

Использование:

Чтобы сделать следующий пример, Akhilesh ответьте:

let signature = "D3D3434498D70C3080D9B084E48350F6519A9E9A71094.25F300BB180DDDD918EE0EBEDD174EE5D874EFEFF"
let decryptedSign = decryptChiper("w61 w5 r s2 w69 s2 r", signature: signature )
print(decryptedSign)

Выход:

33D3494498D70C3E80D9B084E48350F6519A9E9A71094.25F300BB180DDDDD18EE0EBEDD174EE5D874E