SHOW:
|
|
- or go back to the newest paste.
1 | #!/bin/bash | |
2 | set -euo pipefail | |
3 | base_dir="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd -P)" | |
4 | cd "$base_dir" | |
5 | ||
6 | #region functions | |
7 | #region init | |
8 | function add_user_local_bin_to_path() { | |
9 | local expected="$HOME/.local/bin" | |
10 | local path | |
11 | path=$(echo "$PATH" | tr ':' $'\n' | sed -E 's#/+$##g') | |
12 | if ! echo "$path" | grep -q "$expected"; then | |
13 | PATH="$expected:$(echo "$path" | tr $'\n' ':')" | |
14 | fi | |
15 | } | |
16 | ||
17 | function install_bootstrap_ubuntu() { | |
18 | local packages=() | |
19 | curl --version >/dev/null 2>&1 || packages+=( curl ) | |
20 | git --version >/dev/null 2>&1 || packages+=( git ) | |
21 | if [[ ${#packages[@]} -gt 0 ]]; then | |
22 | echo "installing packages: ${packages[*]} .." | |
23 | sudo apt install "${packages[@]}" | |
24 | fi | |
25 | } | |
26 | ||
27 | function is_python_min_version_found() { | |
28 | local pythonVersion | |
29 | pythonVersion=$(python3 --version 2>/dev/null | awk '{ print $2 }' || echo "0.0.0") | |
30 | minVer=$(printf "$pythonVersion\n3.7.0" | sort --version-sort | head -n1) | |
31 | if [[ "$minVer" == "3.7.0" ]]; then | |
32 | return 0 | |
33 | fi | |
34 | return 1 | |
35 | } | |
36 | ||
37 | function install_python_macos() { | |
38 | if ! is_python_min_version_found; then | |
39 | if ! which brew >/dev/null 2>&1; then | |
40 | echo "error: brew not found - download from https://brew.sh/" >&2 | |
41 | exit 1 | |
42 | fi | |
43 | echo "installing python3 .." >&2 | |
44 | HOMEBREW_NO_AUTO_UPDATE=1 brew install --quiet python3 | |
45 | fi | |
46 | } | |
47 | ||
48 | function install_python_ubuntu() { | |
49 | local packages=() | |
50 | is_python_min_version_found || packages+=( python3.10 ) | |
51 | dpkg -l | awk '$2=="python3.10-venv"&&$1=="ii"' | grep -q . \ | |
52 | || packages+=( python3.10-venv ) | |
53 | pip3 --version >/dev/null 2>&1 || packages+=( python3-pip ) | |
54 | if [[ ${#packages[@]} -gt 0 ]]; then | |
55 | echo "installing python3 packages: ${packages[*]} .." | |
56 | sudo apt install "${packages[@]}" | |
57 | fi | |
58 | } | |
59 | #endregion | |
60 | ||
61 | #region sdk | |
62 | function get_platform_os() { | |
63 | case "$(uname -s | tr '[:upper:]' '[:lower:]')" in | |
64 | darwin ) | |
65 | echo "mac" | |
66 | ;; | |
67 | linux ) | |
68 | echo "linux" | |
69 | ;; | |
70 | * ) | |
71 | echo "error: unsupported platform os '$(uname -s)' expected 'Darwin' or 'Linux'" >&2 | |
72 | exit 1 | |
73 | esac | |
74 | } | |
75 | ||
76 | function get_sdk_home() { | |
77 | local android_home=${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}} | |
78 | if [[ "$android_home" == "" ]]; then | |
79 | case $(get_platform_os) in | |
80 | mac ) | |
81 | echo "$HOME/Library/Android/sdk" | |
82 | ;; | |
83 | linux ) | |
84 | echo "$HOME/Android/Sdk" | |
85 | ;; | |
86 | * ) | |
87 | echo "error: unsupported platform" >&2 | |
88 | exit 1 | |
89 | esac | |
90 | fi | |
91 | echo "$android_home" | |
92 | } | |
93 | ||
94 | function ensure_android_home_exists() { | |
95 | if [[ ! -d "$android_home" ]]; then | |
96 | echo "creating android home directory: $android_home" >&2 | |
97 | mkdir -p "$android_home" | |
98 | fi | |
99 | } | |
100 | ||
101 | function get_cmdline_tools_filename() { | |
102 | local platform=$(get_platform_os) | |
103 | local filename=$( \ | |
104 | curl -fsSL https://developer.android.com/studio \ | |
105 | | sed -nE "s/.*(commandlinetools-$platform-[A-Za-z0-9._-]*_latest\.zip).*/\1/p" \ | |
106 | | head -n1 \ | |
107 | ) | |
108 | if [[ "$filename" == "" ]]; then | |
109 | echo "error: could not detect android commandlinetools filename" >&2 | |
110 | exit 1 | |
111 | fi | |
112 | echo "$filename" | |
113 | } | |
114 | ||
115 | function get_cmdline_tools_url() { | |
116 | local filename=$(get_cmdline_tools_filename) | |
117 | echo "https://dl.google.com/android/repository/$filename" | |
118 | } | |
119 | ||
120 | function ensure_cmdline_tools_exists() { | |
121 | local sdkmanager_path="$cmdline_tools_path/latest/bin/sdkmanager" | |
122 | if [[ ! -f "$sdkmanager_path" ]]; then | |
123 | echo "fetching cmdline-tools .." >&2 | |
124 | local url=$(get_cmdline_tools_url) | |
125 | curl -fsSL "$url" -o cmdline-tools.zip | |
126 | unzip cmdline-tools.zip -d cmdline-tools | |
127 | rm cmdline-tools.zip | |
128 | cd cmdline-tools | |
129 | mv cmdline-tools latest | |
130 | cd - >/dev/null | |
131 | fi | |
132 | if ! which sdkmanager >/dev/null 2>&1; then | |
133 | PATH="$cmdline_tools_path/latest/bin:$PATH" | |
134 | fi | |
135 | } | |
136 | ||
137 | function ensure_emulator_exists() { | |
138 | local emulator_version=$(sdkmanager --list_installed | awk '$1 == "emulator" { print $2 }') | |
139 | if [[ "$emulator_version" == "" ]]; then | |
140 | echo "fetching emulator .." >&2 | |
141 | echo y | sdkmanager --install emulator | |
142 | fi | |
143 | if ! which emulator >/dev/null 2>&1; then | |
144 | PATH="$emulator_path:$PATH" | |
145 | fi | |
146 | } | |
147 | ||
148 | function ensure_platform_tools_exists() { | |
149 | local platform_tools_version=$(sdkmanager --list_installed | awk '$1 == "platform-tools" { print $2 }') | |
150 | if [[ "$platform_tools_version" == "" ]]; then | |
151 | echo "fetching platform-tools .." >&2 | |
152 | echo y | sdkmanager --install platform-tools | |
153 | fi | |
154 | if ! which adb >/dev/null 2>&1; then | |
155 | PATH="$platform_tools_path:$PATH" | |
156 | fi | |
157 | } | |
158 | ||
159 | function ensure_platforms_exists() { | |
160 | if [[ ! -d platforms ]]; then | |
161 | echo "creating directory platforms .." >&2 | |
162 | mkdir platforms | |
163 | fi | |
164 | } | |
165 | ||
166 | function get_platform_arch() { | |
167 | case "$(uname -m)" in | |
168 | x86_64 ) | |
169 | echo "x86_64" | |
170 | ;; | |
171 | arm64 ) | |
172 | echo "arm64-v8a" | |
173 | ;; | |
174 | * ) | |
175 | echo "error: unsupported platform arch '$(uname -m)' expected 'x86_64' or 'arm64'" >&2 | |
176 | exit 1 | |
177 | esac | |
178 | } | |
179 | ||
180 | function setup_android_sdk() { | |
181 | android_home=$(get_sdk_home) | |
182 | cmdline_tools_path="$android_home/cmdline-tools" | |
183 | emulator_path="$android_home/emulator" | |
184 | platform_tools_path="$android_home/platform-tools" | |
185 | ||
186 | if [[ "${ANDROID_HOME:-}" == "" ]]; then | |
187 | export ANDROID_HOME=$android_home | |
188 | fi | |
189 | ||
190 | if [[ "${ANDROID_SDK_ROOT:-}" == "" ]]; then | |
191 | export ANDROID_SDK_ROOT=$android_home | |
192 | fi | |
193 | ||
194 | ensure_android_home_exists | |
195 | cd "$android_home" | |
196 | ensure_cmdline_tools_exists | |
197 | ensure_emulator_exists | |
198 | ensure_platform_tools_exists | |
199 | ensure_platforms_exists | |
200 | cd - >/dev/null | |
201 | } | |
202 | #endregion | |
203 | ||
204 | #region submodules | |
205 | function setup_pywidevine() { | |
206 | cd lib | |
207 | if [[ ! -f pywidevine/.git/config ]]; then | |
208 | echo "cloning pywidevine .." | |
209 | git clone --quiet https://github.com/rlaphoenix/pywidevine.git | |
210 | fi | |
211 | cd pywidevine | |
212 | poetry --version >/dev/null 2>&1 || pip3 install poetry | |
213 | poetry config virtualenvs.in-project true | |
214 | poetry install -E serve | |
215 | cd "$base_dir" | |
216 | } | |
217 | ||
218 | function setup_dumper() { | |
219 | cd lib | |
220 | if [[ ! -f dumper/.git/config ]]; then | |
221 | echo "cloning dumper .." | |
222 | git clone --quiet https://github.com/Diazole/dumper.git | |
223 | fi | |
224 | cd dumper | |
225 | echo "installing dumper dependencies .." | |
226 | python3 -m venv venv | |
227 | . venv/bin/activate | |
228 | pip3 install -r requirements.txt | |
229 | deactivate | |
230 | cd "$base_dir" | |
231 | } | |
232 | ||
233 | function install_submodules() { | |
234 | if [[ ! -d "$base_dir/lib" ]]; then | |
235 | mkdir "$base_dir/lib" | |
236 | fi | |
237 | setup_pywidevine | |
238 | setup_dumper | |
239 | } | |
240 | #endregion | |
241 | ||
242 | #region dumper | |
243 | function ensure_frida_server_exists() { | |
244 | case "$(uname -m)" in | |
245 | x86_64 | arm64 ) | |
246 | frida_bin="frida-server-16.0.8-android-$(uname -m)" | |
247 | ;; | |
248 | * ) | |
249 | echo "error: unsupported platform arch '$(uname -m)' expected 'x86_64' or 'arm64'" >&2 | |
250 | exit 1 | |
251 | esac | |
252 | local frida_url="https://github.com/frida/frida/releases/download/16.0.8/$frida_bin.xz" | |
253 | if [[ ! -f "lib/$frida_bin" ]]; then | |
254 | echo "fetching $frida_bin .." | |
255 | curl -fsSL -o- "$frida_url" | xz -d >"lib/$frida_bin" | |
256 | chmod +x "lib/$frida_bin" | |
257 | fi | |
258 | } | |
259 | ||
260 | function set_android_versions() { | |
261 | case "${1:-9}" in | |
262 | 9 ) | |
263 | api_version="28" | |
264 | cdm_version="14.0.0" | |
265 | ;; | |
266 | 10 ) | |
267 | api_version="29" | |
268 | cdm_version="15.0.0" | |
269 | ;; | |
270 | * ) | |
271 | echo "error: android version must be 9 or 10" >&2 | |
272 | exit 1 | |
273 | esac | |
274 | } | |
275 | ||
276 | function set_avd_vars() { | |
277 | avd_package="system-images;android-$api_version;default;$(get_platform_arch)" | |
278 | avd_name="Pixel_6_API_$api_version" | |
279 | avd_device="pixel_6" | |
280 | } | |
281 | ||
282 | function ensure_default_package_exists() { | |
283 | local package_version=$(sdkmanager --list_installed | awk '$1 == "'"$avd_package"'" { print $2 }') | |
284 | if [[ "$package_version" == "" ]]; then | |
285 | echo "fetching $avd_package .." >&2 | |
286 | echo y | sdkmanager --install "$avd_package" | |
287 | fi | |
288 | } | |
289 | ||
290 | function dumper_exit_handler() { | |
291 | if [[ ${dump_keys_pid:-} != "" ]]; then | |
292 | echo "exiting dumper .." >&2 | |
293 | kill "$dump_keys_pid" >/dev/null 2>&1 || true | |
294 | fi | |
295 | if [[ ${emulator_pid:-} != "" ]]; then | |
296 | echo "exiting emulator .." >&2 | |
297 | kill "$emulator_pid" >/dev/null 2>&1 || true | |
298 | sleep 2 | |
299 | fi | |
300 | echo "removing avd $avd_name .." >&2 | |
301 | avdmanager delete avd --name "$avd_name" >/dev/null 2>&1 || true | |
302 | } | |
303 | ||
304 | function create_avd() { | |
305 | echo "creating device $avd_name .." >&2 | |
306 | avdmanager create avd --device "$avd_device" --name "$avd_name" --package "$avd_package" --sdcard 512M | |
307 | ANDROID_EMULATOR_WAIT_TIME_BEFORE_KILL=0 \ | |
308 | emulator -no-audio -no-boot-anim -no-snapshot-save -no-window -avd "$avd_name" >/dev/null & | |
309 | emulator_pid=$! | |
310 | } | |
311 | ||
312 | function copy_frida_server() { | |
313 | echo "copying $frida_bin .." >&2 | |
314 | while true; do | |
315 | if adb push "lib/$frida_bin" /sdcard >/dev/null 2>&1; then | |
316 | break | |
317 | fi | |
318 | sleep 1 | |
319 | done | |
320 | } | |
321 | ||
322 | function start_frida_server() { | |
323 | echo "starting frida server .." >&2 | |
324 | sleep 2 | |
325 | adb shell su 0 sh "-c 'mv /sdcard/$frida_bin /data/local/tmp/ && cd /data/local/tmp && chmod +x $frida_bin && ./$frida_bin'" & | |
326 | sleep 2 | |
327 | } | |
328 | ||
329 | function start_dumper() { | |
330 | echo "starting dumper .." >&2 | |
331 | cd lib/dumper | |
332 | . venv/bin/activate | |
333 | python3 dump_keys.py --cdm-version "$cdm_version" & | |
334 | dump_keys_pid=$! | |
335 | deactivate || true | |
336 | sleep 2 | |
337 | cd - >/dev/null | |
338 | } | |
339 | ||
340 | function launch_drm_url() { | |
341 | echo "launching bitmovin .." >&2 | |
342 | adb shell am start -a android.intent.action.VIEW -d https://bitmovin.com/demos/drm | |
343 | } | |
344 | ||
345 | function wait_for_dumper() { | |
346 | echo "waiting for key dump .." >&2 | |
347 | if [[ ! -d lib/dumper/key_dumps ]]; then | |
348 | mkdir -p lib/dumper/key_dumps | |
349 | fi | |
350 | while true; do | |
351 | key=$(find lib/dumper/key_dumps -type f -name private_key.pem -newermt '-10 seconds' | head -n1) | |
352 | if [[ "$key" != "" ]]; then | |
353 | echo "success! found key at file://$PWD/$key" >&2 | |
354 | break | |
355 | fi | |
356 | sleep 2 | |
357 | done | |
358 | } | |
359 | ||
360 | function create_wvd() { | |
361 | echo "creating wvd file .." >&2 | |
362 | local key_dir="$base_dir/$(dirname "$key")" | |
363 | local tmp_dir=$(mktemp -d) | |
364 | cd lib/pywidevine | |
365 | poetry run pywidevine create-device \ | |
366 | --type ANDROID --level 3 \ | |
367 | --key "$key_dir/private_key.pem" \ | |
368 | --client_id "$key_dir/client_id.bin" \ | |
369 | --output "$tmp_dir" | |
370 | cd - >/dev/null | |
371 | local wvd_file=$(ls -1 "$tmp_dir"/*.wvd) | |
372 | if [[ "$wvd_file" == "" ]]; then | |
373 | echo "error: could not create wvd" >&2 | |
374 | exit 1 | |
375 | fi | |
376 | local new_wvd_name="$(basename "$wvd_file" | sed 's/unknown_//' | sed 's/sdk_built_for_//')" | |
377 | if [[ ! -d "$base_dir/devices" ]]; then | |
378 | mkdir "$base_dir/devices" | |
379 | fi | |
380 | mv "$wvd_file" "$base_dir/devices/$new_wvd_name" | |
381 | echo "success: created device $new_wvd_name" | |
382 | } | |
383 | ||
384 | function dump_keys() { | |
385 | ensure_frida_server_exists | |
386 | set_android_versions "$@" | |
387 | set_avd_vars | |
388 | ensure_default_package_exists | |
389 | trap dumper_exit_handler exit | |
390 | create_avd | |
391 | copy_frida_server | |
392 | start_frida_server | |
393 | start_dumper | |
394 | launch_drm_url | |
395 | wait_for_dumper | |
396 | create_wvd | |
397 | } | |
398 | #endregion | |
399 | ||
400 | function error_reporter() { | |
401 | echo -e "\n\033[91merror: setup failed with status $? at line $1:\033[0m" >&2 | |
402 | echo "" >&2 | |
403 | awk 'NR>L-3 && NR<L+2 { printf "%s%-5d %s%s\n",(NR==L?"\033[91m> ":"\033[90m "),NR,$0,"\033[0m" }' "L=$1" "$0" >&2 | |
404 | } | |
405 | #endregion | |
406 | ||
407 | trap 'error_reporter $LINENO' ERR | |
408 | ||
409 | case "$(uname -s)" in | |
410 | Darwin ) | |
411 | echo "running setup for macOS .." | |
412 | add_user_local_bin_to_path | |
413 | install_python_macos | |
414 | install_submodules | |
415 | ;; | |
416 | Linux ) | |
417 | [[ ! -f /etc/os-release ]] || . /etc/os-release | |
418 | if [[ "${ID:-}" != "ubuntu" ]]; then | |
419 | echo "error: unsupported distro" >&2 | |
420 | exit 1 | |
421 | fi | |
422 | echo "running setup for Ubuntu .." | |
423 | export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring | |
424 | add_user_local_bin_to_path | |
425 | install_bootstrap_ubuntu | |
426 | install_python_ubuntu | |
427 | install_submodules | |
428 | unset PYTHON_KEYRING_BACKEND | |
429 | ;; | |
430 | * ) | |
431 | echo "error: unsupported OS $(uname -s)" >&2 | |
432 | exit 1 | |
433 | esac | |
434 | ||
435 | echo "configuring the environment .." >&2 | |
436 | setup_android_sdk | |
437 | ||
438 | echo "starting dumper .." >&2 | |
439 | dump_keys "$@" | |
440 |