Skip to content

Commit

Permalink
ADD: some dump converters from the proxmark3 repo.
Browse files Browse the repository at this point in the history
  • Loading branch information
iceman1001 committed Dec 2, 2017
1 parent 3df8b07 commit db0e443
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 0 deletions.
27 changes: 27 additions & 0 deletions Software/Tools/pm3_eml2mfd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/python

'''
# Andrei Costin <zveriu@gmail.com>, 2011
# pm3_eml2mfd.py
# Converts PM3 Mifare Classic emulator EML text file to MFD binary dump file
'''

from __future__ import with_statement
import sys
import binascii

def main(argv):
argc = len(argv)
if argc < 3:
print 'Usage:', argv[0], 'input.eml output.mfd'
sys.exit(1)

with file(argv[1], "r") as file_inp, file(argv[2], "wb") as file_out:
for line in file_inp:
line = line.rstrip('\n').rstrip('\r')
print line
data = binascii.unhexlify(line)
file_out.write(data)

if __name__ == '__main__':
main(sys.argv)
53 changes: 53 additions & 0 deletions Software/Tools/pm3_eml_mfd_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/python

from __future__ import with_statement
from tempfile import mkdtemp
from shutil import rmtree
from itertools import imap
from string import hexdigits
import unittest, os
import pm3_eml2mfd, pm3_mfd2eml

class TestEmlMfd(unittest.TestCase):
def setUp(self):
self.tmpdir = mkdtemp()

def tearDown(self):
rmtree(self.tmpdir)

EML2MFD_TESTCASES = [
('', ''),
("41424344\r\n45464748\n494A4B4C\n", "ABCDEFGHIJKL")
]
def test_eml2mfd(self):
self.three_argument_test(pm3_eml2mfd.main, self.EML2MFD_TESTCASES)

def test_mfd2eml(self):
self.three_argument_test(pm3_mfd2eml.main,
imap(reversed, self.EML2MFD_TESTCASES), c14n=hex_c14n)

def three_argument_test(self, operation, cases, c14n=str):
for case_input, case_output in cases:
try:
inp_name = os.path.join(self.tmpdir, 'input')
out_name = os.path.join(self.tmpdir, 'output')
with file(inp_name, 'wb') as in_file:
in_file.write(case_input)
operation(['', inp_name, out_name])
with file(out_name, 'rb') as out_file:
self.assertEquals(c14n(case_output), c14n(out_file.read()))
finally:
for file_name in inp_name, out_name:
if os.path.exists(file_name):
os.remove(file_name)


def hex_c14n(inp):
"""
Canonicalizes the input string by removing non-hexadecimal
characters and making everything uppercase
"""
return ''.join(c.upper() for c in inp if c in hexdigits)

if __name__ == '__main__':
unittest.main()
31 changes: 31 additions & 0 deletions Software/Tools/pm3_mfd2eml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/python

'''
# Andrei Costin <zveriu@gmail.com>, 2011
# pm3_eml2mfd.py
# Converts PM3 Mifare Classic MFD binary dump file to emulator EML text file
'''

from __future__ import with_statement
import sys
import binascii

READ_BLOCKSIZE = 16

def main(argv):
argc = len(argv)
if argc < 3:
print 'Usage:', argv[0], 'input.mfd output.eml'
sys.exit(1)

with file(argv[1], "rb") as file_inp, file(argv[2], "w") as file_out:
while True:
byte_s = file_inp.read(READ_BLOCKSIZE)
if not byte_s:
break
hex_char_repr = binascii.hexlify(byte_s)
file_out.write(hex_char_repr)
file_out.write("\n")

if __name__ == '__main__':
main(sys.argv)
263 changes: 263 additions & 0 deletions Software/Tools/pm3_mfdread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# mfdread.py - Mifare dumps parser in human readable format
# Pavel Zhovner <pavel@zhovner.com>
# https://github.com/zhovner/mfdread
#
#Dependencies:
# easy_install bitstring
#or
# pip install bitstring
#Usage:
# mfdread.py ./dump.mfd
#

import codecs
import copy
import sys
from collections import defaultdict

from bitstring import BitArray


class Options:
FORCE_1K = False


if len(sys.argv) == 1:
sys.exit('''
------------------
Usage: mfdread.py ./dump.mfd
Mifare dumps reader.
''')


def decode(bytes):
decoded = codecs.decode(bytes, "hex")
try:
return str(decoded, "utf-8").rstrip(b'\0')
except:
return ""


class bashcolors:
BLUE = '\033[34m'
RED = '\033[91m'
GREEN = '\033[32m'
WARNING = '\033[93m'
ENDC = '\033[0m'


def accbits_for_blocknum(accbits_str, blocknum):
'''
Decodes the access bit string for block "blocknum".
Returns the three access bits for the block or False if the
inverted bits do not match the access bits.
'''
bits = BitArray([0])
inverted = BitArray([0])

# Block 0 access bits
if blocknum == 0:
bits = BitArray([accbits_str[11], accbits_str[23], accbits_str[19]])
inverted = BitArray([accbits_str[7], accbits_str[3], accbits_str[15]])

# Block 0 access bits
elif blocknum == 1:
bits = BitArray([accbits_str[10], accbits_str[22], accbits_str[18]])
inverted = BitArray([accbits_str[6], accbits_str[2], accbits_str[14]])
# Block 0 access bits
elif blocknum == 2:
bits = BitArray([accbits_str[9], accbits_str[21], accbits_str[17]])
inverted = BitArray([accbits_str[5], accbits_str[1], accbits_str[13]])
# Sector trailer / Block 3 access bits
elif blocknum in (3, 15):
bits = BitArray([accbits_str[8], accbits_str[20], accbits_str[16]])
inverted = BitArray([accbits_str[4], accbits_str[0], accbits_str[12]])

# Check the decoded bits
inverted.invert()
if bits.bin == inverted.bin:
return bits
else:
return False


def accbits_to_permission_sector(accbits):
permissions = {
'000': "- A | A - | A A [read B]",
'010': "- - | A - | A - [read B]",
'100': "- B | A/B - | - B",
'110': "- - | A/B - | - -",
'001': "- A | A A | A A [transport]",
'011': "- B | A/B B | - B",
'101': "- - | A/B B | - -",
'111': "- - | A/B - | - -",
}
if isinstance(accbits, BitArray):
return permissions.get(accbits.bin, "unknown")
else:
return ""


def accbits_to_permission_data(accbits):
permissions = {
'000': "A/B | A/B | A/B | A/B [transport]",
'010': "A/B | - | - | - [r/w]",
'100': "A/B | B | - | - [r/w]",
'110': "A/B | B | B | A/B [value]",
'001': "A/B | - | - | A/B [value]",
'011': " B | B | - | - [r/w]",
'101': " B | - | - | - [r/w]",
'111': " - | - | - | - [r/w]",
}
if isinstance(accbits, BitArray):
return permissions.get(accbits.bin, "unknown")
else:
return ""


def accbit_info(accbits, sector_size):
'''
Returns a dictionary of a access bits for all three blocks in a sector.
If the access bits for block could not be decoded properly, the value is set to False.
'''
access_bits = defaultdict(lambda: False)

if sector_size == 15:
access_bits[sector_size] = accbits_for_blocknum(accbits, sector_size)
return access_bits

# Decode access bits for all 4 blocks of the sector
for i in range(0, 4):
access_bits[i] = accbits_for_blocknum(accbits, i)
return access_bits


def print_info(data):
blocksmatrix = []
blockrights = {}
block_number = 0

data_size = len(data)

if data_size not in {4096, 1024}:
sys.exit("Wrong file size: %d bytes.\nOnly 1024 or 4096 allowed." % len(data))

if Options.FORCE_1K:
data_size = 1024

# read all sectors
sector_number = 0
start = 0
end = 64
while True:
sector = data[start:end]
sector = codecs.encode(sector, 'hex')
if not isinstance(sector, str):
sector = str(sector, 'ascii')
sectors = [sector[x:x + 32] for x in range(0, len(sector), 32)]

blocksmatrix.append(sectors)

# after 32 sectors each sector has 16 blocks instead of 4
sector_number += 1
if sector_number < 32:
start += 64
end += 64
elif sector_number == 32:
start += 64
end += 256
else:
start += 256
end += 256

if start == data_size:
break

blocksmatrix_clear = copy.deepcopy(blocksmatrix)

# add colors for each keyA, access bits, KeyB
for c in range(0, len(blocksmatrix)):
sector_size = len(blocksmatrix[c]) - 1

# Fill in the access bits
blockrights[c] = accbit_info(BitArray('0x' + blocksmatrix[c][sector_size][12:20]), sector_size)

# Prepare colored output of the sector trailor
keyA = bashcolors.RED + blocksmatrix[c][sector_size][0:12] + bashcolors.ENDC
accbits = bashcolors.GREEN + blocksmatrix[c][sector_size][12:20] + bashcolors.ENDC
keyB = bashcolors.BLUE + blocksmatrix[c][sector_size][20:32] + bashcolors.ENDC

blocksmatrix[c][sector_size] = keyA + accbits + keyB

print("File size: %d bytes. Expected %d sectors" % (len(data), sector_number))
print("\n\tUID: " + blocksmatrix[0][0][0:8])
print("\tBCC: " + blocksmatrix[0][0][8:10])
print("\tSAK: " + blocksmatrix[0][0][10:12])
print("\tATQA: " + blocksmatrix[0][0][12:14])
print(" %sKey A%s %sAccess Bits%s %sKey B%s" % (
bashcolors.RED, bashcolors.ENDC, bashcolors.GREEN, bashcolors.ENDC, bashcolors.BLUE, bashcolors.ENDC))
print("╔═════════╦═══════╦══════════════════════════════════╦════════╦═════════════════════════════════════╗")
print("║ Sector ║ Block ║ Data ║ Access ║ A | Acc. | B ║")
print("║ ║ ║ ║ ║ r w | r w | r w [info] ║")
print("║ ║ ║ ║ ║ r | w | i | d/t/r ║")

for q in range(0, len(blocksmatrix)):
print("╠═════════╬═══════╬══════════════════════════════════╬════════╬═════════════════════════════════════╣")
n_blocks = len(blocksmatrix[q])

# z is the block in each sector
for z in range(0, len(blocksmatrix[q])):

# Format the access bits. Print ERR in case of an error
if isinstance(blockrights[q][z], BitArray):
accbits = bashcolors.GREEN + blockrights[q][z].bin + bashcolors.ENDC
else:
accbits = bashcolors.WARNING + "ERR" + bashcolors.ENDC

if q == 0 and z == 0:
permissions = "-"

elif z == n_blocks:
permissions = accbits_to_permission_sector(blockrights[q][z])
else:
permissions = accbits_to_permission_data(blockrights[q][z])

# Print the sector number in the second third row
if z == 2:
qn = q
else:
qn = ""

print("║ %-5s║ %-3d ║ %s ║ %s ║ %-35s ║ %s" % (qn, block_number, blocksmatrix[q][z],
accbits, permissions,
decode(blocksmatrix_clear[q][z])))

block_number += 1

print("╚═════════╩═══════╩══════════════════════════════════╩════════╩═════════════════════════════════════╝")


def main(args):
if args[0] == '-n':
args.pop(0)
bashcolors.BLUE = ""
bashcolors.RED = ""
bashcolors.GREEN = ""
bashcolors.WARNING = ""
bashcolors.ENDC = ""

if args[0] == '-1':
args.pop(0)
Options.FORCE_1K = True

filename = args[0]
with open(filename, "rb") as f:
data = f.read()
print_info(data)


if __name__ == "__main__":
main(sys.argv[1:])

0 comments on commit db0e443

Please sign in to comment.