11using System ;
2+ using System . Collections . Generic ;
23using System . Linq ;
34using System . Text ;
45using System . Text . RegularExpressions ;
@@ -12,132 +13,116 @@ public static string DecipherWithVersion(string cipher, string cipherVersion)
1213 string jsUrl = string . Format ( "http://s.ytimg.com/yts/jsbin/player-{0}.js" , cipherVersion ) ;
1314 string js = HttpHelper . DownloadString ( jsUrl ) ;
1415
15- //Find "C" in this: var A = B.sig||C (B.s)
16- string functNamePattern = @"\""signature"",\s?([a-zA-Z0-9\$]+)\(" ; //Regex Formed To Find Word or DollarSign
16+ var decodeArray = FindSignatureCode ( js ) ;
1717
18- var funcName = Regex . Match ( js , functNamePattern ) . Groups [ 1 ] . Value ;
19-
20- if ( funcName . Contains ( "$" ) )
21- {
22- funcName = "\\ " + funcName ; //Due To Dollar Sign Introduction, Need To Escape
23- }
18+ return DecryptSignature ( cipher , decodeArray ) ;
19+ }
2420
25- string funcPattern = @"(?!h\.)" + @funcName + @"=function\(\w+\)\{.*?\}" ; //Escape funcName string
26- var funcBody = Regex . Match ( js , funcPattern , RegexOptions . Singleline ) . Value ; //Entire sig function
27- var lines = funcBody . Split ( ';' ) ; //Each line in sig function
21+ private static List < int > FindSignatureCode ( string sourceCode )
22+ {
23+ var signatureFunctionName = FindMatch ( sourceCode , @"\.set\s*\(""signature""\s*,\s*([a-zA-Z0-9_$][\w$]*)\(" ) ;
2824
29- string idReverse = "" , idSlice = "" , idCharSwap = "" ; //Hold name for each cipher method
30- string functionIdentifier = "" ;
31- string operations = "" ;
25+ //Optimization of Gantt's technique - functionName not needed
26+ var regExp = @"\s*\([\w$]*\)\s*{[\w$]*=[\w$]*\.split\(""""\);\n*(.+);return [\w$]*\.join" ;
3227
33- foreach ( var line in lines . Skip ( 1 ) . Take ( lines . Length - 2 ) ) //Matches the funcBody with each cipher method. Only runs till all three are defined.
34- {
35- if ( ! string . IsNullOrEmpty ( idReverse ) && ! string . IsNullOrEmpty ( idSlice ) &&
36- ! string . IsNullOrEmpty ( idCharSwap ) )
37- {
38- break ; //Break loop if all three cipher methods are defined
39- }
28+ var reverseFunctionName = FindMatch ( sourceCode , @"([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.reverse\s*\(\s*\)\s*}" ) ;
29+ var sliceFunctionName = FindMatch ( sourceCode , @"([\w$]*)\s*:\s*function\s*\(\s*[\w$]*\s*,\s*[\w$]*\s*\)\s*{\s*(?:return\s*)?[\w$]*\.(?:slice|splice)\(.+\)\s*}" ) ;
4030
41- functionIdentifier = GetFunctionFromLine ( line ) ;
42- string reReverse = string . Format ( @"{0}:\bfunction\b\(\w+\)" , functionIdentifier ) ; //Regex for reverse (one parameter)
43- string reSlice = string . Format ( @"{0}:\bfunction\b\([a],b\).(\breturn\b)?.?\w+\." , functionIdentifier ) ; //Regex for slice (return or not)
44- string reSwap = string . Format ( @"{0}:\bfunction\b\(\w+\,\w\).\bvar\b.\bc=a\b" , functionIdentifier ) ; //Regex for the char swap.
31+ var functionCode = FindMatch ( sourceCode , regExp ) ;
32+ functionCode = functionCode . Replace ( reverseFunctionName , " reverse" ) ;
33+ functionCode = functionCode . Replace ( sliceFunctionName , " slice" ) ;
34+ var functionCodePieces = functionCode . Split ( ';' ) ;
4535
46- if ( Regex . Match ( js , reReverse ) . Success )
47- {
48- idReverse = functionIdentifier ; //If def matched the regex for reverse then the current function is a defined as the reverse
49- }
36+ List < int > decodeArray = new List < int > ( ) ;
5037
51- if ( Regex . Match ( js , reSlice ) . Success )
52- {
53- idSlice = functionIdentifier ; //If def matched the regex for slice then the current function is defined as the slice.
54- }
38+ var regSlice = new Regex ( "slice\\ s*\\ (\\ s*.+([0-9]+)\\ s*\\ )" ) ;
39+ string regSwap = "\\ w+\\ s*\\ (\\ s*\\ w+\\ s*,\\ s*([0-9]+)\\ s*\\ )" ;
40+ string regInline = "\\ w+\\ [0\\ ]\\ s*=\\ s*\\ w+\\ [([0-9]+)\\ s*%\\ s*\\ w+\\ .length\\ ]" ;
5541
56- if ( Regex . Match ( js , reSwap ) . Success )
57- {
58- idCharSwap = functionIdentifier ; //If def matched the regex for charSwap then the current function is defined as swap.
59- }
60- }
61-
62- foreach ( var line in lines . Skip ( 1 ) . Take ( lines . Length - 2 ) )
42+ for ( var i = 0 ; i < functionCodePieces . Length ; i ++ )
6343 {
64- Match m ;
65- functionIdentifier = GetFunctionFromLine ( line ) ;
6644
67- if ( ( m = Regex . Match ( line , @"\(\w+,(?<index>\d+)\)" ) ) . Success && functionIdentifier == idCharSwap )
68- {
69- operations += "w" + m . Groups [ "index" ] . Value + " " ; //operation is a swap (w)
70- }
45+ functionCodePieces [ i ] = functionCodePieces [ i ] . Trim ( ) ;
7146
72- if ( ( m = Regex . Match ( line , @"\(\w+,(?<index>\d+)\)" ) ) . Success && functionIdentifier == idSlice )
73- {
74- operations += "s" + m . Groups [ "index" ] . Value + " " ; //operation is a slice
75- }
47+ var codeLine = functionCodePieces [ i ] ;
7648
77- if ( functionIdentifier == idReverse ) //No regex required for reverse (reverse method has no parameters )
49+ if ( codeLine . Length > 0 )
7850 {
79- operations += "r " ; //operation is a reverse
80- }
81- }
8251
83- operations = operations . Trim ( ) ;
52+ var arrSlice = regSlice . Match ( codeLine ) ;
8453
85- return DecipherWithOperations ( cipher , operations ) ;
86- }
87-
88- private static string ApplyOperation ( string cipher , string op )
89- {
90- switch ( op [ 0 ] )
91- {
92- case 'r' :
93- return new string ( cipher . ToCharArray ( ) . Reverse ( ) . ToArray ( ) ) ;
94-
95- case 'w' :
54+ if ( arrSlice . Success && arrSlice . Length >= 2 )
9655 {
97- int index = GetOpIndex ( op ) ;
98- return SwapFirstChar ( cipher , index ) ;
56+ var slice = int . Parse ( arrSlice . Groups [ 1 ] . Value ) ;
57+ decodeArray . Add ( - slice ) ;
9958 }
100-
101- case 's' :
59+ else if ( functionCodePieces [ i ] . IndexOf ( "reverse" ) >= 0 )
10260 {
103- int index = GetOpIndex ( op ) ;
104- return cipher . Substring ( index ) ;
61+ decodeArray . Add ( 0 ) ;
62+ }
63+ else if ( codeLine . IndexOf ( "[0]" ) >= 0 )
64+ { // inline swap
65+
66+ if ( i + 2 < functionCodePieces . Length && functionCodePieces [ i + 1 ] . IndexOf ( ".length" ) >= 0 && functionCodePieces [ i + 1 ] . IndexOf ( "[0]" ) >= 0 )
67+ {
68+
69+ var inline = FindMatch ( functionCodePieces [ i + 1 ] , regInline ) ;
70+ decodeArray . Add ( int . Parse ( inline ) ) ;
71+
72+ i += 2 ;
73+
74+ }
10575 }
76+ else if ( codeLine . IndexOf ( ',' ) >= 0 )
77+ { // swap
78+ var swap = FindMatch ( codeLine , regSwap ) ;
79+ int swapVal = int . Parse ( swap ) ;
10680
107- default :
108- throw new NotImplementedException ( "Couldn't find cipher operation." ) ;
81+ if ( swapVal > 0 )
82+ {
83+ decodeArray . Add ( swapVal ) ;
84+ }
85+
86+ }
87+ }
10988 }
89+ return decodeArray ;
11090 }
11191
112- private static string DecipherWithOperations ( string cipher , string operations )
92+ private static string DecryptSignature ( string sig , List < int > arr )
11393 {
114- return operations . Split ( new [ ] { " " } , StringSplitOptions . RemoveEmptyEntries )
115- . Aggregate ( cipher , ApplyOperation ) ;
116- }
94+ var sigA = sig ;
11795
118- private static string GetFunctionFromLine ( string currentLine )
119- {
120- Regex matchFunctionReg = new Regex ( @"\w+\.(?<functionID>\w+)\(" ) ; //lc.ac(b,c) want the ac part.
121- Match rgMatch = matchFunctionReg . Match ( currentLine ) ;
122- string matchedFunction = rgMatch . Groups [ "functionID" ] . Value ;
123- return matchedFunction ; //return 'ac'
96+ for ( var i = 0 ; i < arr . Count ; i ++ )
97+ {
98+ var act = arr [ i ] ;
99+ sigA = ( act > 0 ) ? Swap ( sigA . ToCharArray ( ) , act ) : ( ( act == 0 ) ? Reverse ( sigA ) : sigA . Substring ( - act ) ) ;
100+ }
101+
102+ return sigA ;
124103 }
125104
126- private static int GetOpIndex ( string op )
105+ private static string Swap ( char [ ] a , int b )
127106 {
128- string parsed = new Regex ( @".(\d+)" ) . Match ( op ) . Result ( "$1" ) ;
129- int index = Int32 . Parse ( parsed ) ;
107+ var c = a [ 0 ] ;
108+ a [ 0 ] = a [ b % a . Length ] ;
109+ a [ b ] = c ;
130110
131- return index ;
111+ return new string ( a ) ;
132112 }
133113
134- private static string SwapFirstChar ( string cipher , int index )
114+ private static string Reverse ( string s )
115+ {
116+ char [ ] charArray = s . ToCharArray ( ) ;
117+ Array . Reverse ( charArray ) ;
118+ return new string ( charArray ) ;
119+ }
120+ private static string FindMatch ( string text , string regexp )
135121 {
136- var builder = new StringBuilder ( cipher ) ;
137- builder [ 0 ] = cipher [ index ] ;
138- builder [ index ] = cipher [ 0 ] ;
122+ Regex rgx = new Regex ( regexp ) ;
123+ var matches = rgx . Matches ( text ) ;
139124
140- return builder . ToString ( ) ;
125+ return matches [ 0 ] . Groups [ 1 ] . Value ;
141126 }
142127 }
143128}
0 commit comments