]> git.zerfleddert.de Git - proxmark3-svn/blob - client/scripts/lf_bulk_program.lua
Code improved for less memory
[proxmark3-svn] / client / scripts / lf_bulk_program.lua
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
7 getopt = require('getopt')
8 bit32 = require('bit32')
9
10 usage = [[ 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 ]]
15 author = "Brian Redbeard"
16 desc =[[
17 Perform bulk enrollment of 26 bit H10301 style RFID Tags
18 For 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]]--
23 function 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)
32 end
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]]--
38 local 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
47 end
48
49
50 local function isempty(s)
51 return s == nil or s == ''
52 end
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]]--
57 local function cardHex(i,f)
58 fac = bit32.lshift(f,16)
59 id = bit32.bor(i, fac)
60 stream=toBits(id,24)
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,1,12)) and 1 or 0
65 low = not evenparity(string.sub(stream,13)) and 1 or 0
66
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
75 --format length check on bit 38 (cmdlfhid.c:64) and
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)
81
82 end
83
84 local 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
90 if o == 'f' then
91 if isempty(a) then
92 print("You did not supply a facility code, using 0")
93 facility = 0
94 else
95 facility = a
96 end
97 elseif o == 'b' then
98 if isempty(a) then
99 print("You must supply the flag -b (base id)")
100 return
101 else
102 baseid = a
103 end
104 elseif o == 'c' then
105 if isempty(a) then
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
122 if isempty(baseid) then
123 print("You must supply the flag -b (base id)")
124 print(usage)
125 return
126 end
127
128 if isempty(count) then
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
135 if isempty(facility) then
136 print("Using 0 for the facility code as -f was not supplied")
137 facility = 0
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
148 for cardnum = baseid,endid do
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
156 end
157
158
159 main(args)
Impressum, Datenschutz