前言
本篇在 Swift的属性 篇的基础上操作指针读取MachO中属性的案例,针对单个结构体/类进行dump
。具体的操作和注释已经在案例中注明:
(需要注意的是:在解析的过程中,关于FieldDescriptor
中的fieldRecords
,因为fieldRecords
是一片连续的内存空间,其并没有存储一个类似于前面的字段,所以不能取其中的值作为offset,我就计算错过一次,找了好久才发现跟实际手动算皮配不上)
struct PSYModel{
var age: Int
let name: String
}
var size: UInt = 0
// 获取segment:__TEXT, section:__swift5_types的地址(包含了基地址)
var sPtr = getsectdata("__TEXT", "__swift5_types", &size)
// vmAddress(UnsafePointer<mach_header>!),这其实是程序运行的首地址
var mhHeaderPtr = _dyld_get_image_header(0)
// 得到一个segment_command_64结构体地址
var setCommond64Ptr = getsegbyname("__LINKEDIT")
// 定义并计算基地址
var linkBaseAddress:UInt64 = 0
if let vmAddress = setCommond64Ptr?.pointee.vmaddr, let fileOffset = setCommond64Ptr?.pointee.fileoff{
linkBaseAddress = vmAddress - fileOffset
}
var offset:UInt64 = 0
if let unwrappedPtr = sPtr{
// 将UnsafeMutablePointer<Int8>转换成Int,在按位转换成Int64--> UInt64
let intRepreaentation = UInt64(bitPattern: Int64(Int(bitPattern: unwrappedPtr)))
offset = intRepreaentation - linkBaseAddress
}
// 因为UnsafePointer没有具体的类型不能进行计算,需要转换成确定的类型
let mhHeaderPtr_IntRepreaentation = UInt64(bitPattern: Int64(Int(bitPattern: mhHeaderPtr)))
// 计算__swift5_types的地址信息(UInt64)
var dataLoAddress = mhHeaderPtr_IntRepreaentation + offset
// 将地址信息返回指针类型,访问地址取出内容值
var dataLoAddressPtr = withUnsafePointer(to: &dataLoAddress){return $0}
var dataLoContent = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: dataLoAddress) ?? 0)?.pointee
// 得到typeDescriptor的偏移值
var typeDescriptorOffset = UInt64(dataLoContent!) + offset - linkBaseAddress
// 得到typeDescriptor真实地址
var typeDescriptorAddress = typeDescriptorOffset + mhHeaderPtr_IntRepreaentation
// 根据源码得出的结构体信息声明
struct TargetClassDescriptor{
var flags: UInt32
var parent: UInt32
var name: Int32
var accessFunctionPointer: Int32
var fieldDescriptor: Int32
var superClassType: Int32
var metadataNegativeSizeInWords: UInt32
var metadataPositiveSizeInWords: UInt32
var numImmediateMembers: UInt32
var numFields: UInt32
var fieldOffsetVectorOffset: UInt32
var Offset: UInt32
var size: UInt32
//vtable
}
// 将地址值强转成结构体
let classDescriptor = UnsafePointer<TargetClassDescriptor>.init(bitPattern: Int(exactly: typeDescriptorAddress) ?? 0)?.pointee
// 计算结构体名称
if let name = classDescriptor?.name{
// 计算name的地址
let nameAddress = Int64(typeDescriptorAddress) + Int64(name) + 8
print("nameAddress:\(nameAddress)")
if let cChar = UnsafePointer<CChar>.init(bitPattern: Int(exactly: nameAddress) ?? 0){
print("name名字 = \(String(cString: cChar))")
}
}
// 真实地址fieldDescriptorAddress + 结构体偏移值
let fieldDescriptorRelaticveAddress = typeDescriptorAddress + 16
// 取出里面的值,其实就是fieldDescriptor的offset
let fieldDescriptorOffset = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: fieldDescriptorRelaticveAddress) ?? 0)?.pointee
// 得到FieldDescriptor的真实地址
let fieldDescriptorAddress = fieldDescriptorRelaticveAddress + UInt64(fieldDescriptorOffset!)
struct FieldDescriptor{
var mangledTypeName: UInt32
var superclass: UInt32
var Kind: UInt16
var fieldRecordSize: UInt16
var numFields: UInt32 // 属性个数
//var fieldRecords: UInt32 // [FieldRecords]
}
struct FieldRecord{
var Flags : UInt32
var mangledTypeName: UInt32
var fieldName: UInt32
}
// 转换成结构体
let fieldDescriptor = UnsafePointer<FieldDescriptor>.init(bitPattern: Int(exactly: fieldDescriptorAddress) ?? 0)?.pointee
// 真实地址FieldRecord + 结构体偏移值
let fieldRecordAddress = fieldDescriptorAddress + 16
for i in 0..<fieldDescriptor!.numFields{
let stride: UInt64 = UInt64(MemoryLayout<FieldRecord>.stride * Int(i))
let fieldNameRelaticveAddress = fieldRecordAddress + 8 + stride
let fieldNameOffset = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: fieldNameRelaticveAddress) ?? 0)?.pointee
// 计算name的地址
let fieldNameAddress = fieldNameRelaticveAddress + UInt64(fieldNameOffset!) - linkBaseAddress
if let cChar = UnsafePointer<CChar>.init(bitPattern: Int(exactly: fieldNameAddress) ?? 0){
print("属性名字 = \(String(cString: cChar))")
}
}
print("end")
输出:
nameAddress:4294994300
name名字 = PSYModel
属性名字 = age
属性名字 = name
end
Program ended with exit code: 0

网友评论