Skocz do zawartości

JPG Undeleter - Program do odzyskiwania jpegów


Compi

Rekomendowane odpowiedzi

JPG Undeleter

Autor: Daniel Mazur
Waga: 2mb
Opis: Ostatnio z nudów postanowiłem podszkolić się w trochę niskopoziomowych sprawach związanych z komputerami itp. Rozmyślając, co tu można by było napisać wpadłem właśnie na taki pomysł.
Programik ten jest w stanie odczytać usunięte jpgi z dysku, pendrive, karty pamięci (i chyba pamięci telefonu ale nie wiem :$).
Obsługuje wszystkie wszystkie sygnatury jpegów, od standardowych po Canona.
Po znalezieniu magicznego numeru program odczytuje kolejne 3,90MB dla pewnego odzyskania. Nie szuka stopki pliku.
Małe info: Ten szalony program ma zaledwie 220 linijek kodu
Nie grozi wam żadna utrata danych, gdyż ten program tylko czyta dysk, nic nie zapisując.
Dlatego dla pewności proszę dać Save to... i wskazać gdzie ma zapisywać, koniecznie na innym dysku niż skanowany.

Sposób użycia:
Odpalamy program
Klikamy Save to... i wybieramy miejsce poza skanowanym dyskiem
Klikamy na dysk, który chcemy zeskanować
Czekamy na efekty




Dlaczego daje to w demach? Bo planuje rozszerzyć możliwości do większości znanych formatów plików + konfiguracji własnych

Screeny:
Untitled.png
Untitled1.png

Download:
https://gmclan.org/up3899_4_undeletah.html


Jeśli znajdziesz buga, niezwłocznie mnie poinformuj.
Odnośnik do komentarza
Udostępnij na innych stronach

Ok ;)

 

Na początek trochę teorii. Dużo plików ma nagłówki lub jakieś magiczne liczby w stylu 0xFEEDFACE itp, które charakteryzują format i pochodzenie.

Dla przykład pliki JPG zaczynają się od 0xFFD8FFE* (gdzie * oznacza losowy znak, zależnie od producenta aparatu, 0 dla programów typu paint).

Znając nagłowki/liczby można odkopać plik z gąszczu bajtów.

 

Aby odnaleźć plik bo usunięciu lub logicznym uszkodzeniu pliku musimy dostać się do dysku tak jak do pliku. Tak jakbyśmy chcieli odczytać naraz całą zawartość. Jeśli ktoś korzystał z rodziny uniksów, to kojarzy że tam urządzenie są reprezentowane przez pliki w folderze dev (dysk to np. /dev/sda).

 

W Windowsie jest ukryta kernelowa ścieżka która przechowuje urządzenia. Tych ścieżek jest kilka ale wszystkie mają podobne dowiązania.

To tych ścieżek należy między innymi:

\Device\Harddisk*\

\\?\PhysicalDrive*

W starych windowsach \\.\C

 

Gdy otworzymy taki dysk pozostaje tylko odczytywać po fragmencie do bufora i szukać w nim sygnatur.

 

 

UWAGA!

Jako że mam bardzo brzydki styl pisania i pełno nieużywanych zmiennych i zbędnych komentarzy, laik może mieć trudności.

Przepraszam, że przedstawiam taki syfiasty kod, mea culpa

 

GML
unit main;

 

{$mode objfpc}{$H+}

 

interface

 

uses

Classes, SysUtils, FileUtil, BCPanel, BCLabel, BGRAImageList,

BGRAFlashProgressBar, BGRAKnob, BCButton, Forms, Controls, Graphics, Dialogs,

ComCtrls, StdCtrls, ExtCtrls, Windows;

type

 

{ TForm1 }

 

TForm1 = class(TForm)

BCButton1: TBCButton;

BCButton2: TBCButton;

BCLabel1: TBCLabel;

BCLabel2: TBCLabel;

BCLabel3: TBCLabel;

BCLabel4: TBCLabel;

BCPanel1: TBCPanel;

knob: TBGRAKnob;

Label8: TLabel;

pr1: TBGRAFlashProgressBar;

BGRAImageList1: TBGRAImageList;

Edit1: TEdit;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Label4: TLabel;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

ListView: TListView;

Memo1: TMemo;

sdd1: TSelectDirectoryDialog;

procedure BCButton1Click(Sender: TObject);

procedure BCButton2Click(Sender: TObject);

procedure Button1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

procedure ListViewClick(Sender: TObject);

private

{ private declarations }

public

{ public declarations }

end;

Type TCharArray = Array[0..MAX_PATH] of TCHAR;

var

Form1: TForm1;

mountPoint : LPCTSTR;

implementation

{$R *.lfm}

{ TForm1 }

function GetVolumeNameForVolumeMountPointA(lpszVolumeMountPoint: LPCTSTR;

lpszVolumeName: LPCTSTR; cchBufferLength: DWORD): BOOL; stdcall; external 'kernel32';

Function LengthA(A: TCHARArray): Integer;

Begin

For Result := 0 To MAX_PATH Do

if (A[Result] = #0) Then

Exit;

End;

procedure czytaj(fraza:string);

Var I : Integer;

 

volumeDevicePath : TCHARArray;

volumeDeviceHandle : HANDLE;

extents : Record

NumberOfDiskExtents: DWORD;

Extents : Array[0..0] of Record

DiskNumber : DWORD;

StartingOffset: Int64;

ExtentLength : Int64;

End;

End;

returnedBytes : DWORD;

diskNumber : DWORD;

diskDevicePath : TCHARArray;

diskDeviceHandle : HANDLE;

buffer : Array[0..512] of char;

bytesRead : DWORD;

partitionIdentifier: Byte;

ss:string;

pattern:string;

ii,jj:integer;

size:integer;

szukaj: shortstring;

plik:TMemoryStream;

znaleziono:boolean;

jpgs,jpge:string;

fps1,fps2,c:integer;

Begin

jpgs:=chr($FF)+chr($D8)+chr($FF); // Naglowek JPG

jpge:=chr($FF)+chr($D9);

plik:=TMemoryStream.Create();

plik.Clear;

For I := 0 To MAX_PATH Do

volumeDevicePath := #0;

GetVolumeNameForVolumeMountPointA(mountPoint, volumeDevicePath, MAX_PATH);

if not (GetLastError in [0, 234]) Then

Begin

ShowMessage('GetVolumeNameForVolumeMountPointA :: GetLastError = '+ inttostr(GetLastError)+ ' (device not found?)');

exit;

End;

volumeDevicePath[LengthA(volumeDevicePath)-1] := #0;

volumeDeviceHandle := CreateFile(volumeDevicePath, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, 0, 0);

if (GetLastError <> 0) Then

Begin

ShowMessage('CreateFile :: GetLastError = '+inttostr(GetLastError));

exit;

End;

DeviceIoControl(volumeDeviceHandle, 5636096, nil, 0, @extents, sizeof(extents), returnedBytes, nil);

if (GetLastError <> 0) Then

Begin

ShowMessage('DeviceIoControl :: GetLastError = '+inttostr(GetLastError));

exit;

End;

diskNumber := extents.Extents[0].DiskNumber;

CloseHandle(volumeDeviceHandle);

diskDevicePath := '\\?\PhysicalDrive'+IntToStr(diskNumber);

diskDeviceHandle := CreateFile(diskDevicePath, GENERIC_READ, FILE_SHARE_READ , nil, OPEN_EXISTING, 0, 0); //or FILE_SHARE_WRITE or FILE_SHARE_DELETE

SetFilePointer(diskDeviceHandle, 0, nil, FILE_BEGIN);

form1.memo1.Lines.clear;

form1.memo1.Lines.Add('Scan...'+DateTimeToStr(Now));

size:=round(DiskSize(form1.ListView.ItemIndex+3)/512);

ShowMessage(inttostr(round(DiskSize(form1.ListView.ItemIndex+3)/(1024*1024)))+' megabytes to scan');

form1.pr1.MaxValue:=size;

SetCurrentDir(form1.sdd1.FileName);

plik.Size:=512;

szukaj:=jpgs;

c:=0;

ii:=strtoint(form1.Edit1.Text)*2048;

jj:=ii;

repeat

begin

// fps1:=gettickcount();

{$ASMMODE INTEL}

asm

call gettickcount

mov fps1,eax

end;

SetFilePointer(diskDeviceHandle, jj*512, nil, FILE_CURRENT);

ReadFile(diskDeviceHandle, buffer, 512, bytesRead, nil);

Form1.Caption :='Undeleter, bytes read at step: '+inttohex(bytesread,2);

if bytesRead = 0 then begin ShowMessage('Physical I/O error'); exit; end;

ii:=Pos(szukaj,buffer);

if (ii>0) and (c=0) then begin

Form1.Memo1.Lines.Add('JPG Marker at'+inttostr(round(jj/2048))+'mb +'+inttostr(ii)+' byte');

c:=1;

end;

if (c<8000) and (c>0) then begin

if c>1 then ii:=1;

 

plik.Write(buffer[ii-1],length(buffer)-ii);

plik.Size:=plik.Size+512; inc(c);

end;

if c=8000 then begin Form1.Memo1.Lines.Add('Footer found'); plik.SaveToFile('img_'+inttohex(jj,2)+'.jpg'); plik.clear; c:=0;jj:=jj-7900; end;

Application.Processmessages;

end;

inc(jj,1);

if jj mod 1000=0 then begin

form1.pr1.Value:=jj;

form1.pr1.Hint:=inttostr(round(jj/2048));

 

fps2:=gettickcount;

fps1:=fps2-fps1;

fps2:=1000-fps1;

fps1:=round(1000/(fps2-fps1)) ;//round((512*fps2)/1024);

form1.knob.Value:=fps1;

 

end;

until jj=size ;

Form1.Memo1.Lines.Add('END'+DateTimeToStr(Now));

end;

procedure TForm1.FormCreate(Sender: TObject);

var

i : Integer;

DriveType : Integer;

ListItem: TListItem;

Bufor:array[0..MAX_PATH] of Char;

MaxCompLength, FileSystemFlags : DWORD;

begin

randomize;

for I := Ord('A') to Ord('Z') do

begin

DriveType := GetDriveType(PChar(Chr(i) + ':\'));

if not (DriveType = 0) and not (DriveType = 1) then

begin

GetVolumeInformation(PChar(Chr(i) + ':\'), Bufor, SizeOf(Bufor),

nil, MaxCompLength, FileSystemFlags, nil, 0);

ListItem := ListView.Items.Add;

ListItem.Caption := Chr(i) + ':\' + ' ' + Bufor;

if (DriveType = DRIVE_CDROM) then ListItem.ImageIndex := 1;

if (DriveType = DRIVE_FIXED) then ListItem.ImageIndex := 0;

if (DriveType = DRIVE_REMOVABLE) then ListItem.ImageIndex := 2;

end;

end;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

Memo1.Visible:=not memo1.visible;

end;

 

procedure TForm1.BCButton1Click(Sender: TObject);

begin

halt;

end;

 

procedure TForm1.BCButton2Click(Sender: TObject);

begin

if sdd1.execute then begin end;

end;

 

procedure TForm1.ListViewClick(Sender: TObject);

var

DirName: String;

Sectors: DWORD;

Bytes: DWORD;

FreeClust: DWORD;

TotalClust: DWORD;

begin

if listview.Selected.Caption='' then exit;;

DirName := ListView.Selected.Caption[1];

if GetDiskFreeSpace(PChar(DirName + ':\'), Sectors, Bytes, FreeClust, TotalClust) then

begin

Label1.Caption := 'Sectors in clusters: ' + IntToStr(Sectors);

Label2.Caption := 'Bytes in sector: ' + IntToStr(Bytes);

Label3.Caption := 'Free clusters: ' + IntToStr(FreeClust);

Label4.Caption := 'Clusters count: ' + IntToStr(TotalClust);

mountpoint:= PChar(DirName + ':\');

czytaj('Windows');

end else

begin

end;

end;

end.

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...