├── .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 |
--------------------------------------------------------------------------------