]> git.zerfleddert.de Git - proxmark3-svn/blame - client/scripts/lf_bulk_program.lua
Code improved for less memory
[proxmark3-svn] / client / scripts / lf_bulk_program.lua
CommitLineData
79b19c5f
BRH
1--
2-- lf_bulk_program.lua - A tool to clone a large number of tags at once.
3-- Updated 2017-04-18
4--
5-- The getopt-functionality is loaded from pm3/client/lualibs/getopt.lua
6-- Have a look there for further details
7getopt = require('getopt')
8bit32 = require('bit32')
9
10usage = [[ script run lf_bulk_program.lua -f facility -b base_id_num -c count
11
e069547c 12 e.g:
79b19c5f
BRH
13 script run lf_bulk_program.lua -f 1 -b 1000 -c 10
14]]
15author = "Brian Redbeard"
16desc =[[
17Perform bulk enrollment of 26 bit H10301 style RFID Tags
18For more info, check the comments in the code
19]]
20
21--[[Implement a function to simply visualize the bitstream in a text format
22--This is especially helpful for troubleshooting bitwise math issues]]--
23function toBits(num,bits)
24 -- returns a table of bits, most significant first.
25 bits = bits or math.max(1, select(2, math.frexp(num)))
26 local t = {} -- will contain the bits
27 for b = bits, 1, -1 do
28 t[b] = math.fmod(num, 2)
29 num = math.floor((num - t[b]) / 2)
30 end
31 return table.concat(t)
32end
33
34--[[Likely, I'm an idiot, but I couldn't find any parity functions in Lua
e069547c 35 This can also be done with a combination of bitwise operations (in fact,
79b19c5f
BRH
36 is the canonically "correct" way to do it, but my brain doesn't just
37 default to this and so counting some ones is good enough for me]]--
38local function evenparity(s)
39 local _, count = string.gsub(s, "1", "")
e069547c 40
79b19c5f
BRH
41 local p = count % 2
42 if (p == 0) then
43 return(false)
44 else
45 return(true)
46 end
47end
e069547c 48
79b19c5f
BRH
49
50local function isempty(s)
51 return s == nil or s == ''
52end
53
54--[[The Proxmark3 "clone" functions expect the data to be in hex format so
55 take the card id number and facility ID as arguments and construct the
56 hex. This should be easy enough to extend to non 26bit formats]]--
57local function cardHex(i,f)
58 fac = bit32.lshift(f,16)
59 id = bit32.bor(i, fac)
e069547c 60 stream=toBits(id,24)
79b19c5f
BRH
61
62 --As the function defaults to even parity and returns a boolean,
63 --perform a 'not' function to get odd parity
e069547c
TH
64 high = evenparity(string.sub(stream,1,12)) and 1 or 0
65 low = not evenparity(string.sub(stream,13)) and 1 or 0
66
79b19c5f
BRH
67 bits = bit32.bor(bit32.lshift(id,1), low)
68 bits = bit32.bor(bits, bit32.lshift(high,25))
69
70 --Since the lua library bit32 is (obviously) 32 bits and we need to
71 --encode 36 bits to properly do a 26 bit tag with the preamble we need
72 --to create a higher order and lower order component which we will
73 --then assemble in the return. The math above defines the proper
74 --encoding as per HID/Weigand/etc. These bit flips are due to the
e069547c 75 --format length check on bit 38 (cmdlfhid.c:64) and
79b19c5f
BRH
76 --bit 31 (cmdlfhid.c:66).
77 preamble = bit32.bor(0, bit32.lshift(1,5))
78 bits = bit32.bor(bits, bit32.lshift(1,26))
79
80 return ("%04x%08x"):format(preamble,bits)
e069547c 81
79b19c5f
BRH
82end
83
84local function main(args)
85
86 --I really wish a better getopt function would be brought in supporting
87 --long arguments, but it seems this library was chosen for BSD style
88 --compatibility
89 for o, a in getopt.getopt(args, 'f:b:c:h') do
e069547c
TH
90 if o == 'f' then
91 if isempty(a) then
79b19c5f
BRH
92 print("You did not supply a facility code, using 0")
93 facility = 0
e069547c 94 else
79b19c5f
BRH
95 facility = a
96 end
e069547c
TH
97 elseif o == 'b' then
98 if isempty(a) then
79b19c5f
BRH
99 print("You must supply the flag -b (base id)")
100 return
101 else
102 baseid = a
103 end
e069547c
TH
104 elseif o == 'c' then
105 if isempty(a) then
79b19c5f
BRH
106 print("You must supply the flag -c (count)")
107 return
108 else
109 count = a
110 end
111 elseif o == 'h' then
112 print(desc)
113 print(usage)
114 return
115 end
116 end
117
118 --Due to my earlier complaints about how this specific getopt library
119 --works, specifying ":" does not enforce supplying a value, thus we
120 --need to do these checks all over again.
121
e069547c 122 if isempty(baseid) then
79b19c5f
BRH
123 print("You must supply the flag -b (base id)")
124 print(usage)
125 return
126 end
127
e069547c 128 if isempty(count) then
79b19c5f
BRH
129 print("You must supply the flag -c (count)")
130 print(usage)
131 return
132 end
133
134 --If the facility ID is non specified, ensure we code it as zero
e069547c 135 if isempty(facility) then
79b19c5f 136 print("Using 0 for the facility code as -f was not supplied")
e069547c 137 facility = 0
79b19c5f
BRH
138 end
139
140 --The next baseid + count function presents a logic/UX conflict
141 --where users specifying -c 1 (count = 1) would try to program two
142 --tags. This makes it so that -c 0 & -c 1 both code one tag, and all
143 --other values encode the expected amount.
144 if tonumber(count) > 0 then count = count -1 end
145
146 endid = baseid + count
147
e069547c 148 for cardnum = baseid,endid do
79b19c5f
BRH
149 local card = cardHex(cardnum, facility)
150 print("Press enter to program card "..cardnum..":"..facility.." (hex: "..card..")")
151 --This would be better with "press any key", but we'll take
152 --what we can get.
153 io.read()
154 core.console( ('lf hid clone %s'):format(card) )
155 end
156end
157
158
159main(args)
Impressum, Datenschutz