Linus Henze 开源 Fugu15越狱 代码
4 minute read
Linus Henze开源 Fugu15越狱代码
我的博客 https://xlsn0w.github.io/
10月初,Linus Henze 展示了他在运行 iOS15.4.1的 iPhone 上的 Fugu15越狱,他用一种巧妙的新安装方法让我们想起了 JailbreakMe 的日子。
现在,它已经正式发布,并在 Henze 的 GitHub 页面上开源。
https://github.com/pinauten/Fugu15
现在 TrollStore 正式支持 Fugu15越狱应用程序,这意味着用户可以使用 TrollStore 在他们兼容的设备上加载和永久签署 Fugu15越狱应用程序。
以前,用户需要用自己的域名安装一个基于 web 的安装程序,或者将他们的设备连接到 Mac 上,用 Xcode 安装 Fugu15。
公众号Cydiapps 已经发文详细讲解Fugu15
源代码
//
// Fugu15.swift
// Fugu15KernelExploit
//
// Created by Linus Henze.
//
import Foundation
import ProcessCommunication
import CBindings
import KernelPatchfinder
public enum Fugu15LaunchError: Error {
case deviceNotSupported(reason: String)
case posix_spawnFailed(result: Int32, errno: Int32)
case noPongReceived
case kexploitdFailed
case canOnlyLaunchiDownloadAfterExploitRan
case iDownloadLaunchFailed(reply: [String])
}
public enum Fugu15SupportsThisDevice {
case yes
case no(reason: String)
}
public struct Fugu15 {
public static var comm: ProcessCommunication?
public static var patchfinder = KernelPatchfinder.running
static var kernelBase: UInt64 = 0
static var kernelSlide: UInt64 = 0
// Lock for requests to pciPwn
static let requestLock = NSLock()
// Lock to notify exception handler to continue
static let sendRequestLock = NSLock()
// Lock to notify requestor to continue
static let replyLock = NSLock()
// Request
static var request: UInt64 = 0
static var requestAddrPid: UInt64 = 0
static var requestSize: UInt64 = 0
static var requestBuf: Data?
// Reply
static var replyStatus: UInt64 = 0
static var replyResult: UInt64 = 0
static var replyBuf: Data?
public static func supportsThisDevice() -> Fugu15SupportsThisDevice {
// Test iOS version
let osVersion = ProcessInfo.processInfo.operatingSystemVersion
guard osVersion.majorVersion == 15,
osVersion.minorVersion < 5 else {
return .no(reason: "Fugu15 only supports iOS 15 - 15.4.1!")
}
// The exploits should support some 15.5 betas
// Not implemented though
/*if osVersion.minorVersion == 5 {
var size = 1024
let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: size + 1)
defer { ptr.deallocate() }
let res = sysctlbyname("kern.osversion", ptr, &size, nil, 0)
guard res == 0 else {
return .no(reason: "Fugu15 failed to determine your OS version!")
}
ptr[size] = 0 // Ensure that the string is terminated
let vStr = String(cString: ptr)
let supported = ["19A5261w", "19A5281h", "19A5281j", "19A5297e"] // No idea if this is correct
guard supported.contains(vStr) else {
return .no(reason: "Fugu15 only supports iOS 15 - 15.4.1 (and some 15.5 betas)!")
}
}*/
// Ensure device supports pointer authentication
guard deviceSupports(cpuFeature: "PAuth") else {
return .no(reason: "Fugu15 only supports PAC devices (iPhone XS and newer)!")
}
return .yes
}
public static func querySysctlBool(name: String) -> Bool {
var size = 8
let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
defer { ptr.deallocate() }
let res = sysctlbyname(name, ptr, &size, nil, 0)
guard res == 0 else {
return false
}
return ptr[0] != 0
}
public static func deviceSupports(cpuFeature: String) -> Bool {
return querySysctlBool(name: "hw.optional.arm.FEAT_\(cpuFeature)")
}
/**
* Launch kernel exploit. Requires path to oobPCI.
*
* - Parameter oobPCI: Path to the oobPCI executable
* - Parameter logger: A function to log messages
*
* - Warning: This function blocks, do not call it on the main dispatch queue
*/
public static func launchKernelExploit(oobPCI: URL, logger: @escaping (_ msg: String) -> Void) throws {
switch supportsThisDevice() {
case .yes:
break
case .no(reason: let reason):
throw Fugu15LaunchError.deviceNotSupported(reason: reason)
}
// Create pipes to use for communication
// We use control and log pipes
let controlToChild = Pipe()
let controlFromChild = Pipe()
let logFromChild = Pipe()
// We're entitled to do that ;)
var attr: posix_spawnattr_t?
posix_spawnattr_init(&attr)
posix_spawnattr_set_persona_np(&attr, 99, 1)
posix_spawnattr_set_persona_uid_np(&attr, 0)
posix_spawnattr_set_persona_gid_np(&attr, 0)
// Close unnecessary handles
var fileActions: posix_spawn_file_actions_t?
posix_spawn_file_actions_init(&fileActions)
posix_spawn_file_actions_addclose(&fileActions, controlToChild.fileHandleForWriting.fileDescriptor)
posix_spawn_file_actions_addclose(&fileActions, controlFromChild.fileHandleForReading.fileDescriptor)
posix_spawn_file_actions_addclose(&fileActions, logFromChild.fileHandleForReading.fileDescriptor)
var pid: pid_t = 0
var argv: [UnsafeMutablePointer<CChar>?] = [
strdup(CommandLine.arguments[0]),
strdup("Fugu15_server"),
strdup("\(controlToChild.fileHandleForReading.fileDescriptor)"),
strdup("\(controlFromChild.fileHandleForWriting.fileDescriptor)"),
strdup("\(logFromChild.fileHandleForWriting.fileDescriptor)"),
nil
]
defer {
for arg in argv {
free(arg)
}
}
let result = posix_spawn(&pid, argv[0], &fileActions, &attr, &argv, environ)
let err = errno
guard result == 0 else {
throw Fugu15LaunchError.posix_spawnFailed(result: result, errno: err)
}
try? controlToChild.fileHandleForReading.close()
try? controlFromChild.fileHandleForWriting.close()
try? logFromChild.fileHandleForWriting.close()
DispatchQueue(label: "Fugu15-Logging").async {
var buf = ""
while true {
do {
let data = try logFromChild.fileHandleForReading.read(upToCount: 1)
if data == nil || data?.count == 0 {
return
}
if data.unsafelyUnwrapped[0] == 0xA /* newline */ {
logger(buf)
buf = ""
} else {
buf += String(data: data.unsafelyUnwrapped, encoding: .utf8) ?? ""
}
} catch _ {
return
}
}
}
// Send ping
let comm = ProcessCommunication(read: controlFromChild.fileHandleForReading, write: controlToChild.fileHandleForWriting)
comm.sendCommand("ping")
guard comm.receiveCommand() == ["pong"] else {
throw Fugu15LaunchError.noPongReceived
}
comm.sendCommand("pwn", oobPCI.path)
if comm.receiveCommand() != ["ok"] {
throw Fugu15LaunchError.kexploitdFailed
}
comm.sendCommand("waitUntilDone")
if comm.receiveCommand() != ["done"] {
throw Fugu15LaunchError.kexploitdFailed
}
Self.comm = comm
}
public static func launch_iDownload() throws {
guard let comm = Self.comm else {
throw Fugu15LaunchError.canOnlyLaunchiDownloadAfterExploitRan
}
comm.sendCommand("launch_iDownload")
let reply = comm.receiveCommand()
if reply != ["done"] {
throw Fugu15LaunchError.iDownloadLaunchFailed(reply: reply ?? [])
}
}
/**
* Call this method from your main function. Only returns if invoked without a Fugu15 command.
*/
public static func mainHook() {
if CommandLine.arguments.count > 1 {
switch CommandLine.arguments[1] {
case "Fugu15_server":
let logOut = FileHandle(fileDescriptor: Int32(CommandLine.arguments[4])!, closeOnDealloc: true)
Logger.logFileHandle = logOut
guard let checkin = getDKCheckinData() else {
execv(Bundle.main.executablePath, CommandLine.unsafeArgv)
Logger.print("Failed to re-exec myself after failing DK checkin!")
fatalError("Failed to re-exec myself after failing DK checkin!")
}
serverMain(checkin: checkin)
default:
break
}
}
}
}
I feedback.
Let me know what you think of this article on twitter @XLsn0w!
Let me know what you think of this article on twitter @XLsn0w!