├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── afc.py ├── apps.py ├── asr.py ├── certificate.py ├── diagnostics_relay.py ├── file_relay.py ├── libs ├── java │ ├── bcprov-jdk15on-150.jar │ ├── junixsocket-1.3.jar │ └── not-yet-commons-ssl-0.3.11.jar ├── native │ ├── libjunixsocket-linux-1.5-amd64.so │ ├── libjunixsocket-linux-1.5-i386.so │ ├── libjunixsocket-macosx-1.5-i386.dylib │ └── libjunixsocket-macosx-1.5-x86_64.dylib └── python │ ├── construct │ ├── __init__.py │ ├── adapters.py │ ├── core.py │ ├── debug.py │ ├── formats │ │ ├── __init__.py │ │ ├── data │ │ │ ├── __init__.py │ │ │ ├── cap.py │ │ │ └── snoop.py │ │ ├── executable │ │ │ ├── __init__.py │ │ │ ├── elf32.py │ │ │ └── pe32.py │ │ ├── filesystem │ │ │ ├── __init__.py │ │ │ ├── ext2.py │ │ │ ├── fat16.py │ │ │ └── mbr.py │ │ └── graphics │ │ │ ├── __init__.py │ │ │ ├── bmp.py │ │ │ ├── emf.py │ │ │ ├── gif.py │ │ │ ├── png.py │ │ │ └── wmf.py │ ├── lib │ │ ├── __init__.py │ │ ├── binary.py │ │ ├── bitstream.py │ │ ├── container.py │ │ ├── expr.py │ │ ├── hex.py │ │ └── py3compat.py │ ├── macros.py │ ├── protocols │ │ ├── __init__.py │ │ ├── application │ │ │ ├── __init__.py │ │ │ └── dns.py │ │ ├── ipstack.py │ │ ├── layer2 │ │ │ ├── __init__.py │ │ │ ├── arp.py │ │ │ ├── ethernet.py │ │ │ └── mtp2.py │ │ ├── layer3 │ │ │ ├── __init__.py │ │ │ ├── dhcpv4.py │ │ │ ├── dhcpv6.py │ │ │ ├── icmpv4.py │ │ │ ├── igmpv2.py │ │ │ ├── ipv4.py │ │ │ ├── ipv6.py │ │ │ └── mtp3.py │ │ └── layer4 │ │ │ ├── __init__.py │ │ │ ├── isup.py │ │ │ ├── tcp.py │ │ │ └── udp.py │ └── version.py │ ├── six.py │ ├── usbmux │ ├── __init__.py │ └── usbmux.py │ └── util │ ├── __init__.py │ └── bplist.py ├── lockdown.py ├── mobile_config.py ├── mobilebackup.py ├── mobilebackup2.py ├── notification_proxy.py ├── pcapd.py ├── plist_service.py ├── screenshotr.py ├── springboard.py └── syslog.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.class 3 | mklink -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | What is this? 2 | ------------------ 3 | 4 | Jython port of [pymobiledevice](https://github.com/GotoHack/pymobiledevice) 5 | 6 | pymobiledevice is a python implementation of the libimobiledevice cross-platform software library that talks the protocols to support iPhone®, iPod Touch®, iPad® and Apple TV® devices. 7 | 8 | The purpose of this fork is to create a _usable_ Java library for communicating with iDevices. 9 | 10 | The idea originally came from [Taconut](https://github.com/Triforce1), which later became a side-project of [Icew1nd](https://github.com/Triforce1/Icew1nd/). 11 | 12 | If you want to use this in Java, [JMobileDevice](https://github.com/Triforce1/JMobileDevice) can handle the wrapper part for you. 13 | 14 | Why create yet another library? 15 | ------------------ 16 | 17 | Generally it's a better practice to follow [C libimobiledevice](https://github.com/libimobiledevice/libimobiledevice) which is actively developed. 18 | 19 | But for some reason, I guess because of licensing problems, [libimobiledevice-wrapper](https://github.com/ios-driver/libimobiledevice-wrapper) depends on [libimobiledevice-sdk (LGPL 2.1)](http://cgit.sukimashita.com/libimobiledevice-sdk.git/) which is not available to the public, making it impossible to use unless someone writes a libimobiledevice-sdk alternative. 20 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import sys 22 | import os 23 | 24 | try: 25 | from java.lang import System 26 | except ImportError: 27 | raise RuntimeError("Only Jython is supported") 28 | 29 | # Disable SSL/TLS socket randomization that iOS doesn't like 30 | System.setProperty('jsse.enableCBCProtection', 'false') 31 | 32 | # Working directory, a missing variable in Python 33 | # Should work in all cases 34 | wd = os.path.join(os.getcwd(), "tmp", "pymobiledevice") 35 | lib_dir = os.path.join(wd, 'libs') 36 | 37 | # Makes importing 3rd party libraries easier 38 | sys.path.append(os.path.join(lib_dir, 'python')) 39 | 40 | # Jython doesn't have an OS constant 41 | os_name = System.getProperty('os.name').encode('ascii', 'ignore') 42 | 43 | if not os_name.lower().startswith(('windows', 'mac os x', 'linux')): 44 | raise RuntimeError("Unsupported OS: " + os_name) 45 | 46 | # Junixsocket native dependencies 47 | System.setProperty('org.newsclub.net.unix.library.path', os.path.join(lib_dir, 'native')) 48 | jar_dir = os.path.join(lib_dir, 'java') 49 | for jar in os.listdir(jar_dir): 50 | if not (os._name == 'nt' and jar.startswith('junixsocket')): # Don't load junixsocket in Windows 51 | sys.path.append(os.path.join(jar_dir, jar)) 52 | -------------------------------------------------------------------------------- /apps.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import os 22 | 23 | from afc import AFCClient, AFCShell, AFCFile 24 | from lockdown import LockdownClient 25 | 26 | 27 | class InstallationProxy(object): 28 | def __init__(self, lockdown=None): 29 | if lockdown: 30 | self.lockdown = lockdown 31 | else: 32 | self.lockdown = LockdownClient() 33 | 34 | self.service = self.lockdown.startService('com.apple.mobile.installation_proxy') 35 | 36 | def install_ipa(self, ipaPath): 37 | #Start afc service & upload ipa 38 | filename = os.path.basename(ipaPath) 39 | with AFCFile(name='/'+filename, mode='wb', afc=AFCClient(self.lockdown)) as f: 40 | f.write(open(ipaPath, 'rb').read()) 41 | 42 | self.service.sendPlist({ 43 | 'Command': 'Install', 44 | 'PackagePath': filename 45 | }) 46 | 47 | while True: 48 | response = self.service.recvPlist() 49 | if not response: 50 | break 51 | 52 | completion = response.get('PercentComplete') 53 | if completion: 54 | print 'Installing, %s: %s %% Complete' % (ipaPath, completion) 55 | status = response.get('Status') 56 | if status == 'Complete': 57 | print 'Installation %s' % status 58 | break 59 | 60 | def app_info(self): 61 | return self.service.sendRequest({'Command': 'Lookup'})['LookupResult'] 62 | 63 | def list_user_apps(self): 64 | return [[app['CFBundleIdentifier'], app.get('CFBundleDisplayName'), app.get('Container')] 65 | for app in self.app_info().values() 66 | if app.get('ApplicationType') == 'User'] 67 | 68 | def list_system_apps(self): 69 | return [[app['CFBundleIdentifier'], app.get('CFBundleDisplayName')] 70 | for app in self.app_info().values() 71 | if app.get('ApplicationType') == 'System'] 72 | 73 | def list_user_apps_BundleID(self): 74 | return [app['CFBundleIdentifier'] 75 | for app in self.app_info().values() 76 | if app.get('ApplicationType') == 'User'] 77 | 78 | def list_system_apps_BundleID(self): 79 | return [app['CFBundleIdentifier'] 80 | for app in self.app_info().values() 81 | if app.get('ApplicationType') == 'System'] 82 | 83 | def list_all_apps_BundleID(self): 84 | return self.app_info().keys() 85 | 86 | def close(self): 87 | self.service.close() 88 | 89 | def __del__(self): 90 | self.close() 91 | 92 | 93 | class AFCApplication(AFCClient): 94 | def __init__(self, lockdown, applicationBundleID): 95 | super(AFCApplication, self).__init__(lockdown, 'com.apple.mobile.house_arrest') 96 | 97 | response = self.service.sendRequest({ 98 | 'Command': 'VendDocuments', 99 | 'Identifier': applicationBundleID 100 | }) 101 | 102 | error = response.get('Error') 103 | if error: 104 | print error # FIXME 105 | 106 | @classmethod 107 | def as_shell(cls, lockdown, applicationBundleID): 108 | _afc = cls(lockdown, applicationBundleID) 109 | AFCShell(afc=_afc).cmdloop() 110 | -------------------------------------------------------------------------------- /asr.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import sys 22 | import os 23 | from pprint import pprint 24 | from progressbar import ProgressBar 25 | from plist_service import PlistService 26 | 27 | 28 | class ASRClient(object): 29 | def __init__(self, payloadFile): 30 | self.s = PlistService(12345) 31 | self.size = os.path.getsize(payloadFile) 32 | self.packet_payload_size = 1450 33 | self.f = open(payloadFile, "rb") 34 | 35 | def initiate(self, msg): 36 | r = {"Checksum Chunk Size": 131072, 37 | "FEC Slice Stride": 40, 38 | "Packet Payload Size": self.packet_payload_size, 39 | "Packets Per FEC": 25, 40 | "Payload": {"Port": 1, "Size": self.size}, 41 | "Stream ID": 1, 42 | "Version": 1 43 | } 44 | print "ASR: init" 45 | self.s.sendPlist(r) 46 | 47 | def handle_oob_request(self, msg): 48 | length = msg["OOB Length"] 49 | offset = msg["OOB Offset"] 50 | print "ASR: OOB request off=%d len=%d" % (offset, length) 51 | self.f.seek(offset) 52 | data = self.f.read(length) 53 | self.s.send_raw(data) 54 | 55 | def send_payload(self, msg): 56 | self.f.seek(0) 57 | i = self.size 58 | 59 | print "ASR: sending payload (%d bytes)" % self.size 60 | pbar = ProgressBar(self.size) 61 | pbar.start() 62 | while i < self.size: 63 | data = self.f.read(self.packet_payload_size) 64 | self.s.send_raw(data) 65 | i += len(data) 66 | pbar.update(i) 67 | pbar.finish() 68 | 69 | def work_loop(self): 70 | while True: 71 | msg = self.s.recvPlist() 72 | if not msg: 73 | break 74 | Command = msg["Command"] 75 | pprint(msg) 76 | 77 | if Command == "Initiate": 78 | self.initiate(msg) 79 | elif Command == "OOBData": 80 | self.handle_oob_request(msg) 81 | elif Command == "Payload": 82 | self.send_payload(msg) 83 | 84 | if __name__ == "__main__": 85 | asr = ASRClient(sys.argv[1]) 86 | asr.work_loop() 87 | -------------------------------------------------------------------------------- /certificate.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | 22 | from java.security import Security, KeyPairGenerator, KeyFactory 23 | from javax.security.auth.x500 import X500Principal 24 | from java.security.spec import X509EncodedKeySpec 25 | 26 | from java.util import Calendar 27 | from java.math import BigInteger 28 | 29 | from org.bouncycastle.x509 import X509V1CertificateGenerator 30 | from org.bouncycastle.jce.provider import BouncyCastleProvider 31 | 32 | Security.addProvider(BouncyCastleProvider()) 33 | 34 | 35 | def convertPKCS1toPKCS8pubKey(data): 36 | subjectpublickeyrsa_start = "30 81 9E 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8C 00".replace(" ", "").decode("hex") 37 | data = data.replace("-----BEGIN RSA PUBLIC KEY-----", "").replace("-----END RSA PUBLIC KEY-----", "").decode('base64') 38 | if data.startswith("30 81 89 02 81 81 00".replace(" ", "").decode("hex")): 39 | #HAX remove null byte to make 128 bytes modulus 40 | data = "30 81 88 02 81 80".replace(" ", "").decode("hex") + data[7:] 41 | return subjectpublickeyrsa_start + data 42 | 43 | 44 | def generateCertificates(DevicePublicKey): 45 | # Generate random 2048-bit private and public keys 46 | keyPairGenerator = KeyPairGenerator.getInstance("RSA") 47 | keyPairGenerator.initialize(2048) 48 | keyPair = keyPairGenerator.genKeyPair() 49 | 50 | # Make it valid for 10 years 51 | calendar = Calendar.getInstance() 52 | startDate = calendar.getTime() 53 | calendar.add(Calendar.YEAR, 10) 54 | expiryDate = calendar.getTime() 55 | 56 | certGen = X509V1CertificateGenerator() 57 | dnName = X500Principal("CN=pyMobileDevice Self-Signed CA Certificate") 58 | 59 | certGen.setSerialNumber(BigInteger.ONE) 60 | certGen.setIssuerDN(dnName) 61 | certGen.setNotBefore(startDate) 62 | certGen.setNotAfter(expiryDate) 63 | certGen.setSubjectDN(dnName) # subject = issuer 64 | certGen.setPublicKey(keyPair.getPublic()) 65 | certGen.setSignatureAlgorithm("SHA1withRSA") 66 | 67 | #Load PKCS#1 RSA Public Key 68 | spec = X509EncodedKeySpec(convertPKCS1toPKCS8pubKey(DevicePublicKey)) 69 | pubKey = KeyFactory.getInstance("RSA").generatePublic(spec) 70 | 71 | hostCertificate = "-----BEGIN CERTIFICATE-----\n" + certGen.generate(keyPair.getPrivate(), "BC").getEncoded().tostring().encode("base64") + "-----END CERTIFICATE-----\n" 72 | 73 | hostPrivateKey = "-----BEGIN PRIVATE KEY-----\n" + keyPair.getPrivate().getEncoded().tostring().encode("base64") + "-----END PRIVATE KEY-----\n" 74 | 75 | certGen.setPublicKey(pubKey) 76 | dnName = X500Principal("CN=pyMobileDevice Self-Signed Device Certificate") 77 | certGen.setSubjectDN(dnName) 78 | 79 | deviceCertificate = "-----BEGIN CERTIFICATE-----\n" + certGen.generate(keyPair.getPrivate(), "BC").getEncoded().tostring().encode("base64") + "-----END CERTIFICATE-----\n" 80 | 81 | return hostCertificate, hostPrivateKey, deviceCertificate 82 | -------------------------------------------------------------------------------- /diagnostics_relay.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | from pprint import pprint 22 | from lockdown import LockdownClient 23 | 24 | MobileGestaltKeys = [ 25 | "DieId", "SerialNumber", "UniqueChipID", "WifiAddress", "CPUArchitecture", "BluetoothAddress", 26 | "EthernetMacAddress", "FirmwareVersion", "MLBSerialNumber", "ModelNumber", "RegionInfo", "RegionCode", 27 | "DeviceClass", "ProductType", "DeviceName", "UserAssignedDeviceName", "HWModelStr", "SigningFuse", 28 | "SoftwareBehavior", "SupportedKeyboards", "BuildVersion", "ProductVersion", "ReleaseType", "InternalBuild", 29 | "CarrierInstallCapability", "IsUIBuild", "InternationalMobileEquipmentIdentity", "MobileEquipmentIdentifier", 30 | "DeviceColor", "HasBaseband", "SupportedDeviceFamilies", "SoftwareBundleVersion", "SDIOManufacturerTuple", 31 | "SDIOProductInfo", "UniqueDeviceID", "InverseDeviceID", "ChipID", "PartitionType", "ProximitySensorCalibration", 32 | "CompassCalibration", "WirelessBoardSnum", "BasebandBoardSnum", "HardwarePlatform", "RequiredBatteryLevelForSoftwareUpdate", 33 | "IsThereEnoughBatteryLevelForSoftwareUpdate", "BasebandRegionSKU", "encrypted-data-partition", "SysCfg", "DiagData", 34 | "SIMTrayStatus", "CarrierBundleInfoArray", "AllDeviceCapabilities", "wi-fi", "SBAllowSensitiveUI", "green-tea", 35 | "not-green-tea", "AllowYouTube", "AllowYouTubePlugin", "SBCanForceDebuggingInfo", "AppleInternalInstallCapability", 36 | "HasAllFeaturesCapability", "ScreenDimensions", "IsSimulator", "BasebandSerialNumber", "BasebandChipId", "BasebandCertId", 37 | "BasebandSkeyId", "BasebandFirmwareVersion", "cellular-data", "contains-cellular-radio", "RegionalBehaviorGoogleMail", 38 | "RegionalBehaviorVolumeLimit", "RegionalBehaviorShutterClick", "RegionalBehaviorNTSC", "RegionalBehaviorNoWiFi", 39 | "RegionalBehaviorChinaBrick", "RegionalBehaviorNoVOIP", "RegionalBehaviorAll", "ApNonce" 40 | ] 41 | 42 | 43 | class DIAGClient(object): 44 | def __init__(self, lockdown=None, serviceName="com.apple.mobile.diagnostics_relay"): 45 | if lockdown: 46 | self.lockdown = lockdown 47 | else: 48 | self.lockdown = LockdownClient() 49 | 50 | self.service = self.lockdown.startService(serviceName) 51 | self.packet_num = 0 52 | 53 | def stop_session(self): 54 | print "Disconecting..." 55 | self.service.close() 56 | 57 | def query_mobilegestalt(self, MobileGestalt=MobileGestaltKeys): 58 | self.service.sendPlist({"Request": "MobileGestalt", "MobileGestaltKeys": MobileGestalt}) 59 | res = self.service.recvPlist() 60 | #pprint(res) 61 | if "Diagnostics" in res: 62 | return res 63 | 64 | def action(self, action="Shutdown", flags=None): 65 | self.service.sendPlist({"Request": action}) 66 | res = self.service.recvPlist() 67 | #pprint(res) 68 | return res 69 | 70 | def restart(self): 71 | return self.action("Restart") 72 | 73 | def shutdown(self): 74 | return self.action("Shutdown") 75 | 76 | def diagnostics(self, diagType="All"): 77 | self.service.sendPlist({"Request": diagType}) 78 | res = self.service.recvPlist() 79 | pprint(res) 80 | if "Diagnostics" in res: 81 | return res 82 | 83 | def ioregistry_entry(self, name=None, ioclass=None): 84 | req = {"Request": "IORegistry"} 85 | if name: 86 | req["EntryName"] = name 87 | 88 | if ioclass: 89 | req["EntryClass"] = ioclass 90 | 91 | self.service.sendPlist(req) 92 | res = self.service.recvPlist() 93 | pprint(res) 94 | if "Diagnostics" in res: 95 | return res 96 | 97 | def ioregistry_plane(self, plane, ioclass): 98 | req = {"Request": "IORegistry", "CurrentPlane": ioclass} 99 | self.service.sendPlist(req) 100 | res = self.service.recvPlist() 101 | pprint(res) 102 | if "Diagnostics" in res: 103 | return res 104 | 105 | 106 | if __name__ == "__main__": 107 | lockdown = LockdownClient() 108 | ProductVersion = lockdown.getValue("", "ProductVersion") 109 | assert ProductVersion[0] >= "4" 110 | 111 | diag = DIAGClient() 112 | diag.diagnostics() 113 | diag.query_mobilegestalt() 114 | diag.restart() 115 | -------------------------------------------------------------------------------- /file_relay.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | from lockdown import LockdownClient 22 | 23 | SRCFILES = ["AppleSupport", "Network", "UserDatabases", "CrashReporter", "tmp", "SystemConfiguration", "WiFi", "VPN", "Caches"] 24 | 25 | 26 | class FileRelayClient(object): 27 | def __init__(self, lockdown=None, serviceName="com.apple.mobile.file_relay"): 28 | if lockdown: 29 | self.lockdown = lockdown 30 | else: 31 | self.lockdown = LockdownClient() 32 | 33 | self.service = self.lockdown.startService(serviceName) 34 | self.packet_num = 0 35 | 36 | def stop_session(self): 37 | print "Disconecting..." 38 | self.service.close() 39 | 40 | def request_sources(self, sources=["UserDatabases"]): 41 | print "Downloading sources ", sources 42 | self.service.sendPlist({"Sources": sources}) 43 | res = self.service.recvPlist() 44 | if res and res.get("Status") == "Acknowledged": 45 | z = "" 46 | while True: 47 | x = self.service.recv() 48 | if not x: 49 | break 50 | z += x 51 | return z 52 | 53 | if __name__ == "__main__": 54 | lockdown = LockdownClient() 55 | ProductVersion = lockdown.getValue("", "ProductVersion") 56 | assert ProductVersion[0] >= "4" 57 | 58 | fc = FileRelayClient() 59 | f = fc.request_sources(SRCFILES) 60 | #f = fc.request_sources(["SystemConfiguration"]) 61 | if f: 62 | open("fileRelayTest.gz", "wb").write(f) 63 | -------------------------------------------------------------------------------- /libs/java/bcprov-jdk15on-150.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/java/bcprov-jdk15on-150.jar -------------------------------------------------------------------------------- /libs/java/junixsocket-1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/java/junixsocket-1.3.jar -------------------------------------------------------------------------------- /libs/java/not-yet-commons-ssl-0.3.11.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/java/not-yet-commons-ssl-0.3.11.jar -------------------------------------------------------------------------------- /libs/native/libjunixsocket-linux-1.5-amd64.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/native/libjunixsocket-linux-1.5-amd64.so -------------------------------------------------------------------------------- /libs/native/libjunixsocket-linux-1.5-i386.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/native/libjunixsocket-linux-1.5-i386.so -------------------------------------------------------------------------------- /libs/native/libjunixsocket-macosx-1.5-i386.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/native/libjunixsocket-macosx-1.5-i386.dylib -------------------------------------------------------------------------------- /libs/native/libjunixsocket-macosx-1.5-x86_64.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/native/libjunixsocket-macosx-1.5-x86_64.dylib -------------------------------------------------------------------------------- /libs/python/construct/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Construct 2 -- Parsing Made Fun 3 | 4 | Homepage: 5 | http://construct.readthedocs.org 6 | 7 | Hands-on example: 8 | >>> from construct import * 9 | >>> s = Struct("foo", 10 | ... UBInt8("a"), 11 | ... UBInt16("b"), 12 | ... ) 13 | >>> print s.parse(b"\\x01\\x02\\x03") 14 | Container: 15 | a = 1 16 | b = 515 17 | >>> s.build(Container(a = 1, b = 0x0203)) 18 | b"\\x01\\x02\\x03" 19 | """ 20 | 21 | from construct.core import (AdaptationError, Adapter, Anchor, ArrayError, Buffered, Construct, ConstructError, 22 | Container, FieldError, FormatField, LazyBound, LazyContainer, ListContainer, MetaArray, MetaField, OnDemand, 23 | OverwriteError, Packer, Pass, Peek, Pointer, Range, RangeError, Reconfig, RepeatUntil, Restream, Select, 24 | SelectError, Sequence, SizeofError, StaticField, Struct, Subconstruct, Switch, SwitchError, Terminator, 25 | TerminatorError, ULInt24, Union, Value) 26 | from construct.adapters import (BitIntegerAdapter, BitIntegerError, CStringAdapter, ConstAdapter, ConstError, 27 | ExprAdapter, FlagsAdapter, FlagsContainer, HexDumpAdapter, HexString, IndexingAdapter, LengthValueAdapter, 28 | MappingAdapter, MappingError, NoneOf, OneOf, PaddedStringAdapter, PaddingAdapter, PaddingError, SlicingAdapter, 29 | StringAdapter, TunnelAdapter, ValidationError, Validator) 30 | from construct.macros import (Alias, Aligned, AlignedStruct, Array, BFloat32, BFloat64, Bit, BitField, 31 | BitStreamReader, BitStreamWriter, BitStruct, Bitwise, CString, Embedded, EmbeddedBitStruct, Enum, Field, 32 | Flag, FlagsEnum, GreedyRange, If, IfThenElse, LFloat32, LFloat64, Magic, NFloat32, NFloat64, Nibble, Octet, 33 | OnDemandPointer, OpenRange, Optional, OptionalGreedyRange, Padding, PascalString, PrefixedArray, 34 | Rename, SBInt16, SBInt32, SBInt64, SBInt8, SLInt16, SLInt32, SLInt64, SLInt8, SNInt16, SNInt32, SNInt64, 35 | SNInt8, SeqOfOne, String, SymmetricMapping, UBInt16, UBInt32, UBInt64, UBInt8, ULInt16, ULInt32, ULInt64, 36 | ULInt8, UNInt16, UNInt32, UNInt64, UNInt8) 37 | from construct.lib.expr import this 38 | from construct.debug import Probe, Debugger 39 | from construct.version import version, version_string as __version__ 40 | 41 | 42 | #=============================================================================== 43 | # Metadata 44 | #=============================================================================== 45 | __author__ = "Tomer Filiba , Corbin Simpson " 46 | 47 | #=============================================================================== 48 | # Shorthand expressions 49 | #=============================================================================== 50 | Bits = BitField 51 | Byte = UBInt8 52 | Bytes = Field 53 | Const = ConstAdapter 54 | Tunnel = TunnelAdapter 55 | Embed = Embedded 56 | 57 | #=============================================================================== 58 | # exposed names 59 | #=============================================================================== 60 | __all__ = [ 61 | 'AdaptationError', 'Adapter', 'Alias', 'Aligned', 'AlignedStruct', 'Anchor', 'Array', 'ArrayError', 62 | 'BFloat32', 'BFloat64', 'Bit', 'BitField', 'BitIntegerAdapter', 'BitIntegerError', 'BitStreamReader', 63 | 'BitStreamWriter', 'BitStruct', 'Bitwise', 'Buffered', 'CString', 'CStringAdapter', 'ConstAdapter', 64 | 'ConstError', 'Construct', 'ConstructError', 'Container', 'Debugger', 'Embedded', 'EmbeddedBitStruct', 65 | 'Enum', 'ExprAdapter', 'Field', 'FieldError', 'Flag', 'FlagsAdapter', 'FlagsContainer', 'FlagsEnum', 66 | 'FormatField', 'GreedyRange', 'HexDumpAdapter', 'HexString', 'If', 'IfThenElse', 'IndexingAdapter', 67 | 'LFloat32', 'LFloat64', 'LazyBound', 'LazyContainer', 'LengthValueAdapter', 'ListContainer', 'Magic', 68 | 'MappingAdapter', 'MappingError', 'MetaArray', 'MetaField', 'NFloat32', 'NFloat64', 'Nibble', 'NoneOf', 69 | 'Octet', 'OnDemand', 'OnDemandPointer', 'OneOf', 'OpenRange', 'Optional', 'OptionalGreedyRange', 70 | 'OverwriteError', 'Packer', 'PaddedStringAdapter', 'Padding', 'PaddingAdapter', 'PaddingError', 71 | 'PascalString', 'Pass', 'Peek', 'Pointer', 'PrefixedArray', 'Probe', 'Range', 'RangeError', 'Reconfig', 72 | 'Rename', 'RepeatUntil', 'Restream', 'SBInt16', 'SBInt32', 'SBInt64', 'SBInt8', 'SLInt16', 'SLInt32', 73 | 'SLInt64', 'SLInt8', 'SNInt16', 'SNInt32', 'SNInt64', 'SNInt8', 'Select', 'SelectError', 'SeqOfOne', 74 | 'Sequence', 'SizeofError', 'SlicingAdapter', 'StaticField', 'String', 'StringAdapter', 'Struct', 75 | 'Subconstruct', 'Switch', 'SwitchError', 'SymmetricMapping', 'Terminator', 'TerminatorError', 76 | 'TunnelAdapter', 'UBInt16', 'UBInt32', 'UBInt64', 'UBInt8', 'ULInt16', 'ULInt24', 'ULInt32', 'ULInt64', 77 | 'ULInt8', 'UNInt16', 'UNInt32', 'UNInt64', 'UNInt8', 'Union', 'ValidationError', 'Validator', 'Value', 78 | 'this', 'Bits', 'Byte', 'Bytes', 'Const', 'Tunnel', 'Embed', 79 | ] 80 | -------------------------------------------------------------------------------- /libs/python/construct/debug.py: -------------------------------------------------------------------------------- 1 | """ 2 | Debugging utilities for constructs 3 | """ 4 | import sys 5 | import traceback 6 | import pdb 7 | import inspect 8 | from construct.core import Construct, Subconstruct 9 | from construct.lib import HexString, Container, ListContainer 10 | 11 | 12 | class Probe(Construct): 13 | """ 14 | A probe: dumps the context, stack frames, and stream content to the screen 15 | to aid the debugging process. 16 | See also Debugger. 17 | 18 | :param name: the display name 19 | :param show_stream: whether or not to show stream contents. default is True. the stream must be seekable. 20 | :param show_context: whether or not to show the context. default is True. 21 | :param show_stack: whether or not to show the upper stack frames. default is True. 22 | :param stream_lookahead: the number of bytes to dump when show_stack is set. default is 100. 23 | 24 | Example:: 25 | 26 | Struct("foo", 27 | UBInt8("a"), 28 | Probe("between a and b"), 29 | UBInt8("b"), 30 | ) 31 | """ 32 | __slots__ = [ 33 | "printname", "show_stream", "show_context", "show_stack", 34 | "stream_lookahead" 35 | ] 36 | counter = 0 37 | 38 | def __init__(self, name = None, show_stream = True, 39 | show_context = True, show_stack = True, 40 | stream_lookahead = 100): 41 | Construct.__init__(self, None) 42 | if name is None: 43 | Probe.counter += 1 44 | name = "" % (Probe.counter,) 45 | self.printname = name 46 | self.show_stream = show_stream 47 | self.show_context = show_context 48 | self.show_stack = show_stack 49 | self.stream_lookahead = stream_lookahead 50 | def __repr__(self): 51 | return "%s(%r)" % (self.__class__.__name__, self.printname) 52 | def _parse(self, stream, context): 53 | self.printout(stream, context) 54 | def _build(self, obj, stream, context): 55 | self.printout(stream, context) 56 | def _sizeof(self, context): 57 | return 0 58 | 59 | def printout(self, stream, context): 60 | obj = Container() 61 | if self.show_stream: 62 | obj.stream_position = stream.tell() 63 | follows = stream.read(self.stream_lookahead) 64 | if not follows: 65 | obj.following_stream_data = "EOF reached" 66 | else: 67 | stream.seek(-len(follows), 1) 68 | obj.following_stream_data = HexString(follows) 69 | print("") 70 | 71 | if self.show_context: 72 | obj.context = context 73 | 74 | if self.show_stack: 75 | obj.stack = ListContainer() 76 | frames = [s[0] for s in inspect.stack()][1:-1] 77 | frames.reverse() 78 | for f in frames: 79 | a = Container() 80 | a.__update__(f.f_locals) 81 | obj.stack.append(a) 82 | 83 | print("=" * 80) 84 | print("Probe %s" % (self.printname,)) 85 | print(obj) 86 | print("=" * 80) 87 | 88 | class Debugger(Subconstruct): 89 | """ 90 | A pdb-based debugger. When an exception occurs in the subcon, a debugger 91 | will appear and allow you to debug the error (and even fix on-the-fly). 92 | 93 | :param subcon: the subcon to debug 94 | 95 | Example:: 96 | 97 | Debugger( 98 | Enum(UBInt8("foo"), 99 | a = 1, 100 | b = 2, 101 | c = 3 102 | ) 103 | ) 104 | """ 105 | __slots__ = ["retval"] 106 | def _parse(self, stream, context): 107 | try: 108 | return self.subcon._parse(stream, context) 109 | except Exception: 110 | self.retval = NotImplemented 111 | self.handle_exc("(you can set the value of 'self.retval', " 112 | "which will be returned)") 113 | if self.retval is NotImplemented: 114 | raise 115 | else: 116 | return self.retval 117 | def _build(self, obj, stream, context): 118 | try: 119 | self.subcon._build(obj, stream, context) 120 | except Exception: 121 | self.handle_exc() 122 | def handle_exc(self, msg = None): 123 | print("=" * 80) 124 | print("Debugging exception of %s:" % (self.subcon,)) 125 | print("".join(traceback.format_exception(*sys.exc_info())[1:])) 126 | if msg: 127 | print(msg) 128 | pdb.post_mortem(sys.exc_info()[2]) 129 | print("=" * 80) 130 | 131 | -------------------------------------------------------------------------------- /libs/python/construct/formats/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/python/construct/formats/__init__.py -------------------------------------------------------------------------------- /libs/python/construct/formats/data/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | all sorts of raw data serialization (tcpdump capture files, etc.) 3 | """ 4 | -------------------------------------------------------------------------------- /libs/python/construct/formats/data/cap.py: -------------------------------------------------------------------------------- 1 | """ 2 | tcpdump capture file 3 | """ 4 | from construct import * 5 | import time 6 | from datetime import datetime 7 | 8 | 9 | class MicrosecAdapter(Adapter): 10 | def _decode(self, obj, context): 11 | return datetime.fromtimestamp(obj[0] + (obj[1] / 1000000.0)) 12 | def _encode(self, obj, context): 13 | offset = time.mktime(*obj.timetuple()) 14 | sec = int(offset) 15 | usec = (offset - sec) * 1000000 16 | return (sec, usec) 17 | 18 | packet = Struct("packet", 19 | MicrosecAdapter( 20 | Sequence("time", 21 | ULInt32("time"), 22 | ULInt32("usec"), 23 | ) 24 | ), 25 | ULInt32("length"), 26 | Padding(4), 27 | HexDumpAdapter(Field("data", lambda ctx: ctx.length)), 28 | ) 29 | 30 | cap_file = Struct("cap_file", 31 | Padding(24), 32 | Rename("packets", OptionalGreedyRange(packet)), 33 | ) 34 | 35 | 36 | if __name__ == "__main__": 37 | obj = cap_file.parse_stream(open("../../tests/cap2.cap", "rb")) 38 | print(len(obj.packets)) 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /libs/python/construct/formats/data/snoop.py: -------------------------------------------------------------------------------- 1 | """ 2 | what : snoop v2 capture file. 3 | how : http://tools.ietf.org/html/rfc1761 4 | who : jesse @ housejunkie . ca 5 | """ 6 | 7 | import time 8 | from construct import (Adapter, Enum, Field, HexDumpAdapter, Magic, OptionalGreedyRange, 9 | Padding, Struct, UBInt32) 10 | 11 | class EpochTimeStampAdapter(Adapter): 12 | """ Convert epoch timestamp <-> localtime """ 13 | 14 | def _decode(self, obj, context): 15 | return time.ctime(obj) 16 | def _encode(self, obj, context): 17 | return int(time.mktime(time.strptime(obj))) 18 | 19 | packet_record = Struct("packet_record", 20 | UBInt32("original_length"), 21 | UBInt32("included_length"), 22 | UBInt32("record_length"), 23 | UBInt32("cumulative_drops"), 24 | EpochTimeStampAdapter(UBInt32("timestamp_seconds")), 25 | UBInt32("timestamp_microseconds"), 26 | HexDumpAdapter(Field("data", lambda ctx: ctx.included_length)), 27 | # 24 being the static length of the packet_record header 28 | Padding(lambda ctx: ctx.record_length - ctx.included_length - 24), 29 | ) 30 | 31 | datalink_type = Enum(UBInt32("datalink"), 32 | IEEE802dot3 = 0, 33 | IEEE802dot4 = 1, 34 | IEEE802dot5 = 2, 35 | IEEE802dot6 = 3, 36 | ETHERNET = 4, 37 | HDLC = 5, 38 | CHARSYNC = 6, 39 | IBMCHANNEL = 7, 40 | FDDI = 8, 41 | OTHER = 9, 42 | UNASSIGNED = 10, 43 | ) 44 | 45 | snoop_file = Struct("snoop", 46 | Magic("snoop\x00\x00\x00"), 47 | UBInt32("version"), # snoop v1 is deprecated 48 | datalink_type, 49 | OptionalGreedyRange(packet_record), 50 | ) 51 | -------------------------------------------------------------------------------- /libs/python/construct/formats/executable/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/python/construct/formats/executable/__init__.py -------------------------------------------------------------------------------- /libs/python/construct/formats/executable/elf32.py: -------------------------------------------------------------------------------- 1 | """ 2 | Executable and Linkable Format (ELF), 32 bit, big or little endian 3 | Used on *nix systems as a replacement of the older a.out format 4 | 5 | Big-endian support kindly submitted by Craig McQueen (mcqueen-c#edsrd1!yzk!co!jp) 6 | """ 7 | from construct import * 8 | import six 9 | 10 | 11 | def elf32_body(ElfInt16, ElfInt32): 12 | elf32_program_header = Struct("program_header", 13 | Enum(ElfInt32("type"), 14 | NULL = 0, 15 | LOAD = 1, 16 | DYNAMIC = 2, 17 | INTERP = 3, 18 | NOTE = 4, 19 | SHLIB = 5, 20 | PHDR = 6, 21 | _default_ = Pass, 22 | ), 23 | ElfInt32("offset"), 24 | ElfInt32("vaddr"), 25 | ElfInt32("paddr"), 26 | ElfInt32("file_size"), 27 | ElfInt32("mem_size"), 28 | ElfInt32("flags"), 29 | ElfInt32("align"), 30 | ) 31 | 32 | elf32_section_header = Struct("section_header", 33 | ElfInt32("name_offset"), 34 | Pointer(lambda ctx: ctx._.strtab_data_offset + ctx.name_offset, 35 | CString("name") 36 | ), 37 | Enum(ElfInt32("type"), 38 | NULL = 0, 39 | PROGBITS = 1, 40 | SYMTAB = 2, 41 | STRTAB = 3, 42 | RELA = 4, 43 | HASH = 5, 44 | DYNAMIC = 6, 45 | NOTE = 7, 46 | NOBITS = 8, 47 | REL = 9, 48 | SHLIB = 10, 49 | DYNSYM = 11, 50 | _default_ = Pass, 51 | ), 52 | ElfInt32("flags"), 53 | ElfInt32("addr"), 54 | ElfInt32("offset"), 55 | ElfInt32("size"), 56 | ElfInt32("link"), 57 | ElfInt32("info"), 58 | ElfInt32("align"), 59 | ElfInt32("entry_size"), 60 | OnDemandPointer(lambda ctx: ctx.offset, 61 | HexDumpAdapter(Field("data", lambda ctx: ctx.size)) 62 | ), 63 | ) 64 | 65 | return Struct("body", 66 | Enum(ElfInt16("type"), 67 | NONE = 0, 68 | RELOCATABLE = 1, 69 | EXECUTABLE = 2, 70 | SHARED = 3, 71 | CORE = 4, 72 | ), 73 | Enum(ElfInt16("machine"), 74 | NONE = 0, 75 | M32 = 1, 76 | SPARC = 2, 77 | I386 = 3, 78 | Motorolla68K = 4, 79 | Motorolla88K = 5, 80 | Intel860 = 7, 81 | MIPS = 8, 82 | _default_ = Pass 83 | ), 84 | ElfInt32("version"), 85 | ElfInt32("entry"), 86 | ElfInt32("ph_offset"), 87 | ElfInt32("sh_offset"), 88 | ElfInt32("flags"), 89 | ElfInt16("header_size"), 90 | ElfInt16("ph_entry_size"), 91 | ElfInt16("ph_count"), 92 | ElfInt16("sh_entry_size"), 93 | ElfInt16("sh_count"), 94 | ElfInt16("strtab_section_index"), 95 | 96 | # calculate the string table data offset (pointer arithmetics) 97 | # ugh... anyway, we need it in order to read the section names, later on 98 | Pointer(lambda ctx: 99 | ctx.sh_offset + ctx.strtab_section_index * ctx.sh_entry_size + 16, 100 | ElfInt32("strtab_data_offset"), 101 | ), 102 | 103 | # program header table 104 | Rename("program_table", 105 | Pointer(lambda ctx: ctx.ph_offset, 106 | Array(lambda ctx: ctx.ph_count, 107 | elf32_program_header 108 | ) 109 | ) 110 | ), 111 | 112 | # section table 113 | Rename("sections", 114 | Pointer(lambda ctx: ctx.sh_offset, 115 | Array(lambda ctx: ctx.sh_count, 116 | elf32_section_header 117 | ) 118 | ) 119 | ), 120 | ) 121 | 122 | elf32_body_little_endian = elf32_body(ULInt16, ULInt32) 123 | elf32_body_big_endian = elf32_body(UBInt16, UBInt32) 124 | 125 | elf32_file = Struct("elf32_file", 126 | Struct("identifier", 127 | Magic(six.b("\x7fELF")), 128 | Enum(Byte("file_class"), 129 | NONE = 0, 130 | CLASS32 = 1, 131 | CLASS64 = 2, 132 | ), 133 | Enum(Byte("encoding"), 134 | NONE = 0, 135 | LSB = 1, 136 | MSB = 2, 137 | ), 138 | Byte("version"), 139 | Padding(9), 140 | ), 141 | Embedded(IfThenElse("body", lambda ctx: ctx.identifier.encoding == "LSB", 142 | elf32_body_little_endian, 143 | elf32_body_big_endian, 144 | )), 145 | ) 146 | 147 | 148 | if __name__ == "__main__": 149 | obj = elf32_file.parse_stream(open("../../../tests/_ctypes_test.so", "rb")) 150 | #[s.data.value for s in obj.sections] 151 | print(obj) 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /libs/python/construct/formats/filesystem/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | file systems on-disk formats (ext2, fat32, ntfs, ...) 3 | and related disk formats (mbr, ...) 4 | """ 5 | -------------------------------------------------------------------------------- /libs/python/construct/formats/filesystem/ext2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Extension 2 (ext2) 3 | Used in Linux systems 4 | """ 5 | from construct import * 6 | 7 | 8 | Char = SLInt8 9 | UChar = ULInt8 10 | Short = SLInt16 11 | UShort = ULInt16 12 | Long = SLInt32 13 | ULong = ULInt32 14 | 15 | def BlockPointer(name): 16 | return Struct(name, 17 | ULong("block_number"), 18 | OnDemandPointer(lambda ctx: ctx["block_number"]), 19 | ) 20 | 21 | superblock = Struct("superblock", 22 | ULong('inodes_count'), 23 | ULong('blocks_count'), 24 | ULong('reserved_blocks_count'), 25 | ULong('free_blocks_count'), 26 | ULong('free_inodes_count'), 27 | ULong('first_data_block'), 28 | Enum(ULong('log_block_size'), 29 | OneKB = 0, 30 | TwoKB = 1, 31 | FourKB = 2, 32 | ), 33 | Long('log_frag_size'), 34 | ULong('blocks_per_group'), 35 | ULong('frags_per_group'), 36 | ULong('inodes_per_group'), 37 | ULong('mtime'), 38 | ULong('wtime'), 39 | UShort('mnt_count'), 40 | Short('max_mnt_count'), 41 | Const(UShort('magic'), 0xEF53), 42 | UShort('state'), 43 | UShort('errors'), 44 | Padding(2), 45 | ULong('lastcheck'), 46 | ULong('checkinterval'), 47 | ULong('creator_os'), 48 | ULong('rev_level'), 49 | Padding(235 * 4), 50 | ) 51 | 52 | group_descriptor = Struct("group_descriptor", 53 | ULong('block_bitmap'), 54 | ULong('inode_bitmap'), 55 | ULong('inode_table'), 56 | UShort('free_blocks_count'), 57 | UShort('free_inodes_count'), 58 | UShort('used_dirs_count'), 59 | Padding(14), 60 | ) 61 | 62 | inode = Struct("inode", 63 | FlagsEnum(UShort('mode'), 64 | IXOTH = 0x0001, 65 | IWOTH = 0x0002, 66 | IROTH = 0x0004, 67 | IRWXO = 0x0007, 68 | IXGRP = 0x0008, 69 | IWGRP = 0x0010, 70 | IRGRP = 0x0020, 71 | IRWXG = 0x0038, 72 | IXUSR = 0x0040, 73 | IWUSR = 0x0080, 74 | IRUSR = 0x0100, 75 | IRWXU = 0x01C0, 76 | ISVTX = 0x0200, 77 | ISGID = 0x0400, 78 | ISUID = 0x0800, 79 | IFIFO = 0x1000, 80 | IFCHR = 0x2000, 81 | IFDIR = 0x4000, 82 | IFBLK = 0x6000, 83 | IFREG = 0x8000, 84 | IFLNK = 0xC000, 85 | IFSOCK = 0xA000, 86 | IFMT = 0xF000, 87 | ), 88 | UShort('uid'), 89 | ULong('size'), 90 | ULong('atime'), 91 | ULong('ctime'), 92 | ULong('mtime'), 93 | ULong('dtime'), 94 | UShort('gid'), 95 | UShort('links_count'), 96 | ULong('blocks'), 97 | FlagsEnum(ULong('flags'), 98 | SecureDelete = 0x0001, 99 | AllowUndelete = 0x0002, 100 | Compressed = 0x0004, 101 | Synchronous = 0x0008, 102 | ), 103 | Padding(4), 104 | Array(12, ULong('blocks')), 105 | ULong("indirect1_block"), 106 | ULong("indirect2_block"), 107 | ULong("indirect3_block"), 108 | ULong('version'), 109 | ULong('file_acl'), 110 | ULong('dir_acl'), 111 | ULong('faddr'), 112 | UChar('frag'), 113 | Byte('fsize'), 114 | Padding(10) , 115 | ) 116 | 117 | # special inodes 118 | EXT2_BAD_INO = 1 119 | EXT2_ROOT_INO = 2 120 | EXT2_ACL_IDX_INO = 3 121 | EXT2_ACL_DATA_INO = 4 122 | EXT2_BOOT_LOADER_INO = 5 123 | EXT2_UNDEL_DIR_INO = 6 124 | EXT2_FIRST_INO = 11 125 | 126 | directory_record = Struct("directory_entry", 127 | ULong("inode"), 128 | UShort("rec_length"), 129 | UShort("name_length"), 130 | Field("name", lambda ctx: ctx["name_length"]), 131 | Padding(lambda ctx: ctx["rec_length"] - ctx["name_length"]) 132 | ) 133 | 134 | if __name__ == "__main__": 135 | print (superblock.sizeof()) 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /libs/python/construct/formats/filesystem/fat16.py: -------------------------------------------------------------------------------- 1 | # fat.py; ad-hoc fat16 reader 2 | # by Bram Westerbaan 3 | # 4 | # references: 5 | # http://en.wikipedia.org/wiki/File_Allocation_Table 6 | # http://www.ecma-international.org/publications/standards/Ecma-107.htm 7 | # 8 | # example: 9 | # with open("/dev/sdc1") as file: 10 | # fs = FatFs(file) 11 | # for rootdir in fs: 12 | # print rootdir 13 | import numbers 14 | from io import BytesIO, BufferedReader 15 | from construct import Struct, Byte, Bytes, ULInt16, ULInt32, Enum, \ 16 | Array, Padding, Embed, Pass, BitStruct, Flag, Const 17 | 18 | 19 | def Fat16Header(name): 20 | return Struct(name, 21 | Bytes("jumpInstruction", 3), 22 | Bytes("creatingSystemId", 8), 23 | ULInt16("sectorSize"), 24 | Byte("sectorsPerCluster"), 25 | ULInt16("reservedSectorCount"), 26 | Byte("fatCount"), 27 | ULInt16("rootdirEntryCount"), 28 | ULInt16("sectorCount_small"), 29 | Byte("mediaId"), 30 | ULInt16("sectorsPerFat"), 31 | ULInt16("sectorsPerTrack"), 32 | ULInt16("sideCount"), 33 | ULInt32("hiddenSectorCount"), 34 | ULInt32("sectorCount_large"), 35 | Byte("physicalDriveNumber"), 36 | Byte("currentHead"), 37 | Byte("extendedBootSignature"), 38 | Bytes("volumeId", 4), 39 | Bytes("volumeLabel", 11), 40 | Const(Bytes("fsType", 8), "FAT16 "), 41 | Bytes("bootCode", 448), 42 | Const(Bytes("bootSectorSignature", 2), "\x55\xaa")) 43 | 44 | def BootSector(name): 45 | header = Fat16Header("header") 46 | return Struct(name, 47 | Embed(header), 48 | Padding(lambda ctx: ctx.sectorSize - header.sizeof())) 49 | 50 | def FatEntry(name): 51 | return Enum(ULInt16(name), 52 | free_cluster = 0x0000, 53 | bad_cluster = 0xfff7, 54 | last_cluster = 0xffff, 55 | _default_ = Pass) 56 | 57 | def DirEntry(name): 58 | return Struct(name, 59 | Bytes("name", 8), 60 | Bytes("extension", 3), 61 | BitStruct("attributes", 62 | Flag("unused"), 63 | Flag("device"), 64 | Flag("archive"), 65 | Flag("subDirectory"), 66 | Flag("volumeLabel"), 67 | Flag("system"), 68 | Flag("hidden"), 69 | Flag("readonly")), 70 | # reserved 71 | Padding(10), 72 | ULInt16("timeRecorded"), 73 | ULInt16("dateRecorded"), 74 | ULInt16("firstCluster"), 75 | ULInt32("fileSize")) 76 | 77 | def PreDataRegion(name): 78 | rde = DirEntry("rootdirs") 79 | fe = FatEntry("fats") 80 | return Struct(name, 81 | Embed(BootSector("bootSector")), 82 | # the remaining reserved sectors 83 | Padding(lambda ctx: (ctx.reservedSectorCount - 1) 84 | * ctx.sectorSize), 85 | # file allocation tables 86 | Array(lambda ctx: (ctx.fatCount), 87 | Array(lambda ctx: ctx.sectorsPerFat * 88 | ctx.sectorSize / fe.sizeof(), fe)), 89 | # root directories 90 | Array(lambda ctx: (ctx.rootdirEntryCount*rde.sizeof()) 91 | / ctx.sectorSize, rde)) 92 | 93 | class File(object): 94 | def __init__(self, dirEntry, fs): 95 | self.fs = fs 96 | self.dirEntry = dirEntry 97 | 98 | @classmethod 99 | def fromDirEntry(cls, dirEntry, fs): 100 | if dirEntry.name[0] in "\x00\xe5\x2e": 101 | return None 102 | a = dirEntry.attributes 103 | #Long file name directory entry 104 | if a.volumeLabel and a.system and a.hidden and a.readonly: 105 | return None 106 | if a.subDirectory: 107 | return Directory(dirEntry, fs) 108 | return File(dirEntry, fs) 109 | 110 | @classmethod 111 | def fromDirEntries(cls, dirEntries, fs): 112 | return filter(None, [cls.fromDirEntry(de, fs) 113 | for de in dirEntries]) 114 | 115 | def toStream(self, stream): 116 | self.fs.fileToStream(self.dirEntry.firstCluster, stream) 117 | 118 | @property 119 | def name(self): 120 | return "%s.%s" % (self.dirEntry.name.rstrip(), 121 | self.dirEntry.extension) 122 | 123 | def __str__(self): 124 | return "&%s %s" % (self.dirEntry.firstCluster, self.name) 125 | 126 | class Directory(File): 127 | def __init__(self, dirEntry, fs, children=None): 128 | File.__init__(self, dirEntry, fs) 129 | self.children = children 130 | if not self.children: 131 | self.children = File.fromDirEntries(\ 132 | self.fs.getDirEntries(\ 133 | self.dirEntry.firstCluster), fs) 134 | 135 | @property 136 | def name(self): 137 | return self.dirEntry.name.rstrip() 138 | 139 | def __str__(self): 140 | return "&%s %s/" % (self.dirEntry.firstCluster, self.name) 141 | 142 | def __getitem__(self, name): 143 | for file in self.children: 144 | if file.name == name: 145 | return file 146 | 147 | def __iter__(self): 148 | return iter(self.children) 149 | 150 | class FatFs(Directory): 151 | def __init__(self, stream): 152 | self.stream = stream 153 | self.pdr = PreDataRegion("pdr").parse_stream(stream) 154 | Directory.__init__(self, dirEntry = None, 155 | fs = self, children = File.fromDirEntries( 156 | self.pdr.rootdirs, self)) 157 | 158 | def fileToStream(self, clidx, stream): 159 | for clidx in self.getLinkedClusters(clidx): 160 | self.clusterToStream(clidx, stream) 161 | 162 | def clusterToStream(self, clidx, stream): 163 | start, todo = self.getClusterSlice(clidx) 164 | self.stream.seek(start) 165 | while todo > 0: 166 | read = self.stream.read(todo) 167 | if not len(read): 168 | print("failed to read %s bytes at %s" % (todo, self.stream.tell())) 169 | raise EOFError() 170 | todo -= len(read) 171 | stream.write(read) 172 | 173 | def getClusterSlice(self, clidx): 174 | startSector = self.pdr.reservedSectorCount \ 175 | + self.pdr.fatCount * self.pdr.sectorsPerFat \ 176 | + (self.pdr.rootdirEntryCount * 32) \ 177 | / self.pdr.sectorSize \ 178 | + (clidx-2) * self.pdr.sectorsPerCluster 179 | start = startSector * self.pdr.sectorSize 180 | length = self.pdr.sectorSize * self.pdr.sectorsPerCluster 181 | return (start, length) 182 | 183 | def getLinkedClusters(self, clidx): 184 | res = [] 185 | while clidx != "last_cluster": 186 | if not isinstance(clidx, numbers.Real): 187 | print(clidx) 188 | assert False 189 | assert 2 <= clidx <= 0xffef 190 | res.append(clidx) 191 | clidx = self.getNextCluster(clidx) 192 | assert clidx not in res 193 | return res 194 | 195 | def getNextCluster(self, clidx): 196 | ress = set([fat[clidx] for fat in self.pdr.fats]) 197 | if len(ress)==1: 198 | return ress.pop() 199 | print("inconsistencie between FATs: %s points to" % clidx) 200 | for i,fat in enumerate(self.pdr.fats): 201 | print("\t%s according to fat #%s" % (fat[clidx], i)) 202 | res = ress.pop() 203 | print ("assuming %s" % res) 204 | return res 205 | 206 | def getDirEntries(self, clidx): 207 | try: 208 | for de in self._getDirEntries(clidx): 209 | yield de 210 | except IOError: 211 | print("failed to read directory entries at %s" % clidx) 212 | 213 | def _getDirEntries(self, clidx): 214 | de = DirEntry("dirEntry") 215 | with BytesIO() as mem: 216 | self.fileToStream(clidx, mem) 217 | mem.seek(0) 218 | with BufferedReader(mem) as reader: 219 | while reader.peek(1): 220 | yield de.parse_stream(reader) 221 | def __str__(self): 222 | return "/" 223 | 224 | @property 225 | def name(self): 226 | return "" 227 | -------------------------------------------------------------------------------- /libs/python/construct/formats/filesystem/mbr.py: -------------------------------------------------------------------------------- 1 | """ 2 | Master Boot Record 3 | The first sector on disk, contains the partition table, bootloader, et al. 4 | 5 | http://www.win.tue.nl/~aeb/partitions/partition_types-1.html 6 | """ 7 | from construct import * 8 | from binascii import unhexlify 9 | import six 10 | 11 | 12 | mbr = Struct("mbr", 13 | HexDumpAdapter(Bytes("bootloader_code", 446)), 14 | Array(4, 15 | Struct("partitions", 16 | Enum(Byte("state"), 17 | INACTIVE = 0x00, 18 | ACTIVE = 0x80, 19 | ), 20 | BitStruct("beginning", 21 | Octet("head"), 22 | Bits("sect", 6), 23 | Bits("cyl", 10), 24 | ), 25 | Enum(UBInt8("type"), 26 | Nothing = 0x00, 27 | FAT12 = 0x01, 28 | XENIX_ROOT = 0x02, 29 | XENIX_USR = 0x03, 30 | FAT16_old = 0x04, 31 | Extended_DOS = 0x05, 32 | FAT16 = 0x06, 33 | FAT32 = 0x0b, 34 | FAT32_LBA = 0x0c, 35 | NTFS = 0x07, 36 | LINUX_SWAP = 0x82, 37 | LINUX_NATIVE = 0x83, 38 | _default_ = Pass, 39 | ), 40 | BitStruct("ending", 41 | Octet("head"), 42 | Bits("sect", 6), 43 | Bits("cyl", 10), 44 | ), 45 | UBInt32("sector_offset"), # offset from MBR in sectors 46 | UBInt32("size"), # in sectors 47 | ) 48 | ), 49 | Const(Bytes("signature", 2), six.b("\x55\xAA")), 50 | ) 51 | 52 | 53 | 54 | if __name__ == "__main__": 55 | cap1 = unhexlify(six.b( 56 | "33C08ED0BC007CFB5007501FFCBE1B7CBF1B065057B9E501F3A4CBBDBE07B104386E00" 57 | "7C09751383C510E2F4CD188BF583C610497419382C74F6A0B507B4078BF0AC3C0074FC" 58 | "BB0700B40ECD10EBF2884E10E84600732AFE4610807E040B740B807E040C7405A0B607" 59 | "75D2804602068346080683560A00E821007305A0B607EBBC813EFE7D55AA740B807E10" 60 | "0074C8A0B707EBA98BFC1E578BF5CBBF05008A5600B408CD1372238AC1243F988ADE8A" 61 | "FC43F7E38BD186D6B106D2EE42F7E239560A77237205394608731CB80102BB007C8B4E" 62 | "028B5600CD1373514F744E32E48A5600CD13EBE48A560060BBAA55B441CD13723681FB" 63 | "55AA7530F6C101742B61606A006A00FF760AFF76086A0068007C6A016A10B4428BF4CD" 64 | "136161730E4F740B32E48A5600CD13EBD661F9C3496E76616C69642070617274697469" 65 | "6F6E207461626C65004572726F72206C6F6164696E67206F7065726174696E67207379" 66 | "7374656D004D697373696E67206F7065726174696E672073797374656D000000000000" 67 | "0000000000000000000000000000000000000000000000000000000000000000000000" 68 | "00000000000000000000000000000000002C4463B7BDB7BD00008001010007FEFFFF3F" 69 | "000000371671020000C1FF0FFEFFFF761671028A8FDF06000000000000000000000000" 70 | "000000000000000000000000000000000000000055AA")) 71 | 72 | print(mbr.parse(cap1)) 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /libs/python/construct/formats/graphics/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | graphic file formats, including imagery (bmp, jpg, gif, png, ...), 3 | models (3ds, ...), etc. 4 | """ 5 | -------------------------------------------------------------------------------- /libs/python/construct/formats/graphics/bmp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Windows/OS2 Bitmap (BMP) 3 | this could have been a perfect show-case file format, but they had to make 4 | it ugly (all sorts of alignment or 5 | """ 6 | from construct import * 7 | 8 | 9 | #=============================================================================== 10 | # pixels: uncompressed 11 | #=============================================================================== 12 | def UncompressedRows(subcon, align_to_byte = False): 13 | """argh! lines must be aligned to a 4-byte boundary, and bit-pixel 14 | lines must be aligned to full bytes...""" 15 | if align_to_byte: 16 | line_pixels = Bitwise( 17 | Aligned(Array(lambda ctx: ctx.width, subcon), modulus = 8) 18 | ) 19 | else: 20 | line_pixels = Array(lambda ctx: ctx.width, subcon) 21 | return Array(lambda ctx: ctx.height, 22 | Aligned(line_pixels, modulus = 4) 23 | ) 24 | 25 | uncompressed_pixels = Switch("uncompressed", lambda ctx: ctx.bpp, 26 | { 27 | 1 : UncompressedRows(Bit("index"), align_to_byte = True), 28 | 4 : UncompressedRows(Nibble("index"), align_to_byte = True), 29 | 8 : UncompressedRows(Byte("index")), 30 | 24 : UncompressedRows( 31 | Sequence("rgb", Byte("red"), Byte("green"), Byte("blue")) 32 | ), 33 | } 34 | ) 35 | 36 | #=============================================================================== 37 | # pixels: Run Length Encoding (RLE) 8 bit 38 | #=============================================================================== 39 | class RunLengthAdapter(Adapter): 40 | def _encode(self, obj): 41 | return len(obj), obj[0] 42 | def _decode(self, obj): 43 | length, value = obj 44 | return [value] * length 45 | 46 | rle8pixel = RunLengthAdapter( 47 | Sequence("rle8pixel", 48 | Byte("length"), 49 | Byte("value") 50 | ) 51 | ) 52 | 53 | #=============================================================================== 54 | # file structure 55 | #=============================================================================== 56 | bitmap_file = Struct("bitmap_file", 57 | # header 58 | Const(String("signature", 2), "BM"), 59 | ULInt32("file_size"), 60 | Padding(4), 61 | ULInt32("data_offset"), 62 | ULInt32("header_size"), 63 | Enum(Alias("version", "header_size"), 64 | v2 = 12, 65 | v3 = 40, 66 | v4 = 108, 67 | ), 68 | ULInt32("width"), 69 | ULInt32("height"), 70 | Value("number_of_pixels", lambda ctx: ctx.width * ctx.height), 71 | ULInt16("planes"), 72 | ULInt16("bpp"), # bits per pixel 73 | Enum(ULInt32("compression"), 74 | Uncompressed = 0, 75 | RLE8 = 1, 76 | RLE4 = 2, 77 | Bitfields = 3, 78 | JPEG = 4, 79 | PNG = 5, 80 | ), 81 | ULInt32("image_data_size"), # in bytes 82 | ULInt32("horizontal_dpi"), 83 | ULInt32("vertical_dpi"), 84 | ULInt32("colors_used"), 85 | ULInt32("important_colors"), 86 | 87 | # palette (24 bit has no palette) 88 | OnDemand( 89 | Array(lambda ctx: 2 ** ctx.bpp if ctx.bpp <= 8 else 0, 90 | Struct("palette", 91 | Byte("blue"), 92 | Byte("green"), 93 | Byte("red"), 94 | Padding(1), 95 | ) 96 | ) 97 | ), 98 | 99 | # pixels 100 | OnDemandPointer(lambda ctx: ctx.data_offset, 101 | Switch("pixels", lambda ctx: ctx.compression, 102 | { 103 | "Uncompressed" : uncompressed_pixels, 104 | } 105 | ), 106 | ), 107 | ) 108 | 109 | 110 | if __name__ == "__main__": 111 | obj = bitmap_file.parse_stream(open("../../../tests/bitmap8.bmp", "rb")) 112 | print (obj) 113 | print (repr(obj.pixels.value)) 114 | -------------------------------------------------------------------------------- /libs/python/construct/formats/graphics/emf.py: -------------------------------------------------------------------------------- 1 | """ 2 | Enhanced Meta File 3 | """ 4 | from construct import * 5 | 6 | 7 | record_type = Enum(ULInt32("record_type"), 8 | ABORTPATH = 68, 9 | ANGLEARC = 41, 10 | ARC = 45, 11 | ARCTO = 55, 12 | BEGINPATH = 59, 13 | BITBLT = 76, 14 | CHORD = 46, 15 | CLOSEFIGURE = 61, 16 | CREATEBRUSHINDIRECT = 39, 17 | CREATEDIBPATTERNBRUSHPT = 94, 18 | CREATEMONOBRUSH = 93, 19 | CREATEPALETTE = 49, 20 | CREATEPEN = 38, 21 | DELETEOBJECT = 40, 22 | ELLIPSE = 42, 23 | ENDPATH = 60, 24 | EOF = 14, 25 | EXCLUDECLIPRECT = 29, 26 | EXTCREATEFONTINDIRECTW = 82, 27 | EXTCREATEPEN = 95, 28 | EXTFLOODFILL = 53, 29 | EXTSELECTCLIPRGN = 75, 30 | EXTTEXTOUTA = 83, 31 | EXTTEXTOUTW = 84, 32 | FILLPATH = 62, 33 | FILLRGN = 71, 34 | FLATTENPATH = 65, 35 | FRAMERGN = 72, 36 | GDICOMMENT = 70, 37 | HEADER = 1, 38 | INTERSECTCLIPRECT = 30, 39 | INVERTRGN = 73, 40 | LINETO = 54, 41 | MASKBLT = 78, 42 | MODIFYWORLDTRANSFORM = 36, 43 | MOVETOEX = 27, 44 | OFFSETCLIPRGN = 26, 45 | PAINTRGN = 74, 46 | PIE = 47, 47 | PLGBLT = 79, 48 | POLYBEZIER = 2, 49 | POLYBEZIER16 = 85, 50 | POLYBEZIERTO = 5, 51 | POLYBEZIERTO16 = 88, 52 | POLYDRAW = 56, 53 | POLYDRAW16 = 92, 54 | POLYGON = 3, 55 | POLYGON16 = 86, 56 | POLYLINE = 4, 57 | POLYLINE16 = 87, 58 | POLYLINETO = 6, 59 | POLYLINETO16 = 89, 60 | POLYPOLYGON = 8, 61 | POLYPOLYGON16 = 91, 62 | POLYPOLYLINE = 7, 63 | POLYPOLYLINE16 = 90, 64 | POLYTEXTOUTA = 96, 65 | POLYTEXTOUTW = 97, 66 | REALIZEPALETTE = 52, 67 | RECTANGLE = 43, 68 | RESIZEPALETTE = 51, 69 | RESTOREDC = 34, 70 | ROUNDRECT = 44, 71 | SAVEDC = 33, 72 | SCALEVIEWPORTEXTEX = 31, 73 | SCALEWINDOWEXTEX = 32, 74 | SELECTCLIPPATH = 67, 75 | SELECTOBJECT = 37, 76 | SELECTPALETTE = 48, 77 | SETARCDIRECTION = 57, 78 | SETBKCOLOR = 25, 79 | SETBKMODE = 18, 80 | SETBRUSHORGEX = 13, 81 | SETCOLORADJUSTMENT = 23, 82 | SETDIBITSTODEVICE = 80, 83 | SETMAPMODE = 17, 84 | SETMAPPERFLAGS = 16, 85 | SETMETARGN = 28, 86 | SETMITERLIMIT = 58, 87 | SETPALETTEENTRIES = 50, 88 | SETPIXELV = 15, 89 | SETPOLYFILLMODE = 19, 90 | SETROP2 = 20, 91 | SETSTRETCHBLTMODE = 21, 92 | SETTEXTALIGN = 22, 93 | SETTEXTCOLOR = 24, 94 | SETVIEWPORTEXTEX = 11, 95 | SETVIEWPORTORGEX = 12, 96 | SETWINDOWEXTEX = 9, 97 | SETWINDOWORGEX = 10, 98 | SETWORLDTRANSFORM = 35, 99 | STRETCHBLT = 77, 100 | STRETCHDIBITS = 81, 101 | STROKEANDFILLPATH = 63, 102 | STROKEPATH = 64, 103 | WIDENPATH = 66, 104 | _default_ = Pass, 105 | ) 106 | 107 | generic_record = Struct("records", 108 | record_type, 109 | ULInt32("record_size"), # Size of the record in bytes 110 | Union("params", # Parameters 111 | Field("raw", lambda ctx: ctx._.record_size - 8), 112 | Array(lambda ctx: (ctx._.record_size - 8) // 4, ULInt32("params")) 113 | ), 114 | ) 115 | 116 | header_record = Struct("header_record", 117 | Const(record_type, "HEADER"), 118 | ULInt32("record_size"), # Size of the record in bytes 119 | SLInt32("bounds_left"), # Left inclusive bounds 120 | SLInt32("bounds_right"), # Right inclusive bounds 121 | SLInt32("bounds_top"), # Top inclusive bounds 122 | SLInt32("bounds_bottom"), # Bottom inclusive bounds 123 | SLInt32("frame_left"), # Left side of inclusive picture frame 124 | SLInt32("frame_right"), # Right side of inclusive picture frame 125 | SLInt32("frame_top"), # Top side of inclusive picture frame 126 | SLInt32("frame_bottom"), # Bottom side of inclusive picture frame 127 | Const(ULInt32("signature"), 0x464D4520), 128 | ULInt32("version"), # Version of the metafile 129 | ULInt32("size"), # Size of the metafile in bytes 130 | ULInt32("num_of_records"), # Number of records in the metafile 131 | ULInt16("num_of_handles"), # Number of handles in the handle table 132 | Padding(2), 133 | ULInt32("description_size"), # Size of description string in WORDs 134 | ULInt32("description_offset"), # Offset of description string in metafile 135 | ULInt32("num_of_palette_entries"), # Number of color palette entries 136 | SLInt32("device_width_pixels"), # Width of reference device in pixels 137 | SLInt32("device_height_pixels"), # Height of reference device in pixels 138 | SLInt32("device_width_mm"), # Width of reference device in millimeters 139 | SLInt32("device_height_mm"), # Height of reference device in millimeters 140 | 141 | # description string 142 | Pointer(lambda ctx: ctx.description_offset, 143 | StringAdapter( 144 | Array(lambda ctx: ctx.description_size, 145 | Field("description", 2) 146 | ) 147 | ) 148 | ), 149 | 150 | # padding up to end of record 151 | Padding(lambda ctx: ctx.record_size - 88), 152 | ) 153 | 154 | emf_file = Struct("emf_file", 155 | header_record, 156 | Array(lambda ctx: ctx.header_record.num_of_records - 1, 157 | generic_record 158 | ), 159 | ) 160 | 161 | 162 | if __name__ == "__main__": 163 | obj = emf_file.parse_stream(open("../../../tests/emf1.emf", "rb")) 164 | print (obj) 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /libs/python/construct/formats/graphics/gif.py: -------------------------------------------------------------------------------- 1 | # Contributed by 2 | # Dany Zatuchna (danzat at gmail) 3 | """ Implementation of the following grammar for the GIF89a file format 4 | ::= Header * Trailer 5 | 6 | ::= Logical Screen Descriptor [Global Color Table] 7 | 8 | ::= | 9 | 10 | 11 | ::= [Graphic Control Extension] 12 | 13 | ::= | 14 | Plain Text Extension 15 | 16 | ::= Image Descriptor [Local Color Table] Image Data 17 | 18 | ::= Application Extension | 19 | Comment Extension 20 | """ 21 | from construct import * 22 | import six 23 | 24 | 25 | data_sub_block = Struct("data_sub_block", 26 | ULInt8("size"), 27 | String("data", lambda ctx: ctx["size"]) 28 | ) 29 | 30 | gif_logical_screen = Struct("logical_screen", 31 | ULInt16("width"), 32 | ULInt16("height"), 33 | BitStruct("flags", 34 | Bit("global_color_table"), 35 | BitField("color_resolution", 3), 36 | Bit("sort_flag"), 37 | BitField("global_color_table_bpp", 3) 38 | ), 39 | ULInt8("bgcolor_index"), 40 | ULInt8("pixel_aspect_ratio"), 41 | If(lambda ctx: ctx["flags"]["global_color_table"], 42 | Array(lambda ctx: 2**(ctx["flags"]["global_color_table_bpp"] + 1), 43 | Struct("palette", 44 | ULInt8("R"), 45 | ULInt8("G"), 46 | ULInt8("B") 47 | ) 48 | ) 49 | ) 50 | ) 51 | 52 | gif_header = Struct("gif_header", 53 | Const(String("signature", 3), six.b("GIF")), 54 | Const(String("version", 3), six.b("89a")), 55 | ) 56 | 57 | application_extension = Struct("application_extension", 58 | Const(ULInt8("block_size"), 11), 59 | String("application_identifier", 8), 60 | String("application_auth_code", 3), 61 | data_sub_block, 62 | ULInt8("block_terminator") 63 | ) 64 | 65 | comment_extension = Struct("comment_extension", 66 | data_sub_block, 67 | ULInt8("block_terminator") 68 | ) 69 | 70 | graphic_control_extension = Struct("graphic_control_extension", 71 | Const(ULInt8("block_size"), 4), 72 | BitStruct("flags", 73 | BitField("reserved", 3), 74 | BitField("disposal_method", 3), 75 | Bit("user_input_flag"), 76 | Bit("transparent_color_flag"), 77 | ), 78 | ULInt16("delay"), 79 | ULInt8("transparent_color_index"), 80 | ULInt8("block_terminator") 81 | ) 82 | 83 | plain_text_extension = Struct("plain_text_extension", 84 | Const(ULInt8("block_size"), 12), 85 | ULInt16("text_left"), 86 | ULInt16("text_top"), 87 | ULInt16("text_width"), 88 | ULInt16("text_height"), 89 | ULInt8("cell_width"), 90 | ULInt8("cell_height"), 91 | ULInt8("foreground_index"), 92 | ULInt8("background_index"), 93 | data_sub_block, 94 | ULInt8("block_terminator") 95 | ) 96 | 97 | extension = Struct("extension", 98 | ULInt8("label"), 99 | Switch("ext", lambda ctx: ctx["label"], { 100 | 0xFF: application_extension, 101 | 0xFE: comment_extension, 102 | 0xF9: graphic_control_extension, 103 | 0x01: plain_text_extension 104 | }) 105 | ) 106 | 107 | image_descriptor = Struct("image_descriptor", 108 | ULInt16("left"), 109 | ULInt16("top"), 110 | ULInt16("width"), 111 | ULInt16("height"), 112 | BitStruct("flags", 113 | Bit("local_color_table"), 114 | Bit("interlace"), 115 | Bit("sort"), 116 | BitField("reserved", 2), 117 | BitField("local_color_table_bpp", 3) 118 | ), 119 | If(lambda ctx: ctx["flags"]["local_color_table"], 120 | Array(lambda ctx: 2**(ctx["flags"]["local_color_table_bpp"] + 1), 121 | Struct("palette", 122 | ULInt8("R"), 123 | ULInt8("G"), 124 | ULInt8("B") 125 | ) 126 | ) 127 | ), 128 | ULInt8("LZW_minimum_code_size"), 129 | RepeatUntil(lambda obj, ctx: obj.size == 0, data_sub_block) 130 | ) 131 | 132 | gif_data = Struct("gif_data", 133 | ULInt8("introducer"), 134 | Switch("dat", lambda ctx: ctx["introducer"], { 135 | 0x21: extension, 136 | 0x2C: image_descriptor 137 | }) 138 | ) 139 | 140 | gif_file = Struct("gif_file", 141 | gif_header, 142 | gif_logical_screen, 143 | OptionalGreedyRange(gif_data), 144 | #Const(ULInt8("trailer"), 0x3B) 145 | ) 146 | 147 | if __name__ == "__main__": 148 | f = open("../../../tests/sample.gif", "rb") 149 | s = f.read() 150 | f.close() 151 | print(gif_file.parse(s)) 152 | -------------------------------------------------------------------------------- /libs/python/construct/formats/graphics/wmf.py: -------------------------------------------------------------------------------- 1 | """ 2 | Windows Meta File 3 | """ 4 | from construct import * 5 | 6 | 7 | wmf_record = Struct("records", 8 | ULInt32("size"), # size in words, including the size, function and params 9 | Enum(ULInt16("function"), 10 | AbortDoc = 0x0052, 11 | Aldus_Header = 0x0001, 12 | AnimatePalette = 0x0436, 13 | Arc = 0x0817, 14 | BitBlt = 0x0922, 15 | Chord = 0x0830, 16 | CLP_Header16 = 0x0002, 17 | CLP_Header32 = 0x0003, 18 | CreateBitmap = 0x06FE, 19 | CreateBitmapIndirect = 0x02FD, 20 | CreateBrush = 0x00F8, 21 | CreateBrushIndirect = 0x02FC, 22 | CreateFontIndirect = 0x02FB, 23 | CreatePalette = 0x00F7, 24 | CreatePatternBrush = 0x01F9, 25 | CreatePenIndirect = 0x02FA, 26 | CreateRegion = 0x06FF, 27 | DeleteObject = 0x01F0, 28 | DibBitblt = 0x0940, 29 | DibCreatePatternBrush = 0x0142, 30 | DibStretchBlt = 0x0B41, 31 | DrawText = 0x062F, 32 | Ellipse = 0x0418, 33 | EndDoc = 0x005E, 34 | EndPage = 0x0050, 35 | EOF = 0x0000, 36 | Escape = 0x0626, 37 | ExcludeClipRect = 0x0415, 38 | ExtFloodFill = 0x0548, 39 | ExtTextOut = 0x0A32, 40 | FillRegion = 0x0228, 41 | FloodFill = 0x0419, 42 | FrameRegion = 0x0429, 43 | Header = 0x0004, 44 | IntersectClipRect = 0x0416, 45 | InvertRegion = 0x012A, 46 | LineTo = 0x0213, 47 | MoveTo = 0x0214, 48 | OffsetClipRgn = 0x0220, 49 | OffsetViewportOrg = 0x0211, 50 | OffsetWindowOrg = 0x020F, 51 | PaintRegion = 0x012B, 52 | PatBlt = 0x061D, 53 | Pie = 0x081A, 54 | Polygon = 0x0324, 55 | Polyline = 0x0325, 56 | PolyPolygon = 0x0538, 57 | RealizePalette = 0x0035, 58 | Rectangle = 0x041B, 59 | ResetDC = 0x014C, 60 | ResizePalette = 0x0139, 61 | RestoreDC = 0x0127, 62 | RoundRect = 0x061C, 63 | SaveDC = 0x001E, 64 | ScaleViewportExt = 0x0412, 65 | ScaleWindowExt = 0x0410, 66 | SelectClipRegion = 0x012C, 67 | SelectObject = 0x012D, 68 | SelectPalette = 0x0234, 69 | SetBKColor = 0x0201, 70 | SetBKMode = 0x0102, 71 | SetDibToDev = 0x0D33, 72 | SelLayout = 0x0149, 73 | SetMapMode = 0x0103, 74 | SetMapperFlags = 0x0231, 75 | SetPalEntries = 0x0037, 76 | SetPixel = 0x041F, 77 | SetPolyFillMode = 0x0106, 78 | SetReLabs = 0x0105, 79 | SetROP2 = 0x0104, 80 | SetStretchBltMode = 0x0107, 81 | SetTextAlign = 0x012E, 82 | SetTextCharExtra = 0x0108, 83 | SetTextColor = 0x0209, 84 | SetTextJustification = 0x020A, 85 | SetViewportExt = 0x020E, 86 | SetViewportOrg = 0x020D, 87 | SetWindowExt = 0x020C, 88 | SetWindowOrg = 0x020B, 89 | StartDoc = 0x014D, 90 | StartPage = 0x004F, 91 | StretchBlt = 0x0B23, 92 | StretchDIB = 0x0F43, 93 | TextOut = 0x0521, 94 | _default_ = Pass, 95 | ), 96 | Array(lambda ctx: ctx.size - 3, ULInt16("params")), 97 | ) 98 | 99 | wmf_placeable_header = Struct("placeable_header", 100 | Const(ULInt32("key"), 0x9AC6CDD7), 101 | ULInt16("handle"), 102 | SLInt16("left"), 103 | SLInt16("top"), 104 | SLInt16("right"), 105 | SLInt16("bottom"), 106 | ULInt16("units_per_inch"), 107 | Padding(4), 108 | ULInt16("checksum") 109 | ) 110 | 111 | wmf_file = Struct("wmf_file", 112 | # --- optional placeable header --- 113 | Optional(wmf_placeable_header), 114 | 115 | # --- header --- 116 | Enum(ULInt16("type"), 117 | InMemory = 0, 118 | File = 1, 119 | ), 120 | Const(ULInt16("header_size"), 9), 121 | ULInt16("version"), 122 | ULInt32("size"), # file size is in words 123 | ULInt16("number_of_objects"), 124 | ULInt32("size_of_largest_record"), 125 | ULInt16("number_of_params"), 126 | 127 | # --- records --- 128 | GreedyRange(wmf_record) 129 | ) 130 | -------------------------------------------------------------------------------- /libs/python/construct/lib/__init__.py: -------------------------------------------------------------------------------- 1 | from construct.lib.binary import int_to_bin, bin_to_int, swap_bytes, encode_bin, decode_bin 2 | from construct.lib.bitstream import BitStreamReader, BitStreamWriter 3 | from construct.lib.container import (Container, FlagsContainer, ListContainer, 4 | LazyContainer) 5 | from construct.lib.hex import HexString, hexdump 6 | -------------------------------------------------------------------------------- /libs/python/construct/lib/binary.py: -------------------------------------------------------------------------------- 1 | import six 2 | from construct.lib.py3compat import int2byte 3 | 4 | 5 | if six.PY3: 6 | def int_to_bin(number, width = 32): 7 | r""" 8 | Convert an integer into its binary representation in a bytes object. 9 | Width is the amount of bits to generate. If width is larger than the actual 10 | amount of bits required to represent number in binary, sign-extension is 11 | used. If it's smaller, the representation is trimmed to width bits. 12 | Each "bit" is either '\x00' or '\x01'. The MSBit is first. 13 | 14 | Examples: 15 | 16 | >>> int_to_bin(19, 5) 17 | b'\x01\x00\x00\x01\x01' 18 | >>> int_to_bin(19, 8) 19 | b'\x00\x00\x00\x01\x00\x00\x01\x01' 20 | """ 21 | number = int(number) 22 | if number < 0: 23 | number += 1 << width 24 | i = width - 1 25 | bits = bytearray(width) 26 | while number and i >= 0: 27 | bits[i] = number & 1 28 | number >>= 1 29 | i -= 1 30 | return bytes(bits) 31 | 32 | # heavily optimized for performance 33 | def bin_to_int(bits, signed = False): 34 | r""" 35 | Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, 36 | and both '1' and '\x01' are considered one. Set sign to True to interpret 37 | the number as a 2-s complement signed integer. 38 | """ 39 | bits = "".join("01"[b & 1] for b in bits) 40 | if signed and bits[0] == "1": 41 | bits = bits[1:] 42 | bias = 1 << len(bits) 43 | else: 44 | bias = 0 45 | return int(bits, 2) - bias 46 | 47 | _char_to_bin = [0] * 256 48 | _bin_to_char = {} 49 | for i in range(256): 50 | ch = int2byte(i) 51 | bin = int_to_bin(i, 8) 52 | # Populate with for both keys i and ch, to support Python 2 & 3 53 | _char_to_bin[i] = bin 54 | _bin_to_char[bin] = ord(ch) 55 | 56 | def encode_bin(data): 57 | """ 58 | Create a binary representation of the given b'' object. Assume 8-bit 59 | ASCII. Example: 60 | 61 | >>> encode_bin('ab') 62 | b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" 63 | """ 64 | return six.b("").join(_char_to_bin[int(ch)] for ch in data) 65 | 66 | def decode_bin(data): 67 | if len(data) & 7: 68 | raise ValueError("Data length must be a multiple of 8") 69 | i = 0 70 | j = 0 71 | l = len(data) // 8 72 | arr = bytearray(l) 73 | while j < l: 74 | arr[j] = _bin_to_char[data[i:i+8]] 75 | i += 8 76 | j += 1 77 | return arr 78 | 79 | def swap_bytes(bits, bytesize=8): 80 | r""" 81 | Bits is a b'' object containing a binary representation. Assuming each 82 | bytesize bits constitute a bytes, perform a endianness byte swap. Example: 83 | 84 | >>> swap_bytes(b'00011011', 2) 85 | b'11100100' 86 | """ 87 | i = 0 88 | l = len(bits) 89 | output = [six.b("")] * ((l // bytesize) + 1) 90 | j = len(output) - 1 91 | while i < l: 92 | output[j] = bits[i : i + bytesize] 93 | i += bytesize 94 | j -= 1 95 | return six.b("").join(output) 96 | 97 | else: 98 | 99 | def int_to_bin(number, width = 32): 100 | r""" 101 | Convert an integer into its binary representation in a bytes object. 102 | Width is the amount of bits to generate. If width is larger than the actual 103 | amount of bits required to represent number in binary, sign-extension is 104 | used. If it's smaller, the representation is trimmed to width bits. 105 | Each "bit" is either '\x00' or '\x01'. The MSBit is first. 106 | 107 | Examples: 108 | 109 | >>> int_to_bin(19, 5) 110 | '\x01\x00\x00\x01\x01' 111 | >>> int_to_bin(19, 8) 112 | '\x00\x00\x00\x01\x00\x00\x01\x01' 113 | """ 114 | if number < 0: 115 | number += 1 << width 116 | i = width - 1 117 | bits = ["\x00"] * width 118 | while number and i >= 0: 119 | bits[i] = "\x00\x01"[number & 1] 120 | number >>= 1 121 | i -= 1 122 | return "".join(bits) 123 | 124 | # heavily optimized for performance 125 | def bin_to_int(bits, signed = False): 126 | r""" 127 | Logical opposite of int_to_bin. Both '0' and '\x00' are considered zero, 128 | and both '1' and '\x01' are considered one. Set sign to True to interpret 129 | the number as a 2-s complement signed integer. 130 | """ 131 | bits = "".join("01"[ord(b) & 1] for b in bits) 132 | if signed and bits[0] == "1": 133 | bits = bits[1:] 134 | bias = 1 << len(bits) 135 | else: 136 | bias = 0 137 | return int(bits, 2) - bias 138 | 139 | _char_to_bin = [0] * 256 140 | _bin_to_char = {} 141 | for i in range(256): 142 | ch = int2byte(i) 143 | bin = int_to_bin(i, 8) 144 | # Populate with for both keys i and ch, to support Python 2 & 3 145 | _char_to_bin[i] = bin 146 | _bin_to_char[bin] = ch 147 | 148 | def encode_bin(data): 149 | """ 150 | Create a binary representation of the given b'' object. Assume 8-bit 151 | ASCII. Example: 152 | 153 | >>> encode_bin('ab') 154 | b"\x00\x01\x01\x00\x00\x00\x00\x01\x00\x01\x01\x00\x00\x00\x01\x00" 155 | """ 156 | return "".join(_char_to_bin[ord(ch)] for ch in data) 157 | 158 | def decode_bin(data): 159 | if len(data) & 7: 160 | raise ValueError("Data length must be a multiple of 8") 161 | i = 0 162 | j = 0 163 | l = len(data) // 8 164 | chars = [""] * l 165 | while j < l: 166 | chars[j] = _bin_to_char[data[i:i+8]] 167 | i += 8 168 | j += 1 169 | return "".join(chars) 170 | 171 | def swap_bytes(bits, bytesize=8): 172 | r""" 173 | Bits is a b'' object containing a binary representation. Assuming each 174 | bytesize bits constitute a bytes, perform a endianness byte swap. Example: 175 | 176 | >>> swap_bytes(b'00011011', 2) 177 | b'11100100' 178 | """ 179 | i = 0 180 | l = len(bits) 181 | output = [""] * ((l // bytesize) + 1) 182 | j = len(output) - 1 183 | while i < l: 184 | output[j] = bits[i : i + bytesize] 185 | i += bytesize 186 | j -= 1 187 | return "".join(output) 188 | -------------------------------------------------------------------------------- /libs/python/construct/lib/bitstream.py: -------------------------------------------------------------------------------- 1 | import six 2 | from construct.lib.binary import encode_bin, decode_bin 3 | 4 | try: 5 | bytes 6 | except NameError: 7 | bytes = str 8 | 9 | class BitStreamReader(object): 10 | __slots__ = ["substream", "buffer", "total_size"] 11 | 12 | def __init__(self, substream): 13 | self.substream = substream 14 | self.total_size = 0 15 | self.buffer = six.b("") 16 | 17 | def close(self): 18 | if self.total_size % 8 != 0: 19 | raise ValueError("total size of read data must be a multiple of 8", 20 | self.total_size) 21 | 22 | def tell(self): 23 | return self.substream.tell() 24 | 25 | def seek(self, pos, whence = 0): 26 | self.buffer = six.b("") 27 | self.total_size = 0 28 | self.substream.seek(pos, whence) 29 | 30 | def read(self, count): 31 | if count < 0: 32 | raise ValueError("count cannot be negative") 33 | 34 | l = len(self.buffer) 35 | if count == 0: 36 | data = six.b("") 37 | elif count <= l: 38 | data = self.buffer[:count] 39 | self.buffer = self.buffer[count:] 40 | else: 41 | data = self.buffer 42 | count -= l 43 | count_bytes = count // 8 44 | if count & 7: 45 | count_bytes += 1 46 | buf = encode_bin(self.substream.read(count_bytes)) 47 | data += buf[:count] 48 | self.buffer = buf[count:] 49 | self.total_size += len(data) 50 | return data 51 | 52 | class BitStreamWriter(object): 53 | __slots__ = ["substream", "buffer", "pos"] 54 | 55 | def __init__(self, substream): 56 | self.substream = substream 57 | self.buffer = [] 58 | self.pos = 0 59 | 60 | def close(self): 61 | self.flush() 62 | 63 | def flush(self): 64 | raw = decode_bin(six.b("").join(self.buffer)) 65 | self.substream.write(raw) 66 | self.buffer = [] 67 | self.pos = 0 68 | 69 | def tell(self): 70 | return self.substream.tell() + self.pos // 8 71 | 72 | def seek(self, pos, whence = 0): 73 | self.flush() 74 | self.substream.seek(pos, whence) 75 | 76 | def write(self, data): 77 | if not data: 78 | return 79 | if not isinstance(data, bytes): 80 | raise TypeError("data must be a string, not %r" % (type(data),)) 81 | self.buffer.append(data) 82 | -------------------------------------------------------------------------------- /libs/python/construct/lib/container.py: -------------------------------------------------------------------------------- 1 | """ 2 | Various containers. 3 | """ 4 | 5 | def recursion_lock(retval, lock_name = "__recursion_lock__"): 6 | def decorator(func): 7 | def wrapper(self, *args, **kw): 8 | if getattr(self, lock_name, False): 9 | return retval 10 | setattr(self, lock_name, True) 11 | try: 12 | return func(self, *args, **kw) 13 | finally: 14 | setattr(self, lock_name, False) 15 | wrapper.__name__ = func.__name__ 16 | return wrapper 17 | return decorator 18 | 19 | class Container(dict): 20 | """ 21 | A generic container of attributes. 22 | 23 | Containers are the common way to express parsed data. 24 | """ 25 | __slots__ = ["__keys_order__"] 26 | 27 | def __init__(self, **kw): 28 | object.__setattr__(self, "__keys_order__", []) 29 | for k, v in kw.items(): 30 | self[k] = v 31 | def __getattr__(self, name): 32 | try: 33 | return self[name] 34 | except KeyError: 35 | raise AttributeError(name) 36 | def __setitem__(self, key, val): 37 | if key not in self: 38 | self.__keys_order__.append(key) 39 | dict.__setitem__(self, key, val) 40 | def __delitem__(self, key): 41 | dict.__delitem__(self, key) 42 | self.__keys_order__.remove(key) 43 | 44 | __delattr__ = __delitem__ 45 | __setattr__ = __setitem__ 46 | 47 | def clear(self): 48 | dict.clear(self) 49 | del self.__keys_order__[:] 50 | def pop(self, key, *default): 51 | val = dict.pop(self, key, *default) 52 | self.__keys_order__.remove(key) 53 | return val 54 | def popitem(self): 55 | k, v = dict.popitem(self) 56 | self.__keys_order__.remove(k) 57 | return k, v 58 | 59 | def update(self, seq, **kw): 60 | if hasattr(seq, "keys"): 61 | for k in seq.keys(): 62 | self[k] = seq[k] 63 | else: 64 | for k, v in seq: 65 | self[k] = v 66 | dict.update(self, kw) 67 | 68 | def copy(self): 69 | inst = self.__class__() 70 | inst.update(self.iteritems()) 71 | return inst 72 | 73 | __update__ = update 74 | __copy__ = copy 75 | 76 | def __iter__(self): 77 | return iter(self.__keys_order__) 78 | iterkeys = __iter__ 79 | def itervalues(self): 80 | return (self[k] for k in self.__keys_order__) 81 | def iteritems(self): 82 | return ((k, self[k]) for k in self.__keys_order__) 83 | def keys(self): 84 | return self.__keys_order__ 85 | def values(self): 86 | return list(self.itervalues()) 87 | def items(self): 88 | return list(self.iteritems()) 89 | 90 | def __repr__(self): 91 | return "%s(%s)" % (self.__class__.__name__, dict.__repr__(self)) 92 | 93 | @recursion_lock("<...>") 94 | def __pretty_str__(self, nesting = 1, indentation = " "): 95 | attrs = [] 96 | ind = indentation * nesting 97 | for k, v in self.iteritems(): 98 | if not k.startswith("_"): 99 | text = [ind, k, " = "] 100 | if hasattr(v, "__pretty_str__"): 101 | text.append(v.__pretty_str__(nesting + 1, indentation)) 102 | else: 103 | text.append(repr(v)) 104 | attrs.append("".join(text)) 105 | if not attrs: 106 | return "%s()" % (self.__class__.__name__,) 107 | attrs.insert(0, self.__class__.__name__ + ":") 108 | return "\n".join(attrs) 109 | 110 | __str__ = __pretty_str__ 111 | 112 | 113 | class FlagsContainer(Container): 114 | """ 115 | A container providing pretty-printing for flags. 116 | 117 | Only set flags are displayed. 118 | """ 119 | 120 | @recursion_lock("<...>") 121 | def __pretty_str__(self, nesting = 1, indentation = " "): 122 | attrs = [] 123 | ind = indentation * nesting 124 | for k in self.keys(): 125 | v = self.__dict__[k] 126 | if not k.startswith("_") and v: 127 | attrs.append(ind + k) 128 | if not attrs: 129 | return "%s()" % (self.__class__.__name__,) 130 | attrs.insert(0, self.__class__.__name__+ ":") 131 | return "\n".join(attrs) 132 | 133 | 134 | class ListContainer(list): 135 | """ 136 | A container for lists. 137 | """ 138 | __slots__ = ["__recursion_lock__"] 139 | 140 | def __str__(self): 141 | return self.__pretty_str__() 142 | 143 | @recursion_lock("[...]") 144 | def __pretty_str__(self, nesting = 1, indentation = " "): 145 | if not self: 146 | return "[]" 147 | ind = indentation * nesting 148 | lines = ["["] 149 | for elem in self: 150 | lines.append("\n") 151 | lines.append(ind) 152 | if hasattr(elem, "__pretty_str__"): 153 | lines.append(elem.__pretty_str__(nesting + 1, indentation)) 154 | else: 155 | lines.append(repr(elem)) 156 | lines.append("\n") 157 | lines.append(indentation * (nesting - 1)) 158 | lines.append("]") 159 | return "".join(lines) 160 | 161 | 162 | class LazyContainer(object): 163 | 164 | __slots__ = ["subcon", "stream", "pos", "context", "_value"] 165 | 166 | def __init__(self, subcon, stream, pos, context): 167 | self.subcon = subcon 168 | self.stream = stream 169 | self.pos = pos 170 | self.context = context 171 | self._value = NotImplemented 172 | 173 | def __eq__(self, other): 174 | try: 175 | return self._value == other._value 176 | except AttributeError: 177 | return False 178 | 179 | def __ne__(self, other): 180 | return not (self == other) 181 | 182 | def __str__(self): 183 | return self.__pretty_str__() 184 | 185 | def __pretty_str__(self, nesting = 1, indentation = " "): 186 | if self._value is NotImplemented: 187 | text = "" 188 | elif hasattr(self._value, "__pretty_str__"): 189 | text = self._value.__pretty_str__(nesting, indentation) 190 | else: 191 | text = str(self._value) 192 | return "%s: %s" % (self.__class__.__name__, text) 193 | 194 | def read(self): 195 | self.stream.seek(self.pos) 196 | return self.subcon._parse(self.stream, self.context) 197 | 198 | def dispose(self): 199 | self.subcon = None 200 | self.stream = None 201 | self.context = None 202 | self.pos = None 203 | 204 | def _get_value(self): 205 | if self._value is NotImplemented: 206 | self._value = self.read() 207 | return self._value 208 | 209 | value = property(_get_value) 210 | 211 | has_value = property(lambda self: self._value is not NotImplemented) 212 | 213 | 214 | 215 | if __name__ == "__main__": 216 | c = Container(x=5) 217 | c.y = 8 218 | c.z = 9 219 | c.w = 10 220 | c.foo = 5 221 | 222 | print (c) 223 | 224 | 225 | -------------------------------------------------------------------------------- /libs/python/construct/lib/expr.py: -------------------------------------------------------------------------------- 1 | import operator 2 | 3 | if not hasattr(operator, "div"): 4 | operator.div = operator.truediv 5 | 6 | 7 | opnames = { 8 | operator.add : "+", 9 | operator.sub : "-", 10 | operator.mul : "*", 11 | operator.div : "/", 12 | operator.floordiv : "//", 13 | operator.mod : "+", 14 | operator.pow : "**", 15 | operator.xor : "^", 16 | operator.lshift : "<<", 17 | operator.rshift : ">>", 18 | operator.and_ : "and", 19 | operator.or_ : "or", 20 | operator.not_ : "not", 21 | operator.neg : "-", 22 | operator.pos : "+", 23 | operator.contains : "in", 24 | operator.gt : ">", 25 | operator.ge : ">=", 26 | operator.lt : "<", 27 | operator.le : "<=", 28 | operator.eq : "==", 29 | operator.ne : "!=", 30 | } 31 | 32 | 33 | class ExprMixin(object): 34 | __slots__ = () 35 | def __add__(self, other): 36 | return BinExpr(operator.add, self, other) 37 | def __sub__(self, other): 38 | return BinExpr(operator.sub, self, other) 39 | def __mul__(self, other): 40 | return BinExpr(operator.mul, self, other) 41 | def __floordiv__(self, other): 42 | return BinExpr(operator.floordiv, self, other) 43 | def __truediv__(self, other): 44 | return BinExpr(operator.div, self, other) 45 | __div__ = __floordiv__ 46 | def __mod__(self, other): 47 | return BinExpr(operator.mod, self, other) 48 | def __pow__(self, other): 49 | return BinExpr(operator.pow, self, other) 50 | def __xor__(self, other): 51 | return BinExpr(operator.xor, self, other) 52 | def __rshift__(self, other): 53 | return BinExpr(operator.rshift, self, other) 54 | def __lshift__(self, other): 55 | return BinExpr(operator.rshift, self, other) 56 | def __and__(self, other): 57 | return BinExpr(operator.and_, self, other) 58 | def __or__(self, other): 59 | return BinExpr(operator.or_, self, other) 60 | 61 | def __radd__(self, other): 62 | return BinExpr(operator.add, other, self) 63 | def __rsub__(self, other): 64 | return BinExpr(operator.sub, other, self) 65 | def __rmul__(self, other): 66 | return BinExpr(operator.mul, other, self) 67 | def __rfloordiv__(self, other): 68 | return BinExpr(operator.floordiv, other, self) 69 | def __rtruediv__(self, other): 70 | return BinExpr(operator.div, other, self) 71 | __rdiv__ = __rfloordiv__ 72 | def __rmod__(self, other): 73 | return BinExpr(operator.mod, other, self) 74 | def __rpow__(self, other): 75 | return BinExpr(operator.pow, other, self) 76 | def __rxor__(self, other): 77 | return BinExpr(operator.xor, other, self) 78 | def __rrshift__(self, other): 79 | return BinExpr(operator.rshift, other, self) 80 | def __rlshift__(self, other): 81 | return BinExpr(operator.rshift, other, self) 82 | def __rand__(self, other): 83 | return BinExpr(operator.and_, other, self) 84 | def __ror__(self, other): 85 | return BinExpr(operator.or_, other, self) 86 | 87 | def __neg__(self): 88 | return UniExpr(operator.neg, self) 89 | def __pos__(self): 90 | return UniExpr(operator.pos, self) 91 | def __invert__(self): 92 | return UniExpr(operator.not_, self) 93 | __inv__ = __invert__ 94 | 95 | def __contains__(self, other): 96 | return BinExpr(operator.contains, self, other) 97 | def __gt__(self, other): 98 | return BinExpr(operator.gt, self, other) 99 | def __ge__(self, other): 100 | return BinExpr(operator.ge, self, other) 101 | def __lt__(self, other): 102 | return BinExpr(operator.lt, self, other) 103 | def __le__(self, other): 104 | return BinExpr(operator.le, self, other) 105 | def __eq__(self, other): 106 | return BinExpr(operator.eq, self, other) 107 | def __ne__(self, other): 108 | return BinExpr(operator.ne, self, other) 109 | 110 | 111 | class UniExpr(ExprMixin): 112 | __slots__ = ["op", "operand"] 113 | def __init__(self, op, operand): 114 | self.op = op 115 | self.operand = operand 116 | def __repr__(self): 117 | return "%s %r" % (opnames[self.op], self.operand) 118 | def __call__(self, context): 119 | operand = self.operand(context) if callable(self.operand) else self.operand 120 | return self.op(operand) 121 | 122 | 123 | class BinExpr(ExprMixin): 124 | __slots__ = ["op", "lhs", "rhs"] 125 | def __init__(self, op, lhs, rhs): 126 | self.op = op 127 | self.lhs = lhs 128 | self.rhs = rhs 129 | def __repr__(self): 130 | return "(%r %s %r)" % (self.lhs, opnames[self.op], self.rhs) 131 | def __call__(self, context): 132 | lhs = self.lhs(context) if callable(self.lhs) else self.lhs 133 | rhs = self.rhs(context) if callable(self.rhs) else self.rhs 134 | return self.op(lhs, rhs) 135 | 136 | 137 | class Path(ExprMixin): 138 | __slots__ = ["__name", "__parent"] 139 | def __init__(self, name, parent = None): 140 | self.__name = name 141 | self.__parent = parent 142 | def __repr__(self): 143 | if self.__parent is None: 144 | return self.__name 145 | return "%r.%s" % (self.__parent, self.__name) 146 | def __call__(self, context): 147 | if self.__parent is None: 148 | return context 149 | context2 = self.__parent(context) 150 | return context2[self.__name] 151 | def __getattr__(self, name): 152 | return Path(name, self) 153 | 154 | 155 | # let the magic begin! 156 | this = Path("this") 157 | 158 | 159 | if __name__ == "__main__": 160 | x = ~((this.foo * 2 + 3 << 2) % 11) 161 | print (x) 162 | print (x({"foo" : 7})) 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /libs/python/construct/lib/hex.py: -------------------------------------------------------------------------------- 1 | from construct.lib.py3compat import byte2int, int2byte, bytes2str 2 | 3 | 4 | # Map an integer in the inclusive range 0-255 to its string byte representation 5 | _printable = dict((i, ".") for i in range(256)) 6 | _printable.update((i, bytes2str(int2byte(i))) for i in range(32, 128)) 7 | 8 | 9 | def hexdump(data, linesize): 10 | """ 11 | data is a bytes object. The returned result is a string. 12 | """ 13 | prettylines = [] 14 | if len(data) < 65536: 15 | fmt = "%%04X %%-%ds %%s" 16 | else: 17 | fmt = "%%08X %%-%ds %%s" 18 | fmt = fmt % (3 * linesize - 1,) 19 | for i in range(0, len(data), linesize): 20 | line = data[i : i + linesize] 21 | hextext = " ".join('%02x' % byte2int(b) for b in line) 22 | rawtext = "".join(_printable[byte2int(b)] for b in line) 23 | prettylines.append(fmt % (i, str(hextext), str(rawtext))) 24 | return prettylines 25 | 26 | 27 | try: 28 | basecls = bytes 29 | except NameError: 30 | basecls = str 31 | 32 | class HexString(basecls): 33 | """ 34 | Represents bytes that will be hex-dumped to a string when its string 35 | representation is requested. 36 | """ 37 | def __init__(self, data, linesize = 16): 38 | self.linesize = linesize 39 | def __new__(cls, data, *args, **kwargs): 40 | return basecls.__new__(cls, data) 41 | def __str__(self): 42 | if not self: 43 | return "''" 44 | return "\n" + "\n".join(hexdump(self, self.linesize)) 45 | 46 | 47 | -------------------------------------------------------------------------------- /libs/python/construct/lib/py3compat.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # py3compat.py 3 | # 4 | # Some Python2&3 compatibility code 5 | #------------------------------------------------------------------------------- 6 | import sys 7 | PY3 = sys.version_info[0] == 3 8 | 9 | 10 | if PY3: 11 | import io 12 | StringIO = io.StringIO 13 | BytesIO = io.BytesIO 14 | 15 | def bchr(i): 16 | """ When iterating over b'...' in Python 2 you get single b'_' chars 17 | and in Python 3 you get integers. Call bchr to always turn this 18 | to single b'_' chars. 19 | """ 20 | return bytes((i,)) 21 | 22 | def u(s): 23 | return s 24 | 25 | def int2byte(i): 26 | return bytes((i,)) 27 | 28 | def byte2int(b): 29 | return b 30 | 31 | def str2bytes(s): 32 | return s.encode("latin-1") 33 | 34 | def str2unicode(s): 35 | return s 36 | 37 | def bytes2str(b): 38 | return b.decode('latin-1') 39 | 40 | def decodebytes(b, encoding): 41 | return bytes(b, encoding) 42 | 43 | advance_iterator = next 44 | 45 | else: 46 | import cStringIO 47 | StringIO = BytesIO = cStringIO.StringIO 48 | 49 | int2byte = chr 50 | byte2int = ord 51 | bchr = lambda i: i 52 | 53 | def u(s): 54 | return unicode(s, "unicode_escape") 55 | 56 | def str2bytes(s): 57 | return s 58 | 59 | def str2unicode(s): 60 | return unicode(s, "unicode_escape") 61 | 62 | def bytes2str(b): 63 | return b 64 | 65 | def decodebytes(b, encoding): 66 | return b.decode(encoding) 67 | 68 | def advance_iterator(it): 69 | return it.next() 70 | 71 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | protocols - a collection of network protocols 3 | unlike the formats package, protocols convey information between two sides 4 | """ 5 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/application/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | application layer (various) protocols 3 | """ 4 | 5 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/application/dns.py: -------------------------------------------------------------------------------- 1 | """ 2 | Domain Name System (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from construct.protocols.layer3.ipv4 import IpAddressAdapter 6 | from binascii import unhexlify 7 | import six 8 | 9 | 10 | class DnsStringAdapter(Adapter): 11 | def _encode(self, obj, context): 12 | parts = obj.split(".") 13 | parts.append("") 14 | return parts 15 | def _decode(self, obj, context): 16 | return ".".join(obj[:-1]) 17 | 18 | dns_record_class = Enum(UBInt16("class"), 19 | RESERVED = 0, 20 | INTERNET = 1, 21 | CHAOS = 3, 22 | HESIOD = 4, 23 | NONE = 254, 24 | ANY = 255, 25 | ) 26 | 27 | dns_record_type = Enum(UBInt16("type"), 28 | IPv4 = 1, 29 | AUTHORITIVE_NAME_SERVER = 2, 30 | CANONICAL_NAME = 5, 31 | NULL = 10, 32 | MAIL_EXCHANGE = 15, 33 | TEXT = 16, 34 | X25 = 19, 35 | ISDN = 20, 36 | IPv6 = 28, 37 | UNSPECIFIED = 103, 38 | ALL = 255, 39 | ) 40 | 41 | query_record = Struct("query_record", 42 | DnsStringAdapter( 43 | RepeatUntil(lambda obj, ctx: obj == "", 44 | PascalString("name") 45 | ) 46 | ), 47 | dns_record_type, 48 | dns_record_class, 49 | ) 50 | 51 | rdata = Field("rdata", lambda ctx: ctx.rdata_length) 52 | 53 | resource_record = Struct("resource_record", 54 | CString("name", terminators = six.b("\xc0\x00")), 55 | Padding(1), 56 | dns_record_type, 57 | dns_record_class, 58 | UBInt32("ttl"), 59 | UBInt16("rdata_length"), 60 | IfThenElse("data", lambda ctx: ctx.type == "IPv4", 61 | IpAddressAdapter(rdata), 62 | rdata 63 | ) 64 | ) 65 | 66 | dns = Struct("dns", 67 | UBInt16("id"), 68 | BitStruct("flags", 69 | Enum(Bit("type"), 70 | QUERY = 0, 71 | RESPONSE = 1, 72 | ), 73 | Enum(Nibble("opcode"), 74 | STANDARD_QUERY = 0, 75 | INVERSE_QUERY = 1, 76 | SERVER_STATUS_REQUEST = 2, 77 | NOTIFY = 4, 78 | UPDATE = 5, 79 | ), 80 | Flag("authoritive_answer"), 81 | Flag("truncation"), 82 | Flag("recurssion_desired"), 83 | Flag("recursion_available"), 84 | Padding(1), 85 | Flag("authenticated_data"), 86 | Flag("checking_disabled"), 87 | Enum(Nibble("response_code"), 88 | SUCCESS = 0, 89 | FORMAT_ERROR = 1, 90 | SERVER_FAILURE = 2, 91 | NAME_DOES_NOT_EXIST = 3, 92 | NOT_IMPLEMENTED = 4, 93 | REFUSED = 5, 94 | NAME_SHOULD_NOT_EXIST = 6, 95 | RR_SHOULD_NOT_EXIST = 7, 96 | RR_SHOULD_EXIST = 8, 97 | NOT_AUTHORITIVE = 9, 98 | NOT_ZONE = 10, 99 | ), 100 | ), 101 | UBInt16("question_count"), 102 | UBInt16("answer_count"), 103 | UBInt16("authority_count"), 104 | UBInt16("additional_count"), 105 | Array(lambda ctx: ctx.question_count, 106 | Rename("questions", query_record), 107 | ), 108 | Rename("answers", 109 | Array(lambda ctx: ctx.answer_count, resource_record) 110 | ), 111 | Rename("authorities", 112 | Array(lambda ctx: ctx.authority_count, resource_record) 113 | ), 114 | Array(lambda ctx: ctx.additional_count, 115 | Rename("additionals", resource_record), 116 | ), 117 | ) 118 | 119 | 120 | if __name__ == "__main__": 121 | cap1 = unhexlify(six.b("2624010000010000000000000377777706676f6f676c6503636f6d0000010001")) 122 | 123 | cap2 = unhexlify(six.b( 124 | "2624818000010005000600060377777706676f6f676c6503636f6d0000010001c00c00" 125 | "05000100089065000803777777016cc010c02c0001000100000004000440e9b768c02c" 126 | "0001000100000004000440e9b793c02c0001000100000004000440e9b763c02c000100" 127 | "0100000004000440e9b767c030000200010000a88600040163c030c030000200010000" 128 | "a88600040164c030c030000200010000a88600040165c030c030000200010000a88600" 129 | "040167c030c030000200010000a88600040161c030c030000200010000a88600040162" 130 | "c030c0c00001000100011d0c0004d8ef3509c0d0000100010000ca7c000440e9b309c0" 131 | "80000100010000c4c5000440e9a109c0900001000100004391000440e9b709c0a00001" 132 | "00010000ca7c000442660b09c0b00001000100000266000440e9a709" 133 | )) 134 | 135 | obj = dns.parse(cap1) 136 | print (obj) 137 | print (repr(dns.build(obj))) 138 | 139 | print ("-" * 80) 140 | 141 | obj = dns.parse(cap2) 142 | print (obj) 143 | print (repr(dns.build(obj))) 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/ipstack.py: -------------------------------------------------------------------------------- 1 | """ 2 | TCP/IP Protocol Stack 3 | Note: before parsing the application layer over a TCP stream, you must 4 | first combine all the TCP frames into a stream. See utils.tcpip for 5 | some solutions 6 | """ 7 | from construct import Struct, Rename, HexDumpAdapter, Field, Switch, Pass 8 | from construct.protocols.layer2.ethernet import ethernet_header 9 | from construct.protocols.layer3.ipv4 import ipv4_header 10 | from construct.protocols.layer3.ipv6 import ipv6_header 11 | from construct.protocols.layer4.tcp import tcp_header 12 | from construct.protocols.layer4.udp import udp_header 13 | from binascii import unhexlify 14 | import six 15 | 16 | 17 | layer4_tcp = Struct("layer4_tcp", 18 | Rename("header", tcp_header), 19 | HexDumpAdapter( 20 | Field("next", lambda ctx: 21 | ctx["_"]["header"].payload_length - ctx["header"].header_length 22 | ) 23 | ), 24 | ) 25 | 26 | layer4_udp = Struct("layer4_udp", 27 | Rename("header", udp_header), 28 | HexDumpAdapter( 29 | Field("next", lambda ctx: ctx["header"].payload_length) 30 | ), 31 | ) 32 | 33 | layer3_payload = Switch("next", lambda ctx: ctx["header"].protocol, 34 | { 35 | "TCP" : layer4_tcp, 36 | "UDP" : layer4_udp, 37 | }, 38 | default = Pass 39 | ) 40 | 41 | layer3_ipv4 = Struct("layer3_ipv4", 42 | Rename("header", ipv4_header), 43 | layer3_payload, 44 | ) 45 | 46 | layer3_ipv6 = Struct("layer3_ipv6", 47 | Rename("header", ipv6_header), 48 | layer3_payload, 49 | ) 50 | 51 | layer2_ethernet = Struct("layer2_ethernet", 52 | Rename("header", ethernet_header), 53 | Switch("next", lambda ctx: ctx["header"].type, 54 | { 55 | "IPv4" : layer3_ipv4, 56 | "IPv6" : layer3_ipv6, 57 | }, 58 | default = Pass, 59 | ) 60 | ) 61 | 62 | ip_stack = Rename("ip_stack", layer2_ethernet) 63 | 64 | 65 | if __name__ == "__main__": 66 | cap1 = unhexlify(six.b( 67 | "0011508c283c001150886b570800450001e971474000800684e4c0a80202525eedda11" 68 | "2a0050d98ec61d54fe977d501844705dcc0000474554202f20485454502f312e310d0a" 69 | "486f73743a207777772e707974686f6e2e6f72670d0a557365722d4167656e743a204d" 70 | "6f7a696c6c612f352e30202857696e646f77733b20553b2057696e646f7773204e5420" 71 | "352e313b20656e2d55533b2072763a312e382e302e3129204765636b6f2f3230303630" 72 | "3131312046697265666f782f312e352e302e310d0a4163636570743a20746578742f78" 73 | "6d6c2c6170706c69636174696f6e2f786d6c2c6170706c69636174696f6e2f7868746d" 74 | "6c2b786d6c2c746578742f68746d6c3b713d302e392c746578742f706c61696e3b713d" 75 | "302e382c696d6167652f706e672c2a2f2a3b713d302e350d0a4163636570742d4c616e" 76 | "67756167653a20656e2d75732c656e3b713d302e350d0a4163636570742d456e636f64" 77 | "696e673a20677a69702c6465666c6174650d0a4163636570742d436861727365743a20" 78 | "49534f2d383835392d312c7574662d383b713d302e372c2a3b713d302e370d0a4b6565" 79 | "702d416c6976653a203330300d0a436f6e6e656374696f6e3a206b6565702d616c6976" 80 | "650d0a507261676d613a206e6f2d63616368650d0a43616368652d436f6e74726f6c3a" 81 | "206e6f2d63616368650d0a0d0a" 82 | )) 83 | 84 | cap2 = unhexlify(six.b( 85 | "0002e3426009001150f2c280080045900598fd22000036063291d149baeec0a8023c00" 86 | "500cc33b8aa7dcc4e588065010ffffcecd0000485454502f312e3120323030204f4b0d" 87 | "0a446174653a204672692c2031352044656320323030362032313a32363a323520474d" 88 | "540d0a5033503a20706f6c6963797265663d22687474703a2f2f7033702e7961686f6f" 89 | "2e636f6d2f7733632f7033702e786d6c222c2043503d2243414f2044535020434f5220" 90 | "4355522041444d20444556205441492050534120505344204956416920495644692043" 91 | "4f4e692054454c6f204f545069204f55522044454c692053414d69204f54526920554e" 92 | "5269205055426920494e4420504859204f4e4c20554e49205055522046494e20434f4d" 93 | "204e415620494e542044454d20434e542053544120504f4c204845412050524520474f" 94 | "56220d0a43616368652d436f6e74726f6c3a20707269766174650d0a566172793a2055" 95 | "7365722d4167656e740d0a5365742d436f6f6b69653a20443d5f796c683d58336f444d" 96 | "54466b64476c6f5a7a567842463954417a49334d5459784e446b4563476c6b417a4578" 97 | "4e6a59794d5463314e5463456447567a64414d7742485274634777446157356b5a5867" 98 | "7462412d2d3b20706174683d2f3b20646f6d61696e3d2e7961686f6f2e636f6d0d0a43" 99 | "6f6e6e656374696f6e3a20636c6f73650d0a5472616e736665722d456e636f64696e67" 100 | "3a206368756e6b65640d0a436f6e74656e742d547970653a20746578742f68746d6c3b" 101 | "20636861727365743d7574662d380d0a436f6e74656e742d456e636f64696e673a2067" 102 | "7a69700d0a0d0a366263382020200d0a1f8b0800000000000003dcbd6977db38b200fa" 103 | "f9fa9cf90f88326dd9b1169212b5d891739cd84ed2936d1277a7d3cbf1a1484a624c91" 104 | "0c4979893bbfec7d7bbfec556121012eb29d65e6be7be7762c9240a1502854150a85c2" 105 | "c37b87af9f9c7c7873449e9dbc7c41defcf2f8c5f327a4d1ee76dff79e74bb872787ec" 106 | "43bfa3e9ddeed1ab06692cd234daed762f2e2e3a17bd4e18cfbb276fbb8b74e9f7bb49" 107 | "1a7b76da7152a7b1bff110dfed3f5cb896030f4b37b508566dbb9f56def9a4f1240c52" 108 | "3748db275791db20367b9a3452f732a5d0f688bdb0e2c44d27bf9c1cb7470830b1632f" 109 | "4a490a3578c18fd6b9c5dec2f7732b2641783109dc0b7268a56e2bd527a931497b93b4" 110 | "3f49cd493a98a4c3493a9aa4e349aa6bf01f7cd78d89d6b2ed49b3d9baf223f8b307b5" 111 | "004a67eea627ded2dddadedb78d8656de428f856305f5973779223b0fff05ebbbde1db" 112 | "67082a499289ae0f06863e1c8f4c0639eaccbdd9a3547abf798a1f0ec6c73fafd2e4f1" 113 | "51ffd5f1c9e2f9e37ff74e74fbddd941b375eadb0942b3e3d5723a69f6060373a6cff4" 114 | "9e6df586dac8b11c4d1f1afd81319b0df45e6fd4925a6cee6db4dbfb19e225bc1b12e5" 115 | "6a098aed9309715c3b74dc5fde3e7f122ea3308061dac22f4018a4f8878367af5f4f2e" 116 | "bcc001a2d187bfffbefeb2477f75026be9269165bb93d92ab0532f0cb68264fbda9b6d" 117 | "dd0b92bfff867f3abe1bccd3c5f675eca6ab3820c1caf7f7be20e05363029f93c8f7d2" 118 | "ad46a7b1bd475ff62614f2de2c8cb7f08537d93a35fed0fe9a4c1af44363fb91beabed" 119 | "790f4f0d0e7a6f67c7dbbe3eedfd01e5bcbffe9a64bf289e00307bb1f7852371dadb13" 120 | "3df0c3798efba9d93a1db44e87dbd7d8b4cf50e95c780e304be745389fbbf11ef4cddf" 121 | "dcf4b162d629fa94d7defbe2fa892b3ece2c78d8fb221a84517003476a73dc3ad535d6" 122 | "e22c7fbd0db8cf3a511ca6211d3e28933fed9d8ea54f381f66c0c7f2cb0e4c3898ad2b" 123 | "3b0de3c9e918bf25abc88d6ddf02d65581418f94174addc9ebe94717e67ce557207b6d" 124 | "45f892773ae393adc62af57c18ecd27b46e5aa2feea5b58c7c173e6d94be1d3bd5afa3" 125 | "fcf571d409ded9b1eb06ef3d275d00c36f25f4916c6ed2a911cef88b0e4c0ecfa7a5b6" 126 | "27936600b3d28d9bdbe411" 127 | )) 128 | 129 | obj = ip_stack.parse(cap1) 130 | print (obj) 131 | print (repr(ip_stack.build(obj))) 132 | 133 | print ("-" * 80) 134 | 135 | obj = ip_stack.parse(cap2) 136 | print (obj) 137 | print (repr(ip_stack.build(obj))) 138 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer2/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | layer 2 (data link) protocols 3 | """ 4 | 5 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer2/arp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ethernet (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from ethernet import MacAddressAdapter 6 | from construct.protocols.layer3.ipv4 import IpAddressAdapter 7 | from binascii import unhexlify 8 | import six 9 | 10 | 11 | 12 | def HwAddress(name): 13 | return IfThenElse(name, lambda ctx: ctx.hardware_type == "ETHERNET", 14 | MacAddressAdapter(Field("data", lambda ctx: ctx.hwaddr_length)), 15 | Field("data", lambda ctx: ctx.hwaddr_length) 16 | ) 17 | 18 | def ProtoAddress(name): 19 | return IfThenElse(name, lambda ctx: ctx.protocol_type == "IP", 20 | IpAddressAdapter(Field("data", lambda ctx: ctx.protoaddr_length)), 21 | Field("data", lambda ctx: ctx.protoaddr_length) 22 | ) 23 | 24 | arp_header = Struct("arp_header", 25 | Enum(UBInt16("hardware_type"), 26 | ETHERNET = 1, 27 | EXPERIMENTAL_ETHERNET = 2, 28 | ProNET_TOKEN_RING = 4, 29 | CHAOS = 5, 30 | IEEE802 = 6, 31 | ARCNET = 7, 32 | HYPERCHANNEL = 8, 33 | ULTRALINK = 13, 34 | FRAME_RELAY = 15, 35 | FIBRE_CHANNEL = 18, 36 | IEEE1394 = 24, 37 | HIPARP = 28, 38 | ISO7816_3 = 29, 39 | ARPSEC = 30, 40 | IPSEC_TUNNEL = 31, 41 | INFINIBAND = 32, 42 | ), 43 | Enum(UBInt16("protocol_type"), 44 | IP = 0x0800, 45 | ), 46 | UBInt8("hwaddr_length"), 47 | UBInt8("protoaddr_length"), 48 | Enum(UBInt16("opcode"), 49 | REQUEST = 1, 50 | REPLY = 2, 51 | REQUEST_REVERSE = 3, 52 | REPLY_REVERSE = 4, 53 | DRARP_REQUEST = 5, 54 | DRARP_REPLY = 6, 55 | DRARP_ERROR = 7, 56 | InARP_REQUEST = 8, 57 | InARP_REPLY = 9, 58 | ARP_NAK = 10 59 | 60 | ), 61 | HwAddress("source_hwaddr"), 62 | ProtoAddress("source_protoaddr"), 63 | HwAddress("dest_hwaddr"), 64 | ProtoAddress("dest_protoaddr"), 65 | ) 66 | 67 | rarp_header = Rename("rarp_header", arp_header) 68 | 69 | 70 | if __name__ == "__main__": 71 | cap1 = unhexlify(six.b("00010800060400010002e3426009c0a80204000000000000c0a80201")) 72 | obj = arp_header.parse(cap1) 73 | print (obj) 74 | print (repr(arp_header.build(obj))) 75 | 76 | print ("-" * 80) 77 | 78 | cap2 = unhexlify(six.b("00010800060400020011508c283cc0a802010002e3426009c0a80204")) 79 | obj = arp_header.parse(cap2) 80 | print (obj) 81 | print (repr(arp_header.build(obj))) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer2/ethernet.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ethernet (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from binascii import hexlify, unhexlify 6 | import six 7 | 8 | 9 | class MacAddressAdapter(Adapter): 10 | def _encode(self, obj, context): 11 | return unhexlify(obj.replace("-", "")) 12 | def _decode(self, obj, context): 13 | return "-".join(hexlify(b) for b in obj) 14 | 15 | def MacAddress(name): 16 | return MacAddressAdapter(Bytes(name, 6)) 17 | 18 | ethernet_header = Struct("ethernet_header", 19 | MacAddress("destination"), 20 | MacAddress("source"), 21 | Enum(UBInt16("type"), 22 | IPv4 = 0x0800, 23 | ARP = 0x0806, 24 | RARP = 0x8035, 25 | X25 = 0x0805, 26 | IPX = 0x8137, 27 | IPv6 = 0x86DD, 28 | _default_ = Pass, 29 | ), 30 | ) 31 | 32 | 33 | if __name__ == "__main__": 34 | cap = unhexlify(six.b("0011508c283c0002e34260090800")) 35 | obj = ethernet_header.parse(cap) 36 | print (obj) 37 | print (repr(ethernet_header.build(obj))) 38 | 39 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer2/mtp2.py: -------------------------------------------------------------------------------- 1 | """ 2 | Message Transport Part 2 (SS7 protocol stack) 3 | (untested) 4 | """ 5 | from construct import * 6 | 7 | 8 | mtp2_header = BitStruct("mtp2_header", 9 | Octet("flag1"), 10 | Bits("bsn", 7), 11 | Bit("bib"), 12 | Bits("fsn", 7), 13 | Bit("sib"), 14 | Octet("length"), 15 | Octet("service_info"), 16 | Octet("signalling_info"), 17 | Bits("crc", 16), 18 | Octet("flag2"), 19 | ) 20 | 21 | 22 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | layer 3 (network) protocols 3 | """ 4 | 5 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/dhcpv4.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dynamic Host Configuration Protocol for IPv4 3 | 4 | http://www.networksorcery.com/enp/protocol/dhcp.htm 5 | http://www.networksorcery.com/enp/protocol/bootp/options.htm 6 | """ 7 | from construct import * 8 | from ipv4 import IpAddress 9 | from binascii import unhexlify 10 | import six 11 | 12 | 13 | dhcp_option = Struct("dhcp_option", 14 | Enum(Byte("code"), 15 | Pad = 0, 16 | Subnet_Mask = 1, 17 | Time_Offset = 2, 18 | Router = 3, 19 | Time_Server = 4, 20 | Name_Server = 5, 21 | Domain_Name_Server = 6, 22 | Log_Server = 7, 23 | Quote_Server = 8, 24 | LPR_Server = 9, 25 | Impress_Server = 10, 26 | Resource_Location_Server = 11, 27 | Host_Name = 12, 28 | Boot_File_Size = 13, 29 | Merit_Dump_File = 14, 30 | Domain_Name = 15, 31 | Swap_Server = 16, 32 | Root_Path = 17, 33 | Extensions_Path = 18, 34 | IP_Forwarding_enabledisable = 19, 35 | Nonlocal_Source_Routing_enabledisable = 20, 36 | Policy_Filter = 21, 37 | Maximum_Datagram_Reassembly_Size = 22, 38 | Default_IP_TTL = 23, 39 | Path_MTU_Aging_Timeout = 24, 40 | Path_MTU_Plateau_Table = 25, 41 | Interface_MTU = 26, 42 | All_Subnets_are_Local = 27, 43 | Broadcast_Address = 28, 44 | Perform_Mask_Discovery = 29, 45 | Mask_supplier = 30, 46 | Perform_router_discovery = 31, 47 | Router_solicitation_address = 32, 48 | Static_routing_table = 33, 49 | Trailer_encapsulation = 34, 50 | ARP_cache_timeout = 35, 51 | Ethernet_encapsulation = 36, 52 | Default_TCP_TTL = 37, 53 | TCP_keepalive_interval = 38, 54 | TCP_keepalive_garbage = 39, 55 | Network_Information_Service_domain = 40, 56 | Network_Information_Servers = 41, 57 | NTP_servers = 42, 58 | Vendor_specific_information = 43, 59 | NetBIOS_over_TCPIP_name_server = 44, 60 | NetBIOS_over_TCPIP_Datagram_Distribution_Server = 45, 61 | NetBIOS_over_TCPIP_Node_Type = 46, 62 | NetBIOS_over_TCPIP_Scope = 47, 63 | X_Window_System_Font_Server = 48, 64 | X_Window_System_Display_Manager = 49, 65 | Requested_IP_Address = 50, 66 | IP_address_lease_time = 51, 67 | Option_overload = 52, 68 | DHCP_message_type = 53, 69 | Server_identifier = 54, 70 | Parameter_request_list = 55, 71 | Message = 56, 72 | Maximum_DHCP_message_size = 57, 73 | Renew_time_value = 58, 74 | Rebinding_time_value = 59, 75 | Class_identifier = 60, 76 | Client_identifier = 61, 77 | NetWareIP_Domain_Name = 62, 78 | NetWareIP_information = 63, 79 | Network_Information_Service_Domain = 64, 80 | Network_Information_Service_Servers = 65, 81 | TFTP_server_name = 66, 82 | Bootfile_name = 67, 83 | Mobile_IP_Home_Agent = 68, 84 | Simple_Mail_Transport_Protocol_Server = 69, 85 | Post_Office_Protocol_Server = 70, 86 | Network_News_Transport_Protocol_Server = 71, 87 | Default_World_Wide_Web_Server = 72, 88 | Default_Finger_Server = 73, 89 | Default_Internet_Relay_Chat_Server = 74, 90 | StreetTalk_Server = 75, 91 | StreetTalk_Directory_Assistance_Server = 76, 92 | User_Class_Information = 77, 93 | SLP_Directory_Agent = 78, 94 | SLP_Service_Scope = 79, 95 | Rapid_Commit = 80, 96 | Fully_Qualified_Domain_Name = 81, 97 | Relay_Agent_Information = 82, 98 | Internet_Storage_Name_Service = 83, 99 | NDS_servers = 85, 100 | NDS_tree_name = 86, 101 | NDS_context = 87, 102 | BCMCS_Controller_Domain_Name_list = 88, 103 | BCMCS_Controller_IPv4_address_list = 89, 104 | Authentication = 90, 105 | Client_last_transaction_time = 91, 106 | Associated_ip = 92, 107 | Client_System_Architecture_Type = 93, 108 | Client_Network_Interface_Identifier = 94, 109 | Lightweight_Directory_Access_Protocol = 95, 110 | Client_Machine_Identifier = 97, 111 | Open_Group_User_Authentication = 98, 112 | Autonomous_System_Number = 109, 113 | NetInfo_Parent_Server_Address = 112, 114 | NetInfo_Parent_Server_Tag = 113, 115 | URL = 114, 116 | Auto_Configure = 116, 117 | Name_Service_Search = 117, 118 | Subnet_Selection = 118, 119 | DNS_domain_search_list = 119, 120 | SIP_Servers_DHCP_Option = 120, 121 | Classless_Static_Route_Option = 121, 122 | CableLabs_Client_Configuration = 122, 123 | GeoConf = 123, 124 | ), 125 | Switch("value", lambda ctx: ctx.code, 126 | { 127 | # codes without any value 128 | "Pad" : Pass, 129 | }, 130 | # codes followed by length and value fields 131 | default = Struct("value", 132 | Byte("length"), 133 | Field("data", lambda ctx: ctx.length), 134 | ) 135 | ) 136 | ) 137 | 138 | dhcp_header = Struct("dhcp_header", 139 | Enum(Byte("opcode"), 140 | BootRequest = 1, 141 | BootReply = 2, 142 | ), 143 | Enum(Byte("hardware_type"), 144 | Ethernet = 1, 145 | Experimental_Ethernet = 2, 146 | ProNET_Token_Ring = 4, 147 | Chaos = 5, 148 | IEEE_802 = 6, 149 | ARCNET = 7, 150 | Hyperchannel = 8, 151 | Lanstar = 9, 152 | ), 153 | Byte("hardware_address_length"), 154 | Byte("hop_count"), 155 | UBInt32("transaction_id"), 156 | UBInt16("elapsed_time"), 157 | BitStruct("flags", 158 | Flag("boardcast"), 159 | Padding(15), 160 | ), 161 | IpAddress("client_addr"), 162 | IpAddress("your_addr"), 163 | IpAddress("server_addr"), 164 | IpAddress("gateway_addr"), 165 | IpAddress("client_addr"), 166 | Bytes("client_hardware_addr", 16), 167 | Bytes("server_host_name", 64), 168 | Bytes("boot_filename", 128), 169 | # BOOTP/DHCP options 170 | # "The first four bytes contain the (decimal) values 99, 130, 83 and 99" 171 | Const(Bytes("magic", 4), six.b("\x63\x82\x53\x63")), 172 | Rename("options", OptionalGreedyRange(dhcp_option)), 173 | ) 174 | 175 | 176 | if __name__ == "__main__": 177 | test = unhexlify(six.b( 178 | "01" "01" "08" "ff" "11223344" "1234" "0000" 179 | "11223344" "aabbccdd" "11223444" "aabbccdd" "11223344" 180 | 181 | "11223344556677889900aabbccddeeff" 182 | 183 | "41414141414141414141414141414141" "41414141414141414141414141414141" 184 | "41414141414141414141414141414141" "41414141414141414141414141414141" 185 | 186 | "42424242424242424242424242424242" "42424242424242424242424242424242" 187 | "42424242424242424242424242424242" "42424242424242424242424242424242" 188 | "42424242424242424242424242424242" "42424242424242424242424242424242" 189 | "42424242424242424242424242424242" "42424242424242424242424242424242" 190 | 191 | "63825363" 192 | 193 | "0104ffffff00" 194 | "00" 195 | "060811223344aabbccdd" 196 | )) 197 | 198 | print (dhcp_header.parse(test)) 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/dhcpv6.py: -------------------------------------------------------------------------------- 1 | """ 2 | the Dynamic Host Configuration Protocol (DHCP) for IPv6 3 | 4 | http://www.networksorcery.com/enp/rfc/rfc3315.txt 5 | """ 6 | from construct import * 7 | from ipv6 import Ipv6Address 8 | import six 9 | 10 | 11 | dhcp_option = Struct("dhcp_option", 12 | Enum(UBInt16("code"), 13 | OPTION_CLIENTID = 1, 14 | OPTION_SERVERID = 2, 15 | OPTION_IA_NA = 3, 16 | OPTION_IA_TA = 4, 17 | OPTION_IAADDR = 5, 18 | OPTION_ORO = 6, 19 | OPTION_PREFERENCE = 7, 20 | OPTION_ELAPSED_TIME = 8, 21 | OPTION_RELAY_MSG = 9, 22 | OPTION_AUTH = 11, 23 | OPTION_UNICAST = 12, 24 | OPTION_STATUS_CODE = 13, 25 | OPTION_RAPID_COMMIT = 14, 26 | OPTION_USER_CLASS = 15, 27 | OPTION_VENDOR_CLASS = 16, 28 | OPTION_VENDOR_OPTS = 17, 29 | OPTION_INTERFACE_ID = 18, 30 | OPTION_RECONF_MSG = 19, 31 | OPTION_RECONF_ACCEPT = 20, 32 | SIP_SERVERS_DOMAIN_NAME_LIST = 21, 33 | SIP_SERVERS_IPV6_ADDRESS_LIST = 22, 34 | DNS_RECURSIVE_NAME_SERVER = 23, 35 | DOMAIN_SEARCH_LIST = 24, 36 | OPTION_IA_PD = 25, 37 | OPTION_IAPREFIX = 26, 38 | OPTION_NIS_SERVERS = 27, 39 | OPTION_NISP_SERVERS = 28, 40 | OPTION_NIS_DOMAIN_NAME = 29, 41 | OPTION_NISP_DOMAIN_NAME = 30, 42 | SNTP_SERVER_LIST = 31, 43 | INFORMATION_REFRESH_TIME = 32, 44 | BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 33, 45 | BCMCS_CONTROLLER_IPV6_ADDRESS_LIST = 34, 46 | OPTION_GEOCONF_CIVIC = 36, 47 | OPTION_REMOTE_ID = 37, 48 | RELAY_AGENT_SUBSCRIBER_ID = 38, 49 | OPTION_CLIENT_FQDN = 39, 50 | ), 51 | UBInt16("length"), 52 | Field("data", lambda ctx: ctx.length), 53 | ) 54 | 55 | client_message = Struct("client_message", 56 | Bitwise(BitField("transaction_id", 24)), 57 | ) 58 | 59 | relay_message = Struct("relay_message", 60 | Byte("hop_count"), 61 | Ipv6Address("linkaddr"), 62 | Ipv6Address("peeraddr"), 63 | ) 64 | 65 | dhcp_message = Struct("dhcp_message", 66 | Enum(Byte("msgtype"), 67 | # these are client-server messages 68 | SOLICIT = 1, 69 | ADVERTISE = 2, 70 | REQUEST = 3, 71 | CONFIRM = 4, 72 | RENEW = 5, 73 | REBIND = 6, 74 | REPLY = 7, 75 | RELEASE_ = 8, 76 | DECLINE_ = 9, 77 | RECONFIGURE = 10, 78 | INFORMATION_REQUEST = 11, 79 | # these two are relay messages 80 | RELAY_FORW = 12, 81 | RELAY_REPL = 13, 82 | ), 83 | # relay messages have a different structure from client-server messages 84 | Switch("params", lambda ctx: ctx.msgtype, 85 | { 86 | "RELAY_FORW" : relay_message, 87 | "RELAY_REPL" : relay_message, 88 | }, 89 | default = client_message, 90 | ), 91 | Rename("options", GreedyRange(dhcp_option)), 92 | ) 93 | 94 | 95 | if __name__ == "__main__": 96 | test1 = six.b("\x03\x11\x22\x33\x00\x17\x00\x03ABC\x00\x05\x00\x05HELLO") 97 | test2 = six.b("\x0c\x040123456789abcdef0123456789abcdef\x00\x09\x00\x0bhello world\x00\x01\x00\x00") 98 | print (dhcp_message.parse(test1)) 99 | print (dhcp_message.parse(test2)) 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/icmpv4.py: -------------------------------------------------------------------------------- 1 | """ 2 | Internet Control Message Protocol for IPv4 (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from ipv4 import IpAddress 6 | from binascii import unhexlify 7 | import six 8 | 9 | 10 | echo_payload = Struct("echo_payload", 11 | UBInt16("identifier"), 12 | UBInt16("sequence"), 13 | Bytes("data", 32), # length is implementation dependent... 14 | # is anyone using more than 32 bytes? 15 | ) 16 | 17 | dest_unreachable_payload = Struct("dest_unreachable_payload", 18 | Padding(2), 19 | UBInt16("next_hop_mtu"), 20 | IpAddress("host"), 21 | Bytes("echo", 8), 22 | ) 23 | 24 | dest_unreachable_code = Enum(Byte("code"), 25 | Network_unreachable_error = 0, 26 | Host_unreachable_error = 1, 27 | Protocol_unreachable_error = 2, 28 | Port_unreachable_error = 3, 29 | The_datagram_is_too_big = 4, 30 | Source_route_failed_error = 5, 31 | Destination_network_unknown_error = 6, 32 | Destination_host_unknown_error = 7, 33 | Source_host_isolated_error = 8, 34 | Desination_administratively_prohibited = 9, 35 | Host_administratively_prohibited2 = 10, 36 | Network_TOS_unreachable = 11, 37 | Host_TOS_unreachable = 12, 38 | ) 39 | 40 | icmp_header = Struct("icmp_header", 41 | Enum(Byte("type"), 42 | Echo_reply = 0, 43 | Destination_unreachable = 3, 44 | Source_quench = 4, 45 | Redirect = 5, 46 | Alternate_host_address = 6, 47 | Echo_request = 8, 48 | Router_advertisement = 9, 49 | Router_solicitation = 10, 50 | Time_exceeded = 11, 51 | Parameter_problem = 12, 52 | Timestamp_request = 13, 53 | Timestamp_reply = 14, 54 | Information_request = 15, 55 | Information_reply = 16, 56 | Address_mask_request = 17, 57 | Address_mask_reply = 18, 58 | _default_ = Pass, 59 | ), 60 | Switch("code", lambda ctx: ctx.type, 61 | { 62 | "Destination_unreachable" : dest_unreachable_code, 63 | }, 64 | default = Byte("code"), 65 | ), 66 | UBInt16("crc"), 67 | Switch("payload", lambda ctx: ctx.type, 68 | { 69 | "Echo_reply" : echo_payload, 70 | "Echo_request" : echo_payload, 71 | "Destination_unreachable" : dest_unreachable_payload, 72 | }, 73 | default = Pass 74 | ) 75 | ) 76 | 77 | 78 | if __name__ == "__main__": 79 | cap1 = unhexlify(six.b("0800305c02001b006162636465666768696a6b6c6d6e6f70717273747576776162" 80 | "63646566676869")) 81 | cap2 = unhexlify(six.b("0000385c02001b006162636465666768696a6b6c6d6e6f70717273747576776162" 82 | "63646566676869")) 83 | cap3 = unhexlify(six.b("0301000000001122aabbccdd0102030405060708")) 84 | 85 | print (icmp_header.parse(cap1)) 86 | print (icmp_header.parse(cap2)) 87 | print (icmp_header.parse(cap3)) 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/igmpv2.py: -------------------------------------------------------------------------------- 1 | """ 2 | What : Internet Group Management Protocol, Version 2 3 | How : http://www.ietf.org/rfc/rfc2236.txt 4 | Who : jesse @ housejunkie . ca 5 | """ 6 | 7 | from construct import Byte, Enum,Struct, UBInt16 8 | from construct.protocols.layer3.ipv4 import IpAddress 9 | from binascii import unhexlify 10 | import six 11 | 12 | 13 | igmp_type = Enum(Byte("igmp_type"), 14 | MEMBERSHIP_QUERY = 0x11, 15 | MEMBERSHIP_REPORT_V1 = 0x12, 16 | MEMBERSHIP_REPORT_V2 = 0x16, 17 | LEAVE_GROUP = 0x17, 18 | ) 19 | 20 | igmpv2_header = Struct("igmpv2_header", 21 | igmp_type, 22 | Byte("max_resp_time"), 23 | UBInt16("checksum"), 24 | IpAddress("group_address"), 25 | ) 26 | 27 | if __name__ == '__main__': 28 | capture = unhexlify(six.b("1600FA01EFFFFFFD")) 29 | print (igmpv2_header.parse(capture)) 30 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/ipv4.py: -------------------------------------------------------------------------------- 1 | """ 2 | Internet Protocol version 4 (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | import six 6 | from binascii import unhexlify 7 | 8 | 9 | class IpAddressAdapter(Adapter): 10 | def _encode(self, obj, context): 11 | return bytes(int(b) for b in obj.split(".")) 12 | def _decode(self, obj, context): 13 | if bytes is str: 14 | return ".".join(str(ord(b)) for b in obj) 15 | else: 16 | return ".".join("%d" % (b,) for b in obj) 17 | 18 | def IpAddress(name): 19 | return IpAddressAdapter(Bytes(name, 4)) 20 | 21 | def ProtocolEnum(code): 22 | return Enum(code, 23 | ICMP = 1, 24 | TCP = 6, 25 | UDP = 17, 26 | ) 27 | 28 | ipv4_header = Struct("ip_header", 29 | EmbeddedBitStruct( 30 | Const(Nibble("version"), 4), 31 | ExprAdapter(Nibble("header_length"), 32 | decoder = lambda obj, ctx: obj * 4, 33 | encoder = lambda obj, ctx: obj / 4 34 | ), 35 | ), 36 | BitStruct("tos", 37 | Bits("precedence", 3), 38 | Flag("minimize_delay"), 39 | Flag("high_throuput"), 40 | Flag("high_reliability"), 41 | Flag("minimize_cost"), 42 | Padding(1), 43 | ), 44 | UBInt16("total_length"), 45 | Value("payload_length", lambda ctx: ctx.total_length - ctx.header_length), 46 | UBInt16("identification"), 47 | EmbeddedBitStruct( 48 | Struct("flags", 49 | Padding(1), 50 | Flag("dont_fragment"), 51 | Flag("more_fragments"), 52 | ), 53 | Bits("frame_offset", 13), 54 | ), 55 | UBInt8("ttl"), 56 | ProtocolEnum(UBInt8("protocol")), 57 | UBInt16("checksum"), 58 | IpAddress("source"), 59 | IpAddress("destination"), 60 | Field("options", lambda ctx: ctx.header_length - 20), 61 | ) 62 | 63 | 64 | if __name__ == "__main__": 65 | cap = unhexlify(six.b("4500003ca0e3000080116185c0a80205d474a126")) 66 | obj = ipv4_header.parse(cap) 67 | print (obj) 68 | print (repr(ipv4_header.build(obj))) 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/ipv6.py: -------------------------------------------------------------------------------- 1 | """ 2 | Internet Protocol version 6 (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from ipv4 import ProtocolEnum 6 | from binascii import unhexlify 7 | import six 8 | 9 | 10 | class Ipv6AddressAdapter(Adapter): 11 | def _encode(self, obj, context): 12 | if bytes is str: 13 | return "".join(part.decode("hex") for part in obj.split(":")) 14 | else: 15 | return bytes(int(part, 16) for part in obj.split(":")) 16 | def _decode(self, obj, context): 17 | if bytes is str: 18 | return ":".join(b.encode("hex") for b in obj) 19 | else: 20 | return ":".join("%02x" % (b,) for b in obj) 21 | 22 | def Ipv6Address(name): 23 | return Ipv6AddressAdapter(Bytes(name, 16)) 24 | 25 | 26 | ipv6_header = Struct("ip_header", 27 | EmbeddedBitStruct( 28 | OneOf(Bits("version", 4), [6]), 29 | Bits("traffic_class", 8), 30 | Bits("flow_label", 20), 31 | ), 32 | UBInt16("payload_length"), 33 | ProtocolEnum(UBInt8("protocol")), 34 | UBInt8("hoplimit"), 35 | Alias("ttl", "hoplimit"), 36 | Ipv6Address("source"), 37 | Ipv6Address("destination"), 38 | ) 39 | 40 | 41 | if __name__ == "__main__": 42 | o = ipv6_header.parse(six.b("\x6f\xf0\x00\x00\x01\x02\x06\x80" 43 | "0123456789ABCDEF" "FEDCBA9876543210" 44 | )) 45 | print (o) 46 | print (repr(ipv6_header.build(o))) 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer3/mtp3.py: -------------------------------------------------------------------------------- 1 | """ 2 | Message Transport Part 3 (SS7 protocol stack) 3 | (untested) 4 | """ 5 | from construct import * 6 | 7 | 8 | mtp3_header = BitStruct("mtp3_header", 9 | Nibble("service_indicator"), 10 | Nibble("subservice"), 11 | ) 12 | 13 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer4/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | layer 4 (transporation) protocols 3 | """ 4 | 5 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer4/isup.py: -------------------------------------------------------------------------------- 1 | """ 2 | ISDN User Part (SS7 protocol stack) 3 | """ 4 | from construct import * 5 | 6 | 7 | isup_header = Struct("isup_header", 8 | Bytes("routing_label", 5), 9 | UBInt16("cic"), 10 | UBInt8("message_type"), 11 | # mandatory fixed parameters 12 | # mandatory variable parameters 13 | # optional parameters 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer4/tcp.py: -------------------------------------------------------------------------------- 1 | """ 2 | Transmission Control Protocol (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | from binascii import unhexlify 6 | import six 7 | 8 | 9 | tcp_header = Struct("tcp_header", 10 | UBInt16("source"), 11 | UBInt16("destination"), 12 | UBInt32("seq"), 13 | UBInt32("ack"), 14 | EmbeddedBitStruct( 15 | ExprAdapter(Nibble("header_length"), 16 | encoder = lambda obj, ctx: obj / 4, 17 | decoder = lambda obj, ctx: obj * 4, 18 | ), 19 | Padding(3), 20 | Struct("flags", 21 | Flag("ns"), 22 | Flag("cwr"), 23 | Flag("ece"), 24 | Flag("urg"), 25 | Flag("ack"), 26 | Flag("psh"), 27 | Flag("rst"), 28 | Flag("syn"), 29 | Flag("fin"), 30 | ), 31 | ), 32 | UBInt16("window"), 33 | UBInt16("checksum"), 34 | UBInt16("urgent"), 35 | Field("options", lambda ctx: ctx.header_length - 20), 36 | ) 37 | 38 | if __name__ == "__main__": 39 | cap = unhexlify(six.b("0db5005062303fb21836e9e650184470c9bc0000")) 40 | 41 | obj = tcp_header.parse(cap) 42 | print (obj) 43 | built = tcp_header.build(obj) 44 | print (built) 45 | assert cap == built 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /libs/python/construct/protocols/layer4/udp.py: -------------------------------------------------------------------------------- 1 | """ 2 | User Datagram Protocol (TCP/IP protocol stack) 3 | """ 4 | from construct import * 5 | import six 6 | from binascii import unhexlify 7 | 8 | 9 | udp_header = Struct("udp_header", 10 | Value("header_length", lambda ctx: 8), 11 | UBInt16("source"), 12 | UBInt16("destination"), 13 | ExprAdapter(UBInt16("payload_length"), 14 | encoder = lambda obj, ctx: obj + 8, 15 | decoder = lambda obj, ctx: obj - 8, 16 | ), 17 | UBInt16("checksum"), 18 | ) 19 | 20 | if __name__ == "__main__": 21 | cap = unhexlify(six.b("0bcc003500280689")) 22 | obj = udp_header.parse(cap) 23 | print (obj) 24 | print (repr(udp_header.build(obj))) 25 | 26 | 27 | -------------------------------------------------------------------------------- /libs/python/construct/version.py: -------------------------------------------------------------------------------- 1 | version = (2, 5, 1) 2 | version_string = "2.5.1" 3 | release_date = "2013.05.04" 4 | -------------------------------------------------------------------------------- /libs/python/usbmux/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythEch/pymobiledevice/ec293bef60a975db0a5486da9b6ac0e87caeb944/libs/python/usbmux/__init__.py -------------------------------------------------------------------------------- /libs/python/usbmux/usbmux.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env jython 2 | # -*- coding: utf-8 -*- 3 | # 4 | # usbmux.py - usbmux client library for Jython 5 | # 6 | # Copyright (C) 2014 Taconut 7 | # Copyright (C) 2014 PythEch 8 | # Copyright (C) 2009 Hector Martin "marcan" 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation, either version 2 or version 3. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | 23 | import jarray 24 | import os 25 | import socket 26 | import struct 27 | from java.io import BufferedInputStream, BufferedOutputStream 28 | from org.apache.commons.ssl import SSLClient, KeyMaterial, TrustMaterial 29 | 30 | 31 | if os._name == 'nt': 32 | from select import cpython_compatible_select as select 33 | else: 34 | from java.io import File 35 | from org.newsclub.net.unix import AFUNIXSocket, AFUNIXSocketAddress 36 | 37 | try: 38 | import plistlib 39 | haveplist = True 40 | except ImportError: 41 | haveplist = False 42 | 43 | 44 | class MuxError(Exception): 45 | pass 46 | 47 | class MuxVersionError(MuxError): 48 | pass 49 | 50 | 51 | class SafeStreamSocket(object): 52 | def __init__(self, address, family): 53 | self.sock = socket.socket(family, socket.SOCK_STREAM) 54 | self.sock.connect(address) 55 | 56 | def send(self, msg): 57 | totalsent = 0 58 | while totalsent < len(msg): 59 | sent = self.sock.send(msg[totalsent:]) 60 | if sent == 0: 61 | raise MuxError("socket connection broken") 62 | totalsent = totalsent + sent 63 | 64 | def recv(self, size): 65 | msg = '' 66 | while len(msg) < size: 67 | chunk = self.sock.recv(size-len(msg)) 68 | if chunk == '': 69 | raise MuxError("socket connection broken") 70 | msg = msg + chunk 71 | return msg 72 | 73 | 74 | class SafeUNIXSocket(object): 75 | def __init__(self, socketpath): 76 | self.sock = AFUNIXSocket.newInstance() 77 | self.sock.connect(AFUNIXSocketAddress(File(socketpath))) 78 | self._in_buf = BufferedInputStream(self.sock.getInputStream()) 79 | self._out_buf = BufferedOutputStream(self.sock.getOutputStream()) 80 | 81 | def recv(self, n=4096): 82 | data = jarray.zeros(n, 'b') 83 | m = self._in_buf.read(data, 0, n) 84 | if m <= 0: 85 | return "" 86 | if m < n: 87 | data = data[:m] 88 | return data.tostring() 89 | 90 | def send(self, s): 91 | self._out_buf.write(s) 92 | self._out_buf.flush() 93 | return len(s) 94 | 95 | 96 | class SSLSocket(object): 97 | def __init__(self, java_socket, keyfile=None): 98 | self.java_ssl_socket = self._nycs_socket(java_socket, keyfile) 99 | self._in_buf = BufferedInputStream(self.java_ssl_socket.getInputStream()) 100 | self._out_buf = BufferedOutputStream(self.java_ssl_socket.getOutputStream()) 101 | 102 | # Not-Yet-Commons-SSL Socket 103 | def _nycs_socket(self, java_socket, keyfile=None): 104 | host = java_socket.getInetAddress().getHostAddress() 105 | port = java_socket.getPort() 106 | client = SSLClient() 107 | client.setCheckHostname(False) 108 | client.setCheckExpiry(False) 109 | client.setCheckCRL(False) 110 | client.setKeyMaterial(KeyMaterial(keyfile, "")) 111 | client.setTrustMaterial(TrustMaterial.TRUST_ALL) 112 | java_ssl_socket = client.createSocket(java_socket, host, port, 0) 113 | java_ssl_socket.startHandshake() 114 | return java_ssl_socket 115 | 116 | def recv(self, n=4096): 117 | data = jarray.zeros(n, 'b') 118 | m = self._in_buf.read(data, 0, n) 119 | if m <= 0: 120 | return "" 121 | if m < n: 122 | data = data[:m] 123 | return data.tostring() 124 | 125 | def send(self, s): 126 | self._out_buf.write(s) 127 | self._out_buf.flush() 128 | return len(s) 129 | 130 | 131 | class MuxDevice(object): 132 | def __init__(self, devid, usbprod, serial, location): 133 | self.devid = devid 134 | self.usbprod = usbprod 135 | self.serial = serial 136 | self.location = location 137 | 138 | def __str__(self): 139 | return "" % (self.devid, self.usbprod, self.serial, self.location) 140 | 141 | 142 | class BinaryProtocol(object): 143 | TYPE_RESULT = 1 144 | TYPE_CONNECT = 2 145 | TYPE_LISTEN = 3 146 | TYPE_DEVICE_ADD = 4 147 | TYPE_DEVICE_REMOVE = 5 148 | VERSION = 0 149 | 150 | def __init__(self, socket): 151 | self.socket = socket 152 | self.connected = False 153 | 154 | def _pack(self, req, payload): 155 | if req == self.TYPE_CONNECT: 156 | return struct.pack("> 8)}) 294 | if ret != 0: 295 | raise MuxError("Connect failed: error %d" % ret) 296 | self.proto.connected = True 297 | return self.socket 298 | 299 | def close(self): 300 | self.socket.sock.close() 301 | 302 | 303 | class USBMux(object): 304 | def __init__(self, socketpath="/var/run/usbmuxd"): 305 | #FIXME: use /var/db/usbmuxd in Mac OS X 306 | self.socketpath = socketpath 307 | self.listener = MuxConnection(socketpath, BinaryProtocol) 308 | try: 309 | self.listener.listen() 310 | self.version = 0 311 | self.protoclass = BinaryProtocol 312 | except MuxVersionError: 313 | self.listener = MuxConnection(socketpath, PlistProtocol) 314 | self.listener.listen() 315 | self.protoclass = PlistProtocol 316 | self.version = 1 317 | self.devices = self.listener.devices 318 | 319 | def process(self, timeout=None): 320 | self.listener.process(timeout) 321 | 322 | def connect(self, device, port): 323 | connector = MuxConnection(self.socketpath, self.protoclass) 324 | return connector.connect(device, port) 325 | 326 | if __name__ == "__main__": 327 | mux = USBMux() 328 | print "Waiting for devices..." 329 | if not mux.devices: 330 | mux.process(0.1) 331 | while True: 332 | print "Devices:" 333 | for dev in mux.devices: 334 | print dev 335 | mux.process() 336 | -------------------------------------------------------------------------------- /libs/python/util/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | import plistlib 4 | import cPickle 5 | import gzip 6 | from bplist import BPlistReader 7 | 8 | def read_file(filename): 9 | f = open(filename, "rb") 10 | data = f.read() 11 | f.close() 12 | return data 13 | 14 | def write_file(filename,data): 15 | f = open(filename, "wb") 16 | f.write(data) 17 | f.close() 18 | 19 | def makedirs(dirs): 20 | try: 21 | os.makedirs(dirs) 22 | except: 23 | pass 24 | 25 | def getHomePath(foldername, filename): 26 | folderpath = os.path.join('~', foldername) 27 | if not os.path.exists(folderpath): 28 | makedirs(folderpath) 29 | return os.path.join(folderpath, filename) 30 | 31 | def readHomeFile(foldername, filename): 32 | path = getHomePath(foldername, filename) 33 | print "path: %s" % path 34 | if not os.path.exists(path): 35 | return None 36 | return read_file(path) 37 | 38 | #return path to HOME+foldername+filename 39 | def writeHomeFile(foldername, filename, data): 40 | filepath = getHomePath(foldername, filename) 41 | write_file(filepath, data) 42 | return filepath 43 | 44 | def readPlist(filename): 45 | f = open(filename,"rb") 46 | d = f.read(16) 47 | f.close() 48 | if d.startswith("bplist"): 49 | return BPlistReader.plistWithFile(filename) 50 | else: 51 | return plistlib.readPlist(filename) 52 | 53 | def parsePlist(s): 54 | if s.startswith("bplist"): 55 | return BPlistReader.plistWithString(s) 56 | else: 57 | return plistlib.readPlistFromString(s) 58 | 59 | #http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size 60 | def sizeof_fmt(num): 61 | for x in ['bytes','KB','MB','GB','TB']: 62 | if num < 1024.0: 63 | return "%d%s" % (num, x) 64 | num /= 1024.0 65 | 66 | #http://www.5dollarwhitebox.org/drupal/node/84 67 | def convert_bytes(bytes): 68 | bytes = float(bytes) 69 | if bytes >= 1099511627776: 70 | terabytes = bytes / 1099511627776 71 | size = '%.2fT' % terabytes 72 | elif bytes >= 1073741824: 73 | gigabytes = bytes / 1073741824 74 | size = '%.2fG' % gigabytes 75 | elif bytes >= 1048576: 76 | megabytes = bytes / 1048576 77 | size = '%.2fM' % megabytes 78 | elif bytes >= 1024: 79 | kilobytes = bytes / 1024 80 | size = '%.2fK' % kilobytes 81 | else: 82 | size = '%.2fb' % bytes 83 | return size 84 | 85 | def xor_strings(a,b): 86 | r="" 87 | for i in xrange(len(a)): 88 | r+= chr(ord(a[i])^ord(b[i])) 89 | return r 90 | 91 | hex = lambda data: " ".join("%02X" % ord(i) for i in data) 92 | ascii = lambda data: "".join(c if 31 < ord(c) < 127 else "." for c in data) 93 | 94 | def hexdump(d): 95 | hexStr = "" 96 | for i in xrange(0,len(d),16): 97 | data = d[i:i+16] 98 | hexStr += "%08X | %s | %s" % (i, hex(data).ljust(47), ascii(data)) 99 | return hexStr 100 | 101 | def search_plist(directory, matchDict): 102 | for p in map(os.path.normpath, glob.glob(directory + "/*.plist")): 103 | try: 104 | d = plistlib.readPlist(p) 105 | ok = True 106 | for k,v in matchDict.items(): 107 | if d.get(k) != v: 108 | ok = False 109 | break 110 | if ok: 111 | print "Using plist file %s" % p 112 | return d 113 | except: 114 | continue 115 | 116 | def save_pickle(filename,data): 117 | f = gzip.open(filename,"wb") 118 | cPickle.dump(data, f, cPickle.HIGHEST_PROTOCOL) 119 | f.close() 120 | 121 | def load_pickle(filename): 122 | f = gzip.open(filename,"rb") 123 | data = cPickle.load(f) 124 | f.close() 125 | return data 126 | -------------------------------------------------------------------------------- /libs/python/util/bplist.py: -------------------------------------------------------------------------------- 1 | """ 2 | http://github.com/farcaller/bplist-python/blob/master/bplist.py 3 | """ 4 | import struct 5 | import plistlib 6 | from datetime import datetime, timedelta 7 | 8 | class BPListWriter(object): 9 | def __init__(self, objects): 10 | self.bplist = "" 11 | self.objects = objects 12 | 13 | def binary(self): 14 | '''binary -> string 15 | 16 | Generates bplist 17 | ''' 18 | self.data = 'bplist00' 19 | 20 | # TODO: flatten objects and count max length size 21 | 22 | # TODO: write objects and save offsets 23 | 24 | # TODO: write offsets 25 | 26 | # TODO: write metadata 27 | 28 | return self.data 29 | 30 | def write(self, filename): 31 | ''' 32 | 33 | Writes bplist to file 34 | ''' 35 | if self.bplist != "": 36 | pass 37 | # TODO: save self.bplist to file 38 | else: 39 | raise Exception('BPlist not yet generated') 40 | 41 | class BPlistReader(object): 42 | def __init__(self, s): 43 | self.data = s 44 | self.objects = [] 45 | self.resolved = {} 46 | 47 | def __unpackIntStruct(self, sz, s): 48 | '''__unpackIntStruct(size, string) -> int 49 | 50 | Unpacks the integer of given size (1, 2 or 4 bytes) from string 51 | ''' 52 | if sz == 1: 53 | ot = '!B' 54 | elif sz == 2: 55 | ot = '!H' 56 | elif sz == 4: 57 | ot = '!I' 58 | elif sz == 8: 59 | ot = '!Q' 60 | else: 61 | raise Exception('int unpack size '+str(sz)+' unsupported') 62 | return struct.unpack(ot, s)[0] 63 | 64 | def __unpackInt(self, offset): 65 | '''__unpackInt(offset) -> int 66 | 67 | Unpacks int field from plist at given offset 68 | ''' 69 | return self.__unpackIntMeta(offset)[1] 70 | 71 | def __unpackIntMeta(self, offset): 72 | '''__unpackIntMeta(offset) -> (size, int) 73 | 74 | Unpacks int field from plist at given offset and returns its size and value 75 | ''' 76 | obj_header = struct.unpack('!B', self.data[offset])[0] 77 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 78 | int_sz = 2**obj_info 79 | return int_sz, self.__unpackIntStruct(int_sz, self.data[offset+1:offset+1+int_sz]) 80 | 81 | def __resolveIntSize(self, obj_info, offset): 82 | '''__resolveIntSize(obj_info, offset) -> (count, offset) 83 | 84 | Calculates count of objref* array entries and returns count and offset to first element 85 | ''' 86 | if obj_info == 0x0F: 87 | ofs, obj_count = self.__unpackIntMeta(offset+1) 88 | objref = offset+2+ofs 89 | else: 90 | obj_count = obj_info 91 | objref = offset+1 92 | return obj_count, objref 93 | 94 | def __unpackFloatStruct(self, sz, s): 95 | '''__unpackFloatStruct(size, string) -> float 96 | 97 | Unpacks the float of given size (4 or 8 bytes) from string 98 | ''' 99 | if sz == 4: 100 | ot = '!f' 101 | elif sz == 8: 102 | ot = '!d' 103 | else: 104 | raise Exception('float unpack size '+str(sz)+' unsupported') 105 | return struct.unpack(ot, s)[0] 106 | 107 | def __unpackFloat(self, offset): 108 | '''__unpackFloat(offset) -> float 109 | 110 | Unpacks float field from plist at given offset 111 | ''' 112 | obj_header = struct.unpack('!B', self.data[offset])[0] 113 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 114 | int_sz = 2**obj_info 115 | return int_sz, self.__unpackFloatStruct(int_sz, self.data[offset+1:offset+1+int_sz]) 116 | 117 | def __unpackDate(self, offset): 118 | td = int(struct.unpack(">d", self.data[offset+1:offset+9])[0]) 119 | return datetime(year=2001,month=1,day=1) + timedelta(seconds=td) 120 | 121 | def __unpackItem(self, offset): 122 | '''__unpackItem(offset) 123 | 124 | Unpacks and returns an item from plist 125 | ''' 126 | obj_header = struct.unpack('!B', self.data[offset])[0] 127 | obj_type, obj_info = (obj_header & 0xF0), (obj_header & 0x0F) 128 | if obj_type == 0x00: 129 | if obj_info == 0x00: # null 0000 0000 130 | return None 131 | elif obj_info == 0x08: # bool 0000 1000 // false 132 | return False 133 | elif obj_info == 0x09: # bool 0000 1001 // true 134 | return True 135 | elif obj_info == 0x0F: # fill 0000 1111 // fill byte 136 | raise Exception("0x0F Not Implemented") # this is really pad byte, FIXME 137 | else: 138 | raise Exception('unpack item type '+str(obj_header)+' at '+str(offset)+ 'failed') 139 | elif obj_type == 0x10: # int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes 140 | return self.__unpackInt(offset) 141 | elif obj_type == 0x20: # real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes 142 | return self.__unpackFloat(offset) 143 | elif obj_type == 0x30: # date 0011 0011 ... // 8 byte float follows, big-endian bytes 144 | return self.__unpackDate(offset) 145 | elif obj_type == 0x40: # data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes 146 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 147 | return plistlib.Data(self.data[objref:objref+obj_count]) # XXX: we return data as str 148 | elif obj_type == 0x50: # string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes 149 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 150 | return self.data[objref:objref+obj_count] 151 | elif obj_type == 0x60: # string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t 152 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 153 | return self.data[objref:objref+obj_count*2].decode('utf-16be') 154 | elif obj_type == 0x80: # uid 1000 nnnn ... // nnnn+1 is # of bytes 155 | # FIXME: Accept as a string for now 156 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 157 | return plistlib.Data(self.data[objref:objref+obj_count]) 158 | elif obj_type == 0xA0: # array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows 159 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 160 | arr = [] 161 | for i in range(obj_count): 162 | arr.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 163 | return arr 164 | elif obj_type == 0xC0: # set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows 165 | # XXX: not serializable via apple implementation 166 | raise Exception("0xC0 Not Implemented") # FIXME: implement 167 | elif obj_type == 0xD0: # dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows 168 | obj_count, objref = self.__resolveIntSize(obj_info, offset) 169 | keys = [] 170 | for i in range(obj_count): 171 | keys.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 172 | values = [] 173 | objref += obj_count*self.object_ref_size 174 | for i in range(obj_count): 175 | values.append(self.__unpackIntStruct(self.object_ref_size, self.data[objref+i*self.object_ref_size:objref+i*self.object_ref_size+self.object_ref_size])) 176 | dic = {} 177 | for i in range(obj_count): 178 | dic[keys[i]] = values[i] 179 | return dic 180 | else: 181 | raise Exception('don\'t know how to unpack obj type '+hex(obj_type)+' at '+str(offset)) 182 | 183 | def __resolveObject(self, idx): 184 | try: 185 | return self.resolved[idx] 186 | except KeyError: 187 | obj = self.objects[idx] 188 | if type(obj) == list: 189 | newArr = [] 190 | for i in obj: 191 | newArr.append(self.__resolveObject(i)) 192 | self.resolved[idx] = newArr 193 | return newArr 194 | if type(obj) == dict: 195 | newDic = {} 196 | for k,v in obj.iteritems(): 197 | rk = self.__resolveObject(k) 198 | rv = self.__resolveObject(v) 199 | newDic[rk] = rv 200 | self.resolved[idx] = newDic 201 | return newDic 202 | else: 203 | self.resolved[idx] = obj 204 | return obj 205 | 206 | def parse(self): 207 | # read header 208 | if self.data[:8] != 'bplist00': 209 | raise Exception('Bad magic') 210 | 211 | # read trailer 212 | self.offset_size, self.object_ref_size, self.number_of_objects, self.top_object, self.table_offset = struct.unpack('!6xBB4xI4xI4xI', self.data[-32:]) 213 | #print "** plist offset_size:",self.offset_size,"objref_size:",self.object_ref_size,"num_objs:",self.number_of_objects,"top:",self.top_object,"table_ofs:",self.table_offset 214 | 215 | # read offset table 216 | self.offset_table = self.data[self.table_offset:-32] 217 | self.offsets = [] 218 | ot = self.offset_table 219 | for i in xrange(self.number_of_objects): 220 | offset_entry = ot[:self.offset_size] 221 | ot = ot[self.offset_size:] 222 | self.offsets.append(self.__unpackIntStruct(self.offset_size, offset_entry)) 223 | #print "** plist offsets:",self.offsets 224 | 225 | # read object table 226 | self.objects = [] 227 | k = 0 228 | for i in self.offsets: 229 | obj = self.__unpackItem(i) 230 | #print "** plist unpacked",k,type(obj),obj,"at",i 231 | k += 1 232 | self.objects.append(obj) 233 | 234 | # rebuild object tree 235 | #for i in range(len(self.objects)): 236 | # self.__resolveObject(i) 237 | 238 | # return root object 239 | return self.__resolveObject(self.top_object) 240 | 241 | @classmethod 242 | def plistWithString(cls, s): 243 | parser = cls(s) 244 | return parser.parse() 245 | 246 | @classmethod 247 | def plistWithFile(cls, f): 248 | file = open(f,"rb") 249 | parser = cls(file.read()) 250 | file.close() 251 | return parser.parse() 252 | -------------------------------------------------------------------------------- /lockdown.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import platform 22 | import plistlib 23 | import uuid 24 | from usbmux import usbmux 25 | from util import readHomeFile, writeHomeFile 26 | 27 | from certificate import generateCertificates 28 | from plist_service import PlistService 29 | 30 | class NotTrustedError(Exception): 31 | pass 32 | 33 | class PairingError(Exception): 34 | pass 35 | 36 | class NotPairedError(Exception): 37 | pass 38 | 39 | class CannotStopSessionError(Exception): 40 | pass 41 | 42 | class StartServiceError(Exception): 43 | pass 44 | 45 | class FatalPairingError(Exception): 46 | pass 47 | 48 | #Store pairing records and ssl keys in ~/.pymobiledevice 49 | HOMEFOLDER = '.pymobiledevice' 50 | 51 | def list_devices(): 52 | mux = usbmux.USBMux() 53 | mux.process(1) 54 | return [d.serial for d in mux.devices] 55 | 56 | class LockdownClient(object): 57 | def __init__(self, udid=None): 58 | self.service = PlistService(62078, udid) 59 | self.hostID = self.generate_hostID() 60 | self.paired = False 61 | self.label = 'pyMobileDevice' 62 | response = self.service.sendRequest({'Request': 'QueryType'}) 63 | assert response['Type'] == 'com.apple.mobile.lockdown' 64 | 65 | self.allValues = self.getValue() 66 | self.udid = self.allValues.get('UniqueDeviceID') 67 | self.osVersion = self.allValues.get('ProductVersion') 68 | self.devicePublicKey = self.allValues.get('DevicePublicKey').data 69 | 70 | if not self.validate_pairing(): 71 | self.pair() 72 | if not self.validate_pairing(): 73 | raise FatalPairingError 74 | self.paired = True 75 | 76 | def generate_hostID(self): 77 | hostname = platform.node() 78 | hostid = uuid.uuid3(uuid.NAMESPACE_DNS, hostname) 79 | return str(hostid).upper() 80 | 81 | def enter_recovery(self): 82 | return self.service.sendRequest({'Request': 'EnterRecovery'}) 83 | 84 | def stop_session(self): 85 | if self.SessionID and self.service: 86 | self.SessionID = None 87 | response = self.service.sendRequest({ 88 | 'Request': 'StopSession', 89 | 'SessionID': self.SessionID 90 | }) 91 | if not response or response.get('Result') != 'Success': 92 | raise CannotStopSessionError 93 | return response 94 | 95 | def validate_pairing(self): 96 | record = readHomeFile(HOMEFOLDER, '%s.plist' % self.udid) 97 | if record: 98 | pair_record = plistlib.readPlistFromString(record) 99 | hostCertificate = pair_record['HostCertificate'].data 100 | hostPrivateKey = pair_record['HostPrivateKey'].data 101 | print "Found pairing record for device %s" % self.udid 102 | else: 103 | print "No pairing record found for device %s" % self.udid 104 | return False 105 | 106 | ValidatePair = self.service.sendRequest({ 107 | 'Request': 'ValidatePair', 108 | 'PairRecord': pair_record 109 | }) 110 | if not ValidatePair or 'Error' in ValidatePair: 111 | pair_record = None 112 | return False 113 | 114 | StartSession = self.service.sendRequest({ 115 | 'Request': 'StartSession', 116 | 'HostID': pair_record.get('HostID', self.hostID) 117 | }) 118 | self.SessionID = StartSession.get('SessionID') 119 | 120 | if StartSession.get('EnableSessionSSL'): 121 | keyfile = writeHomeFile(HOMEFOLDER, self.udid + "_ssl.txt", hostCertificate + '\n' + hostPrivateKey) 122 | self.service.start_ssl(keyfile) 123 | self.allValues = self.getValue() # iDevice gives more information after being trusted 124 | return True 125 | 126 | def pair(self): 127 | print "Creating host key & certificate" 128 | hostCertificate, hostPrivateKey, deviceCertificate = generateCertificates(self.devicePublicKey) 129 | 130 | pair_record = {'DevicePublicKey': plistlib.Data(self.devicePublicKey), 131 | 'DeviceCertificate': plistlib.Data(deviceCertificate), 132 | 'HostCertificate': plistlib.Data(hostCertificate), 133 | 'HostPrivateKey': plistlib.Data(hostPrivateKey), 134 | 'HostID': self.hostID, 135 | 'RootCertificate': plistlib.Data(hostCertificate), 136 | 'SystemBUID': '30142955-444094379208051516'} 137 | 138 | Pair = self.service.sendRequest({ 139 | 'Request': 'Pair', 140 | 'PairRecord': pair_record 141 | }) 142 | 143 | if self.osVersion[0] == '7' and Pair.get('Error') == 'PasswordProtected': 144 | raise NotTrustedError 145 | 146 | if Pair and Pair.get('Result') == 'Success' or 'EscrowBag' in Pair: 147 | if 'EscrowBag' in Pair: 148 | pair_record['EscrowBag'] = Pair['EscrowBag'] 149 | writeHomeFile(HOMEFOLDER, '%s.plist' % self.udid, plistlib.writePlistToString(pair_record)) 150 | else: 151 | raise PairingError 152 | 153 | def getValue(self, domain=None, key=None): 154 | request = {'Request': 'GetValue', 'Label': self.label} 155 | 156 | if domain: 157 | request['Domain'] = domain 158 | if key: 159 | request['Key'] = key 160 | response = self.service.sendRequest(request) 161 | if response: 162 | r = response.get('Value') 163 | if hasattr(r, 'data'): 164 | return r.data 165 | return r 166 | 167 | def startService(self, name): 168 | if not self.paired: 169 | raise NotPairedError 170 | 171 | StartService = self.service.sendRequest({ 172 | 'Request': 'StartService', 173 | 'Service': name 174 | }) 175 | 176 | if not StartService or 'Error' in StartService: 177 | raise StartServiceError(StartService['Error']) 178 | return PlistService(StartService['Port']) 179 | 180 | if __name__ == '__main__': 181 | l = LockdownClient() 182 | n = writeHomeFile(HOMEFOLDER, '%s_infos.plist' % l.udid, plistlib.writePlistToString(l.allValues)) 183 | print 'Wrote infos to %s' % n 184 | -------------------------------------------------------------------------------- /mobile_config.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import plistlib 22 | from optparse import OptionParser 23 | from pprint import pprint 24 | from util import read_file 25 | from lockdown import LockdownClient 26 | 27 | class MobileConfigService(object): 28 | def __init__(self, lockdown): 29 | self.lockdown = lockdown 30 | self.service = lockdown.startService("com.apple.mobile.MCInstall") 31 | 32 | def GetProfileList(self): 33 | self.service.sendPlist({"RequestType":"GetProfileList"}) 34 | res = self.service.recvPlist() 35 | if res.get("Status") != "Acknowledged": 36 | print "GetProfileList error" 37 | pprint(res) 38 | return 39 | return res 40 | 41 | def InstallProfile(self, s): 42 | #s = plistlib.writePlistToString(payload) 43 | self.service.sendPlist({"RequestType":"InstallProfile", "Payload": plistlib.Data(s)}) 44 | return self.service.recvPlist() 45 | 46 | def RemoveProfile(self, ident): 47 | profiles = self.GetProfileList() 48 | if not profiles: 49 | return 50 | if not profiles["ProfileMetadata"].has_key(ident): 51 | print "Trying to remove not installed profile %s" % ident 52 | return 53 | meta = profiles["ProfileMetadata"][ident] 54 | pprint(meta) 55 | data = plistlib.writePlistToString({"PayloadType": "Configuration", 56 | "PayloadIdentifier": ident, 57 | "PayloadUUID": meta["PayloadUUID"], 58 | "PayloadVersion": meta["PayloadVersion"] 59 | }) 60 | self.service.sendPlist({"RequestType":"RemoveProfile", "ProfileIdentifier": plistlib.Data(data)}) 61 | return self.service.recvPlist() 62 | 63 | def main(): 64 | parser = OptionParser(usage="%prog") 65 | parser.add_option("-l", "--list", dest="list", action="store_true", 66 | default=False, help="List installed profiles") 67 | parser.add_option("-i", "--install", dest="install", action="store", 68 | metavar="FILE", help="Install profile") 69 | parser.add_option("-r", "--remove", dest="remove", action="store", 70 | metavar="IDENTIFIER", help="Remove profile") 71 | (options, args) = parser.parse_args() 72 | 73 | if not options.list and not options.install and not options.remove: 74 | parser.print_help() 75 | return 76 | lockdown = LockdownClient() 77 | mc = MobileConfigService(lockdown) 78 | 79 | if options.list: 80 | pprint(mc.GetProfileList()) 81 | elif options.install: 82 | mc.InstallProfile(read_file(options.install)) 83 | elif options.remove: 84 | pprint(mc.RemoveProfile(options.remove)) 85 | 86 | if __name__ == "__main__": 87 | main() 88 | -------------------------------------------------------------------------------- /mobilebackup.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | import os 21 | import datetime 22 | import plistlib 23 | from afc import AFCClient 24 | from lockdown import LockdownClient 25 | 26 | # 27 | # Fix plistlib.py line 364 28 | # def asBase64(self, maxlinelength=76): 29 | # if self.data != None: 30 | # return _encodeBase64(self.data, maxlinelength) 31 | # return "" 32 | # 33 | # 34 | 35 | 36 | MOBILEBACKUP_E_SUCCESS = 0 37 | MOBILEBACKUP_E_INVALID_ARG = -1 38 | MOBILEBACKUP_E_PLIST_ERROR = -2 39 | MOBILEBACKUP_E_MUX_ERROR = -3 40 | MOBILEBACKUP_E_BAD_VERSION = -4 41 | MOBILEBACKUP_E_REPLY_NOT_OK = -5 42 | MOBILEBACKUP_E_UNKNOWN_ERROR = -256 43 | 44 | DEVICE_LINK_FILE_STATUS_NONE = 0 45 | DEVICE_LINK_FILE_STATUS_HUNK = 1 46 | DEVICE_LINK_FILE_STATUS_LAST_HUNK = 2 47 | 48 | 49 | class MobileBackupClient(object): 50 | def __init__(self, lockdown): 51 | self.lockdown = lockdown 52 | self.service = lockdown.startService("com.apple.mobilebackup") 53 | self.udid = lockdown.udid 54 | DLMessageVersionExchange = self.service.recvPlist() 55 | print DLMessageVersionExchange 56 | version_major = DLMessageVersionExchange[1] 57 | self.service.sendPlist(["DLMessageVersionExchange", "DLVersionsOk", version_major]) 58 | DLMessageDeviceReady = self.service.recvPlist() 59 | if DLMessageDeviceReady and DLMessageDeviceReady[0] == "DLMessageDeviceReady": 60 | print "Got DLMessageDeviceReady" 61 | 62 | def check_filename(self, name): 63 | if name.find("../") != -1: 64 | raise Exception("HAX, sneaky dots in path %s" % name) 65 | if not name.startswith(self.backupPath): 66 | if name.startswith(self.udid): 67 | return os.path.join(self.backupPath, name) 68 | return os.path.join(self.backupPath, self.udid, name) 69 | return name 70 | 71 | 72 | def read_file(self, filename): 73 | filename = self.check_filename(filename) 74 | if os.path.isfile(filename): 75 | f=open(filename, "rb") 76 | data = f.read() 77 | f.close() 78 | return data 79 | return None 80 | 81 | def write_file(self, filename, data): #FIXME 82 | filename = self.check_filename(filename) 83 | try: 84 | print "Writing filename %s" % filename 85 | f=open(filename, "wb") 86 | f.write(data) 87 | f.close() 88 | except: #FIXME 89 | print "mobilebackup.py Could not write", filename 90 | exit() 91 | 92 | 93 | def create_info_plist(self): 94 | root_node = self.lockdown.getValue() 95 | info = {"BuildVersion": root_node["BuildVersion"], 96 | "DeviceName": root_node["DeviceName"], 97 | "Display Name": root_node["DeviceName"], 98 | "GUID": "---", 99 | "ProductType": root_node["ProductType"], 100 | "ProductVersion": root_node["ProductVersion"], 101 | "Serial Number": root_node["SerialNumber"], 102 | "Unique Identifier": self.udid.upper(), 103 | "Target Identifier": self.udid, 104 | "Target Type": "Device", 105 | "iTunes Version": "10.0.1" 106 | } 107 | if root_node.has_key("IntegratedCircuitCardIdentity"): 108 | info["ICCID"] = root_node["IntegratedCircuitCardIdentity"] 109 | if root_node.has_key("InternationalMobileEquipmentIdentity"): 110 | info["IMEI"] = root_node["InternationalMobileEquipmentIdentity"] 111 | info["Last Backup Date"] = datetime.datetime.now() 112 | 113 | iTunesFiles = ["ApertureAlbumPrefs", 114 | "IC-Info.sidb", 115 | "IC-Info.sidv", 116 | "PhotosFolderAlbums", 117 | "PhotosFolderName", 118 | "PhotosFolderPrefs", 119 | "iPhotoAlbumPrefs", 120 | "iTunesApplicationIDs", 121 | "iTunesPrefs", 122 | "iTunesPrefs.plist" 123 | ] 124 | afc = AFCClient(self.lockdown) 125 | iTunesFilesDict = {} 126 | iTunesFiles = afc.read_directory("/iTunes_Control/iTunes/") 127 | #print iTunesFiles 128 | for i in iTunesFiles: 129 | data = afc.get_file_contents("/iTunes_Control/iTunes/" + i) 130 | if data: 131 | iTunesFilesDict[i] = plistlib.Data(data) 132 | info["iTunesFiles"] = iTunesFilesDict 133 | 134 | iBooksData2 = afc.get_file_contents("/Books/iBooksData2.plist") 135 | if iBooksData2: 136 | info["iBooks Data 2"] = plistlib.Data(iBooksData2) 137 | #pprint(info) 138 | print self.lockdown.getValue("com.apple.iTunes") 139 | info["iTunes Settings"] = self.lockdown.getValue("com.apple.iTunes") 140 | #self.backupPath = self.udid 141 | #if not os.path.isdir(self.backupPath): 142 | # os.makedirs(self.backupPath) 143 | #print info 144 | #raw_input() 145 | print "Creating %s" % os.path.join(self.udid,"Info.plist") 146 | self.write_file(os.path.join(self.udid,"Info.plist"), plistlib.writePlistToString(info)) 147 | 148 | def ping(self, message): 149 | self.service.sendPlist(["DLMessagePing", message]) 150 | print "ping response", self.service.recvPlist() 151 | 152 | def device_link_service_send_process_message(self, msg): 153 | return self.service.sendPlist(["DLMessageProcessMessage", msg]) 154 | 155 | def device_link_service_receive_process_message(self): 156 | req = self.service.recvPlist() 157 | if req: 158 | assert req[0] == "DLMessageProcessMessage" 159 | return req[1] 160 | 161 | def send_file_received(self): 162 | return self.device_link_service_send_process_message({"BackupMessageTypeKey": "kBackupMessageBackupFileReceived"}) 163 | 164 | def request_backup(self): 165 | req = {"BackupComputerBasePathKey": "/", 166 | "BackupMessageTypeKey": "BackupMessageBackupRequest", 167 | "BackupProtocolVersion": "1.6" 168 | } 169 | self.create_info_plist() 170 | self.device_link_service_send_process_message(req) 171 | res = self.device_link_service_receive_process_message() 172 | if not res: 173 | return 174 | if res["BackupMessageTypeKey"] != "BackupMessageBackupReplyOK": 175 | print res 176 | return 177 | self.device_link_service_send_process_message(res) 178 | 179 | filedata = "" 180 | f = None 181 | outpath = None 182 | while True: 183 | res = self.service.recvPlist() 184 | if not res or res[0] != "DLSendFile": 185 | if res[0] == "DLMessageProcessMessage": 186 | if res[1].get("BackupMessageTypeKey") == "BackupMessageBackupFinished": 187 | print "Backup finished OK !" 188 | #TODO BackupFilesToDeleteKey 189 | plistlib.writePlist(res[1]["BackupManifestKey"], self.check_filename("Manifest.plist")) 190 | break 191 | data = res[1].data 192 | info = res[2] 193 | if not f: 194 | outpath = self.check_filename(info["DLFileDest"]) 195 | print info["DLFileAttributesKey"]["Filename"], info["DLFileDest"] 196 | f = open(outpath + ".mddata", "wb") 197 | f.write(data) 198 | if info.get("DLFileStatusKey") == DEVICE_LINK_FILE_STATUS_LAST_HUNK: 199 | self.send_file_received() 200 | f.close() 201 | if not info.get("BackupManifestKey", False): 202 | plistlib.writePlist(info["BackupFileInfo"], outpath + ".mdinfo") 203 | f = None 204 | 205 | if __name__ == "__main__": 206 | lockdown = LockdownClient() 207 | mb = MobileBackupClient(lockdown) 208 | mb.request_backup() 209 | -------------------------------------------------------------------------------- /notification_proxy.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | from pprint import pprint 22 | from lockdown import LockdownClient 23 | 24 | class NPClient(object): 25 | def __init__(self, lockdown=None, serviceName="com.apple.mobile.notification_proxy"): 26 | if lockdown: 27 | self.lockdown = lockdown 28 | else: 29 | self.lockdown = LockdownClient() 30 | 31 | self.service = self.lockdown.startService(serviceName) 32 | self.packet_num = 0 33 | 34 | def stop_session(self): 35 | print "Disconecting..." 36 | self.service.close() 37 | 38 | def post_notification(self, notification): 39 | #Sends a notification to the device's notification_proxy. 40 | self.service.sendPlist({"Command": "PostNotification",#} 41 | "Name": notification}) 42 | res = self.service.recvPlist() 43 | pprint(res) 44 | return res 45 | 46 | def observe_notification(self, notification): 47 | #Tells the device to send a notification on the specified event 48 | self.service.sendPlist({"Command": "ObserveNotification",#} 49 | "Name": notification}) 50 | res = self.service.recvPlist() 51 | pprint(res) 52 | return res 53 | 54 | 55 | def get_notification(self, notification): 56 | #Checks if a notification has been sent by the device 57 | res = self.service.recvPlist() 58 | pprint(res) 59 | return res 60 | 61 | 62 | if __name__ == "__main__": 63 | lockdown = LockdownClient() 64 | ProductVersion = lockdown.getValue("", "ProductVersion") 65 | assert ProductVersion[0] >= "4" 66 | 67 | np = NPClient() 68 | np.get_notification() 69 | -------------------------------------------------------------------------------- /pcapd.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import time 22 | import struct 23 | from pymobiledevice.lockdown import LockdownClient 24 | 25 | LINKTYPE_ETHERNET = 1 26 | LINKTYPE_RAW = 101 27 | 28 | 29 | class PcapClient(object): 30 | def __init__(self, filename, lockdown=None): 31 | if lockdown: 32 | self.lockdown = lockdown 33 | else: 34 | self.lockdown = LockdownClient() 35 | 36 | self.service = self.lockdown.startService("com.apple.pcapd") 37 | 38 | self.f = open(filename, "wb") 39 | self.f.write(struct.pack("LBL", data[:9]) 62 | flags1, flags2, offset_to_ip_data, zero = struct.unpack(">LLLL", data[9:0x19]) 63 | assert hdrsize >= 0x19 64 | interfacetype = data[0x19:hdrsize].strip("\x00") 65 | t = time.time() 66 | print interfacetype, packet_size, t 67 | packet = data[hdrsize:] 68 | assert packet_size == len(packet) 69 | if offset_to_ip_data == 0: 70 | #add fake ethernet header for pdp packets 71 | packet = "\xBE\xEF" * 6 + "\x08\x00" + packet 72 | if not self.writePacket(packet): 73 | break 74 | 75 | def stop(self): 76 | self._stop = True 77 | self.f.close() 78 | 79 | if __name__ == "__main__": 80 | PcapClient("test.pcap").capturePackets() 81 | 82 | -------------------------------------------------------------------------------- /plist_service.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import os 22 | import plistlib 23 | import struct 24 | from re import sub 25 | from usbmux import usbmux 26 | from util.bplist import BPlistReader 27 | 28 | 29 | class PlistService(object): 30 | def __init__(self, port, udid=None): 31 | self.port = port 32 | self.connect(udid) 33 | 34 | def connect(self, udid=None): 35 | mux = usbmux.USBMux() 36 | mux.process(5.0) 37 | dev = None 38 | 39 | while not dev and mux.devices: 40 | if udid: 41 | for d in mux.devices: 42 | if d.serial == udid: 43 | dev = d 44 | print "Connecting to device: " + dev.serial 45 | else: 46 | dev = mux.devices[0] 47 | print "Connecting to device: " + dev.serial 48 | 49 | try: 50 | self.socket = mux.connect(dev, self.port) 51 | except: 52 | raise Exception("Connection to device port %d failed" % self.port) 53 | return dev.serial 54 | 55 | def close(self): 56 | self.socket.close() 57 | 58 | def recv(self, len=4096): 59 | return self.socket.recv(len) 60 | 61 | def send(self, data): 62 | return self.socket.send(data) 63 | 64 | def recv_exact(self, l): 65 | data = "" 66 | while l > 0: 67 | d = self.recv(l) 68 | if not d or len(d) == 0: 69 | break 70 | data += d 71 | l -= len(d) 72 | return data 73 | 74 | def recv_raw(self): 75 | l = self.recv(4) 76 | if not l or len(l) != 4: 77 | return 78 | l = struct.unpack(">L", l)[0] 79 | return self.recv_exact(l) 80 | 81 | def send_raw(self, data): 82 | return self.send(struct.pack(">L", len(data)) + data) 83 | 84 | def recvPlist(self): 85 | payload = self.recv_raw() 86 | #print '<<<<<<<<',payload 87 | if not payload: 88 | return 89 | if payload.startswith("bplist00"): 90 | return BPlistReader(payload).parse() 91 | elif payload.startswith("\/ \-_0-9\"\'\\=\.\?\!\+]+', '', payload.decode('utf-8')).encode('utf-8') 94 | return plistlib.readPlistFromString(payload) 95 | else: 96 | raise Exception("recvPlist invalid data : %s" % payload[:100].encode("hex")) 97 | 98 | def sendPlist(self, d): 99 | payload = plistlib.writePlistToString(d) 100 | #print '>>>>',payload 101 | l = struct.pack(">L", len(payload)) 102 | self.send(l + payload) 103 | 104 | def sendRequest(self, plist): 105 | self.sendPlist(plist) 106 | return self.recvPlist() 107 | 108 | def start_ssl(self, keyfile): 109 | if os._name == 'nt': 110 | self.socket = usbmux.SSLSocket(self.socket.sock._sock._get_jsocket(), keyfile) 111 | else: 112 | self.socket = usbmux.SSLSocket(self.socket.sock, keyfile) 113 | -------------------------------------------------------------------------------- /screenshotr.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import os 22 | from time import gmtime, strftime 23 | from optparse import OptionParser 24 | from lockdown import LockdownClient 25 | 26 | class screenshotrClient(object): 27 | def __init__(self, lockdown=None, serviceName='com.apple.mobile.screenshotr'): 28 | if lockdown: 29 | self.lockdown = lockdown 30 | else: 31 | self.lockdown = LockdownClient() 32 | #Starting Screenshot service 33 | self.service = self.lockdown.startService(serviceName) 34 | 35 | #hand check 36 | DLMessageVersionExchange = self.service.recvPlist() 37 | #assert len(DLMessageVersionExchange) == 2 38 | version_major = DLMessageVersionExchange[1] 39 | self.service.sendPlist(["DLMessageVersionExchange", "DLVersionsOk", version_major ]) 40 | DLMessageDeviceReady = self.service.recvPlist() 41 | 42 | def stop_session(self): 43 | self.service.close() 44 | 45 | def take_screenshot(self): 46 | self.service.sendPlist(['DLMessageProcessMessage', {'MessageType': 'ScreenShotRequest'}]) 47 | res = self.service.recvPlist() 48 | 49 | assert len(res) == 2 50 | assert res[0] == "DLMessageProcessMessage" 51 | 52 | if res[1].get('MessageType') == 'ScreenShotReply': 53 | data = res[1]['ScreenShotData'].data 54 | return data 55 | return None 56 | 57 | if __name__ == '__main__': 58 | parser = OptionParser(usage='%prog') 59 | parser.add_option('-p', '--path', dest='outDir', default=False, 60 | help='Output Directory (default: . )', type='string') 61 | (options, args) = parser.parse_args() 62 | 63 | outPath = '.' 64 | if options.outDir: 65 | outPath = options.outDir 66 | 67 | screenshotr = screenshotrClient() 68 | data = screenshotr.take_screenshot() 69 | if data: 70 | filename = strftime('screenshot-%Y-%m-%d-%H-%M-%S.tif',gmtime()) 71 | outPath = os.path.join(outPath, filename) 72 | print 'Saving Screenshot at %s' % outPath 73 | o = open(outPath,'wb') 74 | o.write(data) 75 | -------------------------------------------------------------------------------- /springboard.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # 7 | # pymobiledevice is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Lesser General Public License as published 9 | # by the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # pymobiledevice is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with pymobiledevice. If not, see . 19 | 20 | # Special Thanks: https://github.com/mountainstorm 21 | 22 | from lockdown import LockdownClient 23 | 24 | PORTRAIT = 1 25 | PORTRAIT_UPSIDE_DOWN = 2 26 | LANDSCAPE = 3 # home button to right 27 | LANDSCAPE_HOME_TO_LEFT = 4 28 | 29 | 30 | class SpringboardClient(object): 31 | def __init__(self, lockdown=None): 32 | if lockdown: 33 | self.lockdown = lockdown 34 | else: 35 | self.lockdown = LockdownClient() 36 | self.service = self.lockdown.startService("com.apple.springboardservices") 37 | 38 | def get_iconstate(self): 39 | return self.service.sendRequest({ 40 | 'command': 'getIconState', 41 | 'formatVersion': '2' 42 | })[0] 43 | 44 | def set_iconstate(self, state): 45 | self.service.sendPlist({ 46 | 'command': 'setIconState', 47 | 'iconState': state 48 | }) 49 | 50 | def get_iconpngdata(self, bundleid): 51 | return self.service.sendRequest({ 52 | 'command': 'getIconPNGData', 53 | 'bundleId': bundleid 54 | })['pngData'].data 55 | 56 | def get_interface_orientation(self): 57 | response = self.service.sendRequest({'command': 'getInterfaceOrientation'}) 58 | if response is None or 'interfaceOrientation' not in response: 59 | raise RuntimeError('Unable to retrieve interface orientation') 60 | return response['interfaceOrientation'] 61 | 62 | def get_wallpaper_pngdata(self): 63 | return self.service.sendRequest({'command': 'getHomeScreenWallpaperPNGData'})['pngData'].data 64 | -------------------------------------------------------------------------------- /syslog.py: -------------------------------------------------------------------------------- 1 | # 2 | # pymobiledevice - Jython implementation of libimobiledevice 3 | # 4 | # Copyright (C) 2014 Taconut 5 | # Copyright (C) 2014 PythEch 6 | # Copyright (C) 2013 GotoHack 7 | # 8 | # pymobiledevice is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # pymobiledevice is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with pymobiledevice. If not, see . 20 | 21 | import re 22 | from sys import exit 23 | from optparse import OptionParser 24 | from lockdown import LockdownClient 25 | 26 | class Syslog(object): 27 | def __init__(self, lockdown=None): 28 | if lockdown: 29 | self.lockdown = lockdown 30 | else: 31 | self.lockdown = LockdownClient() 32 | self.c = self.lockdown.startService("com.apple.syslog_relay") 33 | self.c.send("watch") 34 | 35 | 36 | def watch(self,procName=None,logFile=None): 37 | if logFile: 38 | f = open(logFile,'w') 39 | while True: 40 | d = self.c.recv(4096) 41 | if not d: 42 | break 43 | if procName: 44 | procFilter = re.compile(procName,re.IGNORECASE) 45 | if len(d.split(" ")) > 4 and not procFilter.search(d): 46 | continue 47 | print d.strip("\n\x00\x00") 48 | if logFile: 49 | f.write(d.replace("\x00", "")) 50 | 51 | if __name__ == "__main__": 52 | parser = OptionParser(usage="%prog") 53 | parser.add_option("-p", "--process", dest="procName", default=False, 54 | help="Show process log only", type="string") 55 | parser.add_option("-o", "--logfile", dest="logFile", default=False, 56 | help="Write Logs into specified file", type="string") 57 | (options, args) = parser.parse_args() 58 | 59 | try: 60 | while True: 61 | try: 62 | syslog = Syslog() 63 | syslog.watch(procName=options.procName,logFile=options.logFile) 64 | except KeyboardInterrupt: 65 | print "KeyboardInterrupt caught" 66 | raise 67 | else: 68 | pass 69 | 70 | 71 | except (KeyboardInterrupt, SystemExit): 72 | exit() 73 | --------------------------------------------------------------------------------