Youtube tartalmak közvetlen linkjének visszafejtése

A youtube minden egyes a videóknál elérhető formátumhoz (AKA. minőség) egy-egy stream URL-t rendel, azonban az URL-ek egy részét - nem jöttem rá, hogy milyen kritériumok alapján - egy titkosított aláírás átadáshoz köti. Ahhoz, hogy a valódi aláírást megkapjuk, azt vissza kell fejteni.

Adott tehát a JSON tömbben érkező formátumlista elemeiben a signatureCipher JSON property (ill. a kód alapján cipher is lehetne, de sehol nem találkoztam vele), ami maga is egy URL és a következő - URL-encode-olt - elemei vannak:

  • url: a tényleges stream URL, ami azonban az aláírás nélkül nem fog menni, 403-at dob.
  • s: az aláírás, ez az a rész, ami titkosítva van, ha így visszafejtetlenül használjuk, az ugyanúgy 403-at fog eredményezni.
  • sp: az aláírás paraméterének neve, azaz, hogy milyen paraméterben kell majd átadni a stream URL-hez fűzve a visszafejtett aláírást; ez egyébként jelenleg mindenütt 'sig'.

Tehát a végleges URL kb. úgy fog kinézni (pszeudokódban), hogy URLDecode(signatureCipher.url) + '&' + URLDecode(signatureCipher.sp) + '=' + DeCipher(URLDecode(signatureCipher.s));
Hogy az a bizonyos pseudocall, a DeCipher mit takar, azt egy másik JSON tömb jsUrl property-je mögötti JS fájlból derül ki, pl. '/s/player/5dd3f3b2/player_ias.vflset/hu_HU/base.js'. Ez a teljes YT player, amiben benne van többek között a decipher mechanizmus is. A jelek szerint azonban az egész úgy van megkonstruálva, hogy a lépéseket és azok paramétereit változtatni tudják, ők tudják mikor és hogyan, a változók és függvények neveiről nem is beszélve (obfuszkált az egész).

Ha rákeresünk ebben az obfuszkált kódban a 'signatureCipher' stringre, akkor az összes esetben azt fogjuk találni, hogy kb. ilyen kód tartozik hozzá (deobfuszkálva):

var valami = masvalami.cipher || masvalami.signatureCipher;
if(valami)
{
	var megvalami = hivas(valami);
	ize.sp = megvalami.sp;
	ize.s = megvalami.s;
	ize.url = megvalami.url
}
else ize.url = masvalami.url;

Ebben a fájlban a hivas speciel egy aq nevű funkciót takar. Ha rákeresünk (case-dependent módon) az 'aq=function(' stringre, akkor a következőt találjuk:

aq = function(a)
{
	"?" == a.charAt(0) && (a = a.substr(1));
	return Zp(a)
};

Azaz, ha kérdőjellel kezdődik, akkor azt el kell dobni, azonfelül egy másik hívás. Erre is rákeresvén a következőt kapjuk:

Zp = function(a)
{
	for (var b = a.split("&"), c = {}, d = 0, e = b.length; d < e; d++)
	{
		var f = b[d].split("=");
		if (1 == f.length && f[0] || 2 == f.length) try
		{
			var h = nd(f[0] || ""),
				l = nd(f[1] || "");
			h in c ? Array.isArray(c[h]) ? sb(c[h], l) : c[h] = [c[h], l] : c[h] = l
		}
		catch (m)
		{
			m.args = [
			{
				key: f[0],
				value: f[1],
				query: a
			}], gea.hasOwnProperty(f[0]) || ("ReferenceError" === m.name ? g.Jo(m) : g.M(m))
		}
	}
	return c
};

Ebben a következő további - számunkra érdekes - hívásokat találjuk (a kivételkezelés bennünket itt nem érdekel, mert a decipher algoritmusra vagyunk kiváncsiak), egyfelől az nd-t

nd = function(a)
{
	return decodeURIComponent(a.replace(/\+/g, " "))
};

ill. az sb-t:

sb = function(a, b)
{
	for (var c = 1; c < arguments.length; c++)
	{
		var d = arguments[c];
		if (g.Na(d))
		{
			var e = a.length || 0,
				f = d.length || 0;
			a.length = e + f;
			for (var h = 0; h < f; h++) a[e + h] = d[h]
		}
		else a.push(d)
	}
};

Ezen belül még van egy bizonyos g object Na függvénye

g.Na = function(a)
{
	var b = Ma(a);
	return "array" == b || "object" == b && "number" == typeof a.length
};

benne egy Ma meghívással:

Ma = function(a)
{
	var b = typeof a;
	return "object" != b ? b : a ? Array.isArray(a) ? "array" : b : "null"
};

Szerencsére több meghívás már nincs, viszont ezzel nem jutottunk előrébb, mert amint a kódból is látszik (vagy akár rá is lehet hívni a kinyert kódot egy signatureCipher-ből kinyert stringre), ez a katyvasz csak a szétbontásért felelős, hogy egy objektumba beleteszi a három elemet, de nem csinál velük semmit az URL-decode-ingon - meg az esetleges indító kérdőjel leszedésén - kívül.

Ez tehát azt jelenti, hogy a decipher máshol történik, azt külön meg kell hívni a kapott objektum s elemére. Keressünk rá - továbbra is case-dependent módon - arra, hogy '.s);', vagy '.s),'. Az idevágó összes kód úgy néz ki, hogy x = hivas(y.url,y.sp,y.s). A 'hivas' ebben a fájlban speciel '$B'. Keressünk rá, hogy '$B=function(' és nézzük mit csinál:

$B = function(a, b, c)
{
	b = void 0 === b ? "" : b;
	c = void 0 === c ? "" : c;
	a = new Aw(a, !0);
	a.set("alr", "yes");
	c && (c = nw(decodeURIComponent(c)), a.set(b, encodeURIComponent(c)));
	return a
};

Egy meghívás van benne (nw()), ami pont a signature-t piszkálja (itt 'c' paraméter). A függvény a következő:

nw = function(a)
{
	a = a.split("");
	mw.p7(a, 34);
	mw.qM(a, 13);
	mw.UX(a, 3);
	mw.p7(a, 44);
	mw.qM(a, 69);
	mw.UX(a, 2);
	mw.qM(a, 58);
	mw.p7(a, 24);
	mw.UX(a, 1);
	return a.join("")
};

Azaz szétdobja a stringet karaktertömbre, hogy műveleteket tudjon végezni vele (long live teh java's crypt), majd egy mw nevű objektum különféle elemeit különféle paraméterekkel meghívogatja rá, aztán összefűzi megint stringnek. Megvan tehát a visszafejtő függvény, már csak az a kérdés, hogy mit is csinál.

Keressünk rá a 'var mw={' stringre (még mindig case-dependent módon) és megvan az objektumunk, benne a függvényekkel:

var mw = {
	p7: function(a)
	{
		a.reverse()
	},
	UX: function(a, b)
	{
		a.splice(0, b)
	},
	qM: function(a, b)
	{
		var c = a[0];
		a[0] = a[b % a.length];
		a[b % a.length] = c
	}
};

Tehát van benne megfordító függvény, olyan, ami leharap N - pontosabban b - karaktert a végéről és egy olyan, ami az N-edik - pontosabban a c-edik - karaktert felcseréli a nulladikkal, a "túlcímzést" a tömb hosszával maradékos osztást végezvén levédve. Külön felhívnám a figyelmet, hogy az ezeket meghívó függvényben azoknak a meghívásoknak is van paramétere, amik a .reverse()-re wrappelnek, aminek viszont nincs; gondolom ezt a függvényt véletlenszerűen töltik fel a másik műveleteivel és nem vesztegetik az időt annak a vizsgálatával, hogy most minek is adnak át mit...

Nos, megvan, hogy mit és hogyan variál az aláírásban, a parsernek ennek megfelelően ugyanezeket a lépéseket kell végigzongoráznia. Először addig keresi a '.s);' és '.s),' stringeket, amíg onnantól visszafele az első zárójelig egy olyan patternt nem kap, ami úgy néz ki, hogy x.url,x.sp,x.s és ha stimmel, akkor az egyenlőségig visszamászva megvan a függvénynév. Utána meg kell keresni a definícióját 'hivas=function(' stringgel, majd utána megkeresni a függvényben a '(decodeURIComponent(' stringet, majd előtte az egyenlőségjelet, a kettő között van maga a decipher neve.
Azt is ugyanígy meg kell keresni 'decipher=function(', majd benne az 'a=a.split("");' és a ';return' közti részt a pontosvesszők mentén szétdarabolni. Az egyes részelemek '.' és '(' közti része mondja meg, hogy mit csináljunk a signature-rel abban a lépésben és a ',' és ')' közti szám pedig az átadandó paraméter. Ezeket kell utána lépésről lépésre végrehajtani, de ehhez még tudni kell azt is, hogy az adott lépés neve mit takar.
Ehhez pedig fogjuk mondjuk a legelső lépés '.' előtti részét, az az objektum neve, majd rá lehet keresni, hogy 'var objektumnev={' és '};', a kettő közti részeket pedig a '},' stringek mentén szétdarabolni, majd a kapott részeknél a kettőspont előtti rész adja a nevet, az utáni részben pedig ellenőrizni kell, hogy van-e reverse, vagy splice és akkor tudjuk, hogy vagy a forgató, vagy a "leharapó", vagy kizárásos alapon a cserélgető funkció van benne.

A parsert már megírtam, működik, úgyhogy a YTFE következő verziója már maga is képes lesz odaadni a videoplayernek a közvetlen URL-t, a videoplayernek nem kell meghívnia a youtube-dl-t.

Amire viszont nem jöttem rá, hogy a tecső miért csinálja ezt. Nem a terhelést akarják csökkenteni, hogy ezeket az URL-eket ne osztogathassa csak úgy meg a jónép és rá ne lehessen akaszkodni direktben, mert egyrészt az URL-eknek csak egy része van levédve, a többihez nem kell signature, másrészt meg az URL-ben magában is van még plusz védelem (lejárat, ip cím, mittudomén), hogy ugyanazt a kapott URL-t ne lehessen más gépen lejátszani. Azt sem hiszem, hogy a tartalmakat védenék vele pl. a robotoktól, mert ezt a mechanizmust visszafejteni kevesebb idő volt, mint ezt a blogposztot megírni róla, tehát bárki írna erre robotot, az ugyanígy meg tudja kerülni (és ugye még mindig csak a linkek egyik fele van védve).
És akkor még ott van a közkedvelt youtube-dl is, ami a videót is le tudja tölteni, vagy a direkt linket kiköpni a felhasználónak; akár scriptelni is lehet.

Viszont akkor vajon miért?

Hozzászólások

Szerkesztve: 2021. 01. 08., p – 22:08

Ez mar az a lvl ami erdekes, de nem akarok belemelyedni es van ami nem is teljesen jon at, masreszt, hogy nagyon jo kezekben van ahogy latom.

Tanulhatnak mostansag, mert vannak olyan reklamok amik atjutnak a blokkeren amit hasznalok.

Azert erdekes mert by default a legnepszerubb yt blok ff ala a legnagyobb hasznalo bazissal es eddig igen jol mukodott.

Masodreszt, mind magyar szoveges reklam, az egyik a "belgazos kocsog" a masik a "bore megrotyosodik gane" amik rendszeresen eljatszak ezt.

Szoval vagy ezek a reklamosok talatak ki valamit, vagy tanulnak a yutusok. Nem orulok.

AndroidTV ? :D

 

Amugy ha eszkoz, serial, os, ip, vagy barmi specifikus akkor nagyon jo tracking modszer.

Ezert van az, hogy ha megnezek egy videot laposon, akkor pl, tv vagy tablet, ami azonos halozaton van egy ido utan elkezdi mutogatni nazokat a csatornakat.

Tehat szerintem epitik a buborekot ezzel is.

http://karikasostor.hu - Az autentikus zajforrás.

Nem t'om, nekem sose voltak reklámok a tyúktúbon, igaz a JS nálam mindig is tiltva volt, meg amúgy is egy raklap reklámszerver domain szinten blokkolva van a böngészőmben (minden, ami szembejött). Az biztos, hogy nem magába a videostream-be injektálják bele a csicsklámot, hanem megszakítják JS-ből a lejátszást és lejátszanak egy másik stream-et, dehát ez ugye nem működik, ha egy natív videoplayerből nézed a közvetlen linken keresztül. (Ez youtube-dl-lel is működött/működik.)

Droidos cuccom meg még mindig nincsen. :)

A tracking-hez mi szükség van a signature-ös védelemre? És ha ahhoz kell, akkor miért ad-hoc módon alkalmazzák?

"Viszont akkor vajon miért?"

Azért hogy ne legyen egyszerű :) Tökéletes védelem nem lesz soha, ezt ők is tudják, ha egy "nyitott" rendszeren belül (a html5/js az) a gépeden le tudod játszani, akkor letölteni is letudod.

// Happy debugging, suckers
#define true (rand() > 10)

Vagyok egy két "programozós" facebook csoportban. A szakmában dolgozók 70-80 százaléka olyan kérdéseket tesz fel, ami hidd el, hogy nem üti meg azt a szintet amiről beszélsz. Ők valószínűleg az obfuszkált kód láttára engedik el.

// Happy debugging, suckers
#define true (rand() > 10)

Akkor viszont neked, meg bra-ketnek van igazatok. Megfordult ugyan a fejemben, hogy ez megint a szutyokszkriptnek a júzerre történő erőltetése, de aztán úgy voltam vele, hogy nem, mert ez a primitív trutymó nem véd semmitől...hát ezek szerint tévedtem.

Előtte ránéztem, ők egy szofisztikáltabb JS interpretert írtak a célra, de mivel nem értek Pythonul, ezért nem tudtam kihámozni belőle, hogy hogy deciphereli, amit kell.

De azt nem írták le, hogy miért is létezik ez a signature védelem. :P

A JS interpreter erősebb, mivel ha a yt változtatja, akkor van esély, hogy továbbra is működjön. Illetve mégse, mert ugye pont ellenük változtatja a yt, nyilván úgy fogják csinálni, hogy a ytdl-ben valami eltörjön :-)

Ez a macska-egér játék végtelennek ígérkezik. Ja, nem mert a yt el fog néptelenedni ahogy lassan minden érdekes tartalmat letiltanak, és MSM irányba mennek, pont úgy fog járni mint a TV.

Ha vetsz egy pillantást a ytdl kódjára, akkor látni fogod, hogy nincsenek sokkal előbbre, mert az interpretálás nem teljeskörű. Ha pl. a tecső behány egy új funkciót, a splice, reverse funkciók mellé, akkor a ytdl is törni fog. Amivel ők előbbre vannak, az a swapper szubrutin tényleges kielemzése, mert ha ott a tecső mondjuk kicseréli, hogy ne a nulladik, hanem mondjuk a második karakterrel cserélje az N-ediket, akkor az náluk továbbra is működni fog, nálam pedig törik. Dehát, ahogy helytállóan megállapítottad, úgyis ők a célpont, tehát úgyis úgy fogják módosítani a kúgelék, hogy a ytdl törjön. :)

Mi a kecskepüré az az MSM? More Shit (for the) Masses? :P

Ja... A kliensembe többek között ez miatt is raktam feketelistát, nekem ezek a szemetek egyszer jelennek meg, utána a csatornát is blokkolom, így nem tűnt fel, hogy annyira aggasztó méreteket öltött volna a fősodrat-felszopás a kontentek szintjén is. :P
Viszont addig nem fog elnéptelenedni, amíg alternatíva nincs rá, márpedig az alternatíváknak is mindek van valami gyíkja.

Ja, nem mert a yt el fog néptelenedni ahogy lassan minden érdekes tartalmat letiltanak

Mik azok az értelmes tartalmak amiket letiltanak? Nagyon sok forrást követek youtube-on, és tényleg vannak gondok velük, de azt nem látnám hogy tömegével tűnnének el ezek a szolgáltatások.

Pedig paráztatnak minket évek óta, hogy itt a vége, megszűnik a szép élet youtube-on, és hogy kivéreztetik a content creatorokat, és hogy majd nem lehet semmit se feltölteni. Eközben a youtube továbbra is tele van teljesen jó tartalmakkal, és olyan csatornák se nagyon látszanak eltűnni, amit nem is értek hogy hogy tud működni, pl a cinemasins, ami egy mozifilm kb negyedét levetíti hogy kiegészítse a saját kommentárjaival. Pedig ott volna bőven copyright kérdés. Aztán valahogy mégis megoldják.

Vagy mi számodra az értelmes tartalom?

Pl. a pornhibon ugy csinaljak, hogy a kliens oldali javascript, 5mb-os fajldarabokat kap, es ugy tolti le a "filmet". Amit osszefuzve jatszik le.

 

Az egyreszt jo cachelesnek is, masreszt, ha nem kapsz kulcsot, akkor az egy-egy fajldarab url-re szerveroldali hibat dob.

 

Most egyelore ugy van, hogy kapsz kulcsot amint megnyitod a video oldalat, es ugyanaz a kulcs jo szerver oldalon az osszes fajldarabhoz.

 

De nem nehez elkepzelni azt a szituaciot, hogy egy-egy reklam megnezese (aka. challenge teljesitese) utan kapod meg a kovetkezo kulcsot ami nyitja a kovetkezo 5-10 fajldarabot.

 

Innen mar egy lepes csak, hogy a reklam megnezese utan kattintanod kell, amiben ellenorzik hogy tenyleg te nezted meg a reklamot (pl. milyen szinu volt a no ruhaja [piros/kek]).

 

Csak a hulye nem latja, hogy errefele haladunk.

 

Ha mar a lehuzasrol van szo: multkor hallgattam, hogy a patreon 30% jutalekot nyul le, aminek joreszet ugyesen "tranzakcios dij" moge rejtik a szerzodesben. De aki mar adott el barmilyen digitalis cuccot a neten (rajz, program, terv, akarmi) az tudja, hogy olyan 3-7% kozott van max. a tranzakcios dij.

 

Aki meg ketelkedne a youtube jovedelmezosegeben, annak kb. annyit mondanek, hogy egy himihumi tv csatorna allja "Karottanak" az elektromos.porsche atepiteset, addig a nagyobb nezoszamot produkalo youtube csatornaja az annyira eleg kb. hogy benzinre futja egy honapban, hogy be tudjon jarni dolgozni....

nevetseges az elteres. Legalabb egy nagysagrenddel kevesebbet fizet a youtube egy musorert ha ugyanannyi a nezoszam.

Annyi a kulonbseg, hogy globalizalta(es monopolizalta) a TV-t igy a kisember is tud ervenyesulni.

De senkit se tevesszen meg: amelyik csatorna eleri az 1M-os megtekintest videonkent amogott altalaban egy komplett team van (3+ fo) rendes koltsegvetessel.

Saying a programming language is good because it works on all platforms is like saying anal sex is good because it works on all genders....

A tecsőn egyelőre még nem ez van, szerencsére. Az, ha valami mechanizmus a háttérben ellenőrzi, hogy megnézted-e a reklámot, pl. megnézi, hogy letöltötted-e, meg ilyesmi, az mind kikerülhető, a hívások, adatmozgások szimulálhatóak, hiszen ha egy browser meg tudja csinálni, akkor akármi meg tudja csinálni, csak tudni kell, hogy hogyan.

Ha úgy fogják csinálni, ahogy mondod, hogy a site kikérdezi a reklám anyagát, akkor két nap alatt össze fog dőlni a rendszer, ugyanis az emberek, ha nem is blokkolják a reklámot (mert leszarja, mert nem tudja, hogy kell, mert öntudatos kapitalista, mert mittudomén), megnézni attól még nem nézik meg, hanem megvárják azt az öt-tíz másodpercet, amíg le lehet lőni és lelövik, így azt sem fogják tudni, hogy mi volt benne. Ha az lesz, mint a trévében, hogy a reklám skippelhetetlen, akkor a sorsa is az lesz, mint a trévéé.

Jól tolod!

Elérhető a forráskód? Szívesen csinálnék neki ebuild-et Gentoo-hoz...

Hajrá!

"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."