cartelon.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import os
  2. import shutil
  3. import hashlib
  4. import zipfile
  5. #feature imports
  6. import struct
  7. import requests
  8. import json
  9. import logging
  10. from PyQt5.QtGui import *
  11. from PyQt5.QtCore import *
  12. from PyQt5.QtWidgets import *
  13. offset_logo_presequence = [0x62, 0x61, 0x64, 0x5F, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x00]
  14. offset_buttonMap_presequence = [0x00, 0x00, 0x00, 0x71, 0xDB, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
  15. offset_buttonMap_postsequence = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]
  16. def patchCRC32(bisrv_content):
  17. x = crc32mpeg2(bisrv_content[512:len(bisrv_content):1])
  18. bisrv_content[0x18c] = x & 255
  19. bisrv_content[0x18d] = x >> 8 & 255
  20. bisrv_content[0x18e] = x >> 16 & 255
  21. bisrv_content[0x18f] = x >> 24
  22. return bisrv_content
  23. def crc32mpeg2(buf, crc=0xffffffff):
  24. for val in buf:
  25. crc ^= val << 24
  26. for _ in range(8):
  27. crc = crc << 1 if (crc & 0x80000000) == 0 else (crc << 1) ^ 0x104c11db7
  28. return crc
  29. def QImageToRGB565Logo(inputQImage):
  30. print("Converting supplied file to boot logo format")
  31. # Need to increase the size to 512x200
  32. inputQImage = inputQImage.scaled(512, 200, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
  33. inputQImage = inputQImage.convertToFormat(QImage.Format_RGB16)
  34. rgb565Data = []
  35. for y in range(0, 200):
  36. for x in range(0, 512):
  37. pixel = inputQImage.pixelColor(x,y)
  38. pxValue = ((pixel.red() & 248) << 8) + ((pixel.green() & 252) << 3) + (pixel.blue() >> 3)
  39. rgb565Data.append(pxValue)
  40. print("Finished converting image to boot logo format")
  41. return rgb565Data
  42. def findSequence(needle, haystack, offset = 0):
  43. # Loop through the data array starting from the offset
  44. for i in range(len(haystack) - len(needle) + 1):
  45. readpoint = offset + i
  46. # Assume a match until proven otherwise
  47. match = True
  48. # Loop through the target sequence and compare each byte
  49. for j in range(len(needle)):
  50. if haystack[readpoint + j] != needle[j]:
  51. # Mismatch found, break the inner loop and continue the outer loop
  52. match = False
  53. break
  54. # If match is still true after the inner loop, we have found a match
  55. if match:
  56. # Return the index of the first byte of the match
  57. return readpoint
  58. # If we reach this point, no match was found
  59. return -1
  60. def main():
  61. index_path = "FOLDER"
  62. print(f"trying to read {index_path}")
  63. try:
  64. file_handle = open(index_path, 'rb') # rb for read, wb for write
  65. bisrv_content = bytearray(file_handle.read(os.path.getsize(index_path)))
  66. file_handle.close()
  67. print("Finished reading file")
  68. # First, replace CRC32 bits with 00...
  69. bisrv_content[396] = 0x00
  70. bisrv_content[397] = 0x00
  71. bisrv_content[398] = 0x00
  72. bisrv_content[399] = 0x00
  73. print("Blanked CRC32")
  74. # Next identify the boot logo position, and blank it out too...
  75. print("start finding logo")
  76. badExceptionOffset = findSequence(offset_logo_presequence, bisrv_content)
  77. print("finished finding logo")
  78. if (badExceptionOffset > -1): # Check we found the boot logo position
  79. bootLogoStart = badExceptionOffset + 16
  80. for i in range(bootLogoStart, bootLogoStart + 204800):
  81. bisrv_content[i] = 0x00
  82. else: # If no boot logo found exit
  83. return False
  84. print(bootLogoStart)
  85. print("Blanked Bootlogo")
  86. # Next identify the emulator button mappings (if they exist), and blank them out too...
  87. preButtonMapOffset = findSequence(offset_buttonMap_presequence, bisrv_content)
  88. if preButtonMapOffset > -1:
  89. postButtonMapOffset = findSequence(offset_buttonMap_postsequence, bisrv_content, preButtonMapOffset)
  90. if postButtonMapOffset > -1:
  91. for i in range(preButtonMapOffset + 16, i < postButtonMapOffset):
  92. bisrv_content[i] = 0x00
  93. else:
  94. return False
  95. else:
  96. return False
  97. # Next we'll look for (and zero out) the five bytes that the power
  98. # monitoring functions of the SF2000 use for switching the UI's battery
  99. # level indicator. These unfortunately can't be searched for - they're just
  100. # in specific known locations for specific firmware versions...
  101. prePowerCurve = findSequence([0x11, 0x05, 0x00, 0x02, 0x24], bisrv_content)
  102. if prePowerCurve > -1:
  103. powerCurveFirstByteLocation = prePowerCurve + 5
  104. if powerCurveFirstByteLocation == 0x35A8F8:
  105. # Seems to match mid-March layout...
  106. bisrv_content[0x35A8F8] = 0x00
  107. bisrv_content[0x35A900] = 0x00
  108. bisrv_content[0x35A9B0] = 0x00
  109. bisrv_content[0x35A9B8] = 0x00
  110. bisrv_content[0x35A9D4] = 0x00
  111. elif powerCurveFirstByteLocation == 0x35A954:
  112. # Seems to match April 20th layout...
  113. bisrv_content[0x35A954] = 0x00
  114. bisrv_content[0x35A95C] = 0x00
  115. bisrv_content[0x35AA0C] = 0x00
  116. bisrv_content[0x35AA14] = 0x00
  117. bisrv_content[0x35AA30] = 0x00
  118. elif powerCurveFirstByteLocation == 0x35C78C:
  119. # Seems to match May 15th layout...
  120. bisrv_content[0x35C78C] = 0x00
  121. bisrv_content[0x35C794] = 0x00
  122. bisrv_content[0x35C844] = 0x00
  123. bisrv_content[0x35C84C] = 0x00
  124. bisrv_content[0x35C868] = 0x00
  125. elif powerCurveFirstByteLocation == 0x35C790:
  126. # Seems to match May 22nd layout...
  127. bisrv_content[0x35C790] = 0x00
  128. bisrv_content[0x35C798] = 0x00
  129. bisrv_content[0x35C848] = 0x00
  130. bisrv_content[0x35C850] = 0x00
  131. bisrv_content[0x35C86C] = 0x00
  132. elif powerCurveFirstByteLocation == 0x3564EC:
  133. # Seems to match August 3rd layout...
  134. bisrv_content[0x3564EC] = 0x00
  135. bisrv_content[0x3564F4] = 0x00
  136. bisrv_content[0x35658C] = 0x00
  137. bisrv_content[0x356594] = 0x00
  138. bisrv_content[0x3565B0] = 0x00
  139. else:
  140. return False
  141. else:
  142. return False
  143. # If we're here, we've zeroed-out all of the bits of the firmware that are
  144. # semi-user modifiable (boot logo, button mappings and the CRC32 bits); now
  145. # we can generate a hash of what's left and compare it against some known
  146. # values...
  147. print("starting to compute hash")
  148. sha256hasher = hashlib.new('sha256')
  149. sha256hasher.update(bisrv_content)
  150. bisrvHash = sha256hasher.hexdigest()
  151. print(f"Hash: {bisrvHash}")
  152. changeBootLogo(index_path, "/home/user/Documentos/img.png", 0);
  153. except (IOError, OSError):
  154. print("! Failed reading bisrv.")
  155. print(" Check the SD card and file are readable, and the file is not open in another program.")
  156. raise Exception_InvalidPath
  157. def changeBootLogo(index_path, newLogoFileName, msgBox):
  158. # Confirm we arent going to brick the firmware by finding a known version
  159. # Load the new Logo
  160. print("Uploading new boot logo...")
  161. newLogo = QImage(newLogoFileName)
  162. # Convert to RGB565
  163. print("Converting boot logo...")
  164. rgb565Data = QImageToRGB565Logo(newLogo)
  165. # Change the boot logo
  166. print("Uploading boot logo...")
  167. file_handle = open(index_path, 'rb') # rb for read, wb for write
  168. bisrv_content = bytearray(file_handle.read(os.path.getsize(index_path)))
  169. file_handle.close()
  170. logoOffset = findSequence(offset_logo_presequence, bisrv_content)
  171. bootLogoStart = logoOffset + 16
  172. for i in range(0, 512*200):
  173. data = rgb565Data[i].to_bytes(2, 'little')
  174. bisrv_content[bootLogoStart+i*2] = data[0]
  175. bisrv_content[bootLogoStart+i*2+1] = data[1]
  176. print("Updating BIOS file...")
  177. print("Patching CRC")
  178. bisrv_content = patchCRC32(bisrv_content)
  179. print("Uploading BIOS file...")
  180. print("Writing bisrv to file")
  181. file_handle = open(index_path, 'wb') # rb for read, wb for write
  182. file_handle.write(bisrv_content)
  183. file_handle.close()
  184. return True
  185. main()