// // Patcher.swift // WeChatTweak // // Created by Sunny Young on 2025/12/4. // import Darwin import MachO import Foundation struct Patcher { enum Error: Swift.Error { case invalidFile case not64BitMachO(magic: UInt32) case vaNotFound(arch: String, va: UInt64) case noArchMatched } static func patch(binary: URL, config: Config) throws { guard FileManager.default.fileExists(atPath: binary.path) else { throw Error.invalidFile } let entries = config.targets.flatMap { $0.entries } guard !entries.isEmpty else { throw Error.noArchMatched } let fh = try FileHandle(forUpdating: binary) defer { try? fh.close() } // 读 magic 判断 fat / thin guard let magicData = try fh.read(upToCount: 4), magicData.count == 4 else { throw Error.invalidFile } let magicBE = magicData.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian } let isSwappedFat = (magicBE == FAT_CIGAM) var patchedCount = 0 if magicBE == FAT_MAGIC || magicBE == FAT_CIGAM { // FAT header: magic(4) + nfat_arch(4) guard let nfatData = try fh.read(upToCount: 4), nfatData.count == 4 else { throw Error.invalidFile } let rawNfat = nfatData.withUnsafeBytes { $0.load(as: UInt32.self) } let nfat = isSwappedFat ? UInt32(littleEndian: rawNfat) : UInt32(bigEndian: rawNfat) // 先读完 fat_arch 表,避免 patch 时移动文件指针影响后续读取 var archEntries: [(cputype: UInt32, offset: UInt32)] = [] for _ in 0..