magicrescue-1.1.10+dfsg/0000775000000000000000000000000013376322260013504 5ustar rootrootmagicrescue-1.1.10+dfsg/README.md0000664000000000000000000000325213376322260014765 0ustar rootrootMagic Rescue ============ Deprecation notice ------------------ This software is no longer under active development. I will consider merging pull requests, but I will not myself address any issues raised in GitHub. I cannot guarantee that I will make new stable releases. Security notice --------------- Magic Rescue should only be run in a sandboxed environment. It was written in 2004, a time where the internet was a friendlier place. Magic Rescue works by invoking programs written in unsafe languages with input from arbitrary data found on your disk. This exposes a large attack surface to any attacker that is able to place arbitrary data inside files on your disk, including your browser cache. Overview -------- Magic Rescue scans a block device for file types it knows how to recover and calls an external program to extract them. It looks at "magic bytes" in file contents, so it can be used both as an undelete utility and for recovering a corrupted drive or partition. As long as the file data is there, it will find it. It works on any file system, but on very fragmented file systems it can only recover the first chunk of each file. Practical experience (this program was not written for fun) shows, however, that chunks of 30-50MB are not uncommon. Find the latest version at https://github.com/jbj/magicrescue Building -------- There are no build requirements other than a C library and a UNIXish system. To use the dupemap(1) utility, you must have the NDBM compatibility header, which either comes with your system or the development libraries of GDBM or Berkeley DB. ./configure && make && make install The "make install" step is optional. Using ----- man magicrescue magicrescue-1.1.10+dfsg/release.sh0000775000000000000000000000121713376322260015464 0ustar rootroot#!/bin/bash set -e VERSION="$1" if [ "" = "$VERSION" ] || [ "x${VERSION#[0-9]}" = "x$VERSION" ]; then cat << EOF Usage: $0 VERSION Remember to update NEWS first. This script is only meant to be run by the maintainer. EOF exit 1 fi if ! head -n1 NEWS | grep -q '^-'; then echo "$0: no entries at the top of NEWS" exit 1 fi ./configure make docs-clean make docs RELEASE="$VERSION" || exit 1 mv NEWS old_NEWS echo -n "Version $VERSION: " > NEWS date >> NEWS cat old_NEWS >> NEWS rm -f old_NEWS git add NEWS doc cat << EOF All done, now run: git commit -m "Release $VERSION" git tag v$VERSION git push origin v$VERSION EOF magicrescue-1.1.10+dfsg/tools/0000775000000000000000000000000013376322260014644 5ustar rootrootmagicrescue-1.1.10+dfsg/tools/safecat.c0000664000000000000000000000610613376322260016421 0ustar rootroot/* * Magic Rescue * Copyright (C) 2004 Jonas Jensen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include #include #include #include #include #include #include "util.h" static void usage(void) { fprintf(stderr, "Usage: safecat [-dut] FILENAME | COMMAND\n" "Copies verbatim from standard input to standard output. Standard output is\n" "expected to be piped into COMMAND to produce FILENAME. This file will be\n" "checked for size, and if that size falls below certain limits the program\n" "will exit.\n" "\n" " -d Maximum difference between bytes in and out of the command\n" " -t Maximum bytes the command is allowed to produce\n" " -u Maximum bytes to pipe into a command that has stopped producing output\n" "\n" " The values for the -dut options can be postfixed with G, M or K.\n" ); } int main(int argc, char **argv) { long max_diff = 5*1024*1024; long max_unchanged = 1*1024*1024; long max_total = 50*1024*1024; char *ofile; const size_t bufsize = 102400; char *buf; int c; while ((c = getopt(argc, argv, "d:u:t:")) >= 0) { switch (c) { case 'd': max_diff = atol_calc(optarg); break; case 'u': max_unchanged = atol_calc(optarg); break; case 't': max_total = atol_calc(optarg); break; default: fprintf(stderr, "Error parsing options.\n"); usage(); return 1; } } if (argc - optind != 1 || strcmp(argv[optind], "--help") == 0) { usage(); return 1; } ofile = argv[optind]; buf = malloc(bufsize); { off_t total_in = 0, total_out = 0, in_at_last_out = 0; struct stat st; ssize_t read_count, write_count; const char *buf_offset; do { read_count = read(0, buf, bufsize); if (read_count <= 0) break; buf_offset = buf; do { write_count = write(1, buf_offset, read_count); if (write_count <= 0) goto end_loop; read_count -= write_count; buf_offset += write_count; total_in += write_count; } while (read_count > 0); if (stat(ofile, &st) == 0) { if (total_out != st.st_size) { total_out = st.st_size; in_at_last_out = total_in; } } else { total_out = 0; } } while ( max_total > total_out && max_diff > total_in - total_out && max_unchanged > total_in - in_at_last_out); } end_loop: free(buf); return 0; } magicrescue-1.1.10+dfsg/tools/pngextract.pl0000775000000000000000000000147213376322260017367 0ustar rootroot#!/usr/bin/perl use strict; my $max_file_len = 10_000_000; my ($buf, $len, $type); read(STDIN, $buf, 8) == 8 or die "header read error: $!\n"; $buf eq "\211PNG\r\n\032\n" or die "bad magic\n"; print $buf; my $written = 8; while (read(STDIN, $buf, 4) == 4) { $len = unpack("N", $buf) + 8; if ($len > $max_file_len) { die "Invalid chunk length $len\n"; } print $buf; if (read(STDIN, $buf, $len) != $len) { die "read error: $!\n"; } $written += $len + 4; if ($written > $max_file_len) { print STDERR "File too long, aborting\n"; exit 1; } $type = unpack("a4", $buf); if ($type !~ /^[a-zA-Z]{4}$/) { print STDERR "Invalid type code, aborting\n"; exit 1; } print $buf; if ($type eq 'IEND') { print STDERR "Successfully extracted png file\n"; exit 0; } } magicrescue-1.1.10+dfsg/tools/gzip_rename.pl0000775000000000000000000000142413376322260017505 0ustar rootroot#!/usr/bin/perl use strict; use constant FCONT => 1<<1; use constant FEXTRA => 1<<2; use constant FNAME => 1<<3; my $file = $ARGV[0]; unless (@ARGV and -f $file) { die "Usage: gzip_rename.pl FILENAME < orig-data\n"; } my $buf; read STDIN, $buf, 10 or exit; my $flags = (unpack "C4", $buf)[3]; exit unless defined $flags; exit unless $flags & FNAME; if ($flags & FCONT) { read STDIN, $buf, 2 or exit; } if ($flags & FEXTRA) { read STDIN, $buf, 2 or exit; my $len = unpack("v", $buf); # unsigned little-endian 16-bit exit if $len > 10240; read STDIN, $buf, $len or exit; } read STDIN, $buf, 130 or exit; my $origname = unpack("Z130", $buf); if ($origname and length($origname) < 128 and $origname !~ m[[/\x00-\x1F]]) { print "RENAME $origname\n"; } magicrescue-1.1.10+dfsg/tools/oleextract.pl0000775000000000000000000000344413376322260017363 0ustar rootroot#!/usr/bin/perl use strict; # # This script loosely follows the LAOLA file system described at # http://user.cs.tu-berlin.de/~schwartz/pmh/guide.html. It only looks at the # "big block depots", as they seem to be sufficient for finding the length of # the file. use Fcntl qw(:seek); my $buf; # We use sysread/sysseek here to work around problems on cygwin sysread STDIN, $buf, 512; if (substr($buf, 0, 8) ne "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1") { die "Not an MS OLE file\n"; } my $num_of_bbd_blocks = unpack("V", substr($buf, 0x2c)); if ($num_of_bbd_blocks == 0 or $num_of_bbd_blocks > 320) { # Max 320 bbd means the file can only be 128*512*320 = 20MB die "Corrupted file, too many big block depots\n"; } my $max_block = 128*$num_of_bbd_blocks; my @bbds = unpack("V$num_of_bbd_blocks", substr($buf, 0x4c)); my $block_count = 0; my $prevblock = -1; my $block_index = 0; foreach my $block (@bbds) { if ($block > $max_block or $block == $prevblock) { die "Corrupted file, bbd block number out of bounds\n"; } sysseek STDIN, 512*($block - $prevblock - 1), SEEK_CUR or die "sysseek failed: $!\n"; 512 == sysread STDIN, $buf, 512 or die "read failed: $!\n"; my @blockmap = unpack("V128", $buf); for (my $i = 0; $i < 128; $i++) { if ($blockmap[$i] != 0xFFffFFff) { $block_count = $block_index * 128 + $i + 2; } if ($blockmap[$i] < 0xFFffFFfd and $blockmap[$i] > $max_block) { die "Corrupted file, block number too high\n"; } } $prevblock = $block; $block_index++; } if ($block_count > 0) { sysseek STDIN, -512*($bbds[@bbds - 1] + 2), SEEK_CUR # seek to first block or die "seek failed: $!\n"; for (1 .. $block_count) { 512 == sysread STDIN, $buf, 512 or die "read failed: $!\n"; print $buf or die "write failed: $!\n"; } } magicrescue-1.1.10+dfsg/tools/gimp-resave.pl0000775000000000000000000000233213376322260017423 0ustar rootroot#!/usr/bin/perl use strict; use Cwd; use Fcntl qw(:seek); use Gimp qw(:auto); Gimp::init; my $exitval = 1; unless (@ARGV) { print "Usage: $0 FILENAME Before using this you must run the Gimp perl server: \$ gimp --batch '(extension-perl-server 0 0 0)'\n"; exit 1; } my $file = $ARGV[0]; # The Gimp server might be in a different working directory than this script if ($file !~ m[^/]) { $file = getcwd() ."/$file"; } # Open the file and see if it's completely corrupted open FH, $file or die "Opening $file: $!\n"; seek FH, 14, SEEK_CUR or die "seek: $!\n"; my $buf; 12 == read FH, $buf, 12 or die "read: $!\n"; close FH; my ($x, $y, $mode) = unpack("N3", $buf); if ($x > 10_000 or $y > 10_000 or $mode > 10) { print STDERR "$0: bad image: $x x $y, mode $mode\n"; exit 1; } # Prevent message boxes popping up all over the place gimp_message_set_handler(1); my $img = gimp_xcf_load(0, $file, $file); eval { my $layer = gimp_image_get_active_layer($img); gimp_xcf_save(0, $layer, $file, $file); $exitval = 0; print STDERR "Successfully resaved image\n"; }; if ($@) { print STDERR "$@"; } # This must always be called, or Gimp will leak memory gimp_image_delete($img); Gimp::end; exit $exitval; magicrescue-1.1.10+dfsg/tools/inputseek.c0000664000000000000000000000134013376322260017015 0ustar rootroot#include "config.h" #include #include #include #include #include #include "util.h" int main(int argc, char **argv) { if (argc < 3) { fprintf(stderr, "Usage: inputseek [+-=][0x]OFFSET COMMAND [ARG1 [ARG2 ...]]\n" "\n" " Where OFFSET is the byte position to seek standard input to. I can be\n" " written in hex or decimal, and may include a prefix:\n" " = Seek to an absolute position (default)\n" " + Seek forward to a relative position\n" " - Seek to EOF, minus the offset\n" ); return 1; } if (rich_seek(0, argv[1]) == (off_t)-1) { perror("lseek on stdin"); return 1; } execvp(argv[2], &argv[2]); perror("exec"); return 1; } magicrescue-1.1.10+dfsg/tools/script_rename.pl0000775000000000000000000000043013376322260020034 0ustar rootroot#!/usr/bin/perl use strict; my $file = shift or die "Usage: script_rename.pl FILE\n"; open SCRIPT, "<", $file or die "Opening $file: $!\n"; my $line1 =