diff --git a/Sources/MachOKit/DyldCache.swift b/Sources/MachOKit/DyldCache.swift index 68a455c..13828b7 100644 --- a/Sources/MachOKit/DyldCache.swift +++ b/Sources/MachOKit/DyldCache.swift @@ -454,4 +454,88 @@ extension DyldCache { return runtimeOffset + onDiskDylibChainedPointerBaseAddress } + + // https://github.com/apple-oss-distributions/dyld/blob/a571176e8e00c47e95b95e3156820ebec0cbd5e6/common/MetadataVisitor.cpp#L424 + public func resolveOptionalRebase(at offset: UInt64) -> UInt64? { + guard let mappingInfos, + let unslidLoadAddress = mappingInfos.first?.address else { + return nil + } + guard let mapping = mappingAndSlideInfo(forFileOffset: offset) else { + return nil + } + guard let slideInfo = mapping.slideInfo(in: self) else { + let version = mapping.slideInfoVersion(in: self) ?? .none + if version == .none { + if cpu.is64Bit { + let value: UInt64 = fileHandle.read(offset: offset) + guard value != 0 else { return nil } + return value + } else { + let value: UInt32 = fileHandle.read(offset: offset) + guard value != 0 else { return nil } + return numericCast(value) + } + } else { + + } + return nil + } + + let runtimeOffset: UInt64 + let onDiskDylibChainedPointerBaseAddress: UInt64 + switch slideInfo { + case .v1: + let value: UInt32 = fileHandle.read(offset: offset) + guard value != 0 else { return nil } + runtimeOffset = numericCast(value) - unslidLoadAddress + onDiskDylibChainedPointerBaseAddress = unslidLoadAddress + + case let .v2(slideInfo): + let rawValue: UInt64 = fileHandle.read(offset: offset) + guard rawValue != 0 else { return nil } + let deltaMask: UInt64 = 0x00FFFF0000000000 + let valueMask: UInt64 = ~deltaMask + runtimeOffset = rawValue & valueMask + onDiskDylibChainedPointerBaseAddress = slideInfo.value_add + + case .v3: + let rawValue: UInt64 = fileHandle.read(offset: offset) + guard rawValue != 0 else { return nil } + let _fixup = DyldChainedFixupPointerInfo.ARM64E(rawValue: rawValue) + let fixup: DyldChainedFixupPointerInfo = .arm64e(_fixup) + let pointer: DyldChainedFixupPointer = .init( + offset: Int(offset), + fixupInfo: fixup + ) + guard let _runtimeOffset = pointer.rebaseTargetRuntimeOffset( + preferedLoadAddress: unslidLoadAddress + ) else { return nil } + runtimeOffset = _runtimeOffset + onDiskDylibChainedPointerBaseAddress = unslidLoadAddress + + case let .v4(slideInfo): + let rawValue: UInt32 = fileHandle.read(offset: offset) + guard rawValue != 0 else { return nil } + let deltaMask: UInt64 = 0x00000000C0000000 + let valueMask: UInt64 = ~deltaMask + runtimeOffset = numericCast(rawValue) & valueMask + onDiskDylibChainedPointerBaseAddress = slideInfo.value_add + + case let .v5(slideInfo): + let rawValue: UInt64 = fileHandle.read(offset: offset) + guard rawValue != 0 else { return nil } + let _fixup = DyldChainedFixupPointerInfo.ARM64ESharedCache( + rawValue: rawValue + ) + let fixup: DyldChainedFixupPointerInfo = .arm64e_shared_cache(_fixup) + guard let rebase = fixup.rebase else { + return nil + } + runtimeOffset = numericCast(rebase.unpackedTarget) + onDiskDylibChainedPointerBaseAddress = slideInfo.value_add + } + + return runtimeOffset + onDiskDylibChainedPointerBaseAddress + } } diff --git a/Sources/MachOKit/MachOFile.swift b/Sources/MachOKit/MachOFile.swift index 90bf054..223a016 100644 --- a/Sources/MachOKit/MachOFile.swift +++ b/Sources/MachOKit/MachOFile.swift @@ -485,6 +485,45 @@ extension MachOFile { return nil } + public func resolveOptionalRebase(at offset: UInt64) -> UInt64? { + if isLoadedFromDyldCache, + let cache = try? DyldCache(url: url) { + return cache.resolveOptionalRebase(at: offset) + } + + guard let chainedFixup = dyldChainedFixups, + let startsInImage = chainedFixup.startsInImage else { + return nil + } + let startsInSegments = chainedFixup.startsInSegments( + of: startsInImage + ) + + for segment in startsInSegments { + let pointers = chainedFixup.pointers(of: segment, in: self) + guard let pointer = pointers.first(where: { + $0.offset == offset + }) else { continue } + guard pointer.fixupInfo.rebase != nil, + let offset = pointer.rebaseTargetRuntimeOffset(for: self) else { + return nil + } + if is64Bit { + let value: UInt64 = fileHandle.read( + offset: numericCast(headerStartOffset + pointer.offset) + ) + if value == 0 { return nil } + } else { + let value: UInt32 = fileHandle.read( + offset: numericCast(headerStartOffset + pointer.offset) + ) + if value == 0 { return nil } + } + return offset + } + return nil + } + public func resolveBind( at offset: UInt64 ) -> (DyldChainedImport, addend: UInt64)? {