diff --git a/extractor/__init__.py b/extractor/__init__.py index 3779f36..4ce5300 100644 --- a/extractor/__init__.py +++ b/extractor/__init__.py @@ -1,4 +1,4 @@ from .cdm import * from .vendor import * -__version__ = '1.0.0' +__version__ = '1.0.1' diff --git a/extractor/cdm.py b/extractor/cdm.py index 7a189c0..10d5939 100644 --- a/extractor/cdm.py +++ b/extractor/cdm.py @@ -33,8 +33,8 @@ class Cdm: self.logger.info('ABI CPU: %s', self.properties['ro.product.cpu.abi']) # Determine vendor based on SDK API - self.vendor = Vendor.from_sdk_api(self.sdk_api) - self.script: str = self._prepare_hook_script() + self.script = self._prepare_hook_script() + self.vendor = self._prepare_vendor() def _fetch_device_properties(self) -> dict: """ @@ -132,6 +132,36 @@ class Cdm: else: self.logger.warning('Failed to intercept the private key') + def _prepare_vendor(self) -> Vendor: + """ + Prepares and selects the most compatible vendor version based on the device's processes. + """ + details: [int] = [] + for p in self.device.enumerate_processes(): + for k, v in Vendor.SDK_VERSIONS.items(): + if p.name == v[2]: + session: Session = self.device.attach(p.name) + script: Script = session.create_script(self.script) + script.load() + try: + script.exports_sync.getlibrary(v[3]) + details.append(k) + except RPCException: + pass + session.detach() + + if not details: + return Vendor.from_sdk_api(self.sdk_api) + + # Find the closest SDK version to the current one, preferring lower matches in case of a tie. + sdk_api = min(details, key=lambda x: abs(x - self.sdk_api)) + if sdk_api == Vendor.SDK_MAX and self.sdk_api > Vendor.SDK_MAX: + sdk_api = self.sdk_api + elif sdk_api != self.sdk_api: + self.logger.warning('Non-default Widevine version for SDK %s', sdk_api) + + return Vendor.from_sdk_api(sdk_api) + def hook_process(self, process: Process) -> bool: """ Hooks into the specified process to intercept DRM keys. diff --git a/extractor/script.js b/extractor/script.js index 6195177..043c440 100644 --- a/extractor/script.js +++ b/extractor/script.js @@ -7,19 +7,9 @@ const SDK_API = '${SDK_API}'; // Dynamically replaced with the actual SDK API level. const OEM_CRYPTO_API = [ // Mapping of function names across different API levels (obfuscated names may vary). - 'rnmsglvj', - 'polorucp', - 'kqzqahjq', - 'pldrclfq', - 'kgaitijd', - 'cwkfcplc', - 'crhqcdet', - 'ulns', // 11, 13 - 'dnvffnze', // 15 - 'ygjiljer', // 15 - 'qbjxtubz', // 16 - 'qkfrcjtw', // 16 - 'rbhjspoh' // 17 + 'rnmsglvj', 'polorucp', 'kqzqahjq', 'pldrclfq', 'kgaitijd', + 'cwkfcplc', 'crhqcdet', 'ulns', 'dnvffnze', 'ygjiljer', + 'qbjxtubz', 'qkfrcjtw', 'rbhjspoh' // Add more as needed for different versions. ]; diff --git a/extractor/vendor.py b/extractor/vendor.py index 157d2f5..887142b 100644 --- a/extractor/vendor.py +++ b/extractor/vendor.py @@ -24,6 +24,7 @@ class Vendor: 24: (11, '1.0', 'mediadrmserver', 'libwvdrmengine.so'), 23: (11, '1.0', 'mediaserver', 'libwvdrmengine.so') } + SDK_MAX = max(SDK_VERSIONS.keys()) def __init__(self, oem: int, version: str, process: str, library: str): """ @@ -51,7 +52,7 @@ class Vendor: vendor_details = cls.SDK_VERSIONS.get(sdk_api) if not vendor_details: - vendor_details = cls.SDK_VERSIONS[max(cls.SDK_VERSIONS.keys())] + vendor_details = cls.SDK_VERSIONS[cls.SDK_MAX] logger.warning('CMD version is not yet implemented') logger.warning('Using closest supported CDM version: %s', vendor_details[1]) else: