forked from kenzuya/unshackle
Update Netflix
This commit is contained in:
BIN
unshackle/WVDs/hisense_vidaa_tv_14.0.0_92747e74_7110_l1.wvd
Normal file
BIN
unshackle/WVDs/hisense_vidaa_tv_14.0.0_92747e74_7110_l1.wvd
Normal file
Binary file not shown.
@@ -10,7 +10,7 @@ import time
|
|||||||
import zlib
|
import zlib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Optional, Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
import jsonpickle
|
import jsonpickle
|
||||||
import requests
|
import requests
|
||||||
@@ -19,15 +19,18 @@ from Cryptodome.Hash import HMAC, SHA256
|
|||||||
from Cryptodome.PublicKey import RSA
|
from Cryptodome.PublicKey import RSA
|
||||||
from Cryptodome.Random import get_random_bytes
|
from Cryptodome.Random import get_random_bytes
|
||||||
from Cryptodome.Util import Padding
|
from Cryptodome.Util import Padding
|
||||||
|
from pywidevine import PSSH, Cdm, Key
|
||||||
|
|
||||||
from unshackle.core.cacher import Cacher
|
from unshackle.core.cacher import Cacher
|
||||||
|
|
||||||
from .MSLKeys import MSLKeys
|
from .MSLKeys import MSLKeys
|
||||||
from .schemes import EntityAuthenticationSchemes # noqa: F401
|
from .schemes import (
|
||||||
from .schemes import KeyExchangeSchemes
|
EntityAuthenticationSchemes, # noqa: F401
|
||||||
|
KeyExchangeSchemes,
|
||||||
|
)
|
||||||
from .schemes.EntityAuthentication import EntityAuthentication
|
from .schemes.EntityAuthentication import EntityAuthentication
|
||||||
from .schemes.KeyExchangeRequest import KeyExchangeRequest
|
from .schemes.KeyExchangeRequest import KeyExchangeRequest
|
||||||
from pywidevine import Cdm, PSSH, Key
|
|
||||||
|
|
||||||
class MSL:
|
class MSL:
|
||||||
log = logging.getLogger("MSL")
|
log = logging.getLogger("MSL")
|
||||||
@@ -41,7 +44,16 @@ class MSL:
|
|||||||
self.message_id = message_id
|
self.message_id = message_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handshake(cls, scheme: KeyExchangeSchemes, session: requests.Session, endpoint: str, sender: str, cache: Cacher, cdm: Optional[Cdm] = None, config: Any = None):
|
def handshake(
|
||||||
|
cls,
|
||||||
|
scheme: KeyExchangeSchemes,
|
||||||
|
session: requests.Session,
|
||||||
|
endpoint: str,
|
||||||
|
sender: str,
|
||||||
|
cache: Cacher,
|
||||||
|
cdm: Optional[Cdm] = None,
|
||||||
|
config: Any = None,
|
||||||
|
):
|
||||||
cache = cache.get(sender)
|
cache = cache.get(sender)
|
||||||
message_id = random.randint(0, pow(2, 52))
|
message_id = random.randint(0, pow(2, 52))
|
||||||
msl_keys = MSL.load_cache_data(cache)
|
msl_keys = MSL.load_cache_data(cache)
|
||||||
@@ -53,20 +65,18 @@ class MSL:
|
|||||||
if scheme != KeyExchangeSchemes.Widevine:
|
if scheme != KeyExchangeSchemes.Widevine:
|
||||||
msl_keys.rsa = RSA.generate(2048)
|
msl_keys.rsa = RSA.generate(2048)
|
||||||
|
|
||||||
|
|
||||||
if scheme == KeyExchangeSchemes.Widevine:
|
if scheme == KeyExchangeSchemes.Widevine:
|
||||||
if not cdm:
|
if not cdm:
|
||||||
raise Exception('Key exchange scheme Widevine but CDM instance is None.')
|
raise Exception("Key exchange scheme Widevine but CDM instance is None.")
|
||||||
|
|
||||||
session_id = cdm.open()
|
session_id = cdm.open()
|
||||||
msl_keys.cdm_session = session_id
|
msl_keys.cdm_session = session_id
|
||||||
cdm.set_service_certificate(session_id, config["certificate"])
|
cdm.set_service_certificate(session_id, config["certificate"])
|
||||||
challenge = cdm.get_license_challenge(
|
challenge = cdm.get_license_challenge(
|
||||||
session_id=session_id,
|
session_id,
|
||||||
pssh=PSSH("AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQAAAAAAPSZ0kAAAAAAAAAAA=="),
|
PSSH("AAAANHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABQIARIQAAAAAAPSZ0kAAAAAAAAAAA=="),
|
||||||
license_type="OFFLINE",
|
"OFFLINE",
|
||||||
privacy_mode=True,
|
True,
|
||||||
|
|
||||||
)
|
)
|
||||||
keyrequestdata = KeyExchangeRequest.Widevine(challenge)
|
keyrequestdata = KeyExchangeRequest.Widevine(challenge)
|
||||||
entityauthdata = EntityAuthentication.Unauthenticated(sender)
|
entityauthdata = EntityAuthentication.Unauthenticated(sender)
|
||||||
@@ -76,47 +86,48 @@ class MSL:
|
|||||||
keyrequestdata = KeyExchangeRequest.AsymmetricWrapped(
|
keyrequestdata = KeyExchangeRequest.AsymmetricWrapped(
|
||||||
keypairid="superKeyPair",
|
keypairid="superKeyPair",
|
||||||
mechanism="JWK_RSA",
|
mechanism="JWK_RSA",
|
||||||
publickey=msl_keys.rsa.publickey().exportKey(format="DER")
|
publickey=msl_keys.rsa.publickey().exportKey(format="DER"),
|
||||||
)
|
)
|
||||||
|
|
||||||
data = jsonpickle.encode({
|
data = jsonpickle.encode(
|
||||||
"entityauthdata": entityauthdata,
|
{
|
||||||
"headerdata": base64.b64encode(MSL.generate_msg_header(
|
"entityauthdata": entityauthdata,
|
||||||
message_id=message_id,
|
"headerdata": base64.b64encode(
|
||||||
sender=sender,
|
MSL.generate_msg_header(
|
||||||
is_handshake=True,
|
message_id=message_id, sender=sender, is_handshake=True, keyrequestdata=keyrequestdata
|
||||||
keyrequestdata=keyrequestdata
|
).encode("utf-8")
|
||||||
).encode("utf-8")).decode("utf-8"),
|
).decode("utf-8"),
|
||||||
"signature": ""
|
"signature": "",
|
||||||
}, unpicklable=False)
|
},
|
||||||
data += json.dumps({
|
unpicklable=False,
|
||||||
"payload": base64.b64encode(json.dumps({
|
)
|
||||||
"messageid": message_id,
|
data += json.dumps(
|
||||||
"data": "",
|
{
|
||||||
"sequencenumber": 1,
|
"payload": base64.b64encode(
|
||||||
"endofmsg": True
|
json.dumps({"messageid": message_id, "data": "", "sequencenumber": 1, "endofmsg": True}).encode(
|
||||||
}).encode("utf-8")).decode("utf-8"),
|
"utf-8"
|
||||||
"signature": ""
|
)
|
||||||
})
|
).decode("utf-8"),
|
||||||
|
"signature": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = session.post(
|
r = session.post(url=endpoint, data=data)
|
||||||
url=endpoint,
|
|
||||||
data=data
|
|
||||||
)
|
|
||||||
except requests.HTTPError as e:
|
except requests.HTTPError as e:
|
||||||
raise Exception(f"- Key exchange failed, response data is unexpected: {e.response.text}")
|
raise Exception(f"- Key exchange failed, response data is unexpected: {e.response.text}")
|
||||||
|
|
||||||
key_exchange = r.json() # expecting no payloads, so this is fine
|
key_exchange = r.json() # expecting no payloads, so this is fine
|
||||||
if "errordata" in key_exchange:
|
if "errordata" in key_exchange:
|
||||||
raise Exception("- Key exchange failed: " + json.loads(base64.b64decode(
|
raise Exception(
|
||||||
key_exchange["errordata"]
|
"- Key exchange failed: "
|
||||||
).decode())["errormsg"])
|
+ json.loads(base64.b64decode(key_exchange["errordata"]).decode())["errormsg"]
|
||||||
|
)
|
||||||
|
|
||||||
# parse the crypto keys
|
# parse the crypto keys
|
||||||
key_response_data = json.JSONDecoder().decode(base64.b64decode(
|
key_response_data = json.JSONDecoder().decode(base64.b64decode(key_exchange["headerdata"]).decode("utf-8"))[
|
||||||
key_exchange["headerdata"]
|
"keyresponsedata"
|
||||||
).decode("utf-8"))["keyresponsedata"]
|
]
|
||||||
|
|
||||||
if key_response_data["scheme"] != str(scheme):
|
if key_response_data["scheme"] != str(scheme):
|
||||||
raise Exception("- Key exchange scheme mismatch occurred")
|
raise Exception("- Key exchange scheme mismatch occurred")
|
||||||
@@ -133,42 +144,36 @@ class MSL:
|
|||||||
encryption_key = MSL.get_widevine_key(
|
encryption_key = MSL.get_widevine_key(
|
||||||
kid=base64.b64decode(key_data["encryptionkeyid"]),
|
kid=base64.b64decode(key_data["encryptionkeyid"]),
|
||||||
keys=keys,
|
keys=keys,
|
||||||
permissions=["allow_encrypt", "allow_decrypt"]
|
permissions=["allow_encrypt", "allow_decrypt"],
|
||||||
)
|
)
|
||||||
msl_keys.encryption = encryption_key
|
msl_keys.encryption = encryption_key
|
||||||
cls.log.debug(f"Encryption key: {encryption_key}")
|
cls.log.debug(f"Encryption key: {encryption_key}")
|
||||||
sign = MSL.get_widevine_key(
|
sign = MSL.get_widevine_key(
|
||||||
kid=base64.b64decode(key_data["hmackeyid"]),
|
kid=base64.b64decode(key_data["hmackeyid"]),
|
||||||
keys=keys,
|
keys=keys,
|
||||||
permissions=["allow_sign", "allow_signature_verify"]
|
permissions=["allow_sign", "allow_signature_verify"],
|
||||||
)
|
)
|
||||||
cls.log.debug(f"Sign key: {sign}")
|
cls.log.debug(f"Sign key: {sign}")
|
||||||
msl_keys.sign = sign
|
msl_keys.sign = sign
|
||||||
|
|
||||||
elif scheme == KeyExchangeSchemes.AsymmetricWrapped:
|
elif scheme == KeyExchangeSchemes.AsymmetricWrapped:
|
||||||
cipher_rsa = PKCS1_OAEP.new(msl_keys.rsa)
|
cipher_rsa = PKCS1_OAEP.new(msl_keys.rsa)
|
||||||
msl_keys.encryption = MSL.base64key_decode(
|
msl_keys.encryption = MSL.base64key_decode(
|
||||||
json.JSONDecoder().decode(cipher_rsa.decrypt(
|
json.JSONDecoder().decode(
|
||||||
base64.b64decode(key_data["encryptionkey"])
|
cipher_rsa.decrypt(base64.b64decode(key_data["encryptionkey"])).decode("utf-8")
|
||||||
).decode("utf-8"))["k"]
|
)["k"]
|
||||||
)
|
)
|
||||||
msl_keys.sign = MSL.base64key_decode(
|
msl_keys.sign = MSL.base64key_decode(
|
||||||
json.JSONDecoder().decode(cipher_rsa.decrypt(
|
json.JSONDecoder().decode(
|
||||||
base64.b64decode(key_data["hmackey"])
|
cipher_rsa.decrypt(base64.b64decode(key_data["hmackey"])).decode("utf-8")
|
||||||
).decode("utf-8"))["k"]
|
)["k"]
|
||||||
)
|
)
|
||||||
|
|
||||||
msl_keys.mastertoken = key_response_data["mastertoken"]
|
msl_keys.mastertoken = key_response_data["mastertoken"]
|
||||||
|
|
||||||
MSL.cache_keys(msl_keys, cache)
|
MSL.cache_keys(msl_keys, cache)
|
||||||
cls.log.info("MSL handshake successful")
|
cls.log.info("MSL handshake successful")
|
||||||
return cls(
|
return cls(session=session, endpoint=endpoint, sender=sender, keys=msl_keys, message_id=message_id)
|
||||||
session=session,
|
|
||||||
endpoint=endpoint,
|
|
||||||
sender=sender,
|
|
||||||
keys=msl_keys,
|
|
||||||
message_id=message_id
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_cache_data(cacher: Cacher):
|
def load_cache_data(cacher: Cacher):
|
||||||
@@ -184,9 +189,24 @@ class MSL:
|
|||||||
# to an RsaKey :)
|
# to an RsaKey :)
|
||||||
msl_keys.rsa = RSA.importKey(msl_keys.rsa)
|
msl_keys.rsa = RSA.importKey(msl_keys.rsa)
|
||||||
# If it's expired or close to, return None as it's unusable
|
# If it's expired or close to, return None as it's unusable
|
||||||
if msl_keys.mastertoken and ((datetime.utcfromtimestamp(int(json.JSONDecoder().decode(
|
if (
|
||||||
base64.b64decode(msl_keys.mastertoken["tokendata"]).decode("utf-8")
|
msl_keys.mastertoken
|
||||||
)["expiration"])) - datetime.now()).total_seconds() / 60 / 60) < 10:
|
and (
|
||||||
|
(
|
||||||
|
datetime.utcfromtimestamp(
|
||||||
|
int(
|
||||||
|
json.JSONDecoder().decode(
|
||||||
|
base64.b64decode(msl_keys.mastertoken["tokendata"]).decode("utf-8")
|
||||||
|
)["expiration"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
- datetime.now()
|
||||||
|
).total_seconds()
|
||||||
|
/ 60
|
||||||
|
/ 60
|
||||||
|
)
|
||||||
|
< 10
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
return msl_keys
|
return msl_keys
|
||||||
|
|
||||||
@@ -204,8 +224,9 @@ class MSL:
|
|||||||
msl_keys.rsa = RSA.importKey(msl_keys.rsa)
|
msl_keys.rsa = RSA.importKey(msl_keys.rsa)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_msg_header(message_id, sender, is_handshake, userauthdata=None, keyrequestdata=None,
|
def generate_msg_header(
|
||||||
compression="GZIP"):
|
message_id, sender, is_handshake, userauthdata=None, keyrequestdata=None, compression="GZIP"
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
The MSL header carries all MSL data used for entity and user authentication, message encryption
|
The MSL header carries all MSL data used for entity and user authentication, message encryption
|
||||||
and verification, and service tokens. Portions of the MSL header are encrypted.
|
and verification, and service tokens. Portions of the MSL header are encrypted.
|
||||||
@@ -228,7 +249,7 @@ class MSL:
|
|||||||
"capabilities": {
|
"capabilities": {
|
||||||
"compressionalgos": [compression] if compression else [],
|
"compressionalgos": [compression] if compression else [],
|
||||||
"languages": ["en-US"], # bcp-47
|
"languages": ["en-US"], # bcp-47
|
||||||
"encoderformats": ["JSON"]
|
"encoderformats": ["JSON"],
|
||||||
},
|
},
|
||||||
"timestamp": int(time.time()),
|
"timestamp": int(time.time()),
|
||||||
# undocumented or unused:
|
# undocumented or unused:
|
||||||
@@ -272,33 +293,42 @@ class MSL:
|
|||||||
|
|
||||||
def create_message(self, application_data, userauthdata=None):
|
def create_message(self, application_data, userauthdata=None):
|
||||||
self.message_id += 1 # new message must ue a new message id
|
self.message_id += 1 # new message must ue a new message id
|
||||||
headerdata = self.encrypt(self.generate_msg_header(
|
headerdata = self.encrypt(
|
||||||
message_id=self.message_id,
|
self.generate_msg_header(
|
||||||
sender=self.sender,
|
message_id=self.message_id, sender=self.sender, is_handshake=False, userauthdata=userauthdata
|
||||||
is_handshake=False,
|
)
|
||||||
userauthdata=userauthdata
|
)
|
||||||
))
|
|
||||||
|
|
||||||
header = json.dumps({
|
header = json.dumps(
|
||||||
"headerdata": base64.b64encode(headerdata.encode("utf-8")).decode("utf-8"),
|
{
|
||||||
"signature": self.sign(headerdata).decode("utf-8"),
|
"headerdata": base64.b64encode(headerdata.encode("utf-8")).decode("utf-8"),
|
||||||
"mastertoken": self.keys.mastertoken
|
"signature": self.sign(headerdata).decode("utf-8"),
|
||||||
})
|
"mastertoken": self.keys.mastertoken,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
payload_chunks = [self.encrypt(json.dumps({
|
payload_chunks = [
|
||||||
"messageid": self.message_id,
|
self.encrypt(
|
||||||
"data": self.gzip_compress(json.dumps(application_data).encode("utf-8")).decode("utf-8"),
|
json.dumps(
|
||||||
"compressionalgo": "GZIP",
|
{
|
||||||
"sequencenumber": 1, # todo ; use sequence_number from master token instead?
|
"messageid": self.message_id,
|
||||||
"endofmsg": True
|
"data": self.gzip_compress(json.dumps(application_data).encode("utf-8")).decode("utf-8"),
|
||||||
}))]
|
"compressionalgo": "GZIP",
|
||||||
|
"sequencenumber": 1, # todo ; use sequence_number from master token instead?
|
||||||
|
"endofmsg": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
message = header
|
message = header
|
||||||
for payload_chunk in payload_chunks:
|
for payload_chunk in payload_chunks:
|
||||||
message += json.dumps({
|
message += json.dumps(
|
||||||
"payload": base64.b64encode(payload_chunk.encode("utf-8")).decode("utf-8"),
|
{
|
||||||
"signature": self.sign(payload_chunk).decode("utf-8")
|
"payload": base64.b64encode(payload_chunk.encode("utf-8")).decode("utf-8"),
|
||||||
})
|
"signature": self.sign(payload_chunk).decode("utf-8"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
@@ -316,9 +346,7 @@ class MSL:
|
|||||||
payload_chunk = json.loads(base64.b64decode(payload_chunk["payload"]).decode("utf-8"))
|
payload_chunk = json.loads(base64.b64decode(payload_chunk["payload"]).decode("utf-8"))
|
||||||
# decrypt the payload
|
# decrypt the payload
|
||||||
payload_decrypted = AES.new(
|
payload_decrypted = AES.new(
|
||||||
key=self.keys.encryption,
|
key=self.keys.encryption, mode=AES.MODE_CBC, iv=base64.b64decode(payload_chunk["iv"])
|
||||||
mode=AES.MODE_CBC,
|
|
||||||
iv=base64.b64decode(payload_chunk["iv"])
|
|
||||||
).decrypt(base64.b64decode(payload_chunk["ciphertext"]))
|
).decrypt(base64.b64decode(payload_chunk["ciphertext"]))
|
||||||
payload_decrypted = Padding.unpad(payload_decrypted, 16)
|
payload_decrypted = Padding.unpad(payload_decrypted, 16)
|
||||||
payload_decrypted = json.loads(payload_decrypted.decode("utf-8"))
|
payload_decrypted = json.loads(payload_decrypted.decode("utf-8"))
|
||||||
@@ -335,9 +363,9 @@ class MSL:
|
|||||||
error_detail = re.sub(r" \(E3-[^)]+\)", "", error.get("detail", ""))
|
error_detail = re.sub(r" \(E3-[^)]+\)", "", error.get("detail", ""))
|
||||||
|
|
||||||
if error_display:
|
if error_display:
|
||||||
self.log.critical(f"- {error_display}")
|
self.log.critical(f"- {error_display}")
|
||||||
if error_detail:
|
if error_detail:
|
||||||
self.log.critical(f"- {error_detail}")
|
self.log.critical(f"- {error_detail}")
|
||||||
|
|
||||||
if not (error_display or error_detail):
|
if not (error_display or error_detail):
|
||||||
self.log.critical(f"- {error}")
|
self.log.critical(f"- {error}")
|
||||||
@@ -391,22 +419,19 @@ class MSL:
|
|||||||
:return: Serialized JSON String of the encryption Envelope
|
:return: Serialized JSON String of the encryption Envelope
|
||||||
"""
|
"""
|
||||||
iv = get_random_bytes(16)
|
iv = get_random_bytes(16)
|
||||||
return json.dumps({
|
return json.dumps(
|
||||||
"ciphertext": base64.b64encode(
|
{
|
||||||
AES.new(
|
"ciphertext": base64.b64encode(
|
||||||
self.keys.encryption,
|
AES.new(self.keys.encryption, AES.MODE_CBC, iv).encrypt(Padding.pad(plaintext.encode("utf-8"), 16))
|
||||||
AES.MODE_CBC,
|
).decode("utf-8"),
|
||||||
iv
|
"keyid": "{}_{}".format(
|
||||||
).encrypt(
|
self.sender,
|
||||||
Padding.pad(plaintext.encode("utf-8"), 16)
|
json.loads(base64.b64decode(self.keys.mastertoken["tokendata"]).decode("utf-8"))["sequencenumber"],
|
||||||
)
|
),
|
||||||
).decode("utf-8"),
|
"sha256": "AA==",
|
||||||
"keyid": "{}_{}".format(self.sender, json.loads(
|
"iv": base64.b64encode(iv).decode("utf-8"),
|
||||||
base64.b64decode(self.keys.mastertoken["tokendata"]).decode("utf-8")
|
}
|
||||||
)["sequencenumber"]),
|
)
|
||||||
"sha256": "AA==",
|
|
||||||
"iv": base64.b64encode(iv).decode("utf-8")
|
|
||||||
})
|
|
||||||
|
|
||||||
def sign(self, text):
|
def sign(self, text):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -567,6 +567,7 @@ class Netflix(Service):
|
|||||||
self.log.debug(f"Android sign-in header keys: {list(header_data.keys())}")
|
self.log.debug(f"Android sign-in header keys: {list(header_data.keys())}")
|
||||||
sign_in_value = self.extract_android_sign_in_value(payload_data)
|
sign_in_value = self.extract_android_sign_in_value(payload_data)
|
||||||
error_code = self.extract_android_sign_in_error_code(sign_in_value)
|
error_code = self.extract_android_sign_in_error_code(sign_in_value)
|
||||||
|
self.log.fatal(f"Android sign-in failed: {header_data}")
|
||||||
if error_code:
|
if error_code:
|
||||||
raise click.ClickException(f"Android sign-in failed: {error_code}")
|
raise click.ClickException(f"Android sign-in failed: {error_code}")
|
||||||
raise click.ClickException("Android sign-in did not return a useridtoken.")
|
raise click.ClickException("Android sign-in did not return a useridtoken.")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ playready_kdekdh:
|
|||||||
esn_map:
|
esn_map:
|
||||||
# key map of CDM WVD `SystemID = 'ESN you want to use for that CDM WVD'`
|
# key map of CDM WVD `SystemID = 'ESN you want to use for that CDM WVD'`
|
||||||
8159: "NFANDROID1-PRV-P-GOOGLEPIXEL"
|
8159: "NFANDROID1-PRV-P-GOOGLEPIXEL"
|
||||||
8131: "HISETVK84500000000000000000000000007401422"
|
12603: "HISETVK84500000000000000000000000007401422"
|
||||||
22589: "NFANDROID1-PRV-P-SAMSUNG-SM-G975F-22589-RYFPGCV4K7QNZJFT5EK3YZ25TYOC1B1MSFEXR4L8JM99YOFXKZLFLOBTATE2AA2UJ"
|
22589: "NFANDROID1-PRV-P-SAMSUNG-SM-G975F-22589-RYFPGCV4K7QNZJFT5EK3YZ25TYOC1B1MSFEXR4L8JM99YOFXKZLFLOBTATE2AA2UJ"
|
||||||
22590: "NFANDROID1-PXA-P-L3-XIAOMM2102J20SG-22590-020NTB086HJPGG70MDDMR0306MR0NNO5G3DJGFCKS9HJF58ER9QA21VFG4I0246JRN6TF16L9I627EPK708SH42UUMG1ASFVG20F3"
|
22590: "NFANDROID1-PXA-P-L3-XIAOMM2102J20SG-22590-020NTB086HJPGG70MDDMR0306MR0NNO5G3DJGFCKS9HJF58ER9QA21VFG4I0246JRN6TF16L9I627EPK708SH42UUMG1ASFVG20F3"
|
||||||
12063: "NFANDROID1-PRV-P-SHENZHENKTC-49B1U-12063-2PAENERYJWY35H7F24163TMUCBBA4VRHQ2XZX4OBU4MUTKYFW50BMFBVGTUMN6IM0"
|
12063: "NFANDROID1-PRV-P-SHENZHENKTC-49B1U-12063-2PAENERYJWY35H7F24163TMUCBBA4VRHQ2XZX4OBU4MUTKYFW50BMFBVGTUMN6IM0"
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ remote_cdm:
|
|||||||
security_level: 3
|
security_level: 3
|
||||||
type: "decrypt_labs"
|
type: "decrypt_labs"
|
||||||
host: https://keyxtractor.decryptlabs.com
|
host: https://keyxtractor.decryptlabs.com
|
||||||
secret: 7547150416_41da0a32d6237d83_KeyXtractor_api_ext
|
secret: 919240143_41d9c3fac9a5f82e_KeyXtractor_ultimate
|
||||||
- name: "android"
|
- name: "android"
|
||||||
device_name: andorid
|
device_name: andorid
|
||||||
device_type: ANDROID
|
device_type: ANDROID
|
||||||
|
|||||||
Reference in New Issue
Block a user