# install-dep.ps1 — Install a single dependency for Android reverse engineering # Usage: install-dep.ps1 # 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 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 } }