hook
动态链接系统库函数绑定 Fishhook原理模拟
得到符号绑定表,替换绑定的函数地址
@preconcurrency import Darwin
import MachO
func rebindSymbol<CFunc>(name: String, block: @escaping (_ oldFunc: CFunc) -> CFunc) {
vm_protect(mach_task_self_, unsafeBitCast(got.dict["_\(name)"], to: UInt.self), 1, 0, VM_PROT_READ | VM_PROT_WRITE)
got.dict["_\(name)"]?.pointee = unsafeBitCast(block(unsafeBitCast(got.dict["_\(name)"]?.pointee, to: CFunc.self)), to: UnsafeRawPointer.self)
}
func gotInit() {
_dyld_register_func_for_add_image { header, slide in
let header = header!.withMemoryRebound(to: mach_header_64.self, capacity: 1, { $0 })
// segment
var linkEditSegment: UnsafePointer<segment_command_64>!
var symbolTableSegment: UnsafePointer<symtab_command>!
var dynamicSymbolTableSegment: UnsafePointer<dysymtab_command>!
var dataConstSegment: UnsafePointer<segment_command_64>?
var segmentRawPtr = UnsafeRawPointer(header.advanced(by: 1))
for _ in 0..<Int(header.pointee.ncmds) {
let segmentPtr = segmentRawPtr.assumingMemoryBound(to: segment_command_64.self)
if segmentPtr.pointee.cmd == UInt32(LC_SEGMENT_64) && segmentPtr.pointee.segmentName == SEG_LINKEDIT {
linkEditSegment = segmentPtr
}
if segmentPtr.pointee.cmd == UInt32(LC_SYMTAB) {
symbolTableSegment = segmentRawPtr.assumingMemoryBound(to: symtab_command.self)
}
if segmentPtr.pointee.cmd == UInt32(LC_DYSYMTAB) {
dynamicSymbolTableSegment = segmentRawPtr.assumingMemoryBound(to: dysymtab_command.self)
}
if segmentPtr.pointee.cmd == UInt32(LC_SEGMENT_64) && segmentPtr.pointee.segmentName == "__DATA_CONST" {
dataConstSegment = segmentPtr
}
segmentRawPtr = segmentRawPtr.advanced(by: Int(segmentPtr.pointee.cmdsize))
}
guard let dataConstSegment else { return }
// symbol table
let linkEditBase = UInt(slide) + UInt(linkEditSegment.pointee.vmaddr - linkEditSegment.pointee.fileoff)
let symbolTable = UnsafePointer<nlist_64>(bitPattern: linkEditBase + UInt(symbolTableSegment.pointee.symoff))!
let stringTable = UnsafePointer<CChar>(bitPattern: linkEditBase + UInt(symbolTableSegment.pointee.stroff))!
let indirectSymbolTable = UnsafePointer<UInt32>(bitPattern: linkEditBase + UInt(dynamicSymbolTableSegment.pointee.indirectsymoff))!
// got
let dataConstSectionsPtr = dataConstSegment.advanced(by: 1).withMemoryRebound(to: section_64.self, capacity: 1, { $0 })
let dataConstSections = [section_64](UnsafeBufferPointer(start: dataConstSectionsPtr, count: Int(dataConstSegment.pointee.nsects)))
let gotSections = dataConstSections.filter { section in
Int32(section.flags) & SECTION_TYPE == S_NON_LAZY_SYMBOL_POINTERS
}
for section in gotSections {
for i in 0..<(Int(section.size) / MemoryLayout<UnsafeRawPointer>.size) {
// symbol name
let symbolTableIndex = indirectSymbolTable[Int(section.reserved1) + i]
if symbolTableIndex == INDIRECT_SYMBOL_LOCAL || symbolTableIndex == (UInt32(INDIRECT_SYMBOL_ABS) | INDIRECT_SYMBOL_LOCAL) {
continue
}
let stringTableIndex = symbolTable[Int(symbolTableIndex)].n_un.n_strx
let symbolName = String(cString: stringTable.advanced(by: Int(stringTableIndex)))
// binding
let indirectBinding = UnsafeMutablePointer<UnsafeRawPointer>(bitPattern: UInt(slide) + UInt(section.addr))!.advanced(by: i)
got.dict[symbolName] = indirectBinding
}
}
}
}
class GOT: @unchecked Sendable {
var dict: [String: UnsafeMutablePointer<UnsafeRawPointer>] = [:]
}
let got = GOT()
extension segment_command_64 {
var segmentName: String {
String(cString: withUnsafePointer(to: segname, { $0.withMemoryRebound(to: CChar.self, capacity: 1, { $0 }) }))
}
}
gotInit()
typealias ExitFunc = @convention(c) (Int32) -> Void
var oldExit: (ExitFunc)?
rebindSymbol(name: "exit") { oldFunc in
oldExit = oldFunc
return { code in
print("hooked")
oldExit?(code + 3)
} as ExitFunc
}
exit(0)
objc Runtime方法交换
import Foundation
@objcMembers
class A: NSObject {
dynamic func a() {
}
}
@objcMembers
class B: NSObject {
dynamic func b() {
}
}
let a = class_getInstanceMethod(A.self, #selector(A.a))!
let b = class_getInstanceMethod(B.self, #selector(B.b))!
method_exchangeImplementations(a, b)
A().a()
swift dynamicReplacement
dynamic func a() {
}
@_dynamicReplacement(for:a)
func b() {
}
a()