我注意到有些Youtube视频正在加密签名...我已经搜索了一下问题,发现Youtube正在将算法存储在他们的HTML5播放器的Java脚本中,如下所示: https://s.ytimg.com/yts/jsbin/html5player-iw_IL-vflC7Zf5J.js
我找到了这些功能:
function zn(a)
{
a=a.split("");
a=a.slice(2);
a=a.reverse();
a=An(a,7);
a=An(a,21);
a=a.reverse();
return a.join("")
}
function An(a,b)
{
var c=a[0];
a[0]=a[b%a.length];
a[b]=c;
return a
}
现在,我有几个问题:
首先,如果我有一个加密的签名,我需要通过这两个函数签名来获取解密的签名,或者我必须写一个相反的函数来解密数据?
第二,有没有办法让它变得通用,或者每当youtube更新加密签名的算法时,我必须重新编写它? (加密函数)
谢谢!
答案 0 :(得分:1)
第二,有没有办法让它变得通用,或者每当youtube更新加密签名的算法时,我必须重新编写它? (加密函数)
您可以使用已知的不同值(如字符String.fromCharCode(0), String.fromCharCode(1), ...
)传入一个长度相同的字符串,并查看它们在输出字符串中的移动位置:这是转换转换所需的所有信息,如只要它不具有破坏性(即输出字符串的长度相同,每个字符出现一次)。
首先,如果我有一个加密的签名,我需要通过这两个函数签名来获取解密的签名,或者我必须写一个相反的函数来解密数据?
听起来你可以尝试一下,看看哪些有用......?
答案 1 :(得分:0)
实际上,在一些Javascript片段中存在交替的一对模式用于签名解扰,每个模式都不像某些帖子可能建议或期望的那样通用。 这里有一个解决方案
/* Java Class SignatureDecoder, Version 2019-01-03 */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class SignatureDecoder
{
String cacheUrl = null;
String js = null;
public SignatureDecoder()
{
}
public String decode(String jsUrl, String rawSignature, Proxy proxy)
{
if (!loadJs(jsUrl, proxy))
{
return null;
}
// Get scramble function from script, e.g. ".signature=Aq("
final String func = getSignFunction();
if (func == null)
{
return null;
}
final String fs[] = getFuncScript(func);
if (fs == null)
{
return null;
}
String var = null;
String vs = "";
final String ident = "[$A-Za-z0-9_]+";
final String varPat = "(" + ident + ")\\." + ident + "\\([ ]*" + fs[1];
final Pattern vpt = Pattern.compile(varPat);
final Matcher vmt = vpt.matcher(fs[0]);
if (vmt.find(0))
{
var = vmt.group(1);
vs = getVarDef(js, var);
}
final String extract = vs + "\n" + fs[0];
final ScriptEngineManager mgr = new ScriptEngineManager();
final ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
try
{
jsEngine.eval(extract);
final Invocable inv = (Invocable) jsEngine;
final String enc = (String) inv.invokeFunction(func, rawSignature);
return enc;
}
catch (final ScriptException ex)
{
ex.printStackTrace();
}
catch (final NoSuchMethodException x)
{
x.printStackTrace();
}
return rawSignature;
}
public String decode(String jsUrl, String rawSignature)
{
return decode(jsUrl, rawSignature, null);
}
protected boolean loadJs(String jsUrl, Proxy proxy)
{
if (cacheUrl == null || !cacheUrl.equals(jsUrl))
{
cacheUrl = null;
URL jsUrl1;
try
{
jsUrl1 = new URL(jsUrl);
}
catch (final MalformedURLException e1)
{
e1.printStackTrace();
return false;
}
try
{
BufferedReader in;
final StringBuffer buf = new StringBuffer();
final URLConnection conn = proxy == null ? jsUrl1.openConnection() : jsUrl1.openConnection(proxy);
final InputStream is = conn.getInputStream();
in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null)
{
buf.append(inputLine);
buf.append('\n');
}
is.close();
this.js = buf.toString();
this.cacheUrl = jsUrl;
}
catch (final UnknownHostException e)
{
System.err.println("Cannot access script at " + jsUrl);
return false;
}
catch (final IOException e)
{
System.err.println("Error loading script from " + jsUrl);
e.printStackTrace();
return false;
}
}
return true;
}
// var zq={ID:function(a,b){a.splice(0,b)},Bd:function(a){a.reverse()},Px:function(a,b){var c=a[0];a[0]=a[b%a.length];a[b]=c}};
protected String getBlock(String script, int pos1)
{
String res = null;
int pos = pos1;
boolean stop = false;
int brack = 0;
boolean containsBlock = false;
while (!stop)
{
final char ch = script.charAt(pos);
pos++;
switch (ch)
{
case '(':
brack++;
break;
case '{':
brack++;
break;
case '[':
brack++;
break;
case ')':
brack--;
break;
case ']':
brack--;
break;
case '}':
brack--;
break;
case ';':
stop = brack == 0;
break;
case '\n':
stop = brack == 0;
break;
default:
;
}
if (brack > 0)
{
containsBlock = true;
}
else
{
stop = containsBlock;
}
}
res = script.substring(pos1, pos);
return res;
}
protected String getVarDef(String script, String var)
{
String res = null;
final String varPat = "var[ ]+" + var.replace("$", "\\$") + "[ ]*=";
final Pattern pt = Pattern.compile(varPat);
final Matcher mt = pt.matcher(script);
if (mt.find(0))
{
res = mt.group(0);
final int posBlock = mt.end(0);
final String block = getBlock(script, posBlock);
res = res + block;
}
return res;
}
protected String[] getFuncScript(String func)
{
String res[] = null;
final String funcDollar = func.replace("$", "\\$");
final String paramPat = "[ ]*\\(([^\\)]+)\\)";
String funcPat = "function[ ]+" + funcDollar + paramPat;
Pattern pt = Pattern.compile(funcPat);
Matcher mt = pt.matcher(js);
boolean ok = mt.find(0);
if (!ok)
{
funcPat = funcDollar + "=function" + paramPat;
pt = Pattern.compile(funcPat);
mt = pt.matcher(js);
ok = mt.find(0);
}
if (ok)
{
res = new String[2];
String scr = mt.group(0);
final String arg = mt.group(1);
final int posBlock = mt.end(0);
final String block = getBlock(js, posBlock);
scr = scr + block;
res[0] = scr;
res[1] = arg;
}
return res;
}
protected String getSignFunction()
{
if (js == null)
{
return null;
}
// Pattern 1
String func = null;
String funcPat = "\\.signature=([^\\(]+)\\(";
Pattern pt = Pattern.compile(funcPat);
Matcher mt = pt.matcher(js);
if (mt.find(0))
{
func = mt.group(1);
}
// Pattern 2
if (func == null)
{
funcPat = "\\(\\\"signature\\\",([^\\(]+)\\(";
}
pt = Pattern.compile(funcPat);
mt = pt.matcher(js);
if (mt.find(0))
{
func = mt.group(1);
}
// Pattern 3
if (func == null)
{
final int pos = js.indexOf("set(\"alr\",\"yes\")");
if (pos >= 0)
{
int pos1 = pos;
while (pos1 > 0 && js.charAt(pos1) != '\n')
{
pos1--;
}
int pos2 = pos;
while (pos2 < js.length() && js.charAt(pos2) != '\n')
{
pos2++;
}
final String js1 = js.substring(pos1 + 1, pos2);
// d.set("alr","yes");c&&(b||(b="signature"),d.set(b,WK(c)));return d};
final String ident = "[a-zA-Z0-9]+";
funcPat = "(" + ident + ")\\.set\\(\\\"alr\\\",\\\"yes\\\"\\);";
pt = Pattern.compile(funcPat);
mt = pt.matcher(js1);
if (mt.find(0))
{
final String obj = mt.group(1);
final String funcPat2 = obj + "\\.set\\((" + ident + "|\\\"signature\\\"),(" + ident + ")\\(" + ident + "\\)\\)";
final Pattern pt2 = Pattern.compile(funcPat2);
final Matcher mt2 = pt2.matcher(js1);
func = null;
if (mt2.find(0))
{
func = mt2.group(2);
}
else
{
final String fp3 = "\\(([A-Za-z]+)\\(\\(0,window.decodeURIComponent";
pt = Pattern.compile(fp3);
final Matcher mt3 = pt.matcher(js1);
if (mt3.find(0))
{
func = mt3.group(1);
}
}
}
}
}
return func;
}
// Test
public static void main(String args[])
{
final String rawSignature = "C98C987F29D5CC5C651A6FB867EFC316D09CDF015983.E7C61471A1569DEE963C2FB55B025B2FE63CD32929929";
final String expRes = "923DC36EF2B520B59BF2C369EED9651A17416C7E.38C510FDC90D613CFE768BF6A156C5CC5D92F785";
final String jsUrl = "http://s.ytimg.com/yts/jsbin/player-vflI0cIzU/de_DE/base.js";
final String signature = new SignatureDecoder().decode(jsUrl, rawSignature);
System.out.println("\nExpected: " + expRes);
System.out.println("Evaluated: " + signature);
System.out.print("Test ");
if (signature != null && expRes.equals(signature))
{
System.out.println("OK");
}
else
{
System.out.println("FAILED");
}
}
}