Created
November 20, 2021 09:44
-
-
Save MarsTechHAN/ca16243c49e844a076436bdb279fac63 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, os | |
import time | |
import binascii | |
import hashlib | |
import array | |
import math | |
import usb.core | |
import usb.util | |
# Your hexlified payload | |
payload = '0200493200000000000000320000000000000032000000000000003200000000000000020a59000000000032000000000000003200000000000000320000000000000002023d020aaa75814d120f00e58260030200467900e94400601b7a00900f8d780075a001e493f2a308b8000205a0d9f4daf275a0ffe478fff6d8fd7800e84400600a790075a001e4f309d8fc7800e84400600c7900900100e4f0a3d8fcd9fa752900783d7600783e7600783f7600784076007841760278427602784376000876007845760478467600784776007848760078497600087600784b7600784c7600784d760002004675e200afe2747f5ff5e243e22975e300afe274bf5ff5e2afd174fb5ff5d175d18043d10122c2acc2bc75e10075e206900064120c17c2af02380080fb43e10443e10243e10143e18043d81fd2ead2af2275e40075e50275eb0875d41075ee4075ef0075d21275ea4075ec0075ed0075dc0222ae82af837d00ac32aa327b00a8337900e82afae93bfb8c007900c3e89ae964808bf063f08095f0400122ec70118d030deb2ef582e43ff5837416f0020239bc01118d030deb2ef582e43ff5837403f0020239ec30e0108d030deb2ef582e43ff583e4f0020239e824fef582e934fff583751504751600c007c006c005c004120ec8e5828583f0d004d005d006d00724fafa743f35f0fb8a348b35ec30e1208d010de92ef8e43ff9853482853583e493c4540f900f7c93fb88828983f0801f8d030deb2efbe43ffa853482853583e493f9740f59900f7c93f98b828a83f00c020164c020c0e0c0f0c082c083c007c006c005c004c003c002c001c000c0d075d000743055d9ffbf100a7843740126f6e40836f620d903020955743f55d9ffbf0003020946bf02028026bf200302089ebf21028008bf3002803402095375d300afd274fc5f4402f5d27840760002095320de03020953afd474f35f4408f5d4783f7601783e7600783da6db020953aedb7f00be0805bf00028003020872900007e0fc7d00900006e0fb7a004df521ea4cf5227e007f008f26900001e0f523900000e0fd54607003020533752601900000e0fd30e74c7405b52302802b740ab5230280167490b5233290000074fff0900001f07e027f000208769000007845e6f07e017f000208769000007401f09000017460f07e027f000208767eff7f00020876e4b52302805c7401b5230302044e7402b52302803b7403b52302805f7404b52302802d7406b5230280267407b52302801f7409b523028035740bb5230280117491b5230280117492b52302800302052c7e007f00020876784676017e007f00020876784076007e007f000208769000027845e0f67e007f0002087643878043c980900002e0fd900003e0fbe4fa4dfceb4afd53053fec4d6006bc0108bd0005758dff8048edc313cc13ccfdc3e49c74019d5034edc423ccc423541f6ccc541fcc6cccfdc3e49c74019d5005758df3801cab87747f5bf587abc9747f5bf5c98c03c3e49bf58d8005c3e49cf58d7e007f00020876900003e0fd30e012900002e0fd30e00678477601800478477600900003e0fd20e103020525900002e0fd30e106784876018004784876007847b6012e7848b6012978437949e6c397fc08e60997fdc374c89ce49d5014d297d29078437949e6f70809e6f7784b760b806d7847e6702e7848e6702978437949e6c397fc08e60997fdc374c89ce49d5014d297d29078437949e6f70809e6f7784b7600803a7847e670197848b60114d297c29078437949e6f70809e6f7784b7601801c7847b601177848e67012c297d29078437949e6f70809e6f7784b760a7e007f000208767eff7f00020876e52324f5500302086ce52375f003a49005467302084c02068302086c02073902086c02064f02056702086c02065c020677020680900003e0fdbd0102800abd02028011bd035f801875270475280f7e127f00805575271675280f7e207f008049900002e0700b75273675280f7e04ff8038900002e0fdbd010c75276275280f7e1a7f008024900002e0fdbd020c75273a75280f7e287f0080107527ff7528ff7e167f0080047eff7f00c3ee9521ef952250048e218f22c3e5219408e522940040067c087d008004ac21ad228c068d0774ffb5271a74ffb528158e33753200900000c007c00612015cd006d007801e8527158528167517808e188f1990000075f000c007c006120e13d006d007e521c39ef521e5229ff5228e29020876900002e0fd8d21752200020876900000e525f0c3e5219401e522940050030208767e017f00020876900002e0f525020876020876900000e0fd541f7033900003e0fc7d00900002e0fb7a004205ea4204bd0116bc0013900f1de493fd30e5030208767eff7f000208767eff7f00020876900000e0fd53051fbd0268900004e0fdbd0102804abd02028031bd03028018bd81028030bd82028017bd833cadd674bc5d4402f5d68035add674735df5d6802cadd474bc5d4402f5d48021add474735df5d48018add274bc5d4402f5d2800dadd274735df5d280047eff7f00784076000208767eff7f00020876900000e0fd541f704d900003e0fc7d00900002e0fb7a004205ea4204bd0130bc002d900f1de493fd30e51de5a220e7fb75a15575a1aa75a9c143870275a15575a1aa75a9000208767eff7f000208767eff7f00020876900000e0fd53051fbd02028003020846900003e0fc7d00900002e0fb7a004205ea4204ed4c6003020840900005e0fc7d00900004e0fb7a004205ea4204bd0105bc0002805dbd0205bc0002803fbd0305bc00028021bd8105bc0002803abd8205bc0002801cbd8343bc0040add674bf5d4403f5d68071add6747f5d440cf5d68066add474bf5d4403f5d4805badd4747f5d440cf5d48050add274bf5d4403f5d28045add2747f5d440cf5d27eff7f0080367eff7f0080307eff7f00802a900000e4f0900001f0c3e5219402e522940040067e027f008010ae21af22800a7eff7f0080047eff7f00beff0cbf00097523ff75dccf020953c374089ee49f40088edd75dcc002095375dd0075dcc00209537405b523030209247406b52302800302093ec3e5219408e522940040067c087d008004ac21ad228c068d0774ffb5271a74ffb528158e33852932900000c007c00612015cd006d0078025e5292527fce43528fd8c158d167517808e188f1990000075f000c007c006120e13d006d007e521c39ef521e5229ff522ee2529f5298edd63dc40802fe526702b748055e3ff7e00e5214207e52242068fe375dc02801575dd0075dc02800d7422b52302800675dd0043dc02c2d930d82d75dc0275d21275d41275e300c2dac2d9c2d875250078407600783d7600783e7600783f7600784176027842760210da028021e5da30e21fe5a220e7fb75a15575a1aa75a9c143870275a15575a1aa75a900800375d8ffd0d0d000d001d002d003d004d005d006d007d083d082d0f0d0e0d02032c29fd29ec29dc2cdc2cc438780753641e4f537f538f53975150af516f517f5188536828537838538f0e539120d2bac828c3a75150ae4f516f517f5188536828537838538f0e539120dae85823685833785f038f53974fb253a501574012536f536e43537f537e43538f538e43539f539af89740f5f4420f58943c9a0af36c3e49ff58dd28ec299d29cd2acd2bc22c0d0c0e0c0a275d00875a20130981de54c854d820453827f547f6582600e758301854c82e599f0054c534c7fc298309919c3e53e953d400553d4f3800b758302853e82e0f599053ec299d0a2d0e0d0d032e4f53bf53cd297d290120be6900014120c171209cb1200ea12013a12012675dd0075d30075d5009000407401f09000417460f0e52560fc7840e66003020b9a784c794de6c397ff30e70474802fffc3ef648094be403b7e0074022e2440fce43400fd784d8603784d068b82758301e0fb8c828d83f0784de6547ff60ebe3e0040d77840760175d340aed274fc5ef5d2805f7843e6c3953bfd08e6953cfe784586037c00c3ed9bee9c40467843863b08863c7e008f05c3ee9d502674022e2440fce43400fd784d8603784d068b82758301e0fb8c828d83f0784de6547ff60e80d37840760174022ff5d3afd274fc5ff5d2783fe66006783f7600d2997846e660077846760012010f784bb60102800a784bb60a028003020add78437949e6c397fe08e60997ffc374e89e74039f4003020addd297d290784b7600020add75a15575a1aaafb974f85f4406f5b975a10022ae82af83ee4f601505a105a105a105a105a105a105a11ebeff011f80e722ae82af83ee4f60159003e8c007c006120bf9d006d0071ebeff011f80e72243c61022c29fd29ec29dc2cdc2cc43878075101a751106e4f512f51375150af516f517f5188510828511838512f0e513120d2bac828c1475150ae4f516f517f5188510828511838512f0e513120dae85821085831185f012f51374fb2514501574012510f510e43511f511e43512f512e43513f513af89740f5f4420f58943c9a0af10c3e49ff58dd28ed299d29c2210980280fb8599822285829910990280fb22af8210990280fb8f992210980280fb8599822243c62022c2c7d2c5d2c475c2642210c00280fb85c182228582c110c10280fb22af8275a15575a1aaef600543b1018007afb174fe5ff5b175a10075ff00228582ff22f9e51545164517451860777800c308e51820e73be51525e0f515e51633f516e51733f517e51833f518e5829515e5839516e5f09517e9951850d4c3e51813f518e51713f517e51613f516e51513f515e5829515fce5839516fde5f09517fee995184007f98ef08d838c82c3e51813f518e51713f517e51613f516e51513f515d8cee922fb7a20e4fcfdfeffe5822582f582e58333f583e5f033f5f0eb33fb4017dae98042e5822582f582e58333f583e5f033f5f0eb33fbec33fced33fdee33feef33ffec9515ed9516ee9517ef95184013ec9515fced9516fdee9517feef9518ff438201dabeeb22ad82ae83aff08d1a8e1b8f1c85151d85161e85171fa818a9198803890418b8ff0119eb4c6025851d82851e83851ff0120eacfca385821d85831e8d828e838ff0ec120e68a3ad82ae8380ce851a82851b83851cf02220f71130f6138883a88220f509f6a8837583002280fef280f5f0227a10e4fbfce58225e0f582e58333f583eb33fbec33fceb9515f5f0ec95164006fcabf0438201dadd2220f71430f6148883a88220f507e6a88375830022e280f7e49322e022c2d5e58330e70dd2d5e4c39582f582e49583f583e51630e70db2d5e4c39515f515e49516f516120e8330d50be4c39582f582e49583f58322758200221201100100000008030401600004010203010902200001010080320904000002ffffff0007058102400000070502024000000403090428034d0035002000530065007200690061006c00200043006f006e007600650072007400650072001a034d00350053005400410043004b00200049006e0063002e003031323334353637383941424344454600' | |
epOutAddr = 0x02 | |
epInAddr = 0x82 | |
detect_chip_cmd_v2 = [0xa1, 0x12, 0x00, 0x52, 0x11, 0x4d, 0x43, 0x55, 0x20, 0x49, 0x53, | |
0x50, 0x20, 0x26, 0x20, 0x57, 0x43, 0x48, 0x2e, 0x43, 0x4e] | |
end_flash_cmd_v2 = [0xa2, 0x01, 0x00, 0x00] | |
reset_run_cmd_v2 = [0xa2, 0x01, 0x00, 0x01] | |
send_key_cmd_v2 = [0xa3, 0x38, 0x00] + [0x00] * (0x38) | |
erase_chip_cmd_v2 = [0xa4, 0x01, 0x00, 0x08] | |
write_cmd_v2 = [0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] | |
verify_cmd_v2 = [0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] | |
read_cfg_cmd_v2 = [0xa7, 0x02, 0x00, 0x1f, 0x00] | |
print( | |
''' | |
==================== M5 Serial Converter Firmware Updater ==================== | |
FW Version: FW20200114_A2 | |
This is only for update M5StickC or M5Atom Series USB Controller's Firmware | |
, using it for any other purpose may cause damage to your devices. | |
When you are using this software, make sure you have a reliable connection | |
to your device. Any disruption during the process will cause the device | |
not functioning. | |
NO WARRANTIES | |
To the extent permitted by applicable law, neither wsdot, | |
nor any person, either expressly or implicitly, warrants any aspect of | |
this software or program, including any output or results of this software | |
or program. Unless agreed to in writing. This software and program is | |
being provided "as is", without any warranty of any type or nature, | |
either express or implied, including, but not limited to, the implied | |
warranties of merchantability and fitness for a particular purpose, | |
and any warranty that this software or program is free from defects. | |
========================================================================== | |
Press enter to continue . . . | |
''' | |
) | |
input() | |
print('Detecting M5Stack products.') | |
dev = usb.core.find(idVendor=0x0403, idProduct=0x6001) | |
if dev is None: | |
dev = usb.core.find(idVendor=0x4348, idProduct=0x55e0) | |
if dev is None: | |
sys.exit('Cannot find valid M5Stack products.') | |
print('Find M5Stack products in DFU mode.') | |
else: | |
print('Find M5Stack products.') | |
print('Kernel driver deteched.') | |
try: | |
dev.ctrl_transfer(0x40, 0x91, 0, 0, 0) | |
except usb.core.USBError as e: | |
print('Apply magic success.') | |
retryCounter = 20 | |
print('Waiting for device in DFU mode.', end="") | |
while retryCounter: | |
print(".", end="") | |
retryCounter = retryCounter - 1 | |
dev = usb.core.find(idVendor=0x4348, idProduct=0x55e0) | |
time.sleep(0.5) | |
if dev is not None: | |
print('\nFind M5Stack device in DFU mode.') | |
break | |
if retryCounter == 0: | |
sys.exit('\nFail to cast magic stage 2, please contact vendor.') | |
try: | |
if dev.is_kernel_driver_active(0): | |
try: | |
dev.detach_kernel_driver(0) | |
print('Kernel driver deteched.') | |
except usb.core.USBError as e: | |
sys.exit('Could not detach kernel driver stage 2.') | |
except: | |
pass | |
dev.set_configuration() | |
try: | |
usb.util.claim_interface(dev, 0) | |
print('Claim interface success.') | |
except: | |
sys.exit('Could not claim claim_interface.') | |
print('Starting flash routine.') | |
print('Sending Stage1...') | |
dev.write(epOutAddr, detect_chip_cmd_v2) | |
dev.read(epInAddr, 6, 2000) | |
print('Reading Config...') | |
dev.write(epOutAddr, read_cfg_cmd_v2) | |
rec = dev.read(epInAddr, 30, 2000) | |
print("BTVER: V%d.%d%d" % (rec[19], rec[20], rec[21])) | |
if rec[19] != 2 or rec[20] != 3 or rec[21] != 1: | |
sys.exit('BTVER Unmatched.') | |
magicNumA = (rec[22] + rec[23] + rec[24] + rec[25]) % 256 | |
magicNumB = (magicNumA + 0x52) % 256 | |
print('Writing Magic...A: 0x%x, B: 0x%x' % (magicNumA, magicNumB)) | |
dev.write(epOutAddr, send_key_cmd_v2) | |
#print('Key: ', ''.join('0x{:02x} '.format(x) for x in send_key_cmd_v2)) | |
dev.read(epInAddr, 6, 2000) | |
print('Erasing Chip...') | |
dev.write(epOutAddr, erase_chip_cmd_v2) | |
dev.read(epInAddr, 6, 2000) | |
print('Unpacking payload...') | |
payloadSHA256 = hashlib.sha256(binascii.unhexlify(payload)).hexdigest() | |
print('Verifying the payload...') | |
binPayload = list(binascii.unhexlify(payload)) | |
if payloadSHA256.find('05919b94507771ca3aa643d808df2a5bbf4036fce952c6f3ee5cf70d4d6629d7') == -1: | |
sys.exit('Payload SHA256 unmatch.\nSHA256: ' + payloadSHA256) | |
print('Packing the payload...') | |
binPayload = binPayload + [0] * ((math.ceil(len(binPayload) / 56) * 56) - len(binPayload)) | |
for i in range(len(binPayload)): | |
if i % 8 == 7: | |
binPayload[i] = (binPayload[i] ^ magicNumB) % 256 | |
else: | |
binPayload[i] = (binPayload[i] ^ magicNumA) % 256 | |
fileLen = len(binPayload) | |
remLen = fileLen | |
curr_addr = 0 | |
print('Start sending new firmware...') | |
while curr_addr < fileLen: | |
if remLen >= 56: | |
pkt_length = 56 | |
else: | |
pkt_length = remLen | |
__write_cmd_v2 = write_cmd_v2 | |
__write_cmd_v2[1] = pkt_length + 5 | |
__write_cmd_v2[3] = curr_addr % 256 | |
__write_cmd_v2[4] = (curr_addr >> 8) % 256 | |
__write_cmd_v2[7] = remLen % 256 | |
__write_cmd_v2 = __write_cmd_v2 + binPayload[curr_addr:curr_addr+pkt_length] | |
#__write_cmd_v2 = __write_cmd_v2 + [0]*(64 - len(__write_cmd_v2)) | |
#print('\n>>>', ''.join('0x{:02x} '.format(x) for x in __write_cmd_v2)) | |
dev.write(epOutAddr, __write_cmd_v2) | |
rec = dev.read(epInAddr, 6) | |
curr_addr = curr_addr + pkt_length | |
remLen = remLen - pkt_length | |
if rec[4] != 0x00: | |
sys.exit('\nFailed to write to device at %d.' % curr_addr) | |
else: | |
print('\rSending to device, %d/%d' % (curr_addr, fileLen), end='') | |
print('\nStart verifying new firmware...') | |
dev.write(epOutAddr, send_key_cmd_v2) | |
dev.read(epInAddr, 6, 2000) | |
remLen = fileLen | |
curr_addr = 0 | |
while curr_addr < fileLen: | |
if remLen >= 56: | |
pkt_length = 56 | |
else: | |
pkt_length = remLen | |
__verify_cmd_v2 = verify_cmd_v2 | |
__verify_cmd_v2[1] = pkt_length + 5 | |
__verify_cmd_v2[3] = curr_addr % 256 | |
__verify_cmd_v2[4] = (curr_addr >> 8) % 256 | |
__verify_cmd_v2[7] = remLen % 256 | |
__verify_cmd_v2 = __verify_cmd_v2 + binPayload[curr_addr:curr_addr+pkt_length] | |
#__verify_cmd_v2 = __verify_cmd_v2 + [0]*(64 - len(__verify_cmd_v2)) | |
dev.write(epOutAddr, __verify_cmd_v2) | |
rec = dev.read(epInAddr, 6) | |
curr_addr = curr_addr + pkt_length | |
remLen = remLen - pkt_length | |
if rec[4] != 0x00: | |
sys.exit('\nInconsistant found at %d.' % curr_addr) | |
else: | |
print('\rSending to device, %d/%d' % (curr_addr, fileLen), end='') | |
print('\nFirmware verified, end flashing.') | |
try: | |
dev.write(epOutAddr, end_flash_cmd_v2) | |
time.sleep(0.5) | |
print('Resetting to run new firmware.\nHave Fun :p') | |
dev.write(epOutAddr, reset_run_cmd_v2) | |
except: | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment