From 1686e4d1db2a7ebaa1f6126e53e91b6db46b2029 Mon Sep 17 00:00:00 2001 From: "martin.holst@gmail.com" Date: Fri, 18 Oct 2013 11:14:23 +0000 Subject: [PATCH] Added script to dump ndef-compliant tags. Written in collaboration with @asper --- client/scripts/ndef_dump.lua | 205 +++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 client/scripts/ndef_dump.lua diff --git a/client/scripts/ndef_dump.lua b/client/scripts/ndef_dump.lua new file mode 100644 index 00000000..bfb4e341 --- /dev/null +++ b/client/scripts/ndef_dump.lua @@ -0,0 +1,205 @@ + +-- Ability to read what card is there +local getopt = require('getopt') +local cmds = require('commands') +local taglib = require('taglib') + +local desc = +[[This script will automatically recognize and dump full content of a NFC NDEF Initialized tag; non-initialized tags will be ignored. + +Arguments: + -d debug logging on + -h this help + +]] +local example = "script run xxx" +local author = "Martin Holst Swende & Asper" + + + + +--- +-- PrintAndLog +function prlog(...) + -- TODO; replace this with a call to the proper PrintAndLog + print(...) +end +--- +-- Usage help +function help() + prlog(desc) + prlog("Example usage") + prlog(example) +end + +function debug(...) + if DEBUG then + prlog("debug:", ...) + end +end + +--- +-- This is only meant to be used when errors occur +function oops(err) + prlog("ERROR: ",err) + return nil,err +end + +local function show(data) + if DEBUG then + local formatString = ("H%d"):format(string.len(data)) + local _,hexdata = bin.unpack(formatString, data) + debug("Hexdata" , hexdata) + end +end +--- Fire up a connection with a tag, return uid +-- @return UID if successfull +-- @return nil, errormessage if unsuccessfull + +local function open() + debug("Opening connection") + core.clearCommandBuffer() + local x = string.format("hf 14a raw -r -p -s") + debug(x) + core.console(x) + debug("done") + data, err = waitCmd(true) + if err then return oops(err) end + show(data) + local formatString = ("H%d"):format(string.len(data)) + local _,uid = bin.unpack(formatString, data) + return uid +end +--- Shut down tag communication +-- return no return values +local function close() + debug("Closing connection") + core.clearCommandBuffer() + local x = string.format("hf 14a raw -r") + debug(x) + core.console(x) + debug("done") + --data, err = waitCmd(true) + --data, err = waitCmd(false) + +end + + +---_ Gets data from a block +-- @return {block, block+1, block+2, block+3} if successfull +-- @return nil, errormessage if unsuccessfull +local function getBlock(block) + local data, err + + core.clearCommandBuffer() + + local x = string.format("hf 14a raw -r -c -p 30 %02x", block) + debug(x) + core.console(x) + debug("done") + -- By now, there should be an ACK waiting from the device, since + -- we used the -r flag (don't read response). + + data, err = waitCmd(false) + if err then return oops(err) end + show(data) + + if string.len(data) < 18 then + return nil, ("Error, expected at least 18 bytes, got %d"):format(string.len(data)) + end + -- Now, parse out the block data + -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 + -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC + b0 = string.sub(data,1,4) + b1 = string.sub(data,5,8) + b2 = string.sub(data,9,12) + b3 = string.sub(data,13,16) + return {b0,b1,b2,b3} +end + + +--- This function is a lua-implementation of +-- cmdhf14a.c:waitCmd(uint8_t iSelect) +function waitCmd(iSelect) + local response = core.WaitForResponseTimeout(cmds.CMD_ACK,1000) + if response then + local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',response) + + local iLen = arg0 + if iSelect then iLen = arg1 end + debug(("Received %i octets (arg0:%d, arg1:%d)"):format(iLen, arg0, arg1)) + if iLen == 0 then return nil, "No response from tag" end + local recv = string.sub(response,count, iLen+count-1) + return recv + end + return nil, "No response from device" +end + + + +local function main( args) + debug("script started") + local err, data, data2,k,v,i + -- Read the parameters + for o, a in getopt.getopt(args, 'hd') do + if o == "h" then help() return end + if o == "d" then DEBUG = true end + end + + -- Info contained within the tag (block 0 example) + -- 0534 00B9 049C AD7F 4A00 0000 E110 1000 2155 + -- b0b0 b0b0 b1b1 b1b1 b2b2 b2b2 b3b3 b3b3 CRCC + -- MM?? ???? ???? ???? ???? ???? NNVV SS?? ---- + -- M = Manufacturer info + -- N = NDEF-Structure-Compliant (if value is E1) + -- V = NFC Forum Specification version (if 10 = v1.0) + + -- First, 'connect' (fire up the field) and get the uid + local uidHexstr = open() + + -- First, get blockt 3 byte 2 + local blocks, err = getBlock(0) + if err then return oops(err) end + -- Block 3 contains number of blocks + local b3chars = {string.byte(blocks[4], 1,4)} + local numBlocks = b3chars[3] * 2 + 6 + prlog("Number of blocks:", numBlocks) + + -- NDEF compliant? + if b3chars[1] ~= 0xE1 then + return oops("This tag is not NDEF-Complian") + end + + local ndefVersion = b3chars[2] + + -- Block 1, byte 1 contains manufacturer info + local bl1_b1 = string.byte(blocks[1], 1) + local manufacturer = taglib.lookupManufacturer(bl1_b1) + + -- Reuse existing info + local blockData = {blocks[1],blocks[2],blocks[3],blocks[4]} + + + --[[ Due to the infineon my-d move bug + (if I send 30 0F i receive block0f+block00+block01+block02 insted of block0f+block10+block11+block12) + the only way to avoid this is to send the read command as many times as block numbers + removing bytes from 5 to 18 from each answer. + --]] + prlog("Dumping data...please wait") + for i=4,numBlocks-1,1 do + blocks, err = getBlock(i) + if err then return oops(err) end + table.insert(blockData,blocks[1]) + end + -- Deactivate field + close() + -- Print results + prlog(string.format("Tag manufacturer: %s", manufacturer)) + prlog(string.format("Tag UID: %s", uidHexstr)) + prlog(string.format("Tag NDEF version: 0x%02x", ndefVersion)) + + for k,v in ipairs(blockData) do + prlog(string.format("Block %02x: %02x %02x %02x %02x",k-1, string.byte(v, 1,4))) + end +end +main(args) \ No newline at end of file -- 2.39.5