Files

161 lines
7.6 KiB
Python

#!/usr/bin/env python3
"""Patch Symphonium 14.1.0 — nuke all DRM, Firebase, license checks, and telemetry."""
import os, shutil
BASE = '/home/icetop/Music app fix/apktool_output_v4'
def replace_method(filepath, method_sig, replacement, backup=True):
"""Find and replace a method in a smali file. Returns lines removed."""
if backup:
shutil.copy2(filepath, filepath + '.bak')
with open(filepath) as f:
lines = f.readlines()
# Find method start
s = None
for i, line in enumerate(lines):
if method_sig in line:
s = i
break
assert s is not None, f'{method_sig} not found in {filepath}'
e = s
while e < len(lines) and '.end method' not in lines[e]:
e += 1
assert '.end method' in lines[e], f'.end method not found after line {s} in {filepath}'
removed = e - s + 1
lines = lines[:s] + [replacement + '\n'] + lines[e+1:]
with open(filepath, 'w') as f:
f.writelines(lines)
return removed
# ─── 1. Patch nh3.smali (FirebaseManager license class) ───
nh3_path = f'{BASE}/smali/nh3.smali'
shutil.copy2(nh3_path, nh3_path + '.bak')
with open(nh3_path) as f:
lines = f.readlines()
patches = [
('m', 4205, '.method public final m()Z\n .locals 2\n\n iget-object v0, p0, Lnh3;->x:Lhg5;\n\n const/4 v1, 0x1\n\n iput-boolean v1, v0, Lhg5;->y:Z\n\n const/4 v0, 0x1\n\n return v0\n.end method\n'),
('h', 3102, '.method public final h(Lxo1;)Ljava/lang/Object;\n .locals 1\n\n const/4 v0, 0x0\n\n invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;\n\n move-result-object v0\n\n return-object v0\n.end method\n'),
('k', 3753, '.method public final k(Lxo1;)Ljava/lang/Object;\n .locals 1\n\n sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;\n\n return-object v0\n.end method\n'),
('j', 3526, '.method public final j(Lxo1;)Ljava/lang/Object;\n .locals 1\n\n sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;\n\n return-object v0\n.end method\n'),
('d', 1860, '.method public final d(Ljava/lang/String;Ljava/lang/String;Lxo1;)Ljava/lang/Object;\n .locals 1\n\n const/4 v0, 0x0\n\n return-object v0\n.end method\n'),
('r', 5444, '.method public final r(Lxo1;)Ljava/io/Serializable;\n .locals 1\n\n const/4 v0, 0x0\n\n return-object v0\n.end method\n'),
('b', 1270, '.method public final b(Lxo1;)Ljava/lang/Object;\n .locals 1\n\n sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;\n\n return-object v0\n.end method\n'),
('c', 1463, '.method public final c(Ljava/lang/String;Ljava/lang/String;Lxo1;)Ljava/lang/Object;\n .locals 1\n\n const/4 v0, 0x0\n\n return-object v0\n.end method\n'),
]
for name, start_line, stub in patches:
s = start_line - 1
found = -1
for i in range(max(0, s - 5), min(len(lines), s + 5)):
if '.method public final ' + name in lines[i]:
found = i
break
if found == -1:
for i in range(len(lines)):
if '.method public final ' + name in lines[i]:
found = i
break
assert found >= 0, f'{name}() method not found!'
s = found
e = s
while e < len(lines) and '.end method' not in lines[e]:
e += 1
assert '.end method' in lines[e], f'{name}() .end method not found at offset {s}'
removed = e - s + 1
lines = lines[:s] + [stub] + lines[e+1:]
for j in range(len(patches)):
if patches[j][1] > start_line:
patches[j] = (patches[j][0], patches[j][1] - removed + stub.count('\n'), patches[j][2])
print(f' nh3.{name}() — removed {removed} lines')
with open(nh3_path, 'w') as f:
f.writelines(lines)
print(f'nh3.smali: {len(lines)} lines')
# ─── 2. Patch LibSymfonikWrapper.smali ───
lw_path = f'{BASE}/smali/app/symfonik/crypto/internal/LibSymfonikWrapper.smali'
shutil.copy2(lw_path, lw_path + '.bak')
with open(lw_path) as f:
lines = f.readlines()
s = 239 - 1
e = s
while e < len(lines) and '.end method' not in lines[e]:
e += 1
assert '.method public final b' in lines[s]
stub = (
'.method public final b(Lvz3;)V\n'
' .locals 2\n\n'
' sput-object p1, Lapp/symfonik/crypto/internal/LibSymfonikWrapper;->c:Lvz3;\n\n'
' :try_start_0\n'
' const-string v0, "symfonik"\n'
' invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V\n'
' :try_end_0\n'
' .catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0\n\n'
' :catch_0\n'
' sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;\n\n'
' sput-object v0, Lapp/symfonik/crypto/internal/LibSymfonikWrapper;->b:Ljava/lang/Boolean;\n\n'
' check-cast p1, Lapp/symfonik/init/HandlerInitializable$handler$1;\n\n'
' sget-object v0, Lrc5;->a:Landroid/os/Handler;\n\n'
' iget-object p1, p1, Lapp/symfonik/init/HandlerInitializable$handler$1;->a:La04;\n\n'
' new-instance v1, Lql;\n\n'
' const/16 v2, 0x14\n\n'
' invoke-direct {v1, v2, p1}, Lql;-><init>(ILjava/lang/Object;)V\n\n'
' invoke-virtual {v0, v1}, Landroid/os/Handler;->post(Ljava/lang/Runnable;)Z\n\n'
' return-void\n'
'.end method\n'
)
removed = e - s + 1
lines = lines[:s] + [stub] + lines[e+1:]
with open(lw_path, 'w') as f:
f.writelines(lines)
print(f'LibSymfonikWrapper.smali: {len(lines)} lines (removed {removed})')
# ─── 3. TELEMETRY NUKE ───
print()
# 3a. FirebaseAnalytics.smali — kill logEvent() and setCurrentScreen()
fa_path = f'{BASE}/smali/com/google/firebase/analytics/FirebaseAnalytics.smali'
r = replace_method(fa_path, '.method public final a(Ljava/lang/String;Landroid/os/Bundle;)V',
'.method public final a(Ljava/lang/String;Landroid/os/Bundle;)V\n .locals 0\n\n return-void\n.end method')
print(f'FirebaseAnalytics.a(logEvent) — removed {r} lines')
r = replace_method(fa_path, '.method public setCurrentScreen(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;)V',
'.method public setCurrentScreen(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;)V\n .locals 0\n\n return-void\n.end method')
print(f'FirebaseAnalytics.setCurrentScreen() — removed {r} lines')
# 3b. oa2.smali (Matomo/Piwik tracker) — kill dispatch
oa2_path = f'{BASE}/smali/oa2.smali'
r = replace_method(oa2_path, '.method public final b(Llpa;)V',
'.method public final b(Llpa;)V\n .locals 0\n\n return-void\n.end method')
print(f'Matomo oa2.b(dispatch) — removed {r} lines')
# 3c. b70.smali (Crashlytics settings + report upload) — kill settings fetch
b70_path = f'{BASE}/smali/b70.smali'
r = replace_method(b70_path, '.method public j(Lu10;)Ljava/lang/Object;',
'.method public j(Lu10;)Ljava/lang/Object;\n .locals 1\n\n const/4 v0, 0x0\n\n return-object v0\n.end method')
print(f'Crashlytics b70.j(settings) — removed {r} lines')
# 3d. vg3.smali (Firebase Installations HTTP) — kill connection creator
vg3_path = f'{BASE}/smali/vg3.smali'
r = replace_method(vg3_path, '.method public final c(Ljava/net/URL;Ljava/lang/String;)Ljava/net/HttpURLConnection;',
'.method public final c(Ljava/net/URL;Ljava/lang/String;)Ljava/net/HttpURLConnection;\n .locals 1\n\n const/4 v0, 0x0\n\n return-object v0\n.end method')
print(f'FirebaseInst.vg3.c(connection) — removed {r} lines')
# ─── 4. Lower minSdkVersion ───
yml_path = f'{BASE}/apktool.yml'
with open(yml_path) as f:
yml = f.read()
yml = yml.replace('minSdkVersion: 32', 'minSdkVersion: 26')
with open(yml_path, 'w') as f:
f.write(yml)
print(f'\napktool.yml: minSdkVersion 32 → 26')
print('\nAll patches applied. Ready for build.')