-
Notifications
You must be signed in to change notification settings - Fork 4
/
adb-ssl-unpinning.py
executable file
·132 lines (102 loc) · 4.32 KB
/
adb-ssl-unpinning.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env python3
from adbutils import AdbClient, AdbDevice
from sys import argv
import os
from pathlib import Path
import shutil
import subprocess as sp
import xml.etree.ElementTree as ET
# Default ADB
ADB_HOST = '127.0.0.1'
ADB_PORT = 5037
APKTOOL = 'apktool_2.6.1.jar'
JAR_SIGNER = 'uber-apk-signer-1.2.1.jar'
def pull_package(device: AdbDevice, package_name: str, output_path: Path):
apks = device.shell('pm path ' + package_name).splitlines()
if len(apks) == 0:
print('Package not found')
exit(1)
os.mkdir(output_path)
for apk in apks:
apk_path = apk.strip().split(':')[1]
print(f'Pulling {apk_path}...')
device.sync.pull(apk_path, output_path / apk_path.split('/')[-1])
def patch_manifest(unpacked_apk_path: Path):
manifest_path = unpacked_apk_path / "AndroidManifest.xml"
root = ET.parse(manifest_path).getroot()
application = root.find("application")
if application.get("{http://schemas.android.com/apk/res/android}networkSecurityConfig") is None:
# Add networkSecurityConfig attribute
application.set("{http://schemas.android.com/apk/res/android}networkSecurityConfig", "@xml/network_security_config")
with open(manifest_path, "w") as f:
f.write(ET.tostring(root).decode())
def add_network_security_config(unpacked_apk_path: Path):
with open(unpacked_apk_path / "res" / "xml" / "network_security_config.xml", "w") as f:
f.write("""<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</debug-overrides>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
""")
def patch_package(device: AdbDevice, package_name: str):
# Pull original APK
original_output = Path(package_name)
if not os.path.exists(original_output):
pull_package(device, package_name, original_output)
# Remove old patched output directory and create new one
patched_output = Path(package_name + '_patched')
if os.path.exists(patched_output):
shutil.rmtree(patched_output)
os.mkdir(patched_output)
# Process each APK
for apk in os.listdir(original_output):
file_name = os.path.splitext(apk)[0]
apk_path = original_output / apk
unpacked_apk_path = patched_output / file_name
packed_apk_path = patched_output / (file_name + '.repack.apk')
signed_apk_path = patched_output / (file_name + '.repack-aligned-debugSigned.apk')
patched_apk_path = patched_output / (file_name + '_patched.apk')
# Unpack base APK
if file_name == 'base':
sp.run(["java", "-jar", APKTOOL, "d", apk_path, "-o", unpacked_apk_path, "-s"])
else:
sp.run(["java", "-jar", APKTOOL, "d", apk_path, "-o", unpacked_apk_path, "-s", "-r"])
# Disable SSL pinning
if file_name == 'base':
patch_manifest(unpacked_apk_path)
add_network_security_config(unpacked_apk_path)
# Repack APK
if sp.run(["java", "-jar", APKTOOL, "b", unpacked_apk_path, "-o", packed_apk_path]).returncode != 0:
sp.run(["java", "-jar", APKTOOL, "b", unpacked_apk_path, "-o", packed_apk_path, "--use-aapt2"])
# Sign APK
sp.run(["java", "-jar", JAR_SIGNER, "-a", packed_apk_path])
# Clean up
os.remove(packed_apk_path)
shutil.rmtree(unpacked_apk_path)
os.rename(signed_apk_path, patched_apk_path)
# Push patched APKs back to device
print('Uninstalling package...')
device.uninstall(package_name)
# Clean up
print('Installing patched APKs...')
os.system('adb install-multiple ' + ' '.join([str(patched_output / apk) for apk in os.listdir(str(patched_output))]))
if __name__ == '__main__':
if len(argv) < 3:
print('Usage: python3 patch_apk.py <serial> <package_name>')
exit(1)
# Connect to the ADB server
client = AdbClient(host=ADB_HOST, port=ADB_PORT)
device = client.device(argv[1])
package_name = argv[2]
if package_name.startswith('package:'):
package_name = package_name[len('package:'):]
patch_package(device, package_name)