使用PHP或JS解码Youtube密码签名的最佳方法

当字典中的use_cipher_signature = true通过http://www.youtube.com/get_video_info?&video_id=Video_Id返回时,Youtube正在使用一些video的密码签名

示例ID:_JQH3G0cCtY

encryption签名实际上是任何人都可以用几套工作签名进行debugging的encryption签名。 但Youtube不断改变加扰algorithm。 我已经看到很less的Youtubevideo下载工作正常,不受这个变化的游戏的影响。 我认为他们正在检查播放器,并从播放器文件中提取解码脚本,因此会使它们继续运行。

在这种情况下,我需要一些关于实际技术的帮助。 我知道'youtube-dl' – 一个下载video的python程序。 由于我不擅长python,我认为他们使用的是相同的方法。

还有一个用户脚本JS文件在这里: http : //userscripts.org/scripts/show/25105 ,这是做同样的事情。

任何有关理解PHP或JS密码的理智方法的帮助将不胜感激。

url结构和密码不断变化的Youtube。 目前,解密密码签名的最佳方法解释如下:

Youtube中的encryption签名只是“encryption”签名,您必须根据播放器文件(HTML5播放器或Flash播放器)中的algorithm重新排列它们。

例如http://www.youtube.com/watch?v=UxxajLWwzqY目前正在使用以下HTML5播放器文件: //s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js

在这个文件中,您可以通过search'sig'来轻松search签名解密代码。 在这种情况下,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 }; 

以上是解密代码。

但请注意,当他们更改播放器文件时,它会不断变化,所以您必须保持点击正在使用的播放器文件。

此外,要下载带有密码签名的video,您必须注意发送相同的cookie,使用相同的用户代理标头,从相同的IP地址发送请求,并在提取后不久发送请求。 所有这些都是在某些时候需要的

如果对密码解密algorithm感兴趣,请访问CipherAPI

另一个很酷的API: TYstream API

s.ytimg.com/yts/jsbin/html5player-vfltdb6U3.js现在是404,我认为新的URL看起来更像hxxps://s.ytimg.com/yts/jsbin/player-en_US-vfl_cdzrt/base.js

如果你searchJavaScript,你会发现一些看起来像这样的代码

 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,可以做一些自己的帮助,但在代码项目上谈论这个让你烦恼。

我已经翻译了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 } 

但是我认为这个algorithm是不够的,它会按照一个特定的规则解密签名。 实际上,根据这个 perl脚本(你从Jamie Zawinskiinput),algorithm每次都会改变,脚本在几天内收集一系列规则和algorithm! 到目前为止,只有三个命令用于密码,所以我们可以紧凑地表示它们:

 # - 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