Swift中dump出MachO中的属性信息

2022-01-13  本文已影响0人  spyn_n

前言

  本篇在 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
输出结果
上一篇 下一篇

猜你喜欢

热点阅读