diff --git a/CHANGELOG.md b/CHANGELOG.md index 9694529ce..73db91565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] - Added python3 script to convert amiibo nfc Flipper Zero files to eml files to be used with Proxmark3 (@OscarAkaElvis) + - Changed `hf mf restore` - Auth both key A and key B with default password (@wh201906) - Changed `nfc decode -f` - now can detect and convert MFC dumpfiles to NDEF byte arrays (@iceman1001) - Changed `nfc decode` - now handles EXTERNAL RECORDS better (@iceman1001) - Fixed `nfc decode` - now handles NDEF Signature version1 records better (@iceman1001) @@ -62,6 +63,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Update documentation for installation on macOS with MacPorts (@linuxgemini) - Added possible Paxton id to hitag2 tag info output - Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147) + - Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index f5730f14b..90a667105 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -655,6 +655,7 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen = 0; if (bPwd && (bAuthenticating == false) && write) { + SpinDelay(2); if (hitag2_write_page(rx, rxlen, tx, txlen) == false) { return false; } diff --git a/client/lualibs/amiibo_tools.lua b/client/lualibs/amiibo_tools.lua index b4c3f3bbf..e5838ebef 100644 --- a/client/lualibs/amiibo_tools.lua +++ b/client/lualibs/amiibo_tools.lua @@ -55,6 +55,9 @@ amiibo_tools.db = ["0x00000003039bff02"] = { name = "Mario - Power Up Band" }, + ["0x000000030430ff02"] = { + name = "Golden - Power Up Band" + }, ["0x0000010000190002"] = { name = "Dr. Mario" }, @@ -214,6 +217,9 @@ amiibo_tools.db = ["0x0100000003990902"] = { name = "Link - Link's Awakening" }, + ["0x0100000004180902"] = { + name = "Link - Tears of the Kingdom" + }, ["0x0100010000160002"] = { name = "Toon Link" }, @@ -1834,6 +1840,9 @@ amiibo_tools.db = ["0x0800010003820002"] = { name = "Inkling" }, + ["0x0800010004150402"] = { + name = "Inkling - Yellow" + }, ["0x08000200003f0402"] = { name = "Inkling Boy" }, @@ -1870,9 +1879,15 @@ amiibo_tools.db = ["0x08050200038f0402"] = { name = "Octoling Boy" }, + ["0x08050200041b0402"] = { + name = "Octoling - Blue" + }, ["0x0805030003900402"] = { name = "Octoling Octopus" }, + ["0x08060100041c0402"] = { + name = "Smallfry" + }, ["0x09c0010102690e02"] = { name = "Mario - Soccer" }, @@ -2374,6 +2389,9 @@ amiibo_tools.db = ["0x3380000003781402"] = { name = "Solaire of Astora" }, + ["0x33c0000004200002"] = { + name = "Kazuya" + }, ["0x3480000000310002"] = { name = "Mega Man" }, @@ -2455,6 +2473,9 @@ amiibo_tools.db = ["0x3600010003620002"] = { name = "Cloud - Player 2" }, + ["0x3601000004210002"] = { + name = "Sephiroth" + }, ["0x3640000003a20002"] = { name = "Hero" }, @@ -2520,6 +2541,12 @@ amiibo_tools.db = }, ["0x3c80000003a40002"] = { name = "Terry" + }, + ["0x3dc0000004220002"] = { + name = "Steve" + }, + ["0x3dc1000004230002"] = { + name = "Alex" } }, game_series = { @@ -2621,6 +2648,7 @@ amiibo_tools.db = ["0x324"] = "Bayonetta", ["0x334"] = "Pac-man", ["0x338"] = "Dark Souls", + ["0x33c"] = "Tekken", ["0x348"] = "Megaman", ["0x34c"] = "Street fighter", ["0x350"] = "Monster Hunter", @@ -2635,7 +2663,8 @@ amiibo_tools.db = ["0x38c"] = "Diablo", ["0x3a0"] = "Persona", ["0x3b4"] = "Banjo Kazooie", - ["0x3c8"] = "Fatal Fury" + ["0x3c8"] = "Fatal Fury", + ["0x3dc"] = "Minecraft" }, types = { ["0x00"] = "Figure", diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 559057459..8f39ca3e8 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -1109,7 +1109,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { "Restore MIFARE Classic dump file to tag.\n" "\n" "The key file and dump file will program the card sector trailers.\n" - "By default we authenticate to card with key B 0xFFFFFFFFFFFF.\n" + "By default we authenticate to card with key 0xFFFFFFFFFFFF.\n" "If access rights in dump file is all zeros, it will be replaced with default values\n" "\n" "`--uid` param is used for filename templates `hf-mf--dump.bin` and `hf-mf--key.bin.\n" @@ -1321,56 +1321,37 @@ static int CmdHF14AMfRestore(const char *Cmd) { uint8_t wdata[26]; memcpy(wdata + 10, bldata, sizeof(bldata)); - if (use_keyfile_for_auth) { - for (int8_t kt = MF_KEY_B; kt > -1; kt--) { - + for (int8_t kt = MF_KEY_B; kt > -1; kt--) { + if (use_keyfile_for_auth) { if (kt == MF_KEY_A) memcpy(wdata, keyA[s], 6); else memcpy(wdata, keyB[s], 6); - - PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata))); - - clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - uint8_t isOK = resp.oldarg[0] & 0xff; - if (isOK == 0) { - if (b == 0) { - PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B'); - } else { - PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B'); - } - } else { - // if success, skip to next block - break; - } - } else { - PrintAndLogEx(WARNING, "Command execute timeout"); - } + } else { + // use default key to authenticate for the write command + memcpy(wdata, default_key, 6); } - } else { - // use default key to authenticate for the write command - memcpy(wdata, default_key, 6); PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata))); clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, MF_KEY_B, 0, wdata, sizeof(wdata)); + SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata)); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.oldarg[0] & 0xff; if (isOK == 0) { if (b == 0) { - PrintAndLogEx(INFO, "Writing to manufacture block w key B ( " _RED_("fail") " )"); + PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B'); } else { - PrintAndLogEx(FAILED, "Write to block %u w key B ( " _RED_("fail") " )", b); + PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B'); } + } else { + // if success, skip to next block + break; } } else { PrintAndLogEx(WARNING, "Command execute timeout"); } - } // end use_keyfile_for_auth + } } // end loop B } // end loop S diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index e47a60e7c..f720d8599 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -2690,7 +2690,7 @@ static void wait4response(uint8_t b) { int CmdHF14MfUTamper(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfu tamper", - "Set the congiguration of the NTAG 213TT tamper feature\n" + "Set the configuration of the NTAG 213TT tamper feature\n" "Supports:\n" "NTAG 213TT\n", "hf mfu tamper -e -> enable tamper feature\n" @@ -4697,7 +4697,7 @@ static command_t CommandTable[] = { {"restore", CmdHF14AMfURestore, IfPm3Iso14443a, "Restore a dump onto a MFU MAGIC tag"}, {"view", CmdHF14AMfuView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdHF14AMfUWrBl, IfPm3Iso14443a, "Write block"}, - {"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Cofigure the tamper feature on an NTAG 213TT"}, + {"tamper", CmdHF14MfUTamper, IfPm3Iso14443a, "Configure the tamper feature on an NTAG 213TT"}, {"---------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"eload", CmdHF14AMfUeLoad, IfPm3Iso14443a, "Load Ultralight dump file into emulator memory"}, {"esave", CmdHF14AMfuESave, IfPm3Iso14443a, "Save Ultralight dump file from emulator memory"}, diff --git a/client/update_amiibo_tools_lua.py b/client/update_amiibo_tools_lua.py new file mode 100644 index 000000000..873a6e18d --- /dev/null +++ b/client/update_amiibo_tools_lua.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 + +""" +----------------------------------------------------------------------------- +Name: update_amiibo_tools_lua.py + +Author: Cory Solovewicz + +Description: +This is a python script to automate what the updating of the amiibo_tools.lua +file which holds a lua table of all known amiibos. Previously updating the +amiibo_tools.lua was a very manual process. + +This script automates the following original command: +curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq 'del(.amiibos[].release)' | jq 'del(.characters)' | pbcopy --> transform to table +And outputs the formatted file as amiibo_tools.lua +If everything goes well, this should be an updated copy of amiibo_tools.lua +which can then be placed in the /lualibs/ directory. +The temporary amiibo.json file is then deleted + +Dependencies: +python3 -m pip install jq + +How to run: +python update_amiibo_tools_lua.py +The script will create the file amiibo_tools.lua + +After running, manually backup the original /lualibs/amiibo_tools.lua and move the +updated amiibo_tools.lua to the /lualibs/ directory. +----------------------------------------------------------------------------- +""" + +import os +import re +import subprocess +import json +from jq import jq + +def fetch_data(): + print("Fetching amiibo.json") + # Perform the curl command + curl_command = "curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json" + curl_process = subprocess.Popen(curl_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, error = curl_process.communicate() + + if curl_process.returncode != 0: + print("Error fetching data: ", error.decode()) + return None + return output + +def filter_data(data): + print("Filtering downloaded data") + # Convert the output to JSON and use jq to filter data + data_json = json.loads(data) + filtered_data_json = jq('del(.amiibos[].release) | del(.characters)').transform(data_json) + # Convert the filtered JSON data back to a string, preserving Unicode characters + filtered_data = json.dumps(filtered_data_json, indent=2, ensure_ascii=False) + return filtered_data + +def save_data(filtered_data, filename): + # Save filtered data to file + with open(filename, 'w', encoding='utf-8') as file: + file.write(filtered_data) + print(f"Data saved to {filename}") + +def process_file(filename): + # Open the file + with open(filename, 'r', encoding='utf-8') as file: + data = file.read() + + # Perform the replacements + data = data.replace('"name"', 'name') + data = data.replace('"amiibo_series"', 'amiibo_series') + data = data.replace('"amiibos"', 'amiibos') + data = data.replace('"game_series"', 'game_series') + data = data.replace('"types"', 'types') + data = data.replace(':', ' =') + data = re.sub('"0x', '["0x', data) + data = re.sub('" =', '"] =', data) + + # Prepend the text + prepend_text = 'local amiibo_tools = {}\n\n-- curl https://raw.githubusercontent.com/N3evin/AmiiboAPI/master/database/amiibo.json | jq \'del(.amiibos[].release)\' | jq \'del(.characters)\' | pbcopy --> transform to table\namiibo_tools.db =\n' + data = prepend_text + data + + # Append the text + append_text = '\n\nreturn amiibo_tools\n' + data = data + append_text + + return data + +def write_to_file(data, filename): + # Write the output + with open(filename, 'w', encoding='utf-8') as file: + file.write(data) + print(f"Output written to {filename}") + +def delete_file(filename): + try: + os.remove(filename) + print(f"Temporary file {filename} deleted") + except OSError as e: + print(f"Error deleting file {filename}: ", e) + +def main(): + data = fetch_data() + if data: + filtered_data = filter_data(data) + save_data(filtered_data, 'amiibo.json') + processed_data = process_file('amiibo.json') + write_to_file(processed_data, 'amiibo_tools.lua') + delete_file('amiibo.json') + +if __name__ == "__main__": + main()