]> git.zerfleddert.de Git - proxmark3-svn/blob - client/pm3_mfdread.py
FIX: @marshmellow42 's ST detection fix.
[proxmark3-svn] / client / pm3_mfdread.py
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
10 import codecs
11 import sys
12 import copy
13 from struct import unpack
14 from datetime import datetime
15 from bitstring import BitArray
16
17 class Options:
18 FORCE_1K = False
19
20 if len(sys.argv) == 1:
21 print('''
22 ------------------
23 Usage: mfdread.py ./dump.mfd
24 Mifare dumps reader.
25 ''')
26 sys.exit();
27
28 def d(bytes):
29 decoded = codecs.decode(bytes, "hex")
30 try:
31 return str(decoded, "utf-8").rstrip('\0')
32 except:
33 return ""
34
35
36 class bashcolors:
37 BLUE = '\033[34m'
38 RED = '\033[91m'
39 GREEN = '\033[32m'
40 WARNING = '\033[93m'
41 ENDC = '\033[0m'
42
43
44 def 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
78 def 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
94 def 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 ""
109
110
111 def 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
126 def 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
140 if Options.FORCE_1K:
141 cardsize = 16
142
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
153 blocksmatrix_clear = copy.deepcopy(blocksmatrix)
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))
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 ║")
175 for q in range(0, len(blocksmatrix)):
176 print("╠═════════╬═════╬══════════════════════════════════╬════════╬═════════════════════════════════════╣")
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
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
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):
199 print("║ %d%s %d %s %s %-35s ║ %s" %(q,padding,z,blocksmatrix[q][z], accbits, permissions, d(blocksmatrix_clear[q][z])))
200 else:
201 print("║ ║ %d %s %s %-35s ║ %s" %(z,blocksmatrix[q][z], accbits, permissions, d(blocksmatrix_clear[q][z])))
202 print("╚═════════╩═════╩══════════════════════════════════╩════════╩═════════════════════════════════════╝")
203
204
205 def 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 = ""
213
214 if args[0] == '-1':
215 args.pop(0)
216 Options.FORCE_1K = True
217
218 filename = args[0]
219 with open(filename, "rb") as f:
220 data = f.read()
221 print_info(data)
222
223 if __name__ == "__main__":
224 main(sys.argv[1:])
Impressum, Datenschutz