]>
cvs.zerfleddert.de Git - proxmark3-svn/blob - client/pm3_mfdread.py
2 # -*- coding: utf-8 -*-
4 # mfdread.py - Mifare dumps parser in human readable format
5 # Pavel Zhovner <pavel@zhovner.com>
6 # https://github.com/zhovner/mfdread
13 from struct
import unpack
14 from datetime
import datetime
15 from bitstring
import BitArray
20 if len(sys
.argv
) == 1:
23 Usage: mfdread.py ./dump.mfd
29 decoded
= codecs
.decode(bytes
, "hex")
31 return str(decoded
, "utf-8").rstrip('\0')
44 def accbits_for_blocknum(accbits_str
, blocknum
):
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.
51 inverted
= BitArray([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]])
59 bits
= BitArray([accbits_str
[10], accbits_str
[22], accbits_str
[18]])
60 inverted
= BitArray([accbits_str
[6], accbits_str
[2], accbits_str
[14]])
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
67 bits
= BitArray([accbits_str
[8], accbits_str
[20], accbits_str
[16]])
68 inverted
= BitArray([accbits_str
[4], accbits_str
[0], accbits_str
[12]])
70 # Check the decoded bits
72 if bits
.bin
== inverted
.bin
:
78 def accbits_to_permission_sector(accbits
):
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 - | - -",
89 if isinstance(accbits
, BitArray
):
90 return permissions
.get(accbits
.bin
, "unknown")
94 def accbits_to_permission_data(accbits
):
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]",
105 if isinstance(accbits
, BitArray
):
106 return permissions
.get(accbits
.bin
, "unknown")
111 def accbit_info(accbits
):
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.
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
)
126 def print_info(data
):
131 # determine what dump we get 1k or 4k
132 if len(data
) == 4096:
134 elif len(data
) == 1024:
137 print("Wrong file size: %d bytes.\nOnly 1024 or 4096 allowed." % len(data
))
144 for i
in range(0, cardsize
):
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)])
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
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("╠═════════╬═════╬══════════════════════════════════╬════════╬═════════════════════════════════════╣")
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
182 if isinstance(blockrights
[q
][z
], BitArray
):
183 accbits
= bashcolors
.GREEN
+ blockrights
[q
][z
].bin
+ bashcolors
.ENDC
185 accbits
= bashcolors
.WARNING
+ "ERR" + bashcolors
.ENDC
187 if (q
== 0 and z
== 0):
190 permissions
= accbits_to_permission_sector(blockrights
[q
][z
])
192 permissions
= accbits_to_permission_data(blockrights
[q
][z
])
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
199 print("║ %d%s║ %d ║ %s ║ %s ║ %-35s ║ %s" %(q
,padding
,z
,blocksmatrix
[q
][z
], accbits
, permissions
, d(blocksmatrix_clear
[q
][z
])))
201 print("║ ║ %d ║ %s ║ %s ║ %-35s ║ %s" %(z
,blocksmatrix
[q
][z
], accbits
, permissions
, d(blocksmatrix_clear
[q
][z
])))
202 print("╚═════════╩═════╩══════════════════════════════════╩════════╩═════════════════════════════════════╝")
210 bashcolors
.GREEN
= ""
211 bashcolors
.WARNING
= ""
216 Options
.FORCE_1K
= True
219 with
open(filename
, "rb") as f
:
223 if __name__
== "__main__":