From 1bccbcc28451e895449b87f15f94e798e01f0efd Mon Sep 17 00:00:00 2001 From: hyugogirubato <65763543+hyugogirubato@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:53:18 +0200 Subject: [PATCH] Use functions instead of symbols - Merge OEM Crypto API to set - Use functions instead of symbols --- README.md | 13 +++++----- docs/{SYMBOLS.md => FUNCTIONS.md} | 26 +++++++++---------- extractor/cdm.py | 42 +++++++++++++++++-------------- keydive.py | 4 +-- 4 files changed, 45 insertions(+), 40 deletions(-) rename docs/{SYMBOLS.md => FUNCTIONS.md} (55%) diff --git a/README.md b/README.md index 67aba55..20e8d2b 100644 --- a/README.md +++ b/README.md @@ -45,20 +45,21 @@ This sequence ensures that the DRM-protected content is active and ready for key ### Command-Line Options ```shell -usage: keydive.py [-h] [--device DEVICE] [--symbols SYMBOLS] +usage: keydive.py [-h] [--device DEVICE] [--functions FUNCTIONS] Extract Widevine L3 keys from an Android device. options: - -h, --help show this help message and exit - --device DEVICE Target Android device ID. - --symbols SYMBOLS Ghidra XML symbols file. + -h, --help show this help message and exit + --device DEVICE Target Android device ID. + --functions FUNCTIONS + Ghidra XML functions file. ``` -### Extracting Symbols for Advanced Usage +### Extracting Functions for Advanced Usage -For advanced users looking to use custom symbols with KeyDive, a comprehensive guide on extracting symbols from Widevine libraries using Ghidra is available. Please refer to our [Symbols Extraction Guide](./docs/SYMBOLS.md) for detailed instructions. +For advanced users looking to use custom functions with KeyDive, a comprehensive guide on extracting functions from Widevine libraries using Ghidra is available. Please refer to our [Functions Extraction Guide](./docs/FUNCTIONS.md) for detailed instructions. ## Temporary Disabling L1 for L3 Extraction diff --git a/docs/SYMBOLS.md b/docs/FUNCTIONS.md similarity index 55% rename from docs/SYMBOLS.md rename to docs/FUNCTIONS.md index 012b87c..e2d9ee1 100644 --- a/docs/SYMBOLS.md +++ b/docs/FUNCTIONS.md @@ -1,8 +1,8 @@ -# Symbols +# Functions -To utilize custom symbols with KeyDive, particularly when extracting Widevine L3 DRM keys from Android devices, you might need to generate a `symbols.xml` file using Ghidra. This file helps KeyDive accurately identify necessary symbols within the Widevine library, facilitating a more efficient extraction process. Below is a step-by-step guide on how to create a `symbols.xml` file using Ghidra: +To utilize custom functions with KeyDive, particularly when extracting Widevine L3 DRM keys from Android devices, you might need to generate a `functions.xml` file using Ghidra. This file helps KeyDive accurately identify necessary functions within the Widevine library, facilitating a more efficient extraction process. Below is a step-by-step guide on how to create a `functions.xml` file using Ghidra: -### Extracting Symbols with Ghidra +### Extracting functions with Ghidra #### 1. Preparing Ghidra Ensure you have Ghidra installed on your system. If not, download it from the [Ghidra project page](https://ghidra-sre.org/) and follow the installation instructions. @@ -18,27 +18,27 @@ Ensure you have Ghidra installed on your system. If not, download it from the [G - In the "Auto Analysis" window, ensure all relevant analyzers are selected, especially those related to symbol and function discovery. Click "Analyze" to start the process. - Wait for the analysis to complete, which may take some time depending on the binary's size and complexity. -#### 4. Exporting Symbols as XML +#### 4. Exporting Functions as XML - After analysis, navigate to `File` > `Export Program...`. - In the "Export Program" window, choose the "XML" format from the dropdown menu. -- Click "Options" and ensure that only the "Symbols" option is selected. This step is crucial as it filters the export to include only the symbols necessary for KeyDive, making the XML file more manageable and relevant. -- Choose a destination for the `symbols.xml` file and confirm the export. +- Click "Options" and ensure that only the "Functions" option is selected. This step is crucial as it filters the export to include only the functions necessary for KeyDive, making the XML file more manageable and relevant. +- Choose a destination for the `functions.xml` file and confirm the export. -#### 5. Using the Symbols with KeyDive -Once you have the `symbols.xml` file: +#### 5. Using the Functions with KeyDive +Once you have the `functions.xml` file: - Ensure KeyDive is set up according to its documentation. -- When running KeyDive, use the `--symbols` argument to specify the path to your `symbols.xml` file. For example: +- When running KeyDive, use the `--functions` argument to specify the path to your `functions.xml` file. For example: ```shell - python keydive.py --device --symbols /path/to/symbols_x86.xml + python keydive.py --device --functions /path/to/functions_x86.xml ``` - Proceed with the key extraction process as detailed in KeyDive's usage instructions. ### Additional Tips -- **Understanding Symbols:** The `symbols.xml` file maps function names and variables within the Widevine CDM library, enabling KeyDive to correctly identify and hook into specific processes for key extraction. +- **Understanding Functions:** The `functions.xml` file maps function names and variables within the Widevine CDM library, enabling KeyDive to correctly identify and hook into specific processes for key extraction. - **Ghidra Compatibility:** Ensure your version of Ghidra supports the binary format you're analyzing. Newer versions of Ghidra typically offer better support for a wide range of binary formats. -- **Analysis Depth:** While a full analysis is recommended, you can customize the analysis options based on your understanding of the binary and the symbols you are specifically interested in. This can significantly reduce analysis time. +- **Analysis Depth:** While a full analysis is recommended, you can customize the analysis options based on your understanding of the binary and the functions you are specifically interested in. This can significantly reduce analysis time. - **Security Considerations:** Be aware of the security implications of extracting and handling DRM keys. Always comply with legal restrictions and ethical guidelines when using tools like KeyDive and Ghidra for reverse engineering. -By following these steps, you can generate a `symbols.xml` file that aids in the effective use of KeyDive for educational, research, or security analysis purposes. \ No newline at end of file +By following these steps, you can generate a `functions.xml` file that aids in the effective use of KeyDive for educational, research, or security analysis purposes. \ No newline at end of file diff --git a/extractor/cdm.py b/extractor/cdm.py index 83ffdde..2d0a2a6 100644 --- a/extractor/cdm.py +++ b/extractor/cdm.py @@ -4,8 +4,8 @@ import re import subprocess from pathlib import Path -import frida import xmltodict +import frida from _frida import Process from frida.core import Device, Session, Script from Cryptodome.PublicKey import RSA @@ -20,15 +20,15 @@ class Cdm: """ Manages the capture and processing of DRM keys from a specified device using Frida to inject custom hooks. """ - OEM_CRYPTO_API = [ + OEM_CRYPTO_API = { # Mapping of function names across different API levels (obfuscated names may vary). 'rnmsglvj', 'polorucp', 'kqzqahjq', 'pldrclfq', 'kgaitijd', 'cwkfcplc', 'crhqcdet', 'ulns', 'dnvffnze', 'ygjiljer', 'qbjxtubz', 'qkfrcjtw', 'rbhjspoh' # Add more as needed for different versions. - ] + } - def __init__(self, device: str = None, symbols: Path = None): + def __init__(self, device: str = None, functions: Path = None): self.logger = logging.getLogger('Cdm') self.running = True self.keys = {} @@ -42,7 +42,7 @@ class Cdm: self.logger.info('ABI CPU: %s', self.properties['ro.product.cpu.abi']) # Determine vendor based on SDK API - self.script = self._prepare_hook_script(symbols) + self.script = self._prepare_hook_script(functions) self.vendor = self._prepare_vendor() def _fetch_device_properties(self) -> dict: @@ -67,9 +67,9 @@ class Cdm: def _prepare_hook_script(self, path: Path) -> str: """ Prepares and returns the hook script by replacing placeholders with actual values, including - SDK API version and selected symbols from a given XML file. + SDK API version and selected functions from a given XML file. """ - symbols = {} + selected = {} if path: # Verify symbols file path if not path.is_file(): @@ -78,31 +78,35 @@ class Cdm: try: # Parse the XML file program = xmltodict.parse(path.read_bytes())['PROGRAM'] - base_addr = int(program['@IMAGE_BASE'], 16) - functions: [dict] = program['SYMBOL_TABLE']['SYMBOL'] + addr_base = int(program['@IMAGE_BASE'], 16) + functions = program['FUNCTIONS']['FUNCTION'] # Find a target function from a predefined list - target = next((f['@NAME'] for f in functions if f['@NAME'] in self.OEM_CRYPTO_API), None) + target = next((f'@NAME' for f in functions if f['@NAME'] in self.OEM_CRYPTO_API), None) - # Extract relevant symbols + # Extract relevant functions for func in functions: name = func['@NAME'] + params = func['ADDRESS_RANGE'] + args = len(params) - 1 if isinstance(params, list) else 0 - # Add symbol if it matches specific criteria - if any(keyword in name for keyword in - ['UsePrivacyMode', 'PrepareKeyRequest']) or name == target or ( - not target and re.match(r'^[a-z]+$', name)): - addr = hex(int(func['@ADDRESS'], 16) - base_addr) - symbols[addr] = {'name': name, 'address': addr} + # Add function if it matches specific criteria + if ( + name == target + or any(keyword in name for keyword in ['UsePrivacyMode', 'PrepareKeyRequest']) + or (not target and re.match(r'^[a-z]+$', name) and args >= 6) + ): + addr = int(func['@ENTRY_POINT'], 16) - addr_base + selected[addr] = {'name': name, 'address': hex(addr)} except Exception: - raise ValueError('Failed to extract symbols from Ghidra') + raise ValueError('Failed to extract functions from Ghidra') # Read and prepare the hook script content content = SCRIPT_PATH.read_text(encoding='utf-8') # Replace placeholders with actual values content = content.replace('${SDK_API}', str(self.sdk_api)) content = content.replace('${OEM_CRYPTO_API}', json.dumps(self.OEM_CRYPTO_API)) - content = content.replace('${SYMBOLS}', json.dumps(list(symbols.values()))) + content = content.replace('${SYMBOLS}', json.dumps(list(selected.values()))) return content diff --git a/keydive.py b/keydive.py index af3d7e2..2527f02 100644 --- a/keydive.py +++ b/keydive.py @@ -20,7 +20,7 @@ if __name__ == '__main__': # Parse command line arguments for device ID parser = argparse.ArgumentParser(description='Extract Widevine L3 keys from an Android device.') parser.add_argument('--device', required=False, type=str, help='Target Android device ID.') - parser.add_argument('--symbols', required=False, type=Path, help='Ghidra XML symbols file.') + parser.add_argument('--functions', required=False, type=Path, help='Ghidra XML functions file.') args = parser.parse_args() try: @@ -30,7 +30,7 @@ if __name__ == '__main__': raise EnvironmentError('ADB is not recognized as an environment variable') # Initialize CDM handler with given device - cdm = Cdm(device=args.device, symbols=args.symbols) + cdm = Cdm(device=args.device, functions=args.functions) # Find Widevine process on the device process: Process = next((p for p in cdm.device.enumerate_processes() if cdm.vendor.process == p.name), None)