Use functions instead of symbols

- Merge OEM Crypto API to set
- Use functions instead of symbols
This commit is contained in:
hyugogirubato
2024-04-01 15:53:18 +02:00
parent b59551c708
commit 1bccbcc284
4 changed files with 45 additions and 40 deletions

View File

@@ -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