mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 15:38:45 -07:00
975753deac
Patches the Quest build of Rec Room 2023.03.21 (20230317 / 2128210, the
same appVersion as the PC client) to connect to a DorkNet server, using
one native hook library loaded via DT_NEEDED on libmain.so.
- host rewrite onto <svc>.<ServerHost> or a {service}-dev.example.com template
- Photon app ids and region injection (PhotonRegion must match PC)
- TLS / pinning / image-signature bypass, integrity callbacks neutralised
- no-Meta-account build; the server treats platform id 0/1/blank as a
placeholder and keys those accounts by device id
- build.ps1 -Obb packages a DorkNet-<ver>.xapk with one-command
installers for Windows and macOS/Linux; app is named via AppName
- README, docs/quest.md and NOTICE updated; credits RecFlare and
And64InlineHook (MIT)
Tested on a Quest 2: all hooks arm, requests reach the dev server.
146 lines
6.5 KiB
PowerShell
146 lines
6.5 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Install a DorkNet Rec Room .xapk onto a Meta Quest over adb.
|
|
|
|
.DESCRIPTION
|
|
Installs the APK, copies the OBB to the path the game expects, then launches
|
|
the app. Works in Windows PowerShell 5.1 and PowerShell 7. Run it with no
|
|
arguments from the package folder, or double-click install.cmd.
|
|
|
|
.PARAMETER Xapk
|
|
The package to install. Default: the only .xapk next to this script.
|
|
|
|
.PARAMETER Serial
|
|
adb serial of the headset when more than one device is connected.
|
|
|
|
.PARAMETER NoLaunch
|
|
Install only; don't start the app afterwards.
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string]$Xapk,
|
|
[string]$Serial,
|
|
[switch]$NoLaunch
|
|
)
|
|
|
|
# adb writes progress to stderr; under 'Stop' Windows PowerShell would treat
|
|
# that as a failure, so exit codes are checked by hand instead.
|
|
$ErrorActionPreference = 'Continue'
|
|
Set-StrictMode -Version 2
|
|
Add-Type -AssemblyName System.IO.Compression, System.IO.Compression.FileSystem
|
|
|
|
function Say($m) { Write-Host "==> $m" -ForegroundColor Cyan }
|
|
function Fail($m) { Write-Host "ERROR: $m" -ForegroundColor Red; exit 1 }
|
|
|
|
# ---- find the package ----------------------------------------------------
|
|
if (-not $Xapk) {
|
|
$found = @(Get-ChildItem -Path $PSScriptRoot -Filter *.xapk -File)
|
|
if ($found.Count -eq 0) { Fail "no .xapk found next to $PSCommandPath; pass -Xapk <file>." }
|
|
if ($found.Count -gt 1) { Fail "more than one .xapk here; pass -Xapk <file>." }
|
|
$Xapk = $found[0].FullName
|
|
}
|
|
if (-not (Test-Path -LiteralPath $Xapk)) { Fail "package not found: $Xapk" }
|
|
$Xapk = (Resolve-Path -LiteralPath $Xapk).Path
|
|
|
|
# ---- find adb -----------------------------------------------------------
|
|
$adb = $null
|
|
$cmd = Get-Command adb -ErrorAction SilentlyContinue
|
|
if ($cmd) { $adb = $cmd.Source }
|
|
if (-not $adb) {
|
|
$roots = @($env:ANDROID_SDK_ROOT, $env:ANDROID_HOME, (Join-Path $env:LOCALAPPDATA 'Android\Sdk'), $PSScriptRoot) | Where-Object { $_ }
|
|
foreach ($r in $roots) {
|
|
foreach ($c in @((Join-Path $r 'platform-tools\adb.exe'), (Join-Path $r 'adb.exe'))) {
|
|
if (Test-Path $c) { $adb = $c; break }
|
|
}
|
|
if ($adb) { break }
|
|
}
|
|
}
|
|
if (-not $adb) {
|
|
Fail ("adb not found. Install Android platform-tools from " +
|
|
"https://developer.android.com/tools/releases/platform-tools and put adb on PATH " +
|
|
"(or unzip platform-tools next to this script).")
|
|
}
|
|
|
|
# ---- pick the headset ----------------------------------------------------
|
|
$lines = & $adb devices | Select-Object -Skip 1 | Where-Object { $_ -match '\S' }
|
|
$ready = @($lines | Where-Object { $_ -match "^(\S+)\s+device$" } | ForEach-Object { ($_ -split '\s+')[0] })
|
|
$unauth = @($lines | Where-Object { $_ -match '\sunauthorized$' })
|
|
if ($Serial) {
|
|
if ($ready -notcontains $Serial) { Fail "device $Serial is not connected and authorised (adb devices)." }
|
|
} elseif ($ready.Count -eq 1) {
|
|
$Serial = $ready[0]
|
|
} elseif ($ready.Count -gt 1) {
|
|
Fail ("more than one device connected: " + ($ready -join ', ') + ". Pass -Serial <id>.")
|
|
} elseif ($unauth.Count -gt 0) {
|
|
Fail 'the headset is connected but not authorised: put it on and accept "Allow USB debugging".'
|
|
} else {
|
|
Fail 'no headset found. Enable developer mode, connect it over USB, and accept "Allow USB debugging" in the headset.'
|
|
}
|
|
function Adb { & $adb -s $Serial @args }
|
|
$model = (Adb shell getprop ro.product.model | Out-String).Trim()
|
|
Say "headset: $model ($Serial)"
|
|
|
|
# ---- read the package ----------------------------------------------------
|
|
$zip = [System.IO.Compression.ZipFile]::OpenRead($Xapk)
|
|
$tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("dorknet-install-" + [guid]::NewGuid().ToString('N'))
|
|
New-Item -ItemType Directory -Path $tmp | Out-Null
|
|
try {
|
|
$me = $zip.GetEntry('manifest.json')
|
|
if (-not $me) { Fail 'not an XAPK: manifest.json missing.' }
|
|
$sr = New-Object System.IO.StreamReader($me.Open())
|
|
$manifest = $sr.ReadToEnd() | ConvertFrom-Json
|
|
$sr.Dispose()
|
|
$pkg = $manifest.package_name
|
|
Say "package: $($manifest.name) $pkg $($manifest.version_name) ($($manifest.version_code))"
|
|
|
|
function Extract($entry) {
|
|
$out = Join-Path $tmp ([System.IO.Path]::GetFileName($entry.FullName))
|
|
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $out, $true)
|
|
return $out
|
|
}
|
|
|
|
# ---- APK -------------------------------------------------------------
|
|
$apkEntry = $zip.GetEntry("$pkg.apk")
|
|
if (-not $apkEntry) { $apkEntry = @($zip.Entries | Where-Object { $_.FullName -like '*.apk' })[0] }
|
|
if (-not $apkEntry) { Fail 'no APK inside the package.' }
|
|
Say 'installing the app'
|
|
$apkFile = Extract $apkEntry
|
|
$res = (Adb install -r $apkFile 2>&1 | Out-String)
|
|
if ($res -match 'INSTALL_FAILED_UPDATE_INCOMPATIBLE|signatures do not match') {
|
|
Write-Host "An older copy of $pkg is installed with a different signing key." -ForegroundColor Yellow
|
|
Write-Host "It has to be removed first. Your account lives on the server, but local settings on the headset are lost." -ForegroundColor Yellow
|
|
$ans = Read-Host 'Uninstall it and continue? [y/N]'
|
|
if ($ans -notmatch '^(y|yes)$') { Fail 'cancelled.' }
|
|
Adb uninstall $pkg | Out-Null
|
|
$res = (Adb install -r $apkFile 2>&1 | Out-String)
|
|
}
|
|
if ($res -notmatch 'Success') { Fail ("app install failed:`n" + $res.Trim()) }
|
|
Remove-Item -Force $apkFile
|
|
|
|
# ---- OBB (expansion files) ------------------------------------------
|
|
foreach ($x in @($manifest.expansions)) {
|
|
if (-not $x) { continue }
|
|
$entry = $zip.GetEntry($x.file)
|
|
if (-not $entry) { Fail "package is missing $($x.file)." }
|
|
$dest = '/sdcard/' + $x.install_path
|
|
$have = (Adb shell "stat -c %s '$dest' 2>/dev/null" | Out-String).Trim()
|
|
if ($have -eq [string]$entry.Length) { Say "game data already on the headset, skipping ($([System.IO.Path]::GetFileName($dest)))"; continue }
|
|
Say ("copying game data ({0:N2} GB) - this takes a few minutes" -f ($entry.Length / 1GB))
|
|
$f = Extract $entry
|
|
Adb shell "mkdir -p '$([System.IO.Path]::GetDirectoryName($dest).Replace('\','/'))'" | Out-Null
|
|
Adb push $f $dest
|
|
if ($LASTEXITCODE) { Fail 'copying the game data failed (is there enough free space on the headset?).' }
|
|
Remove-Item -Force $f
|
|
}
|
|
} finally {
|
|
$zip.Dispose()
|
|
Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host "Installed. In the headset: Library > Unknown Sources > $($manifest.name)." -ForegroundColor Green
|
|
if (-not $NoLaunch) {
|
|
Say 'launching (put the headset on)'
|
|
Adb shell monkey -p $pkg -c android.intent.category.LAUNCHER 1 2>&1 | Out-Null
|
|
}
|