Skip to content

Instantly share code, notes, and snippets.

@JJTech0130
Created July 5, 2026 20:31
Show Gist options
  • Select an option

  • Save JJTech0130/a878496479afedb93dd02399551e3aec to your computer and use it in GitHub Desktop.

Select an option

Save JJTech0130/a878496479afedb93dd02399551e3aec to your computer and use it in GitHub Desktop.
Implements very basic test of the iAP2 protocol over "com.apple.carkit.service", the lockdownd service used by CarPlay Simulator
# Implements very basic test of the iAP2 protocol over "com.apple.carkit.service", the lockdownd service used by CarPlay Simulator
import asyncio
from pymobiledevice3.lockdown import create_using_usbmux
def checksum(data):
return (0x100 - sum(data)) & 0xFF
def build_packet(control, seq, ack, session_id=0, payload=b''):
length = 9 + (len(payload) + 1 if payload else 0)
header = bytes([0xFF, 0x5A, length >> 8, length & 0xFF, control, seq, ack, session_id])
header += bytes([checksum(header)])
return header + payload + bytes([checksum(payload)]) if payload else header
async def recv_packet(service):
header = await service.recvall(9)
length = (header[2] << 8) | header[3]
payload = await service.recvall(length - 9) if length > 9 else b''
return header + payload
async def iap1_probe(service):
probe = bytes([0xFF, 0x55, 0x02, 0x00, 0xEE, 0x10])
print(f"[iap1] sending: {probe.hex()}")
await service.sendall(probe)
resp = await service.recvall(6)
print(f"[iap1] received: {resp.hex()}")
return resp
async def iap2_handshake(service):
seq = 100
# LinkVer, MaxOutstanding, MaxRecvLen(4096), RetransTimeout(2000ms), CumAckTimeout(22ms),
# MaxRetrans(30), MaxCumAcks(3), Session[id=1, type=0 control, version=2 (required for CarPlay)]
sync_payload = bytes([0x01, 0x05, 0x10, 0x00, 0x07, 0xD0, 0x00, 0x16, 0x1E, 0x03, 0x01, 0x00, 0x02])
syn = build_packet(0x80, seq, 0, payload=sync_payload)
print(f"[iap2] sending SYN: {syn.hex()}")
await service.sendall(syn)
syn_ack = await recv_packet(service)
print(f"[iap2] received: {syn_ack.hex()}")
ack = build_packet(0x40, seq, syn_ack[5]) # final ACK, no payload
print(f"[iap2] sending ACK: {ack.hex()}")
await service.sendall(ack)
return syn_ack
async def connect():
lockdown = await create_using_usbmux()
service = await lockdown.start_lockdown_service("com.apple.carkit.service")
# Technically you're supposed to send an iAP1 probe first, I think? but it doesn't appear to affect anything
#await iap1_probe(service)
await iap2_handshake(service)
return service
if __name__ == "__main__":
asyncio.run(connect())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment