pymobiledevice3 4.27.4__tar.gz → 4.27.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/PKG-INFO +1 -1
  2. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/_version.py +3 -3
  3. pymobiledevice3-4.27.6/pymobiledevice3/restore/mbn.py +606 -0
  4. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/restore.py +22 -10
  5. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/afc.py +3 -2
  6. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/crash_reports.py +1 -1
  7. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/webinspector.py +19 -5
  8. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/tunneld/server.py +3 -2
  9. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/PKG-INFO +1 -1
  10. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/SOURCES.txt +1 -0
  11. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.gitattributes +0 -0
  12. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/FUNDING.yml +0 -0
  13. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  14. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  15. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  16. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/pull_request_template.md +0 -0
  17. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/workflows/codeql.yml +0 -0
  18. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/workflows/generate-executable.py +0 -0
  19. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/workflows/markdown-lint.yml +0 -0
  20. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/workflows/python-app.yml +0 -0
  21. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.github/workflows/python-publish.yml +0 -0
  22. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.gitignore +0 -0
  23. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/.pre-commit-config.yaml +0 -0
  24. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/CODE_OF_CONDUCT.md +0 -0
  25. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/CONTRIBUTING.md +0 -0
  26. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/LICENSE +0 -0
  27. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/README.md +0 -0
  28. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/example.gif +0 -0
  29. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/markdownlint-config.json +0 -0
  30. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/DTServices-14.2.txt +0 -0
  31. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/DTServices-14.5.txt +0 -0
  32. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/RemoteXPC.md +0 -0
  33. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/plist_sniffer.py +0 -0
  34. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/pyinstaller.md +0 -0
  35. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/remotexpc_sniffer.py +0 -0
  36. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/understanding_idevice_protocol_layers.md +0 -0
  37. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/misc/usbmux_sniff.sh +0 -0
  38. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/__init__.py +0 -0
  39. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/__main__.py +0 -0
  40. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/bonjour.py +0 -0
  41. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/ca.py +0 -0
  42. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/__init__.py +0 -0
  43. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/activation.py +0 -0
  44. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/afc.py +0 -0
  45. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/amfi.py +0 -0
  46. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/apps.py +0 -0
  47. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/backup.py +0 -0
  48. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/bonjour.py +0 -0
  49. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/cli_common.py +0 -0
  50. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/companion_proxy.py +0 -0
  51. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/completions.py +0 -0
  52. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/crash.py +0 -0
  53. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/developer.py +0 -0
  54. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/diagnostics.py +0 -0
  55. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/lockdown.py +0 -0
  56. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/mounter.py +0 -0
  57. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/notification.py +0 -0
  58. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/pcap.py +0 -0
  59. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/power_assertion.py +0 -0
  60. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/processes.py +0 -0
  61. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/profile.py +0 -0
  62. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/provision.py +0 -0
  63. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/remote.py +0 -0
  64. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/restore.py +0 -0
  65. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/springboard.py +0 -0
  66. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/syslog.py +0 -0
  67. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/usbmux.py +0 -0
  68. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/version.py +0 -0
  69. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/cli/webinspector.py +0 -0
  70. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/common.py +0 -0
  71. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/exceptions.py +0 -0
  72. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/irecv.py +0 -0
  73. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/irecv_devices.py +0 -0
  74. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/lockdown.py +0 -0
  75. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/lockdown_service_provider.py +0 -0
  76. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/osu/__init__.py +0 -0
  77. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/osu/os_utils.py +0 -0
  78. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/osu/posix_util.py +0 -0
  79. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/osu/win_util.py +0 -0
  80. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/pair_records.py +0 -0
  81. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/__init__.py +0 -0
  82. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/common.py +0 -0
  83. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/__init__.py +0 -0
  84. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/app_service.py +0 -0
  85. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/core_device_service.py +0 -0
  86. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/device_info.py +0 -0
  87. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/diagnostics_service.py +0 -0
  88. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/core_device/file_service.py +0 -0
  89. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/module_imports.py +0 -0
  90. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/remote_service.py +0 -0
  91. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/remote_service_discovery.py +0 -0
  92. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/remotexpc.py +0 -0
  93. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/tunnel_service.py +0 -0
  94. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/utils.py +0 -0
  95. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/remote/xpc_message.py +0 -0
  96. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/__init__.py +0 -0
  97. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/dsc_uuid_map.json +0 -0
  98. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/dsc_uuid_map.py +0 -0
  99. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/firmware_notifications.py +0 -0
  100. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/notifications.txt +0 -0
  101. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/element_attribute.js +0 -0
  102. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/element_clear.js +0 -0
  103. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/enter_fullscreen.js +0 -0
  104. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/find_nodes.js +0 -0
  105. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/focus.js +0 -0
  106. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/get_attribute.js +0 -0
  107. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/is_displayed.js +0 -0
  108. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/is_editable.js +0 -0
  109. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/resources/webinspector/is_enabled.js +0 -0
  110. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/__init__.py +0 -0
  111. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/asr.py +0 -0
  112. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/base_restore.py +0 -0
  113. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/consts.py +0 -0
  114. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/device.py +0 -0
  115. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/fdr.py +0 -0
  116. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/ftab.py +0 -0
  117. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/img4.py +0 -0
  118. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/recovery.py +0 -0
  119. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/restore_options.py +0 -0
  120. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/restored_client.py +0 -0
  121. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/restore/tss.py +0 -0
  122. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/service_connection.py +0 -0
  123. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/__init__.py +0 -0
  124. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/accessibilityaudit.py +0 -0
  125. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/amfi.py +0 -0
  126. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/companion.py +0 -0
  127. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/debugserver_applist.py +0 -0
  128. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/device_arbitration.py +0 -0
  129. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/device_link.py +0 -0
  130. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/diagnostics.py +0 -0
  131. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dtfetchsymbols.py +0 -0
  132. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/__init__.py +0 -0
  133. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +0 -0
  134. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +0 -0
  135. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/__init__.py +0 -0
  136. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +0 -0
  137. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/application_listing.py +0 -0
  138. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/condition_inducer.py +0 -0
  139. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +0 -0
  140. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/device_info.py +0 -0
  141. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/energy_monitor.py +0 -0
  142. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/graphics.py +0 -0
  143. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/location_simulation.py +0 -0
  144. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/location_simulation_base.py +0 -0
  145. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/network_monitor.py +0 -0
  146. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/notifications.py +0 -0
  147. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/process_control.py +0 -0
  148. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/screenshot.py +0 -0
  149. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/instruments/sysmontap.py +0 -0
  150. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/dvt/testmanaged/xcuitest.py +0 -0
  151. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/file_relay.py +0 -0
  152. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/heartbeat.py +0 -0
  153. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/house_arrest.py +0 -0
  154. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/installation_proxy.py +0 -0
  155. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/lockdown_service.py +0 -0
  156. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/misagent.py +0 -0
  157. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/mobile_activation.py +0 -0
  158. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/mobile_config.py +0 -0
  159. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/mobile_image_mounter.py +0 -0
  160. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/mobilebackup2.py +0 -0
  161. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/notification_proxy.py +0 -0
  162. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/os_trace.py +0 -0
  163. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/pcapd.py +0 -0
  164. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/power_assertion.py +0 -0
  165. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/preboard.py +0 -0
  166. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/remote_fetch_symbols.py +0 -0
  167. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/remote_server.py +0 -0
  168. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/restore_service.py +0 -0
  169. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/screenshot.py +0 -0
  170. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/simulate_location.py +0 -0
  171. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/springboard.py +0 -0
  172. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/syslog.py +0 -0
  173. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/__init__.py +0 -0
  174. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/alert.py +0 -0
  175. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/automation_session.py +0 -0
  176. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/cdp_screencast.py +0 -0
  177. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/cdp_server.py +0 -0
  178. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/cdp_target.py +0 -0
  179. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/driver.py +0 -0
  180. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/element.py +0 -0
  181. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/inspector_session.py +0 -0
  182. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/selenium_api.py +0 -0
  183. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/session_protocol.py +0 -0
  184. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/services/web_protocol/switch_to.py +0 -0
  185. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/tcp_forwarder.py +0 -0
  186. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/tunneld/__init__.py +0 -0
  187. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/tunneld/api.py +0 -0
  188. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/usbmux.py +0 -0
  189. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3/utils.py +0 -0
  190. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/dependency_links.txt +0 -0
  191. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/entry_points.txt +0 -0
  192. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/requires.txt +0 -0
  193. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pymobiledevice3.egg-info/top_level.txt +0 -0
  194. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pyproject.toml +0 -0
  195. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/pytest.ini +0 -0
  196. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/requirements.txt +0 -0
  197. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/setup.cfg +0 -0
  198. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/__init__.py +0 -0
  199. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/cli/__init__.py +0 -0
  200. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/cli/test_cli.py +0 -0
  201. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/conftest.py +0 -0
  202. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/__init__.py +0 -0
  203. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/__init__.py +0 -0
  204. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/test_core_profile_session.py +0 -0
  205. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/test_dvt_secure_socket_proxy.py +0 -0
  206. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/test_fetch_symbols.py +0 -0
  207. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/test_location.py +0 -0
  208. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/instruments/test_screenshot.py +0 -0
  209. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_accessibility.py +0 -0
  210. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_afc.py +0 -0
  211. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_apps.py +0 -0
  212. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_backup2.py +0 -0
  213. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_bonjour.py +0 -0
  214. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_crash_reports.py +0 -0
  215. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_list_devices.py +0 -0
  216. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_lockdown.py +0 -0
  217. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_pcapd.py +0 -0
  218. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_springboard_services_relay.py +0 -0
  219. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_start_tunnel.py +0 -0
  220. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_syslog_relay.py +0 -0
  221. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_tcp_forwarder.py +0 -0
  222. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_web_protocol/__init__.py +0 -0
  223. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_web_protocol/common.py +0 -0
  224. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_web_protocol/conftest.py +0 -0
  225. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_web_protocol/test_driver.py +0 -0
  226. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_web_protocol/test_element.py +0 -0
  227. {pymobiledevice3-4.27.4 → pymobiledevice3-4.27.6}/tests/services/test_webinspector.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymobiledevice3
3
- Version: 4.27.4
3
+ Version: 4.27.6
4
4
  Summary: Pure python3 implementation for working with iDevices (iPhone, etc...)
5
5
  Author-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
6
6
  Maintainer-email: doronz88 <doron88@gmail.com>, matan <matan1008@gmail.com>
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '4.27.4'
32
- __version_tuple__ = version_tuple = (4, 27, 4)
31
+ __version__ = version = '4.27.6'
32
+ __version_tuple__ = version_tuple = (4, 27, 6)
33
33
 
34
- __commit_id__ = commit_id = 'g1b0c0afd0'
34
+ __commit_id__ = commit_id = 'gb568fdc20'
@@ -0,0 +1,606 @@
1
+ # mbn.py
2
+ # Support for Qualcomm MBN (Modem Binary) formats — Python port
3
+ # Mirrors the logic of mbn.c (v1/v2/BIN headers, ELF detection, and v7 stitching)
4
+ #
5
+ # Copyright (c) 2012 Martin Szulecki
6
+ # Copyright (c) 2012 Nikias Bassen
7
+ # Copyright (c) 2025 Visual Ehrmanntraut <visual@chefkiss.dev>
8
+ #
9
+ # Ported to Python by DoronZ <doron88@gmail.com>. Licensed under LGPL-2.1-or-later (same as original).
10
+
11
+ import io
12
+ import logging
13
+ from typing import Optional
14
+
15
+ from construct import Bytes, ChecksumError, Int16ul, Int32ul, Int64ul, Struct
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # -----------------------------------------------------------------------------
20
+ # Constants
21
+ # -----------------------------------------------------------------------------
22
+ MBN_V1_MAGIC = b"\x0a\x00\x00\x00"
23
+ MBN_V1_MAGIC_SIZE = 4
24
+
25
+ MBN_V2_MAGIC = b"\xd1\xdc\x4b\x84\x34\x10\xd7\x73"
26
+ MBN_V2_MAGIC_SIZE = 8
27
+
28
+ MBN_BIN_MAGIC = b"\x04\x00\xea\x6c\x69\x48\x55"
29
+ MBN_BIN_MAGIC_SIZE = 7
30
+ MBN_BIN_MAGIC_OFFSET = 1
31
+
32
+ # ELF
33
+ EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3, EI_CLASS = 0, 1, 2, 3, 4
34
+ EI_NIDENT = 16
35
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 = 0x7F, ord("E"), ord("L"), ord("F")
36
+ ELFCLASSNONE, ELFCLASS32, ELFCLASS64 = 0, 1, 2
37
+
38
+ # -----------------------------------------------------------------------------
39
+ # Construct Structs (little-endian)
40
+ # -----------------------------------------------------------------------------
41
+
42
+ # MBN v1
43
+ MBN_V1 = Struct(
44
+ "type" / Int32ul,
45
+ "unk_0x04" / Int32ul,
46
+ "unk_0x08" / Int32ul,
47
+ "unk_0x0c" / Int32ul,
48
+ "data_size" / Int32ul, # total - sizeof(header)
49
+ "sig_offset" / Int32ul, # real offset = enc_sig_offset & 0xFFFFFF00 (FYI)
50
+ "unk_0x18" / Int32ul,
51
+ "unk_0x1c" / Int32ul,
52
+ "unk_0x20" / Int32ul,
53
+ "unk_0x24" / Int32ul,
54
+ )
55
+
56
+ # MBN v2
57
+ MBN_V2 = Struct(
58
+ "magic1" / Bytes(8),
59
+ "unk_0x08" / Int32ul,
60
+ "unk_0x0c" / Int32ul, # 0xFFFFFFFF
61
+ "unk_0x10" / Int32ul, # 0xFFFFFFFF
62
+ "header_size" / Int32ul,
63
+ "unk_0x18" / Int32ul,
64
+ "data_size" / Int32ul, # total - sizeof(header)
65
+ "sig_offset" / Int32ul,
66
+ "unk_0x24" / Int32ul,
67
+ "unk_0x28" / Int32ul,
68
+ "unk_0x2c" / Int32ul,
69
+ "unk_0x30" / Int32ul,
70
+ "unk_0x34" / Int32ul, # 0x1
71
+ "unk_0x38" / Int32ul, # 0x1
72
+ "unk_0x3c" / Int32ul, # 0xFFFFFFFF
73
+ "unk_0x40" / Int32ul, # 0xFFFFFFFF
74
+ "unk_0x44" / Int32ul, # 0xFFFFFFFF
75
+ "unk_0x48" / Int32ul, # 0xFFFFFFFF
76
+ "unk_0x4c" / Int32ul, # 0xFFFFFFFF
77
+ )
78
+
79
+ # MBN BIN
80
+ MBN_BIN = Struct(
81
+ "magic" / Bytes(8),
82
+ "unk_0x08" / Int32ul,
83
+ "version" / Int32ul,
84
+ "total_size" / Int32ul, # includes header
85
+ "unk_0x14" / Int32ul,
86
+ )
87
+
88
+ # v7 trailer header used by mbn_mav25_stitch
89
+ MBN_V7 = Struct(
90
+ "reserved" / Int32ul,
91
+ "version" / Int32ul,
92
+ "common_metadata_size" / Int32ul,
93
+ "qti_metadata_size" / Int32ul,
94
+ "oem_metadata_size" / Int32ul,
95
+ "hash_table_size" / Int32ul,
96
+ "qti_signature_size" / Int32ul,
97
+ "qti_certificate_chain_size" / Int32ul,
98
+ "oem_signature_size" / Int32ul,
99
+ "oem_certificate_chain_size" / Int32ul,
100
+ )
101
+
102
+ # ELF (minimal fields we need)
103
+ ELF32_Ehdr = Struct(
104
+ "e_ident" / Bytes(16),
105
+ "e_type" / Int16ul,
106
+ "e_machine" / Int16ul,
107
+ "e_version" / Int32ul,
108
+ "e_entry" / Int32ul,
109
+ "e_phoff" / Int32ul,
110
+ "e_shoff" / Int32ul,
111
+ "e_flags" / Int32ul,
112
+ "e_ehsize" / Int16ul,
113
+ "e_phentsize" / Int16ul,
114
+ "e_phnum" / Int16ul,
115
+ "e_shentsize" / Int16ul,
116
+ "e_shnum" / Int16ul,
117
+ "e_shstrndx" / Int16ul,
118
+ )
119
+
120
+ ELF64_Ehdr = Struct(
121
+ "e_ident" / Bytes(16),
122
+ "e_type" / Int16ul,
123
+ "e_machine" / Int16ul,
124
+ "e_version" / Int32ul,
125
+ "e_entry" / Int64ul,
126
+ "e_phoff" / Int64ul,
127
+ "e_shoff" / Int64ul,
128
+ "e_flags" / Int32ul,
129
+ "e_ehsize" / Int16ul,
130
+ "e_phentsize" / Int16ul,
131
+ "e_phnum" / Int16ul,
132
+ "e_shentsize" / Int16ul,
133
+ "e_shnum" / Int16ul,
134
+ "e_shstrndx" / Int16ul,
135
+ )
136
+
137
+ ELF32_Phdr = Struct(
138
+ "p_type" / Int32ul,
139
+ "p_offset" / Int32ul,
140
+ "p_vaddr" / Int32ul,
141
+ "p_paddr" / Int32ul,
142
+ "p_filesz" / Int32ul,
143
+ "p_memsz" / Int32ul,
144
+ "p_flags" / Int32ul,
145
+ "p_align" / Int32ul,
146
+ )
147
+
148
+ ELF64_Phdr = Struct(
149
+ "p_type" / Int32ul,
150
+ "p_flags" / Int32ul,
151
+ "p_offset" / Int64ul,
152
+ "p_vaddr" / Int64ul,
153
+ "p_paddr" / Int64ul,
154
+ "p_filesz" / Int64ul,
155
+ "p_memsz" / Int64ul,
156
+ "p_align" / Int64ul,
157
+ )
158
+
159
+
160
+ # -----------------------------------------------------------------------------
161
+ # Helpers
162
+ # -----------------------------------------------------------------------------
163
+
164
+
165
+ def _is_valid_elf_ident(e_ident: bytes) -> bool:
166
+ return (
167
+ len(e_ident) >= EI_NIDENT
168
+ and e_ident[EI_MAG0] == ELFMAG0
169
+ and e_ident[EI_MAG1] == ELFMAG1
170
+ and e_ident[EI_MAG2] == ELFMAG2
171
+ and e_ident[EI_MAG3] == ELFMAG3
172
+ and e_ident[EI_CLASS] != ELFCLASSNONE
173
+ )
174
+
175
+
176
+ def _read_elf_headers(data: bytes):
177
+ if len(data) < EI_NIDENT:
178
+ return None, None
179
+ e_ident = data[:EI_NIDENT]
180
+ if not _is_valid_elf_ident(e_ident):
181
+ return None, None
182
+ if e_ident[EI_CLASS] == ELFCLASS64:
183
+ if len(data) < ELF64_Ehdr.sizeof():
184
+ return None, None
185
+ hdr = ELF64_Ehdr.parse(data[: ELF64_Ehdr.sizeof()])
186
+ return "ELF64", hdr
187
+ elif e_ident[EI_CLASS] == ELFCLASS32:
188
+ if len(data) < ELF32_Ehdr.sizeof():
189
+ return None, None
190
+ hdr = ELF32_Ehdr.parse(data[: ELF32_Ehdr.sizeof()])
191
+ return "ELF32", hdr
192
+ return None, None
193
+
194
+
195
+ def _read_program_headers(data: bytes, kind: str, hdr) -> list:
196
+ phdrs = []
197
+ if hdr.e_phnum == 0:
198
+ logger.error("%s: ELF has no program sections", "_read_program_headers")
199
+ return phdrs
200
+
201
+ table_size = hdr.e_phnum * (
202
+ ELF64_Phdr.sizeof() if kind == "ELF64" else ELF32_Phdr.sizeof()
203
+ )
204
+ if hdr.e_phoff + table_size > len(data):
205
+ logger.error(
206
+ "%s: Program header table is out of bounds", "_read_program_headers"
207
+ )
208
+ return []
209
+
210
+ table = data[hdr.e_phoff:hdr.e_phoff + table_size]
211
+ bio = io.BytesIO(table)
212
+ for _ in range(hdr.e_phnum):
213
+ if kind == "ELF64":
214
+ ph = ELF64_Phdr.parse_stream(bio)
215
+ else:
216
+ ph = ELF32_Phdr.parse_stream(bio)
217
+ phdrs.append(ph)
218
+ return phdrs
219
+
220
+
221
+ def _elf_last_segment_end(data: bytes) -> Optional[int]:
222
+ kind, hdr = _read_elf_headers(data)
223
+ if not hdr:
224
+ return None
225
+ phdrs = _read_program_headers(data, kind, hdr)
226
+ if not phdrs:
227
+ return None
228
+ # last by highest p_offset
229
+ last = max(phdrs, key=lambda p: int(p.p_offset))
230
+ return int(last.p_offset + last.p_filesz)
231
+
232
+
233
+ def _mbn_v7_header_sizes_valid(h, sect_size: int) -> bool:
234
+ total = (
235
+ MBN_V7.sizeof()
236
+ + h.common_metadata_size
237
+ + h.qti_metadata_size
238
+ + h.oem_metadata_size
239
+ + h.hash_table_size
240
+ + h.qti_signature_size
241
+ + h.qti_certificate_chain_size
242
+ + h.oem_signature_size
243
+ + h.oem_certificate_chain_size
244
+ )
245
+ return total <= sect_size
246
+
247
+
248
+ def _mbn_v7_header_sizes_expected(h) -> bool:
249
+ return (
250
+ (h.qti_metadata_size in (0, 0xE0))
251
+ and (h.oem_metadata_size in (0, 0xE0))
252
+ and (h.oem_signature_size in (0, 0x68))
253
+ and (h.oem_certificate_chain_size in (0, 0xD20))
254
+ )
255
+
256
+
257
+ def _mbn_v7_log(h, func: str, prefix: str) -> None:
258
+ logger.debug(
259
+ "%s: %s header {version=0x%x, common_metadata_size=0x%x, qti_metadata_size=0x%x, "
260
+ "oem_metadata_size=0x%x, hash_table_size=0x%x, qti_signature_size=0x%x, "
261
+ "qti_certificate_chain_size=0x%x, oem_signature_size=0x%x, oem_certificate_chain_size=0x%x}",
262
+ func,
263
+ prefix,
264
+ h.version,
265
+ h.common_metadata_size,
266
+ h.qti_metadata_size,
267
+ h.oem_metadata_size,
268
+ h.hash_table_size,
269
+ h.qti_signature_size,
270
+ h.qti_certificate_chain_size,
271
+ h.oem_signature_size,
272
+ h.oem_certificate_chain_size,
273
+ )
274
+
275
+
276
+ # -----------------------------------------------------------------------------
277
+ # Public API
278
+ # -----------------------------------------------------------------------------
279
+
280
+
281
+ def mbn_stitch(data: bytes, blob: bytes) -> Optional[bytes]:
282
+ """
283
+ Overwrite the tail of `data` with `blob`. Format-aware size logging/checks.
284
+ Returns new bytes or None.
285
+ """
286
+ if data is None:
287
+ logger.error("%s: data is NULL", "mbn_stitch")
288
+ return None
289
+ if not data:
290
+ logger.error("%s: data size is 0", "mbn_stitch")
291
+ return None
292
+ if blob is None:
293
+ logger.error("%s: blob is NULL", "mbn_stitch")
294
+ return None
295
+ if not blob:
296
+ logger.error("%s: blob size is 0", "mbn_stitch")
297
+ return None
298
+
299
+ data_size = len(data)
300
+ blob_size = len(blob)
301
+ parsed_size = 0
302
+
303
+ try:
304
+ # MBN v2
305
+ if data_size > MBN_V2_MAGIC_SIZE and data[:MBN_V2_MAGIC_SIZE] == MBN_V2_MAGIC:
306
+ if data_size < MBN_V2.sizeof():
307
+ logger.error("%s: truncated MBN v2 header", "mbn_stitch")
308
+ return None
309
+ h = MBN_V2.parse(data[: MBN_V2.sizeof()])
310
+ parsed_size = h.data_size + MBN_V2.sizeof()
311
+ logger.debug(
312
+ "%s: encountered MBN v2 image, parsed_size = 0x%x",
313
+ "mbn_stitch",
314
+ parsed_size,
315
+ )
316
+
317
+ # MBN v1
318
+ elif data_size > MBN_V1_MAGIC_SIZE and data[:MBN_V1_MAGIC_SIZE] == MBN_V1_MAGIC:
319
+ if data_size < MBN_V1.sizeof():
320
+ logger.error("%s: truncated MBN v1 header", "mbn_stitch")
321
+ return None
322
+ h = MBN_V1.parse(data[: MBN_V1.sizeof()])
323
+ parsed_size = h.data_size + MBN_V1.sizeof()
324
+ logger.debug(
325
+ "%s: encountered MBN v1 image, parsed_size = 0x%x",
326
+ "mbn_stitch",
327
+ parsed_size,
328
+ )
329
+
330
+ # BIN
331
+ elif (
332
+ data_size > (MBN_BIN_MAGIC_SIZE + MBN_BIN_MAGIC_OFFSET)
333
+ and data[MBN_BIN_MAGIC_OFFSET:MBN_BIN_MAGIC_OFFSET + MBN_BIN_MAGIC_SIZE]
334
+ == MBN_BIN_MAGIC
335
+ ):
336
+ if data_size < MBN_BIN.sizeof():
337
+ logger.error("%s: truncated MBN BIN header", "mbn_stitch")
338
+ return None
339
+ h = MBN_BIN.parse(data[: MBN_BIN.sizeof()])
340
+ parsed_size = h.total_size
341
+ logger.debug(
342
+ "%s: encountered MBN BIN image, parsed_size = 0x%x",
343
+ "mbn_stitch",
344
+ parsed_size,
345
+ )
346
+
347
+ # ELF
348
+ else:
349
+ end = _elf_last_segment_end(data)
350
+ if end is not None:
351
+ parsed_size = end
352
+ logger.debug(
353
+ "%s: encountered ELF image, parsed_size = 0x%x",
354
+ "mbn_stitch",
355
+ parsed_size,
356
+ )
357
+ else:
358
+ logger.warning("Unknown file format passed to %s", "mbn_stitch")
359
+ parsed_size = data_size
360
+
361
+ if parsed_size != data_size:
362
+ logger.warning(
363
+ "%s: size mismatch for MBN data, expected 0x%x, input size 0x%x",
364
+ "mbn_stitch",
365
+ parsed_size,
366
+ data_size,
367
+ )
368
+
369
+ stitch_offset = data_size - blob_size
370
+ if stitch_offset < 0 or stitch_offset + blob_size > data_size:
371
+ logger.error(
372
+ "%s: stitch offset (0x%x) + size (0x%x) is larger than the destination (0x%x)",
373
+ "mbn_stitch",
374
+ stitch_offset,
375
+ blob_size,
376
+ data_size,
377
+ )
378
+ return None
379
+
380
+ out = bytearray(data)
381
+ logger.debug(
382
+ "%s: stitching mbn at 0x%x, size 0x%x",
383
+ "mbn_stitch",
384
+ stitch_offset,
385
+ blob_size,
386
+ )
387
+ out[stitch_offset: stitch_offset + blob_size] = blob
388
+ return bytes(out)
389
+
390
+ except ChecksumError as e:
391
+ logger.error("%s: construct checksum error: %s", "mbn_stitch", str(e))
392
+ return None
393
+ except Exception as e:
394
+ logger.error("%s: unexpected error: %s", "mbn_stitch", str(e))
395
+ return None
396
+
397
+
398
+ def mbn_mav25_stitch(data: bytes, blob: bytes) -> Optional[bytes]:
399
+ """
400
+ Patch an ELF's last program-section area with a v7 trailer from `blob`.
401
+ - Writes new metadata+hash at section start
402
+ - Writes OEM sig+chain after existing dest qti sig+chain
403
+ Returns new bytes or None.
404
+ """
405
+ if data is None:
406
+ logger.error("%s: data is NULL", "mbn_mav25_stitch")
407
+ return None
408
+ if not data:
409
+ logger.error("%s: data size is 0", "mbn_mav25_stitch")
410
+ return None
411
+ if blob is None:
412
+ logger.error("%s: blob is NULL", "mbn_mav25_stitch")
413
+ return None
414
+ if not blob:
415
+ logger.error("%s: blob size is 0", "mbn_mav25_stitch")
416
+ return None
417
+
418
+ data_size, blob_size = len(data), len(blob)
419
+
420
+ kind, ehdr = _read_elf_headers(data)
421
+ if not ehdr:
422
+ logger.error("%s: data is not a valid ELF", "mbn_mav25_stitch")
423
+ return None
424
+
425
+ if blob_size < MBN_V7.sizeof():
426
+ logger.error("%s: header is bigger than blob", "mbn_mav25_stitch")
427
+ return None
428
+
429
+ src = MBN_V7.parse(blob[: MBN_V7.sizeof()])
430
+ _mbn_v7_log(src, "mbn_mav25_stitch", "src")
431
+ if src.version != 7:
432
+ logger.error(
433
+ "%s: src header version (0x%x) is incorrect",
434
+ "mbn_mav25_stitch",
435
+ src.version,
436
+ )
437
+ return None
438
+ if not _mbn_v7_header_sizes_expected(src):
439
+ logger.warning(
440
+ "%s: header sizes in header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, "
441
+ "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)",
442
+ "mbn_mav25_stitch",
443
+ src.qti_metadata_size,
444
+ src.oem_metadata_size,
445
+ src.oem_signature_size,
446
+ src.oem_certificate_chain_size,
447
+ )
448
+
449
+ # last PHDR (by index)
450
+ phdrs = _read_program_headers(data, kind, ehdr)
451
+ if not phdrs:
452
+ return None
453
+ last_ph = phdrs[-1]
454
+ sect_off, sect_size = int(last_ph.p_offset), int(last_ph.p_filesz)
455
+
456
+ if sect_off == 0:
457
+ logger.error("%s: section has 0 offset", "mbn_mav25_stitch")
458
+ return None
459
+ if sect_size == 0:
460
+ logger.error("%s: section has 0 size", "mbn_mav25_stitch")
461
+ return None
462
+ if sect_off + sect_size > data_size:
463
+ logger.error(
464
+ "%s: section (0x%x+0x%x) is bigger than the data",
465
+ "mbn_mav25_stitch",
466
+ sect_off,
467
+ sect_size,
468
+ )
469
+ return None
470
+ if sect_size < MBN_V7.sizeof():
471
+ logger.error(
472
+ "%s: dest header is bigger than the section (0x%x)",
473
+ "mbn_mav25_stitch",
474
+ sect_size,
475
+ )
476
+ return None
477
+
478
+ dest = MBN_V7.parse(data[sect_off: sect_off + MBN_V7.sizeof()])
479
+ _mbn_v7_log(dest, "mbn_mav25_stitch", "dest")
480
+ if dest.version != 7:
481
+ logger.error(
482
+ "%s: dest header version (0x%x) is incorrect",
483
+ "mbn_mav25_stitch",
484
+ dest.version,
485
+ )
486
+ return None
487
+ if not _mbn_v7_header_sizes_valid(dest, sect_size):
488
+ logger.error(
489
+ (
490
+ "%s: sizes in dest header are invalid (common_metadata_size=0x%x, qti_metadata_size=0x%x, "
491
+ "oem_metadata_size=0x%x, hash_table_size=0x%x, qti_signature_size=0x%x, "
492
+ "qti_certificate_chain_size=0x%x, oem_signature_size=0x%x, "
493
+ "oem_certificate_chain_size=0x%x)"
494
+ ),
495
+ "mbn_mav25_stitch",
496
+ dest.common_metadata_size,
497
+ dest.qti_metadata_size,
498
+ dest.oem_metadata_size,
499
+ dest.hash_table_size,
500
+ dest.qti_signature_size,
501
+ dest.qti_certificate_chain_size,
502
+ dest.oem_signature_size,
503
+ dest.oem_certificate_chain_size,
504
+ )
505
+ return None
506
+ if not _mbn_v7_header_sizes_expected(dest):
507
+ logger.warning(
508
+ "%s: header sizes in dest header are unexpected (qti_metadata_size=0x%x, oem_metadata_size=0x%x, "
509
+ "oem_signature_size=0x%x, oem_certificate_chain_size=0x%x)",
510
+ "mbn_mav25_stitch",
511
+ dest.qti_metadata_size,
512
+ dest.oem_metadata_size,
513
+ dest.oem_signature_size,
514
+ dest.oem_certificate_chain_size,
515
+ )
516
+
517
+ # compute new layout from src
518
+ new_metadata_size = (
519
+ MBN_V7.sizeof()
520
+ + src.common_metadata_size
521
+ + src.qti_metadata_size
522
+ + src.oem_metadata_size
523
+ )
524
+ new_metadata_and_hash_table_size = new_metadata_size + src.hash_table_size
525
+ new_oem_sig_and_cert_chain_size = (
526
+ src.oem_signature_size + src.oem_certificate_chain_size
527
+ )
528
+
529
+ new_oem_sig_and_cert_chain_off = (
530
+ new_metadata_and_hash_table_size
531
+ + dest.qti_signature_size
532
+ + dest.qti_certificate_chain_size
533
+ )
534
+
535
+ # bounds
536
+ if new_metadata_and_hash_table_size > blob_size:
537
+ logger.error(
538
+ "%s: new metadata (0x%x) and hash table (0x%x) are bigger than the source (0x%x)",
539
+ "mbn_mav25_stitch",
540
+ new_metadata_size,
541
+ src.hash_table_size,
542
+ blob_size,
543
+ )
544
+ return None
545
+ if new_metadata_and_hash_table_size > sect_size:
546
+ logger.error(
547
+ "%s: new metadata (0x%x) and hash table (0x%x) are bigger than the destination (0x%x)",
548
+ "mbn_mav25_stitch",
549
+ new_metadata_size,
550
+ src.hash_table_size,
551
+ sect_size,
552
+ )
553
+ return None
554
+ if new_metadata_and_hash_table_size + new_oem_sig_and_cert_chain_size > blob_size:
555
+ logger.error(
556
+ "%s: new OEM signature and certificate chain are bigger than the source",
557
+ "mbn_mav25_stitch",
558
+ )
559
+ return None
560
+ if new_oem_sig_and_cert_chain_off + new_oem_sig_and_cert_chain_size > sect_size:
561
+ logger.error(
562
+ "%s: new OEM signature and certificate chain are outside the bounds of the destination",
563
+ "mbn_mav25_stitch",
564
+ )
565
+ return None
566
+
567
+ out = bytearray(data)
568
+ # write metadata + hash
569
+ logger.debug(
570
+ "%s: stitching mbn at 0x%x (0x%x bytes)",
571
+ "mbn_mav25_stitch",
572
+ sect_off,
573
+ new_metadata_and_hash_table_size,
574
+ )
575
+ out[sect_off: sect_off + new_metadata_and_hash_table_size] = blob[
576
+ :new_metadata_and_hash_table_size
577
+ ]
578
+
579
+ # write OEM sig + chain
580
+ logger.debug(
581
+ "%s: stitching mbn at 0x%x (0x%x bytes)",
582
+ "mbn_mav25_stitch",
583
+ sect_off + new_oem_sig_and_cert_chain_off,
584
+ new_oem_sig_and_cert_chain_size,
585
+ )
586
+ start = new_metadata_and_hash_table_size
587
+ end = start + new_oem_sig_and_cert_chain_size
588
+
589
+ slice_start = sect_off + new_oem_sig_and_cert_chain_off
590
+ slice_end = sect_off + new_oem_sig_and_cert_chain_off + new_oem_sig_and_cert_chain_size
591
+ out[slice_start:slice_end] = blob[start:end]
592
+
593
+ return bytes(out)
594
+
595
+
596
+ # -----------------------------------------------------------------------------
597
+ # Tiny helpers (optional)
598
+ # -----------------------------------------------------------------------------
599
+
600
+
601
+ def mbn_is_valid_elf(buf: bytes) -> bool:
602
+ return len(buf) >= EI_NIDENT and _is_valid_elf_ident(buf[:EI_NIDENT])
603
+
604
+
605
+ def mbn_is_64bit_elf(buf: bytes) -> bool:
606
+ return len(buf) >= EI_NIDENT and buf[EI_CLASS] == ELFCLASS64