-
Notifications
You must be signed in to change notification settings - Fork 8
New Features on Mifare Classic and Ultralight #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
whywilson
commented
Aug 1, 2025
- hf mf restore to write dump to tag
- hf mfu eRead to load dump from PN532Killer reader
There was a problem hiding this 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 restorecommand to write dump files (.mfd/.bin) to Mifare Classic cards with support for different generations - Adds
hf mfu eReadcommand to extract Mifare Ultralight dumps from emulator slots with JSON/binary output options - Introduces
PN532KillerModeandPN532KillerTagTypeenums 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] |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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.
| Pn532KillerCommand.SetWorkMode, [mode.value, type, index] | |
| Pn532KillerCommand.SetWorkMode, [mode.value, type.value, index] |
script/pn532_cli_unit.py
Outdated
| # 读取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 | ||
|
|
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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.
| # 读取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 |
script/pn532_cli_unit.py
Outdated
| def on_exec(self, args: argparse.Namespace): | ||
| self.cmd.ntag_reader() | ||
| self.cmd.ntag_reader() | ||
| # 读取dump文件 |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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'.
| # 读取dump文件 | |
| # Read dump file |
script/pn532_cli_unit.py
Outdated
| print(f"{CR}Tag is not Gen3{C0}") | ||
| return | ||
| print("Found Gen3 Tag") | ||
| # 设置UID |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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'.
| # 设置UID | |
| # Set UID |
script/pn532_cli_unit.py
Outdated
| # 设置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 |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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'.
| # 设置block0 | |
| # Set block0 |
script/pn532_cli_unit.py
Outdated
| # 设置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 |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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'.
| # 写入其他block | |
| # Write other blocks |
|
|
||
| def on_exec(self, args: argparse.Namespace): | ||
| self.cmd.ntag_reader() | ||
| self.cmd.ntag_reader() |
Copilot
AI
Aug 1, 2025
There was a problem hiding this comment.
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.
| self.cmd.ntag_reader() |