]> git.zerfleddert.de Git - proxmark3-svn/blame - client/scripts/tnp3sim.lua
FIX: lf t55xx config now handles offsets.
[proxmark3-svn] / client / scripts / tnp3sim.lua
CommitLineData
b915fda3 1local cmds = require('commands')
2local getopt = require('getopt')
3local bin = require('bin')
4local lib14a = require('read14a')
5local utils = require('utils')
6local md5 = require('md5')
7local toyNames = require('default_toys')
8
9example =[[
10 1. script run tnp3sim
11 2. script run tnp3sim -m
12 3. script run tnp3sim -m -i myfile
13]]
14author = "Iceman"
15usage = "script run tnp3sim -h -m -i <filename>"
16desc =[[
17This script will try to load a binary datadump of a Mifare TNP3xxx card.
18It vill try to validate all checksums and view some information stored in the dump
19For an experimental mode, it tries to manipulate some data.
20At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim"
21
22Arguments:
23 -h : this help
24 -m : Maxed out items (experimental)
25 -i : filename for the datadump to read (bin)
26]]
27
28local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
04a6113f 29local DEBUG = false -- the debug flag
30
31
32local band = bit32.band
33local bor = bit32.bor
34local lshift = bit32.lshift
35local rshift = bit32.rshift
36local byte = string.byte
37local char = string.char
38local sub = string.sub
39local format = string.format
40
b915fda3 41---
42-- A debug printout-function
43function dbg(args)
44 if not DEBUG then
45 return
46 end
47
48 if type(args) == "table" then
49 local i = 1
50 while result[i] do
51 dbg(result[i])
52 i = i+1
53 end
54 else
55 print("###", args)
56 end
57end
58---
59-- This is only meant to be used when errors occur
60function oops(err)
61 print("ERROR: ",err)
62end
63---
64-- Usage help
65function help()
66 print(desc)
67 print("Example usage")
68 print(example)
69end
70--
71-- Exit message
72function ExitMsg(msg)
73 print( string.rep('--',20) )
74 print( string.rep('--',20) )
75 print(msg)
76 print()
77end
78
b915fda3 79local function writedumpfile(infile)
80 t = infile:read("*all")
81 len = string.len(t)
82 local len,hex = bin.unpack(("H%d"):format(len),t)
83 return hex
84end
85-- blocks with data
86-- there are two dataareas, in block 8 or block 36, ( 1==8 ,
87-- checksum type = 0, 1, 2, 3
88local function GetCheckSum(blocks, dataarea, chksumtype)
89
90 local crc
91 local area = 36
92 if dataarea == 1 then
93 area = 8
94 end
95
96 if chksumtype == 0 then
97 crc = blocks[1]:sub(29,32)
98 elseif chksumtype == 1 then
99 crc = blocks[area]:sub(29,32)
100 elseif chksumtype == 2 then
101 crc = blocks[area]:sub(25,28)
102 elseif chksumtype == 3 then
103 crc = blocks[area]:sub(21,24)
104 end
105 return utils.SwapEndianness(crc,16)
106end
107
108local function SetCheckSum(blocks, chksumtype)
109
110 if blocks == nil then return nil, 'Argument \"blocks\" nil' end
111 local newcrc
112 local area1 = 8
113 local area2 = 36
114
115 if chksumtype == 0 then
116 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0))
117 blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
118 elseif chksumtype == 1 then
119 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1))
120 blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
121 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1))
122 blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
123 elseif chksumtype == 2 then
124 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2))
125 blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32)
126 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2))
127 blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32)
128 elseif chksumtype == 3 then
129 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3))
130 blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32)
131 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3))
132 blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32)
133 end
134end
135
136function CalcCheckSum(blocks, dataarea, chksumtype)
137 local area = 36
138 if dataarea == 1 then
139 area = 8
140 end
141
142 if chksumtype == 0 then
143 data = blocks[0]..blocks[1]:sub(1,28)
144 elseif chksumtype == 1 then
145 data = blocks[area]:sub(1,28)..'0500'
146 elseif chksumtype == 2 then
147 data = blocks[area+1]..blocks[area+2]..blocks[area+4]
148 elseif chksumtype == 3 then
149 data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0)
150 end
151 return utils.Crc16(data)
152end
153
154local function ValidateCheckSums(blocks)
155
156 local isOk, crc, calc
157 -- Checksum Type 0
158 crc = GetCheckSum(blocks,1,0)
159 calc = CalcCheckSum(blocks, 1, 0)
160 if crc == calc then isOk='Ok' else isOk = 'Error' end
161 io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk))
162
163 -- Checksum Type 1 (DATAAREAHEADER 1)
164 crc = GetCheckSum(blocks,1,1)
165 calc = CalcCheckSum(blocks,1,1)
166 if crc == calc then isOk='Ok' else isOk = 'Error' end
167 io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
168
169 -- Checksum Type 1 (DATAAREAHEADER 2)
170 crc = GetCheckSum(blocks,2,1)
171 calc = CalcCheckSum(blocks,2,1)
172 if crc == calc then isOk='Ok' else isOk = 'Error' end
173 io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
174
175 -- Checksum Type 2 (DATAAREA 1)
176 crc = GetCheckSum(blocks,1,2)
177 calc = CalcCheckSum(blocks,1,2)
178 if crc == calc then isOk='Ok' else isOk = 'Error' end
179 io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
180
181 -- Checksum Type 2 (DATAAREA 2)
182 crc = GetCheckSum(blocks,2,2)
183 calc = CalcCheckSum(blocks,2,2)
184 if crc == calc then isOk='Ok' else isOk = 'Error' end
185 io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
186
187 -- Checksum Type 3 (DATAAREA 1)
188 crc = GetCheckSum(blocks,1,3)
189 calc = CalcCheckSum(blocks,1,3)
190 if crc == calc then isOk='Ok' else isOk = 'Error' end
191 io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
192
193 -- Checksum Type 3 (DATAAREA 2)
194 crc = GetCheckSum(blocks,2,3)
195 calc = CalcCheckSum(blocks,2,3)
196 if crc == calc then isOk='Ok' else isOk = 'Error' end
197 io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
198end
199
b915fda3 200local function LoadEmulator(blocks)
201 local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
202 local cmd
203 local blockdata
204 for _,b in pairs(blocks) do
205
206 blockdata = b
207
208 if _%4 ~= 3 then
209 if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then
210 local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT)
211 local baseStr = utils.ConvertHexToAscii(base)
212 local key = md5.sumhexa(baseStr)
213 local enc = core.aes(key, blockdata)
214 local hex = utils.ConvertAsciiToBytes(enc)
215 hex = utils.ConvertBytesToHex(hex)
216
217 blockdata = hex
218 io.write( _..',')
219 end
220 end
221
222 cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata}
223 local err = core.SendCommand(cmd:getBytes())
224 if err then
225 return err
226 end
227 end
228 io.write('\n')
229end
230
04a6113f 231local function Num2Card(m, l)
232
233 local k = {
234 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B,
235 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54,0x56, 0x57, 0x58, 0x59, 0x5A, 0x00
236 }
237 local msw = tonumber(utils.SwapEndiannessStr(m,32),16)
238 local lsw = tonumber(utils.SwapEndiannessStr(l,32),16)
239
240 if msw > 0x17ea1 then
241 return "too big"
242 end
243
244 if msw == 0x17ea1 and lsw > 0x8931fee8 then
245 return "out of range"
246 end
247
248 local s = ""
249 local index
250 for i = 1,10 do
251 index, msw, lsw = DivideByK( msw, lsw)
252 if ( index <= 1 ) then
253 s = char(k[index]) .. s
254 else
255 s = char(k[index-1]) .. s
256 end
257 print (index-1, msw, lsw)
258 end
259 return s
260end
261--33LRT-LM9Q9
262--7, 122, 3474858630
263--20, 4, 1008436634
264--7, 0, 627182959
265--17, 0, 21626998
266--16, 0, 745758
267--23, 0, 25715
268--21, 0, 886
269--16, 0, 30
270--1, 0, 1
271--1, 0, 0
272
273function DivideByK(msw, lsw)
274
275 local lowLSW
276 local highLSW
277 local remainder = 0
278 local RADIX = 29
279
280 --local num = 0 | band( rshift(msw,16), 0xffff)
281 local num = band( rshift(msw, 16), 0xffff)
282
283 --highLSW = 0 | lshift( (num / RADIX) , 16)
284 highLSW = lshift( (num / RADIX) , 16)
285 remainder = num % RADIX
286
287 num = bor( lshift(remainder,16), band(msw, 0xffff))
288
289 --highLSW |= num / RADIX
290 highLSW = highLSW or (num / RADIX)
291 remainder = num % RADIX
292
293 num = bor( lshift(remainder,16), ( band(rshift(lsw,16), 0xffff)))
294
295 --lowLSW = 0 | (num / RADIX) << 16
296 lowLSW = 0 or (lshift( (num / RADIX), 16))
297 remainder = num % RADIX
298
299 num = bor( lshift(remainder,16) , band(lsw, 0xffff) )
300
301 lowLSW = bor(lowLSW, (num / RADIX))
302 remainder = num % RADIX
303 return remainder, highLSW, lowLSW
304
305 uint num = 0 | (msw >> 16) & 0xffff;
306
307 highLSW = 0 | (num / RADIX) << 16;
308 remainder = num % RADIX;
309
310 num = (remainder << 16) | (msw & 0xffff);
311
312 highLSW |= num / RADIX;
313 remainder = num % RADIX;
314
315 num = (remainder << 16) | ((lsw >> 16) & 0xffff);
316
317 lowLSW = 0 | (num / RADIX) << 16;
318 remainder = num % RADIX;
319
320 num = (remainder << 16) | (lsw & 0xffff);
321
322 lowLSW |= num / RADIX;
323 remainder = num % RADIX;
324
325end
326
b915fda3 327local function main(args)
328
329 print( string.rep('--',20) )
330 print( string.rep('--',20) )
331
332 local result, err, hex
333 local maxed = false
334 local inputTemplate = "dumpdata.bin"
335 local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M");
336
337 -- Arguments for the script
338 for o, a in getopt.getopt(args, 'hmi:o:') do
339 if o == "h" then return help() end
340 if o == "m" then maxed = true end
341 if o == "o" then outputTemplate = a end
342 if o == "i" then inputTemplate = a end
343 end
344
345 -- Turn off Debug
346 local cmdSetDbgOff = "hf mf dbg 0"
347 core.console( cmdSetDbgOff)
348
5149e37e 349 -- if not loadFromDump then
350 -- -- Look for tag present on reader,
351 -- result, err = lib14a.read1443a(false)
352 -- if not result then return oops(err) end
b915fda3 353
5149e37e 354 -- core.clearCommandBuffer()
b915fda3 355
5149e37e 356 -- if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
357 -- return oops('This is not a TNP3xxx tag. aborting.')
358 -- end
b915fda3 359
5149e37e 360 -- -- Show tag info
361 -- print((' Found tag : %s'):format(result.name))
362 -- end
b915fda3 363
364 -- Load dump.bin file
365 print( (' Load data from %s'):format(inputTemplate))
366 hex, err = utils.ReadDumpFile(inputTemplate)
367 if not hex then return oops(err) end
368
369 local blocks = {}
370 local blockindex = 0
371 for i = 1, #hex, 32 do
372 blocks[blockindex] = hex:sub(i,i+31)
373 blockindex = blockindex + 1
374 end
375
376 if DEBUG then
377 print('Validating checksums in the loaded datadump')
378 ValidateCheckSums(blocks)
379 end
380
381 --
382 print( string.rep('--',20) )
383 print(' Gathering info')
384 local uid = blocks[0]:sub(1,8)
385 local itemtype = blocks[1]:sub(1,4)
04a6113f 386 local cardidLsw = blocks[1]:sub(9,16)
387 local cardidMsw = blocks[1]:sub(17,24)
b915fda3 388
04a6113f 389 local itemtypename = toyNames[itemtype]
390 if itemtypename == nil then
391 itemtypename = toyNames[utils.SwapEndiannessStr(itemtype,16)]
392 end
393
b915fda3 394 -- Show info
395 print( string.rep('--',20) )
04a6113f 396 print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, itemtypename) )
b915fda3 397 print( (' UID : 0x%s'):format(uid) )
04a6113f 398 print( (' CARDID : 0x%s %s [%s]'):format(
399 cardidMsw,cardidLsw,
400 Num2Card(cardidMsw, cardidLsw))
401 )
b915fda3 402 print( string.rep('--',20) )
403
04a6113f 404
b915fda3 405 -- lets do something.
406 --
407 local experience = blocks[8]:sub(1,6)
408 print(('Experience : %d'):format(utils.SwapEndianness(experience,24)))
409 local money = blocks[8]:sub(7,10)
410 print(('Money : %d'):format(utils.SwapEndianness(money,16)))
411 local fairy = blocks[9]:sub(1,8)
412 --FD0F = Left, FF0F = Right
413 local path = 'not choosen'
414 if fairy:sub(2,2) == 'D' then
415 path = 'Left'
416 elseif fairy:sub(2,2) == 'F' then
417 path = 'Right'
418 end
419 print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path))
420
421 local hat = blocks[9]:sub(8,11)
422 print(('Hat : %d'):format(utils.SwapEndianness(hat,16)))
423
424 --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100.
425 local heropoints = blocks[13]:sub(20,23)
426 print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16)))
427
428 --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed.
429 local challenges = blocks[16]:sub(25,32)
430 print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32)))
431
432 if maxed then
433 print('Lets try to max out some values')
434 -- max out money, experience
435 --print (blocks[8])
436 blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32)
437 blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32)
438 --print (blocks[8])
439
440 -- max out hero challenges
441 --print (blocks[16])
442 blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF'
443 blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF'
444 --print (blocks[16])
445
446 -- max out heropoints
447 --print (blocks[13])
448 blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32)
449 blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32)
450 --print (blocks[13])
451
452 -- Update Checksums
453 print('Updating all checksums')
454 SetCheckSum(blocks, 3)
455 SetCheckSum(blocks, 2)
456 SetCheckSum(blocks, 1)
457 SetCheckSum(blocks, 0)
458
459 print('Validating all checksums')
460 ValidateCheckSums(blocks)
461 end
462
463 --Load dumpdata to emulator memory
464 if DEBUG then
465 print('Sending dumpdata to emulator memory')
466 err = LoadEmulator(blocks)
467 if err then return oops(err) end
468 core.clearCommandBuffer()
8e726f6c 469 print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..'\" <--')
b915fda3 470 end
471end
472main(args)
Impressum, Datenschutz