extundelete *nag nag nag*



  • Hallo,

    ich hab seit langem mal wieder das rm Programm falsch benutzt. Ich wollte ein fileN löschen und hab zufälligerweise fileN-1 getippt und zu schnell das Kommando abgefeuert. Nun gibt es extundelete, aber das klappt doch nichtmal. Das einzige was ich getan habe, nachdem das File gelöscht wurde, ist extundelete herunterladen und installieren und folgendes ausführen:

    sudo extundelete /dev/sdXY --restore-directory $PWD
    

    Nichts. Absolut gar nichts, außer Müll. Benutz ich das Programm denn so falsch, oder warum funktioniert extundelete bei mir denn nicht?



  • Faustregel, nachdem man bemerkt, dass man Dateien gelöscht hat: Partition sofort aushängen oder RO mounten. Nein, wirklich. Nein, wirklich, wirklich! Wird doch auch auf deren Seite gesagt:

    Do not save any more data to the partition with the deleted file for any reason! Doing so may overwrite your deleted data and sabotage any recovery effort. Many background processes will periodically write to disk, so work quickly until the partition is unmounted.

    Und dann noch:

    extundelete is able to match the inode number of a file to a file name by searching the deleted entries in a directory, which are often left behind after deleting the file. If the deleted entry does not exist in the directory in the file system, extundelete will look for a match in older copies which are still in the journal.

    Wenn du neue Daten auf die Platte schreibst, überschreibst du nicht nur Daten in der ... nun, "Datensektion", sondern auch in der Dateizuordnungstabelle (Inode-Tabelle). Genau die geht extundelete durch. Sprich, wenn du die vernichtest, dann verringerst du deine Chance, dass etwas gerettet werden kann.

    Aber: wenn du zumindest einen leicht nachvollziehbaren Weg hast, deine Daten zu erkennen, dann hast du vielleicht noch eine Chance. Mir ist mal was ähnliches mit einer NTFS-Platte passiert (Windows nannte es "Dateisystemwiederherstellung", ich nenne es "Pfusch am Bau"), und ich hatte wichtigen Quellcode auf der Platte und ausgerechnet hiervon kein Backup gemacht.

    Ich habe es damals so gelöst, dass ich die komplette Partition nach Strings durchsucht habe, von dem ich sicher war, dass er überall drin war. Wo die Strings gefunden werden konnten, wurde die Position in eine Log-Datei geschrieben. Ein zweites Programm würde die Daten aus der Position auf der Partition in Dateien dumpen, die man dann durch Handarbeit wieder zusammensetzen konnte.

    (Das hat damals so ungefähr hundert mal besser funktioniert als dieser Photorec Sondermüll, der tagelang rumgerödelt und nichts wiedergefunden hat. Das funktioniert aber nur dann, wenn das Muster der Dateien offensichtlich ist, ansonsten wird's sehr schwierig).

    Den Code habe ich noch. Hässlich wie die Nacht, aber er sollte funktionieren. Wenn du daran interessiert bist, kann ich ihn mal posten.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum Linux/Unix in das Forum Themen rund um die IT verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Ja, ich hab gleich zwei Fehler gemacht:

    1. Man soll extundelete nicht auf ner gemounteten Partition ausführen lassen.
    2. Ich habe kurz nach Löschen der Datei was auf die Festplatte geschrieben - extundelete.

    Aber, ist halb so wild, war nur eine kleine Datei, die ich schnell wieder erneut schreiben kann.

    @dachschaden,
    Danke für deine rasche Antwort, der Code würde mich interessieren.



  • Für das "Lasst uns Muster in der Datei suchen"-Programm:

    /*Compile with: gcc dev_searcher.c -o dev_searcher*/
    
    #define _GNU_SOURCE
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <fcntl.h>
    
    #include <unistd.h>
    
    #define DEVICE "/dev/sdaX"
    
    uint8_t*patterns[]=
    {
    	(uint8_t*)"1",
    	(uint8_t*)"2",
    	(uint8_t*)"3",
    	(uint8_t*)"4",
    	(uint8_t*)"5",
    	NULL
    };
    
    #define SIZE_MEMORY (16)
    #define SIZE_SECTOR (4096 * SIZE_MEMORY)
    
    int main(void)
    {
    	int fd = -1,exit_code = EXIT_FAILURE;
    	int offset;
    
    	uint64_t bytes_available;
    	uint64_t pos_file;
    
    	off_t bytes_read;
    
    	size_t iteration;
    	size_t size_buffer;
    
    	uint8_t*patterns_lengths	= NULL;
    	FILE**	patterns_fds		= NULL;
    	uint8_t*buffer			= NULL;
    	uint8_t*hit;
    
    	size_t patterns_amount;
    	size_t patterns_longest;
    	size_t patterns_current;
    
    	if(getuid())
    	{
    		fprintf(stderr,"Must be root to run program!\n");
    		goto LABEL_END;
    	}
    
    	fd = open(DEVICE,O_RDONLY);
    	if(-1 == fd)
    	{
    		fprintf(stderr,"Cannot open device \"%s\"\n",DEVICE);
    		goto LABEL_END;
    	}
    
    	bytes_available = lseek(fd,0,SEEK_END);
    	lseek(fd,0,SEEK_SET);
    
    	for(patterns_amount = 0;patterns[patterns_amount];patterns_amount++)
    
    	patterns_lengths= malloc(patterns_amount * sizeof(*patterns_lengths));
    	patterns_fds	= malloc(patterns_amount * sizeof(*patterns_fds));
    
    	for(patterns_current = 0;patterns_current < patterns_amount;patterns_current++)
    	{
    		patterns_lengths[patterns_current] = strlen(patterns[patterns_current]);
    		if(patterns_lengths[patterns_current] > patterns_lengths[patterns_longest])
    			patterns_longest = patterns_current;
    
    		patterns_fds[patterns_current] = fopen(patterns[patterns_current],"w");
    		if(NULL == patterns_fds[patterns_current])
    		{
    			while(patterns_current)
    			{
    				--patterns_current;
    				fclose(patterns_fds[patterns_current]);
    				patterns_fds[patterns_current] = NULL;
    			}
    			goto LABEL_END;
    		}
    	}
    
    	size_buffer = SIZE_SECTOR + patterns_lengths[patterns_longest];
    	buffer = malloc(size_buffer);
    
    	bytes_read = read(fd,buffer,SIZE_SECTOR);
    	if(bytes_read != SIZE_SECTOR)
    	{
    		fprintf(stderr,"Couldn't read sector 0!\n");
    		goto LABEL_END;
    	}
    
    	for(patterns_current = 0;patterns_current < patterns_amount;patterns_current++)
    	{
    		hit = memmem(buffer,SIZE_SECTOR,patterns[patterns_current],patterns_lengths[patterns_current]);
    		if(hit)
    		{
    			offset = hit - buffer;
    			fprintf
    			(
    				patterns_fds[patterns_current],
    				"Hit [%lu B|%lu KB|%lu MB|%lu GB]|[%lu B|%lu KB|%lu MB|%lu GB]\n\n%s\n\n",
    				(unsigned long)offset,
    				(unsigned long)offset / 1024,
    				(unsigned long)offset / 1024 / 1024,
    				(unsigned long)offset / 1024 / 1024 / 1024,
    				bytes_available,
    				bytes_available / 1024,
    				bytes_available / 1024 / 1024,
    				bytes_available / 1024 / 1024 / 1024,
    				hit
    			);
    		}
    	}
    
    	memcpy(buffer,buffer + SIZE_SECTOR - patterns_lengths[patterns_longest],patterns_lengths[patterns_longest]);
    
    	pos_file = SIZE_SECTOR;
    
    	iteration = 0;
    	while(pos_file < bytes_available)
    	{
    		if(!(iteration % (62500 / SIZE_MEMORY)))
    		{
    			fprintf
    			(
    				stderr,
    				"Checking [%lu B|%lu KB|%lu MB|%lu GB] of [%lu B|%lu KB|%lu MB|%lu GB]\n",
    				pos_file,
    				pos_file / 1024,
    				pos_file / 1024 / 1024,
    				pos_file / 1024 / 1024 / 1024,
    				bytes_available,
    				bytes_available / 1024,
    				bytes_available / 1024 / 1024,
    				bytes_available / 1024 / 1024 / 1024
    			);
    		}
    		bytes_read = read(fd,buffer + patterns_lengths[patterns_longest],SIZE_SECTOR);
    
    		if(bytes_read != SIZE_SECTOR)
    		{
    			fprintf(stderr,"Couldn't read %lu!\n",pos_file);
    			break;
    		}
    
    		for(patterns_current = 0;patterns_current < patterns_amount;patterns_current++)
    		{
    			hit = memmem(buffer,size_buffer,patterns[patterns_current],patterns_lengths[patterns_current]);
    			if(hit)
    			{
    				offset = hit - buffer;
    				fprintf
    				(
    					patterns_fds[patterns_current],
    					"Hit [%lu B|%lu KB|%lu MB|%lu GB]|[%lu B|%lu KB|%lu MB|%lu GB]\n\n%s\n\n",
    					(pos_file + offset),
    					(pos_file + offset) / 1024,
    					(pos_file + offset) / 1024 / 1024,
    					(pos_file + offset) / 1024 / 1024 / 1024,
    					bytes_available,
    					bytes_available / 1024,
    					bytes_available / 1024 / 1024,
    					bytes_available / 1024 / 1024 / 1024,
    					hit
    				);
    			}
    		}
    
    		pos_file += bytes_read;
    		memcpy(buffer,buffer + SIZE_SECTOR,patterns_lengths[patterns_longest]);
    		++iteration;
    	}
    
    	exit_code = EXIT_SUCCESS;
    
    LABEL_END:
    	if(patterns_fds)
    	{
    		for(patterns_current = 0;patterns_current < patterns_amount;patterns_current++)
    		{
    			if(NULL == patterns_fds[patterns_current])
    				continue;
    			fclose(patterns_fds[patterns_current]);
    		}
    		free(patterns_fds);
    	}
    	free(patterns_lengths);
    	free(buffer);
    	close(fd);
    	exit(exit_code);
    }
    

    Und das "Lasst uns irgendwelche rohen Datenreste in eine Datei schreiben"-Programm:

    /*Compile with: gcc dev_reader.c -o dev_reader*/
    
    #define _GNU_SOURCE
    
    #include <stdio.h>
    #include <stdint.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <fcntl.h>
    
    #include <unistd.h>
    
    #include <sys/sendfile.h>
    
    #define FILE_DEVICE	"/dev/sdaX"
    #define FILE_DUMP	"dump"
    
    #define SIZE_MEMORY (16 * 16)
    #define SIZE_SECTOR (4096 * SIZE_MEMORY)
    
    #define POSITION (264449190000)
    
    int main(void)
    {
    	int fd_dev = -1,exit_code = EXIT_FAILURE;
    	int fd_out;
    	int offset;
    
    	if(getuid())
    	{
    		fprintf(stderr,"Must be root to run program!\n");
    		goto LABEL_END;
    	}
    
    	fd_dev = open(FILE_DEVICE,O_RDONLY);
    	fd_out = open(FILE_DUMP,O_WRONLY|O_CREAT|O_TRUNC,0644);
    	if(-1 == fd_dev)
    	{
    		fprintf(stderr,"Cannot open device \"%s\"\n",FILE_DEVICE);
    		goto LABEL_END;
    	}
    	if(-1 == fd_out)
    	{
    		perror(NULL);
    		fprintf(stderr,"Cannot open dump file \"%s\"\n",FILE_DUMP);
    		goto LABEL_END;
    	}
    
    	lseek(fd_dev,POSITION,SEEK_SET);
    	sendfile(fd_out,fd_dev,NULL,SIZE_SECTOR);
    
    	exit_code = EXIT_SUCCESS;
    	chown(FILE_DUMP,1000,1000);
    
    LABEL_END:
    	close(fd_dev);
    	close(fd_out);
    
    	exit(exit_code);
    }
    

    Ja, ich weiß, der Code ist scheiße, aber ich habe ihn in einer Nacht-und-Nebel-Aktion geschrieben, und er hat funktioniert.



  • Ich habe sowas mal mit grep -B 500 -A 500 /Dev/sdxn gemacht und
    den Müll vor- und nachher per Editor entsorgt. Da war allerdings auch ein eindeutiger Textstring im Quelltext. Hat problemlos funktioniert.


Anmelden zum Antworten