]> git.zerfleddert.de Git - proxmark3-svn/blame - client/pm3_mfdread.py
chg: travis ci again
[proxmark3-svn] / client / pm3_mfdread.py
CommitLineData
f2ba7885 1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# mfdread.py - Mifare dumps parser in human readable format
5# Pavel Zhovner <pavel@zhovner.com>
6# https://github.com/zhovner/mfdread
7
8
9
10import codecs
11import sys
ce1cccd6 12import copy
f2ba7885 13from struct import unpack
14from datetime import datetime
15from bitstring import BitArray
16
ce1cccd6 17class Options:
18 FORCE_1K = False
f2ba7885 19
20if len(sys.argv) == 1:
21 print('''
22------------------
23Usage: mfdread.py ./dump.mfd
24Mifare dumps reader.
f2ba7885 25''')
26 sys.exit();
27
ce1cccd6 28def d(bytes):
29 decoded = codecs.decode(bytes, "hex")
30 try:
31 return str(decoded, "utf-8").rstrip('\0')
32 except:
33 return ""
f2ba7885 34
35
36class bashcolors:
37 BLUE = '\033[34m'
38 RED = '\033[91m'
39 GREEN = '\033[32m'
40 WARNING = '\033[93m'
41 ENDC = '\033[0m'
42
43
44def accbits_for_blocknum(accbits_str, blocknum):
45 '''
46 Decodes the access bit string for block "blocknum".
47 Returns the three access bits for the block or False if the
48 inverted bits do not match the access bits.
49 '''
50 bits = BitArray([0])
51 inverted = BitArray([0])
52 # Block 0 access bits
53 if blocknum == 0:
54 bits = BitArray([accbits_str[11], accbits_str[23], accbits_str[19]])
55 inverted = BitArray([accbits_str[7], accbits_str[3], accbits_str[15]])
56
57 # Block 0 access bits
58 elif blocknum == 1:
59 bits = BitArray([accbits_str[10], accbits_str[22], accbits_str[18]])
60 inverted = BitArray([accbits_str[6], accbits_str[2], accbits_str[14]])
61 # Block 0 access bits
62 elif blocknum == 2:
63 bits = BitArray([accbits_str[9], accbits_str[21], accbits_str[17]])
64 inverted = BitArray([accbits_str[5], accbits_str[1], accbits_str[13]])
65 # Sector trailer / Block 3 access bits
66 elif blocknum == 3:
67 bits = BitArray([accbits_str[8], accbits_str[20], accbits_str[16]])
68 inverted = BitArray([accbits_str[4], accbits_str[0], accbits_str[12]])
69
70 # Check the decoded bits
71 inverted.invert()
72 if bits.bin == inverted.bin:
73 return bits
74 else:
75 return False
76
77
ce1cccd6 78def accbits_to_permission_sector(accbits):
79 permissions = {
80 '000': "- A | A - | A A [read B]",
81 '010': "- - | A - | A - [read B]",
82 '100': "- B | A/B - | - B",
83 '110': "- - | A/B - | - -",
84 '001': "- A | A A | A A [transport]",
85 '011': "- B | A/B B | - B",
86 '101': "- - | A/B B | - -",
87 '111': "- - | A/B - | - -",
88 }
89 if isinstance(accbits, BitArray):
90 return permissions.get(accbits.bin, "unknown")
91 else:
92 return ""
93
94def accbits_to_permission_data(accbits):
95 permissions = {
96 '000': "A/B | A/B | A/B | A/B [transport]",
97 '010': "A/B | - | - | - [r/w]",
98 '100': "A/B | B | - | - [r/w]",
99 '110': "A/B | B | B | A/B [value]",
100 '001': "A/B | - | - | A/B [value]",
101 '011': " B | B | - | - [r/w]",
102 '101': " B | - | - | - [r/w]",
103 '111': " - | - | - | - [r/w]",
104 }
105 if isinstance(accbits, BitArray):
106 return permissions.get(accbits.bin, "unknown")
107 else:
108 return ""
f2ba7885 109
110
111def accbit_info(accbits):
112 '''
113 Returns a dictionary of a access bits for all three blocks in a sector.
114 If the access bits for block could not be decoded properly, the value is set to False.
115 '''
116 decAccbits = {}
117 # Decode access bits for all 4 blocks of the sector
118 for i in range(0, 4):
119 decAccbits[i] = accbits_for_blocknum(accbits, i)
120 return decAccbits
121
122
123
124
125
126def print_info(data):
127
128 blocksmatrix = []
129 blockrights = {}
130
131 # determine what dump we get 1k or 4k
132 if len(data) == 4096:
133 cardsize = 64
134 elif len(data) == 1024:
135 cardsize = 16
136 else:
137 print("Wrong file size: %d bytes.\nOnly 1024 or 4096 allowed." % len(data))
138 sys.exit();
139
ce1cccd6 140 if Options.FORCE_1K:
141 cardsize = 16
142
f2ba7885 143 # read all sectors
144 for i in range(0, cardsize):
145 start = i * 64
146 end = (i + 1) * 64
147 sector = data[start:end]
148 sector = codecs.encode(sector, 'hex')
149 if not type(sector) is str:
150 sector = str(sector, 'ascii')
151 blocksmatrix.append([sector[x:x+32] for x in range(0, len(sector), 32)])
152
ce1cccd6 153 blocksmatrix_clear = copy.deepcopy(blocksmatrix)
f2ba7885 154 # add colors for each keyA, access bits, KeyB
155 for c in range(0, len(blocksmatrix)):
156 # Fill in the access bits
157 blockrights[c] = accbit_info(BitArray('0x'+blocksmatrix[c][3][12:20]))
158 # Prepare colored output of the sector trailor
159 keyA = bashcolors.RED + blocksmatrix[c][3][0:12] + bashcolors.ENDC
160 accbits = bashcolors.GREEN + blocksmatrix[c][3][12:20] + bashcolors.ENDC
161 keyB = bashcolors.BLUE + blocksmatrix[c][3][20:32] + bashcolors.ENDC
162 blocksmatrix[c][3] = keyA + accbits + keyB
163
164
165 print("File size: %d bytes. Expected %d sectors" %(len(data),cardsize))
166 print("\n\tUID: " + blocksmatrix[0][0][0:8])
167 print("\tBCC: " + blocksmatrix[0][0][8:10])
168 print("\tSAK: " + blocksmatrix[0][0][10:12])
169 print("\tATQA: " + blocksmatrix[0][0][12:14])
170 print(" %sKey A%s %sAccess Bits%s %sKey B%s" %(bashcolors.RED,bashcolors.ENDC,bashcolors.GREEN,bashcolors.ENDC,bashcolors.BLUE,bashcolors.ENDC))
ce1cccd6 171 print("╔═════════╦═════╦══════════════════════════════════╦════════╦═════════════════════════════════════╗")
172 print("║ Sector ║Block║ Data ║ Access ║ A | Acc. | B ║")
173 print("║ ║ ║ ║ ║ r w | r w | r w [info] ║")
174 print("║ ║ ║ ║ ║ r | w | i | d/t/r ║")
f2ba7885 175 for q in range(0, len(blocksmatrix)):
ce1cccd6 176 print("╠═════════╬═════╬══════════════════════════════════╬════════╬═════════════════════════════════════╣")
f2ba7885 177
178 # z is the block in each sector
179 for z in range(0, len(blocksmatrix[q])):
180 # Format the access bits. Print ERR in case of an error
181 accbits = ""
182 if isinstance(blockrights[q][z], BitArray):
183 accbits = bashcolors.GREEN + blockrights[q][z].bin + bashcolors.ENDC
184 else:
185 accbits = bashcolors.WARNING + "ERR" + bashcolors.ENDC
186
ce1cccd6 187 if (q == 0 and z == 0):
188 permissions = "-"
189 elif (z == 3):
190 permissions = accbits_to_permission_sector(blockrights[q][z])
191 else:
192 permissions = accbits_to_permission_data(blockrights[q][z])
193
f2ba7885 194 # Add Padding after the sector number
195 padLen = max(1, 5 - len(str(q)))
196 padding = " " * padLen
197 # Only print the sector number in the second third row
198 if (z == 2):
ce1cccd6 199 print("║ %d%s║ %d ║ %s ║ %s ║ %-35s ║ %s" %(q,padding,z,blocksmatrix[q][z], accbits, permissions, d(blocksmatrix_clear[q][z])))
f2ba7885 200 else:
ce1cccd6 201 print("║ ║ %d ║ %s ║ %s ║ %-35s ║ %s" %(z,blocksmatrix[q][z], accbits, permissions, d(blocksmatrix_clear[q][z])))
202 print("╚═════════╩═════╩══════════════════════════════════╩════════╩═════════════════════════════════════╝")
203
204
205def main(args):
206 if args[0] == '-n':
207 args.pop(0)
208 bashcolors.BLUE = ""
209 bashcolors.RED = ""
210 bashcolors.GREEN = ""
211 bashcolors.WARNING = ""
212 bashcolors.ENDC = ""
f2ba7885 213
ce1cccd6 214 if args[0] == '-1':
215 args.pop(0)
216 Options.FORCE_1K = True
f2ba7885 217
ce1cccd6 218 filename = args[0]
f2ba7885 219 with open(filename, "rb") as f:
220 data = f.read()
221 print_info(data)
222
223if __name__ == "__main__":
ce1cccd6 224 main(sys.argv[1:])
Impressum, Datenschutz