| 1 | local cmds = require('commands') |
| 2 | local getopt = require('getopt') |
| 3 | local lib14a = require('read14a') |
| 4 | local utils = require('utils') |
| 5 | local pre = require('precalc') |
| 6 | local toys = require('default_toys') |
| 7 | |
| 8 | local lsh = bit32.lshift |
| 9 | local rsh = bit32.rshift |
| 10 | local bor = bit32.bor |
| 11 | local band = bit32.band |
| 12 | |
| 13 | example =[[ |
| 14 | script run tnp3clone |
| 15 | script run tnp3clone -h |
| 16 | script run tnp3clone -l |
| 17 | script run tnp3clone -t aa00 -s 0030 |
| 18 | |
| 19 | ]] |
| 20 | author = "Iceman" |
| 21 | usage = "script run tnp3clone -t <toytype> -s <subtype>" |
| 22 | desc =[[ |
| 23 | This script will try making a barebone clone of a tnp3 tag on to a magic generation1 card. |
| 24 | |
| 25 | Arguments: |
| 26 | -h : this help |
| 27 | -l : list all known toy tokens |
| 28 | -t <data> : toytype id, 4hex symbols |
| 29 | -s <data> : subtype id, 4hex symbols |
| 30 | |
| 31 | For fun, try the following subtype id: |
| 32 | 0612 - Lightcore |
| 33 | 0118 - Series 1 |
| 34 | 0138 - Series 2 |
| 35 | 0234 - Special |
| 36 | 023c - Special |
| 37 | 0020 - Swapforce |
| 38 | ]] |
| 39 | |
| 40 | |
| 41 | -- This is only meant to be used when errors occur |
| 42 | function oops(err) |
| 43 | print("ERROR: ",err) |
| 44 | end |
| 45 | -- Usage help |
| 46 | function help() |
| 47 | print(desc) |
| 48 | print("Example usage") |
| 49 | print(example) |
| 50 | end |
| 51 | |
| 52 | local function waitCmd() |
| 53 | local response = core.WaitForResponseTimeout(cmds.CMD_ACK,2000) |
| 54 | if response then |
| 55 | local count,cmd,arg0 = bin.unpack('LL',response) |
| 56 | if(arg0==1) then |
| 57 | local count,arg1,arg2,data = bin.unpack('LLH511',response,count) |
| 58 | return data:sub(1,32) |
| 59 | else |
| 60 | return nil, "Couldn't read block." |
| 61 | end |
| 62 | end |
| 63 | return nil, "No response from device" |
| 64 | end |
| 65 | |
| 66 | local function readblock( blocknum, keyA ) |
| 67 | -- Read block 0 |
| 68 | cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blocknum, arg2 = 0, arg3 = 0, data = keyA} |
| 69 | err = core.SendCommand(cmd:getBytes()) |
| 70 | if err then return nil, err end |
| 71 | local block0, err = waitCmd() |
| 72 | if err then return nil, err end |
| 73 | return block0 |
| 74 | end |
| 75 | local function readmagicblock( blocknum ) |
| 76 | -- Read block 0 |
| 77 | local CSETBLOCK_SINGLE_OPERATION = 0x1F |
| 78 | cmd = Command:new{cmd = cmds.CMD_MIFARE_CGETBLOCK, arg1 = CSETBLOCK_SINGLE_OPERATION, arg2 = 0, arg3 = blocknum} |
| 79 | err = core.SendCommand(cmd:getBytes()) |
| 80 | if err then return nil, err end |
| 81 | local block0, err = waitCmd() |
| 82 | if err then return nil, err end |
| 83 | return block0 |
| 84 | end |
| 85 | |
| 86 | local function main(args) |
| 87 | |
| 88 | print( string.rep('--',20) ) |
| 89 | print( string.rep('--',20) ) |
| 90 | |
| 91 | local numBlocks = 64 |
| 92 | local cset = 'hf mf csetbl ' |
| 93 | local csetuid = 'hf mf csetuid ' |
| 94 | local cget = 'hf mf cgetbl ' |
| 95 | local empty = '00000000000000000000000000000000' |
| 96 | local AccAndKeyB = '7F078869000000000000' |
| 97 | -- Defaults to Gusto |
| 98 | local toytype = 'C201' |
| 99 | local subtype = '0030' |
| 100 | local DEBUG = true |
| 101 | |
| 102 | -- Arguments for the script |
| 103 | for o, a in getopt.getopt(args, 'ht:s:l') do |
| 104 | if o == "h" then return help() end |
| 105 | if o == "t" then toytype = a end |
| 106 | if o == "s" then subtype = a end |
| 107 | if o == "l" then return toys.List() end |
| 108 | end |
| 109 | |
| 110 | if #toytype ~= 4 then return oops('Wrong size - toytype. (4hex symbols)') end |
| 111 | if #subtype ~= 4 then return oops('Wrong size - subtype. (4hex symbols)') end |
| 112 | |
| 113 | -- look up type, find & validate types |
| 114 | local item = toys.Find( toytype, subtype) |
| 115 | if item then |
| 116 | print( (' Looking up input: Found %s - %s (%s)'):format(item[6],item[5], item[4]) ) |
| 117 | else |
| 118 | print('Didn\'t find item type. If you are sure about it, report it in') |
| 119 | end |
| 120 | --15,16 |
| 121 | --13-14 |
| 122 | |
| 123 | |
| 124 | -- find tag |
| 125 | result, err = lib14a.read1443a(false) |
| 126 | if not result then return oops(err) end |
| 127 | |
| 128 | -- load keys |
| 129 | local akeys = pre.GetAll(result.uid) |
| 130 | local keyA = akeys:sub(1, 12 ) |
| 131 | |
| 132 | local b0 = readblock(0,keyA) |
| 133 | if not b0 then |
| 134 | print('failed reading block with factorydefault key. Trying chinese magic read.') |
| 135 | b0, err = readmagicblock(0) |
| 136 | if not b0 then |
| 137 | oops(err) |
| 138 | return oops('failed reading block with chinese magic command. quitting...') |
| 139 | end |
| 140 | end |
| 141 | |
| 142 | -- wipe card. |
| 143 | local cmd = (csetuid..'%s 0004 08 w'):format(result.uid) |
| 144 | core.console(cmd) |
| 145 | |
| 146 | local b1 = toytype..string.rep('00',10)..subtype |
| 147 | |
| 148 | local calc = utils.Crc16(b0..b1) |
| 149 | local calcEndian = bor(rsh(calc,8), lsh(band(calc, 0xff), 8)) |
| 150 | |
| 151 | local cmd = (cset..'1 %s%04x'):format( b1, calcEndian) |
| 152 | core.console(cmd) |
| 153 | |
| 154 | local pos, key |
| 155 | for blockNo = 2, numBlocks-1, 1 do |
| 156 | pos = (math.floor( blockNo / 4 ) * 12)+1 |
| 157 | key = akeys:sub(pos, pos + 11 ) |
| 158 | if blockNo%4 == 3 then |
| 159 | cmd = ('%s %d %s%s'):format(cset,blockNo,key,AccAndKeyB) |
| 160 | core.console(cmd) |
| 161 | end |
| 162 | end |
| 163 | core.clearCommandBuffer() |
| 164 | end |
| 165 | main(args) |