Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions FrameworkClientApp/FishHook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,46 +46,46 @@ private func replaceSymbolAtImage(
var dataCmd: UnsafeMutablePointer<segment_command_64>!
var symtabCmd: UnsafeMutablePointer<symtab_command>!
var dynamicSymtabCmd: UnsafeMutablePointer<dysymtab_command>!

guard var curCmdPointer = UnsafeMutableRawPointer(bitPattern: UInt(bitPattern: image)+UInt(MemoryLayout<mach_header_64>.size)) else { return }

for _ in 0..<image.pointee.ncmds {
let curCmd = curCmdPointer.assumingMemoryBound(to: segment_command_64.self)

if curCmd.pointee.cmd == LC_SEGMENT_64 {
let curCmdNameOffset = MemoryLayout.size(ofValue: curCmd.pointee.cmd) + MemoryLayout.size(ofValue: curCmd.pointee.cmdsize)
let curCmdNamePointer = curCmdPointer.advanced(by: curCmdNameOffset).assumingMemoryBound(to: Int8.self)
let curCmdName = String(cString: curCmdNamePointer)
if (curCmdName == SEG_LINKEDIT) {
if curCmdName == SEG_LINKEDIT {
linkeditCmd = curCmd
} else if (curCmdName == SEG_DATA) {
} else if curCmdName == SEG_DATA {
dataCmd = curCmd
}
} else if curCmd.pointee.cmd == LC_SYMTAB {
symtabCmd = UnsafeMutablePointer<symtab_command>(OpaquePointer(curCmd))
} else if curCmd.pointee.cmd == LC_DYSYMTAB {
dynamicSymtabCmd = UnsafeMutablePointer<dysymtab_command>(OpaquePointer(curCmd))
}

curCmdPointer += Int(curCmd.pointee.cmdsize)
}

if linkeditCmd == nil || symtabCmd == nil || dynamicSymtabCmd == nil || dataCmd == nil {
return
}

let linkedBase = slide + Int(linkeditCmd.pointee.vmaddr) - Int(linkeditCmd.pointee.fileoff)
let symtab = UnsafeMutablePointer<nlist_64>(bitPattern: linkedBase + Int(symtabCmd.pointee.symoff))
let strtab = UnsafeMutablePointer<UInt8>(bitPattern: linkedBase + Int(symtabCmd.pointee.stroff))
let indirectsym = UnsafeMutablePointer<UInt32>(bitPattern: linkedBase + Int(dynamicSymtabCmd.pointee.indirectsymoff))

if symtab == nil || strtab == nil || indirectsym == nil {
return
}

for tmp in 0..<dataCmd.pointee.nsects {
let curSection = UnsafeMutableRawPointer(dataCmd).advanced(by: MemoryLayout<segment_command_64>.size + MemoryLayout<section_64>.size*Int(tmp)).assumingMemoryBound(to: section_64.self)

// symbol_pointers sections
if curSection.pointee.flags == S_LAZY_SYMBOL_POINTERS {
replaceSymbolPointerAtSection(curSection, symtab: symtab!, strtab: strtab!, indirectsym: indirectsym!, slide: slide, symbolName: symbol, newMethod: newMethod, oldMethod: &oldMethod)
Expand All @@ -109,11 +109,11 @@ private func replaceSymbolPointerAtSection(
) {
let indirectSymVmAddr = indirectsym.advanced(by: Int(section.pointee.reserved1))
let sectionVmAddr = UnsafeMutablePointer<UnsafeMutableRawPointer>(bitPattern: slide+Int(section.pointee.addr))

if sectionVmAddr == nil {
return
}

for tmp in 0..<Int(section.pointee.size)/MemoryLayout<UnsafeMutableRawPointer>.size {
let curIndirectSym = indirectSymVmAddr.advanced(by: tmp)
if curIndirectSym.pointee == INDIRECT_SYMBOL_ABS || curIndirectSym.pointee == INDIRECT_SYMBOL_LOCAL {
Expand Down
32 changes: 16 additions & 16 deletions FrameworkClientApp/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ class RuntimeClass {

internal class ViewController: UIViewController {
@IBOutlet weak var result: UITextView!

override func viewDidAppear(_ animated: Bool) {
var message = ""

#if arch(arm64)
message += executeChecksForArm64()
#endif

// Runtime Check
let test = RuntimeClass.init()
_ = test.runtimeModifiedFunction()
Expand All @@ -35,7 +35,7 @@ internal class ViewController: UIViewController {
selector: #selector(RuntimeClass.runtimeModifiedFunction),
isClassMethod: false
)

message += """
Jailbreak? \(IOSSecuritySuite.amIJailbroken())
Jailbreak with fail msg? \(IOSSecuritySuite.amIJailbrokenWithFailMessage())
Expand All @@ -51,7 +51,7 @@ internal class ViewController: UIViewController {
Am I runtime hooked? \(amIRuntimeHooked)
Am I proxied? \(IOSSecuritySuite.amIProxied())
"""

result.text = message
}
}
Expand All @@ -60,19 +60,19 @@ internal class ViewController: UIViewController {
extension ViewController {
func executeChecksForArm64() -> String {
// executeAntiHook()

// MSHook Check
func msHookReturnFalse(takes: Int) -> Bool {
return false /// add breakpoint at here to test `IOSSecuritySuite.hasBreakpointAt`
}

typealias FunctionType = @convention(thin) (Int) -> (Bool)
func getSwiftFunctionAddr(_ function: @escaping FunctionType) -> UnsafeMutableRawPointer {
return unsafeBitCast(function, to: UnsafeMutableRawPointer.self)
}

let funcAddr = getSwiftFunctionAddr(msHookReturnFalse)

return """
Am I MSHooked? \(IOSSecuritySuite.amIMSHooked(funcAddr))
Application executable file hash value? \(IOSSecuritySuite.getMachOFileHashValue() ?? "")
Expand All @@ -84,34 +84,34 @@ extension ViewController {
Watchpoint? \(testWatchpoint())
"""
}

func testWatchpoint() -> Bool {

// Uncomment these \/ and set a watch point to check the feature
// var ptr = malloc(9)
// var count = 3
return IOSSecuritySuite.hasWatchpoint()
}

func executeAntiHook() {
typealias MyPrint = @convention(thin) (Any..., String, String) -> Void
func myPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {
print("print has been hooked")
}

let myprint: MyPrint = myPrint
let myPrintPointer = unsafeBitCast(myprint, to: UnsafeMutableRawPointer.self)
var oldMethod: UnsafeMutableRawPointer?

// simulating hook
replaceSymbol(
"$ss5print_9separator10terminatoryypd_S2StF",
newMethod: myPrintPointer,
oldMethod: &oldMethod
)

print("print hasn't been hooked")

// antiHook
IOSSecuritySuite.denySymbolHook("$ss5print_9separator10terminatoryypd_S2StF")
print("print has been antiHooked")
Expand Down
1 change: 1 addition & 0 deletions IOSSecuritySuite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
/* Begin PBXShellScriptBuildPhase section */
70B0BBC7226F3A5F000CFB39 /* SwiftLint */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down
50 changes: 25 additions & 25 deletions IOSSecuritySuite/DebuggerChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,64 @@ internal class DebuggerChecker {
var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
var size = MemoryLayout<kinfo_proc>.stride
let sysctlRet = sysctl(&mib, UInt32(mib.count), &kinfo, &size, nil, 0)

if sysctlRet != 0 {
print("Error occurred when calling sysctl(). The debugger check may not be reliable")
}

return (kinfo.kp_proc.p_flag & P_TRACED) != 0
}

static func denyDebugger() {
// bind ptrace()
let pointerToPtrace = UnsafeMutableRawPointer(bitPattern: -2)
let ptracePtr = dlsym(pointerToPtrace, "ptrace")
typealias PtraceType = @convention(c) (CInt, pid_t, CInt, CInt) -> CInt
let ptrace = unsafeBitCast(ptracePtr, to: PtraceType.self)

// PT_DENY_ATTACH == 31
let ptraceRet = ptrace(31, 0, 0, 0)

if ptraceRet != 0 {
print("Error occured when calling ptrace(). Denying debugger may not be reliable")
}
}

#if arch(arm64)
static func hasBreakpointAt(
_ functionAddr: UnsafeRawPointer,
functionSize: vm_size_t?
) -> Bool {
let funcAddr = vm_address_t(UInt(bitPattern: functionAddr))

var vmStart: vm_address_t = funcAddr
var vmSize: vm_size_t = 0
let vmRegionInfo = UnsafeMutablePointer<Int32>.allocate(
capacity: MemoryLayout<vm_region_basic_info_64>.size/4
)

defer {
vmRegionInfo.deallocate()
}

var vmRegionInfoCount: mach_msg_type_number_t = mach_msg_type_number_t(VM_REGION_BASIC_INFO_64)
var objectName: mach_port_t = 0

let ret = vm_region_64(
mach_task_self_, &vmStart,
&vmSize, VM_REGION_BASIC_INFO_64,
vmRegionInfo, &vmRegionInfoCount,
&objectName
)

if ret != KERN_SUCCESS {
return false
}

let vmRegion = vmRegionInfo.withMemoryRebound(
to: vm_region_basic_info_64.self, capacity: 1, { $0 }
)

if vmRegion.pointee.protection == (VM_PROT_READ | VM_PROT_EXECUTE) {
let armBreakpointOpcode = 0xe7ffdefe
let arm64BreakpointOpcode = 0xd4200000
Expand All @@ -81,7 +81,7 @@ internal class DebuggerChecker {
if let size = functionSize, size < judgeSize {
judgeSize = size
}

for valueToOffset in 0..<(judgeSize / 4) {
if (instructionBegin.advanced(
by: Int(valueToOffset)
Expand All @@ -92,31 +92,31 @@ internal class DebuggerChecker {
}
}
}

return false
}

static func hasWatchpoint() -> Bool {
var threads: thread_act_array_t?
var threadCount: mach_msg_type_number_t = 0
var hasWatchpoint = false

if task_threads(mach_task_self_, &threads, &threadCount) == KERN_SUCCESS {
var threadStat = arm_debug_state64_t()
let capacity = MemoryLayout<arm_debug_state64_t>.size/MemoryLayout<natural_t>.size

let threadStatPointer = withUnsafeMutablePointer(to: &threadStat, {
$0.withMemoryRebound(to: natural_t.self, capacity: capacity, { $0 })
})

var count = mach_msg_type_number_t(
MemoryLayout<arm_debug_state64_t>.size/MemoryLayout<UInt32>.size
)

guard let threads = threads else {
return false
}

for threadIndex in 0..<threadCount where thread_get_state(
threads[Int(threadIndex)],
ARM_DEBUG_STATE64,
Expand All @@ -128,21 +128,21 @@ internal class DebuggerChecker {
).pointee.__wvr.0 != 0
if hasWatchpoint { break }
}

vm_deallocate(
mach_task_self_,
UInt(bitPattern: threads),
vm_size_t(threadCount * UInt32(MemoryLayout<thread_act_t>.size))
)
}

return hasWatchpoint
}
#endif

static func isParentPidUnexpected() -> Bool {
let parentPid: pid_t = getppid()

return parentPid != 1 // LaunchD is pid 1
}
}
Loading