Skip to content

Instantly share code, notes, and snippets.

@MarsTechHAN
Created November 20, 2021 09:44
Show Gist options
  • Save MarsTechHAN/ca16243c49e844a076436bdb279fac63 to your computer and use it in GitHub Desktop.
Save MarsTechHAN/ca16243c49e844a076436bdb279fac63 to your computer and use it in GitHub Desktop.
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