android-reverse-engineering.../plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.ps1

345 lines
12 KiB
PowerShell

# install-dep.ps1 — Install a single dependency for Android reverse engineering
# Usage: install-dep.ps1 <dependency>
# Dependencies: java, jadx, vineflower, dex2jar, apktool, adb
#
# Exit codes:
# 0 — installed successfully
# 1 — installation failed
# 2 — requires manual action
param(
[Parameter(Position=0)]
[string]$Dep
)
$ErrorActionPreference = 'Stop'
function Show-Usage {
Write-Host @"
Usage: install-dep.ps1 <dependency>
Install a dependency required for Android reverse engineering.
Available dependencies:
java Java JDK 17+
jadx jadx decompiler
vineflower Vineflower (Fernflower fork) decompiler
dex2jar DEX to JAR converter
apktool Android resource decoder
adb Android Debug Bridge
The script detects available package managers (winget, scoop, choco), then:
- Installs using the first available manager
- Falls back to direct download to %USERPROFILE%\.local\share\
- Prints manual instructions if no option works
"@
exit 0
}
if (-not $Dep -or $Dep -eq '-h' -or $Dep -eq '--help') { Show-Usage }
# --- Detect environment ---
$hasWinget = [bool](Get-Command winget -ErrorAction SilentlyContinue)
$hasScoop = [bool](Get-Command scoop -ErrorAction SilentlyContinue)
$hasChoco = [bool](Get-Command choco -ErrorAction SilentlyContinue)
function Write-Info { param($msg) Write-Host "[INFO] $msg" }
function Write-Ok { param($msg) Write-Host "[OK] $msg" }
function Write-Fail { param($msg) Write-Host "[FAIL] $msg" -ForegroundColor Red }
function Write-Manual {
param($msg)
Write-Host "[MANUAL] $msg" -ForegroundColor Yellow
Write-Host " Cannot install automatically. Please install manually and retry." -ForegroundColor Yellow
exit 2
}
# --- Helper: download a file ---
function Invoke-Download {
param([string]$Url, [string]$Dest)
Write-Info "Downloading $Url..."
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing
}
# --- Helper: get latest GitHub release tag ---
function Get-GHLatestTag {
param([string]$Repo)
$url = "https://api.github.com/repos/$Repo/releases/latest"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$response = Invoke-RestMethod -Uri $url -UseBasicParsing
return $response.tag_name
}
# --- Helper: ensure directory on PATH ---
function Add-ToUserPath {
param([string]$Dir)
$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'User')
if ($currentPath -notlike "*$Dir*") {
[Environment]::SetEnvironmentVariable('PATH', "$Dir;$currentPath", 'User')
Write-Info "Added $Dir to user PATH. Restart your terminal to apply."
}
if ($env:PATH -notlike "*$Dir*") {
$env:PATH = "$Dir;$env:PATH"
}
}
$localBin = Join-Path $env:USERPROFILE '.local\bin'
$localShare = Join-Path $env:USERPROFILE '.local\share'
# =====================================================================
# Dependency installers
# =====================================================================
function Install-Java {
$javaBin = Get-Command java -ErrorAction SilentlyContinue
if ($javaBin) {
$verOutput = & java -version 2>&1 | Select-Object -First 1
if ("$verOutput" -match '"(\d+)') {
$ver = [int]$Matches[1]
if ($ver -ge 17) {
Write-Ok "Java $ver already installed"
return
}
}
}
Write-Info "Installing Java JDK 17+..."
if ($hasWinget) {
Write-Info "Installing via winget..."
winget install --id Microsoft.OpenJDK.17 --accept-source-agreements --accept-package-agreements
} elseif ($hasScoop) {
Write-Info "Installing via scoop..."
scoop install openjdk17
} elseif ($hasChoco) {
Write-Info "Installing via choco..."
choco install openjdk17 -y
} else {
Write-Manual "Install Java JDK 17+ from https://adoptium.net/"
}
# Verify
$javaBin = Get-Command java -ErrorAction SilentlyContinue
if ($javaBin) {
Write-Ok "Java installed: $(& java -version 2>&1 | Select-Object -First 1)"
} else {
Write-Fail "Java installation may require a terminal restart for PATH update."
exit 1
}
}
function Install-Jadx {
if (Get-Command jadx -ErrorAction SilentlyContinue) {
Write-Ok "jadx already installed"
return
}
# Try scoop first (cleanest on Windows)
if ($hasScoop) {
Write-Info "Installing jadx via scoop..."
scoop install jadx
if (Get-Command jadx -ErrorAction SilentlyContinue) {
Write-Ok "jadx installed via scoop"
return
}
}
# Direct download from GitHub releases
Write-Info "Installing jadx from GitHub releases..."
$tag = Get-GHLatestTag "skylot/jadx"
if (-not $tag) {
Write-Fail "Could not determine latest jadx version."
Write-Manual "Download from https://github.com/skylot/jadx/releases/latest"
}
$version = $tag -replace '^v', ''
$url = "https://github.com/skylot/jadx/releases/download/$tag/jadx-$version.zip"
$tmpZip = Join-Path $env:TEMP "jadx-$version.zip"
Invoke-Download -Url $url -Dest $tmpZip
$installDir = Join-Path $localShare 'jadx'
if (Test-Path $installDir) { Remove-Item $installDir -Recurse -Force }
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
Expand-Archive -Path $tmpZip -DestinationPath $installDir -Force
Remove-Item $tmpZip -Force
# Add jadx\bin to PATH
$jadxBin = Join-Path $installDir 'bin'
Add-ToUserPath $jadxBin
if (Get-Command jadx -ErrorAction SilentlyContinue) {
Write-Ok "jadx $version installed to $installDir"
} else {
Write-Ok "jadx $version installed to $installDir"
Write-Info "Restart your terminal or run: `$env:PATH = '$jadxBin;' + `$env:PATH"
}
}
function Install-Vineflower {
if (Get-Command vineflower -ErrorAction SilentlyContinue) {
Write-Ok "Vineflower CLI already installed"
return
}
if (Get-Command fernflower -ErrorAction SilentlyContinue) {
Write-Ok "Fernflower CLI already installed"
return
}
$ffCandidates = @(
$env:FERNFLOWER_JAR_PATH,
"$env:USERPROFILE\.local\share\vineflower\vineflower.jar",
"$env:USERPROFILE\vineflower\vineflower.jar",
"$env:USERPROFILE\fernflower\fernflower.jar"
)
foreach ($c in $ffCandidates) {
if ($c -and (Test-Path $c -ErrorAction SilentlyContinue)) {
Write-Ok "Vineflower/Fernflower JAR already exists: $c"
return
}
}
# Download JAR from GitHub releases
Write-Info "Installing Vineflower from GitHub releases..."
$tag = Get-GHLatestTag "Vineflower/vineflower"
if (-not $tag) {
Write-Fail "Could not determine latest Vineflower version."
Write-Manual "Download from https://github.com/Vineflower/vineflower/releases/latest"
}
$version = $tag -replace '^v', ''
$url = "https://github.com/Vineflower/vineflower/releases/download/$tag/vineflower-$version.jar"
$installDir = Join-Path $localShare 'vineflower'
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
Invoke-Download -Url $url -Dest (Join-Path $installDir 'vineflower.jar')
# Create wrapper batch file
New-Item -ItemType Directory -Path $localBin -Force | Out-Null
$wrapperPath = Join-Path $localBin 'vineflower.cmd'
Set-Content -Path $wrapperPath -Value "@echo off`r`njava -jar `"$installDir\vineflower.jar`" %*"
Add-ToUserPath $localBin
[Environment]::SetEnvironmentVariable('FERNFLOWER_JAR_PATH', "$installDir\vineflower.jar", 'User')
$env:FERNFLOWER_JAR_PATH = "$installDir\vineflower.jar"
Write-Ok "Vineflower $version installed to $installDir\vineflower.jar"
Write-Info "FERNFLOWER_JAR_PATH set to $installDir\vineflower.jar"
}
function Install-Dex2Jar {
if ((Get-Command d2j-dex2jar -ErrorAction SilentlyContinue) -or
(Get-Command d2j-dex2jar.bat -ErrorAction SilentlyContinue)) {
Write-Ok "dex2jar already installed"
return
}
Write-Info "Installing dex2jar from GitHub releases..."
$tag = try { Get-GHLatestTag "pxb1988/dex2jar" } catch { "v2.4" }
if (-not $tag) { $tag = "v2.4" }
$version = $tag -replace '^v', ''
$url = "https://github.com/pxb1988/dex2jar/releases/download/$tag/dex-tools-v$version.zip"
$tmpZip = Join-Path $env:TEMP "dex2jar-$version.zip"
try {
Invoke-Download -Url $url -Dest $tmpZip
} catch {
$url = "https://github.com/pxb1988/dex2jar/releases/download/$tag/dex-tools-$version.zip"
try {
Invoke-Download -Url $url -Dest $tmpZip
} catch {
Write-Fail "Download failed."
Write-Manual "Download from https://github.com/pxb1988/dex2jar/releases/latest"
}
}
$installDir = Join-Path $localShare 'dex2jar'
if (Test-Path $installDir) { Remove-Item $installDir -Recurse -Force }
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
Expand-Archive -Path $tmpZip -DestinationPath $installDir -Force
Remove-Item $tmpZip -Force
# Find the actual bin directory (may be nested)
$d2jBat = Get-ChildItem -Path $installDir -Recurse -Filter 'd2j-dex2jar.bat' | Select-Object -First 1
if (-not $d2jBat) {
$d2jBat = Get-ChildItem -Path $installDir -Recurse -Filter 'd2j-dex2jar.sh' | Select-Object -First 1
}
if (-not $d2jBat) {
Write-Fail "Could not find d2j-dex2jar in extracted archive."
Write-Manual "Download and extract manually from https://github.com/pxb1988/dex2jar/releases"
}
$binDir = $d2jBat.DirectoryName
Add-ToUserPath $binDir
Write-Ok "dex2jar $version installed to $installDir"
}
function Install-Apktool {
if (Get-Command apktool -ErrorAction SilentlyContinue) {
Write-Ok "apktool already installed"
return
}
if ($hasScoop) {
Write-Info "Installing apktool via scoop..."
scoop install apktool
} elseif ($hasChoco) {
Write-Info "Installing apktool via choco..."
choco install apktool -y
} else {
Write-Manual "Install apktool from https://apktool.org/docs/install"
}
if (Get-Command apktool -ErrorAction SilentlyContinue) {
Write-Ok "apktool installed"
} else {
Write-Fail "apktool installation may have failed."
exit 1
}
}
function Install-Adb {
if (Get-Command adb -ErrorAction SilentlyContinue) {
Write-Ok "adb already installed"
return
}
if ($hasScoop) {
Write-Info "Installing adb via scoop..."
scoop install adb
} elseif ($hasChoco) {
Write-Info "Installing adb via choco..."
choco install adb -y
} elseif ($hasWinget) {
Write-Info "Installing via winget..."
winget install Google.PlatformTools --accept-source-agreements --accept-package-agreements
} else {
Write-Manual "Install Android SDK Platform Tools from https://developer.android.com/tools/releases/platform-tools"
}
if (Get-Command adb -ErrorAction SilentlyContinue) {
Write-Ok "adb installed"
} else {
Write-Fail "adb installation may have failed."
exit 1
}
}
# =====================================================================
# Dispatch
# =====================================================================
switch ($Dep) {
'java' { Install-Java }
'jadx' { Install-Jadx }
'vineflower' { Install-Vineflower }
'fernflower' { Install-Vineflower }
'dex2jar' { Install-Dex2Jar }
'apktool' { Install-Apktool }
'adb' { Install-Adb }
default {
Write-Host "Error: Unknown dependency '$Dep'" -ForegroundColor Red
Write-Host "Available: java, jadx, vineflower, dex2jar, apktool, adb"
exit 1
}
}