Release v1.0.2
This commit is contained in:
parent
bbaa7c67f4
commit
7bba298df9
|
@ -158,3 +158,6 @@ cython_debug/
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
|
# KeyDive
|
||||||
|
device/
|
|
@ -43,17 +43,22 @@ To use KeyDive, follow these steps:
|
||||||
|
|
||||||
### Command-Line Options
|
### Command-Line Options
|
||||||
|
|
||||||
```sh
|
```shell
|
||||||
usage: keydive.py [-h] [--device DEVICE]
|
usage: keydive.py [-h] [--device DEVICE] [--symbols SYMBOLS]
|
||||||
|
|
||||||
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
|
||||||
--device DEVICE Target Android device ID.
|
--device DEVICE Target Android device ID.
|
||||||
|
--symbols SYMBOLS Ghidra XML symbols file.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Extracting Symbols 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.
|
||||||
|
|
||||||
## Temporary Disabling L1 for L3 Extraction
|
## Temporary Disabling L1 for L3 Extraction
|
||||||
|
|
||||||
Some manufacturers (e.g., Xiaomi) allow the use of L1 keyboxes even after unlocking the bootloader. In such cases, it's necessary to install a Magisk module called [liboemcrypto-disabler](https://github.com/Magisk-Modules-Repo/liboemcryptodisabler) to temporarily disable L1, thereby facilitating L3 key extraction.
|
Some manufacturers (e.g., Xiaomi) allow the use of L1 keyboxes even after unlocking the bootloader. In such cases, it's necessary to install a Magisk module called [liboemcrypto-disabler](https://github.com/Magisk-Modules-Repo/liboemcryptodisabler) to temporarily disable L1, thereby facilitating L3 key extraction.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Packages
|
# Package
|
||||||
|
|
||||||
This document provides an overview of the external libraries, tools, and applications utilized within the KeyDive project. Each package plays a crucial role in enabling the project to efficiently extract Widevine L3 keys from Android devices for educational and research purposes.
|
This document provides an overview of the external libraries, tools, and applications utilized within the KeyDive project. Each package plays a crucial role in enabling the project to efficiently extract Widevine L3 keys from Android devices for educational and research purposes.
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Symbols
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
### Extracting Symbols 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.
|
||||||
|
|
||||||
|
#### 2. Importing the ELF Binary
|
||||||
|
- Launch Ghidra and start a new project (or open an existing one).
|
||||||
|
- Import the ELF binary file (e.g., the Widevine CDM library from the Android device) by navigating to `File` > `Import File` and selecting the binary.
|
||||||
|
- Choose the default options for the import settings, unless you have specific requirements.
|
||||||
|
|
||||||
|
#### 3. Analyzing the Binary
|
||||||
|
- Once the binary is imported, double-click on it in the project window to open it in the CodeBrowser tool.
|
||||||
|
- Begin the analysis by navigating to `Analysis` > `Auto Analyze` from the top menu.
|
||||||
|
- 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
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
#### 5. Using the Symbols with KeyDive
|
||||||
|
Once you have the `symbols.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:
|
||||||
|
```shell
|
||||||
|
python keydive.py --device <DEVICE_ID> --symbols /path/to/symbols_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.
|
||||||
|
- **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.
|
||||||
|
- **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.
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -1,28 +0,0 @@
|
||||||
[
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=android.hardware.drm-service.widevine, base=0x5e990b799000, size=24576, path=/vendor/bin/hw/android.hardware.drm-service.widevine)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=linker64, base=0x74822b449000, size=278528, path=/system/bin/linker64)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=android.hardware.drm-V1-ndk.so, base=0x748225906000, size=196608, path=/apex/com.android.vndk.v33/lib64/android.hardware.drm-V1-ndk.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libbase.so, base=0x7482258b3000, size=274432, path=/apex/com.android.vndk.v33/lib64/libbase.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=liblog.so, base=0x74822585e000, size=73728, path=/system/lib64/liblog.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libutils.so, base=0x7482279c9000, size=131072, path=/apex/com.android.vndk.v33/lib64/libutils.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libwvaidl.so, base=0x74822766d000, size=3072000, path=/vendor/lib64/libwvaidl.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libbinder_ndk.so, base=0x74822aca2000, size=98304, path=/system/lib64/libbinder_ndk.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libc++.so, base=0x74822630b000, size=696320, path=/apex/com.android.vndk.v33/lib64/libc++.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libc.so, base=0x748225c08000, size=6520832, path=/apex/com.android.runtime/lib64/bionic/libc.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libm.so, base=0x74822ae11000, size=335872, path=/apex/com.android.runtime/lib64/bionic/libm.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libdl.so, base=0x748225a1f000, size=20480, path=/apex/com.android.runtime/lib64/bionic/libdl.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=android.hardware.common-V2-ndk.so, base=0x74822ac4e000, size=24576, path=/apex/com.android.vndk.v33/lib64/android.hardware.common-V2-ndk.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libc++.so, base=0x748225953000, size=696320, path=/system/lib64/libc++.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libcutils.so, base=0x7482263e1000, size=98304, path=/apex/com.android.vndk.v33/lib64/libcutils.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libvndksupport.so, base=0x74822adc2000, size=16384, path=/system/lib64/libvndksupport.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libcrypto.so, base=0x748225a4d000, size=1634304, path=/apex/com.android.vndk.v33/lib64/libcrypto.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libprotobuf-cpp-lite-3.9.1.so, base=0x74822acc2000, size=503808, path=/vendor/lib64/libprotobuf-cpp-lite-3.9.1.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libandroid_runtime_lazy.so, base=0x74822aff9000, size=16384, path=/system/lib64/libandroid_runtime_lazy.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libbase.so, base=0x74822628f000, size=274432, path=/system/lib64/libbase.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libbinder.so, base=0x74822aea6000, size=860160, path=/system/lib64/libbinder.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libutils.so, base=0x74822ad52000, size=131072, path=/system/lib64/libutils.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libdl_android.so, base=0x74822ad98000, size=12288, path=/apex/com.android.runtime/lib64/bionic/libdl_android.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libcutils.so, base=0x74822af8a000, size=98304, path=/system/lib64/libcutils.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=libnetd_client.so, base=0x748015810000, size=40960, path=/system/lib64/libnetd_client.so)",
|
|
||||||
"Library(process=Process(pid=404, name=\"android.hardware.drm-service.widevine\", parameters={}), name=linux-vdso.so.1, base=0x7fff0bde6000, size=4096, path=linux-vdso.so.1)"
|
|
||||||
]
|
|
110
extractor/cdm.py
110
extractor/cdm.py
|
@ -1,9 +1,11 @@
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import frida
|
import frida
|
||||||
|
import xmltodict
|
||||||
from _frida import Process
|
from _frida import Process
|
||||||
from frida.core import Device, Session, Script, RPCException
|
from frida.core import Device, Session, Script, RPCException
|
||||||
from Cryptodome.PublicKey import RSA
|
from Cryptodome.PublicKey import RSA
|
||||||
|
@ -18,8 +20,15 @@ class Cdm:
|
||||||
"""
|
"""
|
||||||
Manages the capture and processing of DRM keys from a specified device using Frida to inject custom hooks.
|
Manages the capture and processing of DRM keys from a specified device using Frida to inject custom hooks.
|
||||||
"""
|
"""
|
||||||
|
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):
|
def __init__(self, device: str = None, symbols: Path = None):
|
||||||
self.logger = logging.getLogger('Cdm')
|
self.logger = logging.getLogger('Cdm')
|
||||||
self.running = True
|
self.running = True
|
||||||
self.keys = {}
|
self.keys = {}
|
||||||
|
@ -33,7 +42,7 @@ class Cdm:
|
||||||
self.logger.info('ABI CPU: %s', self.properties['ro.product.cpu.abi'])
|
self.logger.info('ABI CPU: %s', self.properties['ro.product.cpu.abi'])
|
||||||
|
|
||||||
# Determine vendor based on SDK API
|
# Determine vendor based on SDK API
|
||||||
self.script = self._prepare_hook_script()
|
self.script = self._prepare_hook_script(symbols)
|
||||||
self.vendor = self._prepare_vendor()
|
self.vendor = self._prepare_vendor()
|
||||||
|
|
||||||
def _fetch_device_properties(self) -> dict:
|
def _fetch_device_properties(self) -> dict:
|
||||||
|
@ -55,12 +64,71 @@ class Cdm:
|
||||||
properties[key] = value
|
properties[key] = value
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
def _prepare_hook_script(self) -> str:
|
def _prepare_hook_script(self, path: Path) -> str:
|
||||||
"""
|
"""
|
||||||
Prepares and returns the hook script with the SDK API version replaced.
|
Prepares and returns the hook script by replacing placeholders with actual values, including
|
||||||
|
SDK API version and selected symbols from a given XML file.
|
||||||
"""
|
"""
|
||||||
script_content = SCRIPT_PATH.read_text(encoding='utf-8')
|
symbols = {}
|
||||||
return script_content.replace("'${SDK_API}'", str(self.sdk_api))
|
if path:
|
||||||
|
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']
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Extract relevant symbols
|
||||||
|
for func in functions:
|
||||||
|
name = func['@NAME']
|
||||||
|
|
||||||
|
# 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}
|
||||||
|
except Exception:
|
||||||
|
raise ValueError('Failed to extract symbols 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())))
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
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 _process_message(self, message: dict, data: bytes) -> None:
|
def _process_message(self, message: dict, data: bytes) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -132,36 +200,6 @@ class Cdm:
|
||||||
else:
|
else:
|
||||||
self.logger.warning('Failed to intercept the private key')
|
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:
|
def hook_process(self, process: Process) -> bool:
|
||||||
"""
|
"""
|
||||||
Hooks into the specified process to intercept DRM keys.
|
Hooks into the specified process to intercept DRM keys.
|
||||||
|
|
|
@ -4,14 +4,10 @@
|
||||||
* Source: https://github.com/hyugogirubato/KeyDive
|
* Source: https://github.com/hyugogirubato/KeyDive
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const SDK_API = '${SDK_API}'; // Dynamically replaced with the actual SDK API level.
|
// Placeholder values dynamically replaced at runtime.
|
||||||
const OEM_CRYPTO_API = [
|
const SDK_API = parseInt('${SDK_API}', 10);
|
||||||
// Mapping of function names across different API levels (obfuscated names may vary).
|
const OEM_CRYPTO_API = JSON.parse('${OEM_CRYPTO_API}');
|
||||||
'rnmsglvj', 'polorucp', 'kqzqahjq', 'pldrclfq', 'kgaitijd',
|
const SYMBOLS = JSON.parse('${SYMBOLS}');
|
||||||
'cwkfcplc', 'crhqcdet', 'ulns', 'dnvffnze', 'ygjiljer',
|
|
||||||
'qbjxtubz', 'qkfrcjtw', 'rbhjspoh'
|
|
||||||
// Add more as needed for different versions.
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
// Logging levels to synchronize with Python's logging module.
|
// Logging levels to synchronize with Python's logging module.
|
||||||
|
@ -71,7 +67,20 @@ const getLibrary = (name) => Process.getModuleByName(name);
|
||||||
const hookLibrary = (name) => {
|
const hookLibrary = (name) => {
|
||||||
// https://github.com/poxyran/misc/blob/master/frida-enumerate-imports.py
|
// https://github.com/poxyran/misc/blob/master/frida-enumerate-imports.py
|
||||||
const library = getLibrary(name);
|
const library = getLibrary(name);
|
||||||
const functions = [...library.enumerateExports(), ...library.enumerateImports()];
|
if (!library) return false;
|
||||||
|
|
||||||
|
let functions;
|
||||||
|
if (SYMBOLS.length > 0) {
|
||||||
|
functions = SYMBOLS.map(symbol => ({
|
||||||
|
'type': 'function',
|
||||||
|
'name': symbol.name,
|
||||||
|
'address': ptr(parseInt(symbol.address, 16) + parseInt(library.base, 16))
|
||||||
|
}));
|
||||||
|
print(Level.INFO, 'Successfully imported symbols');
|
||||||
|
} else {
|
||||||
|
functions = [...library.enumerateExports(), ...library.enumerateImports()];
|
||||||
|
}
|
||||||
|
|
||||||
const targetFunction = functions.find(func => OEM_CRYPTO_API.includes(func.name));
|
const targetFunction = functions.find(func => OEM_CRYPTO_API.includes(func.name));
|
||||||
|
|
||||||
let hookedCount = 0;
|
let hookedCount = 0;
|
||||||
|
|
10
keydive.py
10
keydive.py
|
@ -4,6 +4,7 @@ import time
|
||||||
|
|
||||||
import coloredlogs
|
import coloredlogs
|
||||||
from _frida import Process
|
from _frida import Process
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from extractor.cdm import Cdm
|
from extractor.cdm import Cdm
|
||||||
|
|
||||||
|
@ -17,12 +18,17 @@ 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('--device', type=str, help='Target Android device ID.')
|
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.')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
symbols = args.symbols
|
||||||
|
if symbols and not symbols.is_file():
|
||||||
|
raise FileNotFoundError('Symbols file not found')
|
||||||
|
|
||||||
# Initialize CDM handler with given device
|
# Initialize CDM handler with given device
|
||||||
cdm = Cdm(device=args.device)
|
cdm = Cdm(device=args.device, symbols=symbols)
|
||||||
|
|
||||||
# Find Widevine process on the device
|
# Find Widevine process on the device
|
||||||
process: Process = next((p for p in cdm.device.enumerate_processes() if cdm.vendor.process == p.name), None)
|
process: Process = next((p for p in cdm.device.enumerate_processes() if cdm.vendor.process == p.name), None)
|
||||||
|
|
|
@ -3,3 +3,4 @@ pathlib~=1.0.1
|
||||||
coloredlogs~=15.0.1
|
coloredlogs~=15.0.1
|
||||||
pycryptodomex~=3.20.0
|
pycryptodomex~=3.20.0
|
||||||
protobuf~=4.25.1
|
protobuf~=4.25.1
|
||||||
|
xmltodict~=0.13.0
|
Loading…
Reference in New Issue