| 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) |