获取YouTube视频的签名

时间:2014-06-01 01:05:35

标签: javascript c++ http youtube

我注意到有些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更新加密签名的算法时,我必须重新编写它? (加密函数)

谢谢!

2 个答案:

答案 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");
        }

    }

}