| 1 | --[[ |
| 2 | script to create a clone-dump with new crc |
| 3 | Author: mosci |
| 4 | my Fork: https://github.com/icsom/proxmark3.git |
| 5 | Upstream: https://github.com/Proxmark/proxmark3.git |
| 6 | |
| 7 | 1. read tag-dump, xor byte 22..end with byte 0x05 of the inputfile |
| 8 | 2. write to outfile |
| 9 | 3. set byte 0x05 to newcrc |
| 10 | 4. until byte 0x21 plain like in inputfile |
| 11 | 5. from 0x22..end xored with newcrc |
| 12 | 6. calculate new crc on each segment (needs to know the new MCD & MSN0..2) |
| 13 | |
| 14 | simplest usage: |
| 15 | read a valid legic tag with 'hf legic reader' |
| 16 | save the dump with 'hf legic save orig.hex' |
| 17 | place your 'empty' tag on the reader and run 'script run Legic_clone -i orig.hex -w' |
| 18 | you will see some output like: |
| 19 | read 1024 bytes from legic_dumps/j_0000.hex |
| 20 | |
| 21 | place your empty tag onto the PM3 to read and display the MCD & MSN0..2 |
| 22 | the values will be shown below |
| 23 | confirm whnen ready [y/n] ?y |
| 24 | #db# setting up legic card |
| 25 | #db# MIM 256 card found, reading card ... |
| 26 | #db# Card read, use 'hf legic decode' or |
| 27 | #db# 'data hexsamples 8' to view results |
| 28 | 0b ad c0 de <- !! here you'll see the MCD & MSN of your empty tag, which has to be typed in manually as seen below !! |
| 29 | type in MCD as 2-digit value - e.g.: 00 (default: 79 ) |
| 30 | > 0b |
| 31 | type in MSN0 as 2-digit value - e.g.: 01 (default: 28 ) |
| 32 | > ad |
| 33 | type in MSN1 as 2-digit value - e.g.: 02 (default: d1 ) |
| 34 | > c0 |
| 35 | type in MSN2 as 2-digit value - e.g.: 03 (default: 43 ) |
| 36 | > de |
| 37 | MCD:0b, MSN:ad c0 de, MCC:79 <- this crc is calculated from the MCD & MSN and must match the one on yout empty tag |
| 38 | |
| 39 | wrote 1024 bytes to myLegicClone.hex |
| 40 | enter number of bytes to write? (default: 86 ) |
| 41 | |
| 42 | loaded 1024 samples |
| 43 | #db# setting up legic card |
| 44 | #db# MIM 256 card found, writing 0x00 - 0x01 ... |
| 45 | #db# write successful |
| 46 | ... |
| 47 | #db# setting up legic card |
| 48 | #db# MIM 256 card found, writing 0x56 - 0x01 ... |
| 49 | #db# write successful |
| 50 | proxmark3> |
| 51 | |
| 52 | the default value (number of bytes to write) is calculated over all valid segments and should be ok - just hit enter, wait until write has finished |
| 53 | and your clone should be ready (except there has to be a additional KGH-CRC to be calculated - which credentials are unknown until yet) |
| 54 | |
| 55 | the '-w' switch will only work with my fork - it needs the binary legic_crc8 which is not part of the proxmark3-master-branch |
| 56 | also the ability to write DCF is not possible with the proxmark3-master-branch |
| 57 | but creating dumpfile-clone files will be possible (without valid segment-crc - this has to done manually with) |
| 58 | |
| 59 | |
| 60 | (example) Legic-Prime Layout with 'Kaba Group Header' |
| 61 | +----+----+----+----+----+----+----+----+ |
| 62 | 0x00|MCD |MSN0|MSN1|MSN2|MCC | 60 | ea | 9f | |
| 63 | +----+----+----+----+----+----+----+----+ |
| 64 | 0x08| ff | 00 | 00 | 00 | 11 |Bck0|Bck1|Bck2| |
| 65 | +----+----+----+----+----+----+----+----+ |
| 66 | 0x10|Bck3|Bck4|Bck5|BCC | 00 | 00 |Seg0|Seg1| |
| 67 | +----+----+----+----+----+----+----+----+ |
| 68 | 0x18|Seg2|Seg3|SegC|Stp0|Stp1|Stp2|Stp3|UID0| |
| 69 | +----+----+----+----+----+----+----+----+ |
| 70 | 0x20|UID1|UID2|kghC| |
| 71 | +----+----+----+ |
| 72 | |
| 73 | MCD= ManufacturerID (1 Byte) |
| 74 | MSN0..2= ManufactureSerialNumber (3 Byte) |
| 75 | MCC= CRC (1 Byte) calculated over MCD,MSN0..2 |
| 76 | DCF= DecrementalField (2 Byte) 'credential' (enduser-Tag) seems to have always DCF-low=0x60 DCF-high=0xea |
| 77 | Bck0..5= Backup (6 Byte) Bck0 'dirty-flag', Bck1..5 SegmentHeader-Backup |
| 78 | BCC= BackupCRC (1 Byte) CRC calculated over Bck1..5 |
| 79 | Seg0..3= SegmentHeader (on MIM 4 Byte ) |
| 80 | SegC= SegmentCRC (1 Byte) calculated over MCD,MSN0..2,Seg0..3 |
| 81 | Stp0..n= Stamp0... (variable length) length = Segment-Len - UserData - 1 |
| 82 | UID0..n= UserDater (variable length - with KGH hex 0x00-0x63 / dec 0-99) length = Segment-Len - WRP - WRC - 1 |
| 83 | kghC= KabaGroupHeader (1 Byte + addr 0x0c must be 0x11) |
| 84 | as seen on ths example: addr 0x05..0x08 & 0x0c must have been set to this values - otherwise kghCRC will not be created by a official reader (not accepted) |
| 85 | --]] |
| 86 | |
| 87 | example = "Script create a clone-dump of a dump from a Legic Prime Tag" |
| 88 | author = "Mosci" |
| 89 | desc = |
| 90 | [[ |
| 91 | This is a script which create a clone-dump of a dump from a Legic Prime Tag (MIM256 or MIM1024) |
| 92 | (created with 'hf legic save my_dump.hex') |
| 93 | requiered arguments: |
| 94 | -i <input file> (file to read data from) |
| 95 | |
| 96 | optional arguments : |
| 97 | -h - Help text |
| 98 | -o <output file> - requieres option -c to be given |
| 99 | -c <new-tag crc> - requieres option -o to be given |
| 100 | -d - Display content of found Segments |
| 101 | -s - Display summary at the end |
| 102 | -w - write directly to Tag - a file myLegicClone.hex wille be generated also |
| 103 | |
| 104 | e.g.: |
| 105 | hint: using the CRC '00' will result in a plain dump ( -c 00 ) |
| 106 | |
| 107 | Examples : |
| 108 | script run legic_clone -i my_dump.hex -o my_clone.hex -c f8 |
| 109 | script run legic_clone -i my_dump.hex -d -s |
| 110 | ]] |
| 111 | |
| 112 | local utils = require('utils') |
| 113 | local getopt = require('getopt') |
| 114 | local bxor = bit32.bxor |
| 115 | |
| 116 | -- we need always 2 digits |
| 117 | function prepend_zero(s) |
| 118 | if (string.len(s)==1) then return "0" .. s |
| 119 | else |
| 120 | if (string.len(s)==0) then return "00" |
| 121 | else return s |
| 122 | end |
| 123 | end |
| 124 | end |
| 125 | |
| 126 | --- |
| 127 | -- This is only meant to be used when errors occur |
| 128 | function oops(err) |
| 129 | print("ERROR: ",err) |
| 130 | return nil, err |
| 131 | end |
| 132 | |
| 133 | --- |
| 134 | -- Usage help |
| 135 | function help() |
| 136 | print(desc) |
| 137 | print("Example usage") |
| 138 | print(example) |
| 139 | end |
| 140 | |
| 141 | -- Check availability of file |
| 142 | function file_check(file_name) |
| 143 | local file_found=io.open(file_name, "r") |
| 144 | if file_found==nil then |
| 145 | file_found=false |
| 146 | else |
| 147 | file_found=true |
| 148 | end |
| 149 | return file_found |
| 150 | end |
| 151 | |
| 152 | --- xor-wrapper |
| 153 | -- xor all from addr 0x22 (start counting from 1 => 23) |
| 154 | function xorme(hex, xor, index) |
| 155 | if ( index >= 23 ) then |
| 156 | return ('%02x'):format(bxor( tonumber(hex,16) , tonumber(xor,16) )) |
| 157 | else |
| 158 | return hex |
| 159 | end |
| 160 | end |
| 161 | |
| 162 | -- read input-file into array |
| 163 | function getInputBytes(infile) |
| 164 | local line |
| 165 | local bytes = {} |
| 166 | |
| 167 | local fhi,err = io.open(infile) |
| 168 | if err then print("OOps ... faild to read from file ".. infile); return false; end |
| 169 | |
| 170 | while true do |
| 171 | line = fhi:read() |
| 172 | if line == nil then break end |
| 173 | |
| 174 | for byte in line:gmatch("%w+") do |
| 175 | table.insert(bytes, byte) |
| 176 | end |
| 177 | end |
| 178 | |
| 179 | fhi:close() |
| 180 | |
| 181 | print("\nread ".. #bytes .." bytes from ".. infile) |
| 182 | return bytes |
| 183 | end |
| 184 | |
| 185 | -- write to file |
| 186 | function writeOutputBytes(bytes, outfile) |
| 187 | local line |
| 188 | local bcnt=0 |
| 189 | local fho,err = io.open(outfile,"w") |
| 190 | if err then print("OOps ... faild to open output-file ".. outfile); return false; end |
| 191 | |
| 192 | for i = 1, #bytes do |
| 193 | if (bcnt == 0) then |
| 194 | line=bytes[i] |
| 195 | elseif (bcnt <= 7) then |
| 196 | line=line.." "..bytes[i] |
| 197 | end |
| 198 | if (bcnt == 7) then |
| 199 | -- write line to new file |
| 200 | fho:write(line.."\n") |
| 201 | -- reset counter & line |
| 202 | bcnt=-1 |
| 203 | line="" |
| 204 | end |
| 205 | bcnt=bcnt+1 |
| 206 | end |
| 207 | fho:close() |
| 208 | print("\nwrote ".. #bytes .." bytes to " .. outfile) |
| 209 | return true |
| 210 | end |
| 211 | |
| 212 | -- xore certain bytes |
| 213 | function xorBytes(inBytes, crc) |
| 214 | local bytes = {} |
| 215 | for index = 1, #inBytes do |
| 216 | bytes[index] = xorme(inBytes[index], crc, index) |
| 217 | end |
| 218 | if (#inBytes == #bytes) then |
| 219 | -- replace crc |
| 220 | bytes[5] = string.sub(crc,-2) |
| 221 | return bytes |
| 222 | else |
| 223 | print("error: byte-count missmatch") |
| 224 | return false |
| 225 | end |
| 226 | end |
| 227 | |
| 228 | -- get raw segment-data |
| 229 | function getSegmentData(bytes, start, index) |
| 230 | local raw, len, valid, last, wrp, wrc, rd, crc |
| 231 | local segment = {} |
| 232 | segment[0] = bytes[start].." "..bytes[start+1].." "..bytes[start+2].." "..bytes[start+3] |
| 233 | -- flag = high nibble of byte 1 |
| 234 | segment[1] = string.sub(bytes[start+1],0,1) |
| 235 | |
| 236 | -- valid = bit 6 of byte 1 |
| 237 | segment[2] = tonumber(bit32.extract("0x"..bytes[start+1],6,1),16) |
| 238 | |
| 239 | -- last = bit 7 of byte 1 |
| 240 | segment[3] = tonumber(bit32.extract("0x"..bytes[start+1],7,1),16) |
| 241 | |
| 242 | -- len = (byte 0)+(bit0-3 of byte 1) |
| 243 | segment[4] = tonumber(("%03x"):format(tonumber(bit32.extract("0x"..bytes[start+1],0,3),16)..tonumber(bytes[start],16)),16) |
| 244 | |
| 245 | -- wrp (write proteted) = byte 2 |
| 246 | segment[5] = tonumber(bytes[start+2]) |
| 247 | |
| 248 | -- wrc (write control) - bit 4-6 of byte 3 |
| 249 | segment[6] = tonumber(bit32.extract("0x"..bytes[start+3],4,3),16) |
| 250 | |
| 251 | -- rd (read disabled) - bit 7 of byte 3 |
| 252 | segment[7] = tonumber(bit32.extract("0x"..bytes[start+3],7,1),16) |
| 253 | |
| 254 | -- crc byte 4 |
| 255 | segment[8] = bytes[start+4] |
| 256 | |
| 257 | -- segment index |
| 258 | segment[9] = index |
| 259 | |
| 260 | -- # crc-byte |
| 261 | segment[10] = start+4 |
| 262 | return segment |
| 263 | end |
| 264 | |
| 265 | --- Kaba Group Header |
| 266 | -- checks if a segment does have a kghCRC |
| 267 | -- returns boolean false if no kgh has being detected or the kghCRC if a kgh was detected |
| 268 | function CheckKgh(bytes, segStart, segEnd) |
| 269 | if (bytes[8]=='9f' and bytes[9]=='ff' and bytes[13]=='11') then |
| 270 | local i |
| 271 | local data = {} |
| 272 | segStart=tonumber(segStart,10) |
| 273 | segEnd=tonumber(segEnd,10) |
| 274 | local dataLen = segEnd-segStart-5 |
| 275 | --- gather creadentials for verify |
| 276 | local WRP = bytes[(segStart+2)] |
| 277 | local WRC = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],4,3),16)) |
| 278 | local RD = ("%02x"):format(tonumber(bit32.extract("0x"..bytes[segStart+3],7,1),16)) |
| 279 | local XX = "00" |
| 280 | cmd = bytes[1]..bytes[2]..bytes[3]..bytes[4]..WRP..WRC..RD..XX |
| 281 | for i=(segStart+5), (segStart+5+dataLen-2) do |
| 282 | cmd = cmd..bytes[i] |
| 283 | end |
| 284 | local KGH=("%02x"):format(utils.Crc8Legic(cmd)) |
| 285 | if (KGH==bytes[segEnd-1]) then |
| 286 | return KGH |
| 287 | else |
| 288 | return false |
| 289 | end |
| 290 | else |
| 291 | return false |
| 292 | end |
| 293 | end |
| 294 | |
| 295 | -- get only the addresses of segemnt-crc's and the length of bytes |
| 296 | function getSegmentCrcBytes(bytes) |
| 297 | local start=23 |
| 298 | local index=0 |
| 299 | local crcbytes = {} |
| 300 | repeat |
| 301 | seg = getSegmentData(bytes,start,index) |
| 302 | crcbytes[index]= seg[10] |
| 303 | start = start + seg[4] |
| 304 | index = index + 1 |
| 305 | until (seg[3] == 1 or tonumber(seg[9]) == 126 ) |
| 306 | crcbytes[index] = start |
| 307 | return crcbytes |
| 308 | end |
| 309 | |
| 310 | -- print segment-data (hf legic decode like) |
| 311 | function displaySegments(bytes) |
| 312 | --display segment header(s) |
| 313 | start=23 |
| 314 | index="00" |
| 315 | |
| 316 | --repeat until last-flag ist set to 1 or segment-index has reached 126 |
| 317 | repeat |
| 318 | wrc="" |
| 319 | wrp="" |
| 320 | pld="" |
| 321 | Seg = getSegmentData(bytes,start,index) |
| 322 | KGH = CheckKgh(bytes,start,(start+tonumber(Seg[4],10))) |
| 323 | printSegment(Seg) |
| 324 | |
| 325 | -- wrc |
| 326 | if(Seg[6]>0) then |
| 327 | print("WRC protected area:") |
| 328 | -- length of wrc = wrc |
| 329 | for i=1, Seg[6] do |
| 330 | -- starts at (segment-start + segment-header + segment-crc)-1 |
| 331 | wrc = wrc..bytes[(start+4+1+i)-1].." " |
| 332 | end |
| 333 | print(wrc) |
| 334 | elseif(Seg[5]>0) then |
| 335 | print("Remaining write protected area:") |
| 336 | -- length of wrp = (wrp-wrc) |
| 337 | for i=1, (Seg[5]-Seg[6]) do |
| 338 | -- starts at (segment-start + segment-header + segment-crc + wrc)-1 |
| 339 | wrp = wrp..bytes[(start+4+1+Seg[6]+i)-1].." " |
| 340 | end |
| 341 | print(wrp) |
| 342 | end |
| 343 | |
| 344 | -- payload |
| 345 | print("Remaining segment payload:") |
| 346 | --length of payload = segment-len - segment-header - segment-crc - wrp -wrc |
| 347 | for i=1, (Seg[4]-4-1-Seg[5]-Seg[6]) do |
| 348 | -- starts at (segment-start + segment-header + segment-crc + segment-wrp + segemnt-wrc)-1 |
| 349 | pld = pld..bytes[(start+4+1+Seg[5]+Seg[6]+i)-1].." " |
| 350 | end |
| 351 | print(pld) |
| 352 | if (KGH) then print("'Kaba Group Header' detected"); end |
| 353 | start = start+Seg[4] |
| 354 | index = prepend_zero(tonumber(Seg[9])+1) |
| 355 | |
| 356 | until (Seg[3] == 1 or tonumber(Seg[9]) == 126 ) |
| 357 | end |
| 358 | |
| 359 | -- print Segment values |
| 360 | function printSegment(SegmentData) |
| 361 | res = "\nSegment "..SegmentData[9]..": " |
| 362 | res = res.. "raw header="..SegmentData[0]..", " |
| 363 | res = res.. "flag="..SegmentData[1].." (valid="..SegmentData[2].." last="..SegmentData[3].."), " |
| 364 | res = res.. "len="..("%04d"):format(SegmentData[4])..", " |
| 365 | res = res.. "WRP="..prepend_zero(SegmentData[5])..", " |
| 366 | res = res.. "WRC="..prepend_zero(SegmentData[6])..", " |
| 367 | res = res.. "RD="..SegmentData[7]..", " |
| 368 | res = res.. "crc="..SegmentData[8] |
| 369 | print(res) |
| 370 | end |
| 371 | |
| 372 | -- write clone-data to tag |
| 373 | function writeToTag(plainBytes) |
| 374 | local SegCrcs = {} |
| 375 | if(utils.confirm("\nplace your empty tag onto the PM3 to read and display the MCD & MSN0..2\nthe values will be shown below\n confirm when ready") == false) then |
| 376 | return |
| 377 | end |
| 378 | |
| 379 | -- gather MCD & MSN from new Tag - this must be enterd manually |
| 380 | cmd = 'hf legic read 0x00 0x04' |
| 381 | core.console(cmd) |
| 382 | print("\nthese are the MCD MSN0 MSN1 MSN2 from the Tag that has being read:") |
| 383 | cmd = 'data hexsamples 4' |
| 384 | core.console(cmd) |
| 385 | print("^^ use this values as input for the following answers (one 2-digit-value per question/answer):") |
| 386 | -- enter MCD & MSN (in hex) |
| 387 | MCD = utils.input("type in MCD as 2-digit value - e.g.: 00", plainBytes[1]) |
| 388 | MSN0 = utils.input("type in MSN0 as 2-digit value - e.g.: 01", plainBytes[2]) |
| 389 | MSN1 = utils.input("type in MSN1 as 2-digit value - e.g.: 02", plainBytes[3]) |
| 390 | MSN2 = utils.input("type in MSN2 as 2-digit value - e.g.: 03", plainBytes[4]) |
| 391 | |
| 392 | -- calculate crc8 over MCD & MSN |
| 393 | cmd = MCD..MSN0..MSN1..MSN2 |
| 394 | MCC = ("%02x"):format(utils.Crc8Legic(cmd)) |
| 395 | print("MCD:"..MCD..", MSN:"..MSN0.." "..MSN1.." "..MSN2..", MCC:"..MCC) |
| 396 | |
| 397 | -- calculate new Segment-CRC for each valid segment |
| 398 | SegCrcs = getSegmentCrcBytes(plainBytes) |
| 399 | for i=0, (#SegCrcs-1) do |
| 400 | -- SegCrcs[i]-4 = address of first byte of segmentHeader (low byte segment-length) |
| 401 | segLen=tonumber(("%1x"):format(tonumber(bit32.extract("0x"..plainBytes[(SegCrcs[i]-3)],0,3),16))..("%02x"):format(tonumber(plainBytes[SegCrcs[i]-4],16)),16) |
| 402 | segStart=(SegCrcs[i]-4) |
| 403 | segEnd=(SegCrcs[i]-4+segLen) |
| 404 | KGH=CheckKgh(plainBytes,segStart,segEnd) |
| 405 | if (KGH) then |
| 406 | print("'Kaba Group Header' detected - re-calculate...") |
| 407 | end |
| 408 | cmd = MCD..MSN0..MSN1..MSN2..plainBytes[SegCrcs[i]-4]..plainBytes[SegCrcs[i]-3]..plainBytes[SegCrcs[i]-2]..plainBytes[SegCrcs[i]-1] |
| 409 | plainBytes[SegCrcs[i]] = ("%02x"):format(utils.Crc8Legic(cmd)) |
| 410 | end |
| 411 | |
| 412 | -- apply MCD & MSN to plain data |
| 413 | plainBytes[1] = MCD |
| 414 | plainBytes[2] = MSN0 |
| 415 | plainBytes[3] = MSN1 |
| 416 | plainBytes[4] = MSN2 |
| 417 | plainBytes[5] = MCC |
| 418 | |
| 419 | -- prepare plainBytes for writing (xor plain data with new MCC) |
| 420 | bytes = xorBytes(plainBytes, MCC) |
| 421 | |
| 422 | -- write data to file |
| 423 | if (writeOutputBytes(bytes, "myLegicClone.hex")) then |
| 424 | WriteBytes = utils.input("enter number of bytes to write?", SegCrcs[#SegCrcs]) |
| 425 | |
| 426 | -- load file into pm3-buffer |
| 427 | cmd = 'hf legic load myLegicClone.hex' |
| 428 | core.console(cmd) |
| 429 | |
| 430 | -- write pm3-buffer to Tag |
| 431 | for i=0, WriteBytes do |
| 432 | if ( i<5 or i>6) then |
| 433 | cmd = ('hf legic write 0x%02x 0x01'):format(i) |
| 434 | core.console(cmd) |
| 435 | elseif (i == 6) then |
| 436 | -- write DCF in reverse order (requires 'mosci-patch') |
| 437 | cmd = 'hf legic write 0x05 0x02' |
| 438 | core.console(cmd) |
| 439 | else |
| 440 | print("skipping byte 0x05 - will be written next step") |
| 441 | end |
| 442 | utils.Sleep(0.2) |
| 443 | end |
| 444 | end |
| 445 | end |
| 446 | |
| 447 | -- main function |
| 448 | function main(args) |
| 449 | -- some variables |
| 450 | local i=0 |
| 451 | local oldcrc, newcrc, infile, outfile |
| 452 | local bytes = {} |
| 453 | local segments = {} |
| 454 | |
| 455 | -- parse arguments for the script |
| 456 | for o, a in getopt.getopt(args, 'hwsdc:i::o:') do |
| 457 | -- output file |
| 458 | if o == "o" then |
| 459 | outfile = a |
| 460 | ofs = true |
| 461 | if (file_check(a)) then |
| 462 | local answer = utils.confirm("\nthe output-file "..a.." alredy exists!\nthis will delete the previous content!\ncontinue?") |
| 463 | if (answer==false) then return oops("quiting") end |
| 464 | end |
| 465 | end |
| 466 | -- input file |
| 467 | if o == "i" then |
| 468 | infile = a |
| 469 | if (file_check(infile)==false) then |
| 470 | return oops("input file: "..infile.." not found") |
| 471 | else |
| 472 | bytes = getInputBytes(infile) |
| 473 | oldcrc = bytes[5] |
| 474 | ifs = true |
| 475 | if (bytes == false) then return oops('couldnt get input bytes') end |
| 476 | end |
| 477 | i = i+1 |
| 478 | end |
| 479 | -- new crc |
| 480 | if o == "c" then |
| 481 | newcrc = a |
| 482 | ncs = true |
| 483 | end |
| 484 | -- display segments switch |
| 485 | if o == "d" then ds = true; end |
| 486 | -- display summary switch |
| 487 | if o == "s" then ss = true; end |
| 488 | -- write to tag switch |
| 489 | if o == "w" then ws = true; end |
| 490 | -- help |
| 491 | if o == "h" then return help() end |
| 492 | end |
| 493 | |
| 494 | if (not ifs) then return oops("option -i <input file> is required but missing") end |
| 495 | |
| 496 | -- bytes to plain |
| 497 | bytes = xorBytes(bytes, oldcrc) |
| 498 | |
| 499 | -- show segments (works only on plain bytes) |
| 500 | if (ds) then |
| 501 | print("+------------------------------------------- Segments -------------------------------------------+") |
| 502 | displaySegments(bytes); |
| 503 | end |
| 504 | |
| 505 | if (ofs and ncs) then |
| 506 | -- xor bytes with new crc |
| 507 | newBytes = xorBytes(bytes, newcrc) |
| 508 | -- write output |
| 509 | if (writeOutputBytes(newBytes, outfile)) then |
| 510 | -- show summary if requested |
| 511 | if (ss) then |
| 512 | -- information |
| 513 | res = "\n+-------------------------------------------- Summary -------------------------------------------+" |
| 514 | res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:" |
| 515 | res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc,-2) |
| 516 | res = res .."\nyou may load the new file with: hf legic load "..outfile |
| 517 | res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC" |
| 518 | res = res .."\nafter writing this dump to a tag!" |
| 519 | res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3,Segment-Header0..3" |
| 520 | res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):" |
| 521 | res = res .."\nhf legic crc8 "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26] |
| 522 | -- this can not be calculated without knowing the new MCD, MSN0..2 |
| 523 | print(res) |
| 524 | end |
| 525 | end |
| 526 | else |
| 527 | if (ss) then |
| 528 | -- show why the output-file was not written |
| 529 | print("\nnew file not written - some arguments are missing ..") |
| 530 | print("output file: ".. (ofs and outfile or "not given")) |
| 531 | print("new crc: ".. (ncs and newcrc or "not given")) |
| 532 | end |
| 533 | end |
| 534 | -- write to tag |
| 535 | if (ws and #bytes == 1024) then |
| 536 | writeToTag(bytes) |
| 537 | end |
| 538 | end |
| 539 | |
| 540 | -- call main with arguments |
| 541 | main(args) |