3
3
// MachOObjCSection
4
4
//
5
5
// Created by p-x9 on 2024/12/06
6
- //
6
+ //
7
7
//
8
8
9
9
import Foundation
@@ -24,8 +24,8 @@ public protocol ObjCCategoryProtocol: _FixupResolvable where LayoutField == ObjC
24
24
init ( layout: Layout , offset: Int , isCatlist2: Bool )
25
25
26
26
func name( in machO: MachOFile ) -> String ?
27
- func `class`( in machO: MachOFile ) -> ObjCClass ?
28
- func stubClass( in machO: MachOFile ) -> ObjCStubClass ?
27
+ func `class`( in machO: MachOFile ) -> ( MachOFile , ObjCClass ) ?
28
+ func stubClass( in machO: MachOFile ) -> ( MachOFile , ObjCStubClass ) ?
29
29
func className( in machO: MachOFile ) -> String ?
30
30
func instanceMethodList( in machO: MachOFile ) -> ObjCMethodList ?
31
31
func classMethodList( in machO: MachOFile ) -> ObjCMethodList ?
@@ -34,8 +34,8 @@ public protocol ObjCCategoryProtocol: _FixupResolvable where LayoutField == ObjC
34
34
func protocolList( in machO: MachOFile ) -> ObjCProtocolList ?
35
35
36
36
func name( in machO: MachOImage ) -> String ?
37
- func `class`( in machO: MachOImage ) -> ObjCClass ?
38
- func stubClass( in machO: MachOImage ) -> ObjCStubClass ?
37
+ func `class`( in machO: MachOImage ) -> ( MachOImage , ObjCClass ) ?
38
+ func stubClass( in machO: MachOImage ) -> ( MachOImage , ObjCStubClass ) ?
39
39
func className( in machO: MachOImage ) -> String ?
40
40
func instanceMethodList( in machO: MachOImage ) -> ObjCMethodList ?
41
41
func classMethodList( in machO: MachOImage ) -> ObjCMethodList ?
@@ -58,27 +58,28 @@ extension ObjCCategoryProtocol {
58
58
return machO. fileHandle. readString ( offset: numericCast ( offset) )
59
59
}
60
60
61
- public func `class`( in machO: MachOFile ) -> ObjCClass ? {
62
- guard let cls = _readClass (
61
+ public func `class`( in machO: MachOFile ) -> ( MachOFile , ObjCClass ) ? {
62
+ guard let ( machO , cls) = _readClass (
63
63
at: numericCast ( layout. cls) ,
64
64
field: . cls,
65
65
in: machO
66
66
) else { return nil }
67
67
68
68
if cls. isStubClass { return nil }
69
69
70
- return cls
70
+ return ( machO , cls)
71
71
}
72
- public func stubClass( in machO: MachOFile ) -> ObjCStubClass ? {
73
- guard let cls = _readStubClass (
72
+
73
+ public func stubClass( in machO: MachOFile ) -> ( MachOFile , ObjCStubClass ) ? {
74
+ guard let ( machO, cls) = _readStubClass (
74
75
at: numericCast ( layout. cls) ,
75
76
field: . cls,
76
77
in: machO
77
78
) else { return nil }
78
79
79
80
guard cls. isStubClass else { return nil }
80
81
81
- return cls
82
+ return ( machO , cls)
82
83
}
83
84
84
85
public func className( in machO: MachOFile ) -> String ? {
@@ -163,38 +164,58 @@ extension ObjCCategoryProtocol {
163
164
)
164
165
}
165
166
166
- public func `class`( in machO: MachOImage ) -> ObjCClass ? {
167
+ public func `class`( in machO: MachOImage ) -> ( MachOImage , ObjCClass ) ? {
167
168
guard layout. cls > 0 else { return nil }
168
169
guard let ptr = UnsafeRawPointer ( bitPattern: UInt ( layout. cls) ) else {
169
170
return nil
170
171
}
171
- let offset : Int = numericCast ( layout. cls) - Int( bitPattern: machO. ptr)
172
+
173
+ var targetMachO = machO
174
+ if !targetMachO. contains ( ptr: ptr) {
175
+ guard let cache = DyldCacheLoaded . current,
176
+ let _targetMachO = cache. machO ( containing: ptr) else {
177
+ return nil
178
+ }
179
+ targetMachO = _targetMachO
180
+ }
181
+
182
+ let offset : Int = numericCast ( layout. cls) - Int( bitPattern: targetMachO. ptr)
172
183
173
184
let layout = ptr. assumingMemoryBound ( to: ObjCClass . Layout. self) . pointee
174
185
let cls : ObjCClass = . init( layout: layout, offset: offset)
175
186
176
187
if cls. isStubClass { return nil }
177
188
178
- return cls
189
+ return ( targetMachO , cls)
179
190
}
180
191
181
- public func stubClass( in machO: MachOImage ) -> ObjCStubClass ? {
192
+ public func stubClass( in machO: MachOImage ) -> ( MachOImage , ObjCStubClass ) ? {
182
193
guard layout. cls > 0 else { return nil }
183
194
guard let ptr = UnsafeRawPointer ( bitPattern: UInt ( layout. cls) ) else {
184
195
return nil
185
196
}
186
- let offset : Int = numericCast ( layout. cls) - Int( bitPattern: machO. ptr)
197
+
198
+ var targetMachO = machO
199
+ if !targetMachO. contains ( ptr: ptr) {
200
+ guard let cache = DyldCacheLoaded . current,
201
+ let _targetMachO = cache. machO ( containing: ptr) else {
202
+ return nil
203
+ }
204
+ targetMachO = _targetMachO
205
+ }
206
+
207
+ let offset : Int = numericCast ( layout. cls) - Int( bitPattern: targetMachO. ptr)
187
208
188
209
let layout = ptr. assumingMemoryBound ( to: ObjCStubClass . Layout. self) . pointee
189
210
let cls : ObjCStubClass = . init( layout: layout, offset: offset)
190
211
191
212
guard cls. isStubClass else { return nil }
192
213
193
- return cls
214
+ return ( targetMachO , cls)
194
215
}
195
216
196
217
public func className( in machO: MachOImage ) -> String ? {
197
- guard let cls = `class` ( in: machO) else {
218
+ guard let ( machO , cls) = `class` ( in: machO) else {
198
219
if let section = machO. sectionNumber ( for: . __objc_const) ,
199
220
let symbol = machO. symbol (
200
221
for: offset, inSection: section
@@ -261,12 +282,50 @@ extension ObjCCategoryProtocol {
261
282
}
262
283
}
263
284
285
+ extension ObjCCategoryProtocol {
286
+ @available ( * , deprecated, renamed: " class(in:) " , message: " Use `class(in:)` that returns machO that contains class " )
287
+ public func `class`( in machO: MachOFile ) -> ObjCClass ? {
288
+ guard let ( _, cls) = self . class ( in: machO) else {
289
+ return nil
290
+ }
291
+ return cls
292
+ }
293
+
294
+ @available ( * , deprecated, renamed: " stubClass(in:) " , message: " Use `stubCclass(in:)` that returns machO that contains class " )
295
+ public func stubClass( in machO: MachOFile ) -> ObjCStubClass ? {
296
+ guard let ( _, cls) = self . stubClass ( in: machO) else {
297
+ return nil
298
+ }
299
+ return cls
300
+ }
301
+
302
+ @available ( * , deprecated, renamed: " class(in:) " , message: " Use `class(in:)` that returns machO that contains class " )
303
+ func `class`( in machO: MachOImage ) -> ObjCClass ? {
304
+ guard let ( targetMachO, cls) = self . class ( in: machO) else { return nil }
305
+ let diff = Int ( bitPattern: targetMachO. ptr) - Int( bitPattern: machO. ptr)
306
+ return . init(
307
+ layout: cls. layout,
308
+ offset: cls. offset + diff
309
+ )
310
+ }
311
+
312
+ @available ( * , deprecated, renamed: " stubClass(in:) " , message: " Use `stubCclass(in:)` that returns machO that contains class " )
313
+ func stubClass( in machO: MachOImage ) -> ObjCStubClass ? {
314
+ guard let ( targetMachO, cls) = self . stubClass ( in: machO) else { return nil }
315
+ let diff = Int ( bitPattern: targetMachO. ptr) - Int( bitPattern: machO. ptr)
316
+ return . init(
317
+ layout: cls. layout,
318
+ offset: cls. offset + diff
319
+ )
320
+ }
321
+ }
322
+
264
323
extension ObjCCategoryProtocol {
265
324
private func _readClass(
266
325
at offset: UInt64 ,
267
326
field: LayoutField ,
268
327
in machO: MachOFile
269
- ) -> ObjCClass ? {
328
+ ) -> ( MachOFile , ObjCClass ) ? {
270
329
guard offset > 0 else { return nil }
271
330
var offset : UInt64 = machO. fileOffset (
272
331
of: numericCast ( offset)
@@ -277,50 +336,69 @@ extension ObjCCategoryProtocol {
277
336
}
278
337
if isBind ( field, in: machO) { return nil }
279
338
339
+ var targetMachO = machO
340
+
341
+ var fileHandle = machO. fileHandle
280
342
var resolvedOffset = offset
281
- if let cache = machO. cache {
282
- guard let _offset = cache. fileOffset ( of: offset + cache. mainCacheHeader. sharedRegionStart) else {
283
- return nil
284
- }
343
+ if let ( _cache, _offset) = machO. cacheAndFileOffset (
344
+ fromStart: offset
345
+ ) {
285
346
resolvedOffset = _offset
347
+ fileHandle = _cache. fileHandle
348
+
349
+ let unslidAddress = offset + _cache. mainCacheHeader. sharedRegionStart
350
+ if !targetMachO. contains ( unslidAddress: unslidAddress) ,
351
+ let machO = _cache. machO ( containing: unslidAddress) {
352
+ targetMachO = machO
353
+ }
286
354
}
287
355
288
- let layout : ObjCClass . Layout = machO . fileHandle. read ( offset: resolvedOffset)
289
- return . init(
356
+ let layout : ObjCClass . Layout = fileHandle. read ( offset: resolvedOffset)
357
+ let cls : ObjCClass = . init(
290
358
layout: layout,
291
359
offset: numericCast ( offset) - machO. headerStartOffset
292
360
)
361
+ return ( targetMachO, cls)
293
362
}
294
363
295
364
func _readStubClass(
296
365
at offset: UInt64 ,
297
366
field: LayoutField ,
298
367
in machO: MachOFile
299
- ) -> ObjCStubClass ? {
368
+ ) -> ( MachOFile , ObjCStubClass ) ? {
300
369
guard offset > 0 else { return nil }
301
370
var offset : UInt64 = machO. fileOffset (
302
371
of: numericCast ( offset)
303
372
) + numericCast( machO. headerStartOffset)
304
373
305
-
306
374
if let resolved = resolveRebase ( field, in: machO) {
307
375
offset = machO. fileOffset ( of: resolved) + numericCast( machO. headerStartOffset)
308
376
}
309
377
if isBind ( field, in: machO) { return nil }
310
378
379
+ var targetMachO = machO
380
+
381
+ var fileHandle = machO. fileHandle
311
382
var resolvedOffset = offset
312
- if let cache = machO. cache {
313
- guard let _offset = cache. fileOffset ( of: offset + cache. mainCacheHeader. sharedRegionStart) else {
314
- return nil
315
- }
383
+ if let ( _cache, _offset) = machO. cacheAndFileOffset (
384
+ fromStart: offset
385
+ ) {
316
386
resolvedOffset = _offset
387
+ fileHandle = _cache. fileHandle
388
+
389
+ let unslidAddress = offset + _cache. mainCacheHeader. sharedRegionStart
390
+ if !targetMachO. contains ( unslidAddress: unslidAddress) ,
391
+ let machO = _cache. machO ( containing: unslidAddress) {
392
+ targetMachO = machO
393
+ }
317
394
}
318
395
319
- let layout : ObjCStubClass . Layout = machO . fileHandle. read ( offset: resolvedOffset)
320
- return . init(
396
+ let layout : ObjCStubClass . Layout = fileHandle. read ( offset: resolvedOffset)
397
+ let cls : ObjCStubClass = . init(
321
398
layout: layout,
322
399
offset: numericCast ( offset) - machO. headerStartOffset
323
400
)
401
+ return ( targetMachO, cls)
324
402
}
325
403
326
404
private func _readClassName(
@@ -330,13 +408,13 @@ extension ObjCCategoryProtocol {
330
408
) -> String ? {
331
409
guard offset > 0 else { return nil }
332
410
333
- if let cls = _readClass (
411
+ if let ( targetMachO , cls) = _readClass (
334
412
at: offset,
335
413
field: field,
336
414
in: machO
337
415
) , !cls. isStubClass ,
338
- let data = cls. classROData ( in: machO ) {
339
- return data. name ( in: machO )
416
+ let data = cls. classROData ( in: targetMachO ) {
417
+ return data. name ( in: targetMachO )
340
418
}
341
419
342
420
if let bindSymbolName = resolveBind ( field, in: machO) {
@@ -360,7 +438,7 @@ extension ObjCCategoryProtocol {
360
438
) + numericCast( machO. headerStartOffset)
361
439
362
440
if let resolved = resolveRebase ( field, in: machO) ,
363
- resolved != offset {
441
+ resolved != offset {
364
442
offset = machO. fileOffset ( of: resolved) + numericCast( machO. headerStartOffset)
365
443
}
366
444
// if isBind(\.baseMethods, in: machO) { return nil }
0 commit comments