mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
python script: making Fluke8 pleased
This commit is contained in:
parent
917427cb8c
commit
d0bd3266f2
2 changed files with 729 additions and 691 deletions
|
@ -1,5 +1,19 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Imports
|
||||||
|
#
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import pm3
|
||||||
|
import struct
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from fm11rf08s_recovery import recovery
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Revision log & Licence
|
# Revision log & Licence
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -8,43 +22,27 @@
|
||||||
'''
|
'''
|
||||||
script_ver = "1.2.0"
|
script_ver = "1.2.0"
|
||||||
|
|
||||||
'''
|
# Copyright @csBlueChip
|
||||||
Copyright @csBlueChip
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
# (at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
See LICENSE.txt for the text of the license.
|
# See LICENSE.txt for the text of the license.
|
||||||
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The original version of this script can be found at:
|
# The original version of this script can be found at:
|
||||||
https://github.com/csBlueChip/Proxmark_Stuff/tree/main/MiFare_Docs/Fudan_RF08(S)/PM3_Script
|
# https://github.com/csBlueChip/Proxmark_Stuff/tree/main/MiFare_Docs/Fudan_RF08(S)/PM3_Script
|
||||||
The original version is released with an MIT Licence.
|
# The original version is released with an MIT Licence.
|
||||||
Or please reach out to me [BlueChip] personally for alternative licenses.
|
# Or please reach out to me [BlueChip] personally for alternative licenses.
|
||||||
'''
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
# Imports
|
|
||||||
#
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import argparse
|
|
||||||
import pm3
|
|
||||||
import struct
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from fm11rf08s_recovery import recovery
|
|
||||||
|
|
||||||
# optional color support .. `pip install ansicolors`
|
# optional color support .. `pip install ansicolors`
|
||||||
try:
|
try:
|
||||||
|
@ -54,6 +52,7 @@ except ModuleNotFoundError:
|
||||||
_ = fg
|
_ = fg
|
||||||
return str(s)
|
return str(s)
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Print and Log
|
# Print and Log
|
||||||
# >> "logfile"
|
# >> "logfile"
|
||||||
|
@ -62,8 +61,10 @@ def startlog(uid, append = False):
|
||||||
global logfile
|
global logfile
|
||||||
|
|
||||||
logfile = f"{dpath}hf-mf-{uid:08X}-log.txt"
|
logfile = f"{dpath}hf-mf-{uid:08X}-log.txt"
|
||||||
if append == False:
|
if append is False:
|
||||||
with open(logfile, 'w'): pass
|
with open(logfile, 'w'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# +=========================================================
|
# +=========================================================
|
||||||
def lprint(s, end='\n', flush=False):
|
def lprint(s, end='\n', flush=False):
|
||||||
|
@ -73,6 +74,7 @@ def lprint(s, end='\n', flush=False):
|
||||||
with open(logfile, 'a') as f:
|
with open(logfile, 'a') as f:
|
||||||
f.write(s + end)
|
f.write(s + end)
|
||||||
|
|
||||||
|
|
||||||
# ++============================================================================
|
# ++============================================================================
|
||||||
# == MAIN ==
|
# == MAIN ==
|
||||||
# >> "prompt"
|
# >> "prompt"
|
||||||
|
@ -106,18 +108,19 @@ def main():
|
||||||
keyfile = f"{dpath}hf-mf-{uid:08X}-key.bin"
|
keyfile = f"{dpath}hf-mf-{uid:08X}-key.bin"
|
||||||
keyok = False
|
keyok = False
|
||||||
|
|
||||||
if args.force == False and loadKeys() == True:
|
if args.force is False and loadKeys() is True:
|
||||||
keyok = True
|
keyok = True
|
||||||
else:
|
else:
|
||||||
if args.recover == False:
|
if args.recover is False:
|
||||||
lprint(f"{prompt} * Keys not loaded, use --recover to run recovery script [slow]")
|
lprint(f"{prompt} * Keys not loaded, use --recover to run recovery script [slow]")
|
||||||
else:
|
else:
|
||||||
recoverKeys()
|
recoverKeys()
|
||||||
if loadKeys() == True: keyok = True
|
if loadKeys() is True:
|
||||||
|
keyok = True
|
||||||
|
|
||||||
if keyok == True:
|
if keyok is True:
|
||||||
if verifyKeys() == False:
|
if verifyKeys() is False:
|
||||||
if args.nokeys == False:
|
if args.nokeys is False:
|
||||||
lprint(f"{prompt} ! Use --nokeys to keep going past this point")
|
lprint(f"{prompt} ! Use --nokeys to keep going past this point")
|
||||||
exit(101)
|
exit(101)
|
||||||
|
|
||||||
|
@ -129,9 +132,10 @@ def main():
|
||||||
dumpData()
|
dumpData()
|
||||||
dumpAcl()
|
dumpAcl()
|
||||||
|
|
||||||
if mad == True: dumpMad()
|
if mad is True:
|
||||||
|
dumpMad()
|
||||||
|
|
||||||
if (args.bambu == True) or (detectBambu() == True):
|
if (args.bambu is True) or (detectBambu() is True):
|
||||||
dumpBambu()
|
dumpBambu()
|
||||||
|
|
||||||
lprint(prompt)
|
lprint(prompt)
|
||||||
|
@ -139,6 +143,7 @@ def main():
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Get PM3 preferences
|
# Get PM3 preferences
|
||||||
# >> "dpath"
|
# >> "dpath"
|
||||||
|
@ -150,6 +155,7 @@ def getPrefs():
|
||||||
prefs = json.loads(p.grabbed_output)
|
prefs = json.loads(p.grabbed_output)
|
||||||
dpath = prefs['file.default.dumppath'] + os.path.sep
|
dpath = prefs['file.default.dumppath'] + os.path.sep
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Assert python version
|
# Assert python version
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
@ -160,6 +166,7 @@ def checkVer():
|
||||||
print(f"The script needs at least Python v{required_version[0]}.{required_version[1]}. Abort.")
|
print(f"The script needs at least Python v{required_version[0]}.{required_version[1]}. Abort.")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Parse the CLi arguments
|
# Parse the CLi arguments
|
||||||
# >> args.
|
# >> args.
|
||||||
|
@ -177,17 +184,17 @@ def parseCli():
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.force == True: args.recover = True
|
if args.force is True:
|
||||||
|
args.recover = True
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Find backdoor key
|
# Find backdoor key
|
||||||
# >> "dkey"
|
# >> "dkey"
|
||||||
# >> "blk0"
|
# >> "blk0"
|
||||||
'''
|
# [=] # | sector 00 / 0x00 | ascii
|
||||||
[=] # | sector 00 / 0x00 | ascii
|
# [=] ----+-------------------------------------------------+-----------------
|
||||||
[=] ----+-------------------------------------------------+-----------------
|
# [=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
||||||
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
|
||||||
'''
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def getDarkKey():
|
def getDarkKey():
|
||||||
global dkey
|
global dkey
|
||||||
|
@ -206,8 +213,8 @@ def getDarkKey():
|
||||||
res = p.console(f"{cmd}", capture=False)
|
res = p.console(f"{cmd}", capture=False)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
print(" - success")
|
print(" - success")
|
||||||
dkey = k;
|
dkey = k
|
||||||
break;
|
break
|
||||||
print(f" - fail [{res}]")
|
print(f" - fail [{res}]")
|
||||||
|
|
||||||
if dkey == "":
|
if dkey == "":
|
||||||
|
@ -219,6 +226,7 @@ def getDarkKey():
|
||||||
if " | " in line and "# | s" not in line:
|
if " | " in line and "# | s" not in line:
|
||||||
blk0 = line[10:56+1]
|
blk0 = line[10:56+1]
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Extract data from block 0
|
# Extract data from block 0
|
||||||
# >> "uid"
|
# >> "uid"
|
||||||
|
@ -255,7 +263,7 @@ def decodeBlock0():
|
||||||
|
|
||||||
fida = int(blk0[24:26], 16) # Fudan ID 0x88
|
fida = int(blk0[24:26], 16) # Fudan ID 0x88
|
||||||
fidb = int(blk0[45:47], 16) # Fudan ID 0xFF
|
fidb = int(blk0[45:47], 16) # Fudan ID 0xFF
|
||||||
fid = (fida<<8)|fidb # Fudan ID 0x88FF
|
# fid = (fida<<8)|fidb # Fudan ID 0x88FF
|
||||||
|
|
||||||
hash = blk0[27:44] # Fudan hash "99 AA BB CC DD EE"
|
hash = blk0[27:44] # Fudan hash "99 AA BB CC DD EE"
|
||||||
|
|
||||||
|
@ -279,22 +287,31 @@ def decodeBlock0():
|
||||||
lprint(prompt)
|
lprint(prompt)
|
||||||
|
|
||||||
lprint(f"{prompt} UID/BCC : {uid:08X}/{bcc:02X} - ", end='')
|
lprint(f"{prompt} UID/BCC : {uid:08X}/{bcc:02X} - ", end='')
|
||||||
if bcc == chk: lprint("verified")
|
if bcc == chk:
|
||||||
else: lprint(f"fail. Expected {chk:02X}")
|
lprint("verified")
|
||||||
|
else:
|
||||||
|
lprint(f"fail. Expected {chk:02X}")
|
||||||
|
|
||||||
lprint(f"{prompt} SAK : {sak:02X} - ", end='')
|
lprint(f"{prompt} SAK : {sak:02X} - ", end='')
|
||||||
if sak == 0x01: lprint("NXP MIFARE TNP3xxx 1K")
|
if sak == 0x01:
|
||||||
elif sak == 0x08: lprint("NXP MIFARE CLASSIC 1k | Plus 1k | Ev1 1K")
|
lprint("NXP MIFARE TNP3xxx 1K")
|
||||||
elif sak == 0x09: lprint("NXP MIFARE Mini 0.3k")
|
elif sak == 0x08:
|
||||||
elif sak == 0x10: lprint("NXP MIFARE Plus 2k")
|
lprint("NXP MIFARE CLASSIC 1k | Plus 1k | Ev1 1K")
|
||||||
elif sak == 0x18: lprint("NXP MIFARE Classic 4k | Plus 4k | Ev1 4k")
|
elif sak == 0x09:
|
||||||
else: lprint("{unknown}")
|
lprint("NXP MIFARE Mini 0.3k")
|
||||||
|
elif sak == 0x10:
|
||||||
|
lprint("NXP MIFARE Plus 2k")
|
||||||
|
elif sak == 0x18:
|
||||||
|
lprint("NXP MIFARE Classic 4k | Plus 4k | Ev1 4k")
|
||||||
|
else:
|
||||||
|
lprint("{unknown}")
|
||||||
|
|
||||||
lprint(f"{prompt} ATQA : {atqa:04X}") # show ATQA
|
lprint(f"{prompt} ATQA : {atqa:04X}") # show ATQA
|
||||||
lprint(f"{prompt} Fudan ID : {type}") # show type
|
lprint(f"{prompt} Fudan ID : {type}") # show type
|
||||||
lprint(f"{prompt} Fudan Sig: {hash}") # show ?Partial HMAC?
|
lprint(f"{prompt} Fudan Sig: {hash}") # show ?Partial HMAC?
|
||||||
lprint(f"{prompt} Dark Key : {dkey}") # show key
|
lprint(f"{prompt} Dark Key : {dkey}") # show key
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Fudan validation
|
# Fudan validation
|
||||||
# >> "blk0"
|
# >> "blk0"
|
||||||
|
@ -334,17 +351,20 @@ def fudanValidate():
|
||||||
lprint(prompt)
|
lprint(prompt)
|
||||||
lprint(f"{prompt} ...Use --validate to perform Fudan signature check automatically")
|
lprint(f"{prompt} ...Use --validate to perform Fudan signature check automatically")
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Load keys from file
|
# Load keys from file
|
||||||
# If keys cannot be loaded AND --recover is specified, then run key recovery
|
# If keys cannot be loaded AND --recover is specified, then run key recovery
|
||||||
# >> "keyfile"
|
# >> "keyfile"
|
||||||
# >> "key[17][2]"
|
# >> "key[17][2]"
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
|
|
||||||
def loadKeys():
|
def loadKeys():
|
||||||
global keyfile
|
global keyfile
|
||||||
global key
|
global key
|
||||||
|
|
||||||
key = [[0 for _ in range(2)] for _ in range(17)] # create a fresh array
|
key = [[b'' for _ in range(2)] for _ in range(17)] # create a fresh array
|
||||||
|
|
||||||
lprint(prompt)
|
lprint(prompt)
|
||||||
lprint(f"{prompt} Load Keys from file: |{keyfile}|")
|
lprint(f"{prompt} Load Keys from file: |{keyfile}|")
|
||||||
|
@ -355,11 +375,12 @@ def loadKeys():
|
||||||
for sec in range((16+2)-1):
|
for sec in range((16+2)-1):
|
||||||
key[sec][ab] = fh.read(6)
|
key[sec][ab] = fh.read(6)
|
||||||
|
|
||||||
except IOError as e:
|
except IOError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Run key recovery script
|
# Run key recovery script
|
||||||
# >> "keyfile"
|
# >> "keyfile"
|
||||||
|
@ -378,23 +399,28 @@ def recoverKeys():
|
||||||
r = recovery(quiet=False)
|
r = recovery(quiet=False)
|
||||||
keyfile = r['keyfile']
|
keyfile = r['keyfile']
|
||||||
rkey = r['found_keys']
|
rkey = r['found_keys']
|
||||||
fdump = r['dumpfile']
|
# fdump = r['dumpfile']
|
||||||
rdata = r['data']
|
# rdata = r['data']
|
||||||
|
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
for k in range(0, 16+1):
|
for k in range(0, 16+1):
|
||||||
for ab in [0, 1]:
|
for ab in [0, 1]:
|
||||||
if rkey[k][ab] == "":
|
if rkey[k][ab] == "":
|
||||||
if badrk == 0: lprint(f"{prompt} Some keys were not recovered: ", end='')
|
if badrk == 0:
|
||||||
else: lprint(f", ", end='')
|
lprint(f"{prompt} Some keys were not recovered: ", end='')
|
||||||
|
else:
|
||||||
|
lprint(", ", end='')
|
||||||
badrk += 1
|
badrk += 1
|
||||||
|
|
||||||
kn = k
|
kn = k
|
||||||
if kn > 15: kn += 16
|
if kn > 15:
|
||||||
|
kn += 16
|
||||||
lprint(f"[{kn}/", end='')
|
lprint(f"[{kn}/", end='')
|
||||||
lprint("A]" if ab == 0 else "B]", end='')
|
lprint("A]" if ab == 0 else "B]", end='')
|
||||||
if badrk > 0: lprint("")
|
if badrk > 0:
|
||||||
|
lprint("")
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Verify keys
|
# Verify keys
|
||||||
|
@ -411,11 +437,13 @@ def verifyKeys():
|
||||||
|
|
||||||
for sec in range(0, 16+1): # 16 normal, 1 dark
|
for sec in range(0, 16+1): # 16 normal, 1 dark
|
||||||
sn = sec
|
sn = sec
|
||||||
if (sn > 15): sn = sn + 16
|
if (sn > 15):
|
||||||
|
sn = sn + 16
|
||||||
|
|
||||||
for ab in [0, 1]:
|
for ab in [0, 1]:
|
||||||
bn = (sec * 4) + 3
|
bn = (sec * 4) + 3
|
||||||
if bn >= 64: bn += 64
|
if bn >= 64:
|
||||||
|
bn += 64
|
||||||
|
|
||||||
cmd = f"hf mf rdbl -c {ab} --key {key[sec][ab].hex()} --blk {bn}"
|
cmd = f"hf mf rdbl -c {ab} --key {key[sec][ab].hex()} --blk {bn}"
|
||||||
lprint(f"{prompt} `{cmd}`", end='', flush=True)
|
lprint(f"{prompt} `{cmd}`", end='', flush=True)
|
||||||
|
@ -427,7 +455,7 @@ def verifyKeys():
|
||||||
else:
|
else:
|
||||||
lprint(" ... FAIL", end="")
|
lprint(" ... FAIL", end="")
|
||||||
badk += 1
|
badk += 1
|
||||||
key[sec][ab] = ""
|
key[sec][ab] = b''
|
||||||
|
|
||||||
# check for Mifare Application Directory
|
# check for Mifare Application Directory
|
||||||
if (sec == 0) and (ab == 0) \
|
if (sec == 0) and (ab == 0) \
|
||||||
|
@ -446,20 +474,19 @@ def verifyKeys():
|
||||||
lprint(f"{prompt} All keys verified OK")
|
lprint(f"{prompt} All keys verified OK")
|
||||||
rv = True
|
rv = True
|
||||||
|
|
||||||
if mad == True:
|
if mad is True:
|
||||||
lprint(f"{prompt} MAD key detected")
|
lprint(f"{prompt} MAD key detected")
|
||||||
|
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Read all block data - INCLUDING Dark blocks
|
# Read all block data - INCLUDING Dark blocks
|
||||||
# >> blkn
|
# >> blkn
|
||||||
# >> "data[]"
|
# >> "data[]"
|
||||||
'''
|
# [=] # | sector 00 / 0x00 | ascii
|
||||||
[=] # | sector 00 / 0x00 | ascii
|
# [=] ----+-------------------------------------------------+-----------------
|
||||||
[=] ----+-------------------------------------------------+-----------------
|
# [=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
||||||
[=] 0 | 5C B4 9C A6 D2 08 04 00 04 59 92 25 BF 5F 70 90 | \........Y.%._p.
|
|
||||||
'''
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def readBlocks():
|
def readBlocks():
|
||||||
global data
|
global data
|
||||||
|
@ -488,10 +515,11 @@ def readBlocks():
|
||||||
found = False
|
found = False
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
if " | " in line and "# | s" not in line:
|
if " | " in line and "# | s" not in line:
|
||||||
l = line[4:76]
|
lsub = line[4:76]
|
||||||
data.append(l)
|
data.append(lsub)
|
||||||
found = True
|
found = True
|
||||||
if found: break
|
if found:
|
||||||
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
data.append(f"{n:3d} | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | ----------------")
|
data.append(f"{n:3d} | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | ----------------")
|
||||||
|
@ -499,14 +527,13 @@ def readBlocks():
|
||||||
|
|
||||||
print(" .. OK")
|
print(" .. OK")
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Patch keys in to data
|
# Patch keys in to data
|
||||||
# >> "key[][]"
|
# >> "key[][]"
|
||||||
# >> "data[]"
|
# >> "data[]"
|
||||||
# >> keyok!
|
# >> keyok!
|
||||||
'''
|
# 3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
|
||||||
'''
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def patchKeys(keyok):
|
def patchKeys(keyok):
|
||||||
global key
|
global key
|
||||||
|
@ -518,13 +545,13 @@ def patchKeys(keyok):
|
||||||
for sec in range(0, 16+1):
|
for sec in range(0, 16+1):
|
||||||
blk = (sec * 4) + 3 # find "trailer" for this sector
|
blk = (sec * 4) + 3 # find "trailer" for this sector
|
||||||
if keyok:
|
if keyok:
|
||||||
if key[sec][0] == "":
|
if key[sec][0] == b'':
|
||||||
keyA = "-- -- -- -- -- -- "
|
keyA = "-- -- -- -- -- -- "
|
||||||
else:
|
else:
|
||||||
kstr = key[sec][0].hex()
|
kstr = key[sec][0].hex()
|
||||||
keyA = "".join([kstr[i:i+2] + " " for i in range(0, len(kstr), 2)])
|
keyA = "".join([kstr[i:i+2] + " " for i in range(0, len(kstr), 2)])
|
||||||
|
|
||||||
if key[sec][1] == "":
|
if key[sec][1] == b'':
|
||||||
keyB = "-- -- -- -- -- -- "
|
keyB = "-- -- -- -- -- -- "
|
||||||
else:
|
else:
|
||||||
kstr = key[sec][1].hex()
|
kstr = key[sec][1].hex()
|
||||||
|
@ -535,6 +562,7 @@ def patchKeys(keyok):
|
||||||
else:
|
else:
|
||||||
data[blk] = data[blk][:6] + "-- -- -- -- -- -- " + data[blk][24:36] + "-- -- -- -- -- --"
|
data[blk] = data[blk][:6] + "-- -- -- -- -- -- " + data[blk][24:36] + "-- -- -- -- -- --"
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump data
|
# Dump data
|
||||||
# >> blkn
|
# >> blkn
|
||||||
|
@ -553,7 +581,8 @@ def dumpData():
|
||||||
cnt = 0
|
cnt = 0
|
||||||
for n in blkn:
|
for n in blkn:
|
||||||
sec = (cnt // 4)
|
sec = (cnt // 4)
|
||||||
if sec > 15: sec = sec + 16
|
if sec > 15:
|
||||||
|
sec = sec + 16
|
||||||
|
|
||||||
if (n % 4 == 0):
|
if (n % 4 == 0):
|
||||||
lprint(f"{prompt} {sec:2d}:{data[cnt]}")
|
lprint(f"{prompt} {sec:2d}:{data[cnt]}")
|
||||||
|
@ -564,6 +593,7 @@ def dumpData():
|
||||||
if (cnt % 4 == 0) and (n != blkn[-1]): # Space between sectors
|
if (cnt % 4 == 0) and (n != blkn[-1]): # Space between sectors
|
||||||
lprint(prompt)
|
lprint(prompt)
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Let's try to detect a Bambu card by the date strings...
|
# Let's try to detect a Bambu card by the date strings...
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
@ -572,7 +602,7 @@ def detectBambu():
|
||||||
dl = bytes.fromhex(data[12][6:53]).decode('ascii').rstrip('\x00')
|
dl = bytes.fromhex(data[12][6:53]).decode('ascii').rstrip('\x00')
|
||||||
dls = dl[2:13]
|
dls = dl[2:13]
|
||||||
ds = bytes.fromhex(data[13][6:41]).decode('ascii').rstrip('\x00')
|
ds = bytes.fromhex(data[13][6:41]).decode('ascii').rstrip('\x00')
|
||||||
except Exception as e:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# ds 24_03_22_16
|
# ds 24_03_22_16
|
||||||
|
@ -593,11 +623,9 @@ def detectBambu():
|
||||||
# Dump bambu details
|
# Dump bambu details
|
||||||
# https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
# https://github.com/Bambu-Research-Group/RFID-Tag-Guide/blob/main/README.md
|
||||||
# >> "data[]"
|
# >> "data[]"
|
||||||
'''
|
# 6 18 30 42 53
|
||||||
6 18 30 42 53
|
# | | | | |
|
||||||
| | | | |
|
# 3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
|
||||||
'''
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
def dumpBambu():
|
def dumpBambu():
|
||||||
global data
|
global data
|
||||||
|
@ -646,12 +674,17 @@ def dumpBambu():
|
||||||
|
|
||||||
ShortProductionDateTime_s = bytes.fromhex(data[13][6:53]).decode('ascii').rstrip('\x00')
|
ShortProductionDateTime_s = bytes.fromhex(data[13][6:53]).decode('ascii').rstrip('\x00')
|
||||||
|
|
||||||
Block14_0to3 = data[14][ 6:17]
|
# Block14_0to3 = data[14][6:17]
|
||||||
FilamentLength_m = int(data[14][21:23] + data[14][18:20], 16)
|
FilamentLength_m = int(data[14][21:23] + data[14][18:20], 16)
|
||||||
Block14_6to15 = data[14][24:51]
|
# Block14_6to15 = data[14][24:51]
|
||||||
|
|
||||||
# (16blocks * 16bytes = 256) * 8bits = 2048 bits
|
# (16blocks * 16bytes = 256) * 8bits = 2048 bits
|
||||||
hblk = [42, 44,45,46, 48,49,50, 52,53,54, 56,57,58, 60,61,62]
|
hblk = [42,
|
||||||
|
44, 45, 46,
|
||||||
|
48, 49, 50,
|
||||||
|
52, 53, 54,
|
||||||
|
56, 57, 58,
|
||||||
|
60, 61, 62]
|
||||||
Hash = []
|
Hash = []
|
||||||
for b in hblk:
|
for b in hblk:
|
||||||
Hash.append(data[b][6:53])
|
Hash.append(data[b][6:53])
|
||||||
|
@ -704,97 +737,95 @@ def dumpBambu():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
lprint(f"Failed: {e}")
|
lprint(f"Failed: {e}")
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump ACL
|
# Dump ACL
|
||||||
# >> "data[][]"
|
# >> "data[][]"
|
||||||
'''
|
# 6 18 24 27 30 33 42 53
|
||||||
6 18 24 27 30 33 42 53
|
# | | | | | | | |
|
||||||
| | | | | | | |
|
# 3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
||||||
3 | 00 00 00 00 00 00 87 87 87 69 00 00 00 00 00 00 | .........i......
|
# ab cd ef
|
||||||
ab cd ef
|
#
|
||||||
'''
|
# ,-------------------.
|
||||||
'''
|
# ( 2.2 : ACCESS BITS )
|
||||||
,-------------------.
|
# `-------------------'
|
||||||
( 2.2 : ACCESS BITS )
|
|
||||||
`-------------------'
|
|
||||||
|
|
||||||
The Access bits on both (used) Sectors is the same: 78 77 88
|
# The Access bits on both (used) Sectors is the same: 78 77 88
|
||||||
|
|
||||||
Let's reorganise that according to the official spec Fig 9.
|
# Let's reorganise that according to the official spec Fig 9.
|
||||||
Access C1 C2 C3
|
# Access C1 C2 C3
|
||||||
========== ===========
|
# ========== ===========
|
||||||
78 77 88 --> 78 87 87
|
# 78 77 88 --> 78 87 87
|
||||||
ab cd ef --> cb fa ed
|
# ab cd ef --> cb fa ed
|
||||||
|
|
||||||
The second nybble of each byte is the inverse of the first nybble.
|
# The second nybble of each byte is the inverse of the first nybble.
|
||||||
It is there to trap tranmission errors, so we can just ignore it/them.
|
# It is there to trap tranmission errors, so we can just ignore it/them.
|
||||||
|
|
||||||
So our Access Control value is : {c, f, e} == {7, 8, 8}
|
# So our Access Control value is : {c, f, e} == {7, 8, 8}
|
||||||
|
|
||||||
Let's convert those nybbles to binary
|
# Let's convert those nybbles to binary
|
||||||
(c) 7 --> 0111
|
# (c) 7 --> 0111
|
||||||
(f) 8 --> 1000
|
# (f) 8 --> 1000
|
||||||
(e) 8 --> 1000
|
# (e) 8 --> 1000
|
||||||
|||| ...and transpose them:
|
# |||| ...and transpose them:
|
||||||
||||
|
# ||||
|
||||||
|||`--- 100 - Block 0 Access bits
|
# |||`--- 100 - Block 0 Access bits
|
||||||
||`---- 100 - Block 1 Access bits
|
# ||`---- 100 - Block 1 Access bits
|
||||||
|`----- 100 - Block 2 Access bits
|
# |`----- 100 - Block 2 Access bits
|
||||||
`------ 011 - Block 3 Access bits [Sector Trailer]
|
# `------ 011 - Block 3 Access bits [Sector Trailer]
|
||||||
|
|
||||||
Now we can use the lookup table [Table 3] to work out what we can do
|
# Now we can use the lookup table [Table 3] to work out what we can do
|
||||||
with the Sector Trailer (Block(S,3)):
|
# with the Sector Trailer (Block(S,3)):
|
||||||
|
|
||||||
| Key A | | Access Bits | | Key B |
|
# | Key A | | Access Bits | | Key B |
|
||||||
| read ¦ write | | read ¦ write | | read ¦ write |
|
# | read ¦ write | | read ¦ write | | read ¦ write |
|
||||||
+------¦-------+ +------¦-------+ +------¦-------+
|
# +------¦-------+ +------¦-------+ +------¦-------+
|
||||||
000 : | -- ¦ KeyA | | KeyA ¦ -- | | KeyA ¦ KeyA |
|
# 000 : | -- ¦ KeyA | | KeyA ¦ -- | | KeyA ¦ KeyA |
|
||||||
001 : | -- ¦ KeyA | | KeyA ¦ KeyA | | KeyA ¦ KeyA | Transport Mode
|
# 001 : | -- ¦ KeyA | | KeyA ¦ KeyA | | KeyA ¦ KeyA | Transport Mode
|
||||||
010 : | -- ¦ -- | | KeyA ¦ -- | | KeyA ¦ -- |
|
# 010 : | -- ¦ -- | | KeyA ¦ -- | | KeyA ¦ -- |
|
||||||
|
|
||||||
011 : | -- ¦ KeyB | | A+B ¦ KeyB | | -- ¦ KeyB | <-- Our Card!
|
# 011 : | -- ¦ KeyB | | A+B ¦ KeyB | | -- ¦ KeyB | <-- Our Card!
|
||||||
|
|
||||||
100 : | -- ¦ KeyB | | A+B ¦ -- | | -- ¦ KeyB |
|
# 100 : | -- ¦ KeyB | | A+B ¦ -- | | -- ¦ KeyB |
|
||||||
101 : | -- ¦ -- | | A+B ¦ KeyB | | -- ¦ -- |
|
# 101 : | -- ¦ -- | | A+B ¦ KeyB | | -- ¦ -- |
|
||||||
110 : | -- ¦ -- | | A+B ¦ -- | | -- ¦ -- | }__
|
# 110 : | -- ¦ -- | | A+B ¦ -- | | -- ¦ -- | }__
|
||||||
111 : | -- ¦ -- | | A+B ¦ -- | | -- ¦ -- | } The Same!?
|
# 111 : | -- ¦ -- | | A+B ¦ -- | | -- ¦ -- | } The Same!?
|
||||||
|
|
||||||
Our card uses 011, for (both of) the (used) Sector Trailer(s). So:
|
# Our card uses 011, for (both of) the (used) Sector Trailer(s). So:
|
||||||
Both Key A and Key B can READ the Access Bits
|
# Both Key A and Key B can READ the Access Bits
|
||||||
Key B can (additionally) WRITE to Key A, Key B (itself), and the Access Bits
|
# Key B can (additionally) WRITE to Key A, Key B (itself), and the Access Bits
|
||||||
|
|
||||||
Then we can do a similar lookup for the 3 data Blocks (in this Sector)
|
# Then we can do a similar lookup for the 3 data Blocks (in this Sector)
|
||||||
This time using [Table 4]
|
# This time using [Table 4]
|
||||||
|
|
||||||
| Data | Counter |
|
# | Data | Counter |
|
||||||
| read ¦ write | Inc ¦ Dec |
|
# | read ¦ write | Inc ¦ Dec |
|
||||||
+------¦-------+------¦------+
|
# +------¦-------+------¦------+
|
||||||
000 : | A+B ¦ A+B | A+B ¦ A+B | Transport Mode
|
# 000 : | A+B ¦ A+B | A+B ¦ A+B | Transport Mode
|
||||||
001 : | A+B ¦ -- | -- ¦ A+B |
|
# 001 : | A+B ¦ -- | -- ¦ A+B |
|
||||||
010 : | A+B ¦ -- | -- ¦ -- |
|
# 010 : | A+B ¦ -- | -- ¦ -- |
|
||||||
011 : | KeyB ¦ KeyB | -- ¦ -- |
|
# 011 : | KeyB ¦ KeyB | -- ¦ -- |
|
||||||
|
|
||||||
100 : | A+B ¦ KeyB | -- ¦ -- | <-- Our Card!
|
# 100 : | A+B ¦ KeyB | -- ¦ -- | <-- Our Card!
|
||||||
|
|
||||||
101 : | KeyB ¦ -- | -- ¦ -- |
|
# 101 : | KeyB ¦ -- | -- ¦ -- |
|
||||||
110 : | A+B ¦ KeyB | KeyB ¦ A+B |
|
# 110 : | A+B ¦ KeyB | KeyB ¦ A+B |
|
||||||
111 : | -- ¦ -- | -- ¦ -- |
|
# 111 : | -- ¦ -- | -- ¦ -- |
|
||||||
|
|
||||||
Our card uses 100, for all of the (used) Sectors. So:
|
# Our card uses 100, for all of the (used) Sectors. So:
|
||||||
Both Key A and Key B can READ the Block
|
# Both Key A and Key B can READ the Block
|
||||||
Only Key B can WRITE to the Block
|
# Only Key B can WRITE to the Block
|
||||||
The block cannot be used as a "counter" because:
|
# The block cannot be used as a "counter" because:
|
||||||
Neither key can perform increment nor decrement commands
|
# Neither key can perform increment nor decrement commands
|
||||||
|
|
||||||
WARNING:
|
# WARNING:
|
||||||
IF YOU PLAN TO CHANGE ACCESS BITS, RTFM, THERE IS MUCH TO CONSIDER !
|
# IF YOU PLAN TO CHANGE ACCESS BITS, RTFM, THERE IS MUCH TO CONSIDER !
|
||||||
'''
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def dumpAcl():
|
def dumpAcl():
|
||||||
global blkn
|
global blkn
|
||||||
|
|
||||||
aclkh = [] # key header
|
aclkh = [] # key header
|
||||||
aclk = [0] * 8 # key lookup
|
aclk = [""] * 8 # key lookup
|
||||||
aclkx = [] # key output
|
aclkx = [] # key output
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint(f"{prompt}")
|
||||||
|
@ -809,17 +840,17 @@ def dumpAcl():
|
||||||
aclkh.append("| | read ¦ write || read ¦ write || read ¦ write |")
|
aclkh.append("| | read ¦ write || read ¦ write || read ¦ write |")
|
||||||
aclkh.append("|--------+------¦-------++------¦-------++------¦-------|")
|
aclkh.append("|--------+------¦-------++------¦-------++------¦-------|")
|
||||||
# "| xx | -- ¦ KeyA || KeyA ¦ -- || KeyA ¦ KeyA |"
|
# "| xx | -- ¦ KeyA || KeyA ¦ -- || KeyA ¦ KeyA |"
|
||||||
aclk[0] = "| -- ¦ KeyA || KeyA ¦ -- || KeyA ¦ KeyA | [000]"
|
aclk[0] = "| -- ¦ KeyA || KeyA ¦ -- || KeyA ¦ KeyA | [000]" # noqa: E222
|
||||||
aclk[1] = "| -- ¦ KeyA || KeyA ¦ KeyA || KeyA ¦ KeyA | [001]"
|
aclk[1] = "| -- ¦ KeyA || KeyA ¦ KeyA || KeyA ¦ KeyA | [001]" # noqa: E222
|
||||||
aclk[2] = "| -- ¦ -- || KeyA ¦ -- || KeyA ¦ -- | [010]"
|
aclk[2] = "| -- ¦ -- || KeyA ¦ -- || KeyA ¦ -- | [010]" # noqa: E222
|
||||||
aclk[3] = "| -- ¦ KeyB || A+B ¦ KeyB || -- ¦ KeyB | [011]"
|
aclk[3] = "| -- ¦ KeyB || A+B ¦ KeyB || -- ¦ KeyB | [011]" # noqa: E222
|
||||||
aclk[4] = "| -- ¦ KeyB || A+B ¦ -- || -- ¦ KeyB | [100]"
|
aclk[4] = "| -- ¦ KeyB || A+B ¦ -- || -- ¦ KeyB | [100]" # noqa: E222
|
||||||
aclk[5] = "| -- ¦ -- || A+B ¦ KeyB || -- ¦ -- | [101]"
|
aclk[5] = "| -- ¦ -- || A+B ¦ KeyB || -- ¦ -- | [101]" # noqa: E222
|
||||||
aclk[6] = "| -- ¦ -- || A+B ¦ -- || -- ¦ -- | [110]" # yes, the same!?
|
aclk[6] = "| -- ¦ -- || A+B ¦ -- || -- ¦ -- | [110]" # noqa: E222 # yes, the same!?
|
||||||
aclk[7] = "| -- ¦ -- || A+B ¦ -- || -- ¦ -- | [111]" # ...
|
aclk[7] = "| -- ¦ -- || A+B ¦ -- || -- ¦ -- | [111]" # noqa: E222 # ...
|
||||||
|
|
||||||
acldh = [] # data header
|
acldh = [] # data header
|
||||||
acld = [0] * 8 # data lookup
|
acld = [""] * 8 # data lookup
|
||||||
acldx = [] # data output
|
acldx = [] # data output
|
||||||
|
|
||||||
acldh.append(" _____________________________________ ")
|
acldh.append(" _____________________________________ ")
|
||||||
|
@ -829,16 +860,16 @@ def dumpAcl():
|
||||||
acldh.append("| | read ¦ write || Inc ¦ Dec |")
|
acldh.append("| | read ¦ write || Inc ¦ Dec |")
|
||||||
acldh.append("|-------+------¦-------++------¦------+")
|
acldh.append("|-------+------¦-------++------¦------+")
|
||||||
# "| xxx | A+B ¦ A+B || A+B ¦ A+B | "
|
# "| xxx | A+B ¦ A+B || A+B ¦ A+B | "
|
||||||
acld[0] = "| A+B ¦ A+B || A+B ¦ A+B | [000]"
|
acld[0] = "| A+B ¦ A+B || A+B ¦ A+B | [000]" # noqa: E222
|
||||||
acld[1] = "| A+B ¦ -- || -- ¦ A+B | [001]"
|
acld[1] = "| A+B ¦ -- || -- ¦ A+B | [001]" # noqa: E222
|
||||||
acld[2] = "| A+B ¦ -- || -- ¦ -- | [010]"
|
acld[2] = "| A+B ¦ -- || -- ¦ -- | [010]" # noqa: E222
|
||||||
acld[3] = "| KeyB ¦ KeyB || -- ¦ -- | [011]"
|
acld[3] = "| KeyB ¦ KeyB || -- ¦ -- | [011]" # noqa: E222
|
||||||
acld[4] = "| A+B ¦ KeyB || -- ¦ -- | [100]"
|
acld[4] = "| A+B ¦ KeyB || -- ¦ -- | [100]" # noqa: E222
|
||||||
acld[5] = "| KeyB ¦ -- || -- ¦ -- | [101]"
|
acld[5] = "| KeyB ¦ -- || -- ¦ -- | [101]" # noqa: E222
|
||||||
acld[6] = "| A+B ¦ KeyB || KeyB ¦ A+B | [110]"
|
acld[6] = "| A+B ¦ KeyB || KeyB ¦ A+B | [110]" # noqa: E222
|
||||||
acld[7] = "| -- ¦ -- || -- ¦ -- | [111]"
|
acld[7] = "| -- ¦ -- || -- ¦ -- | [111]" # noqa: E222
|
||||||
|
|
||||||
idx = [0] * (16+2)
|
idx = [] * (16+2)
|
||||||
|
|
||||||
# --- calculate the ACL indices for each sector:block ---
|
# --- calculate the ACL indices for each sector:block ---
|
||||||
for d in data:
|
for d in data:
|
||||||
|
@ -851,10 +882,10 @@ def dumpAcl():
|
||||||
c = int(d[27], 16)
|
c = int(d[27], 16)
|
||||||
f = int(d[31], 16)
|
f = int(d[31], 16)
|
||||||
e = int(d[30], 16)
|
e = int(d[30], 16)
|
||||||
r0 = ((c & (2**0)) << 2) | ((f & (2**0)) << 1) | ((e & (2**0)) )
|
r0 = ((c & (2**0)) << 2) | ((f & (2**0)) << 1) | ((e & (2**0)) ) # noqa: E202
|
||||||
r1 = ((c & (2**1)) << 1) | ((f & (2**1)) ) | ((e & (2**1)) >> 1)
|
r1 = ((c & (2**1)) << 1) | ((f & (2**1)) ) | ((e & (2**1)) >> 1) # noqa: E202
|
||||||
r2 = ((c & (2**2)) ) | ((f & (2**2)) >> 1) | ((e & (2**2)) >> 2)
|
r2 = ((c & (2**2)) ) | ((f & (2**2)) >> 1) | ((e & (2**2)) >> 2) # noqa: E202
|
||||||
r3 = ((c & (2**3)) >> 1) | ((f & (2**3)) >> 2) | ((e & (2**3)) >> 3)
|
r3 = ((c & (2**3)) >> 1) | ((f & (2**3)) >> 2) | ((e & (2**3)) >> 3) # noqa: E221
|
||||||
idx[sec] = [r0, r1, r2, r3]
|
idx[sec] = [r0, r1, r2, r3]
|
||||||
|
|
||||||
# --- build the ACL conversion table ---
|
# --- build the ACL conversion table ---
|
||||||
|
@ -870,24 +901,27 @@ def dumpAcl():
|
||||||
acldx.append(f"| {bn:3d} " + acld[idx[sec][bn % 4]])
|
acldx.append(f"| {bn:3d} " + acld[idx[sec][bn % 4]])
|
||||||
|
|
||||||
# --- print it all out ---
|
# --- print it all out ---
|
||||||
for l in aclkh:
|
for line in aclkh:
|
||||||
lprint(f"{prompt} {l}")
|
lprint(f"{prompt} {line}")
|
||||||
i = 0
|
i = 0
|
||||||
for l in aclkx:
|
for line in aclkx:
|
||||||
lprint(f"{prompt} {l}")
|
lprint(f"{prompt} {line}")
|
||||||
if (i % 4) == 3: lprint(f"{prompt} | | ¦ || ¦ || ¦ |")
|
if (i % 4) == 3:
|
||||||
|
lprint(f"{prompt} | | ¦ || ¦ || ¦ |")
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint(f"{prompt}")
|
||||||
|
|
||||||
for l in acldh:
|
for line in acldh:
|
||||||
lprint(f"{prompt} {l}")
|
lprint(f"{prompt} {line}")
|
||||||
i = 0
|
i = 0
|
||||||
for l in acldx:
|
for line in acldx:
|
||||||
lprint(f"{prompt} {l}")
|
lprint(f"{prompt} {line}")
|
||||||
if (i % 3) == 2: lprint(f"{prompt} | | ¦ || ¦ |")
|
if (i % 3) == 2:
|
||||||
|
lprint(f"{prompt} | | ¦ || ¦ |")
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Full Dump
|
# Full Dump
|
||||||
# >> "uid"
|
# >> "uid"
|
||||||
|
@ -905,10 +939,13 @@ def diskDump():
|
||||||
bad = False
|
bad = False
|
||||||
with open(dump18, 'wb') as f:
|
with open(dump18, 'wb') as f:
|
||||||
for d in data:
|
for d in data:
|
||||||
if "--" in d[6:53]: bad = True
|
if "--" in d[6:53]:
|
||||||
|
bad = True
|
||||||
b = bytes.fromhex(d[6:53].replace(" ", "").replace("--", "FF"))
|
b = bytes.fromhex(d[6:53].replace(" ", "").replace("--", "FF"))
|
||||||
f.write(b)
|
f.write(b)
|
||||||
if bad: lprint(f"{prompt} Bad data exists, and has been saved as 0xFF")
|
if bad:
|
||||||
|
lprint(f"{prompt} Bad data exists, and has been saved as 0xFF")
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump MAD
|
# Dump MAD
|
||||||
|
@ -930,13 +967,14 @@ def dumpMad():
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
lprint("")
|
lprint("")
|
||||||
res = p.console(f"{cmd}")
|
p.console(f"{cmd}")
|
||||||
|
|
||||||
for line in p.grabbed_output.split('\n'):
|
for line in p.grabbed_output.split('\n'):
|
||||||
lprint(line)
|
lprint(line)
|
||||||
|
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
|
|
||||||
# ++============================================================================
|
# ++============================================================================
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue