amiibo update

This commit is contained in:
FalsePhilosopher 2022-06-30 12:19:00 -06:00
parent f321f082bb
commit 916b7b167a
5 changed files with 247 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,24 @@
# AmiiboFlipperConverter https://github.com/Lucaslhm/AmiiboFlipperConverter
Converts Amiibo .bins to a flipper compatible format
Simply run `amiiboconvert.py` from the root directory to generate all amiibos within `raw_amiibos` to `nfcs`
You can target a specific file by appending a path to the end of the call as such that `amiiboconvert.py *path to file*`
You can target a directory full of amiibos by passing a path such that `amiiboconvert.py *path to directory*`
You can also use the amiibos i've generated already.
The original code was created in the Flipper Discord by Friendartiste
The code was modified to run itteratively by Lamp
I, VapidAnt, have modified the code to work in a variety of situations with a recursive function and have uploaded to github
I believe this will make it easy to modify the code in the future and track changes over time.
If you have problems, please make an issue or ping me in the flipper discord.
Feel free to itterate off this and make pull requests.
Happy Flipping!

View File

@ -0,0 +1,223 @@
"""
amiiboconvert.py
3/12/2022
Modified Amiibo Flipper Conversion Code
Original Code by Friendartiste
Modified by Lamp
Modified again by VapidAnt
Modified and commented by bjschafer
Execute with python amiiboconvert -h to see options
"""
import argparse
import logging
import os
import pathlib
from typing import Tuple
def write_output(name: str, assemble: str, out_dir: str):
"""
Handles writing the converted file
:param name: The base filename - e.g. for Foo.bin, Foo
:param assemble: The converted flipper-compatible contents
:param out_dir: The directory to place Foo.nfc in
"""
with open(os.path.join(out_dir, f"{name}.nfc"), "wt") as f:
f.write(assemble)
def convert(contents: bytes) -> Tuple[str, int]:
"""
Convert from bytes into the Page-based format expected by flipper
Each "Page" is 4 bytes hex, notated like:
Page 0: DE AD BE EF
To process, we grab one byte at a time, turn it into a hex string, and store it in `page`.
When page is "full" (has 4 bytes in it), we flush it to the buffer.
When all's said and done, buffer contains text ready for writing to the end of a .nfc file.
Also tracks and returns running page number, since that's also needed.
:param contents: byte array we're reading, from a .bin file
:return: The full string of Pages, suitable for writing to a file
"""
buffer = []
page_count = 0
page = []
for i in range(len(contents) - 1):
byte = contents[i : i + 1].hex()
page.append(byte)
if len(page) == 4:
buffer.append(f"Page {page_count}: {' '.join(page).upper()}")
page = []
page_count += 1
# we may have an unfilled page. This needs to be filled out and appended
logging.debug(f"We have an unfilled final page: {page} with length {len(page)}")
if len(page) > 0:
# pad with zeroes
for i in range(len(page) - 1, 3):
page.append("00")
buffer.append(f"Page {page_count}: {' '.join(page).upper()}")
page_count += 1
return "\n".join(buffer), page_count
def get_uid(contents: bytes) -> str:
"""
the UID appears to be made up of the first 3 bytes, a byte is skipped, and then the next 4 bytes
:param contents: The bytes object we're operating on
:return: something like `23 20 41 6D 69 69 62 6F`
"""
page = []
for i in range(3):
byte = contents[i : i + 1].hex()
page.append(byte)
for i in range(4, 8):
byte = contents[i : i + 1].hex()
page.append(byte)
return " ".join(page).upper()
def assemble_code(contents: {hex}) -> str:
"""
Convert from .bin files to Flipper text-like .nfc files
:param contents: File contents upon which .hex() can be called
:return: A string to be written to a file
"""
conversion, page_count = convert(contents)
return f"""Filetype: Flipper NFC device
Version: 2
# Nfc device type can be UID, Mifare Ultralight, Bank card
Device type: NTAG215
# UID, ATQA and SAK are common for all formats
UID: {get_uid(contents)}
ATQA: 44 00
SAK: 00
# Mifare Ultralight specific data
Signature: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Mifare version: 00 04 04 02 01 00 11 03
Counter 0: 0
Tearing 0: 00
Counter 1: 0
Tearing 1: 00
Counter 2: 0
Tearing 2: 00
Pages total: {page_count}
{conversion}
"""
def convert_file(input_path: str, output_path: str):
"""
Handles reading, converting, and writing a single file
:param input_path: The full path to the .bin file
:param output_path: The base directory to output to
"""
input_extension = os.path.splitext(input_path)[1]
if input_extension == ".bin":
logging.info(f"Writing: {input_path}")
with open(input_path, "rb") as file:
contents = file.read()
name = os.path.split(input_path)[1]
write_output(name.split(".bin")[0], assemble_code(contents), output_path)
elif input_extension == ".nfc":
logging.warning(f"Seems like {input_path} may already be Flipper-compatible!")
else:
logging.info(f"{input_path} doesn't seem like a relevant file, skipping")
def process(path: str, output_path: str):
"""
Process an input file, or walk through an input directory and process every matching .bin file therein
:param path: Path to a single file or a directory containing one or more .bin files
:param output_path: The base directory to output to
"""
if os.path.isfile(path):
convert_file(path, output_path)
else:
for filename in os.listdir(path):
new_path = os.path.join(path, filename)
logging.debug(f"Current file: {filename}; Current path: {new_path}")
if os.path.isfile(path):
convert_file(path, output_path)
else:
logging.debug(f"Recursing into: {new_path}")
process(new_path, output_path)
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-i",
"--input-path",
required=True,
type=pathlib.Path,
help="Single file or directory tree to convert",
)
parser.add_argument(
"-o",
"--output-path",
required=False,
type=pathlib.Path,
help="Directory to store output in. Will be created if it doesn't exist. If not specified, the output will be "
"stored in the same location as the original, with a '.nfc' extension.",
)
parser.add_argument(
"-v",
"--verbose",
action="count",
default=0,
help="Show extra info: pass -v to see what's going on, pass -vv to get useful debug info",
)
args = parser.parse_args()
if args.verbose >= 2:
# set debug
logging.basicConfig(level=logging.DEBUG)
elif args.verbose >= 1:
# set info
logging.basicConfig(level=logging.INFO)
logging.debug(f"Parsed args into {args}")
return args
def main():
args = get_args()
# single file mode
if os.path.isfile(args.input_path):
if not args.output_path:
args.output_path = os.path.split(args.input_path)[0]
# recursive directory mode
elif os.path.isdir(args.input_path):
if not args.output_path:
logging.exception(
ValueError(
f"{args.input_path} is a directory, but no output path given."
)
)
elif not os.path.exists(args.input_path):
logging.exception(
FileNotFoundError(f"{args.input_path} doesn't actually exist")
)
logging.debug(f"Going to create output directory {args.output_path}")
os.makedirs(args.output_path, exist_ok=True)
logging.debug(f"input: {args.input_path}, output: {args.output_path}")
process(args.input_path, args.output_path)
if __name__ == "__main__":
main()
print("----Good Execution----")

Binary file not shown.