]>
Commit | Line | Data |
---|---|---|
1 | local cmds = require('commands') | |
2 | local getopt = require('getopt') | |
3 | local lib14a = require('read14a') | |
4 | local utils = require('utils') | |
5 | example = [[ | |
6 | script run ufodump | |
7 | script run ufodump -b 10 | |
8 | ]] | |
9 | author = "Iceman" | |
10 | desc = | |
11 | [[ | |
12 | This is a script that reads AZTEK iso14443a tags. | |
13 | It starts from block 0, and ends at default block 20. Use 'b' to say different endblock. | |
14 | ||
15 | xor: the first three block (0,1,2) is not XORED. The rest seems to be xored. | |
16 | ||
17 | Arguments: | |
18 | h this helptext | |
19 | b endblock in decimal (1-255, default 20) | |
20 | ]] | |
21 | ||
22 | -- Some globals | |
23 | local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds | |
24 | local DEBUG = false -- the debug flag | |
25 | --- | |
26 | -- A debug printout-function | |
27 | function dbg(args) | |
28 | if DEBUG then | |
29 | print("###", args) | |
30 | end | |
31 | end | |
32 | --- | |
33 | -- This is only meant to be used when errors occur | |
34 | function oops(err) | |
35 | print("ERROR: ",err) | |
36 | core.clearCommandBuffer() | |
37 | end | |
38 | --- | |
39 | -- Usage help | |
40 | function help() | |
41 | print(desc) | |
42 | print("Example usage") | |
43 | print(example) | |
44 | end | |
45 | -- | |
46 | -- writes data to ascii textfile. | |
47 | function writeDumpFile(uid, blockData) | |
48 | local destination = string.format("%s.eml", uid) | |
49 | local file = io.open(destination, "w") | |
50 | if file == nil then | |
51 | return nil, string.format("Could not write to file %s", destination) | |
52 | end | |
53 | local rowlen = string.len(blockData[1]) | |
54 | ||
55 | for i,block in ipairs(blockData) do | |
56 | if rowlen ~= string.len(block) then | |
57 | print(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i)) | |
58 | end | |
59 | file:write(block.."\n") | |
60 | end | |
61 | file:close() | |
62 | return destination | |
63 | end | |
64 | -- | |
65 | --- Picks out and displays the data read from a tag | |
66 | -- Specifically, takes a usb packet, converts to a Command | |
67 | -- (as in commands.lua), takes the data-array and | |
68 | -- reads the number of bytes specified in arg1 (arg0 in c-struct) | |
69 | -- and displays the data | |
70 | -- @blockno just to print which block the data belong to | |
71 | -- @param usbpacket the data received from the device | |
72 | function showdata(blockno, data) | |
73 | local xorkey = '55AA55AA55AA55AA6262' | |
74 | --local s = data.." | "..utils.ConvertHexToAscii(data).." | " | |
75 | local s = data.." | " | |
76 | local dex = '' | |
77 | local rs | |
78 | for i = 1, 20-4, 4 do | |
79 | local item = string.sub(data, i, i+3) | |
80 | local xor = string.sub(xorkey, i, i+3) | |
81 | ||
82 | if blockno > 2 then | |
83 | rs = bit32.bxor(tonumber(item,16) , tonumber(xor,16)) | |
84 | else | |
85 | rs = tonumber(item, 16) | |
86 | end | |
87 | dex = (dex..'%04X'):format(rs) | |
88 | end | |
89 | --s = s..dex.." | "..utils.ConvertHexToAscii(dex) | |
90 | s = s..dex.." | " | |
91 | print( (" %02d | %s"):format(blockno,s)) | |
92 | end | |
93 | -- | |
94 | -- Send a "raw" iso14443a package, ie "hf 14a raw" command | |
95 | function sendRaw(rawdata, options) | |
96 | --print(">> ", rawdata) | |
97 | local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC | |
98 | local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, | |
99 | arg1 = flags, -- Send raw | |
100 | -- arg2 contains the length, which is half the length | |
101 | -- of the ASCII-string rawdata | |
102 | arg2 = string.len(rawdata)/2, | |
103 | data = rawdata} | |
104 | return lib14a.sendToDevice(command, options.ignore_response) | |
105 | end | |
106 | -- | |
107 | -- Sends an instruction to do nothing, only disconnect | |
108 | function disconnect() | |
109 | local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a, arg1 = 0, } | |
110 | -- We can ignore the response here, no ACK is returned for this command | |
111 | -- Check /armsrc/iso14443a.c, ReaderIso14443a() for details | |
112 | return lib14a.sendToDevice(command, true) | |
113 | --core.console("hf 14a raw -r") | |
114 | end | |
115 | --- | |
116 | -- The main entry point | |
117 | function main(args) | |
118 | ||
119 | local ignore_response = false | |
120 | local endblock = 20 | |
121 | ||
122 | -- Read the parameters | |
123 | for o, a in getopt.getopt(args, 'hb:') do | |
124 | if o == "h" then return help() end | |
125 | if o == "b" then endblock = a end | |
126 | end | |
127 | endblock = endblock or 20 | |
128 | ||
129 | -- First of all, connect | |
130 | info, err = lib14a.read1443a(true) | |
131 | if err then disconnect() return oops(err) end | |
132 | core.clearCommandBuffer() | |
133 | ||
134 | local blockData = {} | |
135 | ||
136 | -- Show tag info | |
137 | print(("\nFound Card UID [%s]\n"):format(info.uid)) | |
138 | ||
139 | print("blk | data | xored") | |
140 | print("----+------------------+-------------------") | |
141 | for block = 00, endblock do | |
142 | local cmd = string.format("10%02x00", block) | |
143 | res, err = sendRaw(cmd , {ignore_response = ignore_response}) | |
144 | if err then disconnect() return oops(err) end | |
145 | ||
146 | local cmd_response = Command.parse(res) | |
147 | local len = tonumber(cmd_response.arg1) * 2 | |
148 | local data = string.sub(tostring(cmd_response.data), 0, len-4) | |
149 | ||
150 | showdata(block, data) | |
151 | table.insert(blockData, data) | |
152 | end | |
153 | print("----+------------------+-------------------") | |
154 | disconnect() | |
155 | ||
156 | local filename, err = writeDumpFile(info.uid, blockData) | |
157 | if err then return oops(err) end | |
158 | ||
159 | print(string.format("\nDumped data into %s", filename)) | |
160 | end | |
161 | ||
162 | ||
163 | ||
164 | ||
165 | ------------------------- | |
166 | -- Testing | |
167 | ------------------------- | |
168 | function selftest() | |
169 | DEBUG = true | |
170 | dbg("Performing test") | |
171 | main() | |
172 | dbg("Tests done") | |
173 | end | |
174 | -- Flip the switch here to perform a sanity check. | |
175 | -- It read a nonce in two different ways, as specified in the usage-section | |
176 | if "--test"==args then | |
177 | selftest() | |
178 | else | |
179 | -- Call the main | |
180 | main(args) | |
181 | end |