Skip to content

Conversation

@whywilson
Copy link
Owner

  1. hf mf restore to write dump to tag
  2. hf mfu eRead to load dump from PN532Killer reader

@whywilson whywilson requested a review from Copilot August 1, 2025 10:27
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds two new features for Mifare Classic and Ultralight cards: a restore function to write dump files to physical tags, and an eRead function to extract dumps from PN532Killer emulator slots. The changes also introduce proper enum types for device modes and tag types to improve code maintainability.

  • Adds hf mf restore command to write dump files (.mfd/.bin) to Mifare Classic cards with support for different generations
  • Adds hf mfu eRead command to extract Mifare Ultralight dumps from emulator slots with JSON/binary output options
  • Introduces PN532KillerMode and PN532KillerTagType enums to replace magic numbers in device communication

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
script/pn532_enum.py Adds new command entries and enum types for device modes and tag types
script/pn532_com.py Updates set_work_mode method to use new enum types with proper type hints
script/pn532_cmd.py Implements hf_mfu_eread function for reading Ultralight dumps from emulator
script/pn532_cli_unit.py Adds HfMfRestore and HfMfuEread command classes with extensive duplicate code
script/pn532killer_mf1_emulator.py Updates to use new enum constants instead of magic numbers

def set_work_mode(self, mode: PN532KillerMode = PN532KillerMode.READER, type=PN532KillerTagType.MFC, index=0) -> response:
response = self.send_cmd_sync(
Pn532KillerCommand.SetWorkMode, [mode, type, index]
Pn532KillerCommand.SetWorkMode, [mode.value, type, index]
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type parameter should use .value to access the enum value, similar to how mode is handled. Currently type is being passed directly which may cause issues if an enum is passed.

Suggested change
Pn532KillerCommand.SetWorkMode, [mode.value, type, index]
Pn532KillerCommand.SetWorkMode, [mode.value, type.value, index]

Copilot uses AI. Check for mistakes.
Comment on lines 2543 to 2568
# 读取dump文件
dump_data = {}
if args.f.endswith('.mfd'):
with open(args.f, 'r') as f:
for line in f:
if ':' in line:
block_num, data = line.strip().split(':')
dump_data[int(block_num)] = data.strip()
elif args.f.endswith('.bin'):
with open(args.f, 'rb') as f:
data = f.read()
if len(data) != 1024: # 1KB
print(f"{CR}Error: Bin file must be 1KB{C0}")
return
for i in range(64): # 64 blocks
dump_data[i] = data[i*16:(i+1)*16].hex()
else:
print(f"{CR}Error: Unsupported file format{C0}")
return

# 扫描卡片
resp = self.cmd.hf_14a_scan()
if resp is None:
print("No tag found")
return

Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire block of code (lines 2543-2679) appears to be duplicated from the HfMfRestore class. This creates significant code duplication that should be extracted into a shared method.

Suggested change
# 读取dump文件
dump_data = {}
if args.f.endswith('.mfd'):
with open(args.f, 'r') as f:
for line in f:
if ':' in line:
block_num, data = line.strip().split(':')
dump_data[int(block_num)] = data.strip()
elif args.f.endswith('.bin'):
with open(args.f, 'rb') as f:
data = f.read()
if len(data) != 1024: # 1KB
print(f"{CR}Error: Bin file must be 1KB{C0}")
return
for i in range(64): # 64 blocks
dump_data[i] = data[i*16:(i+1)*16].hex()
else:
print(f"{CR}Error: Unsupported file format{C0}")
return
# 扫描卡片
resp = self.cmd.hf_14a_scan()
if resp is None:
print("No tag found")
return
# Process dump file and scan card
dump_data, resp = self.process_dump_and_scan(args.f, args.k)
if dump_data is None or resp is None:
return

Copilot uses AI. Check for mistakes.
def on_exec(self, args: argparse.Namespace):
self.cmd.ntag_reader()
self.cmd.ntag_reader()
# 读取dump文件
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chinese comments should be translated to English to maintain consistency with the rest of the codebase. This comment means 'Read dump file'.

Suggested change
# 读取dump文件
# Read dump file

Copilot uses AI. Check for mistakes.
print(f"{CR}Tag is not Gen3{C0}")
return
print("Found Gen3 Tag")
# 设置UID
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chinese comment should be translated to English. This comment means 'Set UID'.

Suggested change
# 设置UID
# Set UID

Copilot uses AI. Check for mistakes.
# 设置UID
resp1 = self.cmd.setGen3Uid(uid)
print(f"Set UID to {uid.hex().upper()}: {CG}Success{C0}" if resp1 else f"Set UID to {uid.hex().upper()}: {CR}Failed{C0}")
# 设置block0
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chinese comment should be translated to English. This comment means 'Set block0'.

Suggested change
# 设置block0
# Set block0

Copilot uses AI. Check for mistakes.
# 设置block0
resp2 = self.cmd.setGen3Block0(bytes.fromhex(dump_data[0]))
print(f"Set block0: {CG}Success{C0}" if resp2 else f"Set block0: {CR}Failed{C0}")
# 写入其他block
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chinese comment should be translated to English. This comment means 'Write other blocks'.

Suggested change
# 写入其他block
# Write other blocks

Copilot uses AI. Check for mistakes.

def on_exec(self, args: argparse.Namespace):
self.cmd.ntag_reader()
self.cmd.ntag_reader()
Copy link

Copilot AI Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line appears to be orphaned code that doesn't belong in this context. The ntag_reader() call seems unrelated to the dump file processing logic that follows.

Suggested change
self.cmd.ntag_reader()

Copilot uses AI. Check for mistakes.
@whywilson whywilson merged commit ad11a40 into main Aug 8, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants