Youtube throttle - félig kibogozva...

Mivel s_balazs a múltkor leadta a drótot (ezúton is köszi még egyszer), hogy a Kodiban már megoldott ez a dolog, így kicsit több infóval bírtam nekiugrani a témának...

Kezdjük azzal, hogy a tecső állítólag HTTP/3 over QUIC kapcsolat esetén tojik a throttle signature-re (#1, #2), amivel az a baj, hogy ezt a setupot sem a youtube-dl/yt-dlp/egyéb Pythonos YT extractorok, sem az MPV/VLC/whatever nem fogja egyhamar adni (ez a felállás kb. Chrome/Firefox-only (+ Safari experimental): QUIC, HTTP/3), tehát erre bazírozni tökéletes zsákutca. (Nem, én hiába is implementálnám a YTFE-ben, mert nem az játtsza le a videókat.) A kugli amúgy is elmehetne a vérbe a QUIC erőltetésével, de ez mellékes; akit érdekel, itt egy link: https://medium.com/codavel-blog/quic-vs-tcp-tls-and-why-quic-is-not-the-next-big-thing-d4ef59143efd

Megnéztem azt is, hogy a yt-dlp hogy oldotta meg, de ők kb. behúztak egy JS interpretert a játékba, aztán szíjon gázt a kugli...egyébként nem tudom őket hibáztatni a dologért, csak így a Python mellett még a JS-t is futtatniuk kell majd...

Belemélyedtem a Kodi megoldásának a tanulmányozásába (#1, #2). Ez zéró Python tudás mellett nem volt olyan egyszerű, de szerencsére kommentelték a forrást, így az gyorsan kiderült, hogy ők megkeresik az érintett függvényt, majd szétdobják funkciókra és wrappelik Pythonos megfelelőkre...azaz tkp. majdhogynem ugyanazt csinálták, mint én a múltkor a signatureCipher visszafejtésénél. Ez már gyorsan rávezetett a megoldás felé vezető útra: fogtam a tecső player kódját, majd rákerestem benne a reverse() függvényre, majd némi keresgetés/analizálgatás/scriptelgetés után kipakoltam a legvalószínűbbnek látszó függvényt egy külön fájlba, aztán kinyitottam egy tecső videót a YTFE-vel, kiszedtem egy közvetlen linket, majd az URL-ben lévő cipherelt n paraméterre ráeresztettem a frissen kiberhelt függvényt nodejs segítségével. Visszahelyettesítés után kinyitottam a kapott linket MPV-ben és láss csodát, annyi lett a throttle-nak, lehetett normálisan nézni a full HD-s videót.

Eddig a jó hírek, de most jön a fekete leves. Az ominózus függvény ugyanis így néz ki:

qha = function(a) {
	var b = a.split(""),
	c = [-470482026, -691770757, function(d, e) {
		e = (e % d.length + d.length) % d.length;
		d.splice(-e).reverse().forEach(function(f) {
		d.unshift(f)
		})
	},
	b, 258876269, -1426380890, 318754300, -68090711, -2064438462, -1886316521, 1913911047, 1635047330,
	function(d, e) {
		e = (e % d.length + d.length) % d.length;
		d.splice(-e).reverse().forEach(function(f) {
		d.unshift(f)
		})
	},
	-1815897225, 1940621629, -714586149, -1723898467, null, 778601498, 2145333248, 1245726977, 1952270083, 268207944, 244274044, null,
	function(d, e) {
		e = (e % d.length + d.length) % d.length;
		d.splice(0, 1, d.splice(e, 1, d[0])[0])
	},
	null, -762271981, 604636391, 1087224318, -931565987, -338396815,
	function(d, e) {
		for (e = (e % d.length + d.length) % d.length; e--;) d.unshift(d.pop())
	},
	2126741474,
	function(d) {
		for (var e = d.length; e;) d.push(d.splice(--e, 1)[0])
	},
	-1874551858, -1238260579, 498106911, 1913911047, -1951114300, -504396507, b, 344510945, 905306344, b,
	function(d, e) {
		e = (e % d.length + d.length) % d.length;
		var f = d[0];
		d[0] = d[e];
		d[e] = f
	},
	909033134, 1027812119, 1686673079,
	function(d, e) {
		d.push(e)
	},
	-1902376100,
	function(d, e) {
		e = (e % d.length + d.length) % d.length;
		d.splice(e, 1)
	},
	"push",
	function(d, e) {
		for (var f = 64, h = []; ++f - h.length - 32;) switch (f) {
		case 58:
			f = 96;
			continue;
		case 91:
			f = 44;
			break;
		case 65:
			f = 47;
			continue;
		case 46:
			f = 153;
		case 123:
			f -= 58;
		default:
			h.push(String.fromCharCode(f))
		}
		d.forEach(function(l, m, n) {
		this.push(n[m] = h[(h.indexOf(l) - h.indexOf(this[m]) + m - 32 + f--) % h.length])
		}, e.split(""))
	}
	];
	c[17] = c;
	c[24] = c;
	c[26] = c;
	try {
		c[45](c[17], c[38]), c[12](c[44], c[29]), c[45](c[26], c[0]), c[51](c[41], c[13]), c[12](c[41], c[27]), c[12](c[26], c[11]), c[39](c[17], c[49]), c[9](c[38], c[47]), c[26](c[40], c[0]), c[7](c[8], c[44]), c[14](c[54], c[0]), c[18](c[3], c[25]), c[7](c[33], c[36]), c[15](c[19], c[14]), c[7](c[19], c[9]), c[7](c[6], c[12]), c[41](c[33], c[35]), c[7](c[40], c[5]), c[50](c[42]), c[13](c[14], c[17]), c[6](c[35], c[51]), c[26](c[48], c[50]), c[26](c[35], c[0]), c[6](c[21], c[46]), c[15](c[21], c[42]), c[1](c[2], c[43]), c[15](c[2],
		c[31]), c[1](c[21], c[25]), c[22](c[30], c[17]), c[15](c[44], c[46]), c[22](c[44], c[11]), c[22](c[23], c[38]), c[1](c[23], c[14]), c[35](c[23], c[44]), c[11](c[53], c[20]), c[9](c[51]), c[31](c[51], c[28]), c[18](c[51], c[35]), c[46](c[53], c[6]), c[52](c[51], c[49]), c[11](c[53], c[15])
	} catch (d) {
		return "enhanced_except_75MBkOz-_w8_" + a
	}
	return b.join("")
};

Na, most, ezt visszafejteni még nem olyan nehéz, meg ugyanezt leimplementálni Pascalban sem, de itt nem egyszerűen ezt kell leimplementálni, hanem tkp. egy értelmezőt kellene írni, ami felismeri, hogy ezekből a műveletekből mit és mikor kell végrehajtani. Azaz fel kell, hogy ismerje, hogy a c tömb egyes elemei mit csinálnak, majd utána a try blokkban lévő a c tömb indexeivel meghatározott műveletsorozatot végre kell hajtania. (Külön fun lesz, hogy a c tömbbe a kugli a definíció és a műveletsor közt a tömb pár eleme helyére bekopírozza magát a tömböt még egyszer...)

A másik megoldás az, ami már tkp. készen is van (ill. a pár soros kísérleti PHP kódot még át kéne ültetni Pascalba), csak ahhoz nodejs kell. A kísértés erős, de a hányinger egyelőre erősebb. :P

Úgyhogy látszik már a fény az alagút végén (de miért dudál?!), aztán, ha sikerül, akkor megint menni fog rendesen a tecső, amíg a kugli megint ki nem talál valamit...

Hozzászólások

:O naice.

Every single person is a fool, insane, a failure, or a bad person to at least ten people.

Amúgy ez a küzdelem mire jó? Úgyis mindig elromlik minden módszer, nem? És mindez a reklámok miatt, vagy miért?

De előtte hosszú hónapokig jó. A kugli által eltört dolgok javítása nem tart annyi ideig. Nem a reklámok miatt van (elsősorban), azok nekem browserből sem voltak. Ez azért van, mert a tecső felülete teljesen használhatatlanná vált. Nem csak azért, mert az, ahogy működik az minden csak nem használható, de mellette még a jávaszkript miatt felzabálja a gépet reggelire; egy full HD video lejátszása nálam kb. a CPU 5%-át eszi meg (MPV-ből), még a ventilátorok sem pörögnek fel, viszont maga a tecső, browserből úgy eszi meg a CPU 30-40%-át, hogy pár kép, egyszínű négyzet és némi szöveg kirakása a feladat és úgy bőgeti a ventilátorokat, hogy a szomszéd galaxisban is hallatszik. Jávaszkript. A legelső kiadott YTFE-nél kifejtettem kicsit részletesebben.

Gratula a visszafejtéshez. Tényleg hányinger, amit a yt csinál. Érthetetlen.

"Jegyezze fel a vádhoz - utasította Metcalf őrnagy a tizedest, aki tudott gyorsírni. - Tiszteletlenül beszélt a feljebbvalójával, amikor nem pofázott közbe."

Még nincs teljesen visszafejtve, de köszi. :)
Múltkor is volt téma, nekem is érthetetlen volt, mert egyszerűen megkerülhető védelem volt, de Mcsiv és bra-ket rámutatott, hogy nem is engem akar megfogni a kugli... Mondjuk ez már egy fokkal komolyabb védelem, de ez is kijátszható.

Ügyes.
Viszont eljön majd az idő, amikor a G webassembly-ben tolja le a hókuszpókuszát a böngészőbe. Azt keményebb lesz visszafejteni.

Na, örömmel jelentem, hogy ebben a percben sikerült végképp kibogozni ezt a szart; a kísérleti PHP-s decipherelő ugyanazt adja vissza, mint a nodejs-sel futtatott eredeti kuglis-jávaszkriptes. Még át kell írni Pascalba, utána búcsút inthetünk a throttle-nek. (Aztán jöhet a következő szívatás.)

> A másik megoldás az, ami már tkp. készen is van (ill. a pár soros kísérleti PHP kódot még át kéne ültetni Pascalba), csak ahhoz nodejs kell.

nem világos mihez használod használnád pontosan a nodejst, de én eddig ha js-hez kellett nyúlnom megúsztam a Bellard-fél quickjs-sel. Nem tudom a te céljaidnak megfelelne-e

let's go Brandon!

Hú, köszi, így, ha parancssori JS kell, akkor megszabadulhatok a nodejs sokmegás bloat-jától. Egyébként erre kellett volna csak, hogy miután kipecáztam a kugli örvénylő fostengerének mélyéről a decipher rutint, meghívom valamilyen parancssori JS interpreterrel az n szignatúrára (szerintem a fentebbi kódot viszi bármilyen ES5-nél későbbi JS VM, úgyhogy biztos megfelelt volna a QuickJS is) és így nem kell deciphert írnom...csak közben már megírtam a deciphert. :P De köszi, jól fog ez jönni máskor is.

Az meg még pláne jól jöhet, ha a kugli nagyon bekeményít; most ugyan megint megúsztam - akár külső, akár belső - JS interpreter nélkül, de nem biztos, hogy mindig ilyen szerencsém lesz... A license is megengedi, szóval, ha a kugli előáll egy nap egy olyan cipherrel, ami többszáz kB, akkor tuti az lesz, hogy beágyazom a QuickJS-t. :)

https://github.com/bero1985/besen

itt van ez is, ezt eddig azért nem írtam mert még nem használtam a quickjs-sel ellentétben, de ez a BeRo is jó warekat ír, és ez ráadásul Pascalban van :)
az megkönnyítené ha be kéne ágyazni

let's go Brandon!

Hoppá, ilyen is van? :) Köszi ezt is, ez is még jól jöhet.
Sajnos csak elméletileg lenne könnyebb beágyazni, a gyakorlatban a license (LGPL) miatt ezt egyáltalán nem tudom beágyazni, maximum külső libraryként tudnám használni, dehát úgy akár a QuickJS-t is tudnám, viszont azt tényleg be is tudom ágyazni a programba, csak a wrapper unitot kellene megírnom a fordító által kiköpött objectekhez.