From 3533675b318b24daaf8306c67df7d56e1e17d01d Mon Sep 17 00:00:00 2001 From: p-x9 <50244599+p-x9@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:50:56 +0900 Subject: [PATCH 1/5] Add `uuid` to `PrebuiltLoader` --- Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift index 3f0742a..7a448bc 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift @@ -24,6 +24,10 @@ extension PrebuiltLoader { public var ref: LoaderRef { .init(layout: layout.loader.ref) } + + public var uuid: UUID { + .init(uuid: layout.loader.uuid) + } } extension PrebuiltLoader { From c5747fccb6d917a762837901d4d8678307b3b178 Mon Sep 17 00:00:00 2001 From: p-x9 <50244599+p-x9@users.noreply.github.com> Date: Sun, 10 Nov 2024 05:00:21 +0900 Subject: [PATCH 2/5] Add method to get alternative path for target mach-o image --- .../DyldCache/Loader/PrebuiltLoader.swift | 21 +++++++++++++++++++ .../Loader/PrebuiltLoaderProtocol.swift | 8 +++++++ .../Loader/PrebuiltLoader_Pre1165_3.swift | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift index 7a448bc..374522d 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift @@ -38,6 +38,14 @@ extension PrebuiltLoader { return cache.fileHandle.readString(offset: offset) } + public func altPath(in cache: DyldCache) -> String? { + guard layout.altPathOffset != 0 else { return nil } + guard let offset = cache.fileOffset( + of: numericCast(address) + numericCast(layout.altPathOffset) + ) else { return nil } + return cache.fileHandle.readString(offset: offset) + } + public func dependentLoaderRefs(in cache: DyldCache) -> DataSequence? { guard layout.dependentLoaderRefsArrayOffset != 0, let offset = cache.fileOffset( @@ -65,6 +73,19 @@ extension PrebuiltLoader { ) } + public func altPath(in cache: DyldCacheLoaded) -> String? { + // swiftlint:disable:previous unused_parameter + guard layout.altPathOffset != 0 else { return nil } + guard let baseAddress = UnsafeRawPointer(bitPattern: address) else { + return nil + } + return String( + cString: baseAddress + .advanced(by: numericCast(layout.altPathOffset)) + .assumingMemoryBound(to: CChar.self) + ) + } + public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence? { // swiftlint:disable:previous unused_parameter guard layout.dependentLoaderRefsArrayOffset != 0, diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift index 0f736d9..d58b866 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift @@ -25,6 +25,10 @@ public protocol PrebuiltLoaderProtocol { /// - Parameter cache: DyldCache to which `self` belongs /// - Returns: path name func path(in cache: DyldCache) -> String? + /// alternative path for target mach-o image if install_name does not match real path + /// - Parameter cache: DyldCache to which `self` belongs + /// - Returns: path name + func altPath(in cache: DyldCache) -> String? /// loader reference list of target 's dependencies /// - Parameter cache: DyldCache to which `self` belongs /// - Returns: sequence of loader reference @@ -34,6 +38,10 @@ public protocol PrebuiltLoaderProtocol { /// - Parameter cache: DyldCacheLoaded to which `self` belongs /// - Returns: path name func path(in cache: DyldCacheLoaded) -> String? + /// alternative path for target mach-o image if install_name does not match real path + /// - Parameter cache: DyldCacheLoaded to which `self` belongs + /// - Returns: path name + func altPath(in cache: DyldCacheLoaded) -> String? /// loader reference list of target 's dependencies /// - Parameter cache: DyldCacheLoaded to which `self` belongs /// - Returns: sequence of loader reference diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift index 3fb6a8e..d0aa8f1 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift @@ -32,6 +32,14 @@ extension PrebuiltLoader_Pre1165_3 { return cache.fileHandle.readString(offset: offset) } + public func altPath(in cache: DyldCache) -> String? { + guard layout.altPathOffset != 0 else { return nil } + guard let offset = cache.fileOffset( + of: numericCast(address) + numericCast(layout.altPathOffset) + ) else { return nil } + return cache.fileHandle.readString(offset: offset) + } + public func dependentLoaderRefs(in cache: DyldCache) -> DataSequence? { guard layout.dependentLoaderRefsArrayOffset != 0, let offset = cache.fileOffset( @@ -59,6 +67,19 @@ extension PrebuiltLoader_Pre1165_3 { ) } + public func altPath(in cache: DyldCacheLoaded) -> String? { + // swiftlint:disable:previous unused_parameter + guard layout.altPathOffset != 0 else { return nil } + guard let baseAddress = UnsafeRawPointer(bitPattern: address) else { + return nil + } + return String( + cString: baseAddress + .advanced(by: numericCast(layout.altPathOffset)) + .assumingMemoryBound(to: CChar.self) + ) + } + public func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence? { // swiftlint:disable:previous unused_parameter guard layout.dependentLoaderRefsArrayOffset != 0, From 69e31886842cf7c3c1ee01f96addebe9a1097b5e Mon Sep 17 00:00:00 2001 From: p-x9 <50244599+p-x9@users.noreply.github.com> Date: Sat, 16 Nov 2024 00:29:08 +0900 Subject: [PATCH 3/5] Implemented `SectionLocations` --- .../DyldCache/Loader/PrebuiltLoader.swift | 4 + .../Loader/PrebuiltLoader_Pre1165_3.swift | 4 + .../DyldCache/Loader/SectionLocations.swift | 77 +++++++++++++++++++ Sources/MachOKitC/include/dyld_cache_loader.h | 2 +- 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 Sources/MachOKit/Model/DyldCache/Loader/SectionLocations.swift diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift index 374522d..53080a2 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift @@ -28,6 +28,10 @@ extension PrebuiltLoader { public var uuid: UUID { .init(uuid: layout.loader.uuid) } + + public var sectionLocations: SectionLocations { + .init(layout: layout.sectionLocations) + } } extension PrebuiltLoader { diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift index d0aa8f1..7e15724 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift @@ -22,6 +22,10 @@ extension PrebuiltLoader_Pre1165_3 { public var ref: LoaderRef { .init(layout: layout.loader.ref) } + + public var sectionLocations: SectionLocations { + .init(layout: layout.sectionLocations) + } } extension PrebuiltLoader_Pre1165_3 { diff --git a/Sources/MachOKit/Model/DyldCache/Loader/SectionLocations.swift b/Sources/MachOKit/Model/DyldCache/Loader/SectionLocations.swift new file mode 100644 index 0000000..de924b7 --- /dev/null +++ b/Sources/MachOKit/Model/DyldCache/Loader/SectionLocations.swift @@ -0,0 +1,77 @@ +// +// SectionLocations.swift +// MachOKit +// +// Created by p-x9 on 2024/11/16 +// +// + +import Foundation + +public struct SectionLocations: LayoutWrapper { + public typealias Layout = section_locations + + public var layout: Layout +} + +extension SectionLocations { + // [dyld implementation](https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/include/mach-o/dyld_priv.h#L62) + public enum SectionKind: Int, CaseIterable { + // TEXT: + case text_swift5_protos + case text_swift5_proto + case text_swift5_types + case text_swift5_replace + case text_swift5_replace2 + case text_swift5_ac_funcs + + // DATA*: + case objc_image_info + case data_sel_refs + case data_msg_refs + case data_class_refs + case data_super_refs + case data_protocol_refs + case data_class_list + case data_non_lazy_class_list + case data_stub_list + case data_category_list + case data_category_list2 + case data_non_lazy_category_list + case data_protocol_list + case data_objc_fork_ok + case data_raw_isa + + // ~~ version 1 ~~ + } +} + +extension SectionLocations { + public struct Section { + public let offset: Int + public let size: Int + public let kind: SectionKind + } +} + +extension SectionLocations { + public func section(for kind: SectionKind) -> Section { + var offsets = layout.offsets + var sizes = layout.sizes + let offset = withUnsafePointer(to: &offsets) { + UnsafeRawPointer($0) + .assumingMemoryBound(to: UInt64.self) + .advanced(by: kind.rawValue).pointee + } + let size = withUnsafePointer(to: &sizes) { + UnsafeRawPointer($0) + .assumingMemoryBound(to: UInt64.self) + .advanced(by: kind.rawValue).pointee + } + return .init( + offset: numericCast(offset), + size: numericCast(size), + kind: kind + ) + } +} diff --git a/Sources/MachOKitC/include/dyld_cache_loader.h b/Sources/MachOKitC/include/dyld_cache_loader.h index 280012f..e0909dd 100644 --- a/Sources/MachOKitC/include/dyld_cache_loader.h +++ b/Sources/MachOKitC/include/dyld_cache_loader.h @@ -175,7 +175,7 @@ struct prebuilt_loader { uint32_t overrideBindTargetRefsOffset; uint32_t overrideBindTargetRefsCount; - // struct section_locations sectionLocations; + struct section_locations sectionLocations; }; #endif /* dyld_cache_loader_h */ From d8bbe8260d1eecf4a42f4e7a2f4c15f35b6b0d45 Mon Sep 17 00:00:00 2001 From: p-x9 <50244599+p-x9@users.noreply.github.com> Date: Sat, 16 Nov 2024 01:08:13 +0900 Subject: [PATCH 4/5] Add some properties --- .../MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift | 8 ++++++++ .../Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift | 8 +++++++- .../Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift index 53080a2..1803b7c 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift @@ -21,6 +21,14 @@ extension PrebuiltLoader { layout.loader.isPrebuilt != 0 } + public var neverUnload: Bool { + layout.loader.neverUnload != 0 + } + + public var isPremapped: Bool { + layout.loader.isPremapped != 0 + } + public var ref: LoaderRef { .init(layout: layout.loader.ref) } diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift index d58b866..b15e55d 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift @@ -17,10 +17,16 @@ public protocol PrebuiltLoaderProtocol { /// magic of loader starts var magic: String? { get } - /// PrebuiltLoader vs JustInTimeLoader + /// PrebuiltLoader vs JustInTimeLoader var isPrebuilt: Bool { get } + var neverUnload: Bool { get } + var isPremapped: Bool { get } + var ref: LoaderRef { get } + // Information for all pre-calculated sections that we know about + var sectionLocations: SectionLocations { get } + /// path for target mach-o image /// - Parameter cache: DyldCache to which `self` belongs /// - Returns: path name diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift index 7e15724..69837c2 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift @@ -19,6 +19,14 @@ extension PrebuiltLoader_Pre1165_3 { layout.loader.isPrebuilt != 0 } + public var neverUnload: Bool { + layout.loader.neverUnload != 0 + } + + public var isPremapped: Bool { + layout.loader.isPremapped != 0 + } + public var ref: LoaderRef { .init(layout: layout.loader.ref) } From c6e1c7983ff1c53cc5469c95b1c8b7fb42b908b2 Mon Sep 17 00:00:00 2001 From: p-x9 <50244599+p-x9@users.noreply.github.com> Date: Sat, 16 Nov 2024 02:47:18 +0900 Subject: [PATCH 5/5] Support `ObjCBinaryInfo` --- .../DyldCache/Loader/ObjCBinaryInfo.swift | 15 ++++++ .../DyldCache/Loader/PrebuiltLoader.swift | 20 ++++++++ .../Loader/PrebuiltLoaderProtocol.swift | 8 +++ .../Loader/PrebuiltLoader_Pre1165_3.swift | 20 ++++++++ Sources/MachOKitC/include/dyld_cache_loader.h | 49 +++++++++++++++++++ 5 files changed, 112 insertions(+) create mode 100644 Sources/MachOKit/Model/DyldCache/Loader/ObjCBinaryInfo.swift diff --git a/Sources/MachOKit/Model/DyldCache/Loader/ObjCBinaryInfo.swift b/Sources/MachOKit/Model/DyldCache/Loader/ObjCBinaryInfo.swift new file mode 100644 index 0000000..73b04c6 --- /dev/null +++ b/Sources/MachOKit/Model/DyldCache/Loader/ObjCBinaryInfo.swift @@ -0,0 +1,15 @@ +// +// ObjCBinaryInfo.swift +// MachOKit +// +// Created by p-x9 on 2024/11/16 +// +// + +import Foundation + +public struct ObjCBinaryInfo: LayoutWrapper { + public typealias Layout = objc_binary_info + + public var layout: Layout +} diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift index 1803b7c..6228d09 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader.swift @@ -70,6 +70,14 @@ extension PrebuiltLoader { numberOfElements: numericCast(layout.depCount) ) } + + public func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo? { + guard layout.objcBinaryInfoOffset != 0 else { return nil } + guard let offset = cache.fileOffset( + of: numericCast(address) + numericCast(layout.objcBinaryInfoOffset) + ) else { return nil } + return cache.fileHandle.read(offset: offset) + } } extension PrebuiltLoader { @@ -111,6 +119,18 @@ extension PrebuiltLoader { numberOfElements: numericCast(layout.depCount) ) } + + public func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo? { + // swiftlint:disable:previous unused_parameter + guard layout.objcBinaryInfoOffset != 0, + let baseAddress = UnsafeRawPointer(bitPattern: address) else { + return nil + } + return baseAddress + .advanced(by: numericCast(layout.objcBinaryInfoOffset)) + .assumingMemoryBound(to: ObjCBinaryInfo.self) + .pointee + } } extension PrebuiltLoader { diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift index b15e55d..aaef887 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoaderProtocol.swift @@ -39,6 +39,10 @@ public protocol PrebuiltLoaderProtocol { /// - Parameter cache: DyldCache to which `self` belongs /// - Returns: sequence of loader reference func dependentLoaderRefs(in cache: DyldCache) -> DataSequence? + /// Stores information about the layout of the objc sections in a binary + /// - Parameter cache: DyldCache to which `self` belongs + /// - Returns: binary info for objc + func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo? /// path for target mach-o image /// - Parameter cache: DyldCacheLoaded to which `self` belongs @@ -52,4 +56,8 @@ public protocol PrebuiltLoaderProtocol { /// - Parameter cache: DyldCacheLoaded to which `self` belongs /// - Returns: sequence of loader reference func dependentLoaderRefs(in cache: DyldCacheLoaded) -> MemorySequence? + /// Stores information about the layout of the objc sections in a binary + /// - Parameter cache: DyldCacheLoaded to which `self` belongs + /// - Returns: binary info for objc + func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo? } diff --git a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift index 69837c2..be2b40f 100644 --- a/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift +++ b/Sources/MachOKit/Model/DyldCache/Loader/PrebuiltLoader_Pre1165_3.swift @@ -64,6 +64,14 @@ extension PrebuiltLoader_Pre1165_3 { numberOfElements: numericCast(layout.depCount) ) } + + public func objcBinaryInfo(in cache: DyldCache) -> ObjCBinaryInfo? { + guard layout.objcBinaryInfoOffset != 0 else { return nil } + guard let offset = cache.fileOffset( + of: numericCast(address) + numericCast(layout.objcBinaryInfoOffset) + ) else { return nil } + return cache.fileHandle.read(offset: offset) + } } extension PrebuiltLoader_Pre1165_3 { @@ -105,6 +113,18 @@ extension PrebuiltLoader_Pre1165_3 { numberOfElements: numericCast(layout.depCount) ) } + + public func objcBinaryInfo(in cache: DyldCacheLoaded) -> ObjCBinaryInfo? { + // swiftlint:disable:previous unused_parameter + guard layout.objcBinaryInfoOffset != 0, + let baseAddress = UnsafeRawPointer(bitPattern: address) else { + return nil + } + return baseAddress + .advanced(by: numericCast(layout.objcBinaryInfoOffset)) + .assumingMemoryBound(to: ObjCBinaryInfo.self) + .pointee + } } extension PrebuiltLoader_Pre1165_3 { diff --git a/Sources/MachOKitC/include/dyld_cache_loader.h b/Sources/MachOKitC/include/dyld_cache_loader.h index e0909dd..72dd371 100644 --- a/Sources/MachOKitC/include/dyld_cache_loader.h +++ b/Sources/MachOKitC/include/dyld_cache_loader.h @@ -9,6 +9,7 @@ #ifndef dyld_cache_loader_h #define dyld_cache_loader_h +#include // https://github.com/apple-oss-distributions/dyld/blob/d552c40cd1de105f0ec95008e0e0c0972de43456/dyld/PrebuiltLoader.h#L254 struct prebuilt_loader_set { uint32_t magic; @@ -178,4 +179,52 @@ struct prebuilt_loader { struct section_locations sectionLocations; }; +// https://github.com/apple-oss-distributions/dyld/blob/65bbeed63cec73f313b1d636e63f243964725a9d/dyld/PrebuiltLoader.h#L344 +// Stores information about the layout of the objc sections in a binary, as well as other properties relating to +// the objc information in there. +struct objc_binary_info { + // Offset to the __objc_imageinfo section + uint64_t imageInfoRuntimeOffset; + + // Offsets to sections containing objc pointers + uint64_t selRefsRuntimeOffset; + uint64_t classListRuntimeOffset; + uint64_t categoryListRuntimeOffset; + uint64_t protocolListRuntimeOffset; + + // Counts of the above sections. + uint32_t selRefsCount; + uint32_t classListCount; + uint32_t categoryCount; + uint32_t protocolListCount; + + // Do we have stable Swift fixups to apply to at least one class? + bool hasClassStableSwiftFixups; + + // Do we have any pointer-based method lists to set as uniqued? + bool hasClassMethodListsToSetUniqued; + bool hasCategoryMethodListsToSetUniqued; + bool hasProtocolMethodListsToSetUniqued; + + // Do we have any method lists in which to set selector references. + // Note we only support visiting selector refernces in pointer based method lists + // Relative method lists should have been verified to always point to __objc_selrefs + bool hasClassMethodListsToUnique; + bool hasCategoryMethodListsToUnique; + bool hasProtocolMethodListsToUnique; + + // Whwn serialized to the PrebuildLoader, these fields will encode other information about + // the binary. + + // Offset to an array of uint8_t's. One for each protocol. + // Note this can be 0 (ie, have no fixups), even if we have protocols. That would be the case + // if this binary contains no canonical protocol definitions, ie, all canonical defs are in other binaries + // or the shared cache. + uint32_t protocolFixupsOffset; + // Offset to an array of BindTargetRef's. One for each selector reference to fix up + // Note we only fix up selector refs in the __objc_selrefs section, and in pointer-based method lists + uint32_t selectorReferencesFixupsOffset; + uint32_t selectorReferencesFixupsCount; +}; + #endif /* dyld_cache_loader_h */