#!/bin/bash

DEBUG=0

echo ' _     _____ _                    _             '
echo '| |   | ____| |    _____   ____ _| |_ ___  _ __ '
echo '| |   |  _| | |   / _ \ \ / / _` | __/ _ \| `__|'
echo '| |___| |___| |__|  __/\ V / (_| | || (_) | |   '
echo '|_____|_____|_____\___| \_/ \__,_|\__\___/|_|   '
echo '                                                '
echo 'Top LEL!                                        '
echo '                                                '

sleep 1
if [[ $DEBUG == 1 ]]; then
  set -x
  trap read debug
fi

EXPLOITLIST="$(cat exploits/exploit_list  | grep -P '^[^#]')"
DEVICELIST="$(adb devices | tail -n +2 | head -n -1 | sed "s/$'\t'/ /g")"
TCPPORT="8000"

function show_progress()
{
  local file="$1"
  local disk="$2"
  local disksize="$3"
  local rewrite="\e[1A"
  local progress=0
  local filesize=0
  local cumspeed=1
  local speedavg=0
  local prev_filesize=0
  local timeleft=0
  local counter=1

  (
  while true; do
    filesize=$(stat $file --printf "%s")
    progress=$(($filesize*100/$disksize))
    if [[ $progress -gt 100 ]]; then
      progress=100
    fi
    echo "XXX"
    echo "$progress"
    echo "Disk image ($disk -> $file): $timeleft left @ $(($speedavg/1024)) KiB/s avg"
    echo "XXX"
    sleep 1
    if [[ $progress == 100 ]]; then
      break
    fi
    cumspeed=$(($cumspeed + $filesize - $prev_filesize))
    speedavg=$(($cumspeed / $counter))
    counter=$(($counter + 1))
    timeleft=`date -u -d@$((($disksize - $filesize)/$speedavg)) +"%T"`
    prev_filesize=$filesize
  done
  ) | dialog --title "Copy progress" --gauge "Please wait..." 7 70 0
  clear
}

function deploy_busybox()
{
  pushd tools/busybox-android > /dev/null
  if [[ ! -f busybox ]]; then
    echo "Building Busybox..."
    ./build.sh > /dev/null
  fi
  ./deploy.sh $1 > /dev/null
  echo "Busybox deployed!"
  popd > /dev/null
}

function remove_busybox()
{
  tools/busybox-android/undeploy.sh $1 > /dev/null
  echo "Busybox removed from device"
}

function acquire_disk()
{
  local DISK="$1"
  local DISKNAME=$(basename $DISK)
  local DISKSIZE=$(($(adb -s $2 shell cat /proc/partitions | tr -d $'\xd' | tr -s " " | grep $DISKNAME$ | cut -d' ' -f 4)*1024))

  if [[ $DEBUG == 1 ]]; then
    DISK="/system/bin/mksh"
    DISKSIZE=$(adb -s $2 shell /data/local/tmp/stat -c "%s" $DISK | tr -d $'\xd')
  fi

  local rootcmd
  echo "Starting copy of $DISKNAME on $2 ($(($DISKSIZE/1024)) KiB)"
  for exploit in $EXPLOITLIST; do
    echo -n "Trying exploit $exploit... "
    eval pre_$exploit $2
    rootcmd=$(eval $exploit $2)
    if [[ $? == 0 ]]; then
      echo "Success!"
      break;
    else
      echo "Failure"
      eval post_$exploit $2
    fi
  done
  if [[ $rootcmd == "" ]]; then
    echo "Couldn't find a working exploit. Aborting copy of $DISKNAME on $2"
    return 1
  fi

  pushd dump/$2 > /dev/null
  adb -s $2 forward tcp:$TCPPORT tcp:$TCPPORT
  local start=$(date +%s)
  echo "cd /data/local/tmp;./dd if=$DISK conv=noerror,sync | ./gzip | ./nc -l -p $TCPPORT;exit" | $rootcmd > /dev/null&
  sleep 1
  nc -w 3 localhost $TCPPORT | gunzip | tee $DISKNAME.dd | sha256sum > $DISKNAME.dd.sha256 &
  show_progress $DISKNAME.dd $DISKNAME $DISKSIZE
  local end=$(date +%s)
  sleep 3
  adb -s $2 forward --remove-all
  echo -e "Done.\n\nTime elapsed: $(($end-$start)) seconds\nHASH (SHA-256): $(cat $DISKNAME.dd.sha256 | cut -d' ' -f 1)\n"
  if [[ $(stat --printf="%s" $DISKNAME.dd) == $DISKSIZE ]]; then
    echo "$DISKNAME copied successfully!"
  else
    echo "WARNING: Disk size ($DISKSIZE B) and image size ($(stat --printf="%s" $DISKNAME.dd) B) do NOT match!"
  fi
  popd > /dev/null

  eval post_$exploit $2
  return 0
}

if [[ $DEVICELIST == "" ]]; then
  echo "No devices found! Exiting..."
  exit 1
fi

unset DEVICELIST
OLDIFS="$IFS"
IFS=$'\n'
for line in $(adb devices -l | tail -n +2 | head -n -1 | sed "s/$'\t'/ /g"); do
  SERIAL=$(echo $line | tr -s " " | cut -d ' ' -f 1)
  DEV=$(echo $line | tr -s " " | cut -d ' ' -f 3)
  DESC=$(echo $line | tr -s " " | cut -d ' ' -f 4-)
  DEVICELIST+=( "$DEV" "$SERIAL $DESC" )
done
IFS="$OLDIFS"

SELECTEDDEVICE=$(dialog --stdout --backtitle "LELevator" --title "Select device" --menu "Choose one of the following Android devices" 15 100 8 "${DEVICELIST[@]}")
clear
if [[ $SELECTEDDEVICE == "" ]]; then
  echo "No device selected. Exiting..."
  exit 1
fi

mkdir -p "dump/$SELECTEDDEVICE"

DISKS=$(adb -s $SELECTEDDEVICE shell cat /proc/partitions | grep -oP "mmcblk\d+" | sort -u)
DISKLIST=""
for disk in $DISKS; do
  DISKLIST="$DISKLIST/dev/block/$disk $disk off "
done
SELECTEDDISKS=`dialog --stdout --backtitle "LELevator" --title "Select disk(s) to copy" --checklist "Choose one or more disks to copy" 15 40 4 $DISKLIST`
clear

source exploits/*.sh
deploy_busybox $SELECTEDDEVICE
for disk in $SELECTEDDISKS; do
  acquire_disk $disk $SELECTEDDEVICE
done
remove_busybox $SELECTEDDEVICE

echo "Finished. Have a nice day!"
