+----+----+----+----+----+----+----+----+
0x20|UID1|UID2|kghC|
+----+----+----+
+MCD = Manufacturer ID
+MSN = Manufacturer SerialNumber
+60 ea = DCF Low + DCF high
+9f = raw byte which holds the bits for OLE,WRP,WRC,RD
+ff = unknown but important
+00 = unimportant
+11 = unknown but important
+Bck = header-backup-area
+00 00 = Year (00 = 2000) & Week (not important)
+Seg = Segment Header
+SegC = Crc8 over the Segment Header
+Stp = Stamp (could be more as 4 - up to 7)
+UID = dec User-ID for online-Mapping
+kghC = crc8 over MCD + MSN0..MSN2 + UID
+
+
+(example) Legic-Cash on MIM256/1024 tag' (37 bytes)
+ +----+----+----+----+----+----+----+----+
+ 0x00|Seg0|Seg1|Seg2|Seg3|SegC|STP0|STP1|STP2|
+ +----+----+----+----+----+----+----+----+
+ 0x08|STP3|STP4|STP5|STP6| 01 |CURh|CURl|LIMh|
+ +----+----+----+----+----+----+----+----+
+ 0x10|LIMm|LIMl|CHKh|CHKl|BALh|BALm|BALl|LRBh|
+ +----+----+----+----+----+----+----+----+
+ 0x18|LRBm|LRBl|CHKh|CHKl|SHDh|SHDm|SHDl|LRSh|
+ +----+----+----+----+----+----+----+----+
+ 0x20|LRSm|LRSl| CV |CHKh|CHKl|
+ +----+----+----+----+----+
+STP = Stamp (seems to be always 7 bytes)
+01 = unknown but important
+CUR = currency in HEX (ISO 4217)
+LIM = Cash-Limit
+CHK = crc16 over byte-addr 0x05..0x12
+BAL = Balance
+LRB = ID of the reader that changed the balance
+CHK = crc16 over BAL + LRB
+SHD = shadow Balance
+LRS = ID of the reader that changed the shadow balance (?? should be always the same as LRB)
+CV = Counter value for transactions
+CHK = crc16 over SHD + LRS + CV
--]]
example = "script run legic"
author = "Mosci"
+version = "1.0.1"
desc =
[[
This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024)
it's kinda interactive with following commands in three categories:
- Data I/O Segment Manipulation File I/O
------------------- -------------------- ---------------
- rt => read Tag ds => dump Segments lf => load File
- wt => write Tag as => add Segment sf => save File
- ct => copy io Tag es => edit Segment xf => xor File
- tc => copy oi Tag ed => edit Data
- di => dump inTag rs => remove Segment
- do => dump outTag cc => check Segment-CRC
- ck => check KGH
- tk => toggle KGH-Flag
- q => quit xc => get KGH-Str h => this Help
+ Data I/O Segment Manipulation Token-Data
+ ----------------- -------------------- -----------------
+ rt => read Tag as => add Segment mt => make Token
+ wt => write Tag es => edit Segment Header et => edit Token data
+ ct => copy io Tag ed => edit Segment Data tk => toggle KGH-Flag
+ tc => copy oi Tag rs => remove Segment
+ cc => check Segment-CRC File I/O
+ di => dump inTag ck => check KGH -----------------
+ do => dump outTag lf => load File
+ ds => dump Segments sf => save File
+ lc => dump Legic-Cash xf => xor to File
+ d3p => dump 3rd Party Cash
+ r3p => raw 3rd Party Cash
+
- Data I/O
rt: 'read tag' - reads a tag placed near to the PM3
wt: 'write tag' - writes the content of the 'virtual inTag' to a tag placed near to th PM3
without the need of changing anything - MCD,MSN,MCC will be read from the tag
tc: 'copy tag' - copy the 'second virtual Tag' to 'virtual TAG' - not usefull yet, but inernally needed
di: 'dump inTag' - shows the current content of the 'virtual Tag'
do: 'dump outTag' - shows the current content of the 'virtual outTag'
-
- Segment Manipulation
- (all manipulations happens only in the 'virtual inTAG' - they need to be written with 'wt' to take effect)
ds: 'dump Segments' - will show the content of a selected Segment
as: 'add Segment' - will add a 'empty' Segment to the inTag
es: 'edit Segment' - edit the Segment-Header of a selected Segment (len, WRP, WRC, RD, valid)
all other Segment-Header-Values are either calculated or not needed to edit (yet)
- ed: 'edit data' - edit the Data of a Segment (Stamp & Payload)
+ ed: 'edit data' - edit the Data of a Segment (ADF-Aera / Stamp & Payload specific Data)
+ et: 'edit Token' - edit Data of a Token (CDF-Area / SAM, SAM64, SAM63, IAM, GAM specific Data)
+ mt: 'make Token' - create a Token 'from scratch' (guided)
rs: 'remove segment' - removes a Segment (except Segment 00, but this can be set to valid=0 for Master-Token)
cc: 'check Segment-CRC'- checks & calculates (if check failed) the Segment-CRC of all Segments
ck: 'check KGH-CRC' - checks the and calculates a 'Kaba Group Header' if one was detected
'Kaba Group Header CRC calculation'
tk: 'toggle KGH' - toglle the (script-internal) flag for kgh-calculation for a segment
xc: 'etra c' - show string that was used to calculate the kgh-crc of a segment
-
- Input/Output
+dlc: 'dump Legic-Cash' - show balance and checksums of a legic-Cash Segment
+d3p: 'dump 3rd Party' - show balance, history and checksums of a (yet) unknown 3rd Party Cash-Segment
+r3p: 'raw 3rd Party' - show balance, history and checksums of a (yet) unknown 3rd Party Cash-Segment
+e3p: 'edit 3rd Party' - edit Data in 3rd Party Cash Segment
lf: 'load file' - load a (xored) file from the local Filesystem into the 'virtual inTag'
sf: 'save file' - saves the 'virtual inTag' to the local Filesystem (xored with Tag-MCC)
xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values)
]]
-
---- requirements
+currentTag="inTAG"
+---
+-- requirements
local utils = require('utils')
local getopt = require('getopt')
---- global variables / defines
+---
+-- global variables / defines
local bxor = bit32.bxor
local bbit = bit32.extract
local input = utils.input
local confirm = utils.confirm
---- Error-Handling & Helper
+---
+-- curency-codes for Legic-Cash-Segments (ISO 4217)
+local currency = {
+ ["03d2"]="EUR",
+ ["0348"]="USD",
+ ["033A"]="GBP",
+ ["02F4"]="CHF"
+}
+
+---
-- This is only meant to be used when errors occur
function oops(err)
print("ERROR: ",err)
-- Usage help
function help()
print(desc)
+ print(version)
print("Example usage")
print(example)
end
end
---
--- put certain bytes into a new table
-function bytesToTable(bytes, bstart, bend)
- local t={}
- for i=0, (bend-bstart) do
- t[i]=bytes[bstart+i]
- end
- return t
-end
-
----
--- xor byte (if addr >= 0x22 - start counting from 1 => 23)
+-- xor single byte
function xorme(hex, xor, index)
if ( index >= 23 ) then
return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) ))
---
-- write bytes to file
--- write to file
function writeFile(bytes, filename)
if (filename~='MylegicClone.hex') then
if (file_check(filename)) then
return true
end
+---
+-- put certain bytes into a new table
+function bytesToTable(bytes, bstart, bend)
+ local t={}
+ for i=0, (bend-bstart) do
+ t[i]=bytes[bstart+i]
+ end
+ return t
+end
+
---
-- read from pm3 into virtual-tag
function readFromPM3()
--else return print("user abort"); end
end
+---
+-- write virtual Tag to real Tag
+function writeToTag(plainBytes, taglen, filename)
+ local bytes
+ if(utils.confirm("\nplace your empty tag onto the PM3 to read & write\n") == false) then
+ return
+ end
+
+ -- write data to file
+ if (taglen > 0) then
+ WriteBytes = utils.input("enter number of bytes to write?", taglen)
+
+ -- load file into pm3-buffer
+ if (type(filename)~="string") then filename=input("filename to load to pm3-buffer?","legic.temp") end
+ cmd = 'hf legic load '..filename
+ core.console(cmd)
+
+ -- write pm3-buffer to Tag
+ for i=0, WriteBytes do
+ if ( i<5 or i>6) then
+ cmd = ('hf legic write 0x%02x 0x01'):format(i)
+ core.console(cmd)
+ --print(cmd)
+ elseif (i == 6) then
+ -- write DCF in reverse order (requires 'mosci-patch')
+ cmd = 'hf legic write 0x05 0x02'
+ core.console(cmd)
+ --print(cmd)
+ else
+ print("skipping byte 0x05 - will be written next step")
+ end
+ utils.Sleep(0.2)
+ end
+ end
+end
+
---
-- read file into table
function getInputBytes(infile)
end
---
--- read Tag-Table in bytes-table
-function tagToBytes(tag)
- if (istable(tag)) then
- local bytes = {}
- local i, i2
- -- main token-data
- table.insert(bytes, tag.MCD)
- table.insert(bytes, tag.MSN0)
- table.insert(bytes, tag.MSN1)
- table.insert(bytes, tag.MSN2)
- table.insert(bytes, tag.MCC)
- table.insert(bytes, tag.DCFl)
- table.insert(bytes, tag.DCFh)
- table.insert(bytes, tag.raw)
- table.insert(bytes, tag.SSC)
- -- raw token data
- for i=0, #tag.data do
- table.insert(bytes, tag.data[i])
- end
- -- backup data
- for i=0, #tag.Bck do
- table.insert(bytes, tag.Bck[i])
- end
- -- token-create-time / master-token crc
- for i=0, #tag.MTC do
- table.insert(bytes, tag.MTC[i])
- end
- -- process segments
- if (type(tag.SEG[0])=='table') then
- for i=0, #tag.SEG do
- for i2=1, #tag.SEG[i].raw+1 do
- table.insert(bytes, #bytes+1, tag.SEG[i].raw[i2])
- end
- table.insert(bytes, #bytes+1, tag.SEG[i].crc)
- for i2=0, #tag.SEG[i].data-1 do
- table.insert(bytes, #bytes+1, tag.SEG[i].data[i2])
- end
- end
- end
- -- fill with zeros
- for i=#bytes+1, 1024 do
- table.insert(bytes, i, '00')
- end
- print(#bytes.." bytes of Tag dumped")
- return bytes
- end
- return oops("tag is no table in tagToBytes ("..type(tag)..")")
-end
-
---- virtual TAG functions
-- create tag-table helper
function createTagTable()
local t={
if (tag.Type=="SAM" and #bytes>23) then
tag=segmentsToTag(bytes, tag)
print((#tag.SEG+1).." Segment(s) found")
+ -- unsegmented Master-Token
+ -- only tag-data
+ else
+ for i=0, #tag.Bck do
+ table.insert(tag.data, tag.Bck[i])
+ end
+ tag.data[#tag.data]=tag.MTC[0]
+ tag.Bck=nil
+ --tag.MTC[0]=tag.MTC[1]
+ --tag.MTC[1]=nil
end
print(#bytes.." bytes for Tag processed")
return tag
end
---
--- dump tag-system area
-function dumpCDF(tag)
- local res=""
- local i=0
- local raw=""
+-- read Tag-Table in bytes-table
+function tagToBytes(tag)
if (istable(tag)) then
- res = res.."MCD: "..tag.MCD..", MSN: "..tag.MSN0.." "..tag.MSN1.." "..tag.MSN2..", MCC: "..tag.MCC.."\n"
- res = res.."DCF: "..tag.DCFl.." "..tag.DCFh..", Token_Type="..tag.Type.." (OLE="..tag.OLE.."), Stamp_len="..tag.Stamp_len.."\n"
- res = res.."WRP="..tag.WRP..", WRC="..tag.WRC..", RD="..tag.RD..", raw="..tag.raw..", SSC="..tag.SSC.."\n"
-
- -- credential
- if (tag.raw..tag.SSC=="9fff") then
- res = res.."Remaining Header Area\n"
- for i=0, (#tag.data) do
- res = res..tag.data[i].." "
+ local bytes = {}
+ local i, i2
+ -- main token-data
+ table.insert(bytes, tag.MCD)
+ table.insert(bytes, tag.MSN0)
+ table.insert(bytes, tag.MSN1)
+ table.insert(bytes, tag.MSN2)
+ table.insert(bytes, tag.MCC)
+ table.insert(bytes, tag.DCFl)
+ table.insert(bytes, tag.DCFh)
+ table.insert(bytes, tag.raw)
+ table.insert(bytes, tag.SSC)
+ -- raw token data
+ for i=0, #tag.data do
+ table.insert(bytes, tag.data[i])
end
- res = res.."\nBackup Area\n"
- for i=0, (#tag.Bck) do
- res = res..tag.Bck[i].." "
+ -- backup data
+ if(istable(tag.Bck)) then
+ for i=0, #tag.Bck do
+ table.insert(bytes, tag.Bck[i])
end
- res = res.."\nTime Area\n"
- for i=0, (#tag.MTC) do
- res = res..tag.MTC[i].." "
end
-
- -- Master Token
- else
- res = res .."Master-Token Area\n"
- for i=0, (#tag.data) do
- res = res..tag.data[i].." "
+ -- token-create-time / master-token crc
+ for i=0, #tag.MTC do
+ table.insert(bytes, tag.MTC[i])
end
- for i=0, (#tag.Bck) do
- res = res..tag.Bck[i].." "
+ -- process segments
+ if (type(tag.SEG[0])=='table') then
+ for i=0, #tag.SEG do
+ for i2=1, #tag.SEG[i].raw+1 do
+ table.insert(bytes, #bytes+1, tag.SEG[i].raw[i2])
end
- for i=0, (#tag.MTC-1) do
- res = res..tag.MTC[i].." "
+ table.insert(bytes, #bytes+1, tag.SEG[i].crc)
+ for i2=0, #tag.SEG[i].data-1 do
+ table.insert(bytes, #bytes+1, tag.SEG[i].data[i2])
end
- res = res .. " MT-CRC: "..tag.MTC[1]
end
- return res
- else print("no valid Tag in dumpCDF") end
+end
+ -- fill with zeros
+ for i=#bytes+1, 1024 do
+ table.insert(bytes, i, '00')
+ end
+ print(#bytes.." bytes of Tag dumped")
+ return bytes
+ end
+ return oops("tag is no table in tagToBytes ("..type(tag)..")")
end
---
--- dump single segment
-function dumpSegment(tag, index)
- local i=index
- local i2
- local dp=0 --data-position in table
- local res="" --result
- local raw="" --raw-header
- -- segment
- if ( (istable(tag.SEG[i])) and tag.Type=="SAM") then
- if (istable(tag.SEG[i].raw)) then
- for k,v in pairs(tag.SEG[i].raw) do
- raw=raw..v.." "
+-- make token
+function makeToken()
+ local mt={
+ ['Type'] = {"SAM", "SAM63", "SAM64", "IAM", "GAM"},
+ ['DCF'] = {"60ea", "31fa", "30fa", "80fa", "f0fa"},
+ ['WRP'] = {"15", "2", "2", "2", "2"},
+ ['WRC'] = {"01", "02", "02", "00", "00"},
+ ['RD'] = {"01", "00", "00", "00", "00"},
+ ['Stamp'] = {"00", "00", "00", "00", "00"},
+ ['Segment'] = {"0d", "c0", "04", "00", "be", "01", "02", "03", "04", "01", "02", "03", "04"}
+ }
+ ttype=""
+ for k, v in pairs(mt.Type) do
+ ttype=ttype..k..") "..v.." "
end
+ mtq=tonumber(input("select number for Token-Type\n"..ttype, '1'), 10)
+ if (type(mtq)~="number") then return print("selection invalid!")
+ elseif (mtq>#mt.Type) then return print("selection invalid!")
+ else print("Token-Type '"..mt.Type[mtq].."' selected") end
+ local raw=calcHeaderRaw(mt.WRP[mtq], mt.WRC[mtq], mt.RD[mtq])
+ local mtCRC="00"
+
+ bytes={"01", "02", "03", "04", "cb", string.sub(mt.DCF[mtq], 0, 2), string.sub(mt.DCF[mtq], 3), raw,
+ "00", "00", "00", "00", "00", "00", "00", "00",
+ "00", "00", "00", "00", "00", "00"}
+ if (mtq==1) then
+ for i=0, #mt.Segment do
+ table.insert(bytes, mt.Segment[i])
end
-
- -- segment header
- res = res.."Segment "..("%02d"):format(tag.SEG[i].index)..": "
- res = res .."raw header:"..string.sub(raw,0,-2)..", flag="..tag.SEG[i].flag..", (valid="..("%x"):format(tag.SEG[i].valid)..", last="..("%x"):format(tag.SEG[i].last).."), "
- res = res .."len="..("%04d"):format(tag.SEG[i].len)..", WRP="..("%02x"):format(tag.SEG[i].WRP)..", WRC="..("%02x"):format(tag.SEG[i].WRC)..", "
- res = res .."RD="..("%02x"):format(tag.SEG[i].RD)..", CRC="..tag.SEG[i].crc.." "
- res = res .."("..(checkSegmentCrc(tag, i) and "valid" or "error")..")"
- raw=""
-
- -- WRC protected
- if (tag.SEG[i].WRC>0) then
- res = res .."\nWRC protected area (Stamp):\n"
- for i2=dp, tag.SEG[i].WRC-1 do
- res = res..tag.SEG[i].data[dp].." "
- dp=dp+1
+ bytes[9]="ff"
end
+ -- fill bytes
+ for i=#bytes, 1023 do table.insert(bytes, "00") end
+ -- if Master-Token -> calc Master-Token-CRC
+ if (mtq>1) then bytes[22]=calcMtCrc(bytes) end
+ local tempTag=createTagTable()
+ -- remove segment if MasterToken
+ if (mtq>1) then tempTag.SEG[0]=nil end
+ return bytesToTag(bytes, tempTag)
end
- -- WRP mprotected
- if (tag.SEG[i].WRP>tag.SEG[i].WRC) then
- res = res .."\nRemaining write protected area (Stamp):\n"
- for i2=dp, tag.SEG[i].WRP-tag.SEG[i].WRC-1 do
- res = res..tag.SEG[i].data[dp].." "
- dp=dp+1
+---
+-- edit token-data
+function editTag(tag)
+ -- for simulation it makes sense to edit everything
+ local edit_sim="MCD MSN0 MSN1 MSN2 MCC DCFl DCFh WRP WRC RD"
+ -- on real tags it makes only sense to edit DCF, WRP, WRC, RD
+ local edit_real="DCFl DCFh WRP WRC RD"
+ if (confirm("do you want to edit non-writeable values (e.g. for simulation)?")) then
+ edit_tag=edit_sim
+ else edit_tag=edit_real end
+
+ if(istable(tag)) then
+ for k,v in pairs(tag) do
+ if(type(v)~="table" and type(v)~="boolean" and string.find(edit_tag, k)) then
+ tag[k]=input("value for: "..k, v)
end
end
- -- payload
- if (#tag.SEG[i].data-dp>0) then
- res = res .."\nRemaining segment payload:\n"
- for i2=dp, #tag.SEG[i].data-2 do
- res = res..tag.SEG[i].data[dp].." "
- dp=dp+1
+ if (tag.Type=="SAM") then ttype="Header"; else ttype="Stamp"; end
+ if (confirm("do you want to edit "..ttype.." Data?")) then
+ -- master-token specific
+ if(istable(tag.Bck)==false) then
+ -- stamp-data length=(0xfc-DCFh)
+ -- on MT: SSC holds the Starting Stamp Character (Stamp0)
+ tag.SSC=input(ttype.."0: ", tag.SSC)
+ -- rest of stamp-bytes are in tag.data 0..n
+ for i=0, (tonumber(0xfc ,10)-("%d"):format('0x'..tag.DCFh))-2 do
+ tag.data[i]=input(ttype.. i+1 ..": ", tag.data[i])
end
- if (tag.SEG[i].kgh) then
- res = res..tag.SEG[i].data[dp].." (KGH: "..(checkKghCrc(tag, i) and "valid" or "error")..")"
- else res = res..tag.SEG[i].data[dp] end
- end
- dp=0
- return res
else
- return print("Segment not found")
+ --- on credentials byte7 should always be 9f and byte8 ff
+ -- on Master-Token not (even on SAM63/64 not)
+ -- tag.SSC=input(ttype.."0: ", tag.SSC)
+ for i=0, #tag.data do
+ tag.data[i]=input(ttype.. i ..": ", tag.data[i])
+ end
+end
end
+
+ bytes=tagToBytes(tag)
+
+ --- check data-consistency (calculate tag.raw)
+ bytes[8]=calcHeaderRaw(tag.WRP, tag.WRC, tag.RD)
+
+ --- Master-Token specific
+ -- should be triggered if a SAM was converted to a non-SAM (user-Token to Master-Token)
+ -- or a Master-Token has being edited (also SAM64 & SAM63 - which are in fact Master-Token)
+ if(tag.Type~="SAM" or bytes[6]..bytes[7]~="60ea") then
+ -- calc new Master-Token crc
+ bytes[22]=calcMtCrc(bytes)
+ else
+ -- ensure tag.SSC set to 'ff' on credential-token (SAM)
+ bytes[9]='ff'
+ -- if a Master-Token was converted to a Credential-Token
+ -- lets unset the Time-Area to 00 00 (will contain Stamp-Data on MT)
+ bytes[21]='00'
+ bytes[22]='00'
end
----
--- check all segmnet-crc
-function checkAllSegCrc(tag)
- for i=0, #tag.SEG do
- crc=calcSegmentCrc(tag, i)
- tag.SEG[i].crc=crc
+ tag=bytesToTag(bytes, tag)
end
end
---
--- check all segmnet-crc
-function checkAllKghCrc(tag)
- for i=0, #tag.SEG do
- crc=calcKghCrc(tag, i)
- if (tag.SEG[i].kgh) then
- tag.SEG[i].data[#tag.SEG[i].data-1]=crc
- end
- end
+-- calculates header-byte (addr 0x07)
+function calcHeaderRaw(wrp, wrc, rd)
+ local res
+ wrp=("%02x"):format(tonumber(wrp, 10))
+ rd=tonumber(rd, 16)
+ res=("%02x"):format(tonumber(wrp, 16)+tonumber(wrc.."0", 16)+((rd>0) and tonumber("8"..(rd-1), 16) or 0))
+ return res
end
---
-- sytstem area
res ="\nCDF: System Area"
res= res.."\n"..dumpCDF(tag)
- -- segments (user area)
- if(istable(tag.SEG[0])) then
+ -- segments (user-token area)
+ if(tag.Type=="SAM") then
res = res.."\n\nADF: User Area"
for i=0, #tag.SEG do
res=res.."\n"..dumpSegment(tag, i).."\n"
return res
end
----
--- determine TagType (bits 0..6 of DCFlow)
-function getTokenType(DCFl)
- --[[
- 0x00–0x2f IAM
- 0x30–0x6f SAM
- 0x70–0x7f GAM
- ]]--
- local tt = tonumber(bbit("0x"..DCFl,0,7),10)
- if (tt >= 0 and tt <= 47) then tt = "IAM"
- elseif (tt == 49) then tt = "SAM63"
- elseif (tt == 48) then tt = "SAM64"
- elseif (tt >= 50 and tt <= 111) then tt = "SAM"
- elseif (tt >= 112 and tt <= 127) then tt = "GAM"
- else tt = "???" end
- return tt
-end
-
----
--- regenerate segment-header (after edit)
-function regenSegmentHeader(segment)
- local seg=segment
- local raw = segment.raw
- local i
- -- len bit0..7 | len=12bit=low nibble of byte1..byte0
- raw[1]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),0,8))
- -- high nibble of len bit6=valid , bit7=last of byte 1 | ?what are bit 5+6 for? maybe kgh?
- raw[2]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),4.4)..bbit("0x"..("%02x"):format((seg.valid*64)+(seg.last*128)),0,8))
- -- WRP
- raw[3]=("%02x"):format(bbit("0x"..("%02x"):format(seg.WRP),0,8))
- -- WRC + RD
- raw[4]=("%02x"):format(bbit("0x"..("%03x"):format(seg.WRC),4,3)..bbit("0x"..("%02x"):format(seg.RD*128),0,8))
- -- flag
- seg.flag=string.sub(raw[2],0,1)
- --print(raw[1].." "..raw[2].." "..raw[3].." "..raw[4])
- if(#seg.data>(seg.len-5)) then
- print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5)
- print("Data-Length has being reduced: removing ".. #seg.data-(seg.len-5) .." bytes from Payload");
- for i=(seg.len-5), #seg.data-1 do
- table.remove(seg.data)
- end
- elseif (#seg.data<(seg.len-5)) then
- print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5)
- print("Data-Length has being extended: adding "..(seg.len-5)-#seg.data.." bytes to Payload");
- for i=#seg.data, (seg.len-5)-1 do
- table.insert(seg.data, '00')
- end
- end
- return seg
-end
-
---
-- get segmemnt-data from byte-table
function getSegmentData(bytes, start, index)
else print("no Segments: must be a MIM22") end
end
---- CRC calculation and validation
--- build kghCrc credentials
-function kghCrcCredentials(tag, segid)
- local x='00'
- if (type(segid)=="string") then segid=tonumber(segid,10) end
- if (segid>0) then x='93' end
- local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2..("%02x"):format(tag.SEG[segid].WRP)
- cred = cred..("%02x"):format(tag.SEG[segid].WRC)..("%02x"):format(tag.SEG[segid].RD)..x
- for i=0, #tag.SEG[segid].data-2 do
- cred = cred..tag.SEG[segid].data[i]
- end
- return cred
-end
-
---
--- validate kghCRC to segment in tag-table
-function checkKghCrc(tag, segid)
- if (type(tag.SEG[segid])=='table') then
- if (tag.data[3]=="11" and tag.raw=="9f" and tag.SSC=="ff") then
- local data=kghCrcCredentials(tag, segid)
- if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].data[tag.SEG[segid].len-5-1]) then return true; end
- else return false; end
- else oops("'Kaba Group header' detected but no Segment-Data found") end
-end
-
----
--- calcuate kghCRC for a given segment
-function calcKghCrc(tag, segid)
- -- check if a 'Kaber Group Header' exists
+-- regenerate segment-header (after edit)
+function regenSegmentHeader(segment)
+ local seg=segment
+ local raw = segment.raw
local i
- local data=kghCrcCredentials(tag, segid)
- return ("%02x"):format(utils.Crc8Legic(data))
+ -- len bit0..7 | len=12bit=low nibble of byte1..byte0
+ raw[1]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),0,8))
+ -- high nibble of len bit6=valid , bit7=last of byte 1 | ?what are bit 5+6 for? maybe kgh?
+ raw[2]=("%02x"):format(bbit("0x"..("%03x"):format(seg.len),4.4)..bbit("0x"..("%02x"):format((seg.valid*64)+(seg.last*128)),0,8))
+ -- WRP
+ raw[3]=("%02x"):format(bbit("0x"..("%02x"):format(seg.WRP),0,8))
+ -- WRC + RD
+ raw[4]=("%02x"):format(bbit("0x"..("%03x"):format(seg.WRC),4,3)..bbit("0x"..("%02x"):format(seg.RD*128),0,8))
+ -- flag
+ seg.flag=string.sub(raw[2],0,1)
+ --print(raw[1].." "..raw[2].." "..raw[3].." "..raw[4])
+ if(#seg.data>(seg.len-5)) then
+ print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5)
+ print("Data-Length has being reduced: removing ".. #seg.data-(seg.len-5) .." bytes from Payload");
+ for i=(seg.len-5), #seg.data-1 do
+ table.remove(seg.data)
end
-
----
--- build segmentCrc credentials
-function segmentCrcCredentials(tag, segid)
- local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
- cred = cred ..tag.SEG[segid].raw[1]..tag.SEG[segid].raw[2]..tag.SEG[segid].raw[3]..tag.SEG[segid].raw[4]
- return cred
+ elseif (#seg.data<(seg.len-5)) then
+ print("current payload: ".. #seg.data .." - desired payload: ".. seg.len-5)
+ print("Data-Length has being extended: adding "..(seg.len-5)-#seg.data.." bytes to Payload");
+ for i=#seg.data, (seg.len-5)-1 do
+ table.insert(seg.data, '00')
end
-
----
--- validate segmentCRC for a given segment
-function checkSegmentCrc(tag, segid)
- local data=segmentCrcCredentials(tag, segid)
- if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].crc) then
- return true
- end
- return false
+ end
+ return seg
end
---
--- calculate segmentCRC for a given segment
-function calcSegmentCrc(tag, segid)
- -- check if a 'Kaber Group Header' exists
- local data=segmentCrcCredentials(tag, segid)
- return ("%02x"):format(utils.Crc8Legic(data))
-end
-
---- create master-token
+-- determine TagType (bits 0..6 of DCFlow)
+function getTokenType(DCFl)
+ --[[
+ 0x00–0x2f IAM
+ 0x30–0x6f SAM
+ 0x70–0x7f GAM
+ ]]--
+ local tt = tonumber(bbit("0x"..DCFl,0,7),10)
+ if (tt >= 0 and tt <= 47) then tt = "IAM"
+ elseif (tt == 49) then tt = "SAM63"
+ elseif (tt == 48) then tt = "SAM64"
+ elseif (tt >= 50 and tt <= 111) then tt = "SAM"
+ elseif (tt >= 112 and tt <= 127) then tt = "GAM"
+ else tt = "???" end
+ return tt
+ end
---
--- write virtual Tag to real Tag
--- write clone-data to tag
-function writeToTag(plainBytes, taglen, filename)
+-- dump tag-system area
+function dumpCDF(tag)
+ local res=""
+ local i=0
+ local raw=""
local bytes
- if(utils.confirm("\nplace your empty tag onto the PM3 to read & write\n") == false) then
- return
+ if (istable(tag)) then
+ res = res.."MCD: "..tag.MCD..", MSN: "..tag.MSN0.." "..tag.MSN1.." "..tag.MSN2..", MCC: "..tag.MCC.."\n"
+ res = res.."DCF: "..tag.DCFl.." "..tag.DCFh..", Token_Type="..tag.Type.." (OLE="..tag.OLE.."), Stamp_len="..tag.Stamp_len.."\n"
+ res = res.."WRP="..tag.WRP..", WRC="..tag.WRC..", RD="..tag.RD..", raw="..tag.raw..((tag.raw=='9f') and (", SSC="..tag.SSC.."\n") or "\n")
+
+ -- credential (end-user tag)
+ if (tag.Type=="SAM") then
+ res = res.."Remaining Header Area\n"
+ for i=0, (#tag.data) do
+ res = res..tag.data[i].." "
end
-
- -- write data to file
- if (taglen > 0) then
- WriteBytes = utils.input("enter number of bytes to write?", taglen)
-
- -- load file into pm3-buffer
- if (type(filename)~="string") then filename=input("filename to load to pm3-buffer?","legic.temp") end
- cmd = 'hf legic load '..filename
- core.console(cmd)
-
- -- write pm3-buffer to Tag
- for i=0, WriteBytes do
- if ( i<5 or i>6) then
- cmd = ('hf legic write 0x%02x 0x01'):format(i)
- core.console(cmd)
- --print(cmd)
- elseif (i == 6) then
- -- write DCF in reverse order (requires 'mosci-patch')
- cmd = 'hf legic write 0x05 0x02'
- core.console(cmd)
- --print(cmd)
+ res = res.."\nBackup Area\n"
+ for i=0, (#tag.Bck) do
+ res = res..tag.Bck[i].." "
+ end
+ res = res.."\nTime Area\n"
+ for i=0, (#tag.MTC) do
+ res = res..tag.MTC[i].." "
+ end
+
+ -- Master Token specific
else
- print("skipping byte 0x05 - will be written next step")
+ res = res .."Master-Token Area\nStamp: "
+ res= res..tag.SSC.." "
+ for i=0, tag.Stamp_len-2 do
+ res = res..tag.data[i].." "
end
- utils.Sleep(0.2)
+ res=res.."\nunused payload\n"
+ for i=0, (#tag.data-tag.Stamp_len-1) do
+ res = res..tag.data[i].." "
end
+ bytes=tagToBytes(tag)
+ local mtcrc=calcMtCrc(bytes)
+ res=res.."\nMaster-Token CRC: "
+ res = res ..tag.MTC[1].." ("..((tag.MTC[1]==mtcrc) and "valid" or "error")..")"
+ end
+ return res
+ else print("no valid Tag in dumpCDF") end
+end
+
+---
+-- dump single segment
+function dumpSegment(tag, index)
+ local i=index
+ local i2
+ local dp=0 --data-position in table
+ local res="" --result
+ local raw="" --raw-header
+ -- segment
+ if ( (istable(tag.SEG[i])) and tag.Type=="SAM") then
+ if (istable(tag.SEG[i].raw)) then
+ for k,v in pairs(tag.SEG[i].raw) do
+ raw=raw..v.." "
+ end
+ end
+
+ -- segment header
+ res = res.."Segment "..("%02d"):format(tag.SEG[i].index)..": "
+ res = res .."raw header:"..string.sub(raw,0,-2)..", flag="..tag.SEG[i].flag..", (valid="..("%x"):format(tag.SEG[i].valid)..", last="..("%x"):format(tag.SEG[i].last).."), "
+ res = res .."len="..("%04d"):format(tag.SEG[i].len)..", WRP="..("%02x"):format(tag.SEG[i].WRP)..", WRC="..("%02x"):format(tag.SEG[i].WRC)..", "
+ res = res .."RD="..("%02x"):format(tag.SEG[i].RD)..", CRC="..tag.SEG[i].crc.." "
+ res = res .."("..(checkSegmentCrc(tag, i) and "valid" or "error")..")"
+ raw=""
+
+ -- WRC protected
+ if (tag.SEG[i].WRC>0) then
+ res = res .."\nWRC protected area:\n"
+ for i2=dp, tag.SEG[i].WRC-1 do
+ res = res..tag.SEG[i].data[dp].." "
+ dp=dp+1
+ end
+ end
+
+ -- WRP mprotected
+ if ((tag.SEG[i].WRP-tag.SEG[i].WRC)>0) then
+ res = res .."\nRemaining write protected area:\n"
+ for i2=dp, (tag.SEG[i].WRP-tag.SEG[i].WRC)-1 do
+ res = res..tag.SEG[i].data[dp].." "
+ dp=dp+1
+ end
+ end
+
+ -- payload
+ if (#tag.SEG[i].data-dp>0) then
+ res = res .."\nRemaining segment payload:\n"
+ for i2=dp, #tag.SEG[i].data-2 do
+ res = res..tag.SEG[i].data[dp].." "
+ dp=dp+1
+ end
+ if (tag.SEG[i].kgh) then
+ res = res..tag.SEG[i].data[dp].." (KGH: "..(checkKghCrc(tag, i) and "valid" or "error")..")"
+ else res = res..tag.SEG[i].data[dp] end
+ end
+ dp=0
+ return res
+ else
+ return print("Segment not found")
end
end
---
-- edit Segment Data
function editSegmentData(data)
+ local lc=check4LegicCash(data)
+ io.write("\n")
if (istable(data)) then
for i=0, #data-1 do
data[i]=input("Data"..i..": ", data[i])
end
+ if (lc) then data=fixLegicCash(data) end
return data
else
print("no Segment-Data found")
-- helper to selecting a segment
function selectSegment(tag)
local sel
- if (istable(tag)) then
+ if (istable(tag.SEG[0])) then
print("availabe Segments:\n"..segmentList(tag))
sel=input("select Segment: ", '00')
sel=tonumber(sel,10)
end
---
---
+-- delete segment (except segment 00)
function delSegment(tag, index)
+ if (istable(tag.SEG[0])) then
local i
if (type(index)=="string") then index=tonumber(index,10) end
if (index > 0) then
if(istable(tag.SEG[#tag.SEG])) then tag.SEG[#tag.SEG].last=1 end
return tag
end
+end
+
+---
+-- return bytes 'sstrat' to 'send' from a table
+function dumpTable(tab, header, tstart, tend)
+ res=""
+ for i=tstart, tend do
+ res=res..tab[i].." "
+ end
+ if (string.len(header)==0) then return res
+ else return (header.." #"..(tend-tstart+1).."\n"..res) end
+end
+
+function dump3rdPartyCash1(tag , seg)
+ local uid=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ local stamp=tag.SEG[seg].data[0].." "..tag.SEG[seg].data[1].." "..tag.SEG[seg].data[2]
+ local datastamp=tag.SEG[seg].data[20].." "..tag.SEG[seg].data[21].." "..tag.SEG[seg].data[22]
+ local balance=tonumber(tag.SEG[seg].data[32]..tag.SEG[seg].data[33] ,16)
+ local balancecrc=utils.Crc8Legic(uid..tag.SEG[seg].data[32]..tag.SEG[seg].data[33])
+ local mirror=tonumber(tag.SEG[seg].data[35]..tag.SEG[seg].data[36] ,16)
+ local mirrorcrc=utils.Crc8Legic(uid..tag.SEG[seg].data[35]..tag.SEG[seg].data[36])
+ local lastbal0=tonumber(tag.SEG[seg].data[39]..tag.SEG[seg].data[40] ,16)
+ local lastbal1=tonumber(tag.SEG[seg].data[41]..tag.SEG[seg].data[42] ,16)
+ local lastbal2=tonumber(tag.SEG[seg].data[43]..tag.SEG[seg].data[44] ,16)
+
+ test=""
+ -- display decoded/known stuff
+ print("\n------------------------------")
+ print("Tag-ID:\t\t "..uid)
+ print("Stamp:\t\t "..stamp)
+ print("UID-Mapping: \t\t"..("%06d"):format(tonumber(tag.SEG[seg].data[46]..tag.SEG[seg].data[47]..tag.SEG[seg].data[48], 16)))
+ print("------------------------------")
+ print("checksum 1:\t\t "..tag.SEG[seg].data[31].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 19, 30)), tag.SEG[seg].data[31])..")")
+ print("checksum 2:\t\t "..tag.SEG[seg].data[34].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 32, 33)), tag.SEG[seg].data[34])..")")
+ print("checksum 3:\t\t "..tag.SEG[seg].data[37].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 35, 36)), tag.SEG[seg].data[37])..")")
+
+ print("checksum 4:\t\t "..tag.SEG[seg].data[55].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 46, 54)), tag.SEG[seg].data[55])..")")
+ print("checksum 5:\t\t "..tag.SEG[seg].data[62].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 56, 61)), tag.SEG[seg].data[62])..")")
+ print("checksum 6:\t\t "..tag.SEG[seg].data[73].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 63, 72)), tag.SEG[seg].data[73])..")")
+ print("checksum 7:\t\t "..tag.SEG[seg].data[89].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(tag.SEG[seg].data, "", 74, 88)), tag.SEG[seg].data[89])..")")
+ print("------------------------------")
+ print(string.format("Balance:\t\t %3.2f", balance/100).." ".."("..compareCrc(balancecrc, tag.SEG[seg].data[34])..")")
+ print(string.format("Shadow:\t\t\t %3.2f", mirror/100).." ".."("..compareCrc(balancecrc, tag.SEG[seg].data[37])..")")
+ print("------------------------------")
+ print(string.format("History 1:\t\t %3.2f", lastbal0/100))
+ print(string.format("History 2:\t\t %3.2f", lastbal1/100))
+ print(string.format("History 3:\t\t %3.2f", lastbal2/100))
+ print("------------------------------\n")
+end
+---
+-- compare two bytes
+function compareCrc(calc, guess)
+ calc=("%02x"):format(calc)
+ if (calc==guess) then return "valid"
+ else return "error "..calc.."!="..guess end
+end
+
+---
+-- compare 4 bytes
+function compareCrc16(calc, guess)
+ calc=("%04x"):format(calc)
+ if (calc==guess) then return "valid"
+ else return "error "..calc.."!="..guess end
+end
+
+---
+-- repair / fix (yet known) crc's of a '3rd Party Cash-Segment'
+-- not all bytes know until yet !!
+function fix3rdPartyCash1(uid, data)
+ if(#data==95) then
+ -- checksum 1
+ data[31]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 19, 30)))
+ -- checksum 2
+ data[34]=("%02x"):format(utils.Crc8Legic(uid..data[32]..data[33]))
+ -- checksum 3
+ data[37]=("%02x"):format(utils.Crc8Legic(uid..data[35]..data[36]))
+ -- checksum 4
+ data[55]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 46, 54)))
+ -- checksum 5
+ data[62]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 56, 61)))
+ -- checksum 6
+ data[73]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 63, 72)))
+ -- checksum 7
+ data[89]=("%02x"):format(utils.Crc8Legic(uid..dumpTable(data, "", 74, 88)))
+ return data
+ end
+end
+
+---
+-- edit uid 3rd party cash
+function edit3rdUid(mapid, uid, data)
+ mapid=("%06x"):format(tonumber(mapid, 10))
+ data[46]=string.sub(mapid, 0 ,2)
+ data[47]=string.sub(mapid, 3 ,4)
+ data[48]=string.sub(mapid, 5 ,6)
+ return fix3rdPartyCash1(uid, data)
+end
+
+---
+-- edit balance 3rd party cash
+function edit3rdCash(new_cash, uid, data)
+ new_cash=("%04x"):format(new_cash)
+ data[32]=string.sub(new_cash, 0,2)
+ data[33]=string.sub(new_cash, 3,4)
+ data[34]=("%02x"):format(utils.Crc8Legic(uid..new_cash))
+ data[35]=string.sub(new_cash, 0,2)
+ data[36]=string.sub(new_cash, 3,4)
+ data[37]=("%02x"):format(utils.Crc8Legic(uid..new_cash))
+ data[39]=string.sub(new_cash, 0,2)
+ data[40]=string.sub(new_cash, 3,4)
+ data[41]='00'
+ data[42]='00'
+ data[43]='00'
+ data[44]='00'
+ return fix3rdPartyCash1(uid, data)
+end
+
+---
+-- repair / fix crc's of a 'Legic-Cash-Segment'
+function fixLegicCash(data)
+ if(#data==32 and data[7]=="01") then
+ local crc1, crc2, crc3
+ crc1=("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12)))
+ crc2=("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20)))
+ crc3=("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29)))
+ data[13]=string.sub(crc1, 0, 2)
+ data[14]=string.sub(crc1, 3, 4)
+ data[21]=string.sub(crc2, 0, 2)
+ data[22]=string.sub(crc2, 3, 4)
+ data[30]=string.sub(crc3, 0, 2)
+ data[31]=string.sub(crc3, 3, 4)
+ return data
+ end
+end
+
+---
+-- chack for signature of a '3rd Party Cash-Segment'
+-- not all bytes know until yet !!
+function check43rdPartyCash1(uid, data)
+ if(#data==95) then
+ -- too explicit checking will avoid fixing ;-)
+ if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 19, 30)), data[31])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..data[32]..data[33]), data[34])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..data[35]..data[36]), data[37])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 56, 61)), data[62])=="valid") then
+ --if (compareCrc(utils.Crc8Legic(uid..dumpTable(data, "", 74, 88)), data[89])=="valid") then
+ io.write("3rd Party Cash-Segment detected ")
+ return true
+ --end
+ --end
+ --end
+ --end
+ end
+ end
+ return false
+end
+
+---
+-- chack for signature of a 'Legic-Cash-Segment'
+function check4LegicCash(data)
+ if(#data==32) then
+ local stamp_len=(#data-25)
+ local stamp=""
+ for i=0, stamp_len-1 do
+ stamp=stamp..data[i].." "
+ end
+ if (data[7]=="01") then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 0, 12))) == data[13]..data[14]) then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 15, 20))) == data[21]..data[22]) then
+ if (("%04x"):format(utils.Crc16(dumpTable(data, "", 23, 29))) == data[30]..data[31]) then
+ io.write("Legic-Cash Segment detected ")
+ return true
+ end
+ end
+ end
+ end
+ end
+ return false
+end
+---
+-- calculate Master-Token crc
+function calcMtCrc(bytes)
+ --print(#bytes)
+ local cmd=bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[7]..bytes[6]..bytes[8]
+ local len=(tonumber(0xfc ,10)-("%d"):format('0x'..bytes[7]))
+ for i=1, len do
+ cmd=cmd..bytes[8+i]
+ end
+ local res=("%02x"):format(utils.Crc8Legic(cmd))
+ return res
+end
+
+---
+-- check all segmnet-crc
+function checkAllSegCrc(tag)
+ if (istable(tag.SEG[0])) then
+ for i=0, #tag.SEG do
+ crc=calcSegmentCrc(tag, i)
+ tag.SEG[i].crc=crc
+ end
+ else return print("Matser-Token / unsegmented Tag") end
+end
+
+---
+-- check all segmnet-crc
+function checkAllKghCrc(tag)
+ if (istable(tag.SEG[0])) then
+ for i=0, #tag.SEG do
+ crc=calcKghCrc(tag, i)
+ if (tag.SEG[i].kgh) then
+ tag.SEG[i].data[#tag.SEG[i].data-1]=crc
+ end
+ end
+ end
+end
+
+---
+-- build kghCrc credentials
+function kghCrcCredentials(tag, segid)
+ if (istable(tag) and istable(tag.SEG[0])) then
+ local x='00'
+ if (type(segid)=="string") then segid=tonumber(segid,10) end
+ if (segid>0) then x='93' end
+ local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2..("%02x"):format(tag.SEG[segid].WRP)
+ cred = cred..("%02x"):format(tag.SEG[segid].WRC)..("%02x"):format(tag.SEG[segid].RD)..x
+ for i=0, #tag.SEG[segid].data-2 do
+ cred = cred..tag.SEG[segid].data[i]
+ end
+ return cred
+ end
+end
+
+---
+-- validate kghCRC to segment in tag-table
+function checkKghCrc(tag, segid)
+ if (type(tag.SEG[segid])=='table') then
+ if (tag.data[3]=="11" and tag.raw=="9f" and tag.SSC=="ff") then
+ local data=kghCrcCredentials(tag, segid)
+ if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].data[tag.SEG[segid].len-5-1]) then return true; end
+ else return false; end
+ else oops("'Kaba Group header' detected but no Segment-Data found") end
+end
+
+---
+-- calcuate kghCRC for a given segment
+function calcKghCrc(tag, segid)
+ if (istable(tag.SEG[0])) then
+ -- check if a 'Kaber Group Header' exists
+ local i
+ local data=kghCrcCredentials(tag, segid)
+ return ("%02x"):format(utils.Crc8Legic(data))
+ end
+end
+
+---
+-- build segmentCrc credentials
+function segmentCrcCredentials(tag, segid)
+ if (istable(tag.SEG[0])) then
+ local cred = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ cred = cred ..tag.SEG[segid].raw[1]..tag.SEG[segid].raw[2]..tag.SEG[segid].raw[3]..tag.SEG[segid].raw[4]
+ return cred
+ else return print("Master-Token / unsegmented Tag!") end
+end
+
+---
+-- validate segmentCRC for a given segment
+function checkSegmentCrc(tag, segid)
+ local data=segmentCrcCredentials(tag, segid)
+ if (("%02x"):format(utils.Crc8Legic(data))==tag.SEG[segid].crc) then
+ return true
+ end
+ return false
+end
+
+---
+-- calculate segmentCRC for a given segment
+function calcSegmentCrc(tag, segid)
+ if (istable(tag.SEG[0])) then
+ -- check if a 'Kaber Group Header' exists
+ local data=segmentCrcCredentials(tag, segid)
+ return ("%02x"):format(utils.Crc8Legic(data))
+ end
+end
---
-- helptext for modify-mode
function modifyHelp()
local t=[[
- Data I/O Segment Manipulation File I/O
------------------- -------------------- ---------------
- rt => read Tag ds => dump Segments lf => load File
- wt => write Tag as => add Segment sf => save File
- ct => copy io Tag es => edit Segment xf => xor File
- tc => copy oi Tag ed => edit Data
- di => dump inTag rs => remove Segment
- do => dump outTag cc => check Segment-CRC
- ck => check KGH
- tk => toggle KGH-Flag
- q => quit xc => get KGH-Str h => this Help
+ Data I/O Segment Manipulation Token-Data
+ ----------------- -------------------- -----------------
+ rt => read Tag as => add Segment mt => make Token
+ wt => write Tag es => edit Segment Header et => edit Token data
+ ct => copy io Tag ed => edit Segment Data tk => toggle KGH-Flag
+ tc => copy oi Tag rs => remove Segment
+ tt => toggle Tag cc => check Segment-CRC File I/O
+ di => dump inTag ck => check KGH -----------------
+ do => dump outTag e3p => edit 3rd Party Cash lf => load File
+ ds => dump Segment sf => save File
+ dlc => dump Legic-Cash xf => xor to File
+ d3p => dump 3rd Party Cash
+ r3p => raw 3rd Party Cash
+
+
+ q => quit
]]
return t
end
+
---
-- modify Tag (interactive)
function modifyMode()
- local i, outTAG, inTAG, outfile, infile, sel, segment, bytes, outbytes
+ local i, backupTAG, outTAG, inTAG, outfile, infile, sel, segment, bytes, outbytes
+
actions = {
["h"] = function(x)
- print(modifyHelp().."\n".."tags im Memory:"..(istable(inTAG) and " inTAG" or "")..(istable(outTAG) and " outTAG" or ""))
+ print(" Version: "..version);
+ print(modifyHelp().."\n".."tags im Memory: "..(istable(inTAG) and ((currentTag=='inTAG') and "*mainTAG" or "mainTAG") or "").." "..(istable(backupTAG) and ((currentTag=='backupTAG') and "*backupTAG" or "backupTAG") or ""))
end,
- ["rt"] = function(x) inTAG=readFromPM3(); actions['di']('') end,
+ ["rt"] = function(x)
+ inTAG=readFromPM3();
+ --actions.di()
+ end,
["wt"] = function(x)
- if(istable(inTAG)) then
+ if(istable(inTAG.SEG)) then
local taglen=22
+ if (istable(inTAG.Bck)) then
for i=0, #inTAG.SEG do
taglen=taglen+inTAG.SEG[i].len+5
end
+ end
+
+ local uid_old=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
-- read new tag (output tag)
outTAG=readFromPM3()
outbytes=tagToBytes(outTAG)
inTAG.MSN1 = outbytes[3]
inTAG.MSN2 = outbytes[4]
inTAG.MCC = outbytes[5]
- -- recheck all segments-crc/kghcrc
+ -- recheck all segments-crc/kghcrc (only on a credential)
+ if(istable(inTAG.Bck)) then
checkAllSegCrc(inTAG)
checkAllKghCrc(inTAG)
+ local uid_new=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ for i=0, #inTAG.SEG do
+ if (check43rdPartyCash1(uid_old, inTAG.SEG[i].data)) then
+ io.write(" - fixing known checksums ... ")
+ inTAG.SEG[i].data=fix3rdPartyCash1(uid_new, inTAG.SEG[i].data)
+ io.write(" done\n")
+ end
+ end
+ end
--get bytes from ready outTAG
bytes=tagToBytes(inTAG)
+ -- mater-token-crc
+ if (inTAG.Type~="SAM") then bytes[22]=calcMtCrc(bytes) end
if (bytes) then
writeFile(bytes, 'MylegicClone.hex')
writeToTag(bytes, taglen, 'MylegicClone.hex')
- actions['rt']('')
+ actions.rt('')
end
end
end,
+ ---
+ -- switich and copy virtual tags
+
["ct"] = function(x)
- print("copy virtual input-TAG to output-TAG")
- outTAG=inTAG
+ print("copy mainTAG to backupTAG")
+ outTAG=deepCopy(inTAG)
+ backupTAG=deepCopy(inTAG)
end,
["tc"] = function(x)
- print("copy virtual output-TAG to input-TAG")
- inTAG=outTAG
+ print("copy backupTAG to mainTAG")
+ inTAG=deepCopy(backupTAG)
+ end,
+ ["tt"] = function(x)
+ print("toggle to "..((currentTag=='inTAG') and "backupTAG" or "mainTAG"))
+ if(currentTag=="inTAG") then
+ outTAG=deepCopy(inTAG)
+ inTAG=deepCopy(backupTAG)
+ currentTag='backupTAG'
+ else
+ inTAG=deepCopy(outTAG)
+ currentTag='inTAG'
+ end
end,
["lf"] = function(x)
- filename=input("enter filename: ", "legic.temp")
+ if (file_check(x)) then filename=x
+ else filename=input("enter filename: ", "legic.temp") end
inTAG=readFile(filename)
end,
["sf"] = function(x)
end
end
end,
- ["di"] = function(x) if (istable(inTAG)) then print("\n"..dumpTag(inTAG).."\n") end end,
- ["do"] = function(x) if (istable(outTAG)) then print("\n"..dumpTag(outTAG).."\n") end end,
+ ["di"] = function(x)
+ if (istable(inTAG)) then
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ if(istable(inTAG.SEG[0])) then
+ for i=0, #inTAG.SEG do
+ if(check43rdPartyCash1(uid, inTAG.SEG[i].data)) then
+ io.write("in Segment index: "..inTAG.SEG[i].index.."\n")
+ elseif(check4LegicCash(inTAG.SEG[i].data)) then
+ io.write("in Segment index: "..inTAG.SEG[i].index.."\n")
+ lc=true;
+ lci=inTAG.SEG[i].index;
+ end
+ end
+ end
+ print("\n"..dumpTag(inTAG).."\n")
+ if (lc) then actions["dlc"](lci) end
+ end
+ end,
+ ["do"] = function(x) if (istable(backupTAG)) then print("\n"..dumpTag(backupTAG).."\n") end end,
["ds"] = function(x)
- sel=selectSegment(inTAG)
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
if (sel) then print("\n"..(dumpSegment(inTAG, sel) or "no Segments available").."\n") end
end,
["es"] = function(x)
- sel=selectSegment(inTAG)
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
if (sel) then
- if(istable(inTAG.SEG)) then
+ if(istable(inTAG.SEG[0])) then
inTAG=editSegment(inTAG, sel)
inTAG.SEG[sel]=regenSegmentHeader(inTAG.SEG[sel])
else print("no Segments in Tag") end
inTAG=addSegment(inTAG)
inTAG.SEG[#inTAG.SEG-1]=regenSegmentHeader(inTAG.SEG[#inTAG.SEG-1])
inTAG.SEG[#inTAG.SEG]=regenSegmentHeader(inTAG.SEG[#inTAG.SEG])
- else print("unsegmented Tag!")
+ else print("Master-Token / unsegmented Tag!")
end
end,
["rs"] = function(x)
- if (istable(inTAG)) then
- sel=selectSegment(inTAG)
+ if (istable(inTAG.SEG[0])) then
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
inTAG=delSegment(inTAG, sel)
for i=0, #inTAG.SEG do
inTAG.SEG[i]=regenSegmentHeader(inTAG.SEG[i])
end
end,
["ed"] = function(x)
- sel=selectSegment(inTAG)
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
if (sel) then
inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data)
end
end,
+ ["et"] = function(x)
+ if (istable(inTAG)) then
+ editTag(inTAG)
+ end
+ end,
+ ["mt"] = function(x) inTAG=makeToken(); actions.di() end,
["ts"] = function(x)
- sel=selectSegment(inTAG)
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
regenSegmentHeader(inTAG.SEG[sel])
end,
["tk"] = function(x)
- sel=selectSegment(inTAG)
+ if (istable(inTAG) and istable(inTAG.SEG[0])) then
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
if(inTAG.SEG[sel].kgh) then inTAG.SEG[sel].kgh=false
else inTAG.SEG[sel].kgh=true end
+ end
end,
["k"] = function(x)
+ if (type(x)=="string" and string.len(x)>0) then
print(("%02x"):format(utils.Crc8Legic(x)))
+ end
+ end,
+ ["xb"] = function(x)
end,
["xc"] = function(x)
- --get credential-string for kgh-crc on certain segment
- --usage: xc <segment-index>
- print("k "..kghCrcCredentials(inTAG, x))
+ if (istable(inTAG) and istable(inTAG.SEG[0])) then
+ if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
+ else sel=selectSegment(inTAG) end
+ print("k "..kghCrcCredentials(inTAG, sel))
+ end
+ end,
+ ["dlc"] = function(x)
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ -- if segment index was user defined
+ if (type(x)=="string" and string.len(x)>0) then
+ x=tonumber(x,10)
+ print(string.format("User-Selected Index %02d", x))
+ -- or try to find match
+ else x=autoSelectSegment(inTAG, "legiccash") end
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ if (istable(inTAG.SEG[x])) then
+ io.write("in Segment "..inTAG.SEG[x].index.." :\n")
+ print("--------------------------------\n\tLegic-Cash Values\n--------------------------------")
+ local limit, curr, balance, rid, tcv
+ -- currency of balance & limit
+ curr=currency[inTAG.SEG[x].data[8]..inTAG.SEG[x].data[9]]
+ -- maximum balance
+ limit=string.format("%4.2f", tonumber(inTAG.SEG[x].data[10]..inTAG.SEG[x].data[11]..inTAG.SEG[x].data[12], 16)/100)
+ -- current balance
+ balance=string.format("%4.2f", tonumber(inTAG.SEG[x].data[15]..inTAG.SEG[x].data[16]..inTAG.SEG[x].data[17], 16)/100)
+ -- reader-id who wrote last transaction
+ rid=tonumber(inTAG.SEG[x].data[18]..inTAG.SEG[x].data[19]..inTAG.SEG[x].data[20], 16)
+ -- transaction counter value
+ tcv=tonumber(inTAG.SEG[x].data[29], 16)
+ print("Currency:\t\t "..curr)
+ print("Limit:\t\t\t "..limit)
+ print("Balance:\t\t "..balance)
+ print("Transaction Counter:\t "..tcv)
+ print("Reader-ID:\t\t "..rid.."\n--------------------------------\n")
+ end
+ --end
+ end,
+ ["df"] = function(x)
+ actions["lf"](x)
+ res=""
+ for i=0, #inTAG.SEG[1].data do
+ res=res..inTAG.SEG[1].data[i]
+ end
+ print(res)
+ end,
+ ["d3p"] = function(x)
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ -- if segment index was user defined
+ if (type(x)=="string" and string.len(x)>0) then
+ x=tonumber(x,10)
+ print(string.format("User-Selected Index %02d", x))
+ -- or try to find match
+ else x=autoSelectSegment(inTAG, "3rdparty") end
+
+ if (istable(inTAG) and istable(inTAG.SEG[x]) and inTAG.SEG[x].len == 100) then
+ uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ if (check43rdPartyCash1(uid, inTAG.SEG[x].data)) then
+ dump3rdPartyCash1(inTAG, x)
+ end
+ end
+ end,
+ ["r3p"] = function(x)
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ -- if segment index was user defined
+ if (type(x)=="string" and string.len(x)>0) then
+ x=tonumber(x,10)
+ print(string.format("User-Selected Index %02d", x))
+ -- or try to find match
+ else x=autoSelectSegment(inTAG, "3rdparty") end
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ if (istable(inTAG.SEG[x])) then
+ print("\n\t\tStamp : "..dumpTable(inTAG.SEG[x].data, "", 0 , 2))
+ print("\t\tBlock 0: "..dumpTable(inTAG.SEG[x].data, "", 3 , 18))
+ print()
+ print("\t\tBlock 1: "..dumpTable(inTAG.SEG[x].data, "", 19, 30))
+ print("checksum 1: Tag-ID .. Block 1 => LegicCrc8 = "..inTAG.SEG[x].data[31].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 19, 30)), inTAG.SEG[x].data[31])..")")
+ print()
+ print("\t\tBlock 2: "..dumpTable(inTAG.SEG[x].data, "", 32, 33))
+ print("checksum 2: Block 2 => LegicCrc8 = "..inTAG.SEG[x].data[34].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 32, 33)), inTAG.SEG[x].data[34])..")")
+ print()
+ print("\t\tBlock 3: "..dumpTable(inTAG.SEG[x].data, "", 35, 36))
+ print("checksum 3: Block 3 => LegicCrc8 = "..inTAG.SEG[x].data[37].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 35, 36)), inTAG.SEG[x].data[37])..")")
+ print()
+ print("\t\tyet unknown: "..inTAG.SEG[x].data[38])
+ print()
+ print("\t\tHisatory 1: "..dumpTable(inTAG.SEG[x].data, "", 39, 40))
+ print("\t\tHisatory 2: "..dumpTable(inTAG.SEG[x].data, "", 41, 42))
+ print("\t\tHisatory 3: "..dumpTable(inTAG.SEG[x].data, "", 43, 44))
+ print()
+ print("\t\tyet unknown: "..inTAG.SEG[x].data[45])
+ print()
+ print("\t\tKGH-UID HEX: "..dumpTable(inTAG.SEG[x].data, "", 46, 48))
+ print("\t\tBlock 4: "..dumpTable(inTAG.SEG[x].data, "", 49, 54))
+ print("checksum 4: Tag-ID .. KGH-UID .. Block 4 => LegicCrc8 = "..inTAG.SEG[x].data[55].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 46, 54)), inTAG.SEG[x].data[55])..")")
+ print()
+ print("\t\tBlock 5: "..dumpTable(inTAG.SEG[x].data, "", 56, 61))
+ print("checksum 5: Tag-ID .. Block 5 => LegicCrc8 = "..inTAG.SEG[x].data[62].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 56, 61)), inTAG.SEG[x].data[62])..")")
+ print()
+ print("\t\tBlock 6: "..dumpTable(inTAG.SEG[x].data, "", 63, 72))
+ print("checksum 6: Tag-ID .. Block 6 => LegicCrc8 = "..inTAG.SEG[x].data[73].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 63, 72)), inTAG.SEG[x].data[73])..")")
+ print()
+ print("\t\tBlock 7: "..dumpTable(inTAG.SEG[x].data, "", 74, 88))
+ print("checksum 7: Tag-ID .. Block 7 => LegicCrc8 = "..inTAG.SEG[x].data[89].." ("..compareCrc(utils.Crc8Legic(uid..dumpTable(inTAG.SEG[x].data, "", 74, 88)), inTAG.SEG[x].data[89])..")")
+ print()
+ print("\t\tBlock 8: "..dumpTable(inTAG.SEG[x].data, "", 90, 94))
+ end
+ end,
+ ["e3p"] = function(x)
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ -- if segment index was user defined
+ if (type(x)=="string" and string.len(x)>0) then
+ x=tonumber(x,10)
+ print(string.format("User-Selected Index %02d", x))
+ -- or try to find match
+ else x=autoSelectSegment(inTAG, "3rdparty") end
+
+ if (istable(inTAG) and istable(inTAG.SEG[x]) and inTAG.SEG[x].len == 100) then
+ --if (check43rdPartyCash1(uid, inTAG.SEG[x].data)) then
+ -- change Balance
+ if (confirm("\nedit Balance?")) then
+ local new_cash=input("enter new Balance without comma or currency", "100")
+ inTAG.SEG[x].data=edit3rdCash(new_cash, uid, inTAG.SEG[x].data)
+ end
+ -- change User-ID (used for online-account-mapping)
+ if (confirm("\nedit UserID-Mapping?")) then
+ local new_mapid=input("enter new UserID (6-digit value)", "012345")
+ inTAG.SEG[x].data=edit3rdUid(new_mapid, uid, inTAG.SEG[x].data)
+ end
+ if (confirm("\nedit Stamp?")) then
+ local new_stamp=input("enter new Stamp", getSegmentStamp(inTAG.SEG[x]))
+ inTAG.SEG[x].data=editStamp(new_stamp, uid, inTAG.SEG[x].data)
+ new_stamp=getSegmentStamp(inTAG.SEG[x], 'true')
+ print("stamp_bytes: "..#new_stamp)
+ -- replace stamp in 'block 1' also
+ io.write("editing stamp in Block 1 also ")
+ for i=20, (20+#new_stamp-1) do
+ inTAG.SEG[x].data[i]=new_stamp[i-19]
+ io.write(".");
+ end
+ print(" done")
+ -- fix known checksums
+ inTAG.SEG[x].data=fix3rdPartyCash1(uid, inTAG.SEG[x].data)
+ end
+
+ -- print out new settings
+ dump3rdPartyCash1(inTAG, x)
+ --end
+ end
+ end,
+ ["gs"] = function(x)
+ if(type(x)=="string" and string.len(x)>=2) then x=tonumber(x, 10)
+ else x=selectSegment(inTAG) end
+ local stamp=getSegmentStamp(inTAG.SEG[x])
+ print("Stamp : "..stamp)
+ stamp=str2bytes(stamp)
+ print("lenght: "..#stamp)
+ end,
+ ["c6"] = function(x) local crc16=string.format("%4.04x", utils.Crc16(x))
+ print(string.sub(crc16, 0,2).." "..string.sub(crc16, 3,4))
end,
["cc"] = function(x) if (istable(inTAG)) then checkAllSegCrc(inTAG) end end,
+ ["cb"] = function(x)
+ if (istable(inTAG)) then
+ print("purge BackupArea")
+ inTAG=clearBackupArea(inTAG)
+ end
+ end,
+ ["f3p"] = function(x)
+ if(type(x)=="string" and string.len(x)>=2) then x=tonumber(x, 10)
+ else x=selectSegment(inTAG) end
+ if (istable(inTAG.SEG[x])) then
+ local uid=inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
+ inTAG.SEG[x].data=fix3rdPartyCash1(uid, inTAG.SEG[x].data)
+ end
+ end,
["ck"] = function(x) if (istable(inTAG)) then checkAllKghCrc(inTAG) end end,
- ["q"] = function(x) end,
}
print("modify-modus! enter 'h' for help or 'q' to quit")
repeat
ic=input("Legic command? ('h' for help - 'q' for quit)", "h")
-- command actions
- if (type(actions[string.lower(string.sub(ic,0,1))])=='function') then
- actions[string.lower(string.sub(ic,0,1))](string.sub(ic,3))
+ if (type(actions[string.lower(string.sub(ic,0,3))])=='function') then
+ actions[string.lower(string.sub(ic,0,3))](string.sub(ic,5))
elseif (type(actions[string.lower(string.sub(ic,0,2))])=='function') then
actions[string.lower(string.sub(ic,0,2))](string.sub(ic,4))
- else actions['h']('') end
+ elseif (type(actions[string.lower(string.sub(ic,0,1))])=='function') then
+ actions[string.lower(string.sub(ic,0,1))](string.sub(ic,3))
+ else actions.h('') end
until (string.sub(ic,0,1)=="q")
end
---- main
+function clearBackupArea(tag)
+ for i=1, #tag.Bck do
+ tag.Bck[i]='00'
+ end
+ return tag
+end
+
+function getSegmentStamp(seg, bytes)
+ local stamp=""
+ local stamp_len=7
+ --- the 'real' stamp on MIM is not really easy to tell for me since the 'data-block' covers stamp0..stampn+data0..datan
+ -- there a no stamps longer than 7 bytes & they are write-protected by default , and I have not seen user-credntials
+ -- with stamps smaller 3 bytes (except: Master-Token)
+ -- WRP -> Read/Write Protection
+ -- WRC -> Read/Write Condition
+ -- RD depends on WRC - if WRC > 0 and RD=1: only reader with matching #WRC of Stamp-bytes in thier Database have Read-Access to the Tag
+ if (seg.WRP<7) then stamp_len=(seg.WRP) end
+ for i=1, (stamp_len) do
+ stamp=stamp..seg.data[i-1]
+ end
+ if (bytes) then
+ stamp=str2bytes(stamp)
+ return stamp
+ else return stamp end
+end
+
+function str2bytes(s)
+ local res={}
+ if (string.len(s)%2~=0) then return print("stamp should be a even hexstring e.g.: deadbeef or 0badc0de") end
+ for i=1, string.len(s), 2 do
+ table.insert(res, string.sub(s,i,(i+1)))
+ end
+ return res
+end
+
+function editStamp(new_stamp, uid, data)
+ local stamp=str2bytes(new_stamp)
+ for i=0, #stamp-1 do
+ data[i]=stamp[i+1]
+ end
+ -- now fill in stamp
+ for i=0, (string.len(new_stamp)/2)-1 do
+ data[i]=stamp[i+1]
+ end
+ return fix3rdPartyCash1(uid, data)
+end
+
+function autoSelectSegment(tag, s)
+ local uid=tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2
+ local x=#tag.SEG+1
+ local res = false
+ io.write("autoSelect ")
+ --- search for desired segment-type
+ -- 3rd Party Segment
+ if (s=="3rdparty") then
+ repeat
+ io.write(". ")
+ x=x-1
+ res=check43rdPartyCash1(uid, tag.SEG[x].data)
+ until ( res or x==0 )
+ end
+ -- Legic-Cash Segment
+ if (s=="legiccash") then
+ repeat
+ io.write(". ")
+ x=x-1
+ res=check4LegicCash(tag.SEG[x].data)
+ until ( res or x==0 )
+ end
+ ---
+ -- segment found
+ if (res) then
+ io.write("\nautoselected Index: "..string.format("%02d", x).."\n")
+ return x
+ end
+ ---
+ -- nothing found
+ io.write("no Segment found\n")
+ return -1
+end
+
+--- main function
function main(args)
if (#args == 0 ) then modifyMode() end
--- variables
- local inTAG, outTAG, outfile, interactive, crc, ofs, cfs, dfs
+ local inTAG, backupTAG, outTAG, outfile, interactive, crc, ofs, cfs, dfs
-- just a spacer for better readability
print()
--- parse arguments
print(dumpTag(inTAG))
end
bytes=tagToBytes(inTAG)
- -- xor with given crc
if (cfs) then
+ -- xor willl be done in function writeFile
+ -- with the value of byte[5]
bytes[5]=crc
end
-- write to outfile
if (bytes) then
writeFile(bytes, outfile)
- -- reed new content into virtual tag
-
+ --- read real tag into virtual tag
+ -- inTAG=readFromPM3() end
+ --- or simply use the bytes that where wriiten
inTAG=bytesToTag(bytes, inTAG)
-- show new content
if (dfs) then
print("-----------------------------------------")
- print(dumpTag(outTAG))
+ print(dumpTag(inTAG))
end
end
end
end
+-- Creates a complete/deep copy of the data
+function deepCopy(object)
+ local lookup_table = {}
+ local function _copy(object)
+ if type(object) ~= "table" then
+ return object
+ elseif lookup_table[object] then
+ return lookup_table[object]
+ end
+ local new_table = {}
+ lookup_table[object] = new_table
+ for index, value in pairs(object) do
+ new_table[_copy(index)] = _copy(value)
+ end
+ return setmetatable(new_table, getmetatable(object))
+ end
+ return _copy(object)
+end
+
--- start
main(args)
\ No newline at end of file