This commit is contained in:
Philippe Teuwen 2025-06-15 12:53:33 +02:00
commit a5d02c6ba2
12 changed files with 1643 additions and 1655 deletions

View file

@ -542,7 +542,7 @@ void RunMod(void) {
sprintf(dumpFileName, DUMP_FILE, mattyrun_card.uid[0], mattyrun_card.uid[1], mattyrun_card.uid[2], mattyrun_card.uid[3]);
rdv40_spiffs_write(dumpFileName, emCARD, 1024, RDV40_SPIFFS_SAFETY_SAFE);
Dbprintf("[" _GREEN_("+") "] " _GREEN_("Stored card on %s"), dumpFileName);
#endif
#endif
}
state = STATE_EMULATE;

View file

@ -349,7 +349,7 @@ int sam_get_serial_number(void) {
}
Dbprintf(_YELLOW_("Serial Number: "));
Dbhexdump(sam_response_an[1],sam_serial_an, false);
Dbhexdump(sam_response_an[1], sam_serial_an, false);
goto out;
}

View file

@ -356,7 +356,7 @@ int sam_picopass_get_pacs(PacketCommandNG *c) {
// step 1: ping SAM
sam_get_version(info);
if(info){
if (info) {
sam_get_serial_number();
goto out;
}

File diff suppressed because it is too large Load diff

View file

@ -1,128 +1,128 @@
local getopt = require('getopt')
copyright = ''
author = "TheChamp669"
version = 'v1.0.0'
desc = [[
Perform bulk enrollment of 26 bit AWID style RFID Tags
For more info, check the comments in the code
]]
example = [[
--
script run lf_awid_bulkclone.lua -f 1 -b 1000
]]
usage = [[
script run lf_awid_bulkclone.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function showHelp()
print("Usage: script run <scriptname> [-h]")
print("Options:")
print("-h \t This help")
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:c:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 255')
fc = 255
else
fc = a
end
end
if o == 'b' then
if isempty(a) then
print('You did not supply a starting card number, using 59615')
cn = 59615
else
cn = a
end
end
end
-- Example starting values
local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time
print("Session Start: " .. sessionStart)
print("Facility Code,Card Number")
while true do
print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn))
local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn)
core.console(command)
print(string.format("%d,%d", fc, cn))
print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
break
else
cn = cn + 1
end
end
end
local getopt = require('getopt')
copyright = ''
author = "TheChamp669"
version = 'v1.0.0'
desc = [[
Perform bulk enrollment of 26 bit AWID style RFID Tags
For more info, check the comments in the code
]]
example = [[
--
script run lf_awid_bulkclone.lua -f 1 -b 1000
]]
usage = [[
script run lf_awid_bulkclone.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function showHelp()
print("Usage: script run <scriptname> [-h]")
print("Options:")
print("-h \t This help")
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:c:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 255')
fc = 255
else
fc = a
end
end
if o == 'b' then
if isempty(a) then
print('You did not supply a starting card number, using 59615')
cn = 59615
else
cn = a
end
end
end
-- Example starting values
local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time
print("Session Start: " .. sessionStart)
print("Facility Code,Card Number")
while true do
print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn))
local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn)
core.console(command)
print(string.format("%d,%d", fc, cn))
print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
break
else
cn = cn + 1
end
end
end
main(args)

View file

@ -1,131 +1,131 @@
local getopt = require('getopt')
local ansicolors = require('ansicolors')
local cmds = require('commands')
copyright = ''
author = "TheChamop669"
version = 'v1.0.1'
desc = [[
Perform bulk enrollment of 26 bit H10301 style RFID Tags
For more info, check the comments in the code
]]
example = [[
--
script run lf_hid_bulkclone_v2.lua -f 1 -b 1000
]]
usage = [[
script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 0')
fc = 10
else
fc = a
end
end
if o == 'b' then
if isempty(a) then
print('You did not supply a starting card number, using 1000')
cn = 1000
else
cn = a
end
end
end
local successful_writes = {}
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
while true do
print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn))
local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn)
core.console(command)
table.insert(successful_writes, string.format("%d,%d", fc, cn))
print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
print("Timestamp: ", timestamp)
print("Successful Writes:")
for _, v in ipairs(successful_writes) do print(v) end
break
elseif user_input:lower() ~= 'r' then
cn = cn + 1
end
end
end
main(args)
--[[
Notes:
1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format.
2. The script prompts the user for the initial facility code and card number at the start of the session.
3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts.
4. Upon quitting, the script prints all successful writes along with a timestamp.
5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command.
]]
local getopt = require('getopt')
local ansicolors = require('ansicolors')
local cmds = require('commands')
copyright = ''
author = "TheChamop669"
version = 'v1.0.1'
desc = [[
Perform bulk enrollment of 26 bit H10301 style RFID Tags
For more info, check the comments in the code
]]
example = [[
--
script run lf_hid_bulkclone_v2.lua -f 1 -b 1000
]]
usage = [[
script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 0')
fc = 10
else
fc = a
end
end
if o == 'b' then
if isempty(a) then
print('You did not supply a starting card number, using 1000')
cn = 1000
else
cn = a
end
end
end
local successful_writes = {}
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
while true do
print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn))
local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn)
core.console(command)
table.insert(successful_writes, string.format("%d,%d", fc, cn))
print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
print("Timestamp: ", timestamp)
print("Successful Writes:")
for _, v in ipairs(successful_writes) do print(v) end
break
elseif user_input:lower() ~= 'r' then
cn = cn + 1
end
end
end
main(args)
--[[
Notes:
1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format.
2. The script prompts the user for the initial facility code and card number at the start of the session.
3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts.
4. Upon quitting, the script prints all successful writes along with a timestamp.
5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command.
]]

View file

@ -1,125 +1,125 @@
local getopt = require('getopt')
local cmds = require('commands')
copyright = ''
author = "TheChamp669"
version = 'v1.0.0'
desc = [[
Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags
The vnc is set to 2.
For more info, check the comments in the code
]]
example = [[
--
script run lf_ioprox_bulkclone.lua -f 1 -b 1000
]]
usage = [[
script run lf_ioprox_bulkclone.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 0')
fc = 0
else
fc = a
end
end
if o == 'b' then
if isempty(a) then return oops('You must supply the flag -b (starting card number)') end
cn = a
end
end
local successful_writes = {}
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
while true do
print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn))
-- Writing to block 0 with the specific data for ioProx card format
core.console("lf t55xx write -b 0 -d 00147040")
-- Command to set facility code and card number on the fob
local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn)
core.console(command)
table.insert(successful_writes, string.format("%d,%d", fc, cn))
print("Fob created successfully.")
print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
print("Timestamp: ", timestamp)
print("Successful Writes:")
for _, v in ipairs(successful_writes) do print(v) end
break
elseif user_input:lower() ~= 'r' then
cn = cn + 1
end
end
end
main(args)
local getopt = require('getopt')
local cmds = require('commands')
copyright = ''
author = "TheChamp669"
version = 'v1.0.0'
desc = [[
Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags
The vnc is set to 2.
For more info, check the comments in the code
]]
example = [[
--
script run lf_ioprox_bulkclone.lua -f 1 -b 1000
]]
usage = [[
script run lf_ioprox_bulkclone.lua -f facility -b base_id_num
]]
arguments = [[
-h : this help
-f : facility id
-b : starting card id
]]
local DEBUG = true
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, errr
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
---
-- Exit message
local function exitMsg(msg)
print( string.rep('--',20) )
print( string.rep('--',20) )
print(msg)
print()
end
local function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
if #args == 0 then return help() end
for o, a in getopt.getopt(args, 'f:b:h') do
if o == 'h' then return help() end
if o == 'f' then
if isempty(a) then
print('You did not supply a facility code, using 0')
fc = 0
else
fc = a
end
end
if o == 'b' then
if isempty(a) then return oops('You must supply the flag -b (starting card number)') end
cn = a
end
end
local successful_writes = {}
local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time())
while true do
print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn))
-- Writing to block 0 with the specific data for ioProx card format
core.console("lf t55xx write -b 0 -d 00147040")
-- Command to set facility code and card number on the fob
local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn)
core.console(command)
table.insert(successful_writes, string.format("%d,%d", fc, cn))
print("Fob created successfully.")
print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.")
local user_input = io.read()
if user_input:lower() == 'q' then
print("Timestamp: ", timestamp)
print("Successful Writes:")
for _, v in ipairs(successful_writes) do print(v) end
break
elseif user_input:lower() ~= 'r' then
cn = cn + 1
end
end
end
main(args)

View file

@ -1,488 +1,488 @@
local getopt = require('getopt')
local utils = require('utils')
local ac = require('ansicolors')
local os = require('os')
local dash = string.rep('--', 32)
local dir = os.getenv('HOME') .. '/.proxmark3/logs/'
local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+"))
local log_file_path = dir .. "Paxton_log.txt"
local nam = ""
local pm3 = require('pm3')
p = pm3.pm3()
local command = core.console
command('clear')
author = ' Author: jareckib - 30.01.2025'
tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102'
version = ' version v1.20'
desc = [[
The script automates the copying of Paxton fobs read - write.
It also allows manual input of data for blocks 4-7.
The third option is reading data stored in the log file and create new fob.
Additionally, the script calculates the ID for downgrading Paxton to EM4102.
]]
usage = [[
script run paxton_clone
]]
arguments = [[
script run paxton_clone -h : this help
]]
local debug = true
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
local function help()
print()
print(author)
print(tutorial)
print(version)
print(desc)
print(ac.cyan..' Usage'..ac.reset)
print(usage)
print(ac.cyan..' Arguments'..ac.reset)
print(arguments)
end
local function reset_log_file()
local file = io.open(logfile, "w+")
file:write("")
file:close()
end
local function read_log_file(logfile)
local file = io.open(logfile, "r")
if not file then
error(" Could not open the file")
end
local content = file:read("*all")
file:close()
return content
end
local function parse_blocks(result)
local blocks = {}
for line in result:gmatch("[^\r\n]+") do
local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)")
if block_num and block_data then
block_num = tonumber(block_num)
block_data = block_data:gsub("%s+", "")
blocks[block_num] = block_data
end
end
return blocks
end
local function hex_to_bin(hex_string)
local bin_string = ""
local hex_to_bin_map = {
['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011",
['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111",
['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011",
['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111"
}
for i = 1, #hex_string do
bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)]
end
return bin_string
end
local function remove_last_two_bits(binary_str)
return binary_str:sub(1, #binary_str - 2)
end
local function split_into_5bit_chunks(binary_str)
local chunks = {}
for i = 1, #binary_str, 5 do
table.insert(chunks, binary_str:sub(i, i + 4))
end
return chunks
end
local function remove_parity_bit(chunks)
local no_parity_chunks = {}
for _, chunk in ipairs(chunks) do
if #chunk == 5 then
table.insert(no_parity_chunks, chunk:sub(2))
end
end
return no_parity_chunks
end
local function convert_to_hex(chunks)
local hex_values = {}
for _, chunk in ipairs(chunks) do
if #chunk > 0 then
table.insert(hex_values, string.format("%X", tonumber(chunk, 2)))
end
end
return hex_values
end
local function convert_to_decimal(chunks)
local decimal_values = {}
for _, chunk in ipairs(chunks) do
table.insert(decimal_values, tonumber(chunk, 2))
end
return decimal_values
end
local function find_until_before_f(hex_values)
local result = {}
for _, value in ipairs(hex_values) do
if value == 'F' then
break
end
table.insert(result, value)
end
return result
end
local function process_block(block)
local binary_str = hex_to_bin(block)
binary_str = remove_last_two_bits(binary_str)
local chunks = split_into_5bit_chunks(binary_str)
local no_parity_chunks = remove_parity_bit(chunks)
return no_parity_chunks
end
local function calculate_id_net(blocks)
local all_hex_values = {}
for _, block in ipairs(blocks) do
local hex_values = convert_to_hex(process_block(block))
for _, hex in ipairs(hex_values) do
table.insert(all_hex_values, hex)
end
end
local selected_hex_values = find_until_before_f(all_hex_values)
if #selected_hex_values == 0 then
error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5')
end
local combined_hex = table.concat(selected_hex_values)
if not combined_hex:match("^%x+$") then
error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5')
end
local decimal_id = tonumber(combined_hex)
local stripped_hex_id = string.format("%X", decimal_id)
local padded_hex_id = string.format("%010X", decimal_id)
return decimal_id, padded_hex_id
end
local function calculate_id_switch(blocks)
local all_decimal_values = {}
for _, block in ipairs(blocks) do
local decimal_values = convert_to_decimal(process_block(block))
for _, dec in ipairs(decimal_values) do
table.insert(all_decimal_values, dec)
end
end
if #all_decimal_values < 15 then
error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7')
end
local id_positions = {9, 11, 13, 15, 2, 4, 6, 8}
local id_numbers = {}
for _, pos in ipairs(id_positions) do
table.insert(id_numbers, all_decimal_values[pos])
end
local decimal_id = tonumber(table.concat(id_numbers))
local padded_hex_id = string.format("%010X", decimal_id)
return decimal_id, padded_hex_id
end
local function name_exists_in_log(name)
local file = io.open(log_file_path, "r")
if not file then
return false
end
local pattern = "^Name:%s*" .. name .. "%s*$"
for line in file:lines() do
if line:match(pattern) then
file:close()
return true
end
end
file:close()
return false
end
local function log_result(blocks, em410_id, name)
local log_file = io.open(log_file_path, "a")
if log_file then
log_file:write("Name: " .. name .. "\n")
log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n")
for i = 4, 7 do
log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil"))
end
log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil"))
log_file:write('--------------------------\n')
log_file:close()
print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset)
else
print(" Failed to open log file for writing.")
end
end
local function verify_written_data(original_blocks)
p:console('lf hitag read --ht2 -k BDF5E846')
local result = read_log_file(logfile)
local verified_blocks = parse_blocks(result)
local success = true
for i = 4, 7 do
if original_blocks[i] ~= verified_blocks[i] then
print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.')
success = false
end
end
if success then
print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset)
else
print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset)
end
end
local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
while true do
io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset)
local choice = io.read()
if choice == "1" then
io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
io.read()
print(dash)
p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846")
reset_log_file()
--timer(5)
verify_written_data(blocks)
elseif choice == "2" then
io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
io.read()
p:console("lf em 410x clone --id " .. padded_hex_id)
print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset)
else
print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset)
goto ask_again
end
while true do
print(dash)
io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset)
local another = io.read()
if another:lower() == "n" then
if was_option_3 then
print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist")
return
end
print()
print(ac.green .. " Saving Paxton_log file..." .. ac.reset)
while true do
io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow)
name = io.read()
io.write(ac.reset..'')
if name == nil or name:match("^%s*$") then
print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.')
else
if name_exists_in_log(name) then
print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.')
else
break
end
end
end
log_result(blocks, padded_hex_id, name)
print(ac.green .. " Log saved successfully!" .. ac.reset)
reset_log_file()
return
elseif another:lower() == "y" then
goto ask_again
else
print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset)
end
end
::ask_again::
end
end
local function is_valid_hex(input)
return #input == 8 and input:match("^[0-9A-Fa-f]+$")
end
local function main(args)
while true do
for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end
end
command('clear')
print(dash)
print(ac.green .. ' Select option: ' .. ac.reset)
print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy')
print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7')
print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data")
print(dash)
while true do
io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset)
input_option = io.read()
if input_option == "1" or input_option == "2" or input_option == "3" then
break
else
print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset)
end
end
local was_option_3 = false
if input_option == "1" then
local show_place_message = true
while true do
if show_place_message then
io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..')
end
io.read()
print(dash)
p:console('lf hitag read --ht2 -k BDF5E846')
if not logfile then
error(" No files in this directory")
end
local result = read_log_file(logfile)
local blocks = parse_blocks(result)
local empty_block = false
for i = 4, 7 do
if not blocks[i] then
empty_block = true
break
end
end
if empty_block then
io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..')
show_place_message = false
else
print(' Readed blocks:')
print()
for i = 4, 7 do
if blocks[i] then
print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset))
end
end
local decimal_id, padded_hex_id
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
print(dash)
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
else
print(dash)
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
end
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
print(dash)
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
break
end
end
elseif input_option == "2" then
local blocks = {}
for i = 4, 7 do
while true do
io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow)
local input = io.read()
input = input:upper()
if is_valid_hex(input) then
blocks[i] = input
break
else
print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).')
end
end
end
local decimal_id, padded_hex_id
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
print(ac.reset.. dash)
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
else
print(ac.reset.. dash)
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
end
print(dash)
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
print(dash)
if not padded_hex_id then
print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided')
return
end
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
break
elseif input_option == "3" then
was_option_3 = true
local retries = 3
while retries > 0 do
io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow)
local user_input = io.read()
io.write(ac.reset..'')
if user_input == nil or user_input:match("^%s*$") then
print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!')
end
local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$"
local file = io.open(log_file_path, "r")
if not file then
print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.')
return
end
local lines = {}
for line in file:lines() do
table.insert(lines, line)
end
file:close()
local found = false
for i = 1, #lines do
if lines[i]:match(name_clean) then
nam = user_input
local blocks = {
[4] = lines[i + 2]:match("Block 4: (.+)"),
[5] = lines[i + 3]:match("Block 5: (.+)"),
[6] = lines[i + 4]:match("Block 6: (.+)"),
[7] = lines[i + 5]:match("Block 7: (.+)")
}
local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)")
print(dash)
print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset)
for j = 4, 7 do
print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset))
end
print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset)
print(dash)
local decimal_id, padded_hex_id = em4102_id, em4102_id
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam)
found = true
break
end
end
if not found then
retries = retries - 1
else
break
end
end
if retries == 0 then
print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset)
end
end
print(dash)
print(' Exiting script Lua...')
return
end
end
local getopt = require('getopt')
local utils = require('utils')
local ac = require('ansicolors')
local os = require('os')
local dash = string.rep('--', 32)
local dir = os.getenv('HOME') .. '/.proxmark3/logs/'
local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+"))
local log_file_path = dir .. "Paxton_log.txt"
local nam = ""
local pm3 = require('pm3')
p = pm3.pm3()
local command = core.console
command('clear')
author = ' Author: jareckib - 30.01.2025'
tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102'
version = ' version v1.20'
desc = [[
The script automates the copying of Paxton fobs read - write.
It also allows manual input of data for blocks 4-7.
The third option is reading data stored in the log file and create new fob.
Additionally, the script calculates the ID for downgrading Paxton to EM4102.
]]
usage = [[
script run paxton_clone
]]
arguments = [[
script run paxton_clone -h : this help
]]
local debug = true
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
local function help()
print()
print(author)
print(tutorial)
print(version)
print(desc)
print(ac.cyan..' Usage'..ac.reset)
print(usage)
print(ac.cyan..' Arguments'..ac.reset)
print(arguments)
end
local function reset_log_file()
local file = io.open(logfile, "w+")
file:write("")
file:close()
end
local function read_log_file(logfile)
local file = io.open(logfile, "r")
if not file then
error(" Could not open the file")
end
local content = file:read("*all")
file:close()
return content
end
local function parse_blocks(result)
local blocks = {}
for line in result:gmatch("[^\r\n]+") do
local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)")
if block_num and block_data then
block_num = tonumber(block_num)
block_data = block_data:gsub("%s+", "")
blocks[block_num] = block_data
end
end
return blocks
end
local function hex_to_bin(hex_string)
local bin_string = ""
local hex_to_bin_map = {
['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011",
['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111",
['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011",
['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111"
}
for i = 1, #hex_string do
bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)]
end
return bin_string
end
local function remove_last_two_bits(binary_str)
return binary_str:sub(1, #binary_str - 2)
end
local function split_into_5bit_chunks(binary_str)
local chunks = {}
for i = 1, #binary_str, 5 do
table.insert(chunks, binary_str:sub(i, i + 4))
end
return chunks
end
local function remove_parity_bit(chunks)
local no_parity_chunks = {}
for _, chunk in ipairs(chunks) do
if #chunk == 5 then
table.insert(no_parity_chunks, chunk:sub(2))
end
end
return no_parity_chunks
end
local function convert_to_hex(chunks)
local hex_values = {}
for _, chunk in ipairs(chunks) do
if #chunk > 0 then
table.insert(hex_values, string.format("%X", tonumber(chunk, 2)))
end
end
return hex_values
end
local function convert_to_decimal(chunks)
local decimal_values = {}
for _, chunk in ipairs(chunks) do
table.insert(decimal_values, tonumber(chunk, 2))
end
return decimal_values
end
local function find_until_before_f(hex_values)
local result = {}
for _, value in ipairs(hex_values) do
if value == 'F' then
break
end
table.insert(result, value)
end
return result
end
local function process_block(block)
local binary_str = hex_to_bin(block)
binary_str = remove_last_two_bits(binary_str)
local chunks = split_into_5bit_chunks(binary_str)
local no_parity_chunks = remove_parity_bit(chunks)
return no_parity_chunks
end
local function calculate_id_net(blocks)
local all_hex_values = {}
for _, block in ipairs(blocks) do
local hex_values = convert_to_hex(process_block(block))
for _, hex in ipairs(hex_values) do
table.insert(all_hex_values, hex)
end
end
local selected_hex_values = find_until_before_f(all_hex_values)
if #selected_hex_values == 0 then
error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5')
end
local combined_hex = table.concat(selected_hex_values)
if not combined_hex:match("^%x+$") then
error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5')
end
local decimal_id = tonumber(combined_hex)
local stripped_hex_id = string.format("%X", decimal_id)
local padded_hex_id = string.format("%010X", decimal_id)
return decimal_id, padded_hex_id
end
local function calculate_id_switch(blocks)
local all_decimal_values = {}
for _, block in ipairs(blocks) do
local decimal_values = convert_to_decimal(process_block(block))
for _, dec in ipairs(decimal_values) do
table.insert(all_decimal_values, dec)
end
end
if #all_decimal_values < 15 then
error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7')
end
local id_positions = {9, 11, 13, 15, 2, 4, 6, 8}
local id_numbers = {}
for _, pos in ipairs(id_positions) do
table.insert(id_numbers, all_decimal_values[pos])
end
local decimal_id = tonumber(table.concat(id_numbers))
local padded_hex_id = string.format("%010X", decimal_id)
return decimal_id, padded_hex_id
end
local function name_exists_in_log(name)
local file = io.open(log_file_path, "r")
if not file then
return false
end
local pattern = "^Name:%s*" .. name .. "%s*$"
for line in file:lines() do
if line:match(pattern) then
file:close()
return true
end
end
file:close()
return false
end
local function log_result(blocks, em410_id, name)
local log_file = io.open(log_file_path, "a")
if log_file then
log_file:write("Name: " .. name .. "\n")
log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n")
for i = 4, 7 do
log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil"))
end
log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil"))
log_file:write('--------------------------\n')
log_file:close()
print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset)
else
print(" Failed to open log file for writing.")
end
end
local function verify_written_data(original_blocks)
p:console('lf hitag read --ht2 -k BDF5E846')
local result = read_log_file(logfile)
local verified_blocks = parse_blocks(result)
local success = true
for i = 4, 7 do
if original_blocks[i] ~= verified_blocks[i] then
print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.')
success = false
end
end
if success then
print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset)
else
print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset)
end
end
local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
while true do
io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset)
local choice = io.read()
if choice == "1" then
io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
io.read()
print(dash)
p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846")
p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846")
reset_log_file()
--timer(5)
verify_written_data(blocks)
elseif choice == "2" then
io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..")
io.read()
p:console("lf em 410x clone --id " .. padded_hex_id)
print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset)
else
print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset)
goto ask_again
end
while true do
print(dash)
io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset)
local another = io.read()
if another:lower() == "n" then
if was_option_3 then
print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist")
return
end
print()
print(ac.green .. " Saving Paxton_log file..." .. ac.reset)
while true do
io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow)
name = io.read()
io.write(ac.reset..'')
if name == nil or name:match("^%s*$") then
print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.')
else
if name_exists_in_log(name) then
print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.')
else
break
end
end
end
log_result(blocks, padded_hex_id, name)
print(ac.green .. " Log saved successfully!" .. ac.reset)
reset_log_file()
return
elseif another:lower() == "y" then
goto ask_again
else
print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset)
end
end
::ask_again::
end
end
local function is_valid_hex(input)
return #input == 8 and input:match("^[0-9A-Fa-f]+$")
end
local function main(args)
while true do
for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end
end
command('clear')
print(dash)
print(ac.green .. ' Select option: ' .. ac.reset)
print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy')
print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7')
print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data")
print(dash)
while true do
io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset)
input_option = io.read()
if input_option == "1" or input_option == "2" or input_option == "3" then
break
else
print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset)
end
end
local was_option_3 = false
if input_option == "1" then
local show_place_message = true
while true do
if show_place_message then
io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..')
end
io.read()
print(dash)
p:console('lf hitag read --ht2 -k BDF5E846')
if not logfile then
error(" No files in this directory")
end
local result = read_log_file(logfile)
local blocks = parse_blocks(result)
local empty_block = false
for i = 4, 7 do
if not blocks[i] then
empty_block = true
break
end
end
if empty_block then
io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..')
show_place_message = false
else
print(' Readed blocks:')
print()
for i = 4, 7 do
if blocks[i] then
print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset))
end
end
local decimal_id, padded_hex_id
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
print(dash)
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
else
print(dash)
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
end
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
print(dash)
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
break
end
end
elseif input_option == "2" then
local blocks = {}
for i = 4, 7 do
while true do
io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow)
local input = io.read()
input = input:upper()
if is_valid_hex(input) then
blocks[i] = input
break
else
print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).')
end
end
end
local decimal_id, padded_hex_id
if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then
print(ac.reset.. dash)
print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]})
else
print(ac.reset.. dash)
print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset)
decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]})
end
print(dash)
print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset))
print(dash)
if not padded_hex_id then
print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided')
return
end
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3)
break
elseif input_option == "3" then
was_option_3 = true
local retries = 3
while retries > 0 do
io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow)
local user_input = io.read()
io.write(ac.reset..'')
if user_input == nil or user_input:match("^%s*$") then
print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!')
end
local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$"
local file = io.open(log_file_path, "r")
if not file then
print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.')
return
end
local lines = {}
for line in file:lines() do
table.insert(lines, line)
end
file:close()
local found = false
for i = 1, #lines do
if lines[i]:match(name_clean) then
nam = user_input
local blocks = {
[4] = lines[i + 2]:match("Block 4: (.+)"),
[5] = lines[i + 3]:match("Block 5: (.+)"),
[6] = lines[i + 4]:match("Block 6: (.+)"),
[7] = lines[i + 5]:match("Block 7: (.+)")
}
local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)")
print(dash)
print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset)
for j = 4, 7 do
print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset))
end
print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset)
print(dash)
local decimal_id, padded_hex_id = em4102_id, em4102_id
handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam)
found = true
break
end
end
if not found then
retries = retries - 1
else
break
end
end
if retries == 0 then
print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset)
end
end
print(dash)
print(' Exiting script Lua...')
return
end
end
main(args)

View file

@ -1921,7 +1921,7 @@ int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status,
// if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11
// } else { // SAK b2=0 b4=0 b5=1 b1=0, SAK=0x10
// }
type |= MTPLUS;
type |= MTPLUS;
} else { // SAK b2=0 b4=0 b5=0

View file

@ -327,7 +327,7 @@ static const iclass_config_card_item_t *get_config_card_item(int idx) {
static void print_config_cards(void) {
PrintAndLogEx(INFO, "---- " _CYAN_("Config cards options") " ------------");
for (int i = 0; i < ARRAYLEN(iclass_config_options) ; ++i) {
switch (i){
switch (i) {
case 0:
PrintAndLogEx(INFO, _YELLOW_("---- LED Operations ----"));
break;

View file

@ -567,7 +567,7 @@ static int CmdEM4x70Brute(const char *Cmd) {
return PM3_EINVARG;
}
CLIParserFree(ctx);
// opts structure takes value in BIG ENDIAN form
opts.partial_key_start[0] = (uint8_t)((start_key >> 8) & 0xFF);
opts.partial_key_start[1] = (uint8_t)((start_key >> 0) & 0xFF);
@ -628,7 +628,7 @@ static int CmdEM4x70Unlock(const char *Cmd) {
PrintAndLogEx(FAILED, "PIN length must be 4 bytes, got %d", pin_len);
return PM3_EINVARG;
}
// Client command line parsing and validation complete ... now use the helper function
em4x70_tag_info_t info;
int result = unlock_em4x70(&opts, &info);
@ -768,7 +768,7 @@ static int CmdEM4x70SetKey(const char *Cmd) {
PrintAndLogEx(FAILED, "Key length must be 12 bytes, got %d", key_len);
return PM3_EINVARG;
}
// Client command line parsing and validation complete ... now use the helper function
int result = setkey_em4x70(&opts);

View file

@ -3682,9 +3682,10 @@
"--break stop tag interaction on nr-mac",
"-p, --prevent fake epurse update",
"--shallow shallow mod",
"-d, --data <hex> DER encoded command to send to SAM"
"-d, --data <hex> DER encoded command to send to SAM",
"--info get SAM infos (version, serial number)"
],
"usage": "hf iclass sam [-hvkntp] [--break] [--shallow] [-d <hex>]..."
"usage": "hf iclass sam [-hvkntp] [--break] [--shallow] [-d <hex>]... [--info]"
},
"hf iclass sim": {
"command": "hf iclass sim",
@ -7084,7 +7085,7 @@
},
"hf mfu aesauth": {
"command": "hf mfu aesauth",
"description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0: DataProtKey (default) Key index 1: UIDRetrKey Key index 2: OriginalityKey",
"description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0... DataProtKey (default) Key index 1... UIDRetrKey Key index 2... OriginalityKey",
"notes": [
"hf mfu aesauth",
"hf mfu aesauth --key <16 hex bytes> --index <0..2>"
@ -9397,11 +9398,10 @@
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"--rnd <hex> Random 56-bit",
"--frn <hex> F(RN) 28-bit as 4 hex bytes"
],
"usage": "lf em 4x70 auth [-h] [--par] --rnd <hex> --frn <hex>"
"usage": "lf em 4x70 auth [-h] --rnd <hex> --frn <hex>"
},
"lf em 4x70 autorecover": {
"command": "lf em 4x70 autorecover",
@ -9414,12 +9414,11 @@
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"--rnd <hex> Random 56-bit from known-good authentication",
"--frn <hex> F(RN) 28-bit as 4 hex bytes from known-good authentication",
"--grn <hex> G(RN) 20-bit as 3 hex bytes from known-good authentication"
],
"usage": "lf em 4x70 autorecover [-h] [--par] --rnd <hex> --frn <hex> --grn <hex>"
"usage": "lf em 4x70 autorecover [-h] --rnd <hex> --frn <hex> --grn <hex>"
},
"lf em 4x70 calc": {
"command": "lf em 4x70 calc",
@ -9448,27 +9447,24 @@
"offline": true,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-b, --block <dec> block/word address, dec",
"--rnd <hex> Random 56-bit",
"--frn <hex> F(RN) 28-bit as 4 hex bytes",
"-s, --start <hex> Start bruteforce enumeration from this key value"
],
"usage": "lf em 4x70 brute [-h] [--par] -b <dec> --rnd <hex> --frn <hex> [-s <hex>]"
"usage": "lf em 4x70 brute [-h] -b <dec> --rnd <hex> --frn <hex> [-s <hex>]"
},
"lf em 4x70 info": {
"command": "lf em 4x70 info",
"description": "Tag Information EM4x70 Tag variants include ID48 automotive transponder. ID48 does not use command parity (default). V4070 and EM4170 do require parity bit.",
"notes": [
"lf em 4x70 info",
"lf em 4x70 info --par -> adds parity bit to command"
"lf em 4x70 info"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands"
"-h, --help This help"
],
"usage": "lf em 4x70 info [-h] [--par]"
"usage": "lf em 4x70 info [-h]"
},
"lf em 4x70 recover": {
"command": "lf em 4x70 recover",
@ -9481,13 +9477,12 @@
"offline": true,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-k, --key <hex> Key as 6 hex bytes",
"--rnd <hex> Random 56-bit",
"--frn <hex> F(RN) 28-bit as 4 hex bytes",
"--grn <hex> G(RN) 20-bit as 3 hex bytes"
],
"usage": "lf em 4x70 recover [-h] [--par] -k <hex> --rnd <hex> --frn <hex> --grn <hex>"
"usage": "lf em 4x70 recover [-h] -k <hex> --rnd <hex> --frn <hex> --grn <hex>"
},
"lf em 4x70 setkey": {
"command": "lf em 4x70 setkey",
@ -9500,56 +9495,49 @@
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-k, --key <hex> Key as 12 hex bytes"
],
"usage": "lf em 4x70 setkey [-h] [--par] -k <hex>"
"usage": "lf em 4x70 setkey [-h] -k <hex>"
},
"lf em 4x70 setpin": {
"command": "lf em 4x70 setpin",
"description": "Write new PIN",
"notes": [
"lf em 4x70 setpin -p 11223344 -> Write new PIN",
"lf em 4x70 setpin -p 11223344 --par -> Write new PIN using parity commands"
"lf em 4x70 setpin -p 11223344 -> Write new PIN"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-p, --pin <hex> pin, 4 bytes"
],
"usage": "lf em 4x70 setpin [-h] [--par] -p <hex>"
"usage": "lf em 4x70 setpin [-h] -p <hex>"
},
"lf em 4x70 unlock": {
"command": "lf em 4x70 unlock",
"description": "Unlock EM4x70 by sending PIN Default pin may be: AAAAAAAA 00000000",
"notes": [
"lf em 4x70 unlock -p 11223344 -> Unlock with PIN",
"lf em 4x70 unlock -p 11223344 --par -> Unlock with PIN using parity commands"
"lf em 4x70 unlock -p 11223344 -> Unlock with PIN"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-p, --pin <hex> pin, 4 bytes"
],
"usage": "lf em 4x70 unlock [-h] [--par] -p <hex>"
"usage": "lf em 4x70 unlock [-h] -p <hex>"
},
"lf em 4x70 write": {
"command": "lf em 4x70 write",
"description": "Write EM4x70",
"notes": [
"lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15",
"lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands"
"lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15"
],
"offline": false,
"options": [
"-h, --help This help",
"--par Add parity bit when sending commands",
"-b, --block <dec> block/word address, dec",
"-d, --data <hex> data, 2 bytes"
],
"usage": "lf em 4x70 write [-h] [--par] -b <dec> -d <hex>"
"usage": "lf em 4x70 write [-h] -b <dec> -d <hex>"
},
"lf em help": {
"command": "lf em help",
@ -13377,6 +13365,6 @@
"metadata": {
"commands_extracted": 768,
"extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2025-06-09T12:58:22"
"extracted_on": "2025-06-15T10:52:29"
}
}