]> cvs.zerfleddert.de Git - proxmark3-svn/blob - client/scripts/tnp3sim.lua
ce7720226bf0abf96489016b431e2ac95a954a57
[proxmark3-svn] / client / scripts / tnp3sim.lua
1 local cmds = require('commands')
2 local getopt = require('getopt')
3 local bin = require('bin')
4 local lib14a = require('read14a')
5 local utils = require('utils')
6 local md5 = require('md5')
7 local toyNames = require('default_toys')
8
9 example =[[
10 1. script run tnp3sim
11 2. script run tnp3sim -m
12 3. script run tnp3sim -m -i myfile
13 ]]
14 author = "Iceman"
15 usage = "script run tnp3sim -h -m -i <filename>"
16 desc =[[
17 This script will try to dump the contents of a Mifare TNP3xxx card.
18 It will need a valid KeyA in order to find the other keys and decode the card.
19 Arguments:
20 -h : this help
21 -m : Maxed out item
22 -i : filename for the datadump to read (bin)
23 ]]
24
25 local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
26
27 local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
28 local DEBUG = true -- the debug flag
29 ---
30 -- A debug printout-function
31 function dbg(args)
32 if not DEBUG then
33 return
34 end
35
36 if type(args) == "table" then
37 local i = 1
38 while result[i] do
39 dbg(result[i])
40 i = i+1
41 end
42 else
43 print("###", args)
44 end
45 end
46 ---
47 -- This is only meant to be used when errors occur
48 function oops(err)
49 print("ERROR: ",err)
50 end
51 ---
52 -- Usage help
53 function help()
54 print(desc)
55 print("Example usage")
56 print(example)
57 end
58 --
59 -- Exit message
60 function ExitMsg(msg)
61 print( string.rep('--',20) )
62 print( string.rep('--',20) )
63 print(msg)
64 print()
65 end
66
67 local function writedumpfile(infile)
68 t = infile:read("*all")
69 len = string.len(t)
70 local len,hex = bin.unpack(("H%d"):format(len),t)
71 return hex
72 end
73 -- blocks with data
74 -- there are two dataareas, in block 8 or block 36, ( 1==8 ,
75 -- checksum type = 0, 1, 2, 3
76 local function GetCheckSum(blocks, dataarea, chksumtype)
77
78 local crc
79 local area = 36
80 if dataarea == 1 then
81 area = 8
82 end
83
84 if chksumtype == 0 then
85 crc = blocks[1]:sub(29,32)
86 elseif chksumtype == 1 then
87 crc = blocks[area]:sub(29,32)
88 elseif chksumtype == 2 then
89 crc = blocks[area]:sub(25,28)
90 elseif chksumtype == 3 then
91 crc = blocks[area]:sub(21,24)
92 end
93 return utils.SwapEndianness(crc,16)
94 end
95
96 local function SetCheckSum(blocks, chksumtype)
97
98 if blocks == nil then return nil, 'Argument \"blocks\" nil' end
99 local newcrc
100 local area1 = 8
101 local area2 = 36
102
103 if chksumtype == 0 then
104 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0))
105 blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
106 elseif chksumtype == 1 then
107 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1))
108 blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
109 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1))
110 blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
111 elseif chksumtype == 2 then
112 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2))
113 blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32)
114 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2))
115 blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32)
116 elseif chksumtype == 3 then
117 newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3))
118 blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32)
119 newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3))
120 blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32)
121 end
122 end
123
124 function CalcCheckSum(blocks, dataarea, chksumtype)
125 local area = 36
126 if dataarea == 1 then
127 area = 8
128 end
129
130 if chksumtype == 0 then
131 data = blocks[0]..blocks[1]:sub(1,28)
132 elseif chksumtype == 1 then
133 data = blocks[area]:sub(1,28)..'0500'
134 elseif chksumtype == 2 then
135 data = blocks[area+1]..blocks[area+2]..blocks[area+4]
136 elseif chksumtype == 3 then
137 data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0)
138 end
139 return utils.Crc16(data)
140 end
141
142 local function ValidateCheckSums(blocks)
143
144 local isOk, crc, calc
145 -- Checksum Type 0
146 crc = GetCheckSum(blocks,1,0)
147 calc = CalcCheckSum(blocks, 1, 0)
148 if crc == calc then isOk='Ok' else isOk = 'Error' end
149 io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk))
150
151 -- Checksum Type 1 (DATAAREAHEADER 1)
152 crc = GetCheckSum(blocks,1,1)
153 calc = CalcCheckSum(blocks,1,1)
154 if crc == calc then isOk='Ok' else isOk = 'Error' end
155 io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
156
157 -- Checksum Type 1 (DATAAREAHEADER 2)
158 crc = GetCheckSum(blocks,2,1)
159 calc = CalcCheckSum(blocks,2,1)
160 if crc == calc then isOk='Ok' else isOk = 'Error' end
161 io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
162
163 -- Checksum Type 2 (DATAAREA 1)
164 crc = GetCheckSum(blocks,1,2)
165 calc = CalcCheckSum(blocks,1,2)
166 if crc == calc then isOk='Ok' else isOk = 'Error' end
167 io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
168
169 -- Checksum Type 2 (DATAAREA 2)
170 crc = GetCheckSum(blocks,2,2)
171 calc = CalcCheckSum(blocks,2,2)
172 if crc == calc then isOk='Ok' else isOk = 'Error' end
173 io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
174
175 -- Checksum Type 3 (DATAAREA 1)
176 crc = GetCheckSum(blocks,1,3)
177 calc = CalcCheckSum(blocks,1,3)
178 if crc == calc then isOk='Ok' else isOk = 'Error' end
179 io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
180
181 -- Checksum Type 3 (DATAAREA 2)
182 crc = GetCheckSum(blocks,2,3)
183 calc = CalcCheckSum(blocks,2,3)
184 if crc == calc then isOk='Ok' else isOk = 'Error' end
185 io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
186 end
187
188 -- function EncryptData()
189 -- local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
190 -- if blockNo%4 ~= 3 then
191 -- if blockNo < 8 then
192 -- -- Block 0-7 not encrypted
193 -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
194 -- else
195 -- local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT)
196 -- local baseStr = utils.ConvertHexToAscii(base)
197 -- local md5hash = md5.sumhexa(baseStr)
198 -- local aestest = core.aes(md5hash, blockdata)
199
200 -- local hex = utils.ConvertAsciiToBytes(aestest)
201 -- hex = utils.ConvertBytesToHex(hex)
202 -- --local _,hex = bin.unpack(("H%d"):format(16),aestest)
203
204 -- -- blocks with zero not encrypted.
205 -- if string.find(blockdata, '^0+$') then
206 -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
207 -- else
208 -- blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex)
209 -- io.write( blockNo..',')
210 -- end
211 -- end
212 -- else
213 -- -- Sectorblocks, not encrypted
214 -- blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32))
215 -- end
216
217 -- end
218
219 local function LoadEmulator(blocks)
220 local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
221 local cmd
222 local blockdata
223 for _,b in pairs(blocks) do
224
225 blockdata = b
226
227 if _%4 ~= 3 then
228 if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then
229 local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT)
230 local baseStr = utils.ConvertHexToAscii(base)
231 local key = md5.sumhexa(baseStr)
232 local enc = core.aes(key, blockdata)
233 local hex = utils.ConvertAsciiToBytes(enc)
234 hex = utils.ConvertBytesToHex(hex)
235
236 blockdata = hex
237 io.write( _..',')
238 end
239 end
240
241 cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata}
242 local err = core.SendCommand(cmd:getBytes())
243 if err then
244 return err
245 end
246 end
247 io.write('\n')
248 end
249
250 local function main(args)
251
252 print( string.rep('--',20) )
253 print( string.rep('--',20) )
254
255 local result, err, hex
256 local maxed = false
257 local inputTemplate = "dumpdata.bin"
258 local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M");
259
260 -- Arguments for the script
261 for o, a in getopt.getopt(args, 'hmi:o:') do
262 if o == "h" then return help() end
263 if o == "m" then maxed = true end
264 if o == "o" then outputTemplate = a end
265 if o == "i" then inputTemplate = a end
266 end
267
268 -- Turn off Debug
269 local cmdSetDbgOff = "hf mf dbg 0"
270 core.console( cmdSetDbgOff)
271
272 -- Look for tag present on reader,
273 result, err = lib14a.read1443a(false)
274 if not result then return oops(err) end
275
276 core.clearCommandBuffer()
277
278 if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
279 return oops('This is not a TNP3xxx tag. aborting.')
280 end
281
282 -- Show tag info
283 print((' Found tag : %s'):format(result.name))
284
285 -- Load dump.bin file
286 print( (' Load data from %s'):format(inputTemplate))
287 hex, err = utils.ReadDumpFile(inputTemplate)
288 if not hex then return oops(err) end
289
290 local blocks = {}
291 local blockindex = 0
292 for i = 1, #hex, 32 do
293 blocks[blockindex] = hex:sub(i,i+31)
294 blockindex = blockindex + 1
295 end
296
297 if DEBUG then
298 print('Validating checksums in the loaded datadump')
299 ValidateCheckSums(blocks)
300 end
301
302 --
303 print( string.rep('--',20) )
304 print(' Gathering info')
305 local uid = blocks[0]:sub(1,8)
306 local itemtype = blocks[1]:sub(1,4)
307 local cardid = blocks[1]:sub(9,24)
308
309 -- Show info
310 print( string.rep('--',20) )
311 print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
312 print( (' UID : 0x%s'):format(uid) )
313 print( (' CARDID : 0x%s'):format(cardid ) )
314 print( string.rep('--',20) )
315
316 -- lets do something.
317 --
318 local experience = blocks[8]:sub(1,6)
319 print(('Experience : %d'):format(utils.SwapEndianness(experience,24)))
320 local money = blocks[8]:sub(7,10)
321 print(('Money : %d'):format(utils.SwapEndianness(money,16)))
322 local fairy = blocks[9]:sub(1,8)
323 --FD0F = Left, FF0F = Right
324 local path = 'not choosen'
325 if fairy:sub(2,2) == 'D' then
326 path = 'Left'
327 elseif fairy:sub(2,2) == 'F' then
328 path = 'Right'
329 end
330 print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path))
331
332 local hat = blocks[9]:sub(8,11)
333 print(('Hat : %d'):format(utils.SwapEndianness(hat,16)))
334
335 --0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100.
336 local heropoints = blocks[13]:sub(20,23)
337 print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16)))
338
339 --0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed.
340 local challenges = blocks[16]:sub(25,32)
341 print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32)))
342
343 if maxed then
344 print('Lets try to max out some values')
345 -- max out money, experience
346 --print (blocks[8])
347 blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32)
348 blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32)
349 --print (blocks[8])
350
351 -- max out hero challenges
352 --print (blocks[16])
353 blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF'
354 blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF'
355 --print (blocks[16])
356
357 -- max out heropoints
358 --print (blocks[13])
359 blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32)
360 blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32)
361 --print (blocks[13])
362
363 -- Update Checksums
364 print('Updating all checksums')
365 SetCheckSum(blocks, 3)
366 SetCheckSum(blocks, 2)
367 SetCheckSum(blocks, 1)
368 SetCheckSum(blocks, 0)
369
370 print('Validating all checksums')
371 ValidateCheckSums(blocks)
372 end
373
374 --Load dumpdata to emulator memory
375 if DEBUG then
376 print('Sending dumpdata to emulator memory')
377 err = LoadEmulator(blocks)
378 if err then return oops(err) end
379 core.clearCommandBuffer()
380 print('The simulation is now prepared. run \"hf mf sim\" ')
381 end
382 end
383 main(args)
Impressum, Datenschutz