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