Advertisement
Guest User

android-l3-cdm-dump.sh

a guest
Apr 1st, 2023
684
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 11.71 KB | None | 0 0
  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.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement