]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/scripts/lf_bulk_program.lua
contrib: LF Programming script
[proxmark3-svn] / client / scripts / lf_bulk_program.lua
... / ...
CommitLineData
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
12 e.g:
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
35 This can also be done with a combination of bitwise operations (in fact,
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", "")
40
41 local p = count % 2
42 if (p == 0) then
43 return(false)
44 else
45 return(true)
46 end
47end
48
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)
60 stream=toBits(id,26)
61
62 --As the function defaults to even parity and returns a boolean,
63 --perform a 'not' function to get odd parity
64 high = evenparity(string.sub(stream,0,12)) and 1 or 0
65 low = not evenparity(string.sub(stream,13)) and 1 or 0
66 bits = bit32.bor(bit32.lshift(id,1), low)
67 bits = bit32.bor(bits, bit32.lshift(high,25))
68
69 --Since the lua library bit32 is (obviously) 32 bits and we need to
70 --encode 36 bits to properly do a 26 bit tag with the preamble we need
71 --to create a higher order and lower order component which we will
72 --then assemble in the return. The math above defines the proper
73 --encoding as per HID/Weigand/etc. These bit flips are due to the
74 --format length check on bit 38 (cmdlfhid.c:64) and
75 --bit 31 (cmdlfhid.c:66).
76 preamble = bit32.bor(0, bit32.lshift(1,5))
77 bits = bit32.bor(bits, bit32.lshift(1,26))
78
79 return ("%04x%08x"):format(preamble,bits)
80
81end
82
83local function main(args)
84
85 --I really wish a better getopt function would be brought in supporting
86 --long arguments, but it seems this library was chosen for BSD style
87 --compatibility
88 for o, a in getopt.getopt(args, 'f:b:c:h') do
89 if o == 'f' then
90 if isempty(a) then
91 print("You did not supply a facility code, using 0")
92 facility = 0
93 else
94 facility = a
95 end
96 elseif o == 'b' then
97 if isempty(a) then
98 print("You must supply the flag -b (base id)")
99 return
100 else
101 baseid = a
102 end
103 elseif o == 'c' then
104 if isempty(a) then
105 print("You must supply the flag -c (count)")
106 return
107 else
108 count = a
109 end
110 elseif o == 'h' then
111 print(desc)
112 print(usage)
113 return
114 end
115 end
116
117 --Due to my earlier complaints about how this specific getopt library
118 --works, specifying ":" does not enforce supplying a value, thus we
119 --need to do these checks all over again.
120
121 if isempty(baseid) then
122 print("You must supply the flag -b (base id)")
123 print(usage)
124 return
125 end
126
127 if isempty(count) then
128 print("You must supply the flag -c (count)")
129 print(usage)
130 return
131 end
132
133 --If the facility ID is non specified, ensure we code it as zero
134 if isempty(facility) then
135 print("Using 0 for the facility code as -f was not supplied")
136 facility = 0
137 end
138
139 --The next baseid + count function presents a logic/UX conflict
140 --where users specifying -c 1 (count = 1) would try to program two
141 --tags. This makes it so that -c 0 & -c 1 both code one tag, and all
142 --other values encode the expected amount.
143 if tonumber(count) > 0 then count = count -1 end
144
145 endid = baseid + count
146
147 for cardnum = baseid,endid do
148 local card = cardHex(cardnum, facility)
149 print("Press enter to program card "..cardnum..":"..facility.." (hex: "..card..")")
150 --This would be better with "press any key", but we'll take
151 --what we can get.
152 io.read()
153 core.console( ('lf hid clone %s'):format(card) )
154 end
155end
156
157
158main(args)
Impressum, Datenschutz