New cmd added.

This commit is contained in:
dxl
2022-12-23 22:03:05 +08:00
parent 7dfebd37ab
commit 5817d3f778
4 changed files with 355 additions and 22 deletions
+10 -2
View File
@@ -55,9 +55,10 @@ class ChameleonCLI:
'help': "Device mode get/set"
},
'slot': {
'set': new_uint(chameleon_cli_unit.HWSlotSet, "Set emulation tag slot activated."),
'change': new_uint(chameleon_cli_unit.HWSlotSet, "Set emulation tag slot activated."),
'type': new_uint(chameleon_cli_unit.HWSlotTagType, "Set emulation tag type"),
'init': new_uint(chameleon_cli_unit.HWSlotDataDefault, "Set emulation tag data to default"),
'enable': new_uint(chameleon_cli_unit.HWSlotEnableSet, "Set emulation tag slot enable or disable"),
'help': "Emulation tag slot.",
},
'help': "hardware controller",
@@ -73,6 +74,12 @@ class ChameleonCLI:
'darkside': new_uint(chameleon_cli_unit.HFMFDarkside, "Mifare Classic darkside recover key"),
'rdbl': new_uint(chameleon_cli_unit.HFMFRDBL, "MiFARE Classic read one block"),
'wrbl': new_uint(chameleon_cli_unit.HFMFWRBL, "MiFARE Classic write one block"),
'detection': {
'enable': new_uint(chameleon_cli_unit.HFMFDetectionEnable, "Detection enable"),
'count': new_uint(chameleon_cli_unit.HFMFDetectionLogCount, "Detection log count"),
'decrypt': new_uint(chameleon_cli_unit.HFMFDetectionDecrypt, "Download log and decrypt keys"),
'help': "Mifare Classic detection log"
},
'help': "Mifare Classic mini/1/2/4, attack/read/write"
},
'help': "high frequency tag/reader",
@@ -81,7 +88,8 @@ class ChameleonCLI:
'em': {
'read': new_uint(chameleon_cli_unit.LFEMRead, "Scan em410x tag and print id"),
'write': new_uint(chameleon_cli_unit.LFEMWriteT55xx, "Write em410x id to t55xx"),
'help': "EM410x read/write",
'sim': new_uint(chameleon_cli_unit.LFEMSim, "Simulation a em410x id card."),
'help': "EM410x read/write/emulator",
},
'help': "low frequency tag/reader",
}
+196 -16
View File
@@ -498,6 +498,112 @@ class HFMFWRBL(BaseMF1AuthOpera):
print(f" - {colorama.Fore.RED}Write fail.{colorama.Style.RESET_ALL}")
class HFMFDetectionEnable(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('-e', '--enable', type=int, required=True, choices=[1, 0],
help="1 = enable, 0 = disable")
return parser
# hf mf detection enable -e 1
def on_exec(self, args: argparse.Namespace):
enable = True if args.enable == 1 else False
self.cmd_positive.set_mf1_detection_enable(enable)
print(f" - Set mf1 detection { 'enable' if enable else 'disable'}.")
class HFMFDetectionLogCount(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
return None
# hf mf detection count
def on_exec(self, args: argparse.Namespace):
data_bytes = self.cmd_standard.get_mf1_detection_count().data
count = int.from_bytes(data_bytes, "little", signed=False)
print(f" - MF1 detection log count = {count}")
class HFMFDetectionDecrypt(DeviceRequiredUnit):
detection_log_size = 18
def args_parser(self) -> ArgumentParserNoExit or None:
return None
def decrypt_by_list(self, rs: list):
"""
从侦测日志列表中解密秘钥
:param rs:
:return:
"""
keys = []
for i in range(len(rs)):
item0 = rs[i]
for j in range(i + 1, len(rs)):
item1 = rs[j]
cmd_base = f"{item0['uid']} {item0['nt']} {item0['nr']} {item0['ar']}"
cmd_base += f" {item1['nt']} {item1['nr']} {item1['ar']}"
cmd_recover = f"mfkey32v2.exe {cmd_base}"
# print(cmd_recover)
# Found Key: [e899c526c5cd]
# subprocess.run(cmd_final, cwd=os.path.abspath("../bin/"), shell=True)
process = self.sub_process(cmd_recover)
# wait end
process.wait_process()
# get output
output_str = process.get_output_sync()
# print(output_str)
sea_obj = re.search(r"([a-fA-F0-9]{12})", output_str, flags=re.MULTILINE)
if sea_obj is not None:
keys.append(sea_obj[1])
return keys
# hf mf detection decrypt
def on_exec(self, args: argparse.Namespace):
buffer = bytearray()
index = 0
count = int.from_bytes(self.cmd_standard.get_mf1_detection_count().data, "little", signed=False)
if count == 0:
print(" - No detection log to download")
return
print(f" - MF1 detection log count = {count}, start download", end="")
while index < count:
tmp = self.cmd_positive.get_mf1_detection_log(index).data
recv_count = int(len(tmp) / HFMFDetectionDecrypt.detection_log_size)
index += recv_count
buffer.extend(tmp)
print(f".", end="")
print()
print(f" - Download done ({len(buffer)}bytes), start parse and decrypt")
result_maps = chameleon_cstruct.parse_mf1_detection_result(buffer)
for uid in result_maps.keys():
print(f" - Detection log for uid [{uid.upper()}]")
result_maps_for_uid = result_maps[uid]
for block in result_maps_for_uid:
print(f" > Block {block} detect log decrypting...")
if 'A' in result_maps_for_uid[block]:
# print(f" - A record: { result_maps[block]['A'] }")
records = result_maps_for_uid[block]['A']
if len(records) > 1:
result_maps[uid][block]['A'] = self.decrypt_by_list(records)
if 'B' in result_maps_for_uid[block]:
# print(f" - B record: { result_maps[block]['B'] }")
records = result_maps_for_uid[block]['B']
if len(records) > 1:
result_maps[uid][block]['B'] = self.decrypt_by_list(records)
print(" > Result ---------------------------")
for block in result_maps_for_uid.keys():
if 'A' in result_maps_for_uid[block]:
print(f" > Block {block}, A key result: {result_maps_for_uid[block]['A']}")
if 'B' in result_maps_for_uid[block]:
print(f" > Block {block}, B key result: {result_maps_for_uid[block]['B']}")
return
class LFEMRead(ReaderRequiredUint):
def args_parser(self) -> ArgumentParserNoExit or None:
@@ -509,32 +615,69 @@ class LFEMRead(ReaderRequiredUint):
print(f" - EM410x ID(10H): {colorama.Fore.GREEN}{id_hex}{colorama.Style.RESET_ALL}")
class LFEMWriteT55xx(ReaderRequiredUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
class LFEMCardRequiredUint(DeviceRequiredUnit):
@staticmethod
def add_card_arg(parser: ArgumentParserNoExit):
parser.add_argument("--id", type=str, required=True, help="EM410x tag id", metavar="hex")
return parser
def before_exec(self, args: argparse.Namespace):
if super(LFEMCardRequiredUint, self).before_exec(args):
if not re.match(r"^[a-fA-F0-9]{10}$", args.id):
raise ArgsParserError("ID must include 10 HEX symbols")
return True
return False
def args_parser(self) -> ArgumentParserNoExit or None:
raise NotImplementedError("Please implement this")
def on_exec(self, args: argparse.Namespace):
raise NotImplementedError("Please implement this")
class LFEMWriteT55xx(LFEMCardRequiredUint, ReaderRequiredUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
return self.add_card_arg(parser)
def before_exec(self, args: argparse.Namespace):
b1 = super(LFEMCardRequiredUint, self).before_exec(args)
b2 = super(ReaderRequiredUint, self).before_exec(args)
return b1 and b2
# lf em write --id 4400999559
def on_exec(self, args: argparse.Namespace):
id_hex = args.id
if not re.match(r"^[a-fA-F0-9]{10}$", id_hex):
raise ArgsParserError("ID must include 10 HEX symbols")
id_bytes = bytearray.fromhex(id_hex)
self.cmd_positive.write_em_410x_to_t55xx(id_bytes)
print(f" - EM410x ID(10H): {id_hex} write done.")
class HWSlotSet(DeviceRequiredUnit):
class SlotIndexRequireUint(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
raise NotImplementedError()
def on_exec(self, args: argparse.Namespace):
raise NotImplementedError()
@staticmethod
def add_slot_args(parser: ArgumentParserNoExit):
slot_choices = [1, 2, 3, 4, 5, 6, 7, 8]
parser.add_argument('-s', "--slot", type=int, required=True,
help="Slot index", metavar="number", choices=slot_choices)
return parser
# hw slot set -s 1
class HWSlotSet(SlotIndexRequireUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
return self.add_slot_args(parser)
# hw slot change -s 1
def on_exec(self, args: argparse.Namespace):
slot_index = args.slot
self.cmd_positive.set_slot_activated(slot_index)
@@ -543,8 +686,8 @@ class HWSlotSet(DeviceRequiredUnit):
class TagTypeRequiredUint(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
@staticmethod
def add_type_args(parser: ArgumentParserNoExit):
type_choices = chameleon_cmd.TagSpecificType.list()
help_str = ""
for name, value in chameleon_cmd.TagSpecificType.__members__.items():
@@ -555,11 +698,20 @@ class TagTypeRequiredUint(DeviceRequiredUnit):
metavar="number", choices=type_choices)
return parser
def args_parser(self) -> ArgumentParserNoExit or None:
raise NotImplementedError()
def on_exec(self, args: argparse.Namespace):
raise NotImplementedError()
class HWSlotTagType(TagTypeRequiredUint):
class HWSlotTagType(TagTypeRequiredUint, SlotIndexRequireUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
self.add_type_args(parser)
self.add_slot_args(parser)
return parser
# hw slot tagtype -t 2
def on_exec(self, args: argparse.Namespace):
@@ -568,13 +720,12 @@ class HWSlotTagType(TagTypeRequiredUint):
print(f' - Set slot tag type success.')
class HWSlotDataDefault(TagTypeRequiredUint):
class HWSlotDataDefault(TagTypeRequiredUint, SlotIndexRequireUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = super(HWSlotDataDefault, self).args_parser()
slot_choices = [1, 2, 3, 4, 5, 6, 7, 8]
parser.add_argument('-s', "--slot", type=int, required=True,
help="Slot index", metavar="number", choices=slot_choices)
parser = ArgumentParserNoExit()
self.add_type_args(parser)
self.add_slot_args(parser)
return parser
# hw slot init -s 1 -t 2
@@ -583,3 +734,32 @@ class HWSlotDataDefault(TagTypeRequiredUint):
slot_num = args.slot
self.cmd_positive.set_slot_data_default(slot_num, tag_type)
print(f' - Set slot tag data init success.')
class HWSlotEnableSet(SlotIndexRequireUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
self.add_slot_args(parser)
parser.add_argument('-e', '--enable', type=int, required=True, help="1 is Enable or 0 Disable", choices=[0, 1])
return parser
# hw slot enable -s 1 -e 0
def on_exec(self, args: argparse.Namespace):
slot_num = args.slot
enable = args.enable
self.cmd_positive.set_slot_enable(slot_num, enable)
print(f' - Set slot {slot_num} {"enable" if enable else "disable"} success.')
class LFEMSim(LFEMCardRequiredUint):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
return self.add_card_arg(parser)
# lf em sim --id 4545454545
def on_exec(self, args: argparse.Namespace):
id_hex = args.id
id_bytes = bytearray.fromhex(id_hex)
self.cmd_positive.set_em140x_sim_id(id_bytes)
print(f' - Set em410x tag id success.')
+89 -4
View File
@@ -8,6 +8,7 @@ DATA_CMD_GET_DEVICE_MODE = 1002
DATA_CMD_SET_SLOT_ACTIVATED = 1003
DATA_CMD_SET_SLOT_TAG_TYPE = 1004
DATA_CMD_SET_SLOT_DATA_DEFAULT = 1005
DATA_CMD_SET_SLOT_ENABLE = 1006
DATA_CMD_SCAN_14A_TAG = 2000
DATA_CMD_MF1_SUPPORT_DETECT = 2001
@@ -23,6 +24,11 @@ DATA_CMD_MF1_WRITE_ONE_BLOCK = 2009
DATA_CMD_SCAN_EM410X_TAG = 3000
DATA_CMD_WRITE_EM410X_TO_T5577 = 3001
DATA_CMD_SET_EM410X_EMU_ID = 5000
DATA_CMD_SET_MF1_DETECTION_ENABLE = 5003
DATA_CMD_GET_MF1_DETECTION_COUNT = 5004
DATA_CMD_GET_MF1_DETECTION_RESULT = 5005
@enum.unique
class TagSenseType(enum.IntEnum):
@@ -238,20 +244,24 @@ class BaseChameleonCMD:
data.append(slot_index - 1)
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_ACTIVATED, 0x00, data)
def set_slot_tag_type(self, tag_type: TagSpecificType):
def set_slot_tag_type(self, slot_index: int, tag_type: TagSpecificType):
"""
设置当前卡槽的模拟卡的标签类型
注意:此操作并不会更改flash中的数据,flash中的数据的变动仅在下次保存时更新
:param slot_index: 卡槽号码
:param tag_type: 标签类型
:return:
"""
if slot_index < 1 or slot_index > 8:
raise ValueError("The slot index range error(1-8)")
data = bytearray()
data.append(slot_index - 1)
data.append(tag_type)
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_TAG_TYPE, 0x00, data)
def set_slot_data_default(self, slot_index: int, tag_type: TagSpecificType):
"""
设置当前卡槽的模拟卡的数据为缺省数据
设置指定卡槽的模拟卡的数据为缺省数据
注意:此API会将flash中的数据一并进行设置
:param slot_index: 卡槽号码
:param tag_type: 要设置的缺省标签类型
@@ -264,6 +274,57 @@ class BaseChameleonCMD:
data.append(tag_type)
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_DATA_DEFAULT, 0x00, data)
def set_slot_enable(self, slot_index: int, enable: bool):
"""
设置指定的卡槽是否使能
:param slot_index: 卡槽号码
:param enable: 是否使能
:return:
"""
if slot_index < 1 or slot_index > 8:
raise ValueError("The slot index range error(1-8)")
data = bytearray()
data.append(slot_index - 1)
data.append(0x01 if enable else 0x00)
return self.device.send_cmd_sync(DATA_CMD_SET_SLOT_ENABLE, 0X00, data)
def set_em140x_sim_id(self, id_bytes: bytearray):
"""
设置EM410x模拟的卡号
:param id_bytes: 卡号的字节
:return:
"""
if len(id_bytes) != 5:
raise ValueError("The id bytes length must equal 5")
return self.device.send_cmd_sync(DATA_CMD_SET_EM410X_EMU_ID, 0x00, id_bytes)
def set_mf1_detection_enable(self, enable: bool):
"""
设置是否使能当前卡槽的侦测
:param enable: 是否使能
:return:
"""
data = bytearray()
data.append(0x01 if enable else 0x00)
return self.device.send_cmd_sync(DATA_CMD_SET_MF1_DETECTION_ENABLE, 0x00, data)
def get_mf1_detection_count(self):
"""
获取当前侦测记录的统计个数
:return:
"""
return self.device.send_cmd_sync(DATA_CMD_GET_MF1_DETECTION_COUNT, 0x00, None)
def get_mf1_detection_log(self, index: int):
"""
从指定的index位置开始获取侦测日志
:param index: 开始索引
:return:
"""
data = bytearray()
data.extend(index.to_bytes(4, "big", signed=False))
return self.device.send_cmd_sync(DATA_CMD_GET_MF1_DETECTION_RESULT, 0x00, data)
class NegativeResponseError(Exception):
"""
@@ -348,8 +409,8 @@ class PositiveChameleonCMD(BaseChameleonCMD):
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_tag_type(self, tag_type: TagSpecificType):
ret = super(PositiveChameleonCMD, self).set_slot_tag_type(tag_type)
def set_slot_tag_type(self, slot_index: int, tag_type: TagSpecificType):
ret = super(PositiveChameleonCMD, self).set_slot_tag_type(slot_index, tag_type)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
@@ -357,3 +418,27 @@ class PositiveChameleonCMD(BaseChameleonCMD):
ret = super(PositiveChameleonCMD, self).set_slot_data_default(slot_index, tag_type)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_slot_enable(self, slot_index: int, enable: bool):
ret = super(PositiveChameleonCMD, self).set_slot_enable(slot_index, enable)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_em140x_sim_id(self, id_bytes: bytearray):
ret = super(PositiveChameleonCMD, self).set_em140x_sim_id(id_bytes)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def set_mf1_detection_enable(self, enable: bool):
ret = super(PositiveChameleonCMD, self).set_mf1_detection_enable(enable)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
def get_mf1_detection_log(self, index: int):
ret = super(PositiveChameleonCMD, self).get_mf1_detection_log(index)
self.check_status(ret.status, chameleon_status.Device.STATUS_DEVICE_SUCCESS)
return ret
+60
View File
@@ -69,3 +69,63 @@ def parse_darkside_acquire_result(data: bytearray):
'nr': bytes_to_u32(data[24: 28]),
'ar': bytes_to_u32(data[28: 32]),
}
"""
// 验证的基础信息
struct {
uint8_t block;
uint8_t is_keyb: 1;
uint8_t is_nested: 1;
// 空域,占位置用的
uint8_t : 6;
} cmd;
// mfkey32必要参数
uint8_t uid[4];
uint8_t nt[4];
uint8_t nr[4];
uint8_t ar[4];
"""
def parse_mf1_detection_result(data: bytearray):
"""
From bytes parse detection param
:param data: data
:return:
"""
# 转换
result_list = []
pos = 0
while pos < len(data):
result_list.append({
'block': data[0 + pos],
'type': 0x60 + (data[1 + pos] & 0x01),
'is_nested': True if data[1 + pos] >> 1 & 0x01 == 0x01 else False,
'uid': data[2 + pos: 6 + pos].hex(),
'nt': data[6 + pos: 10 + pos].hex(),
'nr': data[10 + pos: 14 + pos].hex(),
'ar': data[14 + pos: 18 + pos].hex(),
})
pos += 18
# 归类
result_map = {}
for item in result_list:
uid = item['uid']
if uid not in result_map:
result_map[uid] = {}
block = item['block']
if block not in result_map[uid]:
result_map[uid][block] = {}
type_chr = 'A' if item['type'] == 0x60 else 'B'
if type_chr not in result_map[uid][block]:
result_map[uid][block][type_chr] = []
result_map[uid][block][type_chr].append(item)
return result_map