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