| Index: tools/ipoddfu/ipoddfu.py |
| — | — | @@ -0,0 +1,33 @@ |
| | 2 | +#!/usr/bin/env python
|
| | 3 | +#
|
| | 4 | +#
|
| | 5 | +# Copyright 2010 TheSeven
|
| | 6 | +#
|
| | 7 | +#
|
| | 8 | +# This file is part of TheSeven's iPod tools.
|
| | 9 | +#
|
| | 10 | +# TheSeven's iBugger is free software: you can redistribute it and/or
|
| | 11 | +# modify it under the terms of the GNU General Public License as
|
| | 12 | +# published by the Free Software Foundation, either version 2 of the
|
| | 13 | +# License, or (at your option) any later version.
|
| | 14 | +#
|
| | 15 | +# TheSeven's iBugger is distributed in the hope that it will be useful,
|
| | 16 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| | 17 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| | 18 | +# See the GNU General Public License for more details.
|
| | 19 | +#
|
| | 20 | +# You should have received a copy of the GNU General Public License along
|
| | 21 | +# with TheSeven's iPod tools. If not, see <http://www.gnu.org/licenses/>.
|
| | 22 | +#
|
| | 23 | +#
|
| | 24 | +
|
| | 25 | +
|
| | 26 | +import sys
|
| | 27 | +import libipoddfu
|
| | 28 | +
|
| | 29 | +if len(sys.argv) != 2:
|
| | 30 | + print "Syntax: ipoddfu.py <file>"
|
| | 31 | + exit(2)
|
| | 32 | +
|
| | 33 | +dev = libipoddfu.ipoddfu()
|
| | 34 | +dev.uploadfile(sys.argv[1])
|
| Index: tools/ipoddfu/libipoddfu.py |
| — | — | @@ -0,0 +1,148 @@ |
| | 2 | +#!/usr/bin/env python
|
| | 3 | +#
|
| | 4 | +#
|
| | 5 | +# Copyright 2010 TheSeven
|
| | 6 | +#
|
| | 7 | +#
|
| | 8 | +# This file is part of TheSeven's iPod tools.
|
| | 9 | +#
|
| | 10 | +# TheSeven's iBugger is free software: you can redistribute it and/or
|
| | 11 | +# modify it under the terms of the GNU General Public License as
|
| | 12 | +# published by the Free Software Foundation, either version 2 of the
|
| | 13 | +# License, or (at your option) any later version.
|
| | 14 | +#
|
| | 15 | +# TheSeven's iBugger is distributed in the hope that it will be useful,
|
| | 16 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| | 17 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| | 18 | +# See the GNU General Public License for more details.
|
| | 19 | +#
|
| | 20 | +# You should have received a copy of the GNU General Public License along
|
| | 21 | +# with TheSeven's iPod tools. If not, see <http://www.gnu.org/licenses/>.
|
| | 22 | +#
|
| | 23 | +#
|
| | 24 | +
|
| | 25 | +
|
| | 26 | +import sys
|
| | 27 | +import struct
|
| | 28 | +import usb.core
|
| | 29 | +
|
| | 30 | +
|
| | 31 | +class ipoddfu:
|
| | 32 | + def __init__(self, generation = 0, type = 0):
|
| | 33 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1220)
|
| | 34 | + if self.dev and generation in [0, 2] and type in [0, 1]:
|
| | 35 | + self.dev.set_configuration(1)
|
| | 36 | + self.generation = 2;
|
| | 37 | + self.type = 1;
|
| | 38 | + print("Connected to S5L8701 Bootrom DFU mode, USB version %s" % self.dev.bcdDevice)
|
| | 39 | + return
|
| | 40 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1240)
|
| | 41 | + if self.dev and generation in [0, 2] and type in [0, 2]:
|
| | 42 | + self.dev.set_configuration(1)
|
| | 43 | + self.generation = 2;
|
| | 44 | + self.type = 2;
|
| | 45 | + print("Connected to iPod Nano 2G NOR DFU mode, USB version %s" % self.dev.bcdDevice)
|
| | 46 | + return
|
| | 47 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1223)
|
| | 48 | + if self.dev and generation in [0, 3] and type in [0, 1]:
|
| | 49 | + self.dev.set_configuration(1)
|
| | 50 | + self.generation = 3;
|
| | 51 | + self.type = 1;
|
| | 52 | + print("Connected to S5L8702 Bootrom DFU mode, USB version %s" % self.dev.bcdDevice)
|
| | 53 | + return
|
| | 54 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1242)
|
| | 55 | + if self.dev and generation in [0, 3] and type in [0, 1]:
|
| | 56 | + self.dev.set_configuration(1)
|
| | 57 | + self.generation = 3;
|
| | 58 | + self.type = 2;
|
| | 59 | + print("Connected to iPod Nano 3G WTF mode, USB version %s" % self.dev.bcdDevice)
|
| | 60 | + return
|
| | 61 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1225)
|
| | 62 | + if self.dev and generation in [0, 4] and type in [0, 1]:
|
| | 63 | + self.dev.set_configuration(1)
|
| | 64 | + self.generation = 4;
|
| | 65 | + self.type = 1;
|
| | 66 | + print("Connected to S5L8720 Bootrom DFU mode, USB version %s" % self.dev.bcdDevice)
|
| | 67 | + return
|
| | 68 | + self.dev = usb.core.find(idVendor=0x05ac, idProduct=0x1243)
|
| | 69 | + if self.dev and generation in [0, 4] and type in [0, 1]:
|
| | 70 | + self.dev.set_configuration(1)
|
| | 71 | + self.generation = 4;
|
| | 72 | + self.type = 2;
|
| | 73 | + print("Connected to iPod Nano 4G WTF mode, USB version %s" % self.dev.bcdDevice)
|
| | 74 | + return
|
| | 75 | +
|
| | 76 | + raise Exception("Could not find specified DFU device (generation = %d, type = %d)" % (generation, type))
|
| | 77 | +
|
| | 78 | + @staticmethod
|
| | 79 | + def crc32(data):
|
| | 80 | + crc_table = []
|
| | 81 | + for i in range(256):
|
| | 82 | + t = i;
|
| | 83 | + for j in range(8):
|
| | 84 | + if t & 1:
|
| | 85 | + t = (t >> 1) ^ 0xedb88320
|
| | 86 | + else:
|
| | 87 | + t = t >> 1
|
| | 88 | + crc_table.append(t)
|
| | 89 | +
|
| | 90 | + crc = 0xffffffff
|
| | 91 | + for i in range(len(data)):
|
| | 92 | + crc = (crc >> 8) ^ crc_table[(crc ^ struct.unpack("B", data[i])[0]) & 0xff];
|
| | 93 | +
|
| | 94 | + return crc
|
| | 95 | +
|
| | 96 | +
|
| | 97 | + def getcpu(self):
|
| | 98 | + result = self.handle.controlMsg(0xa1, 0xff, 0x3f, 2, 0, 100)
|
| | 99 | + return struct.pack("%dB" % len(result), *result)
|
| | 100 | +
|
| | 101 | +
|
| | 102 | + def upload(self, data, exploit = 0):
|
| | 103 | + if exploit == 1 and self.generation == 2 and self.type == 1:
|
| | 104 | + data = f.read().ljust(0x200f0, "\0") \
|
| | 105 | + + "\xb8\x48\x02\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
|
| | 106 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 107 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 108 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 109 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 110 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 111 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 112 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22" \
|
| | 113 | + + "\0\0\0\x22\0\0\0\x22\0\0\0\x22\0\0\0\x22"
|
| | 114 | +
|
| | 115 | + data = data + struct.pack("<I", self.crc32(data))
|
| | 116 | +
|
| | 117 | + sys.stdout.write("Upload: .")
|
| | 118 | + sys.stdout.flush()
|
| | 119 | + for index in range((len(data) + 2047) // 2048):
|
| | 120 | + self.dev.ctrl_transfer(0x21, 1, index, 0, data[2048 * index : 2048 * (index + 1)], 100)
|
| | 121 | + result = (0, 0, 0, 0, 0, 0)
|
| | 122 | + while result[4] != 0x05:
|
| | 123 | + result = self.dev.ctrl_transfer(0xa1, 3, 0, 0, 6, 100)
|
| | 124 | + sys.stdout.write(".")
|
| | 125 | + sys.stdout.flush()
|
| | 126 | +
|
| | 127 | + self.dev.ctrl_transfer(0x21, 1, index, 0, "", 100)
|
| | 128 | + result = (0, 0, 0, 0, 0, 0)
|
| | 129 | + index = 0
|
| | 130 | + try:
|
| | 131 | + while result[4] != 0x02 and index < 1000:
|
| | 132 | + result = self.dev.ctrl_transfer(0xa1, 3, 0, 0, 6, 100)
|
| | 133 | + index = index + 1
|
| | 134 | + except:
|
| | 135 | + pass
|
| | 136 | +
|
| | 137 | + if (exploit == 0 and (index == 1000 or result[4] == 0x02)) or \
|
| | 138 | + (exploit == 1 and (index == 1000 or result[4] != 0x04)):
|
| | 139 | + print(" failed: %X / %X" % (result[4], result[0]))
|
| | 140 | + raise Exception("DFU upload failed! (%X / %X)" % (result[4], result[0]))
|
| | 141 | + else:
|
| | 142 | + print(" done")
|
| | 143 | +
|
| | 144 | +
|
| | 145 | + def uploadfile(self, file, exploit = 0):
|
| | 146 | + f = open(file, "rb")
|
| | 147 | + data = f.read()
|
| | 148 | + f.close()
|
| | 149 | + self.upload(data, exploit)
|