2 -- Ability to read what card is there
3 local getopt
= require('getopt')
4 local cmds
= require('commands')
5 local taglib
= require('taglib')
8 [[This script will automatically recognize and dump full content of a NFC NDEF Initialized tag; non-initialized tags will be ignored.
10 It also write the dump to an eml-file <uid>.eml.
12 (The difference between an .eml-file and a .bin-file is that the eml file contains
13 ASCII representation of the hex-data, with linebreaks between 'rows'. A .bin-file contains the
14 raw data, but when saving into that for, we lose the infromation about how the memory is structured.
15 For example: 24 bytes could be 6 blocks of 4 bytes, or vice versa.
16 Therefore, the .eml is better to use file when saving dumps.)
23 local example
= "script run xxx"
24 local author
= "Martin Holst Swende & Asper"
28 -- TODO; replace this with a call to the proper PrintAndLog
32 -- This is only meant to be used when errors occur
39 -- Perhaps this will be moved to a separate library at one point
41 --- Writes an eml-file.
42 -- @param uid - the uid of the tag. Used in filename
43 -- @param blockData. Assumed to be on the format {'\0\1\2\3,'\b\e\e\f' ...,
44 -- that is, blockData[row] contains a string with the actual data, not ascii hex representation
45 -- return filename if all went well,
46 -- @reurn nil, error message if unsuccessfull
47 writeDumpFile
= function(uid
, blockData
)
48 local destination
= string.format("%s.eml", uid
)
49 local file
= io
.open(destination
, "w")
51 return nil, string.format("Could not write to file %s", destination
)
53 local rowlen
= string.len(blockData
[1])
55 for i
,block
in ipairs(blockData
) do
56 if rowlen
~= string.len(block
) then
57 prlog(string.format("WARNING: Dumpdata seems corrupted, line %d was not the same length as line 1",i
))
60 local formatString
= string.format("H%d", string.len(block
))
61 local _
,hex
= bin
.unpack(formatString
,block
)
75 prlog("Example usage")
86 local function show(data
)
88 local formatString
= ("H%d"):format(string.len(data
))
89 local _
,hexdata
= bin
.unpack(formatString
, data
)
90 debug("Hexdata" , hexdata
)
93 --- Fire up a connection with a tag, return uid
94 -- @return UID if successfull
95 -- @return nil, errormessage if unsuccessfull
98 debug("Opening connection")
99 core
.clearCommandBuffer()
100 local x
= string.format("hf 14a raw -r -p -s")
104 data
, err
= waitCmd(true)
105 if err
then return oops(err
) end
107 local formatString
= ("H%d"):format(string.len(data
))
108 local _
,uid
= bin
.unpack(formatString
, data
)
111 --- Shut down tag communication
112 -- return no return values
113 local function close()
114 debug("Closing connection")
115 core
.clearCommandBuffer()
116 local x
= string.format("hf 14a raw -r")
120 --data, err = waitCmd(true)
121 --data, err = waitCmd(false)
126 ---_ Gets data from a block
127 -- @return {block, block+1, block+2, block+3} if successfull
128 -- @return nil, errormessage if unsuccessfull
129 local function getBlock(block
)
132 core
.clearCommandBuffer()
134 local x
= string.format("hf 14a raw -r -c -p 30 %02x", block
)
138 -- By now, there should be an ACK waiting from the device, since
139 -- we used the -r flag (don't read response).
141 data
, err
= waitCmd(false)
142 if err
then return oops(err
) end
145 if string.len(data
) < 18 then
146 return nil, ("Expected at least 18 bytes, got %d - this tag is not NDEF-compliant"):format(string.len(data
))
148 -- Now, parse out the block data
149 -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155
150 -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC
151 b0
= string.sub(data
,1,4)
152 b1
= string.sub(data
,5,8)
153 b2
= string.sub(data
,9,12)
154 b3
= string.sub(data
,13,16)
159 --- This function is a lua-implementation of
160 -- cmdhf14a.c:waitCmd(uint8_t iSelect)
161 function waitCmd(iSelect
)
162 local response
= core
.WaitForResponseTimeout(cmds
.CMD_ACK
,1000)
164 local count
,cmd
,arg0
,arg1
,arg2
= bin
.unpack('LLLL',response
)
167 if iSelect
then iLen
= arg1
end
168 debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen
, arg0
, arg1
))
169 if iLen
== 0 then return nil, "No response from tag" end
170 local recv
= string.sub(response
,count
, iLen
+count
-1)
173 return nil, "No response from device"
178 local function main( args
)
179 debug("script started")
180 local err
, data
, data2
,k
,v
,i
181 -- Read the parameters
182 for o
, a
in getopt
.getopt(args
, 'hd') do
183 if o
== "h" then help() return end
184 if o
== "d" then DEBUG
= true end
187 -- Info contained within the tag (block 0 example)
188 -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155
189 -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC
190 -- MM?? ???? ???? ???? ???? ???? NNVV SS?? ----
191 -- M = Manufacturer info
192 -- N = NDEF-Structure-Compliant (if value is E1)
193 -- V = NFC Forum Specification version (if 10 = v1.0)
195 -- First, 'connect' (fire up the field) and get the uid
196 local uidHexstr
= open()
198 -- First, get blockt 3 byte 2
199 local blocks
, err
= getBlock(0)
200 if err
then return oops(err
) end
201 -- Block 3 contains number of blocks
202 local b3chars
= {string.byte(blocks
[4], 1,4)}
203 local numBlocks
= b3chars
[3] * 2 + 6
204 prlog("Number of blocks:", numBlocks
)
207 if b3chars
[1] ~= 0xE1 then
208 return oops("This tag is not NDEF-Compliant")
211 local ndefVersion
= b3chars
[2]
213 -- Block 1, byte 1 contains manufacturer info
214 local bl1_b1
= string.byte(blocks
[1], 1)
215 local manufacturer
= taglib
.lookupManufacturer(bl1_b1
)
217 -- Reuse existing info
218 local blockData
= {blocks
[1],blocks
[2],blocks
[3],blocks
[4]}
221 --[[ Due to the infineon my-d move bug
222 (if I send 30 0F i receive block0f+block00+block01+block02 insted of block0f+block10+block11+block12)
223 the only way to avoid this is to send the read command as many times as block numbers
224 removing bytes from 5 to 18 from each answer.
226 prlog("Dumping data...please wait")
227 for i
=4,numBlocks
-1,1 do
228 blocks
, err
= getBlock(i
)
229 if err
then return oops(err
) end
230 table.insert(blockData
,blocks
[1])
235 prlog(string.format("Tag manufacturer: %s", manufacturer
))
236 prlog(string.format("Tag UID: %s", uidHexstr
))
237 prlog(string.format("Tag NDEF version: 0x%02x", ndefVersion
))
239 for k
,v
in ipairs(blockData
) do
240 prlog(string.format("Block %02x: %02x %02x %02x %02x",k
-1, string.byte(v
, 1,4)))
242 local filename
, err
= utils
.writeDumpFile(uidHexstr
, blockData
)
243 if err
then return oops(err
) end
245 prlog(string.format("Dumped data into %s", filename
))