Skip to content

Commit

Permalink
Merge pull request #117 from p-x9/feature/resolve-optional-rebase
Browse files Browse the repository at this point in the history
Resolve optional rebase in dyld shared cache or mach-o file
  • Loading branch information
p-x9 authored Sep 6, 2024
2 parents 97a95b3 + be69d03 commit 4632684
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
84 changes: 84 additions & 0 deletions Sources/MachOKit/DyldCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
39 changes: 39 additions & 0 deletions Sources/MachOKit/MachOFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)? {
Expand Down

0 comments on commit 4632684

Please sign in to comment.