2024-03-30 20:03:15 +01:00
import argparse
import logging
2024-04-01 12:24:00 +02:00
import subprocess
2024-03-30 20:03:15 +01:00
import time
import coloredlogs
2024-03-31 15:27:10 +02:00
from pathlib import Path
2024-03-30 20:03:15 +01:00
2024-04-01 17:46:39 +02:00
import extractor
2024-03-30 20:03:15 +01:00
from extractor.cdm import Cdm
coloredlogs . install (
fmt = ' %(asctime)s [ %(levelname).1s ] %(name)s : %(message)s ' ,
datefmt = '%Y-%m- %d %H:%M:%S' ,
level = logging . DEBUG )
if __name__ == '__main__' :
logger = logging . getLogger ( 'KeyDive' )
# Parse command line arguments for device ID
parser = argparse . ArgumentParser ( description = 'Extract Widevine L3 keys from an Android device.' )
2024-05-20 12:12:24 +09:00
parser . add_argument ( '-a' , '--auto' , required = False , action = 'store_true' , help = 'Open Bitmovin \' s demo automatically.' )
2024-04-01 18:04:51 +02:00
parser . add_argument ( '-d' , '--device' , required = False , type = str , help = 'Target Android device ID.' )
2024-04-06 15:24:58 +02:00
parser . add_argument ( '-f' , '--functions' , required = False , type = Path , help = 'Path to Ghidra XML functions file.' )
2024-05-22 18:36:36 +02:00
parser . add_argument ( '-w' , '--wvd' , required = False , action = 'store_true' , help = 'Generate WVD.' )
2024-04-06 15:24:58 +02:00
parser . add_argument ( '--force' , required = False , action = 'store_true' , help = 'Force using the default vendor (skipping analysis).' )
2024-03-30 20:03:15 +01:00
args = parser . parse_args ()
try :
2024-04-01 17:46:39 +02:00
logger . info ( 'Version: %s ' , extractor . __version__ )
2024-04-06 15:24:58 +02:00
# Ensure the ADB server is running
2024-05-19 22:41:42 +09:00
sp = subprocess . run ([ 'adb' , 'start-server' ], capture_output = True )
2024-04-19 21:52:59 +02:00
if sp . returncode != 0 :
2024-04-06 15:24:58 +02:00
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' )
2024-03-31 15:27:10 +02:00
2024-04-06 15:24:58 +02:00
# Initialize the CDM handler with the specified or default device
2024-05-21 21:26:31 +09:00
cdm = Cdm ( device = args . device , functions = args . functions , force = args . force , wvd = args . wvd )
2024-03-30 20:03:15 +01:00
2024-04-06 15:24:58 +02:00
# Attempt to locate and identify the Widevine process on the target device
pid = cdm . enumerate_processes () . get ( cdm . vendor . process )
if not pid :
raise EnvironmentError ( 'Widevine process not found on the device' )
logger . info ( 'Process: %s ( %s )' , pid , cdm . vendor . process )
2024-03-30 20:03:15 +01:00
2024-04-06 15:24:58 +02:00
# Hook into the identified process for DRM key extraction
if not cdm . hook_process ( pid = pid ):
raise Exception ( 'Failed to hook into the Widevine process' )
2024-03-30 20:03:15 +01:00
logger . info ( 'Successfully hooked. To test, play a DRM-protected video: https://bitmovin.com/demos/drm' )
2024-05-20 12:12:24 +09:00
if args . auto :
2024-05-22 18:36:36 +02:00
subprocess . run ([ 'adb' , '-s' , cdm . device . id , 'shell' , 'am' , 'start' , '-a' , 'android.intent.action.VIEW' , '-d' , 'https://bitmovin.com/demos/drm' ])
2024-05-20 12:12:24 +09:00
2024-03-30 20:03:15 +01:00
# Keep script running while extracting keys
while cdm . running :
time . sleep ( 1 )
except KeyboardInterrupt :
pass
except Exception as e :
logger . critical ( e )
logger . info ( 'Exiting' )