{"action":"created","issue":{"url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/162","labels_url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/162/labels{/name}","comments_url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/162/comments","events_url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/162/events","html_url":"https://github.com/flagbug/YoutubeExtractor/issues/162","id":123300554,"number":162,"title":"How can you decrypt the signature?","user":{"login":"KhanhNB","id":6745586,"avatar_url":"https://avatars.githubusercontent.com/u/6745586?v=3","gravatar_id":"","url":"https://api.github.com/users/KhanhNB","html_url":"https://github.com/KhanhNB","followers_url":"https://api.github.com/users/KhanhNB/followers","following_url":"https://api.github.com/users/KhanhNB/following{/other_user}","gists_url":"https://api.github.com/users/KhanhNB/gists{/gist_id}","starred_url":"https://api.github.com/users/KhanhNB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KhanhNB/subscriptions","organizations_url":"https://api.github.com/users/KhanhNB/orgs","repos_url":"https://api.github.com/users/KhanhNB/repos","events_url":"https://api.github.com/users/KhanhNB/events{/privacy}","received_events_url":"https://api.github.com/users/KhanhNB/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-12-21T15:38:29Z","updated_at":"2015-12-21T20:05:55Z","closed_at":"2015-12-21T17:35:43Z","body":"I know that with normal videos, Youtube will hardcode the signature in links in \"url_encoded_fmt_stream_map\", but with some videos like VEVO videos, they will only provide one signature so the links in url_encoded_fmt_stream_map will not work. How could know 'how to decrypt  these signatures' ? Can you share it? Thank You!"},"comment":{"url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/comments/166404983","html_url":"https://github.com/flagbug/YoutubeExtractor/issues/162#issuecomment-166404983","issue_url":"https://api.github.com/repos/flagbug/YoutubeExtractor/issues/162","id":166404983,"user":{"login":"Kimmax","id":2475864,"avatar_url":"https://avatars.githubusercontent.com/u/2475864?v=3","gravatar_id":"","url":"https://api.github.com/users/Kimmax","html_url":"https://github.com/Kimmax","followers_url":"https://api.github.com/users/Kimmax/followers","following_url":"https://api.github.com/users/Kimmax/following{/other_user}","gists_url":"https://api.github.com/users/Kimmax/gists{/gist_id}","starred_url":"https://api.github.com/users/Kimmax/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kimmax/subscriptions","organizations_url":"https://api.github.com/users/Kimmax/orgs","repos_url":"https://api.github.com/users/Kimmax/repos","events_url":"https://api.github.com/users/Kimmax/events{/privacy}","received_events_url":"https://api.github.com/users/Kimmax/received_events","type":"User","site_admin":false},"created_at":"2015-12-21T20:05:55Z","updated_at":"2015-12-21T20:05:55Z","body":"Hey there!\r\nI do this by taking the existing code and in case of a change (like the one which was fixed in 2fb0b8d2abdce999df7e8b439597fd6e24b7f26c) try to find out at what point the code fails. And then do some reverse engineering to get the code working again. Let's take as an example the latest code change.\r\n\r\nThe most important code for this is the following _(from Decipherer.cs, Method DecipherWithVersion)_\r\n```C#\r\nstring jsUrl = string.Format(\"http://s.ytimg.com/yts/jsbin/player-{0}.js\", cipherVersion);\r\nstring js = HttpHelper.DownloadString(jsUrl); // ### BREAKPOINT ###\r\n\r\n//Find \"C\" in this: var A = B.sig||C (B.s)\r\nstring functNamePattern = @\"\\.sig\\s*\\|\\|([a-zA-Z0-9\\$]+)\\(\"; //Regex Formed To Find Word or DollarSign\r\n\r\nvar funcName = Regex.Match(js, functNamePattern).Groups[1].Value;\r\n            \r\nif (funcName.Contains(\"$\")) \r\n{\r\n    funcName = \"\\\\\" + funcName; //Due To Dollar Sign Introduction, Need To Escape\r\n}\r\n\r\nstring funcPattern = @\"var \" + @funcName + @\"=function\\(\\w+\\)\\{.*?\\};\"; //Escape funcName string\r\nvar funcBody = Regex.Match(js, funcPattern).Value; //Entire sig function\r\nvar lines = funcBody.Split(';'); //Each line in sig function\r\n```\r\n\r\nStart by placing your breakpoint at the line where the player js is being stored after being downloaded, in this case\r\n\r\n```C#\r\n string js = HttpHelper.DownloadString(jsUrl);\r\n```\r\n\r\nAnd check if this variable get's filled with data _(Tons of, actually)_. If this is **not** the case you have found the first problem: The player file is located in a different location. If this is the case most likely the Regex in the \r\n```C#\r\nGetHtml5PlayerVersion()\r\n```\r\n method has to be updated.\r\nGot the js content in your variable? Good! Copy it over to some Regex capable text editor. _(Sublime does a good job at this)_.\r\nNow continue step for step in VS.\r\n  \r\nThe next thing to check is\r\n```C#\r\n//Find \"C\" in this: var A = B.sig||C (B.s)\r\nstring functNamePattern = @\"\\.sig\\s*\\|\\|([a-zA-Z0-9\\$]+)\\(\";\r\n```\r\nNotice the comment _Find \"C\" in this: var A = B.sig||C (B.s)_.\r\nNone of this characters are actually being used, except for _.sig_. All other are placeholders and are there to show the general form of what we search.\r\nWhat we search for is this:\r\nA variable (Keyword _var_ in js) with the name _A_ which checks if object _B.sig_ OR the return value of method _C_ which gets parameter _B.s_ passed is true (Which means the signature needs to be decrypted).\r\nNow this one was hard, but don't care as much. What we need to know is the actual name of the method **C**, which does the decryption if run in the browser, so we can use it's code.\r\nTo do this we have a regex witch searches exactly for this:\r\n```Regex\r\n\\.sig\\s*\\|\\|([a-zA-Z0-9\\$]+)\\(\r\n```\r\nwhich does this (Copied from regex101.com)\r\n```\r\n\\.sig\\s*\\|\\|([a-zA-Z0-9\\$]+)\\(/\r\n\\. matches the character . literally\r\nsig matches the characters sig literally (case sensitive)\r\n\\s* match any white space character [\\r\\n\\t\\f ]\r\nQuantifier: * Between zero and unlimited times, as many times as possible, giving back as needed [greedy]\r\n\\| matches the character | literally\r\n\\| matches the character | literally\r\n1st Capturing group ([a-zA-Z0-9\\$]+)\r\n[a-zA-Z0-9\\$]+ match a single character present in the list below\r\nQuantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]\r\na-z a single character in the range between a and z (case sensitive)\r\nA-Z a single character in the range between A and Z (case sensitive)\r\n0-9 a single character in the range between 0 and 9\r\n\\$ matches the character $ literally\r\n\\( matches the character ( literally\r\n```\r\nI let out the dollar sign because this is deprecated and not used anymore.\r\nIf you use this regex on the js file (case-sensitive) you should find exactly one match _(hopefully)_ in this case it's\r\n```\r\n.sig||gr(\r\n```\r\nIf you add some characters before and at the end of the match you can see the form again:\r\n```\r\nvar f=e.sig||gr(e.s)\r\n```\r\nBut this time we have the real name of the function which holds the code for decrypting the signatures **gr**.\r\nSince we have the function name now we should be able to pull the code of the method, right? Let's start of with the regex to find that:\r\n```\r\nvar gr=function\\(\\w+\\)\\{.*?\\};\r\n```\r\nagain, the explanation:\r\n```\r\nvar gr=function matches the characters var gr=function literally (case sensitive)\r\n\\( matches the character ( literally\r\n\\w+ match any word character [a-zA-Z0-9_]\r\nQuantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]\r\n\\) matches the character ) literally\r\n\\{ matches the character { literally\r\n.*? matches any character (except newline)\r\nQuantifier: *? Between zero and unlimited times, as few times as possible, expanding as needed [lazy]\r\n\\} matches the character } literally\r\n; matches the character ; literally\r\n```\r\nThis is quite simple: First find the function declaration _var gr=function_ add the parameter (could be everything we don't care, but only word characters are allowed -> _(\\w+)_ now the beginning of the code block _{_, now everything in it (the function's code!) but only up to the end of the code block _}_ and end of declaration _;_.\r\nShould work right?\r\nNo this time. Because that's what changed. If you do step by step debugging you'll find out that after the\r\n```C#\r\n var funcBody = Regex.Match(js, funcPattern).Value; //Entire sig function\r\n```\r\ncall the variable stay empty, because the regex did not match anything in the js file (you can try yourself in your editor). That's bad. What we need to do now is some searching to find the code block in the js again.\r\nYou may do in a other way, but I started this way:\r\nSimplify the regex until you get a reasonable amount of matches to check manually. (Don't try to optimize when you are down to 10 matches if this would take you longer to do than checking manually).\r\nI started by dropping any unneeded characters.\r\nFirst I dropped _var_. No match.\r\nDropped _;_. No match.\r\nDropped everything till I got to _gr=_. If searching case-sensitive you come down to 3 matches -> check them.\r\n1)\r\n```javascript\r\nc.cgr=!0;\r\n```\r\n2) \r\n```javascript\r\nh.gr=function(){W8(this,this.ha,this.Y)};\r\n```\r\n3) \r\n```javascript\r\ngr=function(a){a=a.split(\"\");\r\nfr.Ww(a,13);fr.W9(a,69);fr.Gz(a,3);fr.Ww(a,2);fr.W9(a,79);fr.Gz(a,3);fr.Ww(a,36);return a.join(\"\")}\r\n``` \r\nNo look at the code itself.\r\n1) Not a function declaration, can't be it.\r\n2) Is a function, but takes no parameter's (Remember _C_ takes _B.s_ as parameter), can't be it\r\n3) Is a function, takes parameter, does some actual work and returns something. **Bingo**.\r\n\r\nNow we need a new regex to match the new location and format of the function, look before and after the function:\r\n```javascript\r\nsubstr(2))},gr=function(a){a=a.split(\"\");\r\nfr.Ww(a,13);fr.W9(a,69);fr.Gz(a,3);fr.Ww(a,2);fr.W9(a,79);fr.Gz(a,3);fr.Ww(a,36);return a.join(\"\")},hr=function(a\r\n```\r\nWhat the content does is not our business, but the formatting before and after is:\r\nIt looks like the declaration of the function is now in a list or similar, so the _var_ got dropped, also the semicolon at the end got replaced by an comma. Now adapt these changes to our regex we end up with something like this:\r\n```\r\ngr=function\\(\\w+\\)\\{.*?\\},\r\n```\r\nalso it look like there were some newlines added so it's a good idea to tell regex to match over the whole content, not only per line (Not necessarily necessary, but it could safe us from some trouble in the future)\r\n\r\nBring the regex back into our decryption method:\r\n```C#\r\nstring funcPattern = @funcName + @\"=function\\(\\w+\\)\\{.*?\\},\"; //Escape funcName string\r\n``` \r\nand voilà _funcBody_ should have a value again.\r\nCase closed.\r\n\r\nFrom here it's taking what's in the function body, understanding what is done with the signature (No real encryption, just some character swapping and string reversing) and translating it to C#, so not only our webbrowser can do this, but also our own little library. But this would be even more too much than this comment here is, but googling \"youtube signature decryption\" should lead you way.\r\n\r\nHave a great day!\r\n"}}