mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
python script: wip, less globals, clearer dataflow
This commit is contained in:
parent
5e2b093b3e
commit
2293874402
1 changed files with 241 additions and 288 deletions
|
@ -56,104 +56,111 @@ except ModuleNotFoundError:
|
||||||
# Print and Log
|
# Print and Log
|
||||||
# >> "logfile"
|
# >> "logfile"
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def startlog(uid, append=False):
|
def initlog():
|
||||||
|
global logbuffer
|
||||||
global logfile
|
global logfile
|
||||||
|
logbuffer = ''
|
||||||
|
logfile = None
|
||||||
|
|
||||||
logfile = f"{dpath}hf-mf-{uid:08X}-log.txt"
|
|
||||||
|
def startlog(uid, dpath, append=False):
|
||||||
|
global logfile
|
||||||
|
global logbuffer
|
||||||
|
|
||||||
|
logfile = f"{dpath}hf-mf-{uid.hex().upper()}-log.txt"
|
||||||
if append is False:
|
if append is False:
|
||||||
with open(logfile, 'w'):
|
with open(logfile, 'w'):
|
||||||
pass
|
pass
|
||||||
|
if logbuffer != '':
|
||||||
|
with open(logfile, 'a') as f:
|
||||||
|
f.write(logbuffer)
|
||||||
|
logbuffer = ''
|
||||||
|
|
||||||
|
|
||||||
# +=========================================================
|
def lprint(s='', end='\n', flush=False, prompt="[=]", log=True):
|
||||||
def lprint(s, end='\n', flush=False):
|
|
||||||
|
s = f"{prompt} " + f"\n{prompt} ".join(s.split('\n'))
|
||||||
print(s, end=end, flush=flush)
|
print(s, end=end, flush=flush)
|
||||||
|
|
||||||
if logfile is not None:
|
if log is True:
|
||||||
with open(logfile, 'a') as f:
|
global logbuffer
|
||||||
f.write(s + end)
|
if logfile is not None:
|
||||||
|
with open(logfile, 'a') as f:
|
||||||
|
f.write(s + end)
|
||||||
|
else:
|
||||||
|
# buffering
|
||||||
|
logbuffer += s + end
|
||||||
|
|
||||||
|
|
||||||
# ++============================================================================
|
# ++============================================================================
|
||||||
# == MAIN ==
|
# == MAIN ==
|
||||||
# >> "prompt"
|
|
||||||
# >> p. [console handle]
|
# >> p. [console handle]
|
||||||
# >> "keyfile"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def main():
|
def main():
|
||||||
global prompt
|
|
||||||
global p
|
global p
|
||||||
|
|
||||||
prompt = "[=]"
|
|
||||||
p = pm3.pm3() # console interface
|
p = pm3.pm3() # console interface
|
||||||
|
initlog()
|
||||||
|
|
||||||
getPrefs()
|
|
||||||
if not checkVer():
|
if not checkVer():
|
||||||
return
|
return
|
||||||
parseCli()
|
dpath = getPrefs()
|
||||||
|
args = parseCli()
|
||||||
|
|
||||||
print(f"{prompt} Fudan FM11RF08[S] full card recovery")
|
# No logfile name yet
|
||||||
|
lprint("Fudan FM11RF08[S] full card recovery")
|
||||||
|
lprint(f"\nDump folder: {dpath}")
|
||||||
|
|
||||||
print(prompt)
|
bdkey, blk0 = getBackdoorKey()
|
||||||
print(f"{prompt} Dump folder: {dpath}")
|
if bdkey is None:
|
||||||
|
|
||||||
if not getDarkKey():
|
|
||||||
return
|
return
|
||||||
decodeBlock0()
|
uid = getUIDfromBlock0(blk0)
|
||||||
|
startlog(uid, dpath, append=False)
|
||||||
global keyfile
|
decodeBlock0(blk0)
|
||||||
global mad
|
|
||||||
|
|
||||||
mad = False
|
mad = False
|
||||||
keyfile = f"{dpath}hf-mf-{uid:08X}-key.bin"
|
keyfile = f"{dpath}hf-mf-{uid.hex().upper()}-key.bin"
|
||||||
keyok = False
|
|
||||||
|
|
||||||
if args.force is False and loadKeys() is True:
|
if args.force or (key := loadKeys(keyfile)) is None:
|
||||||
keyok = True
|
|
||||||
else:
|
|
||||||
if args.recover is False:
|
if args.recover is False:
|
||||||
lprint(f"{prompt} * Keys not loaded, use --recover to run recovery script [slow]")
|
lprint("* Keys not loaded, use --recover to run recovery script [slow]")
|
||||||
else:
|
else:
|
||||||
recoverKeys()
|
keyfile = recoverKeys()
|
||||||
if loadKeys() is True:
|
key = loadKeys(keyfile)
|
||||||
keyok = True
|
|
||||||
|
|
||||||
if keyok is True:
|
if key is not None:
|
||||||
if verifyKeys() is False:
|
ret, mad, key = verifyKeys(key)
|
||||||
|
if ret is False:
|
||||||
if args.nokeys is False:
|
if args.nokeys is False:
|
||||||
lprint(f"{prompt} ! Use --nokeys to keep going past this point")
|
lprint("! Use --nokeys to keep going past this point")
|
||||||
return
|
return
|
||||||
|
|
||||||
readBlocks()
|
data, blkn = readBlocks(bdkey)
|
||||||
patchKeys(keyok)
|
data = patchKeys(data, key)
|
||||||
|
|
||||||
diskDump() # save it before you do anything else
|
dump18 = diskDump(data, uid, dpath) # save it before you do anything else
|
||||||
|
|
||||||
dumpData()
|
dumpData(data, blkn)
|
||||||
dumpAcl()
|
dumpAcl(data)
|
||||||
|
|
||||||
if mad is True:
|
if mad is True:
|
||||||
dumpMad()
|
dumpMad(dump18)
|
||||||
|
|
||||||
if (args.bambu is True) or (detectBambu() is True):
|
if (args.bambu is True) or (detectBambu(data) is True):
|
||||||
dumpBambu()
|
dumpBambu(data)
|
||||||
|
|
||||||
lprint(prompt)
|
lprint("\nTadah!")
|
||||||
lprint(f"{prompt} Tadah!")
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Get PM3 preferences
|
# Get PM3 preferences
|
||||||
# >> "dpath"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def getPrefs():
|
def getPrefs():
|
||||||
global dpath
|
|
||||||
|
|
||||||
p.console("prefs show --json")
|
p.console("prefs show --json")
|
||||||
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
|
||||||
|
return dpath
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
|
@ -170,10 +177,8 @@ def checkVer():
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Parse the CLi arguments
|
# Parse the CLi arguments
|
||||||
# >> args.
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def parseCli():
|
def parseCli():
|
||||||
global args
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Full recovery of Fudan FM11RF08* cards.')
|
parser = argparse.ArgumentParser(description='Full recovery of Fudan FM11RF08* cards.')
|
||||||
|
|
||||||
|
@ -187,76 +192,73 @@ def parseCli():
|
||||||
|
|
||||||
if args.force is True:
|
if args.force is True:
|
||||||
args.recover = True
|
args.recover = True
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Find backdoor key
|
# Find backdoor key
|
||||||
# >> "dkey"
|
|
||||||
# >> "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 getBackdoorKey():
|
||||||
global dkey
|
|
||||||
global blk0
|
|
||||||
|
|
||||||
# FM11RF08S FM11RF08 FM11RF32
|
# FM11RF08S FM11RF08 FM11RF32
|
||||||
dklist = ["A396EFA4E24F", "A31667A8CEC1", "518b3354E760"]
|
dklist = ["A396EFA4E24F", "A31667A8CEC1", "518b3354E760"]
|
||||||
|
|
||||||
print(prompt)
|
lprint("\nTrying known backdoor keys...")
|
||||||
print(f"{prompt} Trying known backdoor keys...")
|
|
||||||
|
|
||||||
dkey = ""
|
bdkey = ""
|
||||||
for k in dklist:
|
for k in dklist:
|
||||||
cmd = f"hf mf rdbl -c 4 --key {k} --blk 0"
|
cmd = f"hf mf rdbl -c 4 --key {k} --blk 0"
|
||||||
print(f"{prompt} `{cmd}`", end='', flush=True)
|
lprint(f"\n`{cmd}`", end='', flush=True)
|
||||||
res = p.console(f"{cmd}")
|
res = p.console(f"{cmd}")
|
||||||
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:
|
||||||
blk0 = line[10:56+1]
|
blk0 = line[10:56+1]
|
||||||
if res == 0:
|
if res == 0:
|
||||||
print(" - success")
|
lprint(" - success", prompt='')
|
||||||
dkey = k
|
bdkey = k
|
||||||
break
|
break
|
||||||
print(f" - fail [{res}]")
|
lprint(f" - fail [{res}]", prompt='')
|
||||||
|
|
||||||
|
if bdkey == "":
|
||||||
|
lprint("\n! Unknown key, or card not detected.")
|
||||||
|
return None, None
|
||||||
|
lprint(f" Backdoor Key : {bdkey}") # show key
|
||||||
|
return bdkey, blk0
|
||||||
|
|
||||||
|
|
||||||
|
# +=============================================================================
|
||||||
|
# Extract UID from block 0
|
||||||
|
# ==============================================================================
|
||||||
|
def getUIDfromBlock0(blk0):
|
||||||
|
uids = blk0[0:11] # UID string : "11 22 33 44"
|
||||||
|
uid = bytes.fromhex(uids.replace(' ', '')) # UID (bytes) : 11223344
|
||||||
|
return uid
|
||||||
|
|
||||||
if dkey == "":
|
|
||||||
print(f"{prompt}")
|
|
||||||
print(f"{prompt} ! Unknown key, or card not detected.")
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Extract data from block 0
|
# Extract data from block 0
|
||||||
# >> "uid"
|
|
||||||
# >> "uids"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def decodeBlock0():
|
def decodeBlock0(blk0):
|
||||||
global uid
|
lprint("")
|
||||||
global uids
|
lprint(" UID BCC ++----- RF08 ID -----++")
|
||||||
|
lprint(" ! ! SAK !! !!")
|
||||||
# We do this early so we can name the logfile!
|
lprint(" ! ! ! ATQA !! Fudan Sig !!")
|
||||||
uids = blk0[0:11] # UID string : "11 22 33 44"
|
lprint(" !---------. !. !. !---. VV .---------------. VV")
|
||||||
uid = int(uids.replace(' ', ''), 16) # UID (value) : 0x11223344
|
|
||||||
startlog(uid, append=False)
|
|
||||||
|
|
||||||
lprint(prompt)
|
|
||||||
lprint(f"{prompt} UID BCC ++----- RF08 ID -----++")
|
|
||||||
lprint(f"{prompt} ! ! SAK !! !!")
|
|
||||||
lprint(f"{prompt} ! ! ! ATQA !! Fudan Sig !!")
|
|
||||||
lprint(f"{prompt} !---------. !. !. !---. VV .---------------. VV")
|
|
||||||
# 0 12 15 18 24 27 45
|
# 0 12 15 18 24 27 45
|
||||||
# ! ! ! ! ! ! !
|
# ! ! ! ! ! ! !
|
||||||
# 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
# 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
|
||||||
lprint(f"{prompt} Block 0 : {blk0}")
|
lprint(f" Block 0 : {blk0}")
|
||||||
|
|
||||||
# --- decode block 0 ---
|
# --- decode block 0 ---
|
||||||
|
|
||||||
|
uid = getUIDfromBlock0(blk0)
|
||||||
bcc = int(blk0[12:14], 16) # BCC
|
bcc = int(blk0[12:14], 16) # BCC
|
||||||
chk = 0 # calculate checksum
|
chk = 0 # calculate checksum
|
||||||
for h in uids.split():
|
for h in uid:
|
||||||
chk ^= int(h, 16)
|
chk ^= h
|
||||||
|
|
||||||
sak = int(blk0[15:17], 16) # SAK
|
sak = int(blk0[15:17], 16) # SAK
|
||||||
atqa = int(blk0[18:23].replace(' ', ''), 16) # 0x7788
|
atqa = int(blk0[18:23].replace(' ', ''), 16) # 0x7788
|
||||||
|
@ -284,93 +286,77 @@ def decodeBlock0():
|
||||||
|
|
||||||
# --- show results ---
|
# --- show results ---
|
||||||
|
|
||||||
lprint(prompt)
|
lprint()
|
||||||
|
|
||||||
lprint(f"{prompt} UID/BCC : {uid:08X}/{bcc:02X} - ", end='')
|
|
||||||
if bcc == chk:
|
if bcc == chk:
|
||||||
lprint("verified")
|
desc = "verified"
|
||||||
else:
|
else:
|
||||||
lprint(f"fail. Expected {chk:02X}")
|
desc = f"fail. Expected {chk:02X}"
|
||||||
|
lprint(f" UID/BCC : {uid.hex().upper()}/{bcc:02X} - {desc}")
|
||||||
|
|
||||||
lprint(f"{prompt} SAK : {sak:02X} - ", end='')
|
|
||||||
if sak == 0x01:
|
if sak == 0x01:
|
||||||
lprint("NXP MIFARE TNP3xxx 1K")
|
desc = "NXP MIFARE TNP3xxx 1K"
|
||||||
elif sak == 0x08:
|
elif sak == 0x08:
|
||||||
lprint("NXP MIFARE CLASSIC 1k | Plus 1k | Ev1 1K")
|
desc = "NXP MIFARE CLASSIC 1k | Plus 1k | Ev1 1K"
|
||||||
elif sak == 0x09:
|
elif sak == 0x09:
|
||||||
lprint("NXP MIFARE Mini 0.3k")
|
desc = "NXP MIFARE Mini 0.3k"
|
||||||
elif sak == 0x10:
|
elif sak == 0x10:
|
||||||
lprint("NXP MIFARE Plus 2k")
|
desc = "NXP MIFARE Plus 2k"
|
||||||
elif sak == 0x18:
|
elif sak == 0x18:
|
||||||
lprint("NXP MIFARE Classic 4k | Plus 4k | Ev1 4k")
|
desc = "NXP MIFARE Classic 4k | Plus 4k | Ev1 4k"
|
||||||
else:
|
else:
|
||||||
lprint("{unknown}")
|
desc = "{unknown}"
|
||||||
|
lprint(f" SAK : {sak:02X} - {desc}")
|
||||||
lprint(f"{prompt} ATQA : {atqa:04X}") # show ATQA
|
lprint(f" ATQA : {atqa:04X}") # show ATQA
|
||||||
lprint(f"{prompt} Fudan ID : {type}") # show type
|
lprint(f" Fudan ID : {type}") # show type
|
||||||
lprint(f"{prompt} Fudan Sig: {hash}") # show ?Partial HMAC?
|
lprint(f" Fudan Sig: {hash}") # show ?Partial HMAC?
|
||||||
lprint(f"{prompt} Dark Key : {dkey}") # show key
|
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Fudan validation
|
# Fudan validation
|
||||||
# >> "blk0"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def fudanValidate():
|
def fudanValidate(blk0, live=False):
|
||||||
# Warning, this import causes a "double free or corruption" crash if the script is called twice...
|
|
||||||
# So for now we limit the import only when really needed
|
|
||||||
import requests
|
|
||||||
global blk0
|
|
||||||
|
|
||||||
url = "https://rfid.fm-uivs.com/nfcTools/api/M1KeyRest"
|
url = "https://rfid.fm-uivs.com/nfcTools/api/M1KeyRest"
|
||||||
hdr = "Content-Type: application/text; charset=utf-8"
|
hdr = "Content-Type: application/text; charset=utf-8"
|
||||||
post = f"{blk0.replace(' ', '')}"
|
post = f"{blk0.replace(' ', '')}"
|
||||||
|
|
||||||
lprint(prompt)
|
lprint(f"\n Validator: `wget -q -O -"
|
||||||
lprint(f"{prompt} Validator: `wget -q -O -"
|
|
||||||
f" --header=\"{hdr}\""
|
f" --header=\"{hdr}\""
|
||||||
f" --post-data \"{post}\""
|
f" --post-data \"{post}\""
|
||||||
f" {url}"
|
f" {url}"
|
||||||
" | json_pp`")
|
" | json_pp`")
|
||||||
|
|
||||||
if args.validate:
|
if live:
|
||||||
lprint(prompt)
|
# Warning, this import causes a "double free or corruption" crash if the script is called twice...
|
||||||
lprint(f"{prompt} Check Fudan signature (requires internet)...")
|
# So for now we limit the import only when really needed
|
||||||
|
import requests
|
||||||
|
lprint("\nCheck Fudan signature (requires internet)...")
|
||||||
|
|
||||||
headers = {"Content-Type": "application/text; charset=utf-8"}
|
headers = {"Content-Type": "application/text; charset=utf-8"}
|
||||||
resp = requests.post(url, headers=headers, data=post)
|
resp = requests.post(url, headers=headers, data=post)
|
||||||
|
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
lprint(f"{prompt} HTTP Error {resp.status_code} - check request not processed")
|
lprint(f"HTTP Error {resp.status_code} - check request not processed")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
r = json.loads(resp.text)
|
r = json.loads(resp.text)
|
||||||
lprint(f"{prompt} The man from Fudan, he say: {r['code']} - {r['message']}", end='')
|
|
||||||
if r['data'] is not None:
|
if r['data'] is not None:
|
||||||
lprint(f" {{{r['data']}}}")
|
desc = f" {{{r['data']}}}"
|
||||||
else:
|
else:
|
||||||
lprint("")
|
desc = ""
|
||||||
|
lprint(f"The man from Fudan, he say: {r['code']} - {r['message']}{desc}")
|
||||||
else:
|
else:
|
||||||
lprint(prompt)
|
lprint("\n ...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"
|
|
||||||
# >> "key[17][2]"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
def loadKeys(keyfile):
|
||||||
|
|
||||||
def loadKeys():
|
|
||||||
global keyfile
|
|
||||||
global key
|
|
||||||
|
|
||||||
key = [[b'' 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(f"\nLoad Keys from file: |{keyfile}|")
|
||||||
lprint(f"{prompt} Load Keys from file: |{keyfile}|")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with (open(keyfile, "rb")) as fh:
|
with (open(keyfile, "rb")) as fh:
|
||||||
|
@ -379,25 +365,20 @@ def loadKeys():
|
||||||
key[sec][ab] = fh.read(6)
|
key[sec][ab] = fh.read(6)
|
||||||
|
|
||||||
except IOError:
|
except IOError:
|
||||||
return False
|
return None
|
||||||
|
|
||||||
return True
|
return key
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Run key recovery script
|
# Run key recovery script
|
||||||
# >> "keyfile"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def recoverKeys():
|
def recoverKeys():
|
||||||
global keyfile
|
|
||||||
|
|
||||||
badrk = 0 # 'bad recovered key' count (ie. not recovered)
|
badrk = 0 # 'bad recovered key' count (ie. not recovered)
|
||||||
|
|
||||||
lprint(prompt)
|
lprint("\nRunning recovery script, ETA: Less than 30 minutes")
|
||||||
lprint(f"{prompt} Running recovery script, ETA: Less than 30 minutes")
|
|
||||||
|
|
||||||
lprint(prompt)
|
lprint('\n`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
|
||||||
|
|
||||||
r = recovery(quiet=False)
|
r = recovery(quiet=False)
|
||||||
keyfile = r['keyfile']
|
keyfile = r['keyfile']
|
||||||
|
@ -405,38 +386,36 @@ def recoverKeys():
|
||||||
# fdump = r['dumpfile']
|
# fdump = r['dumpfile']
|
||||||
# rdata = r['data']
|
# rdata = r['data']
|
||||||
|
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
lprint('`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
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:
|
if badrk == 0:
|
||||||
lprint(f"{prompt} Some keys were not recovered: ", end='')
|
lprint("Some keys were not recovered: ", end='')
|
||||||
else:
|
else:
|
||||||
lprint(", ", end='')
|
lprint(", ", end='', prompt='')
|
||||||
badrk += 1
|
badrk += 1
|
||||||
|
|
||||||
kn = k
|
kn = k
|
||||||
if kn > 15:
|
if kn > 15:
|
||||||
kn += 16
|
kn += 16
|
||||||
lprint(f"[{kn}/", end='')
|
lprint(f"[{kn}/", end='', prompt='')
|
||||||
lprint("A]" if ab == 0 else "B]", end='')
|
lprint("A]" if ab == 0 else "B]", end='', prompt='')
|
||||||
if badrk > 0:
|
if badrk > 0:
|
||||||
lprint("")
|
lprint("")
|
||||||
|
return keyfile
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Verify keys
|
# Verify keys
|
||||||
# >> "key[][]"
|
|
||||||
# >> mad!
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def verifyKeys():
|
def verifyKeys(key):
|
||||||
global key
|
|
||||||
global mad
|
|
||||||
|
|
||||||
badk = 0
|
badk = 0
|
||||||
|
mad = False
|
||||||
|
|
||||||
lprint(f"{prompt} Check keys..")
|
lprint("Check keys..")
|
||||||
|
|
||||||
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
|
||||||
|
@ -449,14 +428,14 @@ def verifyKeys():
|
||||||
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" `{cmd}`", end='', flush=True)
|
||||||
|
|
||||||
res = p.console(f"{cmd}", capture=False)
|
res = p.console(f"{cmd}", capture=False)
|
||||||
lprint(" " * (3-len(str(bn))), end="")
|
lprint(" " * (3-len(str(bn))), end="", prompt='')
|
||||||
if res == 0:
|
if res == 0:
|
||||||
lprint(" ... PASS", end="")
|
lprint(" ... PASS", end="", prompt='')
|
||||||
else:
|
else:
|
||||||
lprint(" ... FAIL", end="")
|
lprint(" ... FAIL", end="", prompt='')
|
||||||
badk += 1
|
badk += 1
|
||||||
key[sec][ab] = b''
|
key[sec][ab] = b''
|
||||||
|
|
||||||
|
@ -464,36 +443,33 @@ def verifyKeys():
|
||||||
if (sec == 0) and (ab == 0) \
|
if (sec == 0) and (ab == 0) \
|
||||||
and (key[0][0] == b'\xa0\xa1\xa2\xa3\xa4\xa5'):
|
and (key[0][0] == b'\xa0\xa1\xa2\xa3\xa4\xa5'):
|
||||||
mad = True
|
mad = True
|
||||||
lprint(" - MAD Key")
|
lprint(" - MAD Key, prompt=''")
|
||||||
else:
|
else:
|
||||||
lprint("")
|
lprint("", prompt='')
|
||||||
|
|
||||||
if badk > 0:
|
if badk > 0:
|
||||||
lprint(f"{prompt} ! {badk} bad key", end='')
|
lprint(f"! {badk} bad key", end='')
|
||||||
lprint("s exist" if badk != 1 else " exists")
|
lprint("s exist" if badk != 1 else " exists")
|
||||||
rv = False
|
rv = False, mad, key
|
||||||
|
|
||||||
else:
|
else:
|
||||||
lprint(f"{prompt} All keys verified OK")
|
lprint("All keys verified OK")
|
||||||
rv = True
|
rv = True, mad, key
|
||||||
|
|
||||||
if mad is True:
|
if mad is True:
|
||||||
lprint(f"{prompt} MAD key detected")
|
lprint("MAD key detected")
|
||||||
|
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Read all block data - INCLUDING Dark blocks
|
# Read all block data - INCLUDING advanced verification blocks
|
||||||
# >> blkn
|
#
|
||||||
# >> "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(bdkey):
|
||||||
global data
|
|
||||||
global blkn
|
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
blkn = list(range(0, 63+1)) + list(range(128, 135+1))
|
blkn = list(range(0, 63+1)) + list(range(128, 135+1))
|
||||||
|
@ -502,15 +478,13 @@ def readBlocks():
|
||||||
# The vendor uses keyhole #2 (-b)
|
# The vendor uses keyhole #2 (-b)
|
||||||
# The thief uses keyhole #4 (backdoor)
|
# The thief uses keyhole #4 (backdoor)
|
||||||
# |___
|
# |___
|
||||||
rdbl = f"hf mf rdbl -c 4 --key {dkey} --blk"
|
|
||||||
|
|
||||||
lprint(prompt)
|
lprint("\n Load blocks {0..63, 128..135}[64+8=72] from the card")
|
||||||
lprint(prompt + " Load blocks {0..63, 128..135}[64+8=72] from the card")
|
|
||||||
|
|
||||||
bad = 0
|
bad = 0
|
||||||
for n in blkn:
|
for n in blkn:
|
||||||
cmd = f"{rdbl} {n}"
|
cmd = f"hf mf rdbl -c 4 --key {bdkey} --blk {n}"
|
||||||
print(f"\r{prompt} `{cmd}`", end='', flush=True)
|
lprint(f"`{cmd}`", flush=True, log=False)
|
||||||
|
|
||||||
for retry in range(5):
|
for retry in range(5):
|
||||||
p.console(f"{cmd}")
|
p.console(f"{cmd}")
|
||||||
|
@ -528,26 +502,21 @@ def readBlocks():
|
||||||
data.append(f"{n:3d} | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | ----------------")
|
data.append(f"{n:3d} | -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | ----------------")
|
||||||
bad += 1
|
bad += 1
|
||||||
|
|
||||||
print(" .. OK")
|
lprint(" .. OK", log=False)
|
||||||
|
return data, blkn
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Patch keys in to data
|
# Patch keys in to data
|
||||||
# >> "key[][]"
|
#
|
||||||
# >> "data[]"
|
|
||||||
# >> 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(data, key):
|
||||||
global key
|
lprint("\nPatch keys in to data")
|
||||||
global data
|
|
||||||
|
|
||||||
lprint(prompt)
|
|
||||||
lprint(f"{prompt} Patch keys in to data")
|
|
||||||
|
|
||||||
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 key is not None:
|
||||||
if key[sec][0] == b'':
|
if key[sec][0] == b'':
|
||||||
keyA = "-- -- -- -- -- -- "
|
keyA = "-- -- -- -- -- -- "
|
||||||
else:
|
else:
|
||||||
|
@ -564,22 +533,19 @@ def patchKeys(keyok):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
data[blk] = data[blk][:6] + "-- -- -- -- -- -- " + data[blk][24:36] + "-- -- -- -- -- --"
|
data[blk] = data[blk][:6] + "-- -- -- -- -- -- " + data[blk][24:36] + "-- -- -- -- -- --"
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump data
|
# Dump data
|
||||||
# >> blkn
|
|
||||||
# >> "data[]"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def dumpData():
|
def dumpData(data, blkn):
|
||||||
global blkn
|
|
||||||
global data
|
|
||||||
|
|
||||||
lprint(prompt)
|
lprint()
|
||||||
lprint(f"{prompt} ===========")
|
lprint("===========")
|
||||||
lprint(f"{prompt} Card Data")
|
lprint(" Card Data")
|
||||||
lprint(f"{prompt} ===========")
|
lprint("===========")
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
|
|
||||||
cnt = 0
|
cnt = 0
|
||||||
for n in blkn:
|
for n in blkn:
|
||||||
|
@ -588,19 +554,19 @@ def dumpData():
|
||||||
sec = sec + 16
|
sec = sec + 16
|
||||||
|
|
||||||
if (n % 4 == 0):
|
if (n % 4 == 0):
|
||||||
lprint(f"{prompt} {sec:2d}:{data[cnt]}")
|
lprint(f"{sec:2d}:{data[cnt]}")
|
||||||
else:
|
else:
|
||||||
lprint(f"{prompt} :{data[cnt]}")
|
lprint(f" :{data[cnt]}")
|
||||||
|
|
||||||
cnt += 1
|
cnt += 1
|
||||||
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()
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Let's try to detect a Bambu card by the date strings...
|
# Let's try to detect a Bambu card by the date strings...
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def detectBambu():
|
def detectBambu(data):
|
||||||
try:
|
try:
|
||||||
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]
|
||||||
|
@ -613,33 +579,31 @@ def detectBambu():
|
||||||
# yy y y m m d d h h m m
|
# yy y y m m d d h h m m
|
||||||
exp = r"20[2-3][0-9]_[0-1][0-9]_[0-3][0-9]_[0-2][0-9]_[0-5][0-9]"
|
exp = r"20[2-3][0-9]_[0-1][0-9]_[0-3][0-9]_[0-2][0-9]_[0-5][0-9]"
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
|
||||||
if re.search(exp, dl) and (ds == dls):
|
if re.search(exp, dl) and (ds == dls):
|
||||||
lprint(f"{prompt} Bambu date strings detected.")
|
lprint("\nBambu date strings detected.")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
lprint(f"{prompt} Bambu date strings not detected.")
|
lprint("\nBambu date strings not detected.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# 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[]"
|
#
|
||||||
# 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(data):
|
||||||
global data
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
lprint(f"{prompt} ===========")
|
lprint("===========")
|
||||||
lprint(f"{prompt} Bambu Tag")
|
lprint(" Bambu Tag")
|
||||||
lprint(f"{prompt} ===========")
|
lprint("===========")
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
lprint(f"{prompt} Decompose as Bambu tag .. ", end='')
|
lprint("Decompose as Bambu tag .. ", end='')
|
||||||
|
|
||||||
MaterialVariantIdentifier_s = bytes.fromhex(data[1][6:29]).decode('ascii').rstrip('\x00')
|
MaterialVariantIdentifier_s = bytes.fromhex(data[1][6:29]).decode('ascii').rstrip('\x00')
|
||||||
UniqueMaterialIdentifier_s = bytes.fromhex(data[1][30:53]).decode('ascii').rstrip('\x00') # [**] 8not16
|
UniqueMaterialIdentifier_s = bytes.fromhex(data[1][30:53]).decode('ascii').rstrip('\x00') # [**] 8not16
|
||||||
|
@ -693,49 +657,48 @@ def dumpBambu():
|
||||||
Hash.append(data[b][6:53])
|
Hash.append(data[b][6:53])
|
||||||
|
|
||||||
lprint("[offset:length]")
|
lprint("[offset:length]")
|
||||||
lprint(f"{prompt} Block 1:")
|
lprint(" Block 1:")
|
||||||
lprint(f"{prompt} [ 0: 8] MaterialVariantIdentifier_s = \"{MaterialVariantIdentifier_s}\"")
|
lprint(f" [ 0: 8] MaterialVariantIdentifier_s = \"{MaterialVariantIdentifier_s}\"")
|
||||||
lprint(f"{prompt} [ 8: 8] UniqueMaterialIdentifier_s = \"{UniqueMaterialIdentifier_s}\"")
|
lprint(f" [ 8: 8] UniqueMaterialIdentifier_s = \"{UniqueMaterialIdentifier_s}\"")
|
||||||
lprint(f"{prompt} Block 2:")
|
lprint(" Block 2:")
|
||||||
lprint(f"{prompt} [ 0:16] FilamentType_s = \"{FilamentType_s}\"")
|
lprint(f" [ 0:16] FilamentType_s = \"{FilamentType_s}\"")
|
||||||
lprint(f"{prompt} Block 4:")
|
lprint(" Block 4:")
|
||||||
lprint(f"{prompt} [ 0:16] DetailedFilamentType_s = \"{DetailedFilamentType_s}\"")
|
lprint(f" [ 0:16] DetailedFilamentType_s = \"{DetailedFilamentType_s}\"")
|
||||||
lprint(f"{prompt} Block 5:")
|
lprint(" Block 5:")
|
||||||
lprint(f"{prompt} [ 0: 4] Colour_rgba = 0x{Colour_rgba:08X}")
|
lprint(f" [ 0: 4] Colour_rgba = 0x{Colour_rgba:08X}")
|
||||||
lprint(f"{prompt} [ 4: 2] SpoolWeight_g = {SpoolWeight_g}g")
|
lprint(f" [ 4: 2] SpoolWeight_g = {SpoolWeight_g}g")
|
||||||
lprint(f"{prompt} [6: 2] Block5_7to8 = {{{Block5_7to8}}}")
|
lprint(f" [6: 2] Block5_7to8 = {{{Block5_7to8}}}")
|
||||||
lprint(f"{prompt} [ 8: 4] FilamentDiameter_mm = {FilamentDiameter_mm}mm")
|
lprint(f" [ 8: 4] FilamentDiameter_mm = {FilamentDiameter_mm}mm")
|
||||||
lprint(f"{prompt} [12: 4] Block5_12to15 = {{{Block5_12to15}}}")
|
lprint(f" [12: 4] Block5_12to15 = {{{Block5_12to15}}}")
|
||||||
lprint(f"{prompt} Block 6:")
|
lprint(" Block 6:")
|
||||||
lprint(f"{prompt} [ 0: 2] DryingTemperature_c = {DryingTemperature_c}^C")
|
lprint(f" [ 0: 2] DryingTemperature_c = {DryingTemperature_c}^C")
|
||||||
lprint(f"{prompt} [ 2: 2] DryingTime_h = {DryingTime_h}hrs")
|
lprint(f" [ 2: 2] DryingTime_h = {DryingTime_h}hrs")
|
||||||
lprint(f"{prompt} [ 4: 4] BedTemperatureType_q = {BedTemperatureType_q}")
|
lprint(f" [ 4: 4] BedTemperatureType_q = {BedTemperatureType_q}")
|
||||||
lprint(f"{prompt} [6: 2] BedTemperature_c = {BedTemperature_c}^C")
|
lprint(f" [6: 2] BedTemperature_c = {BedTemperature_c}^C")
|
||||||
lprint(f"{prompt} [ 8: 2] MaxTemperatureForHotend_c = {MaxTemperatureForHotend_c}^C")
|
lprint(f" [ 8: 2] MaxTemperatureForHotend_c = {MaxTemperatureForHotend_c}^C")
|
||||||
lprint(f"{prompt} [10: 2] MinTemperatureForHotend_c = {MinTemperatureForHotend_c}^C")
|
lprint(f" [10: 2] MinTemperatureForHotend_c = {MinTemperatureForHotend_c}^C")
|
||||||
lprint(f"{prompt} [12: 4] Block6_12to15 = {{{Block6_12to15}}}")
|
lprint(f" [12: 4] Block6_12to15 = {{{Block6_12to15}}}")
|
||||||
lprint(f"{prompt} Block 8:")
|
lprint(" Block 8:")
|
||||||
lprint(f"{prompt} [ 0:12] XCamInfo_x = {{{XCamInfo_x}}}")
|
lprint(f" [ 0:12] XCamInfo_x = {{{XCamInfo_x}}}")
|
||||||
lprint(f"{prompt} [12: 4] NozzleDiameter_q = {NozzleDiameter_q:.6f}__")
|
lprint(f" [12: 4] NozzleDiameter_q = {NozzleDiameter_q:.6f}__")
|
||||||
lprint(f"{prompt} Block 9:")
|
lprint(" Block 9:")
|
||||||
# lprint(f"{prompt} [ 0:16] TrayUID_s = \"{TrayUID_s}\"")
|
# lprint(f" [ 0:16] TrayUID_s = \"{TrayUID_s}\"")
|
||||||
lprint(f"{prompt} [ 0:16] TrayUID_s = {{{TrayUID_s}}} ; not ASCII")
|
lprint(f" [ 0:16] TrayUID_s = {{{TrayUID_s}}} ; not ASCII")
|
||||||
lprint(f"{prompt} Block 10:")
|
lprint(" Block 10:")
|
||||||
lprint(f"{prompt} [ 0: 4] Block10_0to3 = {{{Block10_0to3}}}")
|
lprint(f" [ 0: 4] Block10_0to3 = {{{Block10_0to3}}}")
|
||||||
lprint(f"{prompt} [ 4: 2] SppolWidth_um = {SppolWidth_um}um")
|
lprint(f" [ 4: 2] SppolWidth_um = {SppolWidth_um}um")
|
||||||
lprint(f"{prompt} [6:10] Block10_6to15 = {{{Block10_6to15}}}")
|
lprint(f" [6:10] Block10_6to15 = {{{Block10_6to15}}}")
|
||||||
lprint(f"{prompt} Block 12:")
|
lprint(" Block 12:")
|
||||||
lprint(f"{prompt} [ 0:16] ProductionDateTime_s = \"{ProductionDateTime_s}\"")
|
lprint(f" [ 0:16] ProductionDateTime_s = \"{ProductionDateTime_s}\"")
|
||||||
lprint(f"{prompt} Block 13:")
|
lprint(" Block 13:")
|
||||||
lprint(f"{prompt} [ 0:16] ShortProductionDateTime_s = \"{ShortProductionDateTime_s}\"")
|
lprint(f" [ 0:16] ShortProductionDateTime_s = \"{ShortProductionDateTime_s}\"")
|
||||||
lprint(f"{prompt} Block 14:")
|
lprint(" Block 14:")
|
||||||
lprint(f"{prompt} [ 0: 4] Block10_0to3 = {{{Block10_0to3}}}")
|
lprint(f" [ 0: 4] Block10_0to3 = {{{Block10_0to3}}}")
|
||||||
lprint(f"{prompt} [ 4: 2] FilamentLength_m = {FilamentLength_m}m")
|
lprint(f" [ 4: 2] FilamentLength_m = {FilamentLength_m}m")
|
||||||
lprint(f"{prompt} [6:10] Block10_6to15 = {{{Block10_6to15}}}")
|
lprint(f" [6:10] Block10_6to15 = {{{Block10_6to15}}}")
|
||||||
lprint(f"{prompt}")
|
lprint(f"\n Blocks {hblk}:")
|
||||||
lprint(f"{prompt} Blocks {hblk}:")
|
|
||||||
for i in range(0, len(hblk)):
|
for i in range(0, len(hblk)):
|
||||||
lprint(f"{prompt} [ 0:16] HashBlock[{i:2d}] = {{{Hash[i]}}} // #{hblk[i]:2d}")
|
lprint(f" [ 0:16] HashBlock[{i:2d}] = {{{Hash[i]}}} // #{hblk[i]:2d}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
lprint(f"Failed: {e}")
|
lprint(f"Failed: {e}")
|
||||||
|
@ -743,7 +706,7 @@ def dumpBambu():
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump ACL
|
# Dump ACL
|
||||||
# >> "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......
|
||||||
|
@ -824,17 +787,16 @@ def dumpBambu():
|
||||||
# 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(data):
|
||||||
global blkn
|
global blkn
|
||||||
|
|
||||||
aclkh = [] # key header
|
aclkh = [] # key header
|
||||||
aclk = [""] * 8 # key lookup
|
aclk = [""] * 8 # key lookup
|
||||||
aclkx = [] # key output
|
aclkx = [] # key output
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint("\n=====================")
|
||||||
lprint(f"{prompt} =====================")
|
lprint(" Access Control List")
|
||||||
lprint(f"{prompt} Access Control List")
|
lprint("=====================")
|
||||||
lprint(f"{prompt} =====================")
|
|
||||||
|
|
||||||
aclkh.append(" _______________________________________________________ ")
|
aclkh.append(" _______________________________________________________ ")
|
||||||
aclkh.append("| | Sector Trailers |")
|
aclkh.append("| | Sector Trailers |")
|
||||||
|
@ -872,7 +834,7 @@ def dumpAcl():
|
||||||
acld[6] = "| A+B ¦ KeyB || KeyB ¦ A+B | [110]" # noqa: E222
|
acld[6] = "| A+B ¦ KeyB || KeyB ¦ A+B | [110]" # noqa: E222
|
||||||
acld[7] = "| -- ¦ -- || -- ¦ -- | [111]" # noqa: E222
|
acld[7] = "| -- ¦ -- || -- ¦ -- | [111]" # noqa: E222
|
||||||
|
|
||||||
idx = [] * (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:
|
||||||
|
@ -905,39 +867,33 @@ def dumpAcl():
|
||||||
|
|
||||||
# --- print it all out ---
|
# --- print it all out ---
|
||||||
for line in aclkh:
|
for line in aclkh:
|
||||||
lprint(f"{prompt} {line}")
|
lprint(f" {line}")
|
||||||
i = 0
|
i = 0
|
||||||
for line in aclkx:
|
for line in aclkx:
|
||||||
lprint(f"{prompt} {line}")
|
lprint(f" {line}")
|
||||||
if (i % 4) == 3:
|
if (i % 4) == 3:
|
||||||
lprint(f"{prompt} | | ¦ || ¦ || ¦ |")
|
lprint(" | | ¦ || ¦ || ¦ |")
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
|
|
||||||
for line in acldh:
|
for line in acldh:
|
||||||
lprint(f"{prompt} {line}")
|
lprint(f" {line}")
|
||||||
i = 0
|
i = 0
|
||||||
for line in acldx:
|
for line in acldx:
|
||||||
lprint(f"{prompt} {line}")
|
lprint(f" {line}")
|
||||||
if (i % 3) == 2:
|
if (i % 3) == 2:
|
||||||
lprint(f"{prompt} | | ¦ || ¦ |")
|
lprint(" | | ¦ || ¦ |")
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Full Dump
|
# Full Dump
|
||||||
# >> "uid"
|
|
||||||
# >> "dump18"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def diskDump():
|
def diskDump(data, uid, dpath):
|
||||||
global uid
|
dump18 = f"{dpath}hf-mf-{uid.hex().upper()}-dump18.bin"
|
||||||
global dump18
|
|
||||||
|
|
||||||
dump18 = f"{dpath}hf-mf-{uid:08X}-dump18.bin"
|
lprint(f"\nDump Card Data to file: {dump18}")
|
||||||
|
|
||||||
lprint(prompt)
|
|
||||||
lprint(f"{prompt} Dump Card Data to file: {dump18}")
|
|
||||||
|
|
||||||
bad = False
|
bad = False
|
||||||
with open(dump18, 'wb') as f:
|
with open(dump18, 'wb') as f:
|
||||||
|
@ -947,35 +903,32 @@ def diskDump():
|
||||||
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:
|
if bad:
|
||||||
lprint(f"{prompt} Bad data exists, and has been saved as 0xFF")
|
lprint("Bad data exists, and has been saved as 0xFF")
|
||||||
|
return dump18
|
||||||
|
|
||||||
|
|
||||||
# +=============================================================================
|
# +=============================================================================
|
||||||
# Dump MAD
|
# Dump MAD
|
||||||
# >> "dump18"
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
def dumpMad():
|
def dumpMad(dump18):
|
||||||
global dump18
|
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
lprint(f"{prompt} ====================================")
|
lprint("====================================")
|
||||||
lprint(f"{prompt} MiFare Application Directory (MAD)")
|
lprint(" MiFare Application Directory (MAD)")
|
||||||
lprint(f"{prompt} ====================================")
|
lprint("====================================")
|
||||||
lprint(f"{prompt}")
|
lprint()
|
||||||
|
|
||||||
cmd = f"hf mf mad --verbose --file {dump18}"
|
cmd = f"hf mf mad --verbose --file {dump18}"
|
||||||
print(f"{prompt} `{cmd}`")
|
lprint(f"`{cmd}`", log=False)
|
||||||
|
|
||||||
lprint(f"{prompt}")
|
lprint('\n`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,\n')
|
||||||
lprint(f'{prompt} `-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
|
||||||
|
|
||||||
lprint("")
|
|
||||||
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('`-._,-\'"`-._,-"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,-\'"`-._,')
|
||||||
|
|
||||||
|
|
||||||
# ++============================================================================
|
# ++============================================================================
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue