Merge pull request #10 from FoxRefire/main
Open Bitmovin's demo automatically / Generate WVD
This commit is contained in:
commit
28a750cb6d
|
@ -57,16 +57,18 @@ For a detailed step-by-step guide on setting up and executing KeyDive without in
|
||||||
### Command-Line Options
|
### Command-Line Options
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
usage: keydive.py [-h] [-d DEVICE] [-f FUNCTIONS] [--force]
|
usage: keydive.py [-h] [-a] [-d DEVICE] [-f FUNCTIONS] [-w] [--force]
|
||||||
|
|
||||||
Extract Widevine L3 keys from an Android device.
|
Extract Widevine L3 keys from an Android device.
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
|
-a, --auto Open Bitmovin’s demo automatically
|
||||||
-d DEVICE, --device DEVICE
|
-d DEVICE, --device DEVICE
|
||||||
Target Android device ID.
|
Target Android device ID.
|
||||||
-f FUNCTIONS, --functions FUNCTIONS
|
-f FUNCTIONS, --functions FUNCTIONS
|
||||||
Path to Ghidra XML functions file.
|
Path to Ghidra XML functions file.
|
||||||
|
-w, --wvd Generate WVD
|
||||||
--force Force using the default vendor (skipping analysis).
|
--force Force using the default vendor (skipping analysis).
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
@ -11,6 +11,7 @@ from Cryptodome.PublicKey import RSA
|
||||||
|
|
||||||
from extractor.license_protocol_pb2 import SignedMessage, LicenseRequest, ClientIdentification, DrmCertificate, SignedDrmCertificate
|
from extractor.license_protocol_pb2 import SignedMessage, LicenseRequest, ClientIdentification, DrmCertificate, SignedDrmCertificate
|
||||||
from extractor.vendor import Vendor
|
from extractor.vendor import Vendor
|
||||||
|
from pywidevine.device import Device, DeviceTypes
|
||||||
|
|
||||||
SCRIPT_PATH = Path(__file__).parent / 'script.js'
|
SCRIPT_PATH = Path(__file__).parent / 'script.js'
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ class Cdm:
|
||||||
# Add more as needed for different versions.
|
# Add more as needed for different versions.
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, device: str = None, functions: Path = None, force: bool = False):
|
def __init__(self, device: str = None, functions: Path = None, force: bool = False, wvd: bool = False):
|
||||||
self.logger = logging.getLogger('Cdm')
|
self.logger = logging.getLogger('Cdm')
|
||||||
self.functions = functions
|
self.functions = functions
|
||||||
self.running = True
|
self.running = True
|
||||||
|
@ -37,6 +38,9 @@ class Cdm:
|
||||||
self.device: Device = frida.get_device(id=device, timeout=5) if device else frida.get_usb_device(timeout=5)
|
self.device: Device = frida.get_device(id=device, timeout=5) if device else frida.get_usb_device(timeout=5)
|
||||||
self.logger.info('Device: %s (%s)', self.device.name, self.device.id)
|
self.logger.info('Device: %s (%s)', self.device.name, self.device.id)
|
||||||
|
|
||||||
|
# Select if create WVD or not
|
||||||
|
self.wvd = wvd
|
||||||
|
|
||||||
# Obtain device properties
|
# Obtain device properties
|
||||||
self.properties = self._fetch_device_properties()
|
self.properties = self._fetch_device_properties()
|
||||||
|
|
||||||
|
@ -252,6 +256,18 @@ class Cdm:
|
||||||
|
|
||||||
self.logger.info('Dumped client ID: %s', path_client_id)
|
self.logger.info('Dumped client ID: %s', path_client_id)
|
||||||
self.logger.info('Dumped private key: %s', path_private_key)
|
self.logger.info('Dumped private key: %s', path_private_key)
|
||||||
|
|
||||||
|
if self.wvd:
|
||||||
|
path_wvd = path / 'device.wvd'
|
||||||
|
Device(
|
||||||
|
client_id=client_id.SerializeToString(),
|
||||||
|
private_key=private_key.exportKey('PEM'),
|
||||||
|
type_=DeviceTypes['ANDROID'],
|
||||||
|
security_level=3,
|
||||||
|
flags=None
|
||||||
|
).dump(path_wvd)
|
||||||
|
self.logger.info('Created WVD: %s', path_wvd)
|
||||||
|
|
||||||
self.running = False
|
self.running = False
|
||||||
else:
|
else:
|
||||||
self.logger.warning('Failed to intercept the private key')
|
self.logger.warning('Failed to intercept the private key')
|
||||||
|
|
|
@ -19,8 +19,10 @@ if __name__ == '__main__':
|
||||||
|
|
||||||
# Parse command line arguments for device ID
|
# Parse command line arguments for device ID
|
||||||
parser = argparse.ArgumentParser(description='Extract Widevine L3 keys from an Android device.')
|
parser = argparse.ArgumentParser(description='Extract Widevine L3 keys from an Android device.')
|
||||||
|
parser.add_argument('-a', '--auto', required=False, action='store_true', help='Open Bitmovin\'s demo automatically.')
|
||||||
parser.add_argument('-d', '--device', required=False, type=str, help='Target Android device ID.')
|
parser.add_argument('-d', '--device', required=False, type=str, help='Target Android device ID.')
|
||||||
parser.add_argument('-f', '--functions', required=False, type=Path, help='Path to Ghidra XML functions file.')
|
parser.add_argument('-f', '--functions', required=False, type=Path, help='Path to Ghidra XML functions file.')
|
||||||
|
parser.add_argument('-w', '--wvd', required=False, action='store_true', help='Generate WVD')
|
||||||
parser.add_argument('--force', required=False, action='store_true', help='Force using the default vendor (skipping analysis).')
|
parser.add_argument('--force', required=False, action='store_true', help='Force using the default vendor (skipping analysis).')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
@ -34,7 +36,7 @@ if __name__ == '__main__':
|
||||||
raise EnvironmentError('ADB is not recognized as an environment variable, see https://github.com/hyugogirubato/KeyDive/blob/main/docs/PACKAGE.md#adb-android-debug-bridge')
|
raise EnvironmentError('ADB is not recognized as an environment variable, see https://github.com/hyugogirubato/KeyDive/blob/main/docs/PACKAGE.md#adb-android-debug-bridge')
|
||||||
|
|
||||||
# Initialize the CDM handler with the specified or default device
|
# Initialize the CDM handler with the specified or default device
|
||||||
cdm = Cdm(device=args.device, functions=args.functions, force=args.force)
|
cdm = Cdm(device=args.device, functions=args.functions, force=args.force, wvd=args.wvd)
|
||||||
|
|
||||||
# Attempt to locate and identify the Widevine process on the target device
|
# Attempt to locate and identify the Widevine process on the target device
|
||||||
pid = cdm.enumerate_processes().get(cdm.vendor.process)
|
pid = cdm.enumerate_processes().get(cdm.vendor.process)
|
||||||
|
@ -47,6 +49,9 @@ if __name__ == '__main__':
|
||||||
raise Exception('Failed to hook into the Widevine process')
|
raise Exception('Failed to hook into the Widevine process')
|
||||||
logger.info('Successfully hooked. To test, play a DRM-protected video: https://bitmovin.com/demos/drm')
|
logger.info('Successfully hooked. To test, play a DRM-protected video: https://bitmovin.com/demos/drm')
|
||||||
|
|
||||||
|
if args.auto:
|
||||||
|
subprocess.run(['adb', 'shell', 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', 'https://bitmovin.com/demos/drm'])
|
||||||
|
|
||||||
# Keep script running while extracting keys
|
# Keep script running while extracting keys
|
||||||
while cdm.running:
|
while cdm.running:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
Loading…
Reference in New Issue