Skip to content

Commit ebdf59e

Browse files
authored
Merge pull request #1 from aquilu/fix/hosts-data-volume
Robustez v2: SSV/hosts + FileVault + daemon disable + dominios (de assafdori#170)
2 parents 8ba9608 + b62f795 commit ebdf59e

3 files changed

Lines changed: 433 additions & 90 deletions

File tree

bypass-mdm-v2.sh

Lines changed: 111 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/bash
2+
set -o pipefail
23

34
# Define color codes
45
RED='\033[1;31m'
@@ -8,6 +9,7 @@ YEL='\033[1;33m'
89
PUR='\033[1;35m'
910
CYAN='\033[1;36m'
1011
NC='\033[0m'
12+
PB=/usr/libexec/PlistBuddy
1113

1214
# Error handling function
1315
error_exit() {
@@ -110,82 +112,76 @@ find_available_uid() {
110112
return 1
111113
}
112114

113-
# Function to detect system volumes with multiple fallback strategies
114-
detect_volumes() {
115-
local system_vol=""
116-
local data_vol=""
117-
118-
info "Detecting system volumes..." >&2
115+
# Locate the Data volume by APFS role and unlock it if FileVault-locked
116+
# (ported from bypass-mdm-v3 / PR #170). Echoes the real mount point on
117+
# stdout; all chatter goes to stderr.
118+
step() { echo -e "${CYAN}$1${NC}"; }
119+
resolve_data_volume() {
120+
local id data_dev mount_pt
121+
122+
step "Locating the Data volume by APFS role..." >&2
123+
# Position-independent: on the (Data)-role line, pull the diskNsM token by
124+
# PATTERN, not column (diskutil draws "|" tree chars that shift columns).
125+
id=$(diskutil apfs list 2>/dev/null \
126+
| awk '/\(Data\)/{for(i=1;i<=NF;i++) if($i ~ /^disk[0-9]+s[0-9]+$/){print $i; exit}}')
127+
128+
# Fallback 1: a volume literally named "Data" in `diskutil list`.
129+
if [ -z "$id" ]; then
130+
id=$(diskutil list 2>/dev/null \
131+
| awk '/[[:space:]]Data[[:space:]]/{for(i=1;i<=NF;i++) if($i ~ /^disk[0-9]+s[0-9]+$/) v=$i} END{print v}')
132+
fi
119133

120-
# Strategy 1: Look for common macOS APFS volume patterns
121-
# List all volumes and look for system volume (ends with or contains common names)
122-
for vol in /Volumes/*; do
123-
if [ -d "$vol" ]; then
124-
vol_name=$(basename "$vol")
134+
# Fallback 2: ask the user, showing the disk layout.
135+
if [ -z "$id" ] || ! diskutil info "/dev/$id" >/dev/null 2>&1; then
136+
warn "Could not auto-detect the Data volume. Your disks:" >&2
137+
diskutil list >&2
138+
echo "" >&2
139+
read -p "Type the Data volume identifier (e.g. disk3s1): " id </dev/tty
140+
id="${id#/dev/}"
141+
fi
125142

126-
# Check if this looks like a system volume (not Data, not recovery)
127-
if [[ ! "$vol_name" =~ "Data"$ ]] && [[ ! "$vol_name" =~ "Recovery" ]] && [ -d "$vol/System" ]; then
128-
system_vol="$vol_name"
129-
info "Found system volume: $system_vol" >&2
130-
break
131-
fi
132-
fi
133-
done
143+
[ -n "$id" ] || error_exit "No Data volume identifier provided."
144+
data_dev="/dev/$id"
145+
diskutil info "$data_dev" >/dev/null 2>&1 || error_exit "Not a valid disk: $data_dev"
146+
info "Data volume device: $data_dev" >&2
134147

135-
# Strategy 2: If no system volume found, try looking for any volume with /System directory
136-
if [ -z "$system_vol" ]; then
137-
for vol in /Volumes/*; do
138-
if [ -d "$vol/System" ]; then
139-
system_vol=$(basename "$vol")
140-
warn "Using volume with /System directory: $system_vol" >&2
141-
break
142-
fi
143-
done
144-
fi
148+
_mp() { diskutil info "$data_dev" 2>/dev/null | awk -F': *' '/Mount Point/{print $2}' | sed 's/[[:space:]]*$//'; }
149+
mount_pt=$(_mp)
145150

146-
# Strategy 3: Check for Data volume
147-
if [ -d "/Volumes/Data" ]; then
148-
data_vol="Data"
149-
info "Found data volume: $data_vol" >&2
150-
elif [ -n "$system_vol" ] && [ -d "/Volumes/$system_vol - Data" ]; then
151-
data_vol="$system_vol - Data"
152-
info "Found data volume: $data_vol" >&2
153-
else
154-
# Look for any volume ending with "Data"
155-
for vol in /Volumes/*Data; do
156-
if [ -d "$vol" ]; then
157-
data_vol=$(basename "$vol")
158-
warn "Found data volume: $data_vol" >&2
159-
break
160-
fi
161-
done
151+
if [ -z "$mount_pt" ] || [ ! -d "$mount_pt" ]; then
152+
# Try a plain mount first (works for non-encrypted volumes).
153+
diskutil mount "$data_dev" >&2 2>/dev/null
154+
mount_pt=$(_mp)
162155
fi
163-
164-
# Validate findings
165-
if [ -z "$system_vol" ]; then
166-
error_exit "Could not detect system volume. Please ensure you're running this in Recovery mode with a macOS installation present."
156+
if [ -z "$mount_pt" ] || [ ! -d "$mount_pt" ]; then
157+
# Still not mounted -> almost certainly FileVault-locked. Unlock it.
158+
warn "Data volume appears FileVault-locked — unlocking." >&2
159+
echo -e "${YEL}Enter the password of an account on this Mac (or its FileVault recovery key):${NC}" >&2
160+
diskutil apfs unlockVolume "$data_dev" >&2 \
161+
|| error_exit "Failed to unlock the Data volume. Re-run and enter a valid account password / recovery key."
162+
mount_pt=$(_mp)
167163
fi
168164

169-
if [ -z "$data_vol" ]; then
170-
error_exit "Could not detect data volume. Please ensure you're running this in Recovery mode with a macOS installation present."
171-
fi
165+
[ -d "$mount_pt" ] || error_exit "Data volume mount point not found after mount/unlock."
166+
# Sanity: the dslocal node must exist on this volume.
167+
[ -d "$mount_pt/private/var/db/dslocal/nodes/Default" ] \
168+
|| error_exit "This does not look like a macOS Data volume (no dslocal node at $mount_pt)."
172169

173-
echo "$system_vol|$data_vol"
170+
success "Data volume mounted at: $mount_pt" >&2
171+
echo "$mount_pt"
174172
}
175173

176-
# Detect volumes at startup
177-
volume_info=$(detect_volumes)
178-
system_volume=$(echo "$volume_info" | cut -d'|' -f1)
179-
data_volume=$(echo "$volume_info" | cut -d'|' -f2)
174+
# Locate + mount (FileVault-unlock if needed) the Data volume at startup
175+
data_mount=$(resolve_data_volume) || exit 1
176+
data_volume=$(basename "$data_mount")
180177

181178
# Display header
182179
echo ""
183180
echo -e "${CYAN}╔═══════════════════════════════════════════════╗${NC}"
184181
echo -e "${CYAN}║ Bypass MDM By Assaf Dori (assafdori.com) ║${NC}"
185182
echo -e "${CYAN}╚═══════════════════════════════════════════════╝${NC}"
186183
echo ""
187-
success "System Volume: $system_volume"
188-
success "Data Volume: $data_volume"
184+
success "Data Volume: $data_mount"
189185
echo ""
190186

191187
# Prompt user for choice
@@ -200,26 +196,11 @@ select opt in "${options[@]}"; do
200196
echo -e "${YEL}═══════════════════════════════════════${NC}"
201197
echo ""
202198

203-
# Normalize data volume name if needed
204-
if [ "$data_volume" != "Data" ]; then
205-
info "Renaming data volume to 'Data' for consistency..."
206-
if diskutil rename "$data_volume" "Data" 2>/dev/null; then
207-
success "Data volume renamed successfully"
208-
data_volume="Data"
209-
else
210-
warn "Could not rename data volume, continuing with: $data_volume"
211-
fi
212-
fi
213-
214-
# Validate critical paths
215-
info "Validating system paths..."
216-
217-
system_path="/Volumes/$system_volume"
218-
data_path="/Volumes/$data_volume"
199+
# Data volume already located + mounted (FileVault-unlocked if needed)
200+
# by resolve_data_volume(); data_mount is its real mount point.
201+
info "Validating paths..."
219202

220-
if [ ! -d "$system_path" ]; then
221-
error_exit "System volume path does not exist: $system_path"
222-
fi
203+
data_path="$data_mount"
223204

224205
if [ ! -d "$data_path" ]; then
225206
error_exit "Data volume path does not exist: $data_path"
@@ -342,21 +323,44 @@ select opt in "${options[@]}"; do
342323
success "User account created successfully"
343324
echo ""
344325

345-
# Block MDM domains
326+
# Block MDM enrollment domains (SSV-aware; also blocks the org's own MDM
327+
# host read from the DEP record, plus IPv6). Reads the record here, before
328+
# it is removed later in this flow.
346329
info "Blocking MDM enrollment domains..."
347-
348-
hosts_file="$system_path/etc/hosts"
349-
if [ ! -f "$hosts_file" ]; then
350-
warn "Hosts file does not exist, creating it"
351-
touch "$hosts_file" || error_exit "Failed to create hosts file"
330+
hosts_file="$data_path/private/etc/hosts"
331+
record_found="$data_path/private/var/db/ConfigurationProfiles/Settings/.cloudConfigRecordFound"
332+
mdm_host="" org=""
333+
if [ -f "$record_found" ]; then
334+
mdm_host=$(plutil -convert xml1 -o - "$record_found" 2>/dev/null \
335+
| grep -ioE 'https?://[a-z0-9._-]+' | sed -E 's#https?://##' \
336+
| sort -u | grep -viE '(^|\.)apple\.com$' | head -1)
337+
org=$(plutil -convert xml1 -o - "$record_found" 2>/dev/null \
338+
| grep -iA1 OrganizationName | tail -1 | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
339+
[ -n "$org" ] && info "This device is assigned in Apple Business Manager to: $org"
340+
[ -n "$mdm_host" ] && info "Org MDM server host: $mdm_host (will also be blocked)"
341+
else
342+
info "No activation record currently present."
352343
fi
344+
echo ""
353345

354-
# Check if entries already exist to avoid duplicates
355-
grep -q "deviceenrollment.apple.com" "$hosts_file" 2>/dev/null || echo "0.0.0.0 deviceenrollment.apple.com" >>"$hosts_file"
356-
grep -q "mdmenrollment.apple.com" "$hosts_file" 2>/dev/null || echo "0.0.0.0 mdmenrollment.apple.com" >>"$hosts_file"
357-
grep -q "iprofiles.apple.com" "$hosts_file" 2>/dev/null || echo "0.0.0.0 iprofiles.apple.com" >>"$hosts_file"
358-
359-
success "MDM domains blocked in hosts file"
346+
# --- Block the DEP / enrollment domains on the DATA volume's hosts file ---
347+
step "Blocking DEP enrollment domains (Data-volume hosts file)"
348+
[ -f "$hosts_file" ] || { mkdir -p "$(dirname "$hosts_file")"; touch "$hosts_file"; }
349+
# iprofiles.apple.com = the device-side activation-record fetch (THE essential one).
350+
# device/mdm-enrollment = server-side DEP API (harmless to include).
351+
# acmdm = Apple cert/MDM endpoint. We deliberately DO NOT block:
352+
# gdmf.apple.com (breaks Software Update) or albert.apple.com (breaks iMessage/FaceTime).
353+
block_domains=(iprofiles.apple.com deviceenrollment.apple.com mdmenrollment.apple.com acmdm.apple.com)
354+
[ -n "$mdm_host" ] && block_domains+=("$mdm_host")
355+
grep -q "Added by bypass-mdm" "$hosts_file" 2>/dev/null || {
356+
echo "" >>"$hosts_file"
357+
echo "# Added by bypass-mdm — DEP enrollment block" >>"$hosts_file"
358+
}
359+
for d in "${block_domains[@]}"; do
360+
grep -qiE "[[:space:]]$d(\$|[[:space:]])" "$hosts_file" 2>/dev/null && { info "$d already blocked"; continue; }
361+
printf '0.0.0.0 %s\n:: %s\n' "$d" "$d" >>"$hosts_file"
362+
success "blocked $d"
363+
done
360364
echo ""
361365

362366
# Remove configuration profiles
@@ -384,6 +388,23 @@ select opt in "${options[@]}"; do
384388
touch "$config_path/.cloudConfigProfileInstalled" 2>/dev/null && success "Created profile installed marker" || warn "Could not create profile marker"
385389
touch "$config_path/.cloudConfigRecordNotFound" 2>/dev/null && success "Created record not found marker" || warn "Could not create not found marker"
386390

391+
# Disable the enrollment daemon via a launchd override (durable: lives on
392+
# the Data volume, so it survives the System-volume reseal a macOS update
393+
# performs). macOS 26 moved this work to com.apple.ManagedClient.enroll.
394+
info "Disabling the enrollment daemon (durable override on Data volume)..."
395+
launchd_disabled="$data_path/private/var/db/com.apple.xpc.launchd/disabled.plist"
396+
mkdir -p "$(dirname "$launchd_disabled")" 2>/dev/null
397+
[ -f "$launchd_disabled" ] || printf '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0"><dict/></plist>\n' >"$launchd_disabled"
398+
for label in com.apple.ManagedClient.enroll com.apple.mdmclient.daemon.runatboot; do
399+
"$PB" -c "Add :$label bool true" "$launchd_disabled" 2>/dev/null \
400+
|| "$PB" -c "Set :$label true" "$launchd_disabled" 2>/dev/null
401+
done
402+
if [ -f "$launchd_disabled" ]; then
403+
success "Enrollment daemon disabled via $launchd_disabled"
404+
else
405+
warn "Could not write launchd override (daemon not disabled)"
406+
fi
407+
387408
echo ""
388409
echo -e "${GRN}╔═══════════════════════════════════════════════╗${NC}"
389410
echo -e "${GRN}║ MDM Bypass Completed Successfully! ║${NC}"

0 commit comments

Comments
 (0)