]> git.zerfleddert.de Git - proxmark3-svn/blob - client/scripts/ndef_dump.lua
Added script to dump ndef-compliant tags. Written in collaboration with @asper
[proxmark3-svn] / client / scripts / ndef_dump.lua
1
2 -- Ability to read what card is there
3 local getopt = require('getopt')
4 local cmds = require('commands')
5 local taglib = require('taglib')
6
7 local desc =
8 [[This script will automatically recognize and dump full content of a NFC NDEF Initialized tag; non-initialized tags will be ignored.
9
10 Arguments:
11 -d debug logging on
12 -h this help
13
14 ]]
15 local example = "script run xxx"
16 local author = "Martin Holst Swende & Asper"
17
18
19
20
21 ---
22 -- PrintAndLog
23 function prlog(...)
24 -- TODO; replace this with a call to the proper PrintAndLog
25 print(...)
26 end
27 ---
28 -- Usage help
29 function help()
30 prlog(desc)
31 prlog("Example usage")
32 prlog(example)
33 end
34
35 function debug(...)
36 if DEBUG then
37 prlog("debug:", ...)
38 end
39 end
40
41 ---
42 -- This is only meant to be used when errors occur
43 function oops(err)
44 prlog("ERROR: ",err)
45 return nil,err
46 end
47
48 local function show(data)
49 if DEBUG then
50 local formatString = ("H%d"):format(string.len(data))
51 local _,hexdata = bin.unpack(formatString, data)
52 debug("Hexdata" , hexdata)
53 end
54 end
55 --- Fire up a connection with a tag, return uid
56 -- @return UID if successfull
57 -- @return nil, errormessage if unsuccessfull
58
59 local function open()
60 debug("Opening connection")
61 core.clearCommandBuffer()
62 local x = string.format("hf 14a raw -r -p -s")
63 debug(x)
64 core.console(x)
65 debug("done")
66 data, err = waitCmd(true)
67 if err then return oops(err) end
68 show(data)
69 local formatString = ("H%d"):format(string.len(data))
70 local _,uid = bin.unpack(formatString, data)
71 return uid
72 end
73 --- Shut down tag communication
74 -- return no return values
75 local function close()
76 debug("Closing connection")
77 core.clearCommandBuffer()
78 local x = string.format("hf 14a raw -r")
79 debug(x)
80 core.console(x)
81 debug("done")
82 --data, err = waitCmd(true)
83 --data, err = waitCmd(false)
84
85 end
86
87
88 ---_ Gets data from a block
89 -- @return {block, block+1, block+2, block+3} if successfull
90 -- @return nil, errormessage if unsuccessfull
91 local function getBlock(block)
92 local data, err
93
94 core.clearCommandBuffer()
95
96 local x = string.format("hf 14a raw -r -c -p 30 %02x", block)
97 debug(x)
98 core.console(x)
99 debug("done")
100 -- By now, there should be an ACK waiting from the device, since
101 -- we used the -r flag (don't read response).
102
103 data, err = waitCmd(false)
104 if err then return oops(err) end
105 show(data)
106
107 if string.len(data) < 18 then
108 return nil, ("Error, expected at least 18 bytes, got %d"):format(string.len(data))
109 end
110 -- Now, parse out the block data
111 -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155
112 -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC
113 b0 = string.sub(data,1,4)
114 b1 = string.sub(data,5,8)
115 b2 = string.sub(data,9,12)
116 b3 = string.sub(data,13,16)
117 return {b0,b1,b2,b3}
118 end
119
120
121 --- This function is a lua-implementation of
122 -- cmdhf14a.c:waitCmd(uint8_t iSelect)
123 function waitCmd(iSelect)
124 local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000)
125 if response then
126 local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response)
127
128 local iLen = arg0
129 if iSelect then iLen = arg1 end
130 debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1))
131 if iLen == 0 then return nil, "No response from tag" end
132 local recv = string.sub(response,count, iLen+count-1)
133 return recv
134 end
135 return nil, "No response from device"
136 end
137
138
139
140 local function main( args)
141 debug("script started")
142 local err, data, data2,k,v,i
143 -- Read the parameters
144 for o, a in getopt.getopt(args, 'hd') do
145 if o == "h" then help() return end
146 if o == "d" then DEBUG = true end
147 end
148
149 -- Info contained within the tag (block 0 example)
150 -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155
151 -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC
152 -- MM?? ???? ???? ???? ???? ???? NNVV SS?? ----
153 -- M = Manufacturer info
154 -- N = NDEF-Structure-Compliant (if value is E1)
155 -- V = NFC Forum Specification version (if 10 = v1.0)
156
157 -- First, 'connect' (fire up the field) and get the uid
158 local uidHexstr = open()
159
160 -- First, get blockt 3 byte 2
161 local blocks, err = getBlock(0)
162 if err then return oops(err) end
163 -- Block 3 contains number of blocks
164 local b3chars = {string.byte(blocks[4], 1,4)}
165 local numBlocks = b3chars[3] * 2 + 6
166 prlog("Number of blocks:", numBlocks)
167
168 -- NDEF compliant?
169 if b3chars[1] ~= 0xE1 then
170 return oops("This tag is not NDEF-Complian")
171 end
172
173 local ndefVersion = b3chars[2]
174
175 -- Block 1, byte 1 contains manufacturer info
176 local bl1_b1 = string.byte(blocks[1], 1)
177 local manufacturer = taglib.lookupManufacturer(bl1_b1)
178
179 -- Reuse existing info
180 local blockData = {blocks[1],blocks[2],blocks[3],blocks[4]}
181
182
183 --[[ Due to the infineon my-d move bug
184 (if I send 30 0F i receive block0f+block00+block01+block02 insted of block0f+block10+block11+block12)
185 the only way to avoid this is to send the read command as many times as block numbers
186 removing bytes from 5 to 18 from each answer.
187 --]]
188 prlog("Dumping data...please wait")
189 for i=4,numBlocks-1,1 do
190 blocks, err = getBlock(i)
191 if err then return oops(err) end
192 table.insert(blockData,blocks[1])
193 end
194 -- Deactivate field
195 close()
196 -- Print results
197 prlog(string.format("Tag manufacturer: %s", manufacturer))
198 prlog(string.format("Tag UID: %s", uidHexstr))
199 prlog(string.format("Tag NDEF version: 0x%02x", ndefVersion))
200
201 for k,v in ipairs(blockData) do
202 prlog(string.format("Block %02x: %02x %02x %02x %02x",k-1, string.byte(v, 1,4)))
203 end
204 end
205 main(args)
Impressum, Datenschutz