123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- import os
- import shutil
- import hashlib
- import zipfile
- #feature imports
- import struct
- import requests
- import json
- import logging
- from PyQt5.QtGui import *
- from PyQt5.QtCore import *
- from PyQt5.QtWidgets import *
- offset_logo_presequence = [0x62, 0x61, 0x64, 0x5F, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x00]
- offset_buttonMap_presequence = [0x00, 0x00, 0x00, 0x71, 0xDB, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
- 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]
- def patchCRC32(bisrv_content):
- x = crc32mpeg2(bisrv_content[512:len(bisrv_content):1])
- bisrv_content[0x18c] = x & 255
- bisrv_content[0x18d] = x >> 8 & 255
- bisrv_content[0x18e] = x >> 16 & 255
- bisrv_content[0x18f] = x >> 24
- return bisrv_content
- def crc32mpeg2(buf, crc=0xffffffff):
- for val in buf:
- crc ^= val << 24
- for _ in range(8):
- crc = crc << 1 if (crc & 0x80000000) == 0 else (crc << 1) ^ 0x104c11db7
- return crc
- def QImageToRGB565Logo(inputQImage):
- print("Converting supplied file to boot logo format")
- # Need to increase the size to 512x200
- inputQImage = inputQImage.scaled(512, 200, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
- inputQImage = inputQImage.convertToFormat(QImage.Format_RGB16)
- rgb565Data = []
- for y in range(0, 200):
- for x in range(0, 512):
- pixel = inputQImage.pixelColor(x,y)
- pxValue = ((pixel.red() & 248) << 8) + ((pixel.green() & 252) << 3) + (pixel.blue() >> 3)
- rgb565Data.append(pxValue)
- print("Finished converting image to boot logo format")
- return rgb565Data
- def findSequence(needle, haystack, offset = 0):
- # Loop through the data array starting from the offset
- for i in range(len(haystack) - len(needle) + 1):
- readpoint = offset + i
- # Assume a match until proven otherwise
- match = True
- # Loop through the target sequence and compare each byte
- for j in range(len(needle)):
- if haystack[readpoint + j] != needle[j]:
- # Mismatch found, break the inner loop and continue the outer loop
- match = False
- break
- # If match is still true after the inner loop, we have found a match
- if match:
- # Return the index of the first byte of the match
- return readpoint
- # If we reach this point, no match was found
- return -1
-
- def main():
- index_path = "FOLDER"
- print(f"trying to read {index_path}")
- try:
- file_handle = open(index_path, 'rb') # rb for read, wb for write
- bisrv_content = bytearray(file_handle.read(os.path.getsize(index_path)))
- file_handle.close()
- print("Finished reading file")
- # First, replace CRC32 bits with 00...
- bisrv_content[396] = 0x00
- bisrv_content[397] = 0x00
- bisrv_content[398] = 0x00
- bisrv_content[399] = 0x00
- print("Blanked CRC32")
-
- # Next identify the boot logo position, and blank it out too...
- print("start finding logo")
- badExceptionOffset = findSequence(offset_logo_presequence, bisrv_content)
- print("finished finding logo")
- if (badExceptionOffset > -1): # Check we found the boot logo position
- bootLogoStart = badExceptionOffset + 16
- for i in range(bootLogoStart, bootLogoStart + 204800):
- bisrv_content[i] = 0x00
- else: # If no boot logo found exit
- return False
-
- print(bootLogoStart)
-
- print("Blanked Bootlogo")
-
- # Next identify the emulator button mappings (if they exist), and blank them out too...
- preButtonMapOffset = findSequence(offset_buttonMap_presequence, bisrv_content)
- if preButtonMapOffset > -1:
- postButtonMapOffset = findSequence(offset_buttonMap_postsequence, bisrv_content, preButtonMapOffset)
- if postButtonMapOffset > -1:
- for i in range(preButtonMapOffset + 16, i < postButtonMapOffset):
- bisrv_content[i] = 0x00
- else:
- return False
- else:
- return False
-
- # Next we'll look for (and zero out) the five bytes that the power
- # monitoring functions of the SF2000 use for switching the UI's battery
- # level indicator. These unfortunately can't be searched for - they're just
- # in specific known locations for specific firmware versions...
- prePowerCurve = findSequence([0x11, 0x05, 0x00, 0x02, 0x24], bisrv_content)
- if prePowerCurve > -1:
- powerCurveFirstByteLocation = prePowerCurve + 5
- if powerCurveFirstByteLocation == 0x35A8F8:
- # Seems to match mid-March layout...
- bisrv_content[0x35A8F8] = 0x00
- bisrv_content[0x35A900] = 0x00
- bisrv_content[0x35A9B0] = 0x00
- bisrv_content[0x35A9B8] = 0x00
- bisrv_content[0x35A9D4] = 0x00
- elif powerCurveFirstByteLocation == 0x35A954:
- # Seems to match April 20th layout...
- bisrv_content[0x35A954] = 0x00
- bisrv_content[0x35A95C] = 0x00
- bisrv_content[0x35AA0C] = 0x00
- bisrv_content[0x35AA14] = 0x00
- bisrv_content[0x35AA30] = 0x00
- elif powerCurveFirstByteLocation == 0x35C78C:
- # Seems to match May 15th layout...
- bisrv_content[0x35C78C] = 0x00
- bisrv_content[0x35C794] = 0x00
- bisrv_content[0x35C844] = 0x00
- bisrv_content[0x35C84C] = 0x00
- bisrv_content[0x35C868] = 0x00
- elif powerCurveFirstByteLocation == 0x35C790:
- # Seems to match May 22nd layout...
- bisrv_content[0x35C790] = 0x00
- bisrv_content[0x35C798] = 0x00
- bisrv_content[0x35C848] = 0x00
- bisrv_content[0x35C850] = 0x00
- bisrv_content[0x35C86C] = 0x00
- elif powerCurveFirstByteLocation == 0x3564EC:
- # Seems to match August 3rd layout...
- bisrv_content[0x3564EC] = 0x00
- bisrv_content[0x3564F4] = 0x00
- bisrv_content[0x35658C] = 0x00
- bisrv_content[0x356594] = 0x00
- bisrv_content[0x3565B0] = 0x00
- else:
- return False
- else:
- return False
- # If we're here, we've zeroed-out all of the bits of the firmware that are
- # semi-user modifiable (boot logo, button mappings and the CRC32 bits); now
- # we can generate a hash of what's left and compare it against some known
- # values...
- print("starting to compute hash")
- sha256hasher = hashlib.new('sha256')
- sha256hasher.update(bisrv_content)
- bisrvHash = sha256hasher.hexdigest()
- print(f"Hash: {bisrvHash}")
- changeBootLogo(index_path, "/home/user/Documentos/img.png", 0);
-
-
-
- except (IOError, OSError):
- print("! Failed reading bisrv.")
- print(" Check the SD card and file are readable, and the file is not open in another program.")
- raise Exception_InvalidPath
-
-
- def changeBootLogo(index_path, newLogoFileName, msgBox):
- # Confirm we arent going to brick the firmware by finding a known version
- # Load the new Logo
- print("Uploading new boot logo...")
- newLogo = QImage(newLogoFileName)
- # Convert to RGB565
- print("Converting boot logo...")
- rgb565Data = QImageToRGB565Logo(newLogo)
- # Change the boot logo
- print("Uploading boot logo...")
- file_handle = open(index_path, 'rb') # rb for read, wb for write
- bisrv_content = bytearray(file_handle.read(os.path.getsize(index_path)))
- file_handle.close()
- logoOffset = findSequence(offset_logo_presequence, bisrv_content)
- bootLogoStart = logoOffset + 16
-
- for i in range(0, 512*200):
- data = rgb565Data[i].to_bytes(2, 'little')
- bisrv_content[bootLogoStart+i*2] = data[0]
- bisrv_content[bootLogoStart+i*2+1] = data[1]
- print("Updating BIOS file...")
- print("Patching CRC")
- bisrv_content = patchCRC32(bisrv_content)
- print("Uploading BIOS file...")
- print("Writing bisrv to file")
- file_handle = open(index_path, 'wb') # rb for read, wb for write
- file_handle.write(bisrv_content)
- file_handle.close()
- return True
-
-
- main()
|