easily dump unique mifare cards, remembering keys
authorDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 31 Jan 2011 21:49:41 +0000 (22:49 +0100)
committerDobrica Pavlinusic <dpavlin@rot13.org>
Mon, 31 Jan 2011 21:49:41 +0000 (22:49 +0100)
nfc-card-dumper.pl [new file with mode: 0755]

diff --git a/nfc-card-dumper.pl b/nfc-card-dumper.pl
new file mode 100755 (executable)
index 0000000..5403ada
--- /dev/null
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use RFID::Libnfc::Reader;
+use RFID::Libnfc::Constants;
+use File::Slurp;
+use Digest::MD5 qw(md5_hex);
+
+use Data::Dump qw(dump);
+
+my $keyfile = shift @ARGV;
+
+my $r = RFID::Libnfc::Reader->new(debug => 1);
+if ($r->init()) {
+    printf ("Reader: %s\n", $r->name);
+    my $tag = $r->connect(IM_ISO14443A_106);
+
+    if ($tag) {
+        $tag->dump_info;
+    } else {
+        warn "No TAG";
+        exit -1;
+    }
+
+       my $uid = sprintf "%02x%02x%02x%02x", unpack('C4', $tag->{_nai}->abtUid);
+       # @{ $tag->uid }; # FIXME this doesn't work with tags which have 00 in UID!
+
+       warn "UID: $uid\n";
+
+       $keyfile ||= "cards/$uid.key";
+
+       if ( -e $keyfile ) {
+               warn "# loading keys from $keyfile";
+           $tag->load_keys($keyfile);
+               warn "## _keys = ", dump($tag->{_keys});
+       }
+
+    $tag->select if ($tag->can("select")); 
+
+       my $card;
+
+       print STDERR "reading";
+    for (my $i = 0; $i < $tag->blocks; $i++) {
+        if (my $data = $tag->read_block($i)) {
+            # if we are dumping an ultralight token, 
+            # we receive 16 bytes (while a block is 4bytes long)
+            # so we can skip next 3 blocks
+            $i += 3 if ($tag->type eq "ULTRA");
+                       $card .= $data;
+                       print STDERR "$i ";
+        } else {
+            die $tag->error."\n";
+        }
+    }
+       print STDERR "done\n";
+
+       # re-insert keys into dump
+       my $keys = $tag->{_keys} || die "can't find _keys";
+       foreach my $i ( 0 .. $#$keys ) {
+               my $o = $i * 0x40 + 0x30;
+               last if $o > length($card);
+               $card
+                       = substr($card, 0,   $o) . $keys->[$i]->[0]
+                       . substr($card, $o+6, 4) . $keys->[$i]->[1]
+                       . substr($card, $o+16)
+                       ;
+               warn "sector $i keys re-inserted at $o\n";
+       }
+
+       my $md5 = md5_hex($card);
+       if ( glob "cards/$uid.md5.*" ) {
+               warn "SKIPPING, same dump allready exits\n";
+       } else {
+
+               my $out_file = "cards/$uid.$md5";
+               write_file $out_file, $card;
+               print "$out_file ", -s $out_file, " bytes\n";
+               if ( ! -e "cards/$uid.key" ) {
+                       symlink $out_file, "cards/$uid.key" || die "cards/$uid.key: $!";
+                       warn "using keys as default for card $uid\n";
+               }
+               system "./mifare-mad.pl $out_file | vi -R -";
+       }
+
+}
+