From 43b5ee5918473ef6c131912f78135cf823e88738 Mon Sep 17 00:00:00 2001 From: Uli Heilmeier Date: Wed, 8 Apr 2020 22:47:13 +0200 Subject: [PATCH] legic.lua: updated to work again Fixed/changed things: * added info that virtual tag is always MIM1024 * changed reading files to read binary files (as written by 'hf legic dump') * changed extension for writing files (*.bin and *.eml) to be on par with 'hf legic dump' * CRC was calculated wrong when data was not padded with 0 for one char hex strings * readTag (rt) can now be called multiple times without using the wrong filename * tag length was calculated wrong as segment header length field includes the header itself * bytes are XORed before writing them to a tag * default name for file contains now the tag id --- CHANGELOG.md | 1 + client/luascripts/legic.lua | 161 +++++++++++++++++++----------------- 2 files changed, 87 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eff29cc79..0f15617c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Updated 'legic.lua' and 'legic_clone.lua' script - works with current command set (@Pizza_4u) - Rewrote `hf mfdes` functions and added apdu debugging (@bkerler) - Add Mifare Desfire GetDFNames and improve HF MFDES Enum output (@bkerler) - Fix Mifare Desfire select appid handling (@bkerler) diff --git a/client/luascripts/legic.lua b/client/luascripts/legic.lua index 7e0f8d3be..393cc9e52 100644 --- a/client/luascripts/legic.lua +++ b/client/luascripts/legic.lua @@ -91,14 +91,20 @@ CRC1 = crc8 over addr 0x00..0x03+0x07..0x0E (special 'gantner crc8') CRC2 = MCD + MSB0..2+ addr 0x06 + addr 0x05 + addr 0x07 + Stamp (regular Master-Token-CRC) --]] +--[[ +Known issues; needs to be fixed: +* last byte in last segment is handled incorrectly when it is the last bytes on the card itself (MIM256: => byte 256) +--]] + example = "script run legic" -author = "Mosci" -version = "1.0.3" +author = "Mosci, uhei" +version = "1.0.4" desc = [[ This script helps you to read, create and modify Legic Prime Tags (MIM22, MIM256, MIM1024) +The virtual tag (and therefore the file to be saved) is always a MIM1024 tag. it's kinda interactive with following commands in three categories: Data I/O Segment Manipulation Token-Data @@ -108,8 +114,8 @@ it's kinda interactive with following commands in three categories: ed => edit Segment Data tk => toggle KGH-Flag File I/O rs => remove Segment ----------------- cc => check Segment-CRC - lf => load File ck => check KGH - sf => save File ds => dump Segments + lf => load bin File ck => check KGH + sf => save eml/bin File ds => dump Segments xf => xor to File @@ -128,8 +134,8 @@ it's kinda interactive with following commands in three categories: without the need of changing anything - MCD,MSN,MCC will be read from the tag before and applied to the output. - 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) + lf: 'load file' - load a (xored) binary file (*.bin) from the local Filesystem into the 'virtual inTag' + sf: 'save file' - saves the 'virtual inTag' to the local Filesystem as eml and bin (xored with Tag-MCC) xf: 'xor file' - saves the 'virtual inTag' to the local Filesystem (xored with choosen MCC - use '00' for plain values) ct: 'copy tag' - copy the 'virtual Tag' to a second 'virtual TAG' - not usefull yet, but inernally needed @@ -242,6 +248,16 @@ function istable(t) return type(t) == 'table' end +--- +-- To have two char string for a byte +local function padString(str) + if (#str == 1) then + return '0'..str + end + + return str +end + --- -- creates a 'deep copy' of a table (a=b only references) function deepCopy(object) @@ -387,15 +403,15 @@ end function bytesToTag(bytes, tag) if istable(tag) == false then return oops("tag is no table in: bytesToTag ("..type(tag)..")") end - tag.MCD =bytes[1]; - tag.MSN0=bytes[2]; - tag.MSN1=bytes[3]; - tag.MSN2=bytes[4]; - tag.MCC =bytes[5]; - tag.DCFl=bytes[6]; - tag.DCFh=bytes[7]; - tag.raw =bytes[8]; - tag.SSC =bytes[9]; + tag.MCD =padString(bytes[1]); + tag.MSN0=padString(bytes[2]); + tag.MSN1=padString(bytes[3]); + tag.MSN2=padString(bytes[4]); + tag.MCC =padString(bytes[5]); + tag.DCFl=padString(bytes[6]); + tag.DCFh=padString(bytes[7]); + tag.raw =padString(bytes[8]); + tag.SSC =padString(bytes[9]); tag.Type=getTokenType(tag.DCFl); tag.OLE=bbit("0x"..tag.DCFl,7,1) tag.WRP=("%d"):format(bbit("0x"..bytes[8],0,4)) @@ -500,42 +516,26 @@ function tagToBytes(tag) return bytes end + +--- --- PM3 I/O --- ---- --- read from pm3 into virtual-tag -function readFromPM3() - local tag, bytes, infile - infile="legic.temp" - -- core.console("hf legic reader") - -- core.console("hf legic esave "..infile) - core.console("hf legic dump o "..infile) - tag=readFile(infile..".bin") - return tag -end - -local function padString(str) - if (#str == 1) then - return '0'..str - end - - return str -end - ---- -- write virtual Tag to real Tag function writeToTag(tag) local bytes - local filename = 'MylegicClone.hex' local taglen = 22 - if(utils.confirm(acred.."\nplace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then + local writeDCF = false + if(utils.confirm(acred.."\nPlace the (empty) Tag onto the PM3\nand confirm writing to this Tag: "..acoff) == false) then return end + if(utils.confirm(acred.."\nShould the decremental field (DCF) be written?: "..acoff) == true) then + writeDCF = true + end -- get used bytes / tag-len if (istable(tag.SEG)) then if (istable(tag.Bck)) then for i=0, #tag.SEG do - taglen = taglen + tag.SEG[i] . len + 5 + taglen = taglen + tag.SEG[i] . len end end local uid_old = tag.MCD..tag.MSN0..tag.MSN1..tag.MSN2 @@ -571,37 +571,32 @@ function writeToTag(tag) bytes[22] = calcMtCrc(bytes) end if (bytes) then - print("write temp-file '"..filename.."'") - print(accyan) - writeFile(bytes, filename..".bin") - print(acoff) + bytes = xorBytes(bytes,tag.MCC) end end + -- write data to file if (taglen > 0) then WriteBytes = input(acyellow.."enter number of bytes to write?"..acoff, taglen) - -- load file into pm3-buffer - if (type(filename) ~= "string") then - filename = input(acyellow.."filename to load to pm3-buffer?"..acoff, "legic.temp") - end - - cmd = 'hf legic eload 2 '..filename - core.console(cmd) -- write pm3-buffer to Tag - for i=0, WriteBytes do - if (i > 6) then - cmd = ("hf legic write o %x d %s "):format(i, padString(bytes[i])) + for i=1, WriteBytes do + if (i > 7) then + cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i])) print(acgreen..cmd..acoff) core.console(cmd) core.clearCommandBuffer() + elseif (i == 7) then + if (writeDCF) then + -- write DCF in reverse order (requires 'mosci-patch') + cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) + print(acgreen..cmd..acoff) + core.console(cmd) + core.clearCommandBuffer() + else + print(acgreen.."skip byte 0x05-0x06 - DCF"..acoff) + end elseif (i == 6) then - -- write DCF in reverse order (requires 'mosci-patch') - cmd = ('hf legic write o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i])) - print(acgreen..cmd..acoff) - core.console(cmd) - core.clearCommandBuffer() - elseif (i == 5) then print(acgreen.."skip byte 0x05 - will be written next step"..acoff) else print(acgreen.."skip byte 0x00-0x04 - unwritable area"..acoff) @@ -641,12 +636,12 @@ end local function save_BIN(data, filename) local outfile local counter = 1 - local ext = filename:match("^.+(%..+)$") or '' - local fn = filename + local ext = ".bin" + local fn = filename..ext -- Make sure we don't overwrite a file while file_check(fn) do - fn = filename:gsub(ext, tostring(counter)..ext) + fn = filename..ext:gsub(ext, "-"..tostring(counter)..ext) counter = counter + 1 end @@ -664,26 +659,27 @@ end --- -- write bytes to file function writeFile(bytes, filename) - if (filename ~= 'MylegicClone.hex') then - if (file_check(filename)) then - local answer = confirm("\nthe output-file "..filename.." already exists!\nthis will delete the previous content!\ncontinue?") + local emlext = ".eml" + if (filename ~= 'MyLegicClone') then + if (file_check(filename..emlext)) then + local answer = confirm("\nthe output-file "..filename..emlext.." already exists!\nthis will delete the previous content!\ncontinue?") if not answer then return print("user abort") end end end local line local bcnt = 0 - local fho, err = io.open(filename, "w") + local fho, err = io.open(filename..emlext, "w") if err then - return oops("OOps ... failed to open output-file ".. filename) + return oops("OOps ... failed to open output-file ".. filename..emlext) end bytes = xorBytes(bytes, bytes[5]) for i = 1, #bytes do if (bcnt == 0) then - line = bytes[i] + line = padString(bytes[i]) elseif (bcnt <= 7) then - line = line.." "..bytes[i] + line = line.." "..padString(bytes[i]) end if (bcnt == 7) then -- write line to new file @@ -699,7 +695,7 @@ function writeFile(bytes, filename) -- save binary local fn_bin, fn_bin_num = save_BIN(bytes, filename) - print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..acoff) + print("\nwrote "..acyellow..(#bytes * 3)..acoff.." bytes to " ..acyellow..filename..emlext..acoff) if fn_bin and fn_bin_num then print("\nwrote "..acyellow..fn_bin_num..acoff.." bytes to BINARY file "..acyellow..fn_bin..acoff) @@ -708,6 +704,21 @@ function writeFile(bytes, filename) return true end +--- +-- read from pm3 into virtual-tag +function readFromPM3() + local tag, bytes, infile + --infile="legic.temp" + infile=os.tmpname() + core.console("hf legic dump f "..infile) + tag=readFile(infile..".bin") + os.remove(infile) + os.remove(infile..".bin") + os.remove(infile..".eml") + os.remove(infile..".json") + return tag +end + --- Map related --- --- -- make tagMap @@ -2265,8 +2276,8 @@ function modifyHelp() ed => edit Segment Data tk => toggle KGH-Flag File I/O rs => remove Segment ----------------- cc => check Segment-CRC - lf => load File ck => check KGH - sf => save File ds => dump Segments + lf => load bin File ck => check KGH + sf => save eml/bin File ds => dump Segments xf => xor to File @@ -2352,10 +2363,10 @@ function modifyMode() -- save values of mainTAG to a file (xored with MCC of mainTAG) ["sf"] = function(x) if istable(inTAG) then - outfile = input("enter filename:", "legic.temp") + outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2) bytes = tagToBytes(inTAG) --bytes=xorBytes(bytes, inTAG.MCC) - if bytes then + if (bytes) then writeFile(bytes, outfile) end end @@ -2364,7 +2375,7 @@ function modifyMode() -- save values of mainTAG to a file (xored with 'specific' MCC) ["xf"] = function(x) if istable(inTAG) then - outfile = input("enter filename:", "legic.temp") + outfile = input("enter filename:", "hf-legic-"..inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2) crc = input("enter new crc: ('00' for a plain dump)", inTAG.MCC) print("obfuscate with: "..crc) bytes=tagToBytes(inTAG)